@fro.bot/systematic 3.13.3 → 3.13.5
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/dist/cli.js +6 -0
- package/dist/lib/review-artifact-schema.d.ts +5 -0
- package/package.json +1 -1
- package/skills/ce-plan/SKILL.md +2 -0
- package/skills/ce-review/SKILL.md +5 -3
- package/skills/ce-review/references/review-summary-schema.json +43 -0
- package/skills/ce-review/references/synthesis-artifact-contract.md +26 -7
package/dist/cli.js
CHANGED
|
@@ -2116,6 +2116,11 @@ var CoverageSchema = exports_external.object({
|
|
|
2116
2116
|
validator_failures: exports_external.array(ReasonSchema).max(MAX_PERSONAS),
|
|
2117
2117
|
intent_uncertainty: exports_external.array(ReasonSchema).max(MAX_PERSONAS)
|
|
2118
2118
|
}).strict();
|
|
2119
|
+
var DeclinedMergeSchema = exports_external.object({
|
|
2120
|
+
file: RepoRelativePathSchema,
|
|
2121
|
+
input_finding_ids: exports_external.array(boundedText(MAX_INPUT_ID_LENGTH)).min(2).max(MAX_FINDINGS),
|
|
2122
|
+
reason: ReasonSchema
|
|
2123
|
+
}).strict();
|
|
2119
2124
|
var ReviewArtifactSchema = exports_external.object({
|
|
2120
2125
|
schema_version: exports_external.literal(1),
|
|
2121
2126
|
run_id: boundedText(MAX_RUN_ID_LENGTH),
|
|
@@ -2134,6 +2139,7 @@ var ReviewArtifactSchema = exports_external.object({
|
|
|
2134
2139
|
dispatches: exports_external.array(DispatchSchema).max(MAX_PERSONAS),
|
|
2135
2140
|
input_findings: exports_external.array(InputFindingSchema).max(MAX_FINDINGS * MAX_PERSONAS),
|
|
2136
2141
|
findings: exports_external.array(SynthesizedFindingSchema).max(MAX_FINDINGS),
|
|
2142
|
+
declined_merges: exports_external.array(DeclinedMergeSchema).max(MAX_FINDINGS).optional(),
|
|
2137
2143
|
disposition_counts: DispositionCountsSchema,
|
|
2138
2144
|
applied_fixes: exports_external.array(ReasonSchema).max(MAX_FINDINGS),
|
|
2139
2145
|
residual_actionable_work: exports_external.array(ReasonSchema).max(MAX_FINDINGS),
|
|
@@ -218,6 +218,11 @@ export declare const ReviewArtifactSchema: z.ZodObject<{
|
|
|
218
218
|
agreement_credit: string[];
|
|
219
219
|
};
|
|
220
220
|
}>>>;
|
|
221
|
+
declined_merges: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
222
|
+
file: z.ZodString;
|
|
223
|
+
input_finding_ids: z.ZodArray<z.ZodString>;
|
|
224
|
+
reason: z.ZodString;
|
|
225
|
+
}, z.core.$strict>>>;
|
|
221
226
|
disposition_counts: z.ZodObject<{
|
|
222
227
|
surviving: z.ZodNumber;
|
|
223
228
|
merged: z.ZodNumber;
|
package/package.json
CHANGED
package/skills/ce-plan/SKILL.md
CHANGED
|
@@ -443,6 +443,8 @@ For each unit, include:
|
|
|
443
443
|
|
|
444
444
|
Every feature-bearing unit should include the test file path in `**Files:**`.
|
|
445
445
|
|
|
446
|
+
When a unit creates a file in a directory that carries registration obligations — a manifest, index, codemap, module table, or generated artifact that must list it — name those surfaces in the same unit's `**Files:**`, and name the regeneration command in its `**Verification**`. Phase 1.1 already collects this from the repository's own contributor guidance; carry it into the unit rather than leaving it for a failing gate to report. An obligation that no gate enforces is the one most likely to be missed, so state it even when nothing will fail.
|
|
447
|
+
|
|
446
448
|
Use `Execution note` sparingly. Good uses include:
|
|
447
449
|
- `Execution note: Start with a failing integration test for the request/response contract.`
|
|
448
450
|
- `Execution note: Add characterization coverage before modifying this legacy parser.`
|
|
@@ -468,8 +468,10 @@ Before applying the confidence gate, keep the parent-owned ledger through every
|
|
|
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
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
|
-
3. **Deduplicate.**
|
|
472
|
-
|
|
471
|
+
3. **Deduplicate.** Group all gated findings by `normalize(file)`. A file with two or more findings from different personas forms a candidate group. Do not use line number to form groups. Sort findings within each group by line. Adjudicate each candidate group: merge findings judged to describe the same underlying defect; keep genuinely different defects separate. Adjacency creates a candidate, not a conclusion -- findings on the same line that describe different defects must not merge. For each resulting finding, derive the fingerprint from its file and line as `normalize(file) + "|" + line`. Keep highest severity, keep highest confidence, and retain the input IDs that produced the merged entry. Record each declined merge in the artifact's optional `declined_merges` field with the normalized file, input finding IDs considered but not merged, and a brief reason. A singleton that passes the gate is `surviving`; each input in a multi-input merge is provisionally `merged`.
|
|
472
|
+
|
|
473
|
+
Worked example: at `src/lib/model-availability.ts:139`, reliability's `Config hook awaits providers API without a timeout` and adversarial's `Config startup can hang forever behind a stalled /config` describe the same underlying defect in different words, so they merge.
|
|
474
|
+
4. **Cross-reviewer agreement.** When an adjudicated merge contains findings from 2+ independent reviewers, 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).
|
|
473
475
|
5. **Separate pre-existing.** Pull out findings with `pre_existing: true` into a separate list.
|
|
474
476
|
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.
|
|
475
477
|
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.
|
|
@@ -596,7 +598,7 @@ Review complete
|
|
|
596
598
|
|
|
597
599
|
**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.
|
|
598
600
|
- **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.
|
|
599
|
-
- **In-memory matching:** For each surviving finding, look up its detail-tier fields in the validated returns of the contributing reviewers.
|
|
601
|
+
- **In-memory matching:** For each surviving finding, look up its detail-tier fields in the validated returns of the contributing reviewers. Use the merged finding's `input_finding_ids` (`<reviewer>#<1-based finding index>`) to identify the contributing return and source finding. When an input ID cannot be resolved or multiple candidates remain, match on normalized `file`, then use line and `normalize(title)` only as tie-breakers.
|
|
600
602
|
- **Reviewer order:** Try contributing reviewers in the order they appear in the merged finding's reviewer list; use the first validated match.
|
|
601
603
|
- **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.
|
|
602
604
|
|
|
@@ -374,6 +374,49 @@
|
|
|
374
374
|
"additionalProperties": false
|
|
375
375
|
}
|
|
376
376
|
},
|
|
377
|
+
"declined_merges": {
|
|
378
|
+
"maxItems": 32,
|
|
379
|
+
"type": "array",
|
|
380
|
+
"items": {
|
|
381
|
+
"type": "object",
|
|
382
|
+
"properties": {
|
|
383
|
+
"file": {
|
|
384
|
+
"type": "string",
|
|
385
|
+
"minLength": 1,
|
|
386
|
+
"maxLength": 256,
|
|
387
|
+
"allOf": [
|
|
388
|
+
{
|
|
389
|
+
"type": "string",
|
|
390
|
+
"pattern": "\\S"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"type": "string",
|
|
394
|
+
"pattern": "^(?!\\/)(?![A-Za-z]:[\\\\/])(?!\\\\).+"
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
},
|
|
398
|
+
"input_finding_ids": {
|
|
399
|
+
"minItems": 2,
|
|
400
|
+
"maxItems": 32,
|
|
401
|
+
"type": "array",
|
|
402
|
+
"items": {
|
|
403
|
+
"type": "string",
|
|
404
|
+
"minLength": 1,
|
|
405
|
+
"maxLength": 128,
|
|
406
|
+
"pattern": "\\S"
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
"reason": {
|
|
410
|
+
"type": "string",
|
|
411
|
+
"minLength": 1,
|
|
412
|
+
"maxLength": 2048,
|
|
413
|
+
"pattern": "\\S"
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"required": ["file", "input_finding_ids", "reason"],
|
|
417
|
+
"additionalProperties": false
|
|
418
|
+
}
|
|
419
|
+
},
|
|
377
420
|
"disposition_counts": {
|
|
378
421
|
"type": "object",
|
|
379
422
|
"properties": {
|
|
@@ -78,12 +78,19 @@ The artifact must preserve these distinctions:
|
|
|
78
78
|
"title": "<merged finding>",
|
|
79
79
|
"input_finding_ids": ["correctness#2", "testing#1"],
|
|
80
80
|
"provenance": {
|
|
81
|
-
"fingerprint": "<normalize(file) +
|
|
81
|
+
"fingerprint": "<normalize(file) + \"|\" + line>",
|
|
82
82
|
"submitters": ["correctness", "testing"],
|
|
83
83
|
"agreement_credit": []
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
],
|
|
87
|
+
"declined_merges": [
|
|
88
|
+
{
|
|
89
|
+
"file": "src/example.ts",
|
|
90
|
+
"input_finding_ids": ["correctness#3", "testing#2"],
|
|
91
|
+
"reason": "The findings concern separate validation paths."
|
|
92
|
+
}
|
|
93
|
+
],
|
|
87
94
|
"disposition_counts": {
|
|
88
95
|
"surviving": 0,
|
|
89
96
|
"merged": 2,
|
|
@@ -119,12 +126,24 @@ The artifact must preserve these distinctions:
|
|
|
119
126
|
finding has zero ledger entries, not a fabricated finding. Never include the
|
|
120
127
|
offending value in a rejection reason.
|
|
121
128
|
- Synthesized and filtered findings retain their original fields plus
|
|
122
|
-
`input_finding_ids` and provenance. Provenance contains the
|
|
123
|
-
|
|
124
|
-
`submitters
|
|
125
|
-
- `
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
`input_finding_ids` and provenance. Provenance contains the fingerprint
|
|
130
|
+
`normalize(file) + "|" + line`, derived from the merged finding's file and
|
|
131
|
+
line, plus `submitters` and `agreement_credit` arrays.
|
|
132
|
+
- `declined_merges` is optional. For each candidate group that is not merged,
|
|
133
|
+
record the normalized file, the input finding IDs considered and not merged,
|
|
134
|
+
and a brief reason. Candidate groups contain two or more findings from
|
|
135
|
+
different personas on the same normalized file; sort their findings by line.
|
|
136
|
+
Adjacency creates a candidate, not a conclusion: genuinely different
|
|
137
|
+
defects on the same line remain separate.
|
|
138
|
+
- A candidate group may resolve partially. When some findings in a group merge
|
|
139
|
+
and others stay separate, record one entry per declined separation, listing
|
|
140
|
+
the input finding IDs on both sides of it. A group of three where two merge
|
|
141
|
+
and one stays separate records a single entry naming all three IDs, with a
|
|
142
|
+
reason describing why the third is a different defect. Record the separation,
|
|
143
|
+
not the merge; a fully merged group produces no entry.
|
|
144
|
+
- `submitters` contains only personas with an input finding in the adjudicated
|
|
145
|
+
merge. `agreement_credit` contains only personas credited by the
|
|
146
|
+
cross-reviewer agreement boost without an input finding in that merge. A
|
|
128
147
|
persona returning zero findings never appears in `submitters`; do not infer
|
|
129
148
|
submission from the report's Reviewer column.
|
|
130
149
|
- A `filtered` finding remains available for human review with the validator's
|