Skip to content

Commit 729977c

Browse files
committed
Bake Corbits PostHog survey ids into /feedback
Operators never configure survey routing; same public-id class as the baked PostHog project key. Env overrides remain for tests and forks.
1 parent f5069f6 commit 729977c

3 files changed

Lines changed: 53 additions & 49 deletions

File tree

‎docs/TELEMETRY.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,12 @@ because the operator typed the text for that purpose. Hard env kill switches
158158
still win — `DO_NOT_TRACK=1` or `CORBITS_TELEMETRY=0/false/off/no` block
159159
`/feedback` as well. Sending also requires an installation id and API key.
160160

161-
Survey id / question id come from env (`CORBITS_FEEDBACK_SURVEY_ID`,
162-
`CORBITS_FEEDBACK_QUESTION_ID`). Both must be set or capture fails closed with
163-
an “not configured” message — no default survey is baked into the client. When
164-
ids are missing the command is also hidden from the slash menu (still callable
165-
if typed). Success copy says “queued,” not delivered; free text over 2000
161+
Survey id / question id are **baked into the client** (Corbits team survey
162+
`Corbits Code Feedback`). Same trust class as the public PostHog project key —
163+
operators never configure them. Optional env overrides
164+
(`CORBITS_FEEDBACK_SURVEY_ID`, `CORBITS_FEEDBACK_QUESTION_ID`) exist for tests
165+
and forks; setting either to empty fails closed and hides the command from the
166+
slash menu. Success copy says “queued,” not delivered; free text over 2000
166167
characters is truncated with an explicit notice.
167168

168169
## Opting out

‎src/telemetry/feedback.test.ts‎

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -62,38 +62,40 @@ describe("buildSurveyProperties", () => {
6262
test("shapes PostHog custom survey properties", () => {
6363
const props = buildSurveyProperties("ship it", {
6464
turnTraceId: "trace-1",
65-
env: {
66-
CORBITS_FEEDBACK_SURVEY_ID: "survey-abc",
67-
CORBITS_FEEDBACK_QUESTION_ID: "q-1",
68-
},
6965
});
70-
expect(props.$survey_id).toBe("survey-abc");
66+
expect(props.$survey_id).toBe("019fe7ff-d12a-0000-7a63-303f3a874b90");
7167
expect(props.$survey_response).toBe("ship it");
7268
expect(props.turn_trace_id).toBe("trace-1");
7369
expect(props.$survey_questions).toEqual([
7470
{
75-
id: "q-1",
76-
question: "What feedback do you have for Corbits Code?",
71+
id: "913862f4-82aa-4814-8f68-146c05c38a74",
72+
question: "What feedback do you have about Corbits Code?",
7773
response: "ship it",
7874
},
7975
]);
8076
});
77+
78+
test("env override can blank the survey ids", () => {
79+
const props = buildSurveyProperties("x", {
80+
env: {
81+
CORBITS_FEEDBACK_SURVEY_ID: "",
82+
CORBITS_FEEDBACK_QUESTION_ID: "",
83+
},
84+
});
85+
expect(props.$survey_id).toBe("");
86+
});
8187
});
8288

8389
describe("captureFeedback", () => {
8490
test("sends survey sent when ambient telemetry is off", () => {
8591
const { telemetry, events } = captureSpy();
8692
expect(telemetry.enabled).toBe(false);
87-
const status = captureFeedback(telemetry, "great product", {
88-
env: {
89-
CORBITS_FEEDBACK_SURVEY_ID: "s1",
90-
CORBITS_FEEDBACK_QUESTION_ID: "q1",
91-
},
92-
});
93+
const status = captureFeedback(telemetry, "great product");
9394
expect(status).toBe("sent");
9495
expect(events).toHaveLength(1);
9596
expect(events[0]?.event).toBe("survey sent");
9697
expect(events[0]?.properties.$survey_response).toBe("great product");
98+
expect(events[0]?.properties.$survey_id).toBe("019fe7ff-d12a-0000-7a63-303f3a874b90");
9799
});
98100

99101
test("rejects empty text", () => {
@@ -110,14 +112,7 @@ describe("captureFeedback", () => {
110112
batch: { size: 100, intervalMs: 60_000, queueLimit: 100 },
111113
fetchFn: noopFetch,
112114
});
113-
expect(
114-
captureFeedback(telemetry, "hi", {
115-
env: {
116-
CORBITS_FEEDBACK_SURVEY_ID: "s1",
117-
CORBITS_FEEDBACK_QUESTION_ID: "q1",
118-
},
119-
}),
120-
).toBe("blocked");
115+
expect(captureFeedback(telemetry, "hi")).toBe("blocked");
121116
});
122117

123118
test("blocks under env kill switch even with identity", () => {
@@ -133,30 +128,28 @@ describe("captureFeedback", () => {
133128
});
134129
expect(
135130
captureFeedback(telemetry, "hi", {
136-
env: {
137-
CORBITS_TELEMETRY: "0",
138-
CORBITS_FEEDBACK_SURVEY_ID: "s1",
139-
CORBITS_FEEDBACK_QUESTION_ID: "q1",
140-
},
131+
env: { CORBITS_TELEMETRY: "0" },
141132
}),
142133
).toBe("blocked");
143134
});
144135

145-
test("fails closed when survey ids are missing", () => {
136+
test("fails closed when survey ids are blanked via env", () => {
146137
const { telemetry, events } = captureSpy();
147-
expect(captureFeedback(telemetry, "hi", { env: {} })).toBe("unconfigured");
138+
expect(
139+
captureFeedback(telemetry, "hi", {
140+
env: {
141+
CORBITS_FEEDBACK_SURVEY_ID: "",
142+
CORBITS_FEEDBACK_QUESTION_ID: "",
143+
},
144+
}),
145+
).toBe("unconfigured");
148146
expect(events).toHaveLength(0);
149147
});
150148

151149
test("reports truncation when free text exceeds the cap", () => {
152150
const { telemetry, events } = captureSpy();
153151
const long = "x".repeat(FEEDBACK_MAX_CHARS + 50);
154-
const status = captureFeedback(telemetry, long, {
155-
env: {
156-
CORBITS_FEEDBACK_SURVEY_ID: "s1",
157-
CORBITS_FEEDBACK_QUESTION_ID: "q1",
158-
},
159-
});
152+
const status = captureFeedback(telemetry, long);
160153
expect(status).toBe("sent_truncated");
161154
expect(events).toHaveLength(1);
162155
expect(String(events[0]?.properties.$survey_response).length).toBe(FEEDBACK_MAX_CHARS);

‎src/telemetry/feedback.ts‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,34 @@ export const FEEDBACK_BLOCKED =
2323
"Feedback could not be sent (disabled by environment or missing install identity).";
2424

2525
export const FEEDBACK_UNCONFIGURED =
26-
"Feedback is not configured (missing survey id). Set CORBITS_FEEDBACK_SURVEY_ID and CORBITS_FEEDBACK_QUESTION_ID.";
26+
"Feedback is not configured (missing survey id).";
2727

2828
/**
29-
* PostHog survey id for /feedback. Set via CORBITS_FEEDBACK_SURVEY_ID once the
30-
* survey exists in the project (user creates it in PostHog UI).
29+
* Corbits team survey — public routing ids (same trust class as the baked-in
30+
* PostHog project key). Operators never set these. Env override is for tests
31+
* and forks: when the env key is present (even empty), it wins over the default.
3132
*/
33+
export const DEFAULT_FEEDBACK_SURVEY_ID = "019fe7ff-d12a-0000-7a63-303f3a874b90";
34+
export const DEFAULT_FEEDBACK_QUESTION_ID = "913862f4-82aa-4814-8f68-146c05c38a74";
35+
export const FEEDBACK_QUESTION_TEXT = "What feedback do you have about Corbits Code?";
36+
37+
function envOverride(env: NodeJS.ProcessEnv, key: string): string | undefined {
38+
// Present key wins (including empty → fail closed for tests/forks).
39+
if (!Object.prototype.hasOwnProperty.call(env, key)) return undefined;
40+
return (env[key] ?? "").trim();
41+
}
42+
43+
/** PostHog survey id for /feedback. */
3244
export function feedbackSurveyId(env: NodeJS.ProcessEnv = process.env): string {
33-
return env.CORBITS_FEEDBACK_SURVEY_ID?.trim() ?? "";
45+
return envOverride(env, "CORBITS_FEEDBACK_SURVEY_ID") ?? DEFAULT_FEEDBACK_SURVEY_ID;
3446
}
3547

36-
/**
37-
* Free-text question id inside the survey. Set via CORBITS_FEEDBACK_QUESTION_ID.
38-
*/
48+
/** Free-text question id inside the survey. */
3949
export function feedbackQuestionId(env: NodeJS.ProcessEnv = process.env): string {
40-
return env.CORBITS_FEEDBACK_QUESTION_ID?.trim() ?? "";
50+
return envOverride(env, "CORBITS_FEEDBACK_QUESTION_ID") ?? DEFAULT_FEEDBACK_QUESTION_ID;
4151
}
4252

43-
/** True when both survey env ids are present (command is useful to show). */
53+
/** True when both survey ids resolve (defaults always do unless env blanks them). */
4454
export function isFeedbackConfigured(env: NodeJS.ProcessEnv = process.env): boolean {
4555
return feedbackSurveyId(env).length > 0 && feedbackQuestionId(env).length > 0;
4656
}
@@ -68,7 +78,7 @@ export function buildSurveyProperties(
6878
$survey_questions: [
6979
{
7080
id: questionId,
71-
question: "What feedback do you have for Corbits Code?",
81+
question: FEEDBACK_QUESTION_TEXT,
7282
response: capped,
7383
},
7484
],

0 commit comments

Comments
 (0)