@fro.bot/systematic 3.18.2 → 3.18.4
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.
- package/HARNESSES.md +8 -4
- package/dist/ce-review-validator.d.ts +43 -2
- package/dist/cli.js +12 -18
- package/dist/{index-nrgffx9y.js → index-be0zwq50.js} +26 -26
- package/dist/index.js +1 -1
- package/dist/lib/review-artifact-schema.d.ts +18 -1
- package/dist/lib/review-pipeline-contract.d.ts +1446 -0
- package/dist/lib/review-pipeline.d.ts +812 -0
- package/dist/lib/review-return-validator.d.ts +19 -0
- package/dist/pi.js +26 -26
- package/package.json +3 -3
- package/skills/ce-review/SKILL.md +54 -83
- package/skills/ce-review/references/pipeline-invocation.md +263 -0
- package/skills/ce-review/references/review-output-template.md +2 -1
- package/skills/ce-review/references/review-pipeline-schema.json +391 -0
- package/skills/ce-review/references/subagent-template.md +1 -1
- package/skills/ce-review/references/synthesis-artifact-contract.md +57 -68
- package/skills/ce-review/scripts/validate-review.mjs +3305 -86
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Pipeline Phase Invocation
|
|
2
|
+
|
|
3
|
+
This is the canonical invocation detail for the four pure stdin phases of the
|
|
4
|
+
packaged validator shim that `ce:review`'s Stage 4-6 and post-review handoff
|
|
5
|
+
call at their decision boundaries: `screen`, `prepare`, `merge`, and
|
|
6
|
+
`finalize`. `SKILL.md` keeps
|
|
7
|
+
terse call sites; this document carries the envelope shapes and the full
|
|
8
|
+
invocation blocks. `return` and `artifact` are unchanged and documented at
|
|
9
|
+
their existing call sites (Stage 4 raw-return history and the
|
|
10
|
+
[synthesis artifact contract](./synthesis-artifact-contract.md)).
|
|
11
|
+
|
|
12
|
+
Every block below reassigns `SKILL_DIR` in the same fenced block, terminated
|
|
13
|
+
with `;`, and invokes `node "$SKILL_DIR/scripts/validate-review.mjs" <phase>`
|
|
14
|
+
-- never a bare relative path, and never a Claude-only path substitution
|
|
15
|
+
(off-Claude harnesses would silently expand it to nothing).
|
|
16
|
+
|
|
17
|
+
## Never-bypass
|
|
18
|
+
|
|
19
|
+
A helper failure (exit 1 or exit 2) is never permission to hand-synthesize
|
|
20
|
+
the phase's output. On exit 2 (usage error, TTY input, or a stdin read
|
|
21
|
+
failure), retry the launch exactly once with byte-identical input; a second
|
|
22
|
+
exit 2 is a launch failure, not a payload problem. On exit 1 (the input
|
|
23
|
+
was structurally rejected), the parent may correct its own JSON envelope
|
|
24
|
+
exactly once -- fixing a genuine encoding mistake, never reshaping the
|
|
25
|
+
envelope to force acceptance -- and retry; a second exit 1 stops the run
|
|
26
|
+
visibly with degraded or abnormal status. Never fall back to writing a
|
|
27
|
+
finding, a merged finding, a queue, a disposition count, or a report section
|
|
28
|
+
by hand because a phase call failed.
|
|
29
|
+
|
|
30
|
+
## screen
|
|
31
|
+
|
|
32
|
+
Structurally admits one persona's raw return and binds it to the dispatched
|
|
33
|
+
persona, replacing the former separate raw-return-admission and
|
|
34
|
+
dispatch-identity-binding steps with one call. Feed the persona's raw JSON
|
|
35
|
+
return on stdin through a fresh single-quoted heredoc delimiter -- never
|
|
36
|
+
argv, command substitution, or a temp file -- exactly as the packaged
|
|
37
|
+
validator's `return` subcommand was invoked before this phase replaced it.
|
|
38
|
+
|
|
39
|
+
**Output** (`exit 0`): `{ dispatch_outcome, admitted_findings[{input_id, ...finding}], rejected_summary?{dispatch_outcome, rejected_finding_count, rejected_severities, reason}, residual_risks[], testing_gaps[], harness }`.
|
|
40
|
+
`admitted_findings` carries each finding with a stable `<reviewer>#<index>`
|
|
41
|
+
`input_id` and `disposition: "surviving"` pre-assigned. A whole-payload
|
|
42
|
+
rejection (malformed JSON, schema violation, or an identity mismatch between
|
|
43
|
+
the return's `reviewer` field and the dispatched persona) never admits any
|
|
44
|
+
finding from that return.
|
|
45
|
+
|
|
46
|
+
Before each invocation, choose a fresh delimiter for that exact raw payload
|
|
47
|
+
over a safe token alphabet (`A-Z`, `0-9`, `_`), for example a random hex
|
|
48
|
+
token, and verify the delimiter is absent as a complete line in that exact
|
|
49
|
+
raw payload before running. Never reuse a fixed delimiter across payloads.
|
|
50
|
+
Open the heredoc with a single-quoted heredoc opener (`<<'DELIM'`) so the
|
|
51
|
+
payload is never interpolated, and close it with a line containing exactly
|
|
52
|
+
that delimiter.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Resolve the validator relative to the skill's own directory.
|
|
56
|
+
SKILL_DIR="<skill directory stated when this skill loads>";
|
|
57
|
+
node "$SKILL_DIR/scripts/validate-review.mjs" screen --reviewer <persona> --harness <opencode|pi|claude-code> <<'SCREEN_INPUT_A1B2C3D4'
|
|
58
|
+
<the persona's returned JSON payload, copied verbatim>
|
|
59
|
+
SCREEN_INPUT_A1B2C3D4
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Read the exit status:
|
|
63
|
+
|
|
64
|
+
- **exit 0** -- structurally admitted. Parse the already structurally
|
|
65
|
+
validated JSON without logging the raw text; the parent may then attach
|
|
66
|
+
both `harness` and `dispatch_outcome` from this result to the persisted
|
|
67
|
+
per-agent dispatch record. `dispatch_outcome: "empty"` means zero
|
|
68
|
+
findings; `"findings"` means one or more admitted findings.
|
|
69
|
+
- **exit 1** -- the whole return is `dispatch_outcome: "malformed"`, covering
|
|
70
|
+
malformed JSON, a schema violation, and a `reviewer`-field identity
|
|
71
|
+
mismatch alike. Retain only the bounded validator diagnostic on stderr in
|
|
72
|
+
Coverage; never parse or persist payload fields or values.
|
|
73
|
+
- **exit 2**, a missing or unreadable helper, or a command launch failure --
|
|
74
|
+
validation unavailable. Withhold the return and report the exact
|
|
75
|
+
unavailability and what was withheld. Update that selected persona's
|
|
76
|
+
preinitialized dispatch entry from `never_returned` to `dispatch_outcome:
|
|
77
|
+
"validation_unavailable"` with `input_finding_count: 0`, and set
|
|
78
|
+
`run_status` to `degraded`. A run containing `validation_unavailable`
|
|
79
|
+
evidence can never finalize as `completed`, and that persona must not have
|
|
80
|
+
an admitted input finding. `validation_unavailable` is not `malformed` and
|
|
81
|
+
is not `never_returned`; they are distinct coverage states. `never_returned`
|
|
82
|
+
is a task-lifecycle fact for a task that did not return at all, recorded
|
|
83
|
+
without invoking the validator.
|
|
84
|
+
|
|
85
|
+
Structural validity never implies evidence validity. A return that passes
|
|
86
|
+
`screen` is admitted structurally only; its claims still require evidence
|
|
87
|
+
assessment during adjudication.
|
|
88
|
+
|
|
89
|
+
## prepare
|
|
90
|
+
|
|
91
|
+
Applies the confidence gate, forms dedup candidate groups, and unions
|
|
92
|
+
selection-surface coverage across every screened return -- deterministic
|
|
93
|
+
parent-owned bookkeeping that no longer needs model recomputation.
|
|
94
|
+
|
|
95
|
+
**Input:** `{ screen_results[{reviewer, result:<screen output>}], selected_dispatches[{persona, dispatch_outcome, selection_surface?}] }`.
|
|
96
|
+
Assemble `screen_results` from every `screen` call made in this run, and
|
|
97
|
+
`selected_dispatches` from the Stage 3 selection record (including any
|
|
98
|
+
persona whose dispatch never produced a screen result, so `never_returned`
|
|
99
|
+
and `validation_unavailable` personas are represented too).
|
|
100
|
+
|
|
101
|
+
**Output:** `{ confidence_dispositions, coverage_union, singletons, candidate_groups[{file, members[{input_id,line}]}], surviving_findings }`.
|
|
102
|
+
`candidate_groups` are the file-grouped, line-sorted sets of two or more
|
|
103
|
+
admitted findings from different personas that the model must adjudicate in
|
|
104
|
+
`merge`. `singletons` are admitted findings that passed the confidence gate
|
|
105
|
+
but did not land in any candidate group -- they need no adjudication and flow
|
|
106
|
+
straight through. `confidence_dispositions` and `coverage_union` are the
|
|
107
|
+
suppressed-finding ledger and the unioned selection-surface coverage list
|
|
108
|
+
respectively; both feed later phases and Coverage reporting without further
|
|
109
|
+
recomputation.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Resolve the validator relative to the skill's own directory.
|
|
113
|
+
SKILL_DIR="<skill directory stated when this skill loads>";
|
|
114
|
+
node "$SKILL_DIR/scripts/validate-review.mjs" prepare <<'PREPARE_INPUT_A1B2C3D4'
|
|
115
|
+
{ "screen_results": [...], "selected_dispatches": [...] }
|
|
116
|
+
PREPARE_INPUT_A1B2C3D4
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Choose a fresh delimiter the same way as `screen`'s. Read the exit status:
|
|
120
|
+
|
|
121
|
+
- **exit 0** -- the aggregate envelope validated; parse the JSON result and
|
|
122
|
+
carry it into adjudication.
|
|
123
|
+
- **exit 1** -- the aggregate envelope was rejected (malformed JSON or a
|
|
124
|
+
structural violation against the screen results and selected dispatches
|
|
125
|
+
supplied). Never hand-assemble a substitute `prepare` output.
|
|
126
|
+
- **exit 2**, a missing helper, or a launch failure -- unavailable; retry
|
|
127
|
+
once with identical bytes per the never-bypass rule above, then stop
|
|
128
|
+
visibly.
|
|
129
|
+
|
|
130
|
+
## merge
|
|
131
|
+
|
|
132
|
+
Applies the model's adjudication decisions to `prepare`'s candidate groups,
|
|
133
|
+
deriving each merged finding's severity, confidence (including the
|
|
134
|
+
cross-reviewer agreement boost), fingerprint, submitters, and conservatively
|
|
135
|
+
narrowed route -- the model supplies judgment per candidate group; the helper
|
|
136
|
+
supplies the arithmetic and the narrowing rule.
|
|
137
|
+
|
|
138
|
+
**Input:** `{ prepared:<prepare output>, adjudication:<model envelope with decisions[]> }`.
|
|
139
|
+
Build one `decisions[]` entry for every candidate-group member: a `merged`
|
|
140
|
+
decision citing 2+ input IDs from the same group with the merged finding's
|
|
141
|
+
`title`, `why_it_matters`, `evidence`, `line`, `proposed_route` (when the
|
|
142
|
+
merge's route should narrow), `route_narrowing_reason` (required whenever
|
|
143
|
+
`proposed_route` is present), and optional `disagreement_facts` and
|
|
144
|
+
`eligible_agreement_credit`; or a `declined` decision citing exactly one
|
|
145
|
+
input ID with a `declined_reason` explaining why it stays a separate defect.
|
|
146
|
+
Every candidate-group member must be cited by exactly one decision -- no
|
|
147
|
+
omissions, no double-citations. `prepare`'s true singletons need no decision
|
|
148
|
+
at all.
|
|
149
|
+
|
|
150
|
+
**Output:** `{ merged_findings, validator_requests[{finding_id,file,line}], disagreement_facts }`.
|
|
151
|
+
`validator_requests` names the merged findings that fall inside the Stage 5b
|
|
152
|
+
gating band (P0/P1 severity, or `requires_verification: true`) -- dispatch
|
|
153
|
+
exactly one validator subagent per entry, looking up that finding's full
|
|
154
|
+
fields from `merged_findings` by `finding_id`.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Resolve the validator relative to the skill's own directory.
|
|
158
|
+
SKILL_DIR="<skill directory stated when this skill loads>";
|
|
159
|
+
node "$SKILL_DIR/scripts/validate-review.mjs" merge <<'MERGE_INPUT_A1B2C3D4'
|
|
160
|
+
{ "prepared": { ... }, "adjudication": { "decisions": [...] } }
|
|
161
|
+
MERGE_INPUT_A1B2C3D4
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Choose a fresh delimiter the same way as `screen`'s. Read the exit status:
|
|
165
|
+
|
|
166
|
+
- **exit 0** -- the adjudication envelope validated against the prepared
|
|
167
|
+
candidate set; parse the JSON result and carry `merged_findings` and
|
|
168
|
+
`validator_requests` forward.
|
|
169
|
+
- **exit 1** -- the envelope was rejected: malformed JSON, a schema
|
|
170
|
+
violation, an omitted or double-cited candidate member, or a merged
|
|
171
|
+
decision inconsistent with its cited members. Correct the envelope once
|
|
172
|
+
per the never-bypass rule, then stop visibly if it is rejected again.
|
|
173
|
+
Never hand-assemble a substitute merged-finding set.
|
|
174
|
+
- **exit 2**, a missing helper, or a launch failure -- unavailable; retry
|
|
175
|
+
once with identical bytes, then stop visibly.
|
|
176
|
+
|
|
177
|
+
## finalize
|
|
178
|
+
|
|
179
|
+
Synthesizes the run's final report and, in writing modes, the persistable
|
|
180
|
+
artifact: reconciles validator lifecycle results against `merge`'s
|
|
181
|
+
`validator_requests`, routes the model's plan-assessment results into
|
|
182
|
+
residual actionable work and advisory output, derives the risk-aware
|
|
183
|
+
verdict, and computes every queue, disposition count, and coverage entry.
|
|
184
|
+
Called once with `applied_fixes: []` to obtain the queues that drive fix
|
|
185
|
+
dispatch; fix-applying modes call it again with the exact applied-fix
|
|
186
|
+
outcomes and the same validator results, and only that second call is
|
|
187
|
+
persisted. Report-only calls it once and writes nothing.
|
|
188
|
+
|
|
189
|
+
**Input:** `{ merge:<merge output>, prepared:<prepare output>, screen_results:<same array given to prepare>, dispatch_records:<same selected_dispatches>, validator_lifecycle_results[{finding_id, result:{outcome:'true'|'false'|'failed'|'unavailable', reason?}}], plan_assessment:{ verdict, results[{kind:'explicit_unmet_requirement'|'inferred_gap', description}] }, parent_run_metadata:{ run_id, mode:'interactive'|'autofix'|'headless'|'report-only', harness, branch, head_sha, selected_dispatches, timestamps:{started_at, completed_at}, validation:{status, reason?}, applied_fixes[] } }`.
|
|
190
|
+
Reuse `prepared`, `screen_results`, and `dispatch_records` wholesale from the
|
|
191
|
+
earlier phases rather than restating them; `finalize` re-derives the ledger,
|
|
192
|
+
rejected-payload weights, coverage notes, and reviewer ownership from this
|
|
193
|
+
carried state. `validator_lifecycle_results` carries one entry per
|
|
194
|
+
`validator_requests` finding ID -- `outcome: "true"` needs no reason;
|
|
195
|
+
`"false"`, `"failed"`, and `"unavailable"` each require one. `plan_assessment`
|
|
196
|
+
is the model's Stage 2b requirements check: each result's `kind` routes it --
|
|
197
|
+
`explicit_unmet_requirement` becomes residual actionable work and blocks a
|
|
198
|
+
clean verdict; `inferred_gap` becomes advisory-only output and never blocks
|
|
199
|
+
the verdict by itself. Neither kind becomes a finding. `parent_run_metadata`
|
|
200
|
+
carries the run's own identity and mode; `validation` is the artifact
|
|
201
|
+
self-validation envelope, but finalize is called before that
|
|
202
|
+
[artifact validation](./synthesis-artifact-contract.md#artifact-validation)
|
|
203
|
+
step can run, so the only truthful value at that point is
|
|
204
|
+
`{status: "not_attempted", reason}` -- finalize rejects any other value.
|
|
205
|
+
The post-write validation status is reported by the parent in the rendered
|
|
206
|
+
Coverage section, never rewritten into the persisted artifact.
|
|
207
|
+
|
|
208
|
+
**Output:** `{ kind:'writing', artifact, report }` or `{ kind:'report_only', ...report }`.
|
|
209
|
+
`report` carries `verdict`, `findings`, `applied_fixes`,
|
|
210
|
+
`residual_actionable_work`, `advisory_outputs`, `coverage`,
|
|
211
|
+
`input_dispositions`, `disposition_counts`, `queues{fixer,residual,report_only}`,
|
|
212
|
+
`pre_existing_findings`, and `risk_coverage` -- render Stage 6 directly from
|
|
213
|
+
this projection rather than recomputing any of it. In writing modes,
|
|
214
|
+
`artifact` is the exact `review-summary.json` payload to persist.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Resolve the validator relative to the skill's own directory.
|
|
218
|
+
SKILL_DIR="<skill directory stated when this skill loads>";
|
|
219
|
+
node "$SKILL_DIR/scripts/validate-review.mjs" finalize <<'FINALIZE_INPUT_A1B2C3D4'
|
|
220
|
+
{ "merge": { ... }, "prepared": { ... }, "screen_results": [...], "dispatch_records": [...], "validator_lifecycle_results": [...], "plan_assessment": { ... }, "parent_run_metadata": { ... } }
|
|
221
|
+
FINALIZE_INPUT_A1B2C3D4
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Choose a fresh delimiter the same way as `screen`'s. Read the exit status:
|
|
225
|
+
|
|
226
|
+
- **exit 0** -- parse the JSON result. In writing modes, capture the exact
|
|
227
|
+
stdout bytes to a same-directory temp file (see
|
|
228
|
+
[Persisting the artifact](#persisting-the-artifact) below) before rendering
|
|
229
|
+
the report; report-only renders `report` directly and writes nothing.
|
|
230
|
+
- **exit 1** -- the aggregate envelope was rejected: a shape mismatch against
|
|
231
|
+
`merge`/`prepared`, a missing or extra validator-lifecycle result, an
|
|
232
|
+
invalid plan-assessment envelope, or an artifact that failed its own
|
|
233
|
+
internal schema check. Correct the envelope once per the never-bypass
|
|
234
|
+
rule, then stop visibly if it is rejected again. Never hand-assemble a
|
|
235
|
+
substitute report or artifact.
|
|
236
|
+
- **exit 2**, a missing helper, or a launch failure -- unavailable; retry
|
|
237
|
+
once with identical bytes, then stop visibly.
|
|
238
|
+
|
|
239
|
+
### Persisting the artifact
|
|
240
|
+
|
|
241
|
+
Writing-mode `finalize` stdout is the wrapper
|
|
242
|
+
`{ kind: 'writing', artifact, report }`, not the artifact by itself. In
|
|
243
|
+
interactive, autofix, and headless modes, after the persisted `finalize` call
|
|
244
|
+
succeeds, extract only the captured stdout's `artifact` member -- never the
|
|
245
|
+
whole wrapper -- and write that JSON to a temp file created exclusively with
|
|
246
|
+
owner-only permissions in the same `.context/systematic/ce-review/<run-id>`
|
|
247
|
+
directory as the final artifact, then atomically rename it over
|
|
248
|
+
`review-summary.json`. Render the report from the same captured stdout's
|
|
249
|
+
`report` member. No `jq` dependency is assumed; Node performs the extraction:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
node -e 'const r=JSON.parse(require("fs").readFileSync(0,"utf8"));process.stdout.write(JSON.stringify(r.artifact))' \
|
|
253
|
+
< "$FINALIZE_STDOUT" > "$TEMP_FILE"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Remove the temp file on any non-success (a rejected `finalize` call, a write
|
|
257
|
+
failure, or an interrupted run) instead of leaving a partial file behind.
|
|
258
|
+
Only after the rename succeeds does the parent run the existing `artifact`
|
|
259
|
+
subcommand (see the
|
|
260
|
+
[synthesis artifact contract](./synthesis-artifact-contract.md#artifact-validation))
|
|
261
|
+
against the persisted path. Report-only never creates the run directory,
|
|
262
|
+
never writes a temp file, and never runs `artifact` validation -- it has no
|
|
263
|
+
artifact to validate.
|
|
@@ -130,6 +130,7 @@ This fails because: no pipe-delimited tables, no severity-grouped `###` headers,
|
|
|
130
130
|
- **Route column** shows the synthesized handling decision as ``<autofix_class> -> <owner>``.
|
|
131
131
|
- **Header includes** scope, intent, and reviewer team with per-conditional justifications
|
|
132
132
|
- **Mode line** -- include `interactive`, `autofix`, `report-only`, or `headless`
|
|
133
|
+
- **Requirements Completeness section** -- include only when a plan was found in Stage 2b. Render the met/not-addressed/partially-addressed checklist, then list the plan-assessment routing output as its own bullet lists: `explicit_unmet_requirement` results appear as `report.residual_actionable_work` bullets (they gate the verdict); `inferred_gap` results appear as `report.advisory_outputs` bullets (they never gate the verdict alone). Neither kind is a finding -- they never gain a file, line, reviewer, confidence, or route, and never appear in a severity table. Omit the section entirely when no plan was found.
|
|
133
134
|
- **Applied Fixes section** -- include only when a fix phase ran in this review invocation
|
|
134
135
|
- **Residual Actionable Work section** -- include only when unresolved actionable findings were handed off for later work
|
|
135
136
|
- **Pre-existing section** -- separate table, no confidence column (these are informational)
|
|
@@ -137,7 +138,7 @@ This fails because: no pipe-delimited tables, no severity-grouped `###` headers,
|
|
|
137
138
|
- **Learnings & Past Solutions section** -- render only when CE `learnings-researcher` was selected and returned relevant output; results with links to docs/solutions/ files. Omit otherwise.
|
|
138
139
|
- **Agent-Native Gaps section** -- render only when CE `agent-native-reviewer` was selected and returned relevant output. Omit otherwise.
|
|
139
140
|
- **Deployment Notes section** -- key checklist items from deployment-verification-agent. Omit if the agent did not run.
|
|
140
|
-
- **Coverage section** -- suppressed count with original confidences, residual risks, testing gaps, failed reviewers, disposition reconciliation, and risk-coverage entries with their citing input finding IDs and blocked-entry exit conditions. For raw returns, distinguish `findings`, `empty`, `malformed`, `never_returned`, `validation_unavailable` (the persisted raw dispatch outcome, distinct from the artifact-level `validation.status: "unavailable"`), and
|
|
141
|
+
- **Coverage section** -- suppressed count with original confidences, residual risks, testing gaps, failed reviewers, disposition reconciliation, and risk-coverage entries with their citing input finding IDs and blocked-entry exit conditions. For raw returns, distinguish `findings`, `empty`, `malformed`, `never_returned`, and `validation_unavailable` (the persisted raw dispatch outcome, distinct from the artifact-level `validation.status: "unavailable"`), and state what was admitted or withheld
|
|
141
142
|
- **Summary uses blockquotes** for verdict, reasoning, and fix order
|
|
142
143
|
- **Horizontal rule** (`---`) separates findings from verdict
|
|
143
144
|
- **`###` headers** for each section -- never plain text headers
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Code Review Pipeline Envelopes",
|
|
4
|
+
"description": "Structured output schemas for the model-authored envelopes of the ce:review synthesis pipeline (adjudication decisions, validator lifecycle results, and plan assessment). Helper-produced internal phase state (screen output, prepared state, merge output, finalize output) is intentionally excluded: it is TypeScript/Zod-only and never authored by a model.",
|
|
5
|
+
"definitions": {
|
|
6
|
+
"adjudicationEnvelope": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"decisions": {
|
|
10
|
+
"maxItems": 32,
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"oneOf": [
|
|
14
|
+
{
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"decision_id": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"minLength": 1,
|
|
20
|
+
"maxLength": 128,
|
|
21
|
+
"pattern": "\\S"
|
|
22
|
+
},
|
|
23
|
+
"disposition": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"const": "merged"
|
|
26
|
+
},
|
|
27
|
+
"input_finding_ids": {
|
|
28
|
+
"minItems": 2,
|
|
29
|
+
"maxItems": 32,
|
|
30
|
+
"type": "array",
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"maxLength": 128,
|
|
35
|
+
"pattern": "\\S"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"title": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1,
|
|
41
|
+
"maxLength": 256,
|
|
42
|
+
"pattern": "\\S",
|
|
43
|
+
"description": "Short, specific issue title. 10 words or fewer."
|
|
44
|
+
},
|
|
45
|
+
"why_it_matters": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"minLength": 1,
|
|
48
|
+
"maxLength": 2048,
|
|
49
|
+
"pattern": "\\S",
|
|
50
|
+
"description": "Non-empty impact and failure mode -- not 'what is wrong' but 'what breaks'"
|
|
51
|
+
},
|
|
52
|
+
"evidence": {
|
|
53
|
+
"minItems": 1,
|
|
54
|
+
"maxItems": 5,
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": {
|
|
57
|
+
"anyOf": [
|
|
58
|
+
{
|
|
59
|
+
"type": "string",
|
|
60
|
+
"minLength": 1,
|
|
61
|
+
"maxLength": 500,
|
|
62
|
+
"allOf": [
|
|
63
|
+
{
|
|
64
|
+
"type": "string",
|
|
65
|
+
"pattern": "\\S"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "string",
|
|
69
|
+
"pattern": "^(?!\\/)(?![A-Za-z]:[\\\\/])(?!\\\\).+"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"description": "Bounded code-grounded evidence; absolute POSIX, drive-letter, and UNC paths are rejected"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"overflow": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"const": true,
|
|
80
|
+
"description": "Explicit marker that the complete evidence did not fit in one bounded entry"
|
|
81
|
+
},
|
|
82
|
+
"excerpt": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"minLength": 1,
|
|
85
|
+
"maxLength": 500,
|
|
86
|
+
"allOf": [
|
|
87
|
+
{
|
|
88
|
+
"type": "string",
|
|
89
|
+
"pattern": "\\S"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "string",
|
|
93
|
+
"pattern": "^(?!\\/)(?![A-Za-z]:[\\\\/])(?!\\\\).+"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"description": "Bounded excerpt retained when evidence must be shortened"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"required": ["overflow", "excerpt"],
|
|
100
|
+
"additionalProperties": false
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"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."
|
|
105
|
+
},
|
|
106
|
+
"suggested_fix": {
|
|
107
|
+
"description": "Concrete minimal fix. Omit or null if no good fix is obvious -- a bad suggestion is worse than none.",
|
|
108
|
+
"anyOf": [
|
|
109
|
+
{
|
|
110
|
+
"type": "string",
|
|
111
|
+
"maxLength": 2048
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"type": "null"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
"line": {
|
|
119
|
+
"type": "integer",
|
|
120
|
+
"exclusiveMinimum": 0,
|
|
121
|
+
"maximum": 9007199254740991,
|
|
122
|
+
"description": "Primary line number of the issue"
|
|
123
|
+
},
|
|
124
|
+
"disagreement_facts": {
|
|
125
|
+
"maxItems": 32,
|
|
126
|
+
"type": "array",
|
|
127
|
+
"items": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"minLength": 1,
|
|
130
|
+
"maxLength": 2048,
|
|
131
|
+
"pattern": "\\S"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"eligible_agreement_credit": {
|
|
135
|
+
"maxItems": 64,
|
|
136
|
+
"type": "array",
|
|
137
|
+
"items": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"minLength": 1,
|
|
140
|
+
"maxLength": 64,
|
|
141
|
+
"pattern": "\\S",
|
|
142
|
+
"description": "Persona name that produced this output (e.g., 'correctness', 'security')"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"proposed_route": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"autofix_class": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"enum": [
|
|
151
|
+
"safe_auto",
|
|
152
|
+
"gated_auto",
|
|
153
|
+
"manual",
|
|
154
|
+
"advisory"
|
|
155
|
+
],
|
|
156
|
+
"description": "Reviewer's conservative recommendation for how this issue should be handled after synthesis"
|
|
157
|
+
},
|
|
158
|
+
"owner": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"enum": [
|
|
161
|
+
"review-fixer",
|
|
162
|
+
"downstream-resolver",
|
|
163
|
+
"human",
|
|
164
|
+
"release"
|
|
165
|
+
],
|
|
166
|
+
"description": "Who should own the next action for this finding after synthesis"
|
|
167
|
+
},
|
|
168
|
+
"requires_verification": {
|
|
169
|
+
"type": "boolean",
|
|
170
|
+
"description": "Whether any fix for this finding must be re-verified with targeted tests or a follow-up review pass"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"required": [
|
|
174
|
+
"autofix_class",
|
|
175
|
+
"owner",
|
|
176
|
+
"requires_verification"
|
|
177
|
+
],
|
|
178
|
+
"additionalProperties": false
|
|
179
|
+
},
|
|
180
|
+
"route_narrowing_reason": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"minLength": 1,
|
|
183
|
+
"maxLength": 2048,
|
|
184
|
+
"pattern": "\\S"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"required": [
|
|
188
|
+
"decision_id",
|
|
189
|
+
"disposition",
|
|
190
|
+
"input_finding_ids",
|
|
191
|
+
"title",
|
|
192
|
+
"why_it_matters",
|
|
193
|
+
"evidence",
|
|
194
|
+
"line"
|
|
195
|
+
],
|
|
196
|
+
"additionalProperties": false
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"type": "object",
|
|
200
|
+
"properties": {
|
|
201
|
+
"decision_id": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"minLength": 1,
|
|
204
|
+
"maxLength": 128,
|
|
205
|
+
"pattern": "\\S"
|
|
206
|
+
},
|
|
207
|
+
"disposition": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"const": "declined"
|
|
210
|
+
},
|
|
211
|
+
"input_finding_id": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"minLength": 1,
|
|
214
|
+
"maxLength": 128,
|
|
215
|
+
"pattern": "\\S"
|
|
216
|
+
},
|
|
217
|
+
"declined_reason": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"minLength": 1,
|
|
220
|
+
"maxLength": 2048,
|
|
221
|
+
"pattern": "\\S"
|
|
222
|
+
},
|
|
223
|
+
"disagreement_facts": {
|
|
224
|
+
"maxItems": 32,
|
|
225
|
+
"type": "array",
|
|
226
|
+
"items": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"minLength": 1,
|
|
229
|
+
"maxLength": 2048,
|
|
230
|
+
"pattern": "\\S"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"proposed_route": {
|
|
234
|
+
"type": "object",
|
|
235
|
+
"properties": {
|
|
236
|
+
"autofix_class": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"enum": [
|
|
239
|
+
"safe_auto",
|
|
240
|
+
"gated_auto",
|
|
241
|
+
"manual",
|
|
242
|
+
"advisory"
|
|
243
|
+
],
|
|
244
|
+
"description": "Reviewer's conservative recommendation for how this issue should be handled after synthesis"
|
|
245
|
+
},
|
|
246
|
+
"owner": {
|
|
247
|
+
"type": "string",
|
|
248
|
+
"enum": [
|
|
249
|
+
"review-fixer",
|
|
250
|
+
"downstream-resolver",
|
|
251
|
+
"human",
|
|
252
|
+
"release"
|
|
253
|
+
],
|
|
254
|
+
"description": "Who should own the next action for this finding after synthesis"
|
|
255
|
+
},
|
|
256
|
+
"requires_verification": {
|
|
257
|
+
"type": "boolean",
|
|
258
|
+
"description": "Whether any fix for this finding must be re-verified with targeted tests or a follow-up review pass"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"required": [
|
|
262
|
+
"autofix_class",
|
|
263
|
+
"owner",
|
|
264
|
+
"requires_verification"
|
|
265
|
+
],
|
|
266
|
+
"additionalProperties": false
|
|
267
|
+
},
|
|
268
|
+
"route_narrowing_reason": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"minLength": 1,
|
|
271
|
+
"maxLength": 2048,
|
|
272
|
+
"pattern": "\\S"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"required": [
|
|
276
|
+
"decision_id",
|
|
277
|
+
"disposition",
|
|
278
|
+
"input_finding_id",
|
|
279
|
+
"declined_reason"
|
|
280
|
+
],
|
|
281
|
+
"additionalProperties": false
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
"required": ["decisions"],
|
|
288
|
+
"additionalProperties": false
|
|
289
|
+
},
|
|
290
|
+
"validatorLifecycleResult": {
|
|
291
|
+
"oneOf": [
|
|
292
|
+
{
|
|
293
|
+
"type": "object",
|
|
294
|
+
"properties": {
|
|
295
|
+
"outcome": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"const": "true"
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
"required": ["outcome"],
|
|
301
|
+
"additionalProperties": false
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"type": "object",
|
|
305
|
+
"properties": {
|
|
306
|
+
"outcome": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"const": "false"
|
|
309
|
+
},
|
|
310
|
+
"reason": {
|
|
311
|
+
"type": "string",
|
|
312
|
+
"minLength": 1,
|
|
313
|
+
"maxLength": 2048,
|
|
314
|
+
"pattern": "\\S"
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"required": ["outcome", "reason"],
|
|
318
|
+
"additionalProperties": false
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"type": "object",
|
|
322
|
+
"properties": {
|
|
323
|
+
"outcome": {
|
|
324
|
+
"type": "string",
|
|
325
|
+
"const": "failed"
|
|
326
|
+
},
|
|
327
|
+
"reason": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"minLength": 1,
|
|
330
|
+
"maxLength": 2048,
|
|
331
|
+
"pattern": "\\S"
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
"required": ["outcome", "reason"],
|
|
335
|
+
"additionalProperties": false
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"type": "object",
|
|
339
|
+
"properties": {
|
|
340
|
+
"outcome": {
|
|
341
|
+
"type": "string",
|
|
342
|
+
"const": "unavailable"
|
|
343
|
+
},
|
|
344
|
+
"reason": {
|
|
345
|
+
"type": "string",
|
|
346
|
+
"minLength": 1,
|
|
347
|
+
"maxLength": 2048,
|
|
348
|
+
"pattern": "\\S"
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
"required": ["outcome", "reason"],
|
|
352
|
+
"additionalProperties": false
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
"planAssessmentEnvelope": {
|
|
357
|
+
"type": "object",
|
|
358
|
+
"properties": {
|
|
359
|
+
"verdict": {
|
|
360
|
+
"type": "string",
|
|
361
|
+
"minLength": 1,
|
|
362
|
+
"maxLength": 256,
|
|
363
|
+
"pattern": "\\S"
|
|
364
|
+
},
|
|
365
|
+
"results": {
|
|
366
|
+
"maxItems": 32,
|
|
367
|
+
"type": "array",
|
|
368
|
+
"items": {
|
|
369
|
+
"type": "object",
|
|
370
|
+
"properties": {
|
|
371
|
+
"kind": {
|
|
372
|
+
"type": "string",
|
|
373
|
+
"enum": ["explicit_unmet_requirement", "inferred_gap"]
|
|
374
|
+
},
|
|
375
|
+
"description": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"minLength": 1,
|
|
378
|
+
"maxLength": 2048,
|
|
379
|
+
"pattern": "\\S"
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
"required": ["kind", "description"],
|
|
383
|
+
"additionalProperties": false
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
"required": ["verdict", "results"],
|
|
388
|
+
"additionalProperties": false
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|