ralphctl 0.25.0 → 0.27.0

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 (59) hide show
  1. package/README.md +11 -5
  2. package/THIRD-PARTY-NOTICES.md +65 -2
  3. package/dist/agent-definitions/ralphctl-generator.md +3 -2
  4. package/dist/{cli-GQBXYNFN.mjs → cli-EYDXERW6.mjs} +9423 -6665
  5. package/dist/cli.mjs +1 -1
  6. package/dist/manifest.json +20 -3
  7. package/dist/prompts/_partials/approval-gate.md +5 -5
  8. package/dist/prompts/_partials/autonomous-operation.md +23 -6
  9. package/dist/prompts/_partials/conventions-agents-md.md +8 -20
  10. package/dist/prompts/_partials/conventions-claude-md.md +12 -15
  11. package/dist/prompts/_partials/conventions-copilot-instructions.md +6 -10
  12. package/dist/prompts/_partials/decisions.md +3 -9
  13. package/dist/prompts/_partials/evaluator-failure-modes.md +11 -5
  14. package/dist/prompts/_partials/evaluator-grading-rules.md +25 -10
  15. package/dist/prompts/_partials/evidence-bound.md +2 -2
  16. package/dist/prompts/_partials/git-boundary.md +7 -0
  17. package/dist/prompts/_partials/harness-context.md +1 -1
  18. package/dist/prompts/_partials/one-shot-operation.md +6 -0
  19. package/dist/prompts/_partials/question-format.md +7 -0
  20. package/dist/prompts/_partials/skill-body.md +5 -0
  21. package/dist/prompts/_partials/task-blocked.md +10 -0
  22. package/dist/prompts/_partials/task-fields.md +19 -3
  23. package/dist/prompts/_partials/task-sizing.md +2 -2
  24. package/dist/prompts/_partials/validation-checklist.md +6 -8
  25. package/dist/prompts/apply-feedback/template.md +24 -25
  26. package/dist/prompts/create-pr/template.md +21 -15
  27. package/dist/prompts/detect-scripts/template.md +10 -9
  28. package/dist/prompts/detect-skills/template.md +19 -23
  29. package/dist/prompts/distill-learnings/template.md +10 -8
  30. package/dist/prompts/evaluate/template.md +74 -93
  31. package/dist/prompts/evaluate-continuation/template.md +19 -22
  32. package/dist/prompts/ideate/template.md +36 -47
  33. package/dist/prompts/implement/template.md +59 -73
  34. package/dist/prompts/implement-continuation/template.md +21 -20
  35. package/dist/prompts/implement-crash-resume/template.md +13 -4
  36. package/dist/prompts/plan/template.md +75 -64
  37. package/dist/prompts/readiness/template.md +36 -27
  38. package/dist/prompts/refine/template.md +37 -50
  39. package/dist/prompts/reproduce/template.md +9 -7
  40. package/dist/prompts/select-candidate/template.md +17 -10
  41. package/dist/skills/ralphctl-api-and-interface-design/SKILL.md +117 -0
  42. package/dist/skills/ralphctl-code-review-and-quality/SKILL.md +119 -8
  43. package/dist/skills/ralphctl-code-simplification/SKILL.md +100 -0
  44. package/dist/skills/ralphctl-codebase-design/SKILL.md +82 -0
  45. package/dist/skills/ralphctl-debugging-and-error-recovery/SKILL.md +23 -5
  46. package/dist/skills/ralphctl-deprecation-and-migration/SKILL.md +106 -0
  47. package/dist/skills/ralphctl-frontend-ui-engineering/SKILL.md +94 -0
  48. package/dist/skills/ralphctl-humanizer/SKILL.md +137 -0
  49. package/dist/skills/ralphctl-idea-refinement/SKILL.md +2 -0
  50. package/dist/skills/ralphctl-iterative-review/SKILL.md +10 -4
  51. package/dist/skills/ralphctl-observability-and-instrumentation/SKILL.md +104 -0
  52. package/dist/skills/ralphctl-performance-optimization/SKILL.md +123 -0
  53. package/dist/skills/ralphctl-ponytail/SKILL.md +38 -28
  54. package/dist/skills/ralphctl-security-and-hardening/SKILL.md +259 -0
  55. package/dist/skills/ralphctl-source-driven-development/SKILL.md +103 -0
  56. package/dist/skills/ralphctl-spec-driven-development/SKILL.md +148 -0
  57. package/dist/skills/ralphctl-test-driven-development/SKILL.md +29 -2
  58. package/dist/skills/ralphctl-writing-for-agents/SKILL.md +113 -0
  59. package/package.json +10 -10
@@ -10,39 +10,17 @@ render a verdict.
10
10
 
11
11
  {{FLOOR_RUBRIC_SECTION}}
12
12
 
13
- Additional dimensions appended by the planner (when present) are evaluated with the same binary pass/fail
14
- logic. The rubric from `<task_specification>` is the authority — grade against it, not against your own
15
- quality judgment.
13
+ {{EXTRA_DIMENSIONS_SECTION}}
14
+
15
+ Dimensions the planner attached are evaluated with the same binary pass/fail logic. The rubric from
16
+ `<task_specification>` is the authority — grade against it, not against your own quality judgment.
16
17
 
17
18
  {{EVALUATOR_FAILURE_MODES}}
18
19
 
19
- **Verdict values — `passed`, `failed`, `malformed`:**
20
-
21
- Almost every round ends in `passed` or `failed`. Reach for `malformed` only when you genuinely cannot reach a
22
- terminal verdict this round — for example you graded some dimensions but a tooling or environment problem
23
- (a verify command that will not run, an unreadable working tree) blocked the rest, so emitting `passed` or
24
- `failed` would be a guess. `malformed` means "no verdict yet," not "slightly unsure."
25
-
26
- Legitimate `malformed` triggers: the verify command dies without readable output; the working tree is
27
- unreadable or the mounted directory is missing required files; environment setup is broken such that no
28
- criterion command can run. Uncertainty about how to interpret a criterion isn't `malformed` — name the
29
- failing criterion and emit `failed` with a critique.
30
-
31
- When that FAIL stems from criterion ambiguity — two competent reviewers could reasonably disagree about what
32
- the criterion requires — rather than a demonstrable defect, prefix the critique bullet with `[spec-ambiguity]`
33
- and state the interpretation you graded against, so the planner can tighten the criterion instead of treating
34
- it as a code defect.
35
-
36
- When you emit `malformed`, the harness neither marks the work done nor blocks the task — it retries the
37
- attempt: the SAME model gets a fresh attempt while the attempt budget remains, and only when the budget is
38
- exhausted does the round settle with a warning. So `malformed` is honest and recoverable. Do not avoid it by
39
- forcing a `passed` you cannot support — a false `passed` ships a bug; a `malformed` just costs one more attempt.
40
- Conversely, do not reach for `malformed` to dodge a clear `failed`: if you can name a concrete failing
41
- criterion, the verdict is `failed` with a critique, never `malformed`.
42
-
43
- A terminal `passed` or `failed` verdict must grade each dimension in the rubric above with a finding — a
44
- verdict missing a floor dimension is rejected by the harness and re-requested. `malformed` is exempt from
45
- that coverage requirement.
20
+ **Verdict values — `passed`, `failed`, `malformed`:** almost every round ends in `passed` or `failed`;
21
+ `malformed` means "no verdict yet", not "slightly unsure", and the blocked-check rules in `<grading_rules>`
22
+ say when it applies. A false `passed` ships a bug; a false `failed` costs one generator round — but a FAIL
23
+ still needs a concrete observation.
46
24
  </role>
47
25
 
48
26
  {{HARNESS_CONTEXT}}
@@ -51,10 +29,10 @@ that coverage requirement.
51
29
 
52
30
  <goal>
53
31
  Produce one `evaluation` signal in `signals.json` under the harness output directory — `status: "passed"`
54
- only when every floor dimension AND every task-specific dimension passes with concrete evidence;
32
+ only when every floor dimension and every task-specific dimension passes with concrete evidence;
55
33
  `status: "failed"` otherwise with a critique the generator can act on. The exact output path is in the
56
- output contract section at the bottom of this prompt. You may additionally emit `learning` signals for
57
- durable insights discovered while grading; the `evaluation` signal remains exactly one and mandatory.
34
+ output contract section at the bottom of this prompt. You may additionally emit `learning` or `note` signals
35
+ for durable insights discovered while grading; the `evaluation` signal remains exactly one and mandatory.
58
36
  </goal>
59
37
 
60
38
  <success_criteria>
@@ -69,8 +47,7 @@ durable insights discovered while grading; the `evaluation` signal remains exact
69
47
  per-criterion checklist, not only prose. This is in ADDITION to the floor `dimensions`, not a
70
48
  replacement.
71
49
  - A FAIL on any dimension or criterion sets `status: "failed"`.
72
- - The critique (when `status: "failed"`) names each failed item using the (a/b/c/d) format defined in
73
- `<grading_rules>`.
50
+ - The critique (when `status: "failed"`) lists each failed item in the format defined in `<grading_rules>`.
74
51
  - Signal written to `<outputDir>/signals.json` — no other files written, except an evidence overflow log
75
52
  outside the repository when Phase 2 requires one.
76
53
 
@@ -99,9 +76,9 @@ round and never carry a prior PASS forward without your own observation.
99
76
 
100
77
  <evaluation_discipline>
101
78
  Before writing `signals.json`, work through each acceptance criterion and each floor dimension
102
- explicitly. For each, note the concrete observation that supports your PASS or FAIL, and record
103
- a preliminary verdict per criterion before moving to the next — do not defer all verdicts to the
104
- end. The final `signals.json` is the only machine-readable output and must come last.
79
+ explicitly. Grade each criterion and floor dimension as you gather its evidence rather than deciding them
80
+ all at the end; the `criteria` array and dimension findings are where each verdict lands, and
81
+ `signals.json` is written last.
105
82
  </evaluation_discipline>
106
83
 
107
84
  <inputs>
@@ -118,7 +95,7 @@ end. The final `signals.json` is the only machine-readable output and must come
118
95
  <constraints>
119
96
  - Read files and run shell commands. Do not write, edit, or delete any file except `signals.json` in the
120
97
  harness-mounted output directory — and, only when a command's output overflows the evidence bound in
121
- Phase 2, one overflow log in your session working directory (never inside the repository).
98
+ Phase 2, one overflow log in that same output directory (never inside the repository).
122
99
  - Do not run `git stash`, `git add`, or `git commit` — those are write operations.
123
100
  - Do not run setup or migration commands — your session is read-only except for `signals.json`.
124
101
  - The working tree is expected to be dirty: the harness commits the generator's output after this evaluator
@@ -154,9 +131,10 @@ Run deterministic checks first — they are authoritative and cheap.
154
131
 
155
132
  {{PARALLEL_TOOL_CALLS}}
156
133
 
157
- 1. **Run each `auto` criterion's command** from `<task_specification>` directly and record the decisive
158
- output lines for each (bounded per Phase 2). The verify-script rule in `<grading_rules>` governs `<verify_script>`. If any criterion command fails, the implementation fails for that criterion regardless of how clean the
159
- code looks. If a command's result looks flaky — it disagrees with what the code plainly does — re-run it
134
+ 1. **Run each `auto` criterion's command** from `<task_specification>` directly and record the exit code and
135
+ decisive output lines for each (bounded by the evidence bound in Phase 2). The verify-script rule in `<grading_rules>`
136
+ governs `<verify_script>`. If any criterion command fails, the implementation fails for that criterion
137
+ regardless of how clean the code looks. If a command's result looks flaky — it disagrees with what the code plainly does — re-run it
160
138
  once; if the two runs disagree, record the inconsistency itself as evidence, never a clean PASS. Do not
161
139
  stop here — continue grading all criteria so the generator receives a full critique.
162
140
  2. **Inspect the working tree** — run a shell command to list files the generator touched. The tree is
@@ -170,8 +148,8 @@ Run deterministic checks first — they are authoritative and cheap.
170
148
 
171
149
  For every criterion in the contract:
172
150
 
173
- - **`auto` criteria** — run the specified command and cite its exit code and the decisive output lines
174
- in `executionEvidence`. PASS only when the command exits 0 AND the assertion holds; FAIL otherwise.
151
+ - **`auto` criteria** — grade from your Phase 1 run — cite its exit code and decisive lines in
152
+ `executionEvidence`; re-run only under the flaky-result rule in Phase 1. PASS only when the command exits 0 and the assertion holds; FAIL otherwise.
175
153
  - **`manual` criteria** — when the changed behaviour is runnable (a command, a script, a service
176
154
  endpoint, or a test), execute the changed path yourself and cite the observed output as evidence;
177
155
  reading the diff or a green verify script alone does not substitute for that observation. Otherwise
@@ -181,9 +159,9 @@ For every criterion in the contract:
181
159
  {{EVIDENCE_BOUND}}
182
160
 
183
161
  Grade each criterion PASS or FAIL — no middle ground. Any single criterion FAIL forces `status: "failed"`.
184
- A criterion you were blocked from executing follows the UNVERIFIED rule in `<grading_rules>`.
162
+ A criterion you were blocked from executing follows the blocked-checks rule in `<grading_rules>`.
185
163
 
186
- Record each criterion's verdict STRUCTURALLY in the `evaluation` signal's `criteria` array — one entry
164
+ Record each criterion's verdict structurally in the `evaluation` signal's `criteria` array — one entry
187
165
  per criterion with its `id`, a `passed` boolean, and a one-line `evidence` citation. This is the same
188
166
  grading you just did in prose; the array carries it as data so the harness can persist a durable
189
167
  per-criterion checklist across rounds. Grade every criterion — including the ones you could not assess,
@@ -214,8 +192,9 @@ observation — file path, line number, function name, tool output, or quoted sn
214
192
  record the response.
215
193
  - **E2E or smoke suite**: run it when declared in `<project_tooling>` and confirm it reaches
216
194
  the changed behaviour path.
217
- Cite the run command and verbatim observation as evidence in the Correctness dimension finding.
218
- Absence of a run observation when a run-path was declared is a Completeness failure.
195
+
196
+ Cite the run command and verbatim observation as evidence in the Correctness dimension finding. Absence
197
+ of a run observation when a run-path was declared is a Completeness failure.
219
198
 
220
199
  **When `<project_tooling>` carries no runnable-product capability** (a library, a pure type or
221
200
  schema package, or only static analysis tooling listed):
@@ -232,17 +211,15 @@ or output evidence you gathered in Phases 1–3. Grade `applicable: false` only
232
211
  marks exempt (Robustness on a change that touches no error/failure path) and state the concrete reason in
233
212
  `finding` rather than fabricating a pass or fail.
234
213
 
235
- {{EXTRA_DIMENSIONS_SECTION}}
236
-
237
214
  ### Before rendering the verdict
238
215
 
239
216
  Answer both questions honestly:
240
217
 
241
- 1. Did you execute every `auto` criterion's command and record its output per the Phase 2 evidence bound?
242
- (If the task has no `auto` criteria, did you run the verify script as the fallback?) If not, set Completeness `passed: false`
243
- with a one-line finding explaining what you skipped, and set `status: "failed"`.
244
- 2. Can you name a specific observation for each dimension AND each criterion? For every PASS you are about to
245
- emit, point to a concrete piece of evidence. If not, the same applies: Completeness fails.
218
+ 1. Did every `auto` criterion either run, with its output recorded per the evidence bound, or carry an
219
+ UNVERIFIED reason? (If the task has no `auto` criteria, did you run the verify script as the fallback?)
220
+ Apply the blocked-checks rule in `<grading_rules>` to anything that did not run.
221
+ 2. Can you name a specific observation for each dimension and each criterion? For every PASS you are about to
222
+ emit, point to a concrete piece of evidence. If not, Completeness fails.
246
223
 
247
224
  A false PASS is worse than a false FAIL. A false FAIL costs one extra generator round; a false PASS ships a
248
225
  bug. This check exists because the evaluator is the last line of defence against silent-pass regressions.
@@ -267,7 +244,7 @@ Phase 2:
267
244
  - C2: `src/routes/exports.ts:42` returns 400 with `{ error: "invalid date" }` matching the project's error
268
245
  format at `src/lib/errors.ts:8` — PASS.
269
246
 
270
- Phase 3: `src/routes/exports.ts:12` validates via the project's shared Zod schema before reaching the
247
+ Phase 3: `src/routes/exports.ts:12` validates via the project's shared validation schema before reaching the
271
248
  database. Sibling routes at `src/routes/imports.ts` use the same pattern — Consistency PASS.
272
249
 
273
250
  Phase 4 dimensions:
@@ -275,7 +252,9 @@ Phase 4 dimensions:
275
252
  - Correctness — PASS — C1 exited 0 (12/12 green); C2 returns 400 at `src/routes/exports.ts:42`.
276
253
  - Completeness — PASS — schema, controller, and tests all implemented per steps; one TODO comment unrelated
277
254
  to this task's criteria.
278
- - Safety — PASS — input validated via shared Zod schema at `src/routes/exports.ts:12` before DB access.
255
+ - Safety — PASS — input validated via shared validation schema at `src/routes/exports.ts:12` before DB access;
256
+ pre-existing, not graded: `src/routes/reports.ts:31` skips the same validation, and this change neither
257
+ touches nor calls it.
279
258
  - Consistency — PASS — follows existing endpoint patterns in `src/routes/`; uses the shared error format.
280
259
  - Robustness — N/A — the change only adds input validation with a standard 400 response; it introduces no
281
260
  error/failure-recovery path (retries, rollback, degradation) beyond what Correctness already covers.
@@ -306,7 +285,7 @@ Signals:
306
285
  {
307
286
  "dimension": "safety",
308
287
  "passed": true,
309
- "finding": "input validated via shared Zod schema at src/routes/exports.ts:12 before DB access"
288
+ "finding": "input validated via shared validation schema at src/routes/exports.ts:12 before DB access; pre-existing, not graded: src/routes/reports.ts:31 skips the same validation and this change neither touches nor calls it"
310
289
  },
311
290
  {
312
291
  "dimension": "consistency",
@@ -347,7 +326,7 @@ Phase 1: ran C1's test command directly — exit 0, 8 tests green, recorded verb
347
326
  Phase 2:
348
327
 
349
328
  - C1: test command exited 0, 8 tests green — PASS.
350
- - C2: `src/controllers/users.ts:47` calls `parseInt(page)` without validation — NaN propagates into the
329
+ - C2: `src/controllers/users.ts:47` parses `page` without validating it — NaN propagates into the
351
330
  query, which throws an unhandled exception returning 500 — FAIL.
352
331
 
353
332
  Phase 3: `src/repositories/users.ts:23` interpolates `query` directly into a SQL string via template
@@ -362,21 +341,21 @@ Phase 4 dimensions:
362
341
  - Safety — FAIL — `src/repositories/users.ts:23`: SQL injection via unparameterised template literal.
363
342
  Sibling `src/repositories/posts.ts:15` shows the correct pattern.
364
343
  - Consistency — PASS — controller structure follows existing patterns; pagination helper used correctly.
365
- - Robustness — FAIL — `src/controllers/users.ts:47` lets the `NaN` from `parseInt(page)` propagate
344
+ - Robustness — FAIL — `src/controllers/users.ts:47` lets the `NaN` from parsing `page` propagate
366
345
  uncaught into the query layer instead of degrading gracefully (e.g. rejecting with a 400 before the
367
346
  query runs); the same defect that breaks Correctness also breaks graceful error handling here.
368
347
 
369
348
  Verdict: `status: "failed"`, critique:
370
349
 
371
- - "[Correctness · C2] (a) correctness, (b) `parseInt(page)` at `src/controllers/users.ts:47` returns NaN
372
- for non-numeric input, causing an unhandled exception (500), (c) validate `page` before use so
373
- non-numeric input returns 400, (d) `src/controllers/users.ts:47`."
374
- - "[Safety] (a) safety, (b) `WHERE name LIKE '%${query}%'` at `src/repositories/users.ts:23` interpolates
375
- user input into SQL, (c) use a parameterised query with `$1` placeholder, (d)
376
- `src/repositories/users.ts:23`."
377
- - "[Robustness] (a) robustness, (b) `src/controllers/users.ts:47` lets an invalid `page` value propagate
378
- as an uncaught exception instead of a handled 400, (c) validate `page` before use and return a graceful
379
- 400 on failure, (d) `src/controllers/users.ts:47`."
350
+ - [Correctness · C2] `src/controllers/users.ts:47` parses `page` without validating it, so non-numeric input
351
+ yields `NaN` and an unhandled exception (500); it should validate `page` first and return 400; look at
352
+ `src/controllers/users.ts:47`.
353
+ - [Safety] `src/repositories/users.ts:23` interpolates user input into SQL (`WHERE name LIKE '%${query}%'`);
354
+ it should use a parameterised query like `src/repositories/posts.ts:15`; look at
355
+ `src/repositories/users.ts:23`.
356
+ - [Robustness] `src/controllers/users.ts:47` lets an invalid `page` value propagate as an uncaught exception
357
+ instead of a handled 400; it should reject the value before the query runs; look at
358
+ `src/controllers/users.ts:47`.
380
359
 
381
360
  Signals:
382
361
 
@@ -423,7 +402,7 @@ Signals:
423
402
  "evidence": "src/controllers/users.ts:47 returns 500 on non-numeric page (expected 400)"
424
403
  }
425
404
  ],
426
- "critique": "[Correctness · C2] (a) correctness, (b) parseInt(page) at src/controllers/users.ts:47 returns NaN for non-numeric input causing 500, (c) validate page before use so invalid input returns 400, (d) src/controllers/users.ts:47. [Safety] (a) safety, (b) WHERE name LIKE '%${query}%' at src/repositories/users.ts:23 interpolates user input into SQL, (c) use a parameterised query, (d) src/repositories/users.ts:23. [Robustness] (a) robustness, (b) src/controllers/users.ts:47 lets an invalid page value propagate as an uncaught exception, (c) validate page before use and return a graceful 400, (d) src/controllers/users.ts:47.",
405
+ "critique": "- [Correctness · C2] src/controllers/users.ts:47 parses page without validating it, so non-numeric input yields NaN and a 500; it should validate page first and return 400; look at src/controllers/users.ts:47.\n- [Safety] src/repositories/users.ts:23 interpolates user input into SQL (WHERE name LIKE '%${query}%'); it should use a parameterised query like src/repositories/posts.ts:15; look at src/repositories/users.ts:23.\n- [Robustness] src/controllers/users.ts:47 lets an invalid page value propagate as an uncaught exception instead of a handled 400; it should reject the value before the query runs; look at src/controllers/users.ts:47.",
427
406
  "timestamp": "2026-01-01T00:00:00.000Z"
428
407
  }
429
408
  ]
@@ -434,7 +413,7 @@ Signals:
434
413
 
435
414
  <example id="3" label="FAIL — verify passes; round fails because a criterion lacks evidence (anti-rubber-stamp)">
436
415
 
437
- Task: "Migrate auth middleware to the new session store"
416
+ Task: "Migrate auth middleware to the new session store" (a Python service)
438
417
 
439
418
  Criteria:
440
419
 
@@ -449,36 +428,36 @@ Phase 2:
449
428
 
450
429
  - C1: exited 0, 34 tests green — PASS.
451
430
  - C2: searched the codebase for old session-cookie key names — zero references found — PASS.
452
- - C3: searched for the TTL configuration path — no environment variable read, no config key, the value is
453
- hardcoded as `3600` at `src/middleware/session.ts:18` — FAIL.
431
+ - C3: searched for the TTL configuration path — no environment read, no config key, the value is
432
+ hardcoded as `3600` at `app/middleware/session.py:18` — FAIL.
454
433
 
455
- Phase 3: `src/middleware/session.ts:18` shows `const TTL = 3600;` — no reference to `process.env` or any
456
- config service.
434
+ Phase 3: `app/middleware/session.py:18` shows `TTL = 3600` — no `os.environ` lookup or any config service.
457
435
 
458
436
  Phase 4 dimensions:
459
437
 
460
- - Correctness — FAIL — C3: TTL is hardcoded at `src/middleware/session.ts:18`; no environment variable read
461
- found in the file or its imports.
438
+ - Correctness — FAIL — C3: TTL is hardcoded at `app/middleware/session.py:18`; no environment read found in
439
+ the module or its imports.
462
440
  - Completeness — FAIL — C3 has no evidence of implementation; step 3 ("expose TTL via env var") has no
463
441
  corresponding code.
464
- - Safety — PASS — new session store uses the project's standard signing key from `src/config/secrets.ts`.
465
- - Consistency — PASS — middleware structure matches `src/middleware/csrf.ts`; config access follows the
466
- pattern in `src/middleware/rate-limit.ts`.
467
- - Robustness — PASS — `src/middleware/session.ts:31` catches store-lookup failures and falls back to
442
+ - Safety — PASS — new session store uses the project's standard signing key from `app/config/secrets.py`.
443
+ - Consistency — PASS — middleware structure matches `app/middleware/csrf.py`; config access follows the
444
+ pattern in `app/middleware/rate_limit.py`.
445
+ - Robustness — PASS — `app/middleware/session.py:31` catches store-lookup failures and falls back to
468
446
  issuing a fresh anonymous session, matching the retry/fallback pattern already used in
469
- `src/middleware/csrf.ts`.
447
+ `app/middleware/csrf.py`.
470
448
 
471
449
  Note: C1's test command passed. This round still fails because C3 is unimplemented — a passing test
472
450
  command does not confirm TTL configurability.
473
451
 
474
452
  Verdict: `status: "failed"`, critique:
475
453
 
476
- - "[Correctness · C3] (a) correctness, (b) `src/middleware/session.ts:18` hardcodes `TTL = 3600` with no
477
- environment variable read, (c) read the TTL from an environment variable (e.g.
478
- `SESSION_TTL_SECONDS`) with a fallback default, (d) `src/middleware/session.ts:18`."
479
- - "[Completeness · C3] (a) completeness, (b) step 3 "expose TTL via env var" has no implementation — no
480
- `process.env` reference in `src/middleware/session.ts` or its imports, (c) implement step 3 before
481
- marking the task complete, (d) `src/middleware/session.ts` and its import graph."
454
+ - [Correctness · C3] `app/middleware/session.py:18` hardcodes `TTL = 3600` with no environment read; it should
455
+ read the TTL from an environment variable (e.g. `SESSION_TTL_SECONDS`) with a fallback default; look at
456
+ `app/middleware/session.py:18`.
457
+ - [Completeness · C3] step 3 ("expose TTL via env var") has no implementation — no environment read in
458
+ `app/middleware/session.py` or its imports; it should be implemented before the task is complete; look at
459
+ `app/middleware/session.py` and its imports.
460
+
482
461
  </example>
483
462
 
484
463
  <example id="4" label="FAIL — clean tree means no work was done this round; grade failed, not malformed">
@@ -489,7 +468,8 @@ Situation: the working tree is clean — no uncommitted changes visible. The ver
489
468
  generator's prior commit message claims the work is done, but the harness has not committed for this round
490
469
  yet (dirty-tree is the expected state; clean-tree means the generator wrote nothing this round).
491
470
 
492
- Phase 1: shell inspection shows no uncommitted changes. The diff is empty.
471
+ Phase 1: shell inspection shows no uncommitted changes. The diff is empty, and
472
+ `src/payments/gateway.ts` still wraps its calls in the old hand-rolled retry loop.
493
473
 
494
474
  Phase 2: C1 auto criterion — test command exits 0 but this only confirms existing tests pass.
495
475
 
@@ -498,10 +478,11 @@ were executed this round.
498
478
 
499
479
  Verdict: `status: "failed"`, critique:
500
480
 
501
- - "[Completeness] (a) completeness, (b) working tree is clean — no uncommitted changes visible, suggesting
502
- the generator produced no output this round, (c) execute the declared task steps and leave the resulting
503
- changes uncommitted in the working tree so the next evaluator round has a diff to review, (d) declared
504
- steps in the task specification above — start there."
481
+ - [Completeness] the working tree is clean — no uncommitted changes visible, and
482
+ `src/payments/gateway.ts` still uses the old hand-rolled retry loop, so the generator produced no output
483
+ this round; it should execute the declared task steps and leave the resulting changes uncommitted in the
484
+ working tree so the next evaluator round has a diff to review; look at `src/payments/gateway.ts`.
485
+
505
486
  </example>
506
487
 
507
488
  </examples>
@@ -15,20 +15,17 @@ tooling, and render a verdict.
15
15
 
16
16
  {{FLOOR_RUBRIC_SECTION}}
17
17
 
18
+ {{EXTRA_DIMENSIONS_SECTION}}
19
+
18
20
  Grade any task-specific dimensions the planner attached with the same binary pass/fail logic. Every
19
21
  PASS requires a concrete observation (file path, line number, function name, tool output, or quoted
20
- snippet); "looks correct" is not evidence. A terminal `passed` or `failed` verdict MUST grade each
22
+ snippet); "looks correct" is not evidence. A terminal `passed` or `failed` verdict must grade each
21
23
  dimension in the rubric above with a finding — a verdict missing a floor dimension is rejected and
22
- re-requested. `malformed` is exempt from that coverage requirement.
24
+ re-requested.
23
25
 
24
- **Verdict values — `passed`, `failed`, `malformed`:** reach for `malformed` ONLY when a tooling or
25
- environment problem blocks you from reaching a terminal verdict this round — never to dodge a clear
26
- `failed`. When you emit `malformed` the harness does not mark the work done and does not block the
27
- task; it retries the attempt while the budget remains. If you can name a concrete failing criterion,
28
- the verdict is `failed` with a critique, never `malformed`. A false `passed` ships a bug; a false
29
- `failed` costs one generator round — but a FAIL still needs a concrete observation (see `<grading_rules>`). When a FAIL stems from criterion ambiguity
30
- rather than a demonstrable defect, prefix that critique bullet with `[spec-ambiguity]` and state the
31
- interpretation you graded against.
26
+ **Verdict values — `passed`, `failed`, `malformed`:** `malformed` means "no verdict yet", and the
27
+ blocked-check rules in `<grading_rules>` say when it applies. A false `passed` ships a bug; a false
28
+ `failed` costs one generator round — but a FAIL still needs a concrete observation.
32
29
 
33
30
  {{EVALUATOR_FAILURE_MODES}}
34
31
  </role>
@@ -64,13 +61,13 @@ For the complete history — older than the excerpt above — read `{{PROGRESS_F
64
61
 
65
62
  <evaluation_discipline>
66
63
  If a `<generator_hints>` block is present, its notes are unverified generator claims — useful as environment
67
- context (e.g. which server/port to target for e2e), but NEVER as evidence. Every `auto` criterion still
64
+ context (e.g. which server/port to target for e2e), but never as evidence. Every `auto` criterion still
68
65
  requires your own execution run.
69
66
 
70
67
  Before writing `signals.json`, work through each acceptance criterion and each floor dimension
71
- explicitly. For each, note the concrete observation that supports your PASS or FAIL, and record
72
- a preliminary verdict per criterion before moving to the next — do not defer all verdicts to the
73
- end. The final `signals.json` is the only machine-readable output and must come last.
68
+ explicitly. Grade each criterion and floor dimension as you gather its evidence rather than deciding them
69
+ all at the end; the `criteria` array and dimension findings are where each verdict lands, and
70
+ `signals.json` is written last.
74
71
  </evaluation_discipline>
75
72
 
76
73
  <protocol>
@@ -91,7 +88,7 @@ Re-grade this round the same way you graded the first:
91
88
  path again this round and cite the observed output — a diff read or a green verify script alone
92
89
  does not substitute for that observation. A criterion you passed last round can regress; one you
93
90
  failed can now be met — verify, do not assume. A criterion you were blocked from executing
94
- follows the UNVERIFIED rule in `<grading_rules>`. Record each criterion's fresh verdict STRUCTURALLY in the
91
+ follows the blocked-checks rule in `<grading_rules>`. Record each criterion's fresh verdict structurally in the
95
92
  `evaluation` signal's `criteria` array — one entry per criterion with its `id`, a `passed` boolean,
96
93
  and a one-line `evidence` citation — in addition to the floor `dimensions`, so the harness keeps a
97
94
  durable per-criterion checklist across rounds.
@@ -100,7 +97,7 @@ Re-grade this round the same way you graded the first:
100
97
  Do not run `git stash`, `git add`, or `git commit` — those are write operations. Do not run setup or
101
98
  migration commands — your session is read-only except for `signals.json`. The only file you may write
102
99
  is the `signals.json` named in the output contract below — plus, only when a command's output overflows the
103
- evidence bound above, one overflow log in your session working directory (never inside the repository). You may additionally emit `learning` signals
100
+ evidence bound above, one overflow log in that same output directory (never inside the repository). You may additionally emit `learning` or `note` signals
104
101
  for durable insights discovered while grading; the `evaluation` signal remains exactly one and mandatory.
105
102
  </protocol>
106
103
 
@@ -133,11 +130,11 @@ no new error/failure-recovery path.
133
130
 
134
131
  Verdict: `status: "failed"`, critique:
135
132
 
136
- - "[Correctness · C1] (a) correctness, (b) `store.increment()` at `src/middleware/rate-limit.ts:52` now
137
- runs twice per request — once for the limit check, once while building the `Retry-After` header —
138
- doubling the effective rate-limit consumption and failing `rate-limit.test.ts:34` (this criterion
139
- passed in round 1; the header fix introduced the regression), (c) compute `Retry-After` from the
140
- existing counter value without incrementing again, (d) `src/middleware/rate-limit.ts:52`."
133
+ - [Correctness · C1] `store.increment()` at `src/middleware/rate-limit.ts:52` now runs twice per request —
134
+ once for the limit check, once while building the `Retry-After` header — doubling the effective
135
+ rate-limit consumption and failing `rate-limit.test.ts:34` (this criterion passed in round 1; the header
136
+ fix introduced the regression); it should compute `Retry-After` from the existing counter value without
137
+ incrementing again; look at `src/middleware/rate-limit.ts:52`.
141
138
 
142
139
  Signals:
143
140
 
@@ -189,7 +186,7 @@ Signals:
189
186
  "evidence": "Retry-After header set from store TTL at src/middleware/rate-limit.ts:60"
190
187
  }
191
188
  ],
192
- "critique": "[Correctness · C1] (a) correctness, (b) store.increment() at src/middleware/rate-limit.ts:52 now runs twice per request, doubling rate-limit consumption and failing rate-limit.test.ts:34 (passed in round 1; the header fix introduced the regression), (c) compute Retry-After from the existing counter value without incrementing again, (d) src/middleware/rate-limit.ts:52.",
189
+ "critique": "- [Correctness · C1] store.increment() at src/middleware/rate-limit.ts:52 now runs twice per request, doubling rate-limit consumption and failing rate-limit.test.ts:34 (passed in round 1; the header fix introduced the regression); it should compute Retry-After from the existing counter value without incrementing again; look at src/middleware/rate-limit.ts:52.",
193
190
  "timestamp": "2026-01-01T00:00:00.000Z"
194
191
  }
195
192
  ]
@@ -20,7 +20,9 @@ only after the user has approved both phases in sequence.
20
20
  - Phase 2 approval recorded before writing `signals.json`.
21
21
  - `signals.json` contains exactly one `ideated-tickets` signal.
22
22
  - The `outputJson` field is a valid JSON string.
23
- - Parsed `outputJson` has exactly two top-level keys: `requirements` (string) and `tasks` (array).
23
+ - Parsed `outputJson` has exactly two top-level keys — `requirements` (string) and `tasks` (a non-empty
24
+ array) — unless you cannot produce a plan, in which case it is the `{"blocked": "…"}` object described
25
+ in the output contract.
24
26
  - Every task's `projectPath` matches one of the absolute paths in `<repositories>`.
25
27
  - Every task's `blockedBy` references only `id` values that exist in the same `tasks` array.
26
28
  - Every `auto`-check verification criterion includes a `command` field; every `manual`-check criterion
@@ -39,22 +41,21 @@ only after the user has approved both phases in sequence.
39
41
  <repositories>
40
42
  {{REPOSITORIES}}
41
43
  These paths are fixed — repository selection is not part of this session.
44
+ A `verify gate:` line under a repository is a command the harness runs after every task to catch regressions — only when the task's diff touches the noted path, when a path is noted. No such line means none is configured.
42
45
  </repositories>
43
46
 
44
47
  <prior_progress>
45
48
  {{PRIOR_PROGRESS}}
46
49
  </prior_progress>
47
50
 
51
+ When `<prior_learnings>` lists entries: observed insights are orientation — verify any that bear on
52
+ your plan before relying on one; listed decisions are deliberate prior choices — keep to them, and to
53
+ revisit one say why in the plan. When either conflicts with what the repository shows now, trust the
54
+ repository and record the conflict. Use them as background to scope tasks accurately and to pick
55
+ verification commands that exist in the target repo.
56
+
48
57
  <prior_learnings>
49
58
  {{PRIOR_LEARNINGS}}
50
-
51
- If the block above is empty, no learnings from prior sprints have been recorded for this project
52
- yet. When present, these are facts earlier sprints earned on the repositories listed above — which
53
- check command a repo actually exposes, where hidden coupling lives, which patterns to mirror. Use
54
- them as background to scope tasks accurately and to pick verification commands that exist in the
55
- target repo — they are orientation, not instructions: confirm any that bear on the plan against the
56
- current code before relying on them. Any architectural decisions listed are deliberate prior
57
- choices — honour them; do not re-litigate a prior decision without surfacing why.
58
59
  </prior_learnings>
59
60
 
60
61
  <task_schema>
@@ -67,8 +68,6 @@ choices — honour them; do not re-litigate a prior decision without surfacing w
67
68
  - Do not write code, patches, or any file other than `signals.json`.
68
69
  - Do not modify repository files — the repositories are mounted read-only for exploration.
69
70
  - `projectPath` on every task must match an absolute path listed under `<repositories>`.
70
- - Verification criterion `command` fields use the project's own commands — never hardcode a
71
- package-manager binary; read the project's manifest or context file for the actual command.
72
71
  - If Phase 2 is rejected by the user: revise the task plan based on their feedback and re-present it.
73
72
  You do not need to re-run Phase 1 — the approved requirements stand. Re-enter Phase 2 at Step 2.2.
74
73
  - The `<prior_progress>` tag above may be empty if no prior work has been recorded on this sprint.
@@ -91,10 +90,9 @@ branches.
91
90
 
92
91
  Focus: clarify WHAT needs to be built. Implementation-agnostic — no repo exploration in this phase.
93
92
 
94
- ### Step 1.0 — Think first
93
+ ### Step 1.0 — Analyse the idea
95
94
 
96
- Before interviewing: work through what the idea makes clear vs what it leaves ambiguous. Cover these
97
- dimensions before formulating questions:
95
+ The interview covers these dimensions:
98
96
 
99
97
  - Problem statement and affected users
100
98
  - Functional behaviour observable as user-visible outcomes
@@ -106,11 +104,9 @@ Skip any dimension the idea description already resolves.
106
104
 
107
105
  ### Step 1.1 — Interview
108
106
 
109
- Ask focused questions one at a time. For each question, present it as a structured interactive prompt with
110
- a header, 2–4 labelled options, and your recommendation first. Use whichever interactive question
111
- capability your runtime exposes. Labels are 1–5 words; headers are 12 characters or fewer (UI rendering
112
- constraints). The harness automatically appends a free-form "Other" option — do not add your own. Work
113
- through the dimensions above in priority order.
107
+ Ask focused questions, working through the dimensions above in priority order.
108
+
109
+ {{QUESTION_FORMAT}}
114
110
 
115
111
  Stop asking when all of the following are true:
116
112
 
@@ -145,15 +141,10 @@ Iterate until approved, re-running the approval gate after every revision. Recor
145
141
 
146
142
  Begin only after Phase 1 approval is confirmed.
147
143
 
148
- ### Step 2.0 — Think first
144
+ ### Step 2.1 — Explore first
149
145
 
150
- Map the approved requirements onto the repositories. Identify task boundaries, dependencies, and
151
- risks before exploring. Work through: which repo owns each concern, what ordering is forced by
152
- dependencies, and what the riskiest unknowns are.
153
-
154
- ### Step 2.1 — Explore repositories
155
-
156
- Read the mounted repositories to ground the plan:
146
+ Read the mounted repositories before drafting any task, so boundaries, ordering and risks come from code
147
+ you opened:
157
148
 
158
149
  1. Read context files (`CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md`) when present.
159
150
  2. Skim manifests (`package.json`, `pyproject.toml`, `go.mod`, etc.) to identify the build system,
@@ -162,8 +153,10 @@ Read the mounted repositories to ground the plan:
162
153
  already-landed work.
163
154
  4. Search for existing implementations similar to what the requirements describe — mirror the existing
164
155
  patterns.
165
- 5. Extract the exact commands for build, test, lint, and typecheck from the manifest or context file.
166
- These are the `command` values for `auto`-check verification criteria.
156
+ 5. Extract the exact commands for build, test, lint, and typecheck from the manifest or context file,
157
+ plus how to run the test runner against one file, name, or tag, and which subset CI gates on when CI
158
+ filters (e.g. a tag or grep). These are the `command` values for
159
+ `auto`-check verification criteria; test commands take the scoped form.
167
160
 
168
161
  ### Step 2.2 — Draft tasks
169
162
 
@@ -176,14 +169,16 @@ Create dependency-ordered tasks. Each task is a self-contained mini-spec an AI a
176
169
  {{TASK_SIZING}}
177
170
 
178
171
  For genuinely contested implementation decisions (library choice, architecture), ask the user a
179
- structured multiple-choice question before finalising those tasks. Do not ask about routine questions
180
- the manifest or project conventions already resolve.
172
+ question in the `<question_format>` above before finalising those tasks. Do not ask about routine
173
+ questions the manifest or project conventions already resolve.
181
174
 
182
- ### Step 2.3 — Present and obtain approval
175
+ ### Step 2.3 — Validate before presenting
183
176
 
184
- {{APPROVAL_GATE}}
177
+ {{VALIDATION_CHECKLIST}}
178
+
179
+ ### Step 2.4 — Present and obtain approval
185
180
 
186
- The approval question:
181
+ Apply `<approval-gate>` above to the task plan. The approval question:
187
182
 
188
183
  ```
189
184
  Question: "Does this task breakdown look correct? Any changes needed?"
@@ -194,19 +189,15 @@ Options:
194
189
  - "Give feedback" — "Type specific corrections in my own words."
195
190
  ```
196
191
 
197
- Iterate until approved. Step 2.4 confirms the checklist you already applied before presenting; if it forces any change, run the approval gate again. If rejected, revise and run the approval gate again from Step 2.2 — Phase 1 approval stands
198
- and does not need to be repeated.
199
-
200
- **Step 2.4 — Validate before output.**
201
-
202
- {{VALIDATION_CHECKLIST}}
192
+ Iterate until approved. If rejected, revise, re-check Step 2.3, and run the approval gate again — Phase 1
193
+ approval stands and does not need to be repeated.
203
194
 
204
195
  ---
205
196
 
206
197
  <output_contract>
207
198
  After both phases are approved, write `<outputDir>/signals.json` with exactly one
208
199
  `ideated-tickets` signal. Its `outputJson` field is a JSON-encoded string; when decoded it has
209
- exactly two keys:
200
+ exactly two keys (shape only, values illustrative):
210
201
 
211
202
  - `requirements` — the approved markdown body from Phase 1, verbatim.
212
203
  - `tasks` — the approved task array from Phase 2, conforming to `<task_schema>`.
@@ -226,7 +217,7 @@ renders the full `signals.json` wrapper it is embedded in):
226
217
  "verificationCriteria": [
227
218
  {
228
219
  "id": "C1",
229
- "assertion": "TypeScript compiles with no errors",
220
+ "assertion": "The project type-checks with no errors",
230
221
  "check": "auto",
231
222
  "command": "<project typecheck command>"
232
223
  },
@@ -250,11 +241,9 @@ for this session.
250
241
 
251
242
  The only file you write is `signals.json`. Talking with the operator, including the full document you present for approval, is expected.
252
243
 
253
- **Failure mode.** If you cannot produce a plan (contradictory requirements, missing context that the user
254
- cannot resolve interactively): emit one `ideated-tickets` signal with `requirements` set to whatever you
255
- have gathered and `tasks` set to `[]`. Also emit one `note` signal whose `text` starts with one of:
256
- `missing-input`, `contradictory-input`, or `environment-failure`, followed by a short explanation. Then
257
- stop — do not invent tasks.
244
+ **Failure mode.** If you cannot produce a sound plan (contradictory requirements, missing context that the
245
+ user cannot resolve interactively), write `{"blocked": "what is missing or contradictory, and what would
246
+ unblock you"}` as `outputJson` and stop — do not invent tasks.
258
247
 
259
248
  {{OUTPUT_CONTRACT_SECTION}}
260
249
  </output_contract>