opencode-swarm 7.146.2 → 7.146.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.
Files changed (86) hide show
  1. package/.opencode/skills/swarm-pr-review/SKILL.md +27 -44
  2. package/.opencode/skills/swarm-pr-review/references/findings-persistence-contract.md +52 -12
  3. package/.opencode/skills/swarm-pr-review/references/lane-output-recoverability.md +6 -3
  4. package/.opencode/skills/swarm-pr-review/references/parser-dry-run.md +19 -1
  5. package/.opencode/skills/swarm-pr-review/references/verdict-settlement-contract.md +41 -0
  6. package/dist/agents/council-prompts.d.ts +3 -3
  7. package/dist/background/candidate-contract.d.ts +21 -1
  8. package/dist/background/candidate-parser.d.ts +21 -1
  9. package/dist/background/pending-delegations.d.ts +8 -1
  10. package/dist/background/pr-review-collection-receipt.d.ts +70 -0
  11. package/dist/cli/{config-doctor-vstrprja.js → config-doctor-578ebqhn.js} +2 -2
  12. package/dist/cli/{core-3wzpwe5z.js → core-2ne03a43.js} +1 -1
  13. package/dist/cli/{curation-policy-x19e8bqc.js → curation-policy-g353f457.js} +6 -6
  14. package/dist/cli/{curator-llm-factory-6bra0bfd.js → curator-llm-factory-6hgn7p6n.js} +27 -27
  15. package/dist/cli/{curator-cvy1s7wd.js → curator-w52frg17.js} +27 -27
  16. package/dist/cli/{evidence-summary-service-yhap2xph.js → evidence-summary-service-nj4p6a0d.js} +11 -11
  17. package/dist/cli/{gate-evidence-vxbyq5sb.js → gate-evidence-4vnjdh9y.js} +6 -6
  18. package/dist/cli/{guardrail-explain-h8cnwa02.js → guardrail-explain-rq01z1yz.js} +28 -28
  19. package/dist/cli/{guardrail-log-syb7tz2w.js → guardrail-log-ratb651f.js} +3 -3
  20. package/dist/cli/{hive-promoter-3tex870c.js → hive-promoter-pbm9kee1.js} +27 -27
  21. package/dist/cli/{index-yxhcy5cm.js → index-1mbdwy12.js} +55 -1
  22. package/dist/cli/{index-01ybcsa5.js → index-3neh2mxk.js} +2 -2
  23. package/dist/cli/{index-5e5a1y2r.js → index-3p4wgm0d.js} +1 -1
  24. package/dist/cli/{index-4vwn66wk.js → index-5cbbtbvf.js} +3 -3
  25. package/dist/cli/{index-z5ppkn8y.js → index-6eycwm3v.js} +6 -6
  26. package/dist/cli/{index-bghwrr59.js → index-6q35swn2.js} +1 -1
  27. package/dist/cli/{index-qbpxrw95.js → index-8py21zn6.js} +2 -2
  28. package/dist/cli/{index-tj861zhd.js → index-96zkay2e.js} +4 -4
  29. package/dist/cli/{index-y3hmyvt6.js → index-bq4mvwht.js} +2 -2
  30. package/dist/cli/{index-rfph0nhf.js → index-brb64k96.js} +1426 -635
  31. package/dist/cli/{index-p0m03xa6.js → index-df8xj9hr.js} +4 -4
  32. package/dist/cli/{index-cr90rcg3.js → index-dp5w9s5z.js} +7 -7
  33. package/dist/cli/{index-w0cj7zyd.js → index-f75qjtn5.js} +1 -1
  34. package/dist/cli/{index-vmfaafte.js → index-ffqdah8s.js} +5 -5
  35. package/dist/cli/{index-f3x2gsby.js → index-fp2d44f5.js} +1 -1
  36. package/dist/cli/{index-jv9xs6mb.js → index-g2r8nknz.js} +2 -2
  37. package/dist/cli/{index-n4k0pt5f.js → index-g335vrc7.js} +4 -4
  38. package/dist/cli/{index-z9ed68jt.js → index-gr3zfcsh.js} +18 -4
  39. package/dist/cli/{index-w5r84rd1.js → index-hcb25p12.js} +1 -1
  40. package/dist/cli/{index-ycgm9pzg.js → index-hw1yghpg.js} +7 -6
  41. package/dist/cli/{index-a1febb2k.js → index-jgwhpza8.js} +2 -2
  42. package/dist/cli/{index-cx67qa9g.js → index-kjmcp9mf.js} +1 -1
  43. package/dist/cli/{index-42nq97rb.js → index-kv2j4cnq.js} +6 -6
  44. package/dist/cli/{index-zkaz3fhw.js → index-p3k155dv.js} +2 -2
  45. package/dist/cli/{index-qyvjp0bq.js → index-q81s0m8k.js} +66 -37
  46. package/dist/cli/{index-97psh79d.js → index-rpy0bent.js} +178 -18
  47. package/dist/cli/{index-r46q6996.js → index-t798v5pq.js} +29 -29
  48. package/dist/cli/{index-e1hjd15c.js → index-tp5ytzzg.js} +1 -1
  49. package/dist/cli/{index-vj9bba5k.js → index-vdrwj7z0.js} +4 -4
  50. package/dist/cli/{index-46cypnz3.js → index-wesj94x0.js} +4 -4
  51. package/dist/cli/{index-c9jr4j2q.js → index-xsxj4vbf.js} +1 -1
  52. package/dist/cli/index.js +27 -27
  53. package/dist/cli/{knowledge-escalator-mn4sx4qd.js → knowledge-escalator-jbazxmk5.js} +11 -11
  54. package/dist/cli/{knowledge-events-x975ngy4.js → knowledge-events-jyqy3st8.js} +9 -9
  55. package/dist/cli/{knowledge-link-8pr02pza.js → knowledge-link-jkx8xjxp.js} +5 -5
  56. package/dist/cli/{knowledge-store-33p762ey.js → knowledge-store-e2defagd.js} +6 -6
  57. package/dist/cli/{knowledge-validator-q5jc0scs.js → knowledge-validator-pnmdsw2b.js} +8 -8
  58. package/dist/cli/{pending-delegations-kkrczqv7.js → pending-delegations-k2yqg1sj.js} +3 -3
  59. package/dist/cli/{pr-subscriptions-2xn238xt.js → pr-subscriptions-js5v2xr6.js} +3 -3
  60. package/dist/cli/{runner-e7z9cf5y.js → runner-q7d22d1w.js} +6 -6
  61. package/dist/cli/{scan-cursor-p7t5mb4x.js → scan-cursor-snx85enn.js} +7 -7
  62. package/dist/cli/{schema-t8bmshhj.js → schema-6rmxzg6g.js} +1 -1
  63. package/dist/cli/{scope-persistence-2kyrgsca.js → scope-persistence-23cqafkx.js} +7 -7
  64. package/dist/cli/{skill-generator-fwvmcv8m.js → skill-generator-980zjk9q.js} +13 -13
  65. package/dist/cli/{telemetry-t109dhv7.js → telemetry-xzy0qeap.js} +1 -1
  66. package/dist/cli/{worktree-collision-ownership-2jtg2my1.js → worktree-collision-ownership-xj0bsg92.js} +3 -3
  67. package/dist/cli/{worktree-isolation-87j70zg1.js → worktree-isolation-4d0nc04c.js} +27 -27
  68. package/dist/commands/close.d.ts +1 -0
  69. package/dist/commands/context-map-stats.d.ts +5 -0
  70. package/dist/config/schema.d.ts +16 -0
  71. package/dist/context-map/telemetry.d.ts +168 -26
  72. package/dist/council/council-evidence-writer.d.ts +2 -1
  73. package/dist/council/council-freshness.d.ts +49 -0
  74. package/dist/council/council-review-identity.d.ts +133 -0
  75. package/dist/council/council-round-state.d.ts +27 -3
  76. package/dist/council/disagreement-detector.d.ts +12 -2
  77. package/dist/council/general-council-types.d.ts +32 -0
  78. package/dist/council/types.d.ts +43 -7
  79. package/dist/hooks/pr-workflow-gate.d.ts +58 -5
  80. package/dist/index.js +177 -152
  81. package/dist/observability/catalog.d.ts +7 -5
  82. package/dist/telemetry.d.ts +22 -1
  83. package/dist/tools/dispatch-lanes.d.ts +30 -8
  84. package/dist/tools/phase-complete/gates/types.d.ts +7 -0
  85. package/dist/tools/write-final-council-evidence.d.ts +1 -7
  86. package/package.json +2 -1
@@ -689,7 +689,7 @@ the review head SHA recorded at the top.
689
689
  Each persisted finding record must include at least:
690
690
 
691
691
  ```json
692
- {"finding_id":"F-001","status":"PENDING","file_line":"src/file.ts:123","evidence":"quote, command output, lane id, or reviewer rationale","next_action":"route_to_reviewer"}
692
+ {"finding_id":"F-001","status":"PENDING","file_line":"src/file.ts:123","evidence":"quote, command output, lane id, or reviewer rationale","next_action":"route_to_reviewer","severity":"HIGH"}
693
693
  ```
694
694
 
695
695
  Minimum field contract:
@@ -697,10 +697,9 @@ Minimum field contract:
697
697
  - `finding_id`: stable ID from the candidate/reviewer/critic ledger.
698
698
  - `status`: one of `PENDING`, `CONFIRMED`, `DISPROVED`, or `PRE_EXISTING`.
699
699
  - `file_line`: exact `file:line`, or `N/A` with reason when cross-file.
700
- - `evidence`: compact source-backed proof (lane/reviewer/critic IDs or command
701
- output references when available).
702
- - `next_action`: `route_to_reviewer`, `route_to_critic`, `report`,
703
- `suppress_with_reason`, or `handoff_to_feedback`.
700
+ - `evidence`: compact source-backed proof (lane/reviewer/critic IDs or command output references when available).
701
+ - `next_action`: `route_to_reviewer`, `route_to_critic`, `report`, `suppress_with_reason`, or `handoff_to_feedback`.
702
+ - `severity`: REQUIRED at every boundary — omitting it is a violation, not a shortcut. Vocabulary is the VERDICT dialect `INFO|LOW|MEDIUM|HIGH|CRITICAL|NONE`. At `post_explorer` it must equal the severity of the `[CANDIDATE]` row the record projects (so never `NONE`, which no candidate row can declare) — except the mechanically derived `CLEAN-REVIEW` sentinel emitted when discovery found nothing, whose severity is `NONE`; at `post_reviewer` the reviewer `final_severity`; at `post_critic` the **critic** `final_severity` for critic-routed records, otherwise the reviewer's (issue #2279).
704
703
 
705
704
  Persist after every major validation boundary (Profile A via the controller
706
705
  calls below; Profiles B/C by appending the same boundary-tagged records to the
@@ -714,8 +713,8 @@ ledger file):
714
713
  record to `CONFIRMED`, `DISPROVED`, `PRE_EXISTING`, or keep `PENDING` with a
715
714
  concrete `next_action` if more evidence is required.
716
715
  3. **Post-critic:** after Phase 8 critic challenge, call the controller with
717
- `boundary: "post_critic"` and update final status,
718
- severity/action notes in `evidence`, and final reporting or handoff action.
716
+ `boundary: "post_critic"` and update final status, the authoritative
717
+ `severity`, and final reporting or handoff action.
719
718
 
720
719
  **Enforced order, dispositions, and error reporting (Profile A).** Checkpoints
721
720
  are admitted only after the trigger evaluation completes, then strictly
@@ -723,7 +722,7 @@ are admitted only after the trigger evaluation completes, then strictly
723
722
  checkpoint persisted; records must match the authoritative reviewer/critic
724
723
  verdict rows, and an invalid payload is rejected in ONE call listing every
725
724
  violation as `finding_id: field expected <value>, got <value>`. Full contract
726
- (write order, disposition matrix, severity-omission, handoff schema):
725
+ (write order, dispositions, severity authority table, handoff schema):
727
726
  references/findings-persistence-contract.md.
728
727
 
729
728
  Resume/reload procedure: read the latest `findings.jsonl` and reconstruct the
@@ -983,7 +982,7 @@ build a minimal correct single-lane reproduction using the same workflow mode,
983
982
  lane identity, exact head, and canonical row. Before retrying, distinguish the
984
983
  three independent input layers: the header schema, data-row values, and tool
985
984
  argument shape. A correct header does not repair an invalid severity or lane
986
- value, and correct row data does not repair malformed dispatch JSON. Benign shape defects (evidence pipes, marker rows, verdict-row pipes) are auto-repaired and recorded as salvage — never a retry reason alone (contract and fidelity boundaries: `references/lane-output-recoverability.md`).
985
+ value, and correct row data does not repair malformed dispatch JSON. Benign shape defects (evidence pipes, marker rows, verdict-row pipes, a header re-emitted as a data row) are auto-repaired and recorded as salvage — never a retry reason alone; the `parse_lane_candidates` receipt discloses them as `repair_kinds`, and a `[CLEAN]` attestation discredited beside a same-lane `[CANDIDATE]` row as `clean_attestation_salvaged` + `clean_attestation_salvage_reason` (the parse SUCCEEDS and the attestation still supplies no coverage) (contract and fidelity boundaries: `references/lane-output-recoverability.md`).
987
986
 
988
987
  Classify the incident from actual user-visible harm and the first failed
989
988
  predicate, not from the number of retries or the eventual result. A successful
@@ -1338,6 +1337,11 @@ file area, category, or count — not the full candidate set. The reviewer must
1338
1337
  re-read the candidate's file:line evidence and relevant context pack entries
1339
1338
  directly.
1340
1339
 
1340
+ A reviewer or critic chunk may own any non-empty subset of the current
1341
+ inventory. On a retry, that subset may overlap prior successful work; the lane
1342
+ contract is the assigned item set for that chunk, not a requirement to re-own
1343
+ the full inventory every time.
1344
+
1341
1345
  Under Profile A, dispatch reviewer chunks with `dispatch_lanes_async`,
1342
1346
  `mode: "swarm-pr-review:reviewer"`, a unique non-empty `workflow_lane` per
1343
1347
  chunk, `review_item_ids` containing the exact candidate IDs assigned to that
@@ -1364,8 +1368,10 @@ Reviewer ownership is not accepted as an architect assertion. Under Profile A,
1364
1368
  the controller derives the immutable candidate inventory from the
1365
1369
  integrity-checked base, mandatory micro-lane, and council artifacts; under
1366
1370
  Profiles B/C, the orchestrator derives the same inventory from the persisted
1367
- ledgers. Either way, the union of `review_item_ids` must equal that inventory
1368
- exactly, with no omitted or invented IDs. If discovery produces no candidates,
1371
+ ledgers. Either way, successful reviewer batches compose item by item: the
1372
+ union of their accepted `review_item_ids` must equal that inventory exactly,
1373
+ with the newest successful verdict winning for each item. If discovery produces
1374
+ no candidates,
1369
1375
  the derived sentinel is `CLEAN-REVIEW`, which still requires one independent
1370
1376
  semantic reviewer row (a fresh subagent on Profile B; a separate reviewer pass
1371
1377
  on Profile C).
@@ -1436,7 +1442,8 @@ assigned candidate. A malformed `[REVIEWED]` row is not a verdict: re-dispatch
1436
1442
  with the exact contract (max 2), then mark the reviewer dimension BLOCKED if no
1437
1443
  valid row returns.
1438
1444
 
1439
- `DISPROVED` findings must include the reason. `PRE_EXISTING` findings must include the base-branch evidence if available.
1445
+ `DISPROVED` reviewer rows must use `NONE` for `final_severity`. `PRE_EXISTING`
1446
+ findings must include the base-branch evidence if available.
1440
1447
 
1441
1448
  After reviewer lanes settle, persist the post-reviewer finding ledger before
1442
1449
  critic routing or synthesis. The artifact must preserve `CONFIRMED`,
@@ -1473,38 +1480,14 @@ machine enforcement cannot safely infer every repository-specific trust
1473
1480
  boundary from prose. Completion is blocked until that exact derived inventory
1474
1481
  has valid critic rows.
1475
1482
 
1476
- Reviewer and critic settlement compose across batches, item by item: a phase
1477
- settles once every review item in the current mechanically assigned inventory
1478
- holds a successful verdict, whether that coverage comes from one batch or from
1479
- several complementary partial retries. A later degraded, truncated, stale,
1480
- wrong-identity, or malformed batch never supplies a verdict for the items it
1481
- touches, but it does not discard verdicts other batches already supplied for
1482
- different items.
1483
-
1484
- When more than one successful batch covers the same item, the most recent
1485
- successful batch wins that item. This conflict rule is one shared computation,
1486
- so settlement and every downstream verdict use (candidate inventory, critic
1487
- routing, final synthesis) never disagree about which claim is authoritative
1488
- for an item. A batch contributes only when it was validated against the exact
1489
- candidate inventory current at validation time; a batch recorded before that
1490
- binding existed contributes only if it is wholly successful and its item set
1491
- exactly matches the current inventory — the historical all-or-nothing rule,
1492
- preserved unchanged for state that predates composition.
1493
-
1494
- A critic claim is bound per item to the exact reviewer row it was validated
1495
- against, not to the reviewer batch as a whole. A reviewer retry that
1496
- reproduces a byte-identical row for an item retains that item's critic work;
1497
- a reviewer row that changed at all — even one field — invalidates only that
1498
- item's critic claim, not the whole critic wave. Critic batches recorded
1499
- before per-item binding existed keep the old behavior: any newer reviewer
1500
- batch invalidates them wholesale. Dispatch a fresh critic wave to cover
1501
- whatever items composition leaves unclaimed; critic evidence can never
1502
- predate the reviewer evidence it purports to challenge.
1503
-
1504
- Settlement is item completeness, not lane completeness: a declared lane that
1505
- never completes produces a diagnostic naming the abandoned lane, not an
1506
- automatic block, as long as every item in the inventory already holds a
1507
- successful verdict from some lane.
1483
+ Reviewer and critic settlement MUST compose successful verdicts item by item
1484
+ across complementary partial batches. The newest successful claim wins each
1485
+ item; malformed or stale batches contribute nothing without erasing healthy
1486
+ sibling claims. Collection MUST validate exact lane ownership atomically, and
1487
+ critic claims MUST bind to the exact reviewer row for their item. Settlement is
1488
+ item completeness, not lane completeness. Follow the full retry, legacy,
1489
+ binding, and diagnostic contract in
1490
+ [`references/verdict-settlement-contract.md`](references/verdict-settlement-contract.md).
1508
1491
 
1509
1492
  Under Profile A, dispatch critic chunks with `dispatch_lanes_async`,
1510
1493
  `mode: "swarm-pr-review:critic"`, a unique non-empty `workflow_lane` per
@@ -63,14 +63,53 @@ At `post_explorer` every record must be `PENDING` with
63
63
 
64
64
  ## Severity semantics
65
65
 
66
- `severity` is optional at every boundary and is not validated on
67
- `post_explorer` records. When present it must equal the authoritative severity
68
- verbatim: the reviewer `final_severity` at `post_reviewer` (and for
69
- non-critic-routed records at `post_critic`); for critic-routed records at
70
- `post_critic` it must satisfy BOTH the reviewer and critic severities so
71
- when the critic downgrades (reviewer `MEDIUM`, critic `LOW`), the only
72
- accepted record omits `severity` entirely until the severity-dialect
73
- unification lands (#2279). Omitting the field is accepted at every boundary.
66
+ `severity` is REQUIRED on every findings record, at every boundary. Omitting it
67
+ is a violation, not a shortcut the rejection names the value you owed, e.g.
68
+ `severity expected "MEDIUM", got (omitted)` (issue #2279).
69
+
70
+ The vocabulary is the VERDICT dialect `INFO | LOW | MEDIUM | HIGH | CRITICAL |
71
+ NONE` because a findings record is a projection of an authenticated
72
+ `[REVIEWED]`/`[CRITIC]` row. `NONE` is a first-class value here: a `DISPROVED`
73
+ critic verdict is required to carry it, and a CONFIRMED-but-cosmetic reviewer
74
+ verdict legitimately does. (This is a WIDER set than the `[CANDIDATE]` row
75
+ severities, which exclude `NONE` — a discovered candidate asserting "no severity"
76
+ is a contradiction.)
77
+
78
+ Exactly one authority applies per record; there is never a value that must
79
+ satisfy two:
80
+
81
+ | Boundary | Routing | `severity` must equal |
82
+ | --- | --- | --- |
83
+ | `post_explorer` | has a `[CANDIDATE]` row | the severity that row declared (never `NONE`) |
84
+ | `post_explorer` | `CLEAN-REVIEW` with no row | `NONE` |
85
+ | `post_reviewer` | any | the reviewer `final_severity` |
86
+ | `post_critic` | not critic-routed | the reviewer `final_severity` |
87
+ | `post_critic` | critic-routed | the **critic** `final_severity` — the final word |
88
+
89
+ A record is critic-routed when the reviewer classification is `CONFIRMED` and the
90
+ reviewer severity is `CRITICAL`, `HIGH`, or `MEDIUM`.
91
+
92
+ Because the critic is authoritative for critic-routed records, a **downgrade is
93
+ encodable verbatim**: reviewer `MEDIUM` + critic `LOW` persists as
94
+ `severity: "LOW"` and validates. The former rule — omit the field when the two
95
+ authorities disagree — is gone; it disabled the comparison against both
96
+ authorities and is now itself rejected.
97
+
98
+ At `post_explorer` the authority is the `[CANDIDATE]` row the record projects:
99
+ the severity must equal what that row declared, compared exactly (issue #2320).
100
+ Because candidate rows validate against the candidate vocabulary, `NONE` can
101
+ never match one.
102
+
103
+ The one exception is the mechanically derived `CLEAN-REVIEW` sentinel, emitted
104
+ as the whole inventory when discovery found nothing at all. It has no
105
+ `[CANDIDATE]` row, so its severity is `NONE` — the same value its mandated
106
+ reviewer row carries — and a zero-finding review never has to invent a severity
107
+ and then change it.
108
+
109
+ `CLEAN-REVIEW` is **not a reserved id**: `candidate_id` is free text, so a lane
110
+ may name a real finding that. The rule is therefore keyed on the authority, not
111
+ the name — whenever a `[CANDIDATE]` row exists for the id, that row wins and its
112
+ severity is compared exactly. The sentinel rule applies only when no row exists.
74
113
 
75
114
  ## Error reporting
76
115
 
@@ -86,10 +125,11 @@ BLOCKED: PR_REVIEW post_reviewer artifact invalid — 4 violation(s):
86
125
  C-1: severity expected "HIGH", got "LOW"
87
126
  ```
88
127
 
89
- A critic-downgraded record that carries a severity is told the only passing
90
- value explicitly: `severity expected NONE (omit field; reviewer "MEDIUM" and
91
- critic "LOW" disagree), got "LOW"`. Repair every listed violation and resubmit
92
- in a single round trip; do not guess-and-retry one record at a time.
128
+ A critic-downgraded record is compared against the critic alone, so carrying the
129
+ stale reviewer value is reported plainly: `severity expected "LOW", got "MEDIUM"`.
130
+ An omitted severity is reported the same way: `severity expected "LOW", got
131
+ (omitted)`. Repair every listed violation and resubmit in a single round trip; do
132
+ not guess-and-retry one record at a time.
93
133
 
94
134
  ## Handoff artifact schema
95
135
 
@@ -48,10 +48,13 @@ their exact owned workflow lanes are marked salvaged. Council, reviewer, and
48
48
  critic outputs remain fail-closed and require retry when incomplete. `[CLEAN]`
49
49
  is absence evidence and therefore requires a complete transcript. One positive
50
50
  row in a consolidated lane never salvages a sibling dimension whose only
51
- evidence is `[CLEAN]` or missing. Recovery reasons are lane-scoped and use four
51
+ evidence is `[CLEAN]` or missing. Recovery reasons are lane-scoped and use five
52
52
  kinds: `parser-normalization`, `parser-row-recovery`,
53
- `truncated-preview-durable-artifact`, and
54
- `transcript-incomplete-terminal-candidate`.
53
+ `truncated-preview-durable-artifact`,
54
+ `transcript-incomplete-terminal-candidate`, and
55
+ `clean-attestation-salvaged` (a `[CLEAN]` attestation conflicting with a
56
+ same-lane `[CANDIDATE]` row was discredited while the candidate rows were
57
+ retained — the attestation contributes no coverage).
55
58
 
56
59
  ## Verdict-row pipe tolerance and its fidelity boundary
57
60
 
@@ -48,7 +48,25 @@ The orchestrator calls `parse_lane_candidates` for each `output_ref`:
48
48
 
49
49
  ### Step 2 — Structured response
50
50
 
51
- The parser returns a `ParseResultWithSidecar`. On success, `error` and `error_code` are absent:
51
+ The parser returns a `ParseResultWithSidecar`. On success, `error` and `error_code` are absent.
52
+
53
+ A successful receipt may additionally carry **salvage disclosure** fields, which
54
+ report that the artifact was accepted only after a narrow, auditable repair —
55
+ never that it was pristine (issue #2279):
56
+
57
+ - `repair_kinds` — structural repairs applied before the strict parse, e.g.
58
+ `["duplicate-header-row-dropped"]` when a canonical header was re-emitted as a
59
+ data row, or `["synthesized-header"]`, `["summary-row-dropped"]`.
60
+ - `clean_attestation_salvaged: true` plus `clean_attestation_salvage_reason` — a
61
+ `[CLEAN]` attestation conflicted with a same-lane `[CANDIDATE]` row, so the
62
+ attestation was discredited while the candidate rows were retained. The parse
63
+ SUCCEEDS. Do **not** read this as coverage: `clean_attestation` is absent
64
+ whenever it is set, so a lane with no candidate rows still fails coverage.
65
+ A `[CLEAN]` that failed for any other reason (degraded or partial source,
66
+ duplicate attestation, lane mismatch) still hard-errors and never reports a
67
+ salvage.
68
+
69
+ Example success receipt:
52
70
 
53
71
  ```json
54
72
  {
@@ -0,0 +1,41 @@
1
+ # Verdict settlement contract
2
+
3
+ Reviewer and critic settlement composes across batches, item by item. A phase
4
+ settles once every review item in the current mechanically assigned inventory
5
+ holds a successful verdict, whether that coverage comes from one batch or from
6
+ several complementary partial retries. A later degraded, truncated, stale,
7
+ wrong-identity, or malformed batch never supplies a verdict for the items it
8
+ touches, but it does not discard verdicts other batches already supplied for
9
+ different items.
10
+
11
+ When more than one successful batch covers the same item, the most recent
12
+ successful batch wins that item. This conflict rule is one shared computation,
13
+ so settlement and every downstream verdict use—candidate inventory, critic
14
+ routing, and final synthesis—never disagree about which claim is authoritative
15
+ for an item. A batch contributes only the items it was validated for against
16
+ the exact candidate inventory current at validation time. Partial batches are
17
+ first-class inputs, not an error state. Legacy artifacts that predate exact
18
+ item binding remain all-or-nothing and MUST validate against their complete
19
+ recorded inventory before they contribute any claim.
20
+
21
+ Collection validates every dispatched reviewer or critic lane against the exact
22
+ assigned verdict rows and records lane-atomic accepted and rejected IDs before
23
+ settlement. A malformed, missing, or surplus row never silently upgrades the
24
+ lane: the lane accepts every assigned ID only when the complete assigned row set
25
+ is valid; otherwise it rejects every assigned ID for precise re-dispatch. The
26
+ lane report MUST disclose both sets.
27
+
28
+ A critic claim binds per item to the exact reviewer row it was validated
29
+ against, not to the reviewer batch as a whole. A reviewer retry that reproduces
30
+ a byte-identical row for an item retains that item's critic work. A reviewer row
31
+ that changes at all—even one field—invalidates only that item's critic claim,
32
+ not the whole critic wave. Critic batches recorded before per-item binding
33
+ existed keep the legacy behavior: any newer reviewer batch invalidates them
34
+ wholesale. Dispatch a fresh critic wave to cover whatever items composition
35
+ leaves unclaimed. Critic evidence can never predate the reviewer evidence it
36
+ purports to challenge.
37
+
38
+ Settlement is item completeness, not lane completeness. A declared lane that
39
+ never completes produces a diagnostic naming the abandoned lane, not an
40
+ automatic block, as long as every item in the inventory already holds a
41
+ successful verdict from some lane.
@@ -21,6 +21,6 @@
21
21
  * MAINTAIN/CONCEDE/NUANCE for disagreements) is preserved verbatim, as is
22
22
  * the JSON response schema consumed by convene_general_council.
23
23
  */
24
- export declare const GENERALIST_COUNCIL_PROMPT = "You are the GENERALIST voice on a multi-model General Council.\n\nYou are the GENERALIST voice on this council. Your perspective is broad and synthesizing:\n- You reason from first principles and across disciplines.\n- You weigh competing considerations without domain bias.\n- You surface tensions between different valid approaches.\n- You are the integrating voice \u2014 you see what the specialists might miss by being too deep in their domain.\nMember ID: \"council_generalist\" | Role: \"generalist\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
25
- export declare const SKEPTIC_COUNCIL_PROMPT = "You are the SKEPTIC voice on a multi-model General Council.\n\nYou are the SKEPTIC voice on this council. Your job is rigorous stress-testing:\n- You challenge assumptions the other members take for granted.\n- You look for weak points, edge cases, and unstated dependencies.\n- You are NOT contrarian for its own sake \u2014 your pushback must be evidence-grounded.\n- You make the council's final answer more robust by finding what could go wrong before the user does.\nMember ID: \"council_skeptic\" | Role: \"skeptic\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
26
- export declare const DOMAIN_EXPERT_COUNCIL_PROMPT = "You are the DOMAIN EXPERT voice on a multi-model General Council.\n\nYou are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:\n- You go deep where others stay broad.\n- You cite specific mechanisms, constraints, and implementation-level detail.\n- You surface edge cases and gotchas that only emerge at depth.\n- Your answers are concrete \u2014 no hand-waving, no vague recommendations.\nMember ID: \"council_domain_expert\" | Role: \"domain_expert\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
24
+ export declare const GENERALIST_COUNCIL_PROMPT = "You are the GENERALIST voice on a multi-model General Council.\n\nYou are the GENERALIST voice on this council. Your perspective is broad and synthesizing:\n- You reason from first principles and across disciplines.\n- You weigh competing considerations without domain bias.\n- You surface tensions between different valid approaches.\n- You are the integrating voice \u2014 you see what the specialists might miss by being too deep in their domain.\nMember ID: \"council_generalist\" | Role: \"generalist\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"claims\": [\n {\n \"subject\": \"The specific question or decision this claim is about\",\n \"statement\": \"Your position on that subject, in one or two sentences\",\n \"stance\": \"support\",\n \"confidence\": 0.8,\n \"evidence\": [\"URL or source reference, if any\"]\n }\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- `claims` is optional but strongly encouraged (max 8): list your key positions as bounded structured claims. Use one of these `stance` values exactly: \"support\" (the position holds), \"oppose\" (the position is wrong \u2014 a contrary position), \"alternative\" (a different option is better \u2014 a contrary position), \"concern\" (risk flagged without taking a side), \"neutral\" (no position). Claims make contrary positions detectable even without explicit disagreement phrasing.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
25
+ export declare const SKEPTIC_COUNCIL_PROMPT = "You are the SKEPTIC voice on a multi-model General Council.\n\nYou are the SKEPTIC voice on this council. Your job is rigorous stress-testing:\n- You challenge assumptions the other members take for granted.\n- You look for weak points, edge cases, and unstated dependencies.\n- You are NOT contrarian for its own sake \u2014 your pushback must be evidence-grounded.\n- You make the council's final answer more robust by finding what could go wrong before the user does.\nMember ID: \"council_skeptic\" | Role: \"skeptic\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"claims\": [\n {\n \"subject\": \"The specific question or decision this claim is about\",\n \"statement\": \"Your position on that subject, in one or two sentences\",\n \"stance\": \"support\",\n \"confidence\": 0.8,\n \"evidence\": [\"URL or source reference, if any\"]\n }\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- `claims` is optional but strongly encouraged (max 8): list your key positions as bounded structured claims. Use one of these `stance` values exactly: \"support\" (the position holds), \"oppose\" (the position is wrong \u2014 a contrary position), \"alternative\" (a different option is better \u2014 a contrary position), \"concern\" (risk flagged without taking a side), \"neutral\" (no position). Claims make contrary positions detectable even without explicit disagreement phrasing.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
26
+ export declare const DOMAIN_EXPERT_COUNCIL_PROMPT = "You are the DOMAIN EXPERT voice on a multi-model General Council.\n\nYou are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:\n- You go deep where others stay broad.\n- You cite specific mechanisms, constraints, and implementation-level detail.\n- You surface edge cases and gotchas that only emerge at depth.\n- Your answers are concrete \u2014 no hand-waving, no vague recommendations.\nMember ID: \"council_domain_expert\" | Role: \"domain_expert\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"claims\": [\n {\n \"subject\": \"The specific question or decision this claim is about\",\n \"statement\": \"Your position on that subject, in one or two sentences\",\n \"stance\": \"support\",\n \"confidence\": 0.8,\n \"evidence\": [\"URL or source reference, if any\"]\n }\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- `claims` is optional but strongly encouraged (max 8): list your key positions as bounded structured claims. Use one of these `stance` values exactly: \"support\" (the position holds), \"oppose\" (the position is wrong \u2014 a contrary position), \"alternative\" (a different option is better \u2014 a contrary position), \"concern\" (risk flagged without taking a side), \"neutral\" (no position). Claims make contrary positions detectable even without explicit disagreement phrasing.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n\n## READ-ONLY ADVISORY LANE CONTEXT\n\nYou may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.\n\n- Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.\n- Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.\n- Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.\n- Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.\n";
@@ -1,5 +1,25 @@
1
1
  export declare const CANDIDATE_SEVERITIES: readonly ["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"];
2
2
  export type CandidateSeverity = (typeof CANDIDATE_SEVERITIES)[number];
3
+ /**
4
+ * Severity vocabulary of the PR-review FINDINGS artifact.
5
+ *
6
+ * A findings record is a projection of an authenticated `[REVIEWED]`/`[CRITIC]`
7
+ * verdict row, never of a `[CANDIDATE]` row — so it must speak the VERDICT
8
+ * dialect. That dialect is `REVIEW_SEVERITIES` in `src/hooks/pr-workflow-gate.ts`,
9
+ * which is exactly `CANDIDATE_SEVERITIES` plus `NONE` (a DISPROVED critic verdict
10
+ * is *required* to carry `NONE`, and a CONFIRMED-but-cosmetic reviewer verdict
11
+ * legitimately does). Reusing `CANDIDATE_SEVERITIES` for findings made `NONE`
12
+ * unrepresentable and forced field omission as its only encoding — which in turn
13
+ * disabled the gate's severity comparison (issue #2279).
14
+ *
15
+ * Deliberately a SEPARATE constant rather than a widened `CANDIDATE_SEVERITIES`:
16
+ * that one still governs explorer/micro-lane `[CANDIDATE]` rows
17
+ * (`isCandidateSeverity` → `analyzeCandidateFields`) and the required sidecar
18
+ * field (`candidate-sidecar-store.ts`), where `NONE` is never legitimate — a
19
+ * candidate row asserting "no severity" is a contradiction, not a finding.
20
+ */
21
+ export declare const FINDINGS_SEVERITIES: readonly ["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL", "NONE"];
22
+ export type FindingsSeverity = (typeof FINDINGS_SEVERITIES)[number];
3
23
  export declare const CANDIDATE_CONFIDENCES: readonly ["HIGH", "MEDIUM", "LOW"];
4
24
  export type CandidateConfidence = (typeof CANDIDATE_CONFIDENCES)[number];
5
25
  export type RowFormatFamily = 'base_explorer' | 'micro_lane';
@@ -51,7 +71,7 @@ export interface NormalizedCandidateArtifact {
51
71
  /** Narrow, auditable repairs applied before the unchanged strict parser runs. */
52
72
  repairKinds: CandidateArtifactRepairKind[];
53
73
  }
54
- export type CandidateArtifactRepairKind = 'synthesized-header' | 'terminal-protocol-fence' | 'redundant-clean-confidence' | 'clean-evidence-pipe-tail-merge' | 'summary-row-dropped';
74
+ export type CandidateArtifactRepairKind = 'synthesized-header' | 'terminal-protocol-fence' | 'redundant-clean-confidence' | 'clean-evidence-pipe-tail-merge' | 'summary-row-dropped' | 'duplicate-header-row-dropped';
55
75
  /**
56
76
  * Normalize a lane artifact ONCE so every consumer parses byte-identical text.
57
77
  *
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { type CandidateConfidence, type CandidateSeverity, type RowFormatFamily, type CleanAttestationRecord as SharedCleanAttestationRecord } from './candidate-contract';
2
+ import { type CandidateArtifactRepairKind, type CandidateConfidence, type CandidateSeverity, type RowFormatFamily, type CleanAttestationRecord as SharedCleanAttestationRecord } from './candidate-contract';
3
3
  declare const ArtifactInputSchema: z.ZodObject<{
4
4
  output_ref: z.ZodString;
5
5
  batchId: z.ZodString;
@@ -138,6 +138,26 @@ export interface ParseResult {
138
138
  error_code?: string;
139
139
  candidates: CandidateRecord[];
140
140
  clean_attestation?: CleanAttestationRecord;
141
+ /**
142
+ * The artifact carried a `[CLEAN]` attestation that had to be discredited,
143
+ * but the artifact itself is still valid and its candidate rows were retained.
144
+ * The parse SUCCEEDS: `error`/`error_code` are absent. Mutually exclusive with
145
+ * `error_code` by construction (issue #2279).
146
+ *
147
+ * Callers must not read this as coverage: `clean_attestation` is `undefined`
148
+ * whenever this is set, so a lane with zero candidate rows still fails
149
+ * coverage exactly as before.
150
+ */
151
+ clean_attestation_salvaged?: boolean;
152
+ /** Human-readable reason a salvaged attestation was discredited. */
153
+ clean_attestation_salvage_reason?: string;
154
+ /**
155
+ * Structural repairs applied by `normalizeCandidateArtifact` before the strict
156
+ * parse. Present only on the `parseAndPersist` path, which is the one that
157
+ * normalizes; disclosed so the tool receipt reports a repaired artifact
158
+ * instead of silently presenting it as pristine.
159
+ */
160
+ repair_kinds?: CandidateArtifactRepairKind[];
141
161
  invocation_envelope: InvocationEnvelope;
142
162
  diagnostics: DiagnosticsSummary;
143
163
  }
@@ -212,7 +212,14 @@ export interface BackgroundPromptSnapshot {
212
212
  truncated: boolean;
213
213
  digest: string;
214
214
  }
215
- export type BackgroundDelegationRecoveryKind = 'parser-normalization' | 'parser-row-recovery' | 'truncated-preview-durable-artifact' | 'transcript-incomplete-terminal-candidate';
215
+ export type BackgroundDelegationRecoveryKind = 'parser-normalization' | 'parser-row-recovery' | 'truncated-preview-durable-artifact' | 'transcript-incomplete-terminal-candidate'
216
+ /**
217
+ * A `[CLEAN]` attestation was discredited while the artifact's candidate rows
218
+ * were retained. Distinct from `parser-normalization` (a text-shape repair by
219
+ * `normalizeCandidateArtifact`) because nothing was repaired — an assertion
220
+ * was dropped (issue #2279).
221
+ */
222
+ | 'clean-attestation-salvaged';
216
223
  export interface BackgroundDelegationWorkflowLaneRecovery {
217
224
  workflowLane: string;
218
225
  kind: BackgroundDelegationRecoveryKind;
@@ -0,0 +1,70 @@
1
+ import { z } from 'zod';
2
+ export declare const PR_REVIEW_COLLECTION_RECEIPT_PREFIX = "[PR_REVIEW_COLLECTION_RECEIPT_V1] ";
3
+ export declare const PR_REVIEW_COLLECTION_RECEIPT_SHED_PREFIX = "[PR_REVIEW_COLLECTION_RECEIPT_SHED_V1] ";
4
+ /** Bound durable receipt metadata even when a malformed producer supplies text. */
5
+ export declare const MAX_PR_REVIEW_COLLECTION_RECEIPT_CHARS: number;
6
+ /** Keep public assignment schemas aligned with the largest durable receipt. */
7
+ export declare const MAX_PR_REVIEW_COLLECTION_RECEIPT_ITEM_IDS = 10000;
8
+ declare const PrReviewCollectionReceiptPayloadSchema: z.ZodObject<{
9
+ schemaVersion: z.ZodLiteral<1>;
10
+ parentSessionId: z.ZodString;
11
+ batchId: z.ZodString;
12
+ laneId: z.ZodString;
13
+ mode: z.ZodEnum<{
14
+ "swarm-pr-review:reviewer": "swarm-pr-review:reviewer";
15
+ "swarm-pr-review:critic": "swarm-pr-review:critic";
16
+ }>;
17
+ workflowLane: z.ZodString;
18
+ outputDigest: z.ZodString;
19
+ disposition: z.ZodEnum<{
20
+ rejected: "rejected";
21
+ accepted: "accepted";
22
+ }>;
23
+ reviewItemIds: z.ZodArray<z.ZodString>;
24
+ }, z.core.$strict>;
25
+ export type PrReviewCollectionReceiptPayload = z.infer<typeof PrReviewCollectionReceiptPayloadSchema>;
26
+ declare const PrReviewCollectionReceiptShedMarkerSchema: z.ZodObject<{
27
+ schemaVersion: z.ZodLiteral<1>;
28
+ parentSessionId: z.ZodString;
29
+ batchId: z.ZodString;
30
+ laneId: z.ZodString;
31
+ mode: z.ZodEnum<{
32
+ "swarm-pr-review:reviewer": "swarm-pr-review:reviewer";
33
+ "swarm-pr-review:critic": "swarm-pr-review:critic";
34
+ }>;
35
+ workflowLane: z.ZodString;
36
+ outputDigest: z.ZodString;
37
+ disposition: z.ZodEnum<{
38
+ rejected: "rejected";
39
+ accepted: "accepted";
40
+ }>;
41
+ reviewItemCount: z.ZodNumber;
42
+ reviewItemDigest: z.ZodString;
43
+ }, z.core.$strict>;
44
+ export type PrReviewCollectionReceiptShedMarker = z.infer<typeof PrReviewCollectionReceiptShedMarkerSchema>;
45
+ export interface PrReviewCollectionReceiptBinding {
46
+ parentSessionId: string;
47
+ batchId?: string;
48
+ callID: string;
49
+ laneId?: string;
50
+ correlationId: string;
51
+ mode?: string;
52
+ workflowLane?: string;
53
+ }
54
+ export interface PrReviewCollectionReceiptResult {
55
+ text?: string;
56
+ digest: string;
57
+ }
58
+ export interface PrReviewCollectionReceiptPartition {
59
+ assignedReviewItemIds: string[];
60
+ acceptedReviewItemIds: string[];
61
+ rejectedReviewItemIds: string[];
62
+ }
63
+ export declare function encodePrReviewCollectionReceiptFooter(binding: PrReviewCollectionReceiptBinding, result: PrReviewCollectionReceiptResult, receipt: PrReviewCollectionReceiptPartition): string | null;
64
+ export declare function projectPrReviewCollectionReceipt(payload: PrReviewCollectionReceiptPayload): PrReviewCollectionReceiptPartition;
65
+ export declare function encodePrReviewCollectionReceiptShedMarker(payload: PrReviewCollectionReceiptPayload): string;
66
+ export declare function encodePrReviewCollectionReceiptShedMarkerFromReceipt(binding: PrReviewCollectionReceiptBinding, result: PrReviewCollectionReceiptResult, receipt: PrReviewCollectionReceiptPartition): string | null;
67
+ export declare function parsePrReviewCollectionReceiptShedMarker(binding: PrReviewCollectionReceiptBinding, result: PrReviewCollectionReceiptResult): PrReviewCollectionReceiptShedMarker | null;
68
+ export declare function projectPrReviewCollectionReceiptShedMarker(marker: PrReviewCollectionReceiptShedMarker, reviewItemIds: readonly string[]): PrReviewCollectionReceiptPartition | null;
69
+ export declare function parsePrReviewCollectionReceiptFooter(binding: PrReviewCollectionReceiptBinding, result: PrReviewCollectionReceiptResult): PrReviewCollectionReceiptPayload | null;
70
+ export {};
@@ -12,8 +12,8 @@ import {
12
12
  shouldRunOnStartup,
13
13
  writeBackupArtifact,
14
14
  writeDoctorArtifact
15
- } from "./index-yxhcy5cm.js";
16
- import"./index-z9ed68jt.js";
15
+ } from "./index-1mbdwy12.js";
16
+ import"./index-gr3zfcsh.js";
17
17
  import"./index-cpg98bh1.js";
18
18
  import"./index-z6xqpmqg.js";
19
19
  import"./index-zjygnfay.js";
@@ -14,7 +14,7 @@ import {
14
14
  resolveWorktreeBaseDir,
15
15
  shortenWorktreePath,
16
16
  writeLaneProfileToDiskReal
17
- } from "./index-cx67qa9g.js";
17
+ } from "./index-kjmcp9mf.js";
18
18
  import"./index-cpg98bh1.js";
19
19
  import"./index-9e6fdz2h.js";
20
20
  import"./index-4rhhvd1a.js";
@@ -4,13 +4,13 @@ import {
4
4
  authorizeCuration,
5
5
  buildConfigFingerprintInput,
6
6
  readCohortConfigFingerprint
7
- } from "./index-e1hjd15c.js";
7
+ } from "./index-tp5ytzzg.js";
8
8
  import"./index-rtry5xyf.js";
9
- import"./index-w0cj7zyd.js";
10
- import"./index-qbpxrw95.js";
11
- import"./index-ycgm9pzg.js";
12
- import"./index-bghwrr59.js";
13
- import"./index-qyvjp0bq.js";
9
+ import"./index-f75qjtn5.js";
10
+ import"./index-8py21zn6.js";
11
+ import"./index-hw1yghpg.js";
12
+ import"./index-6q35swn2.js";
13
+ import"./index-q81s0m8k.js";
14
14
  import"./index-7g4c7s5r.js";
15
15
  import"./index-bpmtbmy9.js";
16
16
  import"./index-ed5ykebp.js";