amicus 4.8.1 → 4.9.1
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +316 -0
- package/README.md +8 -3
- package/docs/ROADMAP.md +101 -10
- package/docs/configuration.md +54 -4
- package/docs/council.md +102 -14
- package/docs/troubleshooting.md +9 -2
- package/docs/usage.md +128 -12
- package/electron/ipc-setup.js +41 -18
- package/electron/main.js +19 -5
- package/electron/offer-session.js +51 -0
- package/electron/setup-ui.js +46 -39
- package/electron/workspace-ui/live-dead-seats.js +163 -91
- package/electron/workspace-ui/workspace-banners.js +30 -7
- package/electron/workspace-ui/workspace-matrix.js +23 -3
- package/electron/workspace-ui/workspace-seats.js +95 -79
- package/package.json +1 -1
- package/schemas/council-run.schema.json +2 -2
- package/schemas/council-tally.schema.json +17 -1
- package/schemas/council-verdict.schema.json +12 -4
- package/schemas/run.schema.json +6 -1
- package/skills/second-opinion/COUNCIL-DESIGN.md +1 -1
- package/skills/second-opinion/MANUAL-ORCHESTRATION.md +1 -1
- package/skills/second-opinion/MODEL-NOTES.md +88 -9
- package/skills/second-opinion/SEAT-BRIEFS.md +36 -4
- package/skills/second-opinion/SKILL.md +151 -36
- package/src/cli-council-run-bench.js +98 -6
- package/src/cli-handlers-council-run.js +18 -6
- package/src/cli-handlers-council.js +57 -7
- package/src/cli-handlers-doctor.js +1 -1
- package/src/cli.js +3 -1
- package/src/council/anonymize.js +2 -1
- package/src/council/briefings-chair-task.js +161 -0
- package/src/council/briefings-chair.js +33 -8
- package/src/council/briefings-debate.js +79 -13
- package/src/council/briefings-stage2-task.js +236 -0
- package/src/council/briefings-stage2.js +103 -26
- package/src/council/briefings-task.js +167 -0
- package/src/council/briefings.js +41 -4
- package/src/council/chair-fallback.js +95 -0
- package/src/council/debate.js +38 -21
- package/src/council/findings.js +3 -2
- package/src/council/ledger.js +2 -2
- package/src/council/parse-stage2.js +63 -15
- package/src/council/report-cost.js +61 -0
- package/src/council/report-html.js +26 -4
- package/src/council/report-md.js +30 -2
- package/src/council/report.js +40 -37
- package/src/council/run-assemble.js +21 -6
- package/src/council/run-chair.js +44 -95
- package/src/council/run-debate-revote.js +81 -49
- package/src/council/run-debate.js +51 -34
- package/src/council/run-finish.js +5 -3
- package/src/council/run-retry-keys.js +4 -4
- package/src/council/run-retry-launch.js +4 -4
- package/src/council/run-retry-notes.js +72 -15
- package/src/council/run-stage1-launch.js +4 -4
- package/src/council/run-stage1-rows.js +9 -6
- package/src/council/run-stage2.js +81 -47
- package/src/council/run-stages.js +9 -21
- package/src/council/run-stats-entry.js +46 -1
- package/src/council/run.js +28 -13
- package/src/council/seats.js +2 -2
- package/src/council/stage1-bind.js +3 -2
- package/src/council/verdict-seat-loss.js +124 -0
- package/src/council/verdict.js +108 -99
- package/src/headless.js +256 -49
- package/src/mcp-council-bench.js +64 -3
- package/src/mcp-council-run.js +10 -3
- package/src/mcp-server.js +52 -12
- package/src/mcp-tools.js +41 -5
- package/src/observe/council-legs.js +2 -2
- package/src/opencode-client.js +19 -1
- package/src/pack/pack-forward.js +15 -12
- package/src/pack/pack-resolve.js +1 -1
- package/src/prompt-builder.js +17 -1
- package/src/sidecar/fanout-leg-fallback.js +2 -1
- package/src/sidecar/fanout-leg.js +26 -0
- package/src/sidecar/fanout.js +1 -1
- package/src/sidecar/list-council.js +178 -0
- package/src/sidecar/list-limit.js +3 -1
- package/src/sidecar/list-search.js +2 -1
- package/src/sidecar/models-render.js +71 -0
- package/src/sidecar/models.js +19 -45
- package/src/sidecar/read.js +34 -10
- package/src/sidecar/reopen-spend.js +2 -1
- package/src/sidecar/setup.js +13 -4
- package/src/sidecar/start.js +2 -1
- package/src/template/render.js +16 -7
- package/src/utils/alias-audit.js +10 -3
- package/src/utils/alias-shadow-writer.js +220 -0
- package/src/utils/alias-shadow.js +294 -0
- package/src/utils/config.js +1 -1
- package/src/utils/curated-models.js +19 -9
- package/src/utils/degrade.js +12 -5
- package/src/utils/doctor-alias-check.js +2 -5
- package/src/utils/engine-log-parse.js +289 -0
- package/src/utils/engine-log-tail.js +114 -0
- package/src/utils/engine-log.js +250 -0
- package/src/utils/engine-skew-records.js +146 -0
- package/src/utils/engine-skew.js +300 -0
- package/src/utils/gateway-router.js +21 -3
- package/src/utils/model-canonicalization.js +55 -6
- package/src/utils/model-catalog.js +27 -9
- package/src/utils/model-fetcher.js +69 -16
- package/src/utils/model-shortlist.js +5 -2
- package/src/utils/provider-default-picker.js +6 -3
- package/src/utils/quick-picks.js +45 -7
- package/src/utils/result-schema.js +17 -1
- package/src/utils/text-sanitize.js +81 -0
- package/src/utils/ttft.js +57 -0
- package/src/utils/untrusted-fence.js +111 -1
- package/src/workspace/fold-format.js +28 -7
- package/src/workspace/live-normalize.js +2 -1
- package/src/workspace/matrix-model.js +6 -2
- package/src/workspace/run-detail.js +33 -7
- package/src/workspace/seat-space.js +10 -6
|
@@ -50,7 +50,8 @@ function seatOf(leg) {
|
|
|
50
50
|
model: leg.model || null,
|
|
51
51
|
modelInput: leg.modelInput || null,
|
|
52
52
|
role: leg.role || null,
|
|
53
|
-
// ⚠️ v4.8 R5: the leg's seat id, and the reason live-dead-seats.js
|
|
53
|
+
// ⚠️ v4.8 R5: the leg's seat id, and the reason live-dead-seats.js ::
|
|
54
|
+
// deadSeats' `if (s.seat)` suppression arm's
|
|
54
55
|
// `if (s.seat)` arm is reachable at all. Null on a unique-alias bench, so the
|
|
55
56
|
// guard there stays load-bearing — see the comment at that line.
|
|
56
57
|
seat: leg.seat || null,
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* unconditionally (src/council/tally.js :: tally) — it is never a real source for
|
|
16
16
|
* either the override badge or the post-override tier. Only `buildVerdict`
|
|
17
17
|
* materializes `{from,to,reason}` and rewrites `tier` to `tierOverride.to`
|
|
18
|
-
* (src/council/verdict.js
|
|
18
|
+
* (src/council/verdict.js :: buildVerdict's `findings` map — re-anchored BY SYMBOL at v4.9 W9,
|
|
19
|
+
* which shifted the old `:128-132`). So both fields are joined in from
|
|
19
20
|
* verdict.findings[] by `id`; when verdict is absent/unparseable (caller
|
|
20
21
|
* passes null/undefined, or a finding has no verdict-side counterpart) the
|
|
21
22
|
* row falls back to tally's own (pre-override) tier and renders no badge.
|
|
@@ -183,7 +184,10 @@ function buildMatrixModel(tally, labelMap, verdict) {
|
|
|
183
184
|
// ⚠️ DE-ROT (F29): v4.1 decorates tally.json findings in place with
|
|
184
185
|
// `debate: {action, previousTier}` (src/council/debate.js :: decorateRecord; action ∈
|
|
185
186
|
// defended|amended|withdrawn|no-response) and verdict.json carries it through
|
|
186
|
-
// (src/council/verdict.js
|
|
187
|
+
// (src/council/verdict.js :: buildVerdict's `if (f.debate)` carry-through — the old
|
|
188
|
+
// `:43` was ALREADY rotted onto summarizeSeatLoss, which has since left verdict.js
|
|
189
|
+
// altogether; re-anchored by symbol, not re-numbered). Consumed by
|
|
190
|
+
// electron/workspace-ui/workspace-matrix.js's
|
|
187
191
|
// renderMatrix, which renders a `.debate-badge` in the tier cell (alongside the
|
|
188
192
|
// thin/tierOverride badges) so a withdrawn/amended/defended/no-response finding never
|
|
189
193
|
// renders as an ordinary live row. Absent on non-debate runs, hence `|| null`.
|
|
@@ -124,7 +124,7 @@ function costPanel(run, tally) {
|
|
|
124
124
|
|
|
125
125
|
// ⚠️ PRE-FLIGHT (P3): F04's correction is implemented here rather than left as prose.
|
|
126
126
|
// VERIFIED on shipped main (Task 0): `finalize(exitCode, error)` writes `error: error || null`
|
|
127
|
-
// (run-finalize.js :: writeRunTerminal), and `return finalize(degraded.value ? 2 : 0)` (run.js:
|
|
127
|
+
// (run-finalize.js :: writeRunTerminal), and `return finalize(degraded.value ? 2 : 0)` (run.js:294) is the ONLY
|
|
128
128
|
// exit-2 path — it passes NO error. Every error-bearing call is `finalize(1, …)`. So on a
|
|
129
129
|
// `status:'partial'` run — precisely the run this panel exists to explain — `run.error` is
|
|
130
130
|
// GUARANTEED null, and the old one-line formula rendered "undefined: undefined".
|
|
@@ -142,13 +142,32 @@ function degradedReason(run) {
|
|
|
142
142
|
return null;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
// v4.9 W8 T-B: `intent` rides this payload so the renderer can label a task run's
|
|
146
|
+
// chip `ANSWER:` (electron/workspace-ui/workspace-matrix.js :: renderVerdict is a
|
|
147
|
+
// plain browser script and cannot require() src/, so a fork key it cannot read is
|
|
148
|
+
// a fork it cannot make). Unlike verdict.json — emit-when-'task' per the W5 ruling,
|
|
149
|
+
// because that artifact has a byte-identity contract — this is an in-memory IPC
|
|
150
|
+
// model whose literal is CLOSED and always materializes every key with a default,
|
|
151
|
+
// so `intent` is materialized both ways and defaults to 'review'. The renderer
|
|
152
|
+
// still treats an ABSENT key as review: pre-v4.9 payloads carry none.
|
|
153
|
+
// ⚠️ v4.9 fix round 2 (council B2): sourced from `run` as well as `verdict`.
|
|
154
|
+
// Reading `verdict.intent` ALONE meant the two panels that exist to explain a
|
|
155
|
+
// broken run could not label it: on the narrow leg where a task run exits before
|
|
156
|
+
// the verdict write — or leaves a truncated one — there is no verdict.intent to
|
|
157
|
+
// read, and the panel defaulted to review, so the Workspace chip said "no chair
|
|
158
|
+
// verdict" about a run that was never on that scale. `run.json` checkpoints
|
|
159
|
+
// `intent: 'task'` at start (run.js :: runCouncil) and `run` is already this
|
|
160
|
+
// function's first parameter, so the honest source costs nothing to reach.
|
|
145
161
|
function verdictPanel(run, verdict) {
|
|
146
162
|
const reason = degradedReason(run);
|
|
163
|
+
// PR #200 round-5 B3: parens on the whole disjunction — behaviour-identical.
|
|
164
|
+
const intent = ((verdict && verdict.intent === 'task') || (run && run.intent === 'task')) ? 'task' : 'review';
|
|
147
165
|
if (!verdict || verdict.parseError) {
|
|
148
|
-
return { present: false, overallVerdict: null, tierCounts: null, streetCred: [], decisions: [], reason };
|
|
166
|
+
return { present: false, overallVerdict: null, tierCounts: null, streetCred: [], decisions: [], reason, intent };
|
|
149
167
|
}
|
|
150
168
|
return {
|
|
151
169
|
present: true,
|
|
170
|
+
intent,
|
|
152
171
|
overallVerdict: verdict.overallVerdict === undefined ? null : verdict.overallVerdict,
|
|
153
172
|
tierCounts: verdict.tierCounts || null,
|
|
154
173
|
streetCred: Array.isArray(verdict.streetCred) ? verdict.streetCred : [],
|
|
@@ -233,11 +252,18 @@ function getRunDetail(project, runId) {
|
|
|
233
252
|
// of a copy of the question makes that divergence unrepresentable.
|
|
234
253
|
seatSpace: isSeatTable(run.seats),
|
|
235
254
|
// ⚠️ Fix-wave 3 (council-3 C2): seats[] is PRESENT but unusable, so the run silently
|
|
236
|
-
// lost per-seat
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
255
|
+
// lost per-seat ARTIFACT NAMING — two seats on one model become indistinguishable in
|
|
256
|
+
// the reviews/judges/re-vote panels, whose roster this flag sends back to `bench`
|
|
257
|
+
// (workspace-lazy.js :: roster). isSeatTable fails WHOLE (one malformed entry drops the
|
|
258
|
+
// entire table), which is the fail-safe direction but is exactly the correct-but-silent
|
|
259
|
+
// degrade the product principle rejects. Emitted here, beside the predicate that decides
|
|
260
|
+
// it, rather than re-derived renderer-side; workspace-banners.js is its only consumer.
|
|
261
|
+
// ⚠️ "in every panel" — what this comment said until v4.9 W9 — was already FALSE when
|
|
262
|
+
// written, and W9's PR5b-1 measured it: `costPanel` above maps `tally.runStats`, whose
|
|
263
|
+
// `seat` is stamped from the in-memory seat at assembly (run-stats-entry.js ::
|
|
264
|
+
// buildRunStatsEntry), so the seats panel keeps one row per seat no matter what
|
|
265
|
+
// run.seats looks like. Ruling V15 discloses that split in the banner rather than
|
|
266
|
+
// forcing the seats panel down to `seatSpace` for uniformity.
|
|
241
267
|
// NOT the same as `!seatSpace`: a run with no seats[] at all is a legacy run, not a
|
|
242
268
|
// broken one, and must not be bannered.
|
|
243
269
|
seatTableRejected: Array.isArray(run.seats) && run.seats.length > 0 && !isSeatTable(run.seats),
|
|
@@ -75,18 +75,22 @@ function isSeatTable(seats) {
|
|
|
75
75
|
* bound seat a `rebuttal-` an orphan may have written, re-arming RN-1 in the debate
|
|
76
76
|
* namespace (MEASURED; the one regression this fix wave introduced). The question is:
|
|
77
77
|
* does the note POSITIVELY PROVE the orphan did NOT write this kind? Exactly one such
|
|
78
|
-
* proof exists. `orphanLegNote` has three call sites — run-stages.js
|
|
79
|
-
* and its retry
|
|
80
|
-
*
|
|
78
|
+
* proof exists. `orphanLegNote` has three call sites — two in run-stages.js :: runStage1
|
|
79
|
+
* (Stage-1's own bind and its retry pass; cited `:71 and :140` until the v4.9 W9 fix round
|
|
80
|
+
* moved a builder out of that function and both numbers rotted — anchored by SYMBOL now, per
|
|
81
|
+
* the anti-rot rule) and run-stage2.js :: bindStage2Seats (the -s2 judge wave) — and
|
|
82
|
+
* `data.waveId` separates them EXACTLY, not heuristically: run-stage2.js :: bindStage2Seats
|
|
83
|
+
* and the launch site in run-stage2.js :: runStage2 both build it as `${runId}-s2` from
|
|
81
84
|
* the runId this run.json carries. A -s2 note says the leg BOUND in Stage 1, so its review
|
|
82
85
|
* landed under a SEAT name: `review-<alias>.md` is provably not its. Nothing else is
|
|
83
86
|
* provable, and the near misses are why:
|
|
84
87
|
* - a Stage-1 note exonerates NOTHING, not even judge-: that orphan is re-admitted to
|
|
85
|
-
* Stage 2 under a PLACEHOLDER seat
|
|
86
|
-
*
|
|
88
|
+
* Stage 2 under a PLACEHOLDER seat that stage1-bind.js :: bindPaddedWave pads in and
|
|
89
|
+
* drops from `judgeSeatOf` (called from run-stage2.js :: bindStage2Seats since the
|
|
90
|
+
* v4.9 W2 split), so its judge leg takes the alias branch too — and emits no -s2 note,
|
|
87
91
|
* because it BOUND. Measured: run-stages.test.js :: "M2: the placeholder never becomes…".
|
|
88
92
|
* - rebuttal-/revote- are never exonerated: a debate leg whose raiser/judge key names no
|
|
89
|
-
* seat takes materializeDebate's alias branch (run-debate.js ::
|
|
93
|
+
* seat takes materializeDebate's alias branch (run-debate.js :: runDefenseWave;
|
|
90
94
|
* run-debate-revote.js :: runRevoteWave, `seat = seatOf.get(leg) || null`). A rebuttal
|
|
91
95
|
* leg's unbound raiser still has no note recording it. A revote leg's unbound judge
|
|
92
96
|
* SOMETIMES gets one, since v4.8 T5.1 (channel `seat-unbound`, run-debate-revote.js's
|