@fro.bot/systematic 3.12.3 → 3.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.12.3",
3
+ "version": "3.12.4",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -456,17 +456,17 @@ The parent-owned artifact and its reconciliation rules are defined in the [synth
456
456
 
457
457
  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.
458
458
 
459
- Before applying the confidence gate, assign every finding in a valid return a stable parent-owned `input_id` of `<reviewer>#<1-based finding index>` and keep the parent-owned ledger through every later stage. See the [synthesis artifact contract](./references/synthesis-artifact-contract.md) for the ledger's authoritative reconciliation rules.
459
+ Before applying the confidence gate, keep the parent-owned ledger through every later stage. See the [synthesis artifact contract](./references/synthesis-artifact-contract.md) for the input-ID and reconciliation rules.
460
460
 
461
461
  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`.
462
462
  - **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.
463
463
  - **Per-finding required:** title, severity, file, line, why_it_matters, confidence, evidence, autofix_class, owner, requires_verification, pre_existing.
464
464
  - **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.
465
- - **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.
466
- - **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.
467
- - **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.
465
+ - **Environment-value detection:** JSON Schema cannot determine where a string came from, so recursively inspect every string leaf in the parsed payload before writing. Apply the environment-value matching, structural-detector, and finding-granularity rules in the [synthesis artifact contract](./references/synthesis-artifact-contract.md). This detector is an additional parent-side check, not a schema claim.
466
+ - **Safe rejection message:** Use the safe rejection message rule in the [synthesis artifact contract](./references/synthesis-artifact-contract.md); never include the offending value, raw return, or validator parameters.
467
+ - **No partial writes:** Do not write or merge a finding until it passes the parent-side validation rules. Apply the admitted-finding persistence and rejected-payload ledger rules in the [synthesis artifact contract](./references/synthesis-artifact-contract.md). A valid admitted finding is then annotated by the parent with `harness` and `dispatch_outcome` and written by the parent only. Revalidate the enriched record before persistence.
468
468
  - **Dispatch outcome:** Record the parent-owned dispatch outcomes and ledger dispositions according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md); keep dispatch outcomes separate from finding dispositions.
469
- - **Rejection policy: degrade, do not fail the whole review.** Continue merging conforming returns when a persona is rejected; record the rejection according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md). If every persona fails or times out, use the existing degraded-review behavior.
469
+ - **Rejection policy: degrade, do not fail the whole review.** Continue merging conforming returns when a persona or finding is rejected; record the rejection and apply the risk-aware verdict according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md). If every persona fails or times out, use the existing degraded-review behavior.
470
470
  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.
471
471
  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`.
472
472
  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 according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md).
@@ -480,7 +480,7 @@ Before applying the confidence gate, assign every finding in a valid return a st
480
480
  9. **Sort.** Order by severity (P0 first) -> confidence (descending) -> file path -> line number.
481
481
  10. **Collect coverage data.** Union residual_risks and testing_gaps across reviewers.
482
482
  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.
483
- 12. **Keep the input ledger complete.** Every enumerated input finding must receive exactly one final disposition and reason; reconcile the ledger according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md).
483
+ 12. **Keep the input ledger complete.** Reconcile admitted findings and rejected-payload summaries according to the [synthesis artifact contract](./references/synthesis-artifact-contract.md).
484
484
 
485
485
  ### Stage 5b: Validation pass
486
486
 
@@ -519,7 +519,7 @@ Assemble the final report using **pipe-delimited markdown tables for findings**
519
519
  9. **Agent-Native Gaps.** Surface agent-native-reviewer results. Omit section if no gaps found.
520
520
  10. **Deployment Notes.** If deployment-verification-agent ran, surface the key Go/No-Go items: blocking pre-deploy checks, the most important verification queries, rollback caveats, and monitoring focus areas. Keep the checklist actionable rather than dropping it into Coverage.
521
521
  11. **Coverage.** Suppressed count, residual risks, testing gaps, failed/timed-out reviewers, validator failures, and any intent uncertainty carried by non-interactive modes.
522
- 12. **Verdict.** Ready to merge / Ready with fixes / Not ready. Fix order if applicable. When an `explicit` plan has unaddressed requirements, the verdict must reflect it — a PR that's code-clean but missing planned requirements is "Not ready" unless the omission is intentional. When an `inferred` plan has unaddressed requirements, note it in the verdict reasoning but do not block on it alone.
522
+ 12. **Verdict.** Ready to merge / Ready with fixes / Not ready. Fix order if applicable. When an `explicit` plan has unaddressed requirements, the verdict must reflect it — a PR that's code-clean but missing planned requirements is "Not ready" unless the omission is intentional. When an `inferred` plan has unaddressed requirements, note it in the verdict reasoning but do not block on it alone. Apply the risk-aware degraded verdict rule from the [synthesis artifact contract](./references/synthesis-artifact-contract.md).
523
523
 
524
524
  Do not include time estimates.
525
525
 
@@ -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 persona return passes full-schema and environment-value
23
- validation. Rejected or never-returned personas do not produce per-agent
24
- files. If a later confidence or validation stage changes an input disposition,
25
- the parent updates the record and synthesis ledger before finalizing the
26
- artifact.
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
 
@@ -41,10 +43,15 @@ The artifact must preserve these distinctions:
41
43
  "dispatch_outcome": "findings",
42
44
  "input_finding_count": 2
43
45
  },
46
+ {
47
+ "persona": "testing",
48
+ "dispatch_outcome": "findings",
49
+ "input_finding_count": 1
50
+ },
44
51
  {
45
52
  "persona": "kieran-typescript",
46
53
  "dispatch_outcome": "malformed",
47
- "input_finding_count": 1,
54
+ "input_finding_count": 2,
48
55
  "rejection_reason": "Rejected persona kieran-typescript return: field findings[0].evidence failed schema validation."
49
56
  }
50
57
  ],
@@ -55,6 +62,14 @@ The artifact must preserve these distinctions:
55
62
  "confidence": 0.55,
56
63
  "disposition": "suppressed",
57
64
  "reason": "confidence 0.55 is below the 0.60 gate"
65
+ },
66
+ {
67
+ "reviewer": "kieran-typescript",
68
+ "dispatch_outcome": "malformed",
69
+ "rejected_finding_count": 2,
70
+ "rejected_severities": ["P2", "P3"],
71
+ "disposition": "rejected",
72
+ "reason": "Rejected persona kieran-typescript return: field findings[0].evidence failed schema validation."
58
73
  }
59
74
  ],
60
75
  "findings": [
@@ -73,7 +88,7 @@ The artifact must preserve these distinctions:
73
88
  "merged": 2,
74
89
  "suppressed": 1,
75
90
  "filtered": 0,
76
- "rejected": 0
91
+ "rejected": 2
77
92
  }
78
93
  }
79
94
  ```
@@ -84,16 +99,24 @@ The artifact must preserve these distinctions:
84
99
  naming persona and field without echoing the offending value. Dispatch
85
100
  outcome is separate from finding disposition.
86
101
  - `input_findings` is the authoritative parent-owned ledger. Before the
87
- confidence gate, every safely enumerable finding receives an `input_id` of
88
- `<reviewer>#<1-based finding index>`. Every enumerated input has exactly one
89
- final `disposition`: `surviving`, `merged`, `suppressed`, `filtered`, or
90
- `rejected`, plus a reason. Disposition counts equal the input-finding count.
91
- If a rejected return has a safely enumerable `findings` array, assign IDs and
92
- record each enumerated input as `rejected`.
93
- A malformed JSON return with no safely enumerable finding has zero ledger
94
- entries, not a fabricated finding. A rejected payload's reason is the exact
95
- safe rejection message, not a bucket such as `invalid`; never include the
96
- offending value.
102
+ confidence gate, every admitted finding receives an `input_id` of
103
+ `<reviewer>#<1-based finding index>`. Every admitted input has exactly one
104
+ final `disposition`: `surviving`, `merged`, `suppressed`, or `filtered`, plus
105
+ a reason. A rejected payload is represented by one summary ledger entry,
106
+ carrying the persona name, its `dispatch_outcome`, the
107
+ `rejected_finding_count` of findings not admitted, `disposition: "rejected"`,
108
+ `rejected_severities`, a list of the severities of the findings not
109
+ admitted as parsed from the payload, and the exact safe rejection message.
110
+ When a rejected finding's severity is absent, malformed, or not a valid
111
+ severity value, record it as `unknown`. Severity is metadata; recording it
112
+ never includes the offending value. Do not enumerate rejected findings or
113
+ assign them input IDs. A finding-level environment rejection uses the same
114
+ summary entry while admitted findings from that return continue normally.
115
+ Disposition counts are weighted by `rejected_finding_count` for that summary
116
+ entry, so their sum equals the total number of findings observed, not the
117
+ number of ledger rows. A malformed JSON return with no safely enumerable
118
+ finding has zero ledger entries, not a fabricated finding. Never include the
119
+ offending value in a rejection reason.
97
120
  - Synthesized and filtered findings retain their original fields plus
98
121
  `input_finding_ids` and provenance. Provenance contains the exact dedup
99
122
  fingerprint `normalize(file) + line_bucket(line, +/-3) + normalize(title)`,
@@ -120,8 +143,66 @@ the verdict is finalized. Existing artifacts without this additive metadata
120
143
  remain valid, with downstream consumers falling back to file mtime.
121
144
 
122
145
  Validation and persistence remain parent-side: no per-agent record or finding
123
- is written or merged until the complete persona payload passes schema and
124
- environment-value validation. Rejected or malformed persona returns do not
125
- fail the whole review; the review degrades while conforming returns continue
126
- through synthesis. Only an orchestration or storage failure that prevents the
127
- parent from producing the required run artifact is run-fatal.
146
+ is written or merged until that finding passes schema and environment-value
147
+ validation. Rejected findings are recorded through the single rejected-payload
148
+ ledger summary; admitted findings from the same return remain eligible for
149
+ synthesis. Rejected or malformed persona returns do not fail the whole review;
150
+ the review degrades while conforming returns continue through synthesis. Only
151
+ an orchestration or storage failure that prevents the parent from producing the
152
+ required run artifact is run-fatal.
153
+
154
+ ## Environment-value validation
155
+
156
+ The parent recursively inspects every string leaf without logging the raw
157
+ return or any matched value. Structural environment detectors remain
158
+ unbounded and unchanged: `$NAME`, `${NAME}`, `process.env.NAME`,
159
+ `os.environ[...]`, and `NAME=value` assignments using a known environment
160
+ variable name are shape-based checks.
161
+
162
+ Value-based matching uses only non-empty runtime environment values that are
163
+ at least 16 characters long and are not composed solely of digits, dots,
164
+ dashes, or path-separator characters (forward slash or backslash). A
165
+ value is also eligible regardless of length when
166
+ its variable name contains one of `TOKEN`, `SECRET`, `KEY`, `PASSWORD`,
167
+ `PASSWD`, `CREDENTIAL`, `AUTH`, `SESSION`, `COOKIE`, `PRIVATE`, `_PASS`,
168
+ `_PWD`, `PASSPHRASE`, or `_SALT`, matched as a case-insensitive substring.
169
+ Entries containing an underscore are matched against the variable name as
170
+ written; the underscore is deliberate and prevents matching benign names that
171
+ merely contain the bare word. Values that satisfy neither condition are not
172
+ matched. A match is an exact or embedded match.
173
+
174
+ If the offending string is inside one finding, drop that finding and record it
175
+ through the rejected-payload summary entry; the remaining findings continue
176
+ through validation and synthesis. If the offending string is outside any
177
+ finding, reject the whole payload. Every rejection uses only the persona name,
178
+ JSON path, and a fixed reason (`schema validation`, `environment-value
179
+ detection`, or `malformed JSON`):
180
+ `Rejected persona <name> return: field <JSON path> failed <reason>.` Never
181
+ echo the matched value.
182
+
183
+ ## Risk-aware degraded verdict
184
+
185
+ The risk-critical surfaces are `security`, `data-migrations`, `api-contract`,
186
+ `reliability`, and `performance`. They are the conditional personas selected
187
+ specifically for the matching diff shape in Stage 3. If one of those selected
188
+ personas has `dispatch_outcome: "malformed"` or
189
+ `dispatch_outcome: "never_returned"`, the review verdict must not be clean:
190
+ it is blocking unless another persona covered the same surface and returned
191
+ validated evidence for it. For this rule, validated evidence means at least
192
+ one finding from that other persona's return passed complete schema and
193
+ environment-value validation and is relevant to the same surface. A coverage
194
+ note alone cannot satisfy this rule; the verdict must reflect the missing
195
+ risk-critical evidence.
196
+
197
+ Finding-level rejection is keyed by the severities in
198
+ `rejected_severities`. A selected risk-critical persona whose rejected
199
+ findings include any `P0`, `P1`, or `unknown` severity is treated exactly as a
200
+ rejected persona for this verdict rule: blocking unless another persona
201
+ covered the same surface with validated evidence. A selected risk-critical
202
+ persona whose rejected findings are only `P2` or `P3` does not block on that
203
+ basis alone; record it in the Coverage section instead. Unknown severity is
204
+ treated as blocking as deliberate fail-closed behavior because the parent
205
+ could not determine what was lost. Admitted findings and verdict blocking
206
+ are independent: surviving findings from the same return continue through
207
+ synthesis normally. Partial return is not partial coverage when the lost
208
+ part was critical.