@fro.bot/systematic 3.18.3 → 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.
@@ -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
+ }
@@ -52,7 +52,7 @@ Rules:
52
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.
53
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
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.
55
+ - Finding paths MUST be repository-relative. The schema rejects absolute paths. Do not reproduce credential literals (API keys, tokens, passwords) in a finding's title, evidence, or fix; a source-level environment-variable reference (`process.env.API_KEY`, `${SECRET_TOKEN}`, and similar) is valid evidence and should be cited as such.
56
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`, `validation_unavailable` and `surviving`, `merged`, `suppressed`, `filtered`, `rejected`).
57
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.
58
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.
@@ -28,11 +28,11 @@ reason. An unfinished `in_progress` artifact is evidence of an abnormal run,
28
28
  not evidence of a clean run. Never infer a clean run from an absent artifact.
29
29
 
30
30
  The artifact is parent-owned. Per-agent full-detail JSON files are written
31
- only for findings admitted after the parent completes schema and
32
- environment-value validation. A finding rejected by environment-value
33
- detection is not persisted; other findings from the same return may proceed.
34
- A payload rejected at top level, or a rejected, never-returned, or
35
- validation-unavailable persona, does not produce a per-agent file. If a later confidence or validation stage
31
+ only for findings admitted after the parent completes schema validation. A
32
+ finding rejected by schema validation is not persisted; other findings from
33
+ the same return may proceed. A payload rejected at top level, or a rejected,
34
+ never-returned, or validation-unavailable persona, does not produce a
35
+ per-agent file. If a later confidence or validation stage
36
36
  changes an input disposition, the parent updates the record and synthesis
37
37
  ledger before finalizing the artifact.
38
38
 
@@ -131,7 +131,7 @@ The artifact must preserve these distinctions:
131
131
  When a rejected finding's severity is absent, malformed, or not a valid
132
132
  severity value, record it as `unknown`. Severity is metadata; recording it
133
133
  never includes the offending value. Do not enumerate rejected findings or
134
- assign them input IDs. A finding-level environment rejection uses the same
134
+ assign them input IDs. A finding-level schema rejection uses the same
135
135
  summary entry while admitted findings from that return continue normally.
136
136
  New writers must emit a rejected-summary row only for `findings` or
137
137
  `malformed`. The schema_version 1 validator deliberately continues to accept a
@@ -183,8 +183,8 @@ is finalized; consumers can therefore tell whether the artifact describes the
183
183
  current checkout.
184
184
 
185
185
  Validation and persistence remain parent-side: no per-agent record or finding
186
- is written or merged until that finding passes schema and environment-value
187
- validation. Rejected findings are recorded through the single rejected-payload
186
+ is written or merged until that finding passes schema validation. Rejected
187
+ findings are recorded through the single rejected-payload
188
188
  ledger summary; admitted findings from the same return remain eligible for
189
189
  synthesis. Rejected or malformed persona returns do not fail the whole review;
190
190
  the review degrades while conforming returns continue through synthesis. Only
@@ -193,37 +193,30 @@ required run artifact is run-fatal.
193
193
 
194
194
  ## Raw-return admission and validation availability
195
195
 
196
- Before a persona return is parsed into fields, screened for environment values,
197
- assessed for evidence, synthesized, or persisted, the parent admits it with the
198
- packaged structural validator:
199
-
200
- ```bash
201
- # Resolve the validator relative to the skill's own directory.
202
- SKILL_DIR="<skill directory stated when this skill loads>";
203
- node "$SKILL_DIR/scripts/validate-review.mjs" return <<'REVIEW_RETURN_A1B2C3D4'
204
- <the persona's returned JSON payload, copied verbatim>
205
- REVIEW_RETURN_A1B2C3D4
206
- ```
196
+ Before a persona return is parsed into fields, assessed for evidence,
197
+ synthesized, or persisted, the parent admits it with the packaged structural
198
+ validator's `screen` phase, which structurally admits the return and binds it
199
+ to the dispatched persona in one call, replacing the former separate
200
+ raw-return-admission and dispatch-identity-binding steps. The full envelope,
201
+ the invocation block, and the never-bypass rule are canonically defined in
202
+ [pipeline invocation: screen](./pipeline-invocation.md#screen); this section
203
+ states the resulting contract.
207
204
 
208
205
  Before each invocation, choose a fresh delimiter for that exact raw payload from
209
206
  a safe token alphabet (`A-Z`, `0-9`, `_`), verify the delimiter is absent as a
210
207
  complete line in that exact payload, and never reuse a fixed delimiter. The
211
- `REVIEW_RETURN_A1B2C3D4` token above is only an illustration. Open the heredoc
212
- with a single-quoted heredoc opener (`<<'DELIM'`) and close it with a line
213
- containing exactly that delimiter. The payload travels on stdin, never in argv;
214
- never use unquoted interpolation or command substitution, and never write the
215
- payload to a temp file.
208
+ payload travels on stdin, never in argv, command substitution, or a temp file.
216
209
 
217
- The parent maps the result to `dispatch_outcome`, keeping lifecycle, structural
218
- validity, environment screening, and evidence assessment separate:
210
+ The parent maps the result to `dispatch_outcome`, keeping lifecycle,
211
+ structural validity, and evidence assessment separate:
219
212
 
220
213
  - **exit 0** — structurally admitted. Parse the already structurally validated
221
- JSON without logging the raw text, then run the existing environment-value
222
- screen over that parsed object before persistence. Zero findings is `empty`;
223
- one or more findings is `findings`. Admission is structural only: it never
224
- asserts that a finding's claims or cited evidence are true.
214
+ JSON without logging the raw text. Zero findings is `empty`; one or more
215
+ findings is `findings`. Admission is structural only: it never asserts that
216
+ a finding's claims or cited evidence are true.
225
217
  - **exit 1** — `malformed`. Record bounded validator diagnostics only; do not
226
- parse, screen, or persist payload fields or values.
218
+ parse or persist payload fields or values. This covers malformed JSON, a
219
+ schema violation, and a dispatch identity mismatch alike.
227
220
  - **exit 2**, a missing or unreadable helper, or a launch failure — validation
228
221
  unavailable. Withhold the return and report the exact unavailability and what
229
222
  was withheld. Update that selected persona's preinitialized dispatch entry
@@ -236,14 +229,15 @@ validity, environment screening, and evidence assessment separate:
236
229
  task-lifecycle fact for a task that did not return. Validation unavailable is
237
230
  not malformed and is not never_returned.
238
231
 
239
- **Dispatch identity binding.** Structural admission does not prove who produced a
240
- return. Immediately after `exit 0` and before the environment-value screen,
241
- persistence, or synthesis, the parent parses the admitted return's `reviewer`
242
- field and confirms it equals the dispatched persona. A return whose `reviewer`
243
- does not match the dispatched persona is an identity mismatch: reject the whole
244
- return as `dispatch_outcome: "malformed"`, record only a bounded rejection reason
245
- naming the expected persona, set `run_status` to `degraded`, and do not admit,
246
- screen, persist, or synthesize its payload.
232
+ **Dispatch identity binding** is folded into `screen`: it confirms the
233
+ returned `reviewer` field matches the dispatched persona before it returns
234
+ `exit 0`. A return whose `reviewer` does not match the dispatched persona is
235
+ an identity mismatch: `screen` rejects the whole return as `dispatch_outcome:
236
+ "malformed"`, and the parent records only a bounded rejection reason naming
237
+ the expected persona, sets `run_status` to `degraded`, and does not admit,
238
+ persist, or synthesize its payload. The stdin-only, flag-scoped validator
239
+ cannot see dispatch context beyond `--reviewer`/`--harness`, so this
240
+ comparison is `screen`'s own responsibility, not a separate parent step.
247
241
 
248
242
  `validation_unavailable` is an additive enum value: `schema_version` stays `1`,
249
243
  existing v1 artifacts remain valid, and no new field or migration is introduced.
@@ -256,34 +250,29 @@ that is a different object and phase, and these fields are never repurposed for
256
250
  raw-dispatch availability. These admission states are surfaced in the report's
257
251
  Coverage, which reports the exact unavailability and what was withheld.
258
252
 
259
- ## Environment-value validation
260
-
261
- The parent recursively inspects every string leaf without logging the raw
262
- return or any matched value. Structural environment detectors remain
263
- unbounded and unchanged: `$NAME`, `${NAME}`, `process.env.NAME`,
264
- `os.environ[...]`, and `NAME=value` assignments using a known environment
265
- variable name are shape-based checks.
266
-
267
- Value-based matching uses only non-empty runtime environment values that are
268
- at least 16 characters long and are not composed solely of digits, dots,
269
- dashes, or path-separator characters (forward slash or backslash). A
270
- value is also eligible regardless of length when
271
- its variable name contains one of `TOKEN`, `SECRET`, `KEY`, `PASSWORD`,
272
- `PASSWD`, `CREDENTIAL`, `AUTH`, `SESSION`, `COOKIE`, `PRIVATE`, `_PASS`,
273
- `_PWD`, `PASSPHRASE`, or `_SALT`, matched as a case-insensitive substring.
274
- Entries containing an underscore are matched against the variable name as
275
- written; the underscore is deliberate and prevents matching benign names that
276
- merely contain the bare word. Values that satisfy neither condition are not
277
- matched. A match is an exact or embedded match.
278
-
279
- If the offending string is inside one finding, drop that finding and record it
280
- through the rejected-payload summary entry; the remaining findings continue
281
- through validation and synthesis. If the offending string is outside any
282
- finding, reject the whole payload. Every rejection uses only the persona name,
283
- JSON path, and a fixed reason (`schema validation`, `environment-value
284
- detection`, or `malformed JSON`):
253
+ ## Sensitive-evidence handling
254
+
255
+ Review artifacts may contain sensitive source-derived information. They are
256
+ not certified secret-free.
257
+
258
+ Reviewers must describe credential and secret-handling defects without
259
+ reproducing credential values. Cite repository-relative locations and
260
+ behavioral evidence instead of the value itself. An environment-variable
261
+ reference appearing in reviewed source (`process.env.API_KEY`,
262
+ `${SECRET_TOKEN}`, and similar) is valid evidence and is never rejected for
263
+ being a reference.
264
+
265
+ The parent must not deliberately log, cache, or write a raw return to a
266
+ temporary file. Diagnostics stay allowlisted to persona name, JSON path, and a
267
+ fixed reason (`schema validation` or `malformed JSON`):
285
268
  `Rejected persona <name> return: field <JSON path> failed <reason>.` Never
286
- echo the matched value.
269
+ exception text, raw validation-library issue objects, candidate values, or
270
+ variable names.
271
+
272
+ These are handling instructions that reduce accidental disclosure, not
273
+ technical containment. Real containment would require restricting reviewer
274
+ inputs and capabilities at the harness boundary, which this portable Node
275
+ helper does not provide.
287
276
 
288
277
  ## Artifact validation
289
278
 
@@ -387,8 +376,8 @@ it is blocking unless another persona covered the lost surface with validated
387
376
  evidence. For this rule, a validated finding from another persona covers a
388
377
  lost risk-critical surface if and only if the finding's `file` appears in the
389
378
  lost persona's recorded `selection_surface`; validated evidence means at least
390
- one finding from that other persona's return passed complete schema and
391
- environment-value validation. A coverage note alone cannot satisfy this rule;
379
+ one finding from that other persona's return passed complete schema
380
+ validation. A coverage note alone cannot satisfy this rule;
392
381
  the verdict must reflect the missing risk-critical evidence.
393
382
 
394
383
  Finding-level rejection is keyed by the severities in