@fro.bot/systematic 3.12.3 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATTRIBUTIONS.md +2 -2
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +324 -2
- package/dist/{index-h26p98ny.js → index-0stf3ag0.js} +948 -948
- package/dist/index.js +1 -1
- package/dist/lib/review-artifact-schema.d.ts +239 -0
- package/package.json +9 -6
- package/skills/ce-review/SKILL.md +8 -7
- package/skills/ce-review/references/review-summary-schema.json +517 -0
- package/skills/ce-review/references/synthesis-artifact-contract.md +143 -22
|
@@ -19,11 +19,13 @@ reason. An unfinished `in_progress` artifact is evidence of an abnormal run,
|
|
|
19
19
|
not evidence of a clean run. Never infer a clean run from an absent artifact.
|
|
20
20
|
|
|
21
21
|
The artifact is parent-owned. Per-agent full-detail JSON files are written
|
|
22
|
-
only after the
|
|
23
|
-
validation.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
only for findings admitted after the parent completes schema and
|
|
23
|
+
environment-value validation. A finding rejected by environment-value
|
|
24
|
+
detection is not persisted; other findings from the same return may proceed.
|
|
25
|
+
A payload rejected at top level, or a rejected or never-returned persona,
|
|
26
|
+
does not produce a per-agent file. If a later confidence or validation stage
|
|
27
|
+
changes an input disposition, the parent updates the record and synthesis
|
|
28
|
+
ledger before finalizing the artifact.
|
|
27
29
|
|
|
28
30
|
## Required distinctions and reconciliation
|
|
29
31
|
|
|
@@ -32,6 +34,7 @@ The artifact must preserve these distinctions:
|
|
|
32
34
|
```json
|
|
33
35
|
{
|
|
34
36
|
"run_id": "<run-id>",
|
|
37
|
+
"schema_version": 1,
|
|
35
38
|
"mode": "<interactive | autofix | headless>",
|
|
36
39
|
"harness": "<opencode | pi | claude-code>",
|
|
37
40
|
"run_status": "<in_progress | completed | degraded | abnormal>",
|
|
@@ -41,10 +44,15 @@ The artifact must preserve these distinctions:
|
|
|
41
44
|
"dispatch_outcome": "findings",
|
|
42
45
|
"input_finding_count": 2
|
|
43
46
|
},
|
|
47
|
+
{
|
|
48
|
+
"persona": "testing",
|
|
49
|
+
"dispatch_outcome": "findings",
|
|
50
|
+
"input_finding_count": 1
|
|
51
|
+
},
|
|
44
52
|
{
|
|
45
53
|
"persona": "kieran-typescript",
|
|
46
54
|
"dispatch_outcome": "malformed",
|
|
47
|
-
"input_finding_count":
|
|
55
|
+
"input_finding_count": 2,
|
|
48
56
|
"rejection_reason": "Rejected persona kieran-typescript return: field findings[0].evidence failed schema validation."
|
|
49
57
|
}
|
|
50
58
|
],
|
|
@@ -55,6 +63,14 @@ The artifact must preserve these distinctions:
|
|
|
55
63
|
"confidence": 0.55,
|
|
56
64
|
"disposition": "suppressed",
|
|
57
65
|
"reason": "confidence 0.55 is below the 0.60 gate"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"reviewer": "kieran-typescript",
|
|
69
|
+
"dispatch_outcome": "malformed",
|
|
70
|
+
"rejected_finding_count": 2,
|
|
71
|
+
"rejected_severities": ["P2", "P3"],
|
|
72
|
+
"disposition": "rejected",
|
|
73
|
+
"reason": "Rejected persona kieran-typescript return: field findings[0].evidence failed schema validation."
|
|
58
74
|
}
|
|
59
75
|
],
|
|
60
76
|
"findings": [
|
|
@@ -73,7 +89,7 @@ The artifact must preserve these distinctions:
|
|
|
73
89
|
"merged": 2,
|
|
74
90
|
"suppressed": 1,
|
|
75
91
|
"filtered": 0,
|
|
76
|
-
"rejected":
|
|
92
|
+
"rejected": 2
|
|
77
93
|
}
|
|
78
94
|
}
|
|
79
95
|
```
|
|
@@ -84,16 +100,24 @@ The artifact must preserve these distinctions:
|
|
|
84
100
|
naming persona and field without echoing the offending value. Dispatch
|
|
85
101
|
outcome is separate from finding disposition.
|
|
86
102
|
- `input_findings` is the authoritative parent-owned ledger. Before the
|
|
87
|
-
confidence gate, every
|
|
88
|
-
`<reviewer>#<1-based finding index>`. Every
|
|
89
|
-
final `disposition`: `surviving`, `merged`, `suppressed`, `filtered`,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
confidence gate, every admitted finding receives an `input_id` of
|
|
104
|
+
`<reviewer>#<1-based finding index>`. Every admitted input has exactly one
|
|
105
|
+
final `disposition`: `surviving`, `merged`, `suppressed`, or `filtered`, plus
|
|
106
|
+
a reason. A rejected payload is represented by one summary ledger entry,
|
|
107
|
+
carrying the persona name, its `dispatch_outcome`, the
|
|
108
|
+
`rejected_finding_count` of findings not admitted, `disposition: "rejected"`,
|
|
109
|
+
`rejected_severities`, a list of the severities of the findings not
|
|
110
|
+
admitted as parsed from the payload, and the exact safe rejection message.
|
|
111
|
+
When a rejected finding's severity is absent, malformed, or not a valid
|
|
112
|
+
severity value, record it as `unknown`. Severity is metadata; recording it
|
|
113
|
+
never includes the offending value. Do not enumerate rejected findings or
|
|
114
|
+
assign them input IDs. A finding-level environment rejection uses the same
|
|
115
|
+
summary entry while admitted findings from that return continue normally.
|
|
116
|
+
Disposition counts are weighted by `rejected_finding_count` for that summary
|
|
117
|
+
entry, so their sum equals the total number of findings observed, not the
|
|
118
|
+
number of ledger rows. A malformed JSON return with no safely enumerable
|
|
119
|
+
finding has zero ledger entries, not a fabricated finding. Never include the
|
|
120
|
+
offending value in a rejection reason.
|
|
97
121
|
- Synthesized and filtered findings retain their original fields plus
|
|
98
122
|
`input_finding_ids` and provenance. Provenance contains the exact dedup
|
|
99
123
|
fingerprint `normalize(file) + line_bucket(line, +/-3) + normalize(title)`,
|
|
@@ -120,8 +144,105 @@ the verdict is finalized. Existing artifacts without this additive metadata
|
|
|
120
144
|
remain valid, with downstream consumers falling back to file mtime.
|
|
121
145
|
|
|
122
146
|
Validation and persistence remain parent-side: no per-agent record or finding
|
|
123
|
-
is written or merged until
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
147
|
+
is written or merged until that finding passes schema and environment-value
|
|
148
|
+
validation. Rejected findings are recorded through the single rejected-payload
|
|
149
|
+
ledger summary; admitted findings from the same return remain eligible for
|
|
150
|
+
synthesis. Rejected or malformed persona returns do not fail the whole review;
|
|
151
|
+
the review degrades while conforming returns continue through synthesis. Only
|
|
152
|
+
an orchestration or storage failure that prevents the parent from producing the
|
|
153
|
+
required run artifact is run-fatal.
|
|
154
|
+
|
|
155
|
+
## Environment-value validation
|
|
156
|
+
|
|
157
|
+
The parent recursively inspects every string leaf without logging the raw
|
|
158
|
+
return or any matched value. Structural environment detectors remain
|
|
159
|
+
unbounded and unchanged: `$NAME`, `${NAME}`, `process.env.NAME`,
|
|
160
|
+
`os.environ[...]`, and `NAME=value` assignments using a known environment
|
|
161
|
+
variable name are shape-based checks.
|
|
162
|
+
|
|
163
|
+
Value-based matching uses only non-empty runtime environment values that are
|
|
164
|
+
at least 16 characters long and are not composed solely of digits, dots,
|
|
165
|
+
dashes, or path-separator characters (forward slash or backslash). A
|
|
166
|
+
value is also eligible regardless of length when
|
|
167
|
+
its variable name contains one of `TOKEN`, `SECRET`, `KEY`, `PASSWORD`,
|
|
168
|
+
`PASSWD`, `CREDENTIAL`, `AUTH`, `SESSION`, `COOKIE`, `PRIVATE`, `_PASS`,
|
|
169
|
+
`_PWD`, `PASSPHRASE`, or `_SALT`, matched as a case-insensitive substring.
|
|
170
|
+
Entries containing an underscore are matched against the variable name as
|
|
171
|
+
written; the underscore is deliberate and prevents matching benign names that
|
|
172
|
+
merely contain the bare word. Values that satisfy neither condition are not
|
|
173
|
+
matched. A match is an exact or embedded match.
|
|
174
|
+
|
|
175
|
+
If the offending string is inside one finding, drop that finding and record it
|
|
176
|
+
through the rejected-payload summary entry; the remaining findings continue
|
|
177
|
+
through validation and synthesis. If the offending string is outside any
|
|
178
|
+
finding, reject the whole payload. Every rejection uses only the persona name,
|
|
179
|
+
JSON path, and a fixed reason (`schema validation`, `environment-value
|
|
180
|
+
detection`, or `malformed JSON`):
|
|
181
|
+
`Rejected persona <name> return: field <JSON path> failed <reason>.` Never
|
|
182
|
+
echo the matched value.
|
|
183
|
+
|
|
184
|
+
## Artifact validation
|
|
185
|
+
|
|
186
|
+
The parent writes `schema_version: 1` into `review-summary.json` before
|
|
187
|
+
validating it. This ordering makes the artifact validatable at all: without
|
|
188
|
+
`schema_version`, the validator reports the legacy status (exit 3) rather than
|
|
189
|
+
a real validation result.
|
|
190
|
+
|
|
191
|
+
After writing `review-summary.json`, the parent runs
|
|
192
|
+
`systematic validate-review-artifact <path>` against it. A nonzero exit means
|
|
193
|
+
the run is not complete. The [executable schema](./review-summary-schema.json)
|
|
194
|
+
is generated from a Zod source and is the machine-checkable form of the shape
|
|
195
|
+
described here.
|
|
196
|
+
|
|
197
|
+
On validation failure, the parent repairs the artifact and re-runs the
|
|
198
|
+
validator. It does not report a verdict over an artifact that failed
|
|
199
|
+
validation, and it does not delete the artifact to escape the check. A failing
|
|
200
|
+
artifact is evidence and stays on disk; an absent artifact is never evidence
|
|
201
|
+
of a clean run.
|
|
202
|
+
|
|
203
|
+
This is enforcement by visible failure, not by containment. An agent that
|
|
204
|
+
never runs the command can still finalize an artifact, but produces no evidence
|
|
205
|
+
in either direction. That is why the command exists as an independently
|
|
206
|
+
runnable check rather than as a self-validation instruction, and why its result
|
|
207
|
+
belongs in the run record.
|
|
208
|
+
|
|
209
|
+
`mode:report-only` writes no artifact and therefore performs no validation.
|
|
210
|
+
|
|
211
|
+
## Historical corpus exclusion
|
|
212
|
+
|
|
213
|
+
Artifacts without `schema_version` predate this contract, are excluded from
|
|
214
|
+
quantitative analysis, and no legacy reader will be written. The validator
|
|
215
|
+
backs this exclusion with its exit 3 legacy status rather than leaving it as
|
|
216
|
+
a prose-only decision. Across 26 run directories, 7 synthesis artifacts were
|
|
217
|
+
written under two different filenames (`review-summary.json` and
|
|
218
|
+
`summary.json`); no two shared a shape. A parser would need seven special
|
|
219
|
+
cases to recover data that still could not answer cross-reviewer agreement
|
|
220
|
+
questions, because 19 of the 26 runs had no synthesis artifact to reconcile
|
|
221
|
+
against at all.
|
|
222
|
+
|
|
223
|
+
## Risk-aware degraded verdict
|
|
224
|
+
|
|
225
|
+
The risk-critical surfaces are `security`, `data-migrations`, `api-contract`,
|
|
226
|
+
`reliability`, and `performance`. They are the conditional personas selected
|
|
227
|
+
specifically for the matching diff shape in Stage 3. If one of those selected
|
|
228
|
+
personas has `dispatch_outcome: "malformed"` or
|
|
229
|
+
`dispatch_outcome: "never_returned"`, the review verdict must not be clean:
|
|
230
|
+
it is blocking unless another persona covered the same surface and returned
|
|
231
|
+
validated evidence for it. For this rule, validated evidence means at least
|
|
232
|
+
one finding from that other persona's return passed complete schema and
|
|
233
|
+
environment-value validation and is relevant to the same surface. A coverage
|
|
234
|
+
note alone cannot satisfy this rule; the verdict must reflect the missing
|
|
235
|
+
risk-critical evidence.
|
|
236
|
+
|
|
237
|
+
Finding-level rejection is keyed by the severities in
|
|
238
|
+
`rejected_severities`. A selected risk-critical persona whose rejected
|
|
239
|
+
findings include any `P0`, `P1`, or `unknown` severity is treated exactly as a
|
|
240
|
+
rejected persona for this verdict rule: blocking unless another persona
|
|
241
|
+
covered the same surface with validated evidence. A selected risk-critical
|
|
242
|
+
persona whose rejected findings are only `P2` or `P3` does not block on that
|
|
243
|
+
basis alone; record it in the Coverage section instead. Unknown severity is
|
|
244
|
+
treated as blocking as deliberate fail-closed behavior because the parent
|
|
245
|
+
could not determine what was lost. Admitted findings and verdict blocking
|
|
246
|
+
are independent: surviving findings from the same return continue through
|
|
247
|
+
synthesis normally. Partial return is not partial coverage when the lost
|
|
248
|
+
part was critical.
|