@fro.bot/systematic 3.10.0 → 3.10.1

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: architecture-strategist
3
- description: "Analyzes code changes from an architectural perspective for pattern compliance and design integrity. Use when reviewing PRs, adding services, or evaluating structural refactors."
3
+ description: "Analyzes code changes from an architectural perspective for pattern compliance and design integrity. Use when reviewing PRs, adding services, or evaluating structural refactors. Dispatched by deepen-plan and ce-plan's deepening workflow, not by ce:review."
4
4
  tools: Read, Grep, Glob, Bash
5
5
  mode: subagent
6
6
  temperature: 0.1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: code-simplicity-reviewer
3
- description: "Final review pass to ensure code is as simple and minimal as possible. Use after implementation is complete to identify YAGNI violations and simplification opportunities."
3
+ description: "Final review pass to ensure code is as simple and minimal as possible. Use after implementation is complete to identify YAGNI violations and simplification opportunities. Dispatched by ce-compound for code-heavy issues, not by ce:review."
4
4
  tools: Read, Grep, Glob, Bash
5
5
  mode: subagent
6
6
  temperature: 0.1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pattern-recognition-specialist
3
- description: "Analyzes code for design patterns, anti-patterns, naming conventions, and duplication. Use when checking codebase consistency or verifying new code follows established patterns."
3
+ description: "Analyzes code for design patterns, anti-patterns, naming conventions, and duplication. Use when checking codebase consistency or verifying new code follows established patterns. Dispatched by deepen-plan, ce-plan's deepening workflow, and ce-compound, not by ce:review."
4
4
  tools: Read, Grep, Glob, Bash
5
5
  mode: subagent
6
6
  temperature: 0.6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.10.0",
3
+ "version": "3.10.1",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -64,7 +64,7 @@ All tokens are optional. Each one present means one less thing to infer. When ab
64
64
  - **Skip all user questions.** Never use the platform question tool (`question` in OpenCode, `request_user_input` in Codex, `ask_user` in Gemini; in Pi, use the blocking-question extension if available, otherwise present numbered options in chat and wait) or other interactive prompts. Infer intent conservatively if the diff metadata is thin.
65
65
  - **Require a determinable diff scope.** If headless mode cannot determine a diff scope (no branch, PR, or `base:` ref determinable without user interaction), emit `Review failed (headless mode). Reason: no diff scope detected. Re-invoke with a branch name, PR number, or base:<ref>.` and stop without dispatching agents.
66
66
  - **Apply only `safe_auto -> review-fixer` findings in a single pass.** No bounded re-review rounds. Leave `gated_auto`, `manual`, `human`, and `release` work unresolved and return them in the structured output.
67
- - **Return all non-auto findings as structured text output.** Use the headless output envelope format (see Stage 6 below) preserving severity, autofix_class, owner, requires_verification, confidence, pre_existing, and suggested_fix per finding. Enrich with detail-tier fields (why_it_matters, evidence[]) from the per-agent artifact files on disk (see Detail enrichment in Stage 6).
67
+ - **Return all non-auto findings as structured text output.** Use the headless output envelope format (see Stage 6 below) preserving severity, autofix_class, owner, requires_verification, confidence, pre_existing, and suggested_fix per finding. Enrich with detail-tier fields (why_it_matters, evidence[]) from the validated inline persona returns (see Detail enrichment in Stage 6).
68
68
  - **Write a run artifact** under `.context/systematic/ce-review/<run-id>/` summarizing findings, applied fixes, and advisory outputs. Include the artifact path in the structured output.
69
69
  - **Do not create todo files.** The caller receives structured findings and routes downstream work itself.
70
70
  - **Do not switch the shared checkout.** If the caller passes an explicit PR or branch target, `mode:headless` must run in an isolated checkout/worktree or stop instead of running `gh pr checkout` / `git checkout`. When stopping, emit `Review failed (headless mode). Reason: cannot switch shared checkout. Re-invoke with base:<ref> to review the current checkout, or run from an isolated worktree.`
@@ -383,16 +383,18 @@ The orchestrator (this skill) stays on the default model because it handles inte
383
383
 
384
384
  #### Run ID
385
385
 
386
- Generate a unique run identifier before dispatching any agents. This ID scopes all agent artifact files and the post-review run artifact to the same directory.
386
+ Generate a unique run identifier before dispatching any agents. This ID scopes the parent-owned per-agent records and the post-review run artifact to the same directory.
387
387
 
388
388
  ```bash
389
389
  RUN_ID=$(date +%Y%m%d-%H%M%S)-$(head -c4 /dev/urandom | od -An -tx1 | tr -d ' ')
390
390
  mkdir -p ".context/systematic/ce-review/$RUN_ID"
391
391
  ```
392
392
 
393
- Pass `{run_id}` to every persona sub-agent so they can write their full analysis to `.context/systematic/ce-review/{run_id}/{reviewer_name}.json`.
393
+ Keep `{run_id}` in the parent orchestrator. Do not pass it, an artifact path, or any write instruction to persona sub-agents. The parent writes a per-agent record only after the returned payload passes validation.
394
394
 
395
- **Report-only mode:** Skip run-id generation and directory creation. Do not pass `{run_id}` to agents. Agents return compact JSON only with no file write, consistent with report-only's no-write contract.
395
+ Capture the actual invoking harness once in the parent (`opencode`, `pi`, or `claude-code`). Do not infer it from persona metadata or declared tools. Add this parent-owned value to each persisted record and to the synthesis artifact so R6 remains explicit. `mode:report-only` still records nothing because it has no run artifact.
396
+
397
+ **Report-only mode:** Skip run-id generation and directory creation. Agents return the same full JSON payload, with no file write, consistent with report-only's no-write contract.
396
398
 
397
399
  #### Spawning
398
400
 
@@ -405,14 +407,14 @@ Spawn each selected persona reviewer as a parallel sub-agent using the subagent
405
407
  3. The JSON output contract from the findings schema included below
406
408
  4. PR metadata: title, body, and URL when reviewing a PR (empty string otherwise). Passed in a `<pr-context>` block so reviewers can verify code against stated intent
407
409
  5. Review context: intent summary, file list, diff
408
- 6. Run ID and reviewer name for the artifact file path
410
+ 6. Reviewer name for the returned `reviewer` field
409
411
  7. **For `project-standards` only:** the standards file path list from Stage 3b, wrapped in a `<standards-paths>` block appended to the review context
410
412
 
411
- Persona sub-agents are **read-only** with respect to the project: they review and return structured JSON. They do not edit project files or propose refactors. The one permitted write is saving their full analysis to the `.context/` artifact path specified in the output contract.
413
+ Persona sub-agents are **read-only** with respect to the project: they review and return structured JSON. They do not edit project files, write artifacts, or propose refactors. The parent orchestrator owns all persistence.
412
414
 
413
415
  Read-only here means **non-mutating**, not "no shell access." Reviewer sub-agents may use non-mutating inspection commands when needed to gather evidence or verify scope, including read-oriented `git` / `gh` usage such as `git diff`, `git show`, `git blame`, `git log`, and `gh pr view`. They must not edit project files, change branches, commit, push, create PRs, or otherwise mutate the checkout or repository state.
414
416
 
415
- Each persona sub-agent writes full JSON (all schema fields) to `.context/systematic/ce-review/{run_id}/{reviewer_name}.json` and returns compact JSON with merge-tier fields only:
417
+ Each persona sub-agent returns one full JSON payload (all schema fields) to the parent:
416
418
 
417
419
  ```json
418
420
  {
@@ -428,6 +430,10 @@ Each persona sub-agent writes full JSON (all schema fields) to `.context/systema
428
430
  "owner": "downstream-resolver",
429
431
  "requires_verification": true,
430
432
  "pre_existing": false,
433
+ "why_it_matters": "An unowned lookup can expose another account's orders.",
434
+ "evidence": [
435
+ "orders_controller.rb:42 uses params[:id] without an ownership guard."
436
+ ],
431
437
  "suggested_fix": "Add current_user.owns?(account) guard before lookup"
432
438
  }
433
439
  ],
@@ -436,7 +442,9 @@ Each persona sub-agent writes full JSON (all schema fields) to `.context/systema
436
442
  }
437
443
  ```
438
444
 
439
- Detail-tier fields (`why_it_matters`, `evidence`) are in the artifact file only. `suggested_fix` is optional in both tiers -- included in compact returns when present so the orchestrator has fix context for auto-apply decisions. If the file write fails, the compact return still provides everything the merge needs.
445
+ `why_it_matters` and `evidence` are returned inline with the merge-tier fields. `suggested_fix` remains optional. The parent validates the complete payload before writing any per-agent record; a malformed or rejected return is never partially persisted.
446
+
447
+ Returning the detail tier inline increases parent context per persona. The previous compact/detail split kept synthesis context lean, so this is an intentional cost of deleting the sub-agent write path. Verify it against a real multi-persona run. If it materially degrades synthesis, use a second targeted request per persona and keep the write parent-side; never restore sub-agent disk access.
440
448
 
441
449
  **CE always-on agents** (agent-native-reviewer, learnings-researcher) are dispatched as standard Agent calls in parallel with the persona agents. Give them the same review context bundle the personas receive: entry mode, any PR metadata gathered in Stage 1, intent summary, review base branch name when known, `BASE:` marker, file list, diff, and `UNTRACKED:` scope notes. Do not invoke them with a generic "review this" prompt. Their output is unstructured and synthesized separately in Stage 6.
442
450
 
@@ -444,22 +452,22 @@ Detail-tier fields (`why_it_matters`, `evidence`) are in the artifact file only.
444
452
 
445
453
  ### Stage 5: Merge findings
446
454
 
447
- Convert multiple reviewer compact JSON returns into one deduplicated, confidence-gated finding set. The compact returns contain merge-tier fields (title, severity, file, line, confidence, autofix_class, owner, requires_verification, pre_existing) plus the optional suggested_fix. Detail-tier fields (why_it_matters, evidence) are on disk in the per-agent artifact files and are not loaded at this stage.
448
-
449
- 1. **Validate.** Check each compact return for required top-level and per-finding fields, plus value constraints. Drop malformed returns or findings. Record the drop count.
450
- - **Top-level required:** reviewer (string), findings (array), residual_risks (array), testing_gaps (array). Drop the entire return if any are missing or wrong type.
451
- - **Per-finding required:** title, severity, file, line, confidence, autofix_class, owner, requires_verification, pre_existing
452
- - **Value constraints:**
453
- - severity: P0 | P1 | P2 | P3
454
- - autofix_class: safe_auto | gated_auto | manual | advisory
455
- - owner: review-fixer | downstream-resolver | human | release
456
- - confidence: numeric, 0.0-1.0
457
- - line: positive integer
458
- - pre_existing, requires_verification: boolean
459
- - Do not validate against the full schema here -- the full schema (including why_it_matters and evidence) applies to the artifact files on disk, not the compact returns.
460
- 2. **Confidence gate.** Suppress findings below 0.60 confidence. Exception: P0 findings at 0.50+ confidence survive the gate -- critical-but-uncertain issues must not be silently dropped. Record the suppressed count. This matches the persona instructions and the schema's confidence thresholds.
461
- 3. **Deduplicate.** Compute fingerprint: `normalize(file) + line_bucket(line, +/-3) + normalize(title)`. When fingerprints match, merge: keep highest severity, keep highest confidence, note which reviewers flagged it.
462
- 4. **Cross-reviewer agreement.** When 2+ independent reviewers flag the same issue (same fingerprint), boost the merged confidence by 0.10 (capped at 1.0). Cross-reviewer agreement is strong signal -- independent reviewers converging on the same issue is more reliable than any single reviewer's confidence. Note the agreement in the Reviewer column of the output (e.g., "security, correctness").
455
+ Convert multiple reviewer JSON returns into one deduplicated, confidence-gated finding set. Each persona return already contains both tiers. The parent must retain the validated payload in memory for merge and synthesis, then persist only the same validated data.
456
+
457
+ Before applying the confidence gate, assign every finding in a valid return a stable parent-owned `input_id` of `<reviewer>#<1-based finding index>`. Keep an input ledger through every later stage. The ledger is the authoritative reconciliation record in the synthesis artifact; it is not part of the persona's returned payload. If a return is rejected but its parsed `findings` array can be safely enumerated, assign IDs and record every enumerated input as `rejected`. If the return is malformed JSON or has no safely enumerable findings, record no synthetic input findings; the persona-level dispatch record and its exact safe rejection reason still record the rejection.
458
+
459
+ 1. **Validate before any write.** Treat every persona return as untrusted input. Parse the returned text as JSON without logging the raw text, then validate the complete parsed object against `references/findings-schema.json`, including `why_it_matters` and `evidence`.
460
+ - **Top-level required:** reviewer (string), findings (array), residual_risks (array), testing_gaps (array). Reject the entire persona return if any are missing or wrong type.
461
+ - **Per-finding required:** title, severity, file, line, why_it_matters, confidence, evidence, autofix_class, owner, requires_verification, pre_existing.
462
+ - **Schema constraints:** enforce every enum, type, confidence, line, path, evidence count, evidence length, and explicit overflow-marker bound from the schema. Empty evidence, absolute paths, and over-bound evidence are rejection cases, not truncation cases.
463
+ - **Environment-value detection:** JSON Schema cannot determine where a string came from, so recursively inspect every string leaf in the parsed payload before writing. Reject the payload when a string contains a shell/environment reference (`$NAME`, `${NAME}`, `process.env.NAME`, or `os.environ[...]`), an assignment using a known environment variable (`NAME=value`), or a current environment value as an exact or embedded match. Use a conservative match set of non-empty runtime environment values; never log the matched value. This detector is an additional parent-side check, not a schema claim.
464
+ - **Safe rejection message:** report only `Rejected persona <name> return: field <JSON path> failed <reason>.` Derive `<JSON path>` from the validator or recursive scan and use a fixed reason such as `schema validation`, `environment-value detection`, or `malformed JSON`; never include the offending value, raw return, or validator parameters.
465
+ - **No partial writes:** do not write a per-agent record or merge any finding until the entire persona payload passes schema and environment-value validation. A valid payload is then annotated by the parent with `harness` and `dispatch_outcome` and written by the parent only. Revalidate the enriched record before persistence.
466
+ - **Dispatch outcome:** a valid non-empty return is `findings`; a valid empty return is `empty`; invalid JSON or a rejected schema/environment payload is `malformed`; timeout or no return is `never_returned`. Keep these outcomes separate from finding `disposition`.
467
+ - **Rejection policy: degrade, do not fail the whole review.** Continue merging conforming returns, record the rejected persona's `dispatch_outcome` and safe rejection reason in the synthesis artifact, and give any rejected input the `rejected` disposition in the later reconciliation. If every persona fails or times out, use the existing degraded-review behavior. This preserves partial review coverage without ever persisting a non-conforming artifact; only an orchestration/storage failure that prevents the parent from producing its required run artifact is run-fatal.
468
+ 2. **Confidence gate.** Suppress findings below 0.60 confidence. Exception: P0 findings at 0.50+ confidence survive the gate -- critical-but-uncertain issues must not be silently dropped. Record the suppressed finding's original confidence and an explicit reason in the input ledger. A retained P0 at 0.50+ is recorded as `surviving` unless it later participates in a deduplication merge. This matches the persona instructions and the schema's confidence thresholds.
469
+ 3. **Deduplicate.** Compute fingerprint: `normalize(file) + line_bucket(line, +/-3) + normalize(title)`. When fingerprints match, merge: keep highest severity, keep highest confidence, preserve the exact fingerprint, and retain the input IDs that produced the merged entry. A singleton that passes the gate is `surviving`; each input in a multi-input merge is provisionally `merged`.
470
+ 4. **Cross-reviewer agreement.** When 2+ independent reviewers flag the same issue (same fingerprint), boost the merged confidence by 0.10 (capped at 1.0). Cross-reviewer agreement is strong signal -- independent reviewers converging on the same issue is more reliable than any single reviewer's confidence. Preserve the distinction in the merged finding's artifact provenance: `submitters` contains only personas with an input finding in that fingerprint group; `agreement_credit` contains only personas credited by the agreement boost without an input finding in that group. A persona with zero findings never appears in `submitters`. Do not infer submission from the report's Reviewer column.
463
471
  5. **Separate pre-existing.** Pull out findings with `pre_existing: true` into a separate list.
464
472
  6. **Resolve disagreements.** When reviewers flag the same code region but disagree on severity, autofix_class, or owner, annotate the Reviewer column with the disagreement (e.g., "security (P0), correctness (P1) -- kept P0"). This transparency helps the user understand why a finding was routed the way it was.
465
473
  7. **Normalize routing.** For each merged finding, set the final `autofix_class`, `owner`, and `requires_verification`. If reviewers disagree, keep the most conservative route. Synthesis may narrow a finding from `safe_auto` to `gated_auto` or `manual`, but must not widen it without new evidence.
@@ -470,10 +478,11 @@ Convert multiple reviewer compact JSON returns into one deduplicated, confidence
470
478
  9. **Sort.** Order by severity (P0 first) -> confidence (descending) -> file path -> line number.
471
479
  10. **Collect coverage data.** Union residual_risks and testing_gaps across reviewers.
472
480
  11. **Preserve CE agent artifacts.** Keep the learnings, agent-native, schema-drift, and deployment-verification outputs alongside the merged finding set. Do not drop unstructured agent output just because it does not match the persona JSON schema.
481
+ 12. **Keep the input ledger complete.** Every enumerated input finding has exactly one final disposition: `surviving`, `merged`, `suppressed`, `filtered`, or `rejected`, plus a reason. The ledger's disposition counts must sum to its input count. A rejected payload's reason is the exact safe rejection message produced by validation, not a bucket such as "invalid"; never include the offending value.
473
482
 
474
483
  ### Stage 5b: Validation pass
475
484
 
476
- Run an independent validation pass over the merged finding set before synthesis. This pass annotates each gated finding `validated: true` or `validated: false` with a one-sentence reason. It never deletes a finding findings with `validated: false` are surfaced in the "Filtered (not validated)" group in Stage 6, not removed from the report.
485
+ Run an independent validation pass over the merged finding set before synthesis. This pass annotates each gated finding `validated: true` or `validated: false` with a one-sentence reason. A `validated: false` finding is dropped from the surviving/actioned set and receives disposition `filtered`, but is retained in the synthesis artifact and surfaced in the "Filtered (not validated)" group in Stage 6. It is not erased from the record.
477
486
 
478
487
  **Gating band (default):** Validate only findings that are **P0 or P1 severity**, or that have `requires_verification: true`. Findings outside this band pass through to Stage 6 unvalidated and unfiltered — no validator is dispatched for them. This bounds cost: one validator subagent per gated finding.
479
488
 
@@ -482,9 +491,9 @@ Run an independent validation pass over the merged finding set before synthesis.
482
491
  1. Identify all gated findings from the Stage 5 merged set.
483
492
  2. For each gated finding, spawn one validator subagent in parallel using the validator template at `references/validator-template.md`. Pass the finding fields, the intent summary, the file list, and the full diff.
484
493
  3. Collect `{validated, reason}` from each validator. Attach both fields to the finding.
485
- 4. **Never drop a finding.** A finding with `validated: false` is routed to the "Filtered (not validated)" group for Stage 6 presentation. It is not removed from the report, not suppressed, and not excluded from the Coverage count.
486
- 5. Findings with `validated: true` flow through to Stage 6 unchanged — they appear in the normal severity tables.
487
- 6. Findings outside the gating band carry no `validated` annotation and appear in Stage 6 severity tables unchanged.
494
+ 4. **Reconcile filtered inputs.** A finding with `validated: false` moves to the "Filtered (not validated)" presentation group in Stage 6, and every input ID contributing to that merged finding is updated to disposition `filtered` with the validator's exact one-sentence reason. It is not `suppressed`, `rejected`, or silently excluded from the input ledger.
495
+ 5. Findings with `validated: true` flow through to Stage 6 unchanged — they appear in the normal severity tables. Their input ledger dispositions remain `surviving` for singleton findings or `merged` for deduplicated groups.
496
+ 6. Findings outside the gating band carry no `validated` annotation and appear in Stage 6 severity tables unchanged; their input ledger dispositions remain `surviving` or `merged`.
488
497
 
489
498
  **Failure handling:** If a validator subagent fails or times out, treat the finding as `validated: true` (conservative fallback — keep it in the actioned set) and note the validator failure in the Coverage section.
490
499
 
@@ -494,7 +503,7 @@ Run an independent validation pass over the merged finding set before synthesis.
494
503
 
495
504
  Assemble the final report using **pipe-delimited markdown tables for findings** from the review output template included below. The table format is mandatory for finding rows in interactive mode — do not render findings as freeform text blocks or horizontal-rule-separated prose. Other report sections (Applied Fixes, Learnings, Coverage, etc.) use bullet lists and the `---` separator before the verdict, as shown in the template.
496
505
 
497
- 1. **Header.** Scope, intent, mode, reviewer team with per-conditional justifications.
506
+ 1. **Header.** Scope, intent, mode, harness, reviewer team with per-conditional justifications.
498
507
  2. **Findings.** Rendered as pipe-delimited tables grouped by severity (`### P0 -- Critical`, `### P1 -- High`, `### P2 -- Moderate`, `### P3 -- Low`). Each finding row shows `#`, file, issue, reviewer(s), confidence, and synthesized route. Omit empty severity levels. Never render findings as freeform text blocks or numbered lists. Only findings with `validated: true` (or no `validated` annotation) appear in these tables.
499
508
  3. **Requirements Completeness.** Include only when a plan was found in Stage 2b. For each requirement (R1, R2, etc.) and implementation unit in the plan, report whether corresponding work appears in the diff. Use a simple checklist: met / not addressed / partially addressed. Routing depends on `plan_source`:
500
509
  - **`explicit`** (caller-provided or PR body): Flag unaddressed requirements as P1 findings with `autofix_class: manual`, `owner: downstream-resolver`. These enter the residual actionable queue and can become todos.
@@ -525,7 +534,7 @@ Scope: <scope-line>
525
534
  Intent: <intent-summary>
526
535
  Reviewers: <reviewer-list with conditional justifications>
527
536
  Verdict: <Ready to merge | Ready with fixes | Not ready>
528
- Artifact: .context/systematic/ce-review/<run-id>/
537
+ Artifact: .context/systematic/ce-review/<run-id>/review-summary.json
529
538
 
530
539
  Applied N safe_auto fixes.
531
540
 
@@ -583,15 +592,15 @@ Coverage:
583
592
  Review complete
584
593
  ```
585
594
 
586
- **Detail enrichment (headless only):** The headless envelope includes `Why:`, `Evidence:`, and `Suggested fix:` lines. After merge (Stage 5), read the per-agent artifact files from `.context/systematic/ce-review/{run_id}/` for only the findings that survived dedup and confidence gating.
587
- - **Field tiers:** `Why:` and `Evidence:` are detail-tier -- load from per-agent artifact files. `Suggested fix:` is merge-tier -- use it directly from the compact return without artifact lookup.
588
- - **Artifact matching:** For each surviving finding, look up its detail-tier fields in the artifact files of the contributing reviewers. Match on `file + line_bucket(line, +/-3)` (the same tolerance used in Stage 5 dedup) within each contributing reviewer's artifact. When multiple artifact entries fall within the line bucket, apply `normalize(title)` to both the merged finding's title and each candidate entry's title as a tie-breaker.
589
- - **Reviewer order:** Try contributing reviewers in the order they appear in the merged finding's reviewer list; use the first match.
590
- - **No-match fallback:** If no artifact file contains a match (all writes failed, or the finding was synthesized during merge), omit the `Why:` and `Evidence:` lines for that finding and note the gap in Coverage. The `Suggested fix:` line can still be populated from the compact return since it is merge-tier.
595
+ **Detail enrichment (headless only):** The headless envelope includes `Why:`, `Evidence:`, and `Suggested fix:` lines. After merge (Stage 5), use the validated full persona returns retained in parent memory for only the findings that survived dedup and confidence gating.
596
+ - **Field tiers:** `Why:` and `Evidence:` are detail-tier and are already present in the validated inline return. `Suggested fix:` is also available directly from that return and survives merge as optional fix context.
597
+ - **In-memory matching:** For each surviving finding, look up its detail-tier fields in the validated returns of the contributing reviewers. Match on `file + line_bucket(line, +/-3)` (the same tolerance used in Stage 5 dedup). When multiple entries fall within the line bucket, apply `normalize(title)` to the merged finding's title and each candidate entry's title as a tie-breaker.
598
+ - **Reviewer order:** Try contributing reviewers in the order they appear in the merged finding's reviewer list; use the first validated match.
599
+ - **No-match fallback:** If no validated in-memory return contains a match, omit the `Why:` and `Evidence:` lines for that finding and note the gap in Coverage. This should indicate a synthesis/matching gap, not a failed artifact-file write. Never re-read per-agent files to recover detail.
591
600
 
592
601
  **Formatting rules:**
593
602
  - The `[needs-verification]` marker appears only on findings where `requires_verification: true`.
594
- - The `Artifact:` line gives callers the path to the full run artifact for machine-readable access to the complete findings schema. The text envelope is the primary handoff; the artifact is for debugging and full-fidelity access.
603
+ - The `Artifact:` line gives callers the path to the parent-written `review-summary.json` for machine-readable access to the complete findings schema, provenance, dispatch outcomes, and disposition ledger. The text envelope is the primary handoff; the artifact is for debugging and full-fidelity access.
595
604
  - Findings with `owner: release` appear in the Advisory section (they are operational/rollout items, not code fixes).
596
605
  - Findings with `pre_existing: true` appear in the Pre-existing section regardless of autofix_class.
597
606
  - Findings with `validated: false` from Stage 5b appear in the "Filtered (not validated)" section. They are surfaced for human review — not removed. Include the validator reason on the indented `Validator reason:` line.
@@ -691,18 +700,22 @@ After presenting findings and verdict (Stage 6), route the next steps by mode. R
691
700
 
692
701
  #### Step 4: Emit artifacts and downstream handoff
693
702
 
694
- - In interactive, autofix, and headless modes, write a per-run artifact under `.context/systematic/ce-review/<run-id>/` containing:
695
- - synthesized findings (merged output from Stage 5)
696
- - applied fixes
697
- - residual actionable work
698
- - advisory-only outputs
699
- Per-agent full-detail JSON files (`{reviewer_name}.json`) are already present in this directory from Stage 4 dispatch.
703
+ - In interactive, autofix, and headless modes, write **`review-summary.json` unconditionally** under `.context/systematic/ce-review/<run-id>/`, including when every persona returns `empty` and there are zero surviving findings. `mode:report-only` remains exempt: it skips run-id and directory creation and writes nothing.
704
+ - `review-summary.json` is the parent-owned synthesis artifact and must contain, at minimum:
705
+ - `run_id`, `mode`, `harness` (`opencode`, `pi`, or `claude-code`), and run lifecycle fields;
706
+ - a `dispatches` entry for every selected persona with `persona`, `dispatch_outcome` (`findings`, `empty`, `malformed`, or `never_returned`), the number of safely enumerated input findings, and the exact safe `rejection_reason` when applicable;
707
+ - an `input_findings` ledger with one entry per safely enumerated input, its `input_id`, reviewer, original confidence, final `disposition` (`surviving`, `merged`, `suppressed`, `filtered`, or `rejected`), and a stated reason. Its count must reconcile exactly with the sum of disposition counts. A malformed JSON return with no safely enumerable finding has zero ledger entries, not a fabricated finding;
708
+ - surviving synthesized findings and filtered findings, each retaining their original fields plus `input_finding_ids` and provenance. Every synthesized finding's provenance must include the exact dedup `fingerprint`, `submitters`, and `agreement_credit` arrays. `submitters` means independent input submissions; `agreement_credit` means agreement boost credit without a corresponding input submission;
709
+ - applied fixes, residual actionable work, advisory-only outputs, coverage data, and the harness value.
710
+ - During the pre-dispatch setup described in Stage 4, initialize the synthesis artifact with lifecycle state `in_progress` and all selected personas initialized as `never_returned`. Update each dispatch entry as returns arrive. Finalize it as `completed` or `degraded` after synthesis; if the parent catches an abort or storage/orchestration failure, finalize it as `abnormal` with the stated termination reason. If the process dies before finalization, the pre-written `in_progress` artifact is itself an explicit incomplete run and must be counted as abnormal rather than treated as a missing or clean run. Never infer a clean run from an absent artifact.
711
+ - Per-agent full-detail JSON files (`{reviewer_name}.json`) are written by the parent only after the persona return passes full-schema and environment-value validation. Rejected or never-returned personas do not produce a per-agent file; their dispatch outcome remains in the synthesis artifact. If a later confidence or validation stage changes an input disposition, update the parent-owned record and synthesis ledger before finalizing `review-summary.json`.
700
712
  - Also write `metadata.json` alongside the findings so downstream skills can verify the artifact matches the current branch and HEAD. Minimum fields:
701
713
  ```json
702
714
  {
703
715
  "run_id": "<run-id>",
704
716
  "branch": "<git branch --show-current at dispatch time>",
705
717
  "head_sha": "<git rev-parse HEAD at dispatch time>",
718
+ "harness": "<opencode | pi | claude-code>",
706
719
  "verdict": "<Ready to merge | Ready with fixes | Not ready>",
707
720
  "completed_at": "<ISO 8601 UTC timestamp>"
708
721
  }
@@ -1,134 +1,338 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "title": "Code Review Findings",
4
- "description": "Structured output schema for code review sub-agents",
5
- "type": "object",
6
- "required": ["reviewer", "findings", "residual_risks", "testing_gaps"],
7
- "properties": {
8
- "reviewer": {
4
+ "description": "Structured output schemas for code review sub-agent returns and parent-persisted records",
5
+ "$ref": "#/definitions/parentRecord",
6
+ "definitions": {
7
+ "dispatchOutcome": {
9
8
  "type": "string",
10
- "description": "Persona name that produced this output (e.g., 'correctness', 'security')"
9
+ "enum": ["findings", "empty", "malformed", "never_returned"],
10
+ "description": "What a persona returned: findings, empty, malformed, or never returned"
11
11
  },
12
- "findings": {
13
- "type": "array",
14
- "description": "List of code review findings. Empty array if no issues found.",
15
- "items": {
16
- "type": "object",
17
- "required": [
18
- "title",
19
- "severity",
20
- "file",
21
- "line",
22
- "why_it_matters",
23
- "autofix_class",
24
- "owner",
25
- "requires_verification",
26
- "confidence",
27
- "evidence",
28
- "pre_existing"
29
- ],
30
- "properties": {
31
- "title": {
32
- "type": "string",
33
- "description": "Short, specific issue title. 10 words or fewer.",
34
- "maxLength": 100
35
- },
36
- "severity": {
37
- "type": "string",
38
- "enum": ["P0", "P1", "P2", "P3"],
39
- "description": "Issue severity level"
40
- },
41
- "file": {
42
- "type": "string",
43
- "description": "Relative file path from repository root"
44
- },
45
- "line": {
46
- "type": "integer",
47
- "description": "Primary line number of the issue",
48
- "minimum": 1
49
- },
50
- "why_it_matters": {
51
- "type": "string",
52
- "description": "Impact and failure mode -- not 'what is wrong' but 'what breaks'"
53
- },
54
- "autofix_class": {
12
+ "disposition": {
13
+ "type": "string",
14
+ "enum": ["surviving", "merged", "suppressed", "filtered", "rejected"],
15
+ "description": "What happened to an input finding: surviving, merged, suppressed, filtered, or rejected"
16
+ },
17
+ "harness": {
18
+ "type": "string",
19
+ "enum": ["opencode", "pi", "claude-code"],
20
+ "description": "Harness that produced the artifact; populated by the parent orchestrator"
21
+ },
22
+ "repoRelativePath": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "maxLength": 256,
26
+ "pattern": "^(?!/)(?![A-Za-z]:[\\\\/])(?!\\\\).+",
27
+ "description": "Relative file path from repository root; absolute POSIX, drive-letter, and UNC paths are rejected"
28
+ },
29
+ "boundedEvidenceString": {
30
+ "type": "string",
31
+ "minLength": 1,
32
+ "maxLength": 500,
33
+ "pattern": "^(?!/)(?![A-Za-z]:[\\\\/])(?!\\\\).+",
34
+ "description": "Bounded code-grounded evidence; absolute POSIX, drive-letter, and UNC paths are rejected"
35
+ },
36
+ "overflowExcerpt": {
37
+ "type": "string",
38
+ "minLength": 1,
39
+ "maxLength": 500,
40
+ "pattern": "^(?!/)(?![A-Za-z]:[\\\\/])(?!\\\\).+",
41
+ "description": "Bounded excerpt retained when evidence must be shortened"
42
+ },
43
+ "overflowEvidence": {
44
+ "type": "object",
45
+ "required": ["overflow", "excerpt"],
46
+ "properties": {
47
+ "overflow": {
48
+ "const": true,
49
+ "description": "Explicit marker that the complete evidence did not fit in one bounded entry"
50
+ },
51
+ "excerpt": {
52
+ "$ref": "#/definitions/overflowExcerpt"
53
+ }
54
+ },
55
+ "additionalProperties": false
56
+ },
57
+ "findingProperties": {
58
+ "type": "object",
59
+ "properties": {
60
+ "title": {
61
+ "type": "string",
62
+ "minLength": 1,
63
+ "maxLength": 256,
64
+ "pattern": "\\S",
65
+ "description": "Short, specific issue title. 10 words or fewer."
66
+ },
67
+ "severity": {
68
+ "type": "string",
69
+ "enum": ["P0", "P1", "P2", "P3"],
70
+ "description": "Issue severity level"
71
+ },
72
+ "file": {
73
+ "$ref": "#/definitions/repoRelativePath"
74
+ },
75
+ "line": {
76
+ "type": "integer",
77
+ "minimum": 1,
78
+ "description": "Primary line number of the issue"
79
+ },
80
+ "why_it_matters": {
81
+ "type": "string",
82
+ "minLength": 1,
83
+ "maxLength": 2048,
84
+ "pattern": "\\S",
85
+ "description": "Non-empty impact and failure mode -- not 'what is wrong' but 'what breaks'"
86
+ },
87
+ "autofix_class": {
88
+ "type": "string",
89
+ "enum": ["safe_auto", "gated_auto", "manual", "advisory"],
90
+ "description": "Reviewer's conservative recommendation for how this issue should be handled after synthesis"
91
+ },
92
+ "owner": {
93
+ "type": "string",
94
+ "enum": ["review-fixer", "downstream-resolver", "human", "release"],
95
+ "description": "Who should own the next action for this finding after synthesis"
96
+ },
97
+ "requires_verification": {
98
+ "type": "boolean",
99
+ "description": "Whether any fix for this finding must be re-verified with targeted tests or a follow-up review pass"
100
+ },
101
+ "suggested_fix": {
102
+ "type": ["string", "null"],
103
+ "maxLength": 2048,
104
+ "description": "Concrete minimal fix. Omit or null if no good fix is obvious -- a bad suggestion is worse than none."
105
+ },
106
+ "confidence": {
107
+ "type": "number",
108
+ "minimum": 0.0,
109
+ "maximum": 1.0,
110
+ "description": "Reviewer confidence in this finding, calibrated per persona"
111
+ },
112
+ "evidence": {
113
+ "type": "array",
114
+ "minItems": 1,
115
+ "maxItems": 5,
116
+ "description": "Code-grounded evidence. At least 1 and at most 5 bounded entries; split evidence across entries or use an explicit overflow marker rather than silently truncating it.",
117
+ "items": {
118
+ "oneOf": [
119
+ {
120
+ "$ref": "#/definitions/boundedEvidenceString"
121
+ },
122
+ {
123
+ "$ref": "#/definitions/overflowEvidence"
124
+ }
125
+ ]
126
+ }
127
+ },
128
+ "disposition": {
129
+ "$ref": "#/definitions/disposition"
130
+ },
131
+ "pre_existing": {
132
+ "type": "boolean",
133
+ "description": "True if this issue exists in unchanged code unrelated to the current diff"
134
+ }
135
+ }
136
+ },
137
+ "artifactProperties": {
138
+ "type": "object",
139
+ "properties": {
140
+ "reviewer": {
141
+ "type": "string",
142
+ "minLength": 1,
143
+ "maxLength": 64,
144
+ "pattern": "\\S",
145
+ "description": "Persona name that produced this output (e.g., 'correctness', 'security')"
146
+ },
147
+ "harness": {
148
+ "$ref": "#/definitions/harness"
149
+ },
150
+ "dispatch_outcome": {
151
+ "$ref": "#/definitions/dispatchOutcome"
152
+ },
153
+ "findings": {
154
+ "type": "array",
155
+ "maxItems": 32,
156
+ "description": "List of code review findings. Empty array if no issues found."
157
+ },
158
+ "residual_risks": {
159
+ "type": "array",
160
+ "maxItems": 64,
161
+ "description": "Risks the reviewer noticed but could not confirm as findings",
162
+ "items": {
55
163
  "type": "string",
56
- "enum": ["safe_auto", "gated_auto", "manual", "advisory"],
57
- "description": "Reviewer's conservative recommendation for how this issue should be handled after synthesis"
58
- },
59
- "owner": {
164
+ "maxLength": 1024
165
+ }
166
+ },
167
+ "testing_gaps": {
168
+ "type": "array",
169
+ "maxItems": 64,
170
+ "description": "Missing test coverage the reviewer identified",
171
+ "items": {
60
172
  "type": "string",
61
- "enum": ["review-fixer", "downstream-resolver", "human", "release"],
62
- "description": "Who should own the next action for this finding after synthesis"
63
- },
64
- "requires_verification": {
65
- "type": "boolean",
66
- "description": "Whether any fix for this finding must be re-verified with targeted tests or a follow-up review pass"
67
- },
68
- "suggested_fix": {
69
- "type": ["string", "null"],
70
- "description": "Concrete minimal fix. Omit or null if no good fix is obvious -- a bad suggestion is worse than none."
71
- },
72
- "confidence": {
73
- "type": "number",
74
- "description": "Reviewer confidence in this finding, calibrated per persona",
75
- "minimum": 0.0,
76
- "maximum": 1.0
77
- },
78
- "evidence": {
79
- "type": "array",
80
- "description": "Code-grounded evidence: snippets, line references, or pattern descriptions. At least 1 item.",
81
- "items": { "type": "string" },
82
- "minItems": 1
83
- },
84
- "pre_existing": {
85
- "type": "boolean",
86
- "description": "True if this issue exists in unchanged code unrelated to the current diff"
173
+ "maxLength": 1024
87
174
  }
88
175
  }
89
176
  }
90
177
  },
91
- "residual_risks": {
92
- "type": "array",
93
- "description": "Risks the reviewer noticed but could not confirm as findings",
94
- "items": { "type": "string" }
95
- },
96
- "testing_gaps": {
97
- "type": "array",
98
- "description": "Missing test coverage the reviewer identified",
99
- "items": { "type": "string" }
100
- }
101
- },
102
-
103
- "_meta": {
104
- "confidence_thresholds": {
105
- "suppress": "Below 0.60 -- do not report. Finding is speculative noise. Exception: P0 findings at 0.50+ may be reported.",
106
- "flag": "0.60-0.69 -- include only when the issue is clearly actionable with concrete evidence.",
107
- "confident": "0.70-0.84 -- real and important. Report with full evidence.",
108
- "certain": "0.85-1.00 -- verifiable from the code alone. Report."
109
- },
110
- "severity_definitions": {
111
- "P0": "Critical breakage, exploitable vulnerability, data loss/corruption. Must fix before merge.",
112
- "P1": "High-impact defect likely hit in normal usage, breaking contract. Should fix.",
113
- "P2": "Moderate issue with meaningful downside (edge case, perf regression, maintainability trap). Fix if straightforward.",
114
- "P3": "Low-impact, narrow scope, minor improvement. User's discretion."
178
+ "subAgentFinding": {
179
+ "type": "object",
180
+ "required": [
181
+ "title",
182
+ "severity",
183
+ "file",
184
+ "line",
185
+ "why_it_matters",
186
+ "autofix_class",
187
+ "owner",
188
+ "requires_verification",
189
+ "confidence",
190
+ "evidence",
191
+ "pre_existing"
192
+ ],
193
+ "properties": {
194
+ "title": { "$ref": "#/definitions/findingProperties/properties/title" },
195
+ "severity": {
196
+ "$ref": "#/definitions/findingProperties/properties/severity"
197
+ },
198
+ "file": { "$ref": "#/definitions/findingProperties/properties/file" },
199
+ "line": { "$ref": "#/definitions/findingProperties/properties/line" },
200
+ "why_it_matters": {
201
+ "$ref": "#/definitions/findingProperties/properties/why_it_matters"
202
+ },
203
+ "autofix_class": {
204
+ "$ref": "#/definitions/findingProperties/properties/autofix_class"
205
+ },
206
+ "owner": { "$ref": "#/definitions/findingProperties/properties/owner" },
207
+ "requires_verification": {
208
+ "$ref": "#/definitions/findingProperties/properties/requires_verification"
209
+ },
210
+ "suggested_fix": {
211
+ "$ref": "#/definitions/findingProperties/properties/suggested_fix"
212
+ },
213
+ "confidence": {
214
+ "$ref": "#/definitions/findingProperties/properties/confidence"
215
+ },
216
+ "evidence": {
217
+ "$ref": "#/definitions/findingProperties/properties/evidence"
218
+ },
219
+ "pre_existing": {
220
+ "$ref": "#/definitions/findingProperties/properties/pre_existing"
221
+ }
222
+ },
223
+ "additionalProperties": false
115
224
  },
116
- "autofix_classes": {
117
- "safe_auto": "Local, deterministic code or test fix suitable for the in-skill fixer. Examples: extract duplicated helper, add missing nil check, fix off-by-one, add missing test, remove dead code. Do not default to advisory when a concrete safe fix exists.",
118
- "gated_auto": "Concrete fix exists, but it changes behavior, permissions, contracts, or other sensitive areas that deserve explicit approval. Examples: add auth to unprotected endpoint, change API response shape.",
119
- "manual": "Actionable issue that requires design decisions or cross-cutting changes. Examples: redesign data model, add pagination strategy, choose between architectural approaches.",
120
- "advisory": "Informational or operational item that should be surfaced in the report only. Examples: design asymmetry the PR improves but does not fully resolve, residual risk notes, deployment considerations."
225
+ "parentFinding": {
226
+ "type": "object",
227
+ "required": [
228
+ "title",
229
+ "severity",
230
+ "file",
231
+ "line",
232
+ "why_it_matters",
233
+ "autofix_class",
234
+ "owner",
235
+ "requires_verification",
236
+ "confidence",
237
+ "evidence",
238
+ "disposition",
239
+ "pre_existing"
240
+ ],
241
+ "properties": {
242
+ "title": { "$ref": "#/definitions/findingProperties/properties/title" },
243
+ "severity": {
244
+ "$ref": "#/definitions/findingProperties/properties/severity"
245
+ },
246
+ "file": { "$ref": "#/definitions/findingProperties/properties/file" },
247
+ "line": { "$ref": "#/definitions/findingProperties/properties/line" },
248
+ "why_it_matters": {
249
+ "$ref": "#/definitions/findingProperties/properties/why_it_matters"
250
+ },
251
+ "autofix_class": {
252
+ "$ref": "#/definitions/findingProperties/properties/autofix_class"
253
+ },
254
+ "owner": { "$ref": "#/definitions/findingProperties/properties/owner" },
255
+ "requires_verification": {
256
+ "$ref": "#/definitions/findingProperties/properties/requires_verification"
257
+ },
258
+ "suggested_fix": {
259
+ "$ref": "#/definitions/findingProperties/properties/suggested_fix"
260
+ },
261
+ "confidence": {
262
+ "$ref": "#/definitions/findingProperties/properties/confidence"
263
+ },
264
+ "evidence": {
265
+ "$ref": "#/definitions/findingProperties/properties/evidence"
266
+ },
267
+ "disposition": {
268
+ "$ref": "#/definitions/findingProperties/properties/disposition"
269
+ },
270
+ "pre_existing": {
271
+ "$ref": "#/definitions/findingProperties/properties/pre_existing"
272
+ }
273
+ },
274
+ "additionalProperties": false
121
275
  },
122
- "owners": {
123
- "review-fixer": "The in-skill fixer can own this when policy allows.",
124
- "downstream-resolver": "Turn this into residual work for later resolution.",
125
- "human": "A person must make a judgment call before code changes should continue.",
126
- "release": "Operational or rollout follow-up; do not convert into code-fix work automatically."
276
+ "subAgentReturn": {
277
+ "type": "object",
278
+ "required": ["reviewer", "findings", "residual_risks", "testing_gaps"],
279
+ "properties": {
280
+ "reviewer": {
281
+ "$ref": "#/definitions/artifactProperties/properties/reviewer"
282
+ },
283
+ "findings": {
284
+ "allOf": [
285
+ { "$ref": "#/definitions/artifactProperties/properties/findings" },
286
+ {
287
+ "items": { "$ref": "#/definitions/subAgentFinding" }
288
+ }
289
+ ]
290
+ },
291
+ "residual_risks": {
292
+ "$ref": "#/definitions/artifactProperties/properties/residual_risks"
293
+ },
294
+ "testing_gaps": {
295
+ "$ref": "#/definitions/artifactProperties/properties/testing_gaps"
296
+ }
297
+ },
298
+ "additionalProperties": false
127
299
  },
128
- "return_tiers": {
129
- "description": "Finding fields are split into two tiers. The full schema (with all required fields) applies to the artifact file on disk. The compact return to the orchestrator omits detail-tier fields. Both are valid uses of this schema in different contexts.",
130
- "merge_tier": "Returned to orchestrator: title, severity, file, line, confidence, autofix_class, owner, requires_verification, pre_existing, suggested_fix (optional). Plus top-level reviewer, residual_risks, testing_gaps.",
131
- "detail_tier": "Required in artifact file, omitted from compact return: why_it_matters, evidence. The artifact file must pass full schema validation including all required fields. Headless output depends on why_it_matters and evidence being present in the artifact."
300
+ "parentRecord": {
301
+ "type": "object",
302
+ "required": [
303
+ "reviewer",
304
+ "harness",
305
+ "dispatch_outcome",
306
+ "findings",
307
+ "residual_risks",
308
+ "testing_gaps"
309
+ ],
310
+ "properties": {
311
+ "reviewer": {
312
+ "$ref": "#/definitions/artifactProperties/properties/reviewer"
313
+ },
314
+ "harness": {
315
+ "$ref": "#/definitions/artifactProperties/properties/harness"
316
+ },
317
+ "dispatch_outcome": {
318
+ "$ref": "#/definitions/artifactProperties/properties/dispatch_outcome"
319
+ },
320
+ "findings": {
321
+ "allOf": [
322
+ { "$ref": "#/definitions/artifactProperties/properties/findings" },
323
+ {
324
+ "items": { "$ref": "#/definitions/parentFinding" }
325
+ }
326
+ ]
327
+ },
328
+ "residual_risks": {
329
+ "$ref": "#/definitions/artifactProperties/properties/residual_risks"
330
+ },
331
+ "testing_gaps": {
332
+ "$ref": "#/definitions/artifactProperties/properties/testing_gaps"
333
+ }
334
+ },
335
+ "additionalProperties": false
132
336
  }
133
337
  }
134
338
  }
@@ -2,6 +2,14 @@
2
2
 
3
3
  13 reviewer personas organized into always-on, cross-cutting conditional, and stack-specific conditional layers, plus CE-specific agents. The orchestrator uses this catalog to select which reviewers to spawn for each review.
4
4
 
5
+ ## Shared persona pool
6
+
7
+ The `agents/review/` directory is a shared persona pool, not `ce:review`'s roster. Directory placement does not imply that a persona is selectable by `ce:review`. These shared personas are dispatched by other workflows and intentionally do not appear in this catalog's `ce:review` selection tables:
8
+
9
+ - `systematic:review:architecture-strategist` — dispatched by `deepen-plan` and `ce-plan`'s deepening workflow for architectural analysis.
10
+ - `systematic:review:pattern-recognition-specialist` — dispatched by `deepen-plan`, `ce-plan`'s deepening workflow, and `ce-compound` for consistency, duplication, and pattern analysis.
11
+ - `systematic:review:code-simplicity-reviewer` — dispatched by `ce-compound` for code-heavy issues.
12
+
5
13
  ## Always-on (4 personas + 2 CE agents)
6
14
 
7
15
  Spawned on every review regardless of diff content.
@@ -14,6 +14,7 @@ Use this **exact format** when presenting synthesized review findings. Findings
14
14
  **Mode:** autofix
15
15
 
16
16
  **Reviewers:** correctness, testing, maintainability, security, api-contract
17
+ - **Harness:** opencode
17
18
  - security -- new public endpoint accepts user-provided format parameter
18
19
  - api-contract -- new /api/orders/export route with response schema
19
20
 
@@ -124,7 +125,7 @@ This fails because: no pipe-delimited tables, no severity-grouped `###` headers,
124
125
  - **Pipe-delimited markdown tables** for findings -- never ASCII box-drawing characters or per-finding horizontal-rule separators between entries (the report-level `---` before the verdict is still required)
125
126
  - **Severity-grouped sections** -- `### P0 -- Critical`, `### P1 -- High`, `### P2 -- Moderate`, `### P3 -- Low`. Omit empty severity levels.
126
127
  - **Always include file:line location** for code review issues
127
- - **Reviewer column** shows which persona(s) flagged the issue. Multiple reviewers = cross-reviewer agreement.
128
+ - **Reviewer column** shows which persona(s) submitted the issue. Multiple reviewers indicate independent submissions, not merely agreement credit. The machine-readable synthesis artifact keeps `submitters` separate from `agreement_credit`; do not infer submission from an agreement boost or from the display column alone.
128
129
  - **Confidence column** shows the finding's confidence score
129
130
  - **Route column** shows the synthesized handling decision as ``<autofix_class> -> <owner>``.
130
131
  - **Header includes** scope, intent, and reviewer team with per-conditional justifications
@@ -136,7 +137,7 @@ This fails because: no pipe-delimited tables, no severity-grouped `###` headers,
136
137
  - **Learnings & Past Solutions section** -- results from learnings-researcher, with links to docs/solutions/ files
137
138
  - **Agent-Native Gaps section** -- results from agent-native-reviewer. Omit if no gaps found.
138
139
  - **Deployment Notes section** -- key checklist items from deployment-verification-agent. Omit if the agent did not run.
139
- - **Coverage section** -- suppressed count, residual risks, testing gaps, failed reviewers
140
+ - **Coverage section** -- suppressed count with original confidences, residual risks, testing gaps, failed reviewers, and disposition reconciliation
140
141
  - **Summary uses blockquotes** for verdict, reasoning, and fix order
141
142
  - **Horizontal rule** (`---`) separates findings from verdict
142
143
  - **`###` headers** for each section -- never plain text headers
@@ -148,8 +149,69 @@ In `mode:headless`, replace the interactive pipe-delimited table report with a s
148
149
  - **No pipe-delimited tables.** Findings use `[severity][autofix_class -> owner] File: <file:line> -- <title>` line format with indented Why/Evidence/Suggested fix lines.
149
150
  - **Findings grouped by autofix_class** (gated-auto, manual, advisory) instead of severity. Within each group, findings are sorted by severity.
150
151
  - **Verdict in header** (top of output) instead of bottom, so programmatic callers get it first.
151
- - **`Artifact:` line** in metadata header gives callers the path to the full run artifact.
152
+ - **`Artifact:` line** in metadata header gives callers the path to `review-summary.json`, the full run artifact with provenance, dispatch outcomes, and disposition reconciliation.
152
153
  - **`[needs-verification]` marker** on findings where `requires_verification: true`.
153
154
  - **Evidence lines** included per finding.
154
155
  - **"Filtered (not validated)" section** included when Stage 5b produced findings with `validated: false`. Uses `[severity][autofix_class -> owner] File: <file:line> -- <title>` format with an indented `Validator reason:` line. These findings are surfaced for human review, not removed.
155
156
  - **Completion signal:** "Review complete" as the final line.
157
+
158
+ ## Synthesis Artifact Contract
159
+
160
+ For interactive, autofix, and headless runs, the parent writes `.context/systematic/ce-review/<run-id>/review-summary.json` even when every selected persona returns `empty` and no finding survives. `mode:report-only` is the deliberate no-write exception.
161
+
162
+ The artifact must preserve the following distinctions:
163
+
164
+ ```json
165
+ {
166
+ "run_id": "<run-id>",
167
+ "mode": "<interactive | autofix | headless>",
168
+ "harness": "<opencode | pi | claude-code>",
169
+ "run_status": "<in_progress | completed | degraded | abnormal>",
170
+ "dispatches": [
171
+ {
172
+ "persona": "correctness",
173
+ "dispatch_outcome": "findings",
174
+ "input_finding_count": 2
175
+ },
176
+ {
177
+ "persona": "kieran-typescript",
178
+ "dispatch_outcome": "malformed",
179
+ "input_finding_count": 1,
180
+ "rejection_reason": "Rejected persona kieran-typescript return: field findings[0].evidence failed schema validation."
181
+ }
182
+ ],
183
+ "input_findings": [
184
+ {
185
+ "input_id": "correctness#1",
186
+ "reviewer": "correctness",
187
+ "confidence": 0.55,
188
+ "disposition": "suppressed",
189
+ "reason": "confidence 0.55 is below the 0.60 gate"
190
+ }
191
+ ],
192
+ "findings": [
193
+ {
194
+ "title": "<merged finding>",
195
+ "input_finding_ids": ["correctness#2", "testing#1"],
196
+ "provenance": {
197
+ "fingerprint": "<normalize(file) + line_bucket(line, +/-3) + normalize(title)>",
198
+ "submitters": ["correctness", "testing"],
199
+ "agreement_credit": []
200
+ }
201
+ }
202
+ ],
203
+ "disposition_counts": {
204
+ "surviving": 0,
205
+ "merged": 2,
206
+ "suppressed": 1,
207
+ "filtered": 0,
208
+ "rejected": 0
209
+ }
210
+ }
211
+ ```
212
+
213
+ - `dispatch_outcome` records what a persona returned: `findings`, `empty`, `malformed`, or `never_returned`. A rejection reason is preserved as the exact safe validation reason, naming persona and field without echoing the offending value.
214
+ - `disposition` records what happened to each input finding: `surviving`, `merged`, `suppressed`, `filtered`, or `rejected`. Every safely enumerable input has exactly one disposition and stated reason; the disposition counts must equal the input-finding count.
215
+ - `submitters` contains only personas with an input finding in the merged fingerprint group. `agreement_credit` contains only personas credited by the cross-reviewer agreement boost without an input finding in that group. A persona returning zero findings never appears in `submitters`.
216
+ - `filtered` findings remain available for human review with the validator's stated reason, but are not part of the surviving/actioned set. A suppressed finding retains its original confidence, including the P0 exception for confidence `0.50` or higher.
217
+ - The parent initializes the artifact as `in_progress` before dispatch. A completed run becomes `completed` or `degraded`; an interrupted or failed run is `abnormal` with its stated termination reason. An unfinished `in_progress` artifact is evidence of an abnormal run, not evidence of a clean run.
@@ -22,23 +22,11 @@ The supplied diff is the primary source of truth. Use the supplied paths and lin
22
22
  </bounded-investigation>
23
23
 
24
24
  <output-contract>
25
- You produce up to two outputs depending on whether a run ID was provided:
25
+ Return exactly one JSON payload to the parent. The payload contains the complete schema for every finding, including both the merge tier and the detail tier (`why_it_matters`, `evidence`, and `suggested_fix` when present).
26
26
 
27
- 1. **Artifact file (when run ID is present).** If a Run ID appears in <review-context> below, WRITE your full analysis (all schema fields, including why_it_matters, evidence, and suggested_fix) as JSON to:
28
- .context/systematic/ce-review/{run_id}/{reviewer_name}.json
29
- This is the ONE write operation you are permitted to make. Use the platform's file-write tool.
30
- If the write fails, continue -- the compact return still provides everything the merge needs.
31
- If no Run ID is provided (the field is empty or absent), skip this step entirely -- do not attempt any file write.
27
+ Do not write any file. Do not use a Run ID or an artifact path. Persistence is owned by the parent orchestrator: it validates this returned payload, adds parent-owned provenance, and writes only conforming data. This rule is the same in every supported harness.
32
28
 
33
- 2. **Compact return (always).** RETURN compact JSON to the parent with ONLY merge-tier fields per finding:
34
- title, severity, file, line, confidence, autofix_class, owner, requires_verification, pre_existing, suggested_fix.
35
- Do NOT include why_it_matters or evidence in the returned JSON.
36
- Include reviewer, residual_risks, and testing_gaps at the top level.
37
-
38
- The full file preserves detail for downstream consumers (headless output, debugging).
39
- The compact return keeps the orchestrator's context lean for merge and synthesis.
40
-
41
- The schema below describes the **full artifact file format** (all fields required). For the compact return, follow the field list above -- omit why_it_matters and evidence even though the schema marks them as required.
29
+ The schema below defines the payload's fields and bounds. Its transport is inline for this contract; any schema metadata describing a compact return or a separate detail artifact is superseded by this output contract.
42
30
 
43
31
  {schema}
44
32
 
@@ -62,9 +50,12 @@ False-positive categories to actively suppress:
62
50
 
63
51
  Rules:
64
52
  - You are a leaf reviewer inside an already-running systematic review workflow. Do not invoke systematic skills or agents unless this template explicitly instructs you to. Perform your analysis directly and return findings in the required output format only.
65
- - Every finding in the full artifact file MUST include at least one evidence item grounded in the actual code. The compact return omits evidence -- the evidence requirement applies to the disk artifact only.
53
+ - Every returned finding MUST include at least one evidence item grounded in the actual code. Detail fields are part of the returned payload, not a second output.
54
+ - Evidence is bounded to at most 5 entries of at most 500 characters each. Split a longer trail across entries when it fits; otherwise retain a bounded `excerpt` with `{ "overflow": true, "excerpt": "..." }`. Never silently truncate evidence.
55
+ - Finding paths MUST be repository-relative. The schema rejects absolute paths, while the parent-side validator in Unit 3 detects environment values because JSON Schema cannot infer where a string came from.
56
+ - The parent adds `harness`, `dispatch_outcome`, and `disposition` after validating the return. Do not invent those parent-owned fields. The parent uses only the canonical values defined by the schema (`findings`, `empty`, `malformed`, `never_returned` and `surviving`, `merged`, `suppressed`, `filtered`, `rejected`).
66
57
  - Set pre_existing to true ONLY for issues in unchanged code that are unrelated to this diff. If the diff makes the issue newly relevant, it is NOT pre-existing.
67
- - You are operationally read-only. The one permitted exception is writing your full analysis to the `.context/` artifact path when a run ID is provided. You may also use non-mutating inspection commands, including read-oriented `git` / `gh` commands, to gather evidence. Do not edit project files, change branches, commit, push, create PRs, or otherwise mutate the checkout or repository state.
58
+ - You are operationally read-only. You may use non-mutating inspection commands, including read-oriented `git` / `gh` commands, to gather evidence. Do not write files, edit project files, change branches, commit, push, create PRs, or otherwise mutate the checkout or repository state.
68
59
  - Set `autofix_class` accurately -- not every finding is `advisory`. Use this decision guide:
69
60
  - `safe_auto`: The fix is local and deterministic — the fixer can apply it mechanically without design judgment. Examples: extracting a duplicated helper, adding a missing nil/null check, fixing an off-by-one, adding a missing test for an untested code path, removing dead code.
70
61
  - `gated_auto`: A concrete fix exists but it changes contracts, permissions, or crosses a module boundary in a way that deserves explicit approval. Examples: adding authentication to an unprotected endpoint, changing a public API response shape, switching from soft-delete to hard-delete.
@@ -83,7 +74,6 @@ Rules:
83
74
  </pr-context>
84
75
 
85
76
  <review-context>
86
- Run ID: {run_id}
87
77
  Reviewer name: {reviewer_name}
88
78
 
89
79
  Intent: {intent_summary}
@@ -106,5 +96,4 @@ Diff:
106
96
  | `{pr_metadata}` | Stage 1 output | PR title, body, and URL when reviewing a PR. Empty string when reviewing a branch or standalone checkout |
107
97
  | `{file_list}` | Stage 1 output | List of changed files from the scope step |
108
98
  | `{diff}` | Stage 1 output | The actual diff content to review |
109
- | `{run_id}` | Stage 4 output | Unique review run identifier for the artifact directory |
110
- | `{reviewer_name}` | Stage 3 output | Persona or agent name used as the artifact filename stem |
99
+ | `{reviewer_name}` | Stage 3 output | Persona name used in the returned `reviewer` field |