@telora/daemon 0.23.29 → 0.23.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/build-info.json +9 -3
  2. package/dist/backends/claude/one-shot-model.d.ts.map +1 -1
  3. package/dist/backends/claude/one-shot-model.js +1 -0
  4. package/dist/backends/claude/one-shot-model.js.map +1 -1
  5. package/dist/composition/daemon-contexts.d.ts.map +1 -1
  6. package/dist/composition/daemon-contexts.js +2 -0
  7. package/dist/composition/daemon-contexts.js.map +1 -1
  8. package/dist/composition/qa-author-pass-context.d.ts +7 -0
  9. package/dist/composition/qa-author-pass-context.d.ts.map +1 -0
  10. package/dist/composition/qa-author-pass-context.js +68 -0
  11. package/dist/composition/qa-author-pass-context.js.map +1 -0
  12. package/dist/composition/spawn-pass-deps.d.ts +1 -1
  13. package/dist/composition/spawn-pass-deps.d.ts.map +1 -1
  14. package/dist/config/live-daemon-config.js +1 -1
  15. package/dist/daemon-state/provider-window.d.ts.map +1 -1
  16. package/dist/daemon-state/provider-window.js +1 -0
  17. package/dist/daemon-state/provider-window.js.map +1 -1
  18. package/dist/focus/daemon-contexts.d.ts +3 -0
  19. package/dist/focus/daemon-contexts.d.ts.map +1 -1
  20. package/dist/focus/daemon-contexts.js.map +1 -1
  21. package/dist/focus/focus-loop-registry.d.ts.map +1 -1
  22. package/dist/focus/focus-loop-registry.js +21 -0
  23. package/dist/focus/focus-loop-registry.js.map +1 -1
  24. package/dist/git/types.d.ts.map +1 -1
  25. package/dist/git/types.js +1 -0
  26. package/dist/git/types.js.map +1 -1
  27. package/dist/prompt-sections/qa-author-section.d.ts +54 -0
  28. package/dist/prompt-sections/qa-author-section.d.ts.map +1 -0
  29. package/dist/prompt-sections/qa-author-section.js +189 -0
  30. package/dist/prompt-sections/qa-author-section.js.map +1 -0
  31. package/dist/qa/qa-author-faithfulness.d.ts +67 -0
  32. package/dist/qa/qa-author-faithfulness.d.ts.map +1 -0
  33. package/dist/qa/qa-author-faithfulness.js +157 -0
  34. package/dist/qa/qa-author-faithfulness.js.map +1 -0
  35. package/dist/qa/qa-author-mode.d.ts +34 -0
  36. package/dist/qa/qa-author-mode.d.ts.map +1 -0
  37. package/dist/qa/qa-author-mode.js +29 -0
  38. package/dist/qa/qa-author-mode.js.map +1 -0
  39. package/dist/qa/qa-author-output.d.ts +23 -0
  40. package/dist/qa/qa-author-output.d.ts.map +1 -0
  41. package/dist/qa/qa-author-output.js +66 -0
  42. package/dist/qa/qa-author-output.js.map +1 -0
  43. package/dist/qa/qa-author-pass.d.ts +60 -0
  44. package/dist/qa/qa-author-pass.d.ts.map +1 -0
  45. package/dist/qa/qa-author-pass.js +163 -0
  46. package/dist/qa/qa-author-pass.js.map +1 -0
  47. package/dist/qa/qa-author-runner.d.ts +60 -0
  48. package/dist/qa/qa-author-runner.d.ts.map +1 -0
  49. package/dist/qa/qa-author-runner.js +175 -0
  50. package/dist/qa/qa-author-runner.js.map +1 -0
  51. package/dist/qa/qa-focus-changes.d.ts +32 -0
  52. package/dist/qa/qa-focus-changes.d.ts.map +1 -0
  53. package/dist/qa/qa-focus-changes.js +59 -0
  54. package/dist/qa/qa-focus-changes.js.map +1 -0
  55. package/dist/queries/api-client/shared.d.ts +1 -0
  56. package/dist/queries/api-client/shared.d.ts.map +1 -1
  57. package/dist/queries/api-client/shared.js +14 -1
  58. package/dist/queries/api-client/shared.js.map +1 -1
  59. package/dist/queries/deliveries/deliveries.d.ts +15 -27
  60. package/dist/queries/deliveries/deliveries.d.ts.map +1 -1
  61. package/dist/queries/deliveries/deliveries.js +5 -37
  62. package/dist/queries/deliveries/deliveries.js.map +1 -1
  63. package/dist/queries/index.d.ts +1 -1
  64. package/dist/queries/index.d.ts.map +1 -1
  65. package/dist/queries/index.js +1 -1
  66. package/dist/queries/index.js.map +1 -1
  67. package/dist/queries/qa-packets/qa-packets.d.ts +83 -0
  68. package/dist/queries/qa-packets/qa-packets.d.ts.map +1 -0
  69. package/dist/queries/qa-packets/qa-packets.js +79 -0
  70. package/dist/queries/qa-packets/qa-packets.js.map +1 -0
  71. package/dist/testing/fixtures/api-client.js +1 -1
  72. package/dist/testing/fixtures/index.js +1 -1
  73. package/dist/types/qa-packet.d.ts +28 -0
  74. package/dist/types/qa-packet.d.ts.map +1 -0
  75. package/dist/types/qa-packet.js +36 -0
  76. package/dist/types/qa-packet.js.map +1 -0
  77. package/package.json +3 -3
@@ -0,0 +1,189 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/prompt-sections/qa-author-section.test.ts,
3
+ // packages/daemon/src/qa/qa-author-unfaithful-answer.test.ts
4
+ // PINNED-BY-END
5
+ import { QA_AUTHOR_MODE } from '../types/qa-packet.js';
6
+ /** The system prompt every QA-author call runs under (a resumed session may keep its recorded one). */
7
+ export const QA_AUTHOR_SYSTEM_PROMPT = 'You write UI test packets: click-level test cases a person runs by hand in a web browser against a ' +
8
+ 'QA environment. You never edit files and never run a command that changes anything. You end every ' +
9
+ 'answer with exactly one fenced json block.';
10
+ /** The heading the prompt opens with -- the anchor tests and logs name it by. */
11
+ export const QA_AUTHOR_HEADING = '# WRITE THE UI TEST PACKET FOR THIS FOCUS';
12
+ function verbatim(text, none) {
13
+ const t = (text ?? '').trim();
14
+ return t ? ['```text', t, '```'] : [none];
15
+ }
16
+ function isRecord(value) {
17
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
18
+ }
19
+ /** The armed baseline criteria, each quoted as the arm stamped it. */
20
+ function armedBaselineLines(criteria) {
21
+ if (criteria === null || criteria === undefined)
22
+ return ['(the arm stamped no criteria)'];
23
+ if (!Array.isArray(criteria))
24
+ return ['```json', JSON.stringify(criteria, null, 2), '```'];
25
+ const lines = [];
26
+ for (const entry of criteria) {
27
+ if (isRecord(entry) && typeof entry.criterion === 'string' && entry.criterion.trim()) {
28
+ lines.push(...verbatim(entry.criterion, ''));
29
+ if (entry.drafted === true)
30
+ lines.push('(machine-drafted, accepted at the arm)');
31
+ }
32
+ else {
33
+ lines.push('```json', JSON.stringify(entry), '```');
34
+ }
35
+ }
36
+ return lines.length > 0 ? lines : ['(the arm stamped no criteria)'];
37
+ }
38
+ function targetLines(candidate, reviewedSha) {
39
+ const { environment, baseUrl, accessNote } = candidate.qaTarget;
40
+ return [
41
+ '## The QA target',
42
+ `- Environment: ${environment?.trim() || '(not set)'}`,
43
+ baseUrl?.trim()
44
+ ? `- Base URL: ${baseUrl.trim()}`
45
+ : '- Base URL: (not set) -- write every path relative anyway; the human resolves it against the environment they test in.',
46
+ `- Access: ${accessNote?.trim() || '(no access note)'}`,
47
+ `- The packet describes commit \`${reviewedSha}\`.`,
48
+ '',
49
+ 'Every case\'s `path` is RELATIVE to the base URL (for example `/settings?tab=billing`). Never write a scheme, a host, or `..`.',
50
+ ];
51
+ }
52
+ function criteriaLines(candidate) {
53
+ const lines = [
54
+ '## The acceptance criteria -- quote them VERBATIM',
55
+ 'Each case names ONE of the criteria below in its `criterion` field, copied EXACTLY: one whole line of a criteria ' +
56
+ 'block (without its leading bullet or number) or one whole block. A paraphrase, a summary, a fragment or two ' +
57
+ 'criteria merged into one is REFUSED. Only the focus\'s acceptance criteria, the armed baseline criteria and each ' +
58
+ 'delivery\'s "Acceptance criteria" count -- a description is not a criterion.',
59
+ '',
60
+ `### Focus "${candidate.focusName}"`,
61
+ ...verbatim(candidate.focusAcceptanceCriteria, '(the focus declares no acceptance criteria)'),
62
+ '',
63
+ '### Armed baseline criteria (what the human held this focus to when they armed it)',
64
+ ...armedBaselineLines(candidate.armedBaselineCriteria),
65
+ ];
66
+ for (const d of candidate.deliveries) {
67
+ lines.push('', `### Delivery "${d.name}" (${d.executionStatus ?? 'status unknown'})`);
68
+ if (d.description?.trim())
69
+ lines.push(...verbatim(d.description, ''));
70
+ lines.push('Acceptance criteria:', ...verbatim(d.acceptanceCriteria, '(none declared)'));
71
+ }
72
+ return lines;
73
+ }
74
+ function retestLines(candidate) {
75
+ const failed = candidate.previousPacket?.failedCases ?? [];
76
+ if (failed.length === 0)
77
+ return [];
78
+ const lines = [
79
+ '## Re-test: the previous QA cycle FAILED',
80
+ 'A human failed these cases when they ran the previous packet. For each one whose criterion is still among the ' +
81
+ 'criteria above, a case with `"retest": true` and `"retestOf": "<its id>"` that quotes THAT SAME criterion is ' +
82
+ 'REQUIRED -- the packet is refused without it, and a retest quoting another criterion does not count. Drop one ' +
83
+ 'only when its criterion is no longer listed above. While any of them still applies, the no-UI-surface marker is ' +
84
+ 'refused too.',
85
+ ];
86
+ for (const c of failed) {
87
+ lines.push(`- \`${c.id}\` -- criterion: ${JSON.stringify(c.criterion)}; path \`${c.path}\`; ` +
88
+ `steps: ${JSON.stringify(c.steps)}; expected: ${JSON.stringify(c.expected)}`);
89
+ }
90
+ return lines;
91
+ }
92
+ function knowledgeLines(candidate, mode, fresh) {
93
+ if (mode === QA_AUTHOR_MODE.RESUMED) {
94
+ return [
95
+ '## What you know',
96
+ 'You built this focus: this conversation is the coding session that built it, and the review has passed. ' +
97
+ 'Describe what you built in your own words. You may read files in the working directory (Read, Grep, Glob) ' +
98
+ 'to confirm a route, a label or a button name. Change nothing.',
99
+ ];
100
+ }
101
+ const lines = [
102
+ '## What was built',
103
+ 'You did not build this focus. Work from its deliveries above, the review summary, its commits and its diff below.',
104
+ '',
105
+ '### Review summary',
106
+ ...verbatim(candidate.latestReviewSummary, '(no review summary was recorded)'),
107
+ '',
108
+ '### Commits',
109
+ ...verbatim(fresh?.commitLog, '(no commits could be listed)'),
110
+ '',
111
+ '### Diff',
112
+ ];
113
+ if (fresh?.note)
114
+ lines.push(`(${fresh.note})`);
115
+ lines.push(...(fresh?.diff.trim() ? ['```diff', fresh.diff, '```'] : ['(no diff could be read)']));
116
+ if (fresh?.truncated)
117
+ lines.push('(The diff was cut at its size cap; the rest of the change is not shown.)');
118
+ return lines;
119
+ }
120
+ const RULE_LINES = [
121
+ '## The rules',
122
+ '- Write ONLY UI-facing cases: something a person opens, clicks or types into in the browser and sees the result of. ' +
123
+ 'No API calls, CLI commands, database queries, log reading or code inspection.',
124
+ '- One case per behavior a person can observe, tied to ONE criterion. A criterion nothing in the UI can show gets no case.',
125
+ '- `id`: short and unique within the packet (c1, c2, ...).',
126
+ '- `criterion`: that criterion, copied exactly from the list above -- one line without its bullet, or one whole block.',
127
+ '- `built`: what was built for it, in a sentence or two.',
128
+ '- `path`: where to start, relative to the base URL.',
129
+ '- `steps`: click-level actions in order, one action each ("Click **Save**").',
130
+ '- `expected`: what the person should see when the criterion is met.',
131
+ '- If nothing in this focus changes anything a person can click or see, answer with the no-UI-surface marker instead of cases.',
132
+ '- Do not ask questions. Do not edit files. Do not run git or any command that writes.',
133
+ ];
134
+ const OUTPUT_LINES = [
135
+ '## Your answer',
136
+ 'End your answer with exactly ONE fenced json block and nothing after it. Either the cases:',
137
+ '```json',
138
+ '{"cases": [{"id": "c1", "criterion": "<verbatim criterion>", "built": "<what was built>", "path": "/relative/path", ' +
139
+ '"steps": ["<step 1>", "<step 2>"], "expected": "<what the person sees>"}]}',
140
+ '```',
141
+ 'or, when nothing in the focus has a UI surface:',
142
+ '```json',
143
+ '{"noUiSurface": true}',
144
+ '```',
145
+ 'Add `"retest": true, "retestOf": "<previous case id>"` only to a case that re-tests a previously failed one.',
146
+ ];
147
+ /** The heading a corrective attempt's addition opens with. */
148
+ export const QA_AUTHOR_CORRECTION_HEADING = '## YOUR PREVIOUS ANSWER WAS REFUSED';
149
+ /**
150
+ * What a corrective attempt appends to the prompt: the rules the previous
151
+ * answer broke, one per line, and the instruction to write the whole packet
152
+ * again. Pure; the same text for every engine.
153
+ */
154
+ export function buildQaAuthorCorrection(violations) {
155
+ return [
156
+ QA_AUTHOR_CORRECTION_HEADING,
157
+ 'You answered this once already, and that packet was refused because it broke these rules:',
158
+ ...violations.map((v) => `- ${v}`),
159
+ '',
160
+ 'Write the WHOLE packet again, following every rule above: copy each `criterion` exactly from the criteria ' +
161
+ 'listed, and add every required retest case. End with exactly one fenced json block.',
162
+ ].join('\n') + '\n';
163
+ }
164
+ /**
165
+ * The QA-author prompt for one candidate. `reviewedSha` is the commit the
166
+ * packet is pinned to; `fresh` carries the change for a fresh pass (ignored
167
+ * when resumed). Pure: the same inputs give the same text.
168
+ */
169
+ export function buildQaAuthorPrompt(candidate, mode, reviewedSha, fresh = null) {
170
+ const intro = [
171
+ QA_AUTHOR_HEADING,
172
+ `The team's work on the focus "${candidate.focusName}" is finished and reviewed. A HUMAN will now check it by hand: ` +
173
+ 'they open the product in a web browser at the QA target below and run the test packet you write, case by case. ' +
174
+ 'Write that packet.',
175
+ ];
176
+ if (candidate.focusDescription?.trim())
177
+ intro.push('', 'The focus:', ...verbatim(candidate.focusDescription, ''));
178
+ const sections = [
179
+ intro,
180
+ targetLines(candidate, reviewedSha),
181
+ criteriaLines(candidate),
182
+ retestLines(candidate),
183
+ knowledgeLines(candidate, mode, fresh),
184
+ [...RULE_LINES],
185
+ [...OUTPUT_LINES],
186
+ ].filter((s) => s.length > 0);
187
+ return sections.map((s) => s.join('\n')).join('\n\n') + '\n';
188
+ }
189
+ //# sourceMappingURL=qa-author-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-section.js","sourceRoot":"","sources":["../../src/prompt-sections/qa-author-section.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Is a QA-author answer FAITHFUL to its focus? Every case quotes one of the
3
+ * criteria the pass was shown (the focus's acceptance criteria, each
4
+ * non-cancelled delivery's, each armed baseline criterion -- normalized, never
5
+ * paraphrased), and on a re-entry after a QA fail every failed case whose
6
+ * criterion still applies is re-tested (retest: true, retestOf: <its id>).
7
+ *
8
+ * The daemon runs this BEFORE it asks for the ready write, so an unfaithful
9
+ * answer can be re-asked (qa-author-runner.ts) instead of only refused. The
10
+ * authoritative rule is the edge's: checkQaPacketFaithful in
11
+ * src/lib/qa/qa-packet.ts (mirrored to supabase/functions/_shared), which
12
+ * daemon_qa_packet_write applies before a ready or no_ui_surface write. The
13
+ * daemon cannot import src/lib, so this is its own copy; qa-author-
14
+ * faithfulness.test.ts runs the SAME conformance table
15
+ * (src/lib/qa/__fixtures__/qa-faithfulness-cases.json) the canonical vitest
16
+ * runs, so the two cannot drift.
17
+ */
18
+ import type { QaPacketCandidate } from '../queries/qa-packets/qa-packets.js';
19
+ /** What the rule reads of one case. */
20
+ export interface QaFaithfulnessCase {
21
+ id: string;
22
+ criterion: string;
23
+ retest?: boolean;
24
+ retestOf?: string;
25
+ }
26
+ /** What the rule reads of a packet and its focus. */
27
+ export interface QaPacketFaithfulnessInput {
28
+ /** The packet's cases ([] for a no-UI-surface packet). */
29
+ cases: readonly QaFaithfulnessCase[];
30
+ noUiSurface: boolean;
31
+ /** The quotable criteria (qaCriteriaFromTexts); normalized again here. */
32
+ criteria: readonly string[];
33
+ /** The cases a human failed in the previous QA cycle ([] when it did not fail). */
34
+ previousFailedCases: ReadonlyArray<Pick<QaFaithfulnessCase, 'id' | 'criterion'>>;
35
+ }
36
+ /**
37
+ * The one normalization both sides of a criterion comparison get. Pure and
38
+ * idempotent: trim; strip surrounding quotes and a leading list marker, one
39
+ * layer at a time until neither is left; collapse whitespace runs to one
40
+ * space. Case, punctuation and wording are kept.
41
+ */
42
+ export declare function normalizeQaCriterion(text: string): string;
43
+ /** Every whole text block and each of its non-empty lines, normalized and de-duplicated. Pure. */
44
+ export declare function qaCriteriaFromTexts(texts: ReadonlyArray<string | null | undefined>): string[];
45
+ /** The criterion strings of an armed_baseline_criteria array; anything else yields none. Pure. */
46
+ export declare function qaArmedBaselineCriterionTexts(value: unknown): string[];
47
+ /**
48
+ * Is the packet faithful? Pure. One human-readable line per violation; [] is
49
+ * faithful. Rules: (1) every criterion is one of `criteria`; (2) every
50
+ * previously failed case whose criterion still applies is re-tested by a case
51
+ * quoting that same criterion; (3) a retest case carries both flag and
52
+ * retestOf, naming a failed case, and quotes the criterion that case tested;
53
+ * (4) no UI surface while a retest is owed is refused.
54
+ */
55
+ export declare function checkQaPacketFaithful(input: QaPacketFaithfulnessInput): string[];
56
+ /**
57
+ * The violations of one parsed answer against what the candidate read handed
58
+ * the author -- the same inputs daemon_qa_packet_write checks the write
59
+ * against. Pure.
60
+ */
61
+ export declare function qaAnswerFaithfulnessViolations(candidate: Pick<QaPacketCandidate, 'focusAcceptanceCriteria' | 'deliveries' | 'armedBaselineCriteria' | 'previousPacket'>, answer: {
62
+ kind: 'cases';
63
+ cases: readonly unknown[];
64
+ } | {
65
+ kind: 'no_ui_surface';
66
+ }): string[];
67
+ //# sourceMappingURL=qa-author-faithfulness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-faithfulness.d.ts","sourceRoot":"","sources":["../../src/qa/qa-author-faithfulness.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,yBAAyB;IACxC,0DAA0D;IAC1D,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,mFAAmF;IACnF,mBAAmB,EAAE,aAAa,CAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC;CAClF;AAsBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,EAAE,CAU7F;AAMD,kGAAkG;AAClG,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAOtE;AAqCD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM,EAAE,CAgChF;AAcD;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,yBAAyB,GAAG,YAAY,GAAG,uBAAuB,GAAG,gBAAgB,CAAC,EACzH,MAAM,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAC/E,MAAM,EAAE,CAYV"}
@@ -0,0 +1,157 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/qa/qa-author-faithfulness.test.ts
3
+ // PINNED-BY-END
4
+ const QUOTE_PAIRS = [
5
+ ['"', '"'],
6
+ ["'", "'"],
7
+ ['“', '”'],
8
+ ['‘', '’'],
9
+ ];
10
+ const LIST_MARKER = /^(?:[-*+•]|\d+[.)])\s+/;
11
+ const QUOTE_MAX_CHARS = 160;
12
+ function stripQuotePair(text) {
13
+ for (const [open, close] of QUOTE_PAIRS) {
14
+ if (text.length >= 2 && text.startsWith(open) && text.endsWith(close))
15
+ return text.slice(1, -1).trim();
16
+ }
17
+ return text;
18
+ }
19
+ function stripListMarker(text) {
20
+ return text.replace(LIST_MARKER, '').trim();
21
+ }
22
+ /**
23
+ * The one normalization both sides of a criterion comparison get. Pure and
24
+ * idempotent: trim; strip surrounding quotes and a leading list marker, one
25
+ * layer at a time until neither is left; collapse whitespace runs to one
26
+ * space. Case, punctuation and wording are kept.
27
+ */
28
+ export function normalizeQaCriterion(text) {
29
+ let t = text.trim();
30
+ for (;;) {
31
+ const next = stripListMarker(stripQuotePair(t));
32
+ if (next === t)
33
+ break;
34
+ t = next;
35
+ }
36
+ return t.replace(/\s+/g, ' ');
37
+ }
38
+ /** Every whole text block and each of its non-empty lines, normalized and de-duplicated. Pure. */
39
+ export function qaCriteriaFromTexts(texts) {
40
+ const out = new Set();
41
+ for (const text of texts) {
42
+ if (typeof text !== 'string')
43
+ continue;
44
+ for (const piece of [text, ...text.split(/\r?\n/)]) {
45
+ const normalized = normalizeQaCriterion(piece);
46
+ if (normalized)
47
+ out.add(normalized);
48
+ }
49
+ }
50
+ return [...out];
51
+ }
52
+ function isRecord(value) {
53
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
54
+ }
55
+ /** The criterion strings of an armed_baseline_criteria array; anything else yields none. Pure. */
56
+ export function qaArmedBaselineCriterionTexts(value) {
57
+ if (!Array.isArray(value))
58
+ return [];
59
+ return value.flatMap((entry) => {
60
+ if (!isRecord(entry))
61
+ return [];
62
+ const criterion = entry.criterion;
63
+ return typeof criterion === 'string' && criterion.trim().length > 0 ? [criterion] : [];
64
+ });
65
+ }
66
+ function quoteForViolation(text) {
67
+ const t = text.trim();
68
+ return JSON.stringify(t.length > QUOTE_MAX_CHARS ? `${t.slice(0, QUOTE_MAX_CHARS)}...` : t);
69
+ }
70
+ /** Rules 1 and 3 for one case: it quotes a criterion; its retest flag and retestOf agree and name a failed case. */
71
+ function caseViolations(c, quotable, failedCriteria) {
72
+ const out = [];
73
+ if (!quotable.has(normalizeQaCriterion(c.criterion))) {
74
+ out.push(`case ${c.id}: criterion ${quoteForViolation(c.criterion)} is not one of the focus's acceptance criteria ` +
75
+ '(copy one line, without its bullet, or one whole block, exactly)');
76
+ }
77
+ const retestOf = typeof c.retestOf === 'string' ? c.retestOf.trim() : '';
78
+ const failedList = failedCriteria.size > 0 ? `failed: ${[...failedCriteria.keys()].join(', ')}` : 'it failed no case';
79
+ if (c.retest === true && !retestOf) {
80
+ out.push(`case ${c.id}: is flagged "retest": true but names no retestOf`);
81
+ }
82
+ else if (retestOf && c.retest !== true) {
83
+ out.push(`case ${c.id}: names retestOf ${quoteForViolation(retestOf)} but is not flagged "retest": true`);
84
+ }
85
+ else if (retestOf && !failedCriteria.has(retestOf)) {
86
+ out.push(`case ${c.id}: retestOf ${quoteForViolation(retestOf)} is not a case the human failed in the previous QA cycle (${failedList})`);
87
+ }
88
+ else if (retestOf && failedCriteria.get(retestOf) !== normalizeQaCriterion(c.criterion)) {
89
+ out.push(`case ${c.id}: re-tests failed case ${retestOf} but quotes a different criterion -- a retest quotes the ` +
90
+ `criterion the failed case tested, ${quoteForViolation(failedCriteria.get(retestOf) ?? '')}`);
91
+ }
92
+ return out;
93
+ }
94
+ /**
95
+ * Is the packet faithful? Pure. One human-readable line per violation; [] is
96
+ * faithful. Rules: (1) every criterion is one of `criteria`; (2) every
97
+ * previously failed case whose criterion still applies is re-tested by a case
98
+ * quoting that same criterion; (3) a retest case carries both flag and
99
+ * retestOf, naming a failed case, and quotes the criterion that case tested;
100
+ * (4) no UI surface while a retest is owed is refused.
101
+ */
102
+ export function checkQaPacketFaithful(input) {
103
+ const quotable = new Set(input.criteria.map(normalizeQaCriterion).filter((c) => c.length > 0));
104
+ const failedCriteria = new Map(input.previousFailedCases.map((f) => [f.id.trim(), normalizeQaCriterion(f.criterion)]));
105
+ const violations = input.cases.flatMap((c) => caseViolations(c, quotable, failedCriteria));
106
+ const required = input.previousFailedCases.filter((f) => quotable.has(normalizeQaCriterion(f.criterion)));
107
+ if (input.noUiSurface && required.length > 0) {
108
+ violations.push(`the packet marks no UI surface, but the previous QA cycle failed UI case(s) ${required.map((f) => f.id).join(', ')} ` +
109
+ 'whose criteria still apply; each needs a retest case');
110
+ return violations;
111
+ }
112
+ for (const f of required) {
113
+ const id = f.id.trim();
114
+ const criterion = normalizeQaCriterion(f.criterion);
115
+ const retested = input.cases.some((c) => c.retest === true &&
116
+ typeof c.retestOf === 'string' &&
117
+ c.retestOf.trim() === id &&
118
+ normalizeQaCriterion(c.criterion) === criterion);
119
+ if (!retested) {
120
+ violations.push(`previous failed case ${id} (criterion ${quoteForViolation(f.criterion)}) still applies but no case re-tests it: ` +
121
+ `add a case quoting that criterion with "retest": true, "retestOf": "${id}"`);
122
+ }
123
+ }
124
+ return violations;
125
+ }
126
+ /** The fields the rule reads of a structurally parsed answer case (qa-author-output.ts checked id and criterion). */
127
+ function toFaithfulnessCase(value) {
128
+ const c = isRecord(value) ? value : {};
129
+ const out = {
130
+ id: typeof c.id === 'string' ? c.id.trim() : '',
131
+ criterion: typeof c.criterion === 'string' ? c.criterion : '',
132
+ };
133
+ if (c.retest === true)
134
+ out.retest = true;
135
+ if (typeof c.retestOf === 'string' && c.retestOf.trim())
136
+ out.retestOf = c.retestOf.trim();
137
+ return out;
138
+ }
139
+ /**
140
+ * The violations of one parsed answer against what the candidate read handed
141
+ * the author -- the same inputs daemon_qa_packet_write checks the write
142
+ * against. Pure.
143
+ */
144
+ export function qaAnswerFaithfulnessViolations(candidate, answer) {
145
+ const criteria = qaCriteriaFromTexts([
146
+ candidate.focusAcceptanceCriteria,
147
+ ...candidate.deliveries.map((d) => d.acceptanceCriteria),
148
+ ...qaArmedBaselineCriterionTexts(candidate.armedBaselineCriteria),
149
+ ]);
150
+ return checkQaPacketFaithful({
151
+ cases: answer.kind === 'cases' ? answer.cases.map(toFaithfulnessCase) : [],
152
+ noUiSurface: answer.kind === 'no_ui_surface',
153
+ criteria,
154
+ previousFailedCases: candidate.previousPacket?.failedCases ?? [],
155
+ });
156
+ }
157
+ //# sourceMappingURL=qa-author-faithfulness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-faithfulness.js","sourceRoot":"","sources":["../../src/qa/qa-author-faithfulness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Which way the QA-author pass runs for one focus: RESUMED -- a fork of the
3
+ * coding team's own Claude session, which already knows what it built -- or
4
+ * FRESH, over the delivery summaries and the diff.
5
+ *
6
+ * Resume only when the focus's coding lineage holds a CLAUDE session id (a
7
+ * Codex id cannot be resumed by the claude CLI; session/session-lineage.ts
8
+ * keys Claude under the bare lineage) AND the focus worktree that session ran
9
+ * in still exists: the CLI finds a session's transcript by the directory it
10
+ * ran in, and the session's file reads are relative to it. Anything else runs
11
+ * fresh, with the reason recorded in the log.
12
+ */
13
+ import type { QaPacketCandidate } from '../queries/qa-packets/qa-packets.js';
14
+ import { QA_AUTHOR_MODE } from '../types/qa-packet.js';
15
+ /** The lineage whose session built the focus. */
16
+ export declare const QA_CODING_LINEAGE = "coding";
17
+ /** What the decision reads besides the candidate. */
18
+ export interface QaAuthorModeFacts {
19
+ /** The focus worktree the coding session ran in, or null when none is known. */
20
+ worktreePath: string | null;
21
+ /** Whether that directory still exists. */
22
+ worktreeExists: boolean;
23
+ }
24
+ export type QaAuthorModeDecision = {
25
+ mode: typeof QA_AUTHOR_MODE.RESUMED;
26
+ sessionId: string;
27
+ cwd: string;
28
+ } | {
29
+ mode: typeof QA_AUTHOR_MODE.FRESH;
30
+ reason: string;
31
+ };
32
+ /** Decide resumed vs fresh. Pure. */
33
+ export declare function decideQaAuthorMode(candidate: Pick<QaPacketCandidate, 'codingSessionIds'>, facts: QaAuthorModeFacts): QaAuthorModeDecision;
34
+ //# sourceMappingURL=qa-author-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-mode.d.ts","sourceRoot":"","sources":["../../src/qa/qa-author-mode.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,OAAO,cAAc,CAAC,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,OAAO,cAAc,CAAC,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,qCAAqC;AACrC,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,EACtD,KAAK,EAAE,iBAAiB,GACvB,oBAAoB,CAmBtB"}
@@ -0,0 +1,29 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/qa/qa-author-mode.test.ts
3
+ // PINNED-BY-END
4
+ import { sessionMapKey } from '../session/session-lineage.js';
5
+ import { QA_AUTHOR_MODE } from '../types/qa-packet.js';
6
+ /** The lineage whose session built the focus. */
7
+ export const QA_CODING_LINEAGE = 'coding';
8
+ /** Decide resumed vs fresh. Pure. */
9
+ export function decideQaAuthorMode(candidate, facts) {
10
+ const sessions = candidate.codingSessionIds;
11
+ const sessionId = sessions[sessionMapKey('claude', QA_CODING_LINEAGE)];
12
+ if (!sessionId) {
13
+ const codex = sessions[sessionMapKey('codex', QA_CODING_LINEAGE)];
14
+ return {
15
+ mode: QA_AUTHOR_MODE.FRESH,
16
+ reason: codex
17
+ ? 'the coding session ran on codex, which the claude CLI cannot resume'
18
+ : 'no coding session is recorded for the focus',
19
+ };
20
+ }
21
+ if (!facts.worktreePath) {
22
+ return { mode: QA_AUTHOR_MODE.FRESH, reason: 'no focus worktree is known to resume the coding session in' };
23
+ }
24
+ if (!facts.worktreeExists) {
25
+ return { mode: QA_AUTHOR_MODE.FRESH, reason: `the focus worktree ${facts.worktreePath} no longer exists` };
26
+ }
27
+ return { mode: QA_AUTHOR_MODE.RESUMED, sessionId, cwd: facts.worktreePath };
28
+ }
29
+ //# sourceMappingURL=qa-author-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-mode.js","sourceRoot":"","sources":["../../src/qa/qa-author-mode.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,2DAA2D;AAC3D,gBAAgB;AAgBhB,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,iDAAiD;AACjD,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAc1C,qCAAqC;AACrC,MAAM,UAAU,kBAAkB,CAChC,SAAsD,EACtD,KAAwB;IAExB,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC;IAC5C,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;QAClE,OAAO;YACL,IAAI,EAAE,cAAc,CAAC,KAAK;YAC1B,MAAM,EAAE,KAAK;gBACX,CAAC,CAAC,qEAAqE;gBACvE,CAAC,CAAC,6CAA6C;SAClD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,4DAA4D,EAAE,CAAC;IAC9G,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,sBAAsB,KAAK,CAAC,YAAY,mBAAmB,EAAE,CAAC;IAC7G,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Read the QA-author pass's answer: the LAST fenced ```json block of the
3
+ * output, holding either {"cases": [...]} or {"noUiSurface": true} (the output
4
+ * contract prompt-sections/qa-author-section.ts states).
5
+ *
6
+ * The check here is structural only -- an array of objects with string fields,
7
+ * click-level steps, a path that is not absolute -- so an answer that could
8
+ * never be a packet is caught before it is written. The authoritative case
9
+ * contract is the edge's (supabase/functions/_shared/qa-packet.ts
10
+ * parseQaCases): a ready write it refuses is recorded as a failed packet.
11
+ */
12
+ export type QaAuthorOutput = {
13
+ kind: 'cases';
14
+ cases: unknown[];
15
+ } | {
16
+ kind: 'no_ui_surface';
17
+ } | {
18
+ kind: 'error';
19
+ error: string;
20
+ };
21
+ /** Parse a QA-author answer. Pure. */
22
+ export declare function parseQaAuthorOutput(text: string): QaAuthorOutput;
23
+ //# sourceMappingURL=qa-author-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-output.d.ts","sourceRoot":"","sources":["../../src/qa/qa-author-output.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA+BrC,sCAAsC;AACtC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAyBhE"}
@@ -0,0 +1,66 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/prompt-sections/qa-author-section.test.ts,
3
+ // packages/daemon/src/qa/qa-author-output.test.ts
4
+ // PINNED-BY-END
5
+ const FENCED_JSON = /```json[^\S\n]*\n([\s\S]*?)```/gi;
6
+ const CASE_STRING_FIELDS = ['id', 'criterion', 'built', 'path', 'expected'];
7
+ function isRecord(value) {
8
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
9
+ }
10
+ /** Whether `path` reaches off the QA target: a scheme, a protocol-relative or backslash start. */
11
+ function isAbsolutePath(path) {
12
+ const p = path.trim();
13
+ return /^[a-z][a-z0-9+.-]*:/i.test(p) || p.startsWith('//') || p.startsWith('\\');
14
+ }
15
+ /** The first structural problem of one case, or null. */
16
+ function caseProblem(value, index) {
17
+ const at = `case ${index + 1}`;
18
+ if (!isRecord(value))
19
+ return `${at} is not an object`;
20
+ for (const field of CASE_STRING_FIELDS) {
21
+ const v = value[field];
22
+ if (typeof v !== 'string' || v.trim() === '')
23
+ return `${at}: ${field} must be a non-empty string`;
24
+ }
25
+ if (isAbsolutePath(value.path))
26
+ return `${at}: path must be relative to the QA target base URL`;
27
+ const steps = value.steps;
28
+ if (!Array.isArray(steps) || steps.length === 0 || !steps.every((s) => typeof s === 'string' && s.trim() !== '')) {
29
+ return `${at}: steps must be a non-empty array of strings`;
30
+ }
31
+ return null;
32
+ }
33
+ /** Parse a QA-author answer. Pure. */
34
+ export function parseQaAuthorOutput(text) {
35
+ const blocks = [...text.matchAll(FENCED_JSON)].map((m) => m[1] ?? '');
36
+ const last = blocks.at(-1);
37
+ if (last === undefined)
38
+ return { kind: 'error', error: 'the answer has no fenced json block' };
39
+ let parsed;
40
+ try {
41
+ parsed = JSON.parse(last);
42
+ }
43
+ catch (err) {
44
+ return { kind: 'error', error: `the last json block is not valid JSON: ${err.message}` };
45
+ }
46
+ if (!isRecord(parsed))
47
+ return { kind: 'error', error: 'the last json block is not an object' };
48
+ const cases = parsed.cases;
49
+ const hasCases = Array.isArray(cases) && cases.length > 0;
50
+ if (parsed.noUiSurface === true) {
51
+ return hasCases
52
+ ? { kind: 'error', error: 'the answer both marks no UI surface and lists cases' }
53
+ : { kind: 'no_ui_surface' };
54
+ }
55
+ if (!Array.isArray(cases))
56
+ return { kind: 'error', error: 'the last json block has neither "cases" nor "noUiSurface": true' };
57
+ if (cases.length === 0)
58
+ return { kind: 'error', error: 'the answer lists no cases and does not mark no UI surface' };
59
+ for (let i = 0; i < cases.length; i++) {
60
+ const problem = caseProblem(cases[i], i);
61
+ if (problem)
62
+ return { kind: 'error', error: problem };
63
+ }
64
+ return { kind: 'cases', cases };
65
+ }
66
+ //# sourceMappingURL=qa-author-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-author-output.js","sourceRoot":"","sources":["../../src/qa/qa-author-output.ts"],"names":[],"mappings":"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"}