instar 1.3.959 → 1.3.960

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.959",
3
+ "version": "1.3.960",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,7 +25,7 @@
25
25
  "deterministic": 14
26
26
  }
27
27
  },
28
- "benchedPromptSource": "src/core/MessagingToneGate.ts:TONE_GATE_PROMPT_TEMPLATE",
28
+ "benchedPromptSource": "src/core/MessagingToneGate.ts#TONE_GATE_PROMPT_TEMPLATE",
29
29
  "benchedPromptHash": "4ae0cf6b02663c21a695393727bd05662334f0d8f1a9d3e45d8d9b2141208d54",
30
30
  "capturedAt": "2026-07-23T22:30:00.000Z"
31
31
  },
@@ -47,7 +47,7 @@
47
47
  "deterministic": 6
48
48
  }
49
49
  },
50
- "benchedPromptSource": "src/monitoring/ExternalHogClassifierPrompt.ts:EXTERNAL_HOG_CLASSIFIER_PROMPT_TEMPLATE",
50
+ "benchedPromptSource": "src/monitoring/ExternalHogClassifierPrompt.ts#EXTERNAL_HOG_CLASSIFIER_PROMPT_TEMPLATE",
51
51
  "benchedPromptHash": "98b026dbe3ee48cab1403ef24218e9e24f6ea2b3d598c23e383bed4e894cbb56",
52
52
  "capturedAt": "2026-07-24T01:20:00.000Z",
53
53
  "scoredPopulation": "production-candidate only (10 of 17 cases). Excluded by design: 4 floor-excluded (never allowlist-matched, so no model is ever consulted about them), 1 invalid-unwinnable (renders byte-identical to another case with the opposite expected answer — a prompt defect, see ACT-1212), 2 contested-expectation (the models made the better argument and the expectation was withdrawn). Excluded cases are retained in the task file as evidence, not deleted.",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-25T10:47:31.807Z",
5
- "instarVersion": "1.3.959",
4
+ "generatedAt": "2026-07-25T10:59:45.006Z",
5
+ "instarVersion": "1.3.960",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,75 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The Benchmark-Divergence Detector — which compares how a model performs in
9
+ production against how it scored on its benchmark — has never produced a single
10
+ actionable verdict since it shipped. It does now.
11
+
12
+ Before comparing, the detector verifies that the benchmark it holds actually
13
+ corresponds to the live prompt; if it can't confirm that, it declines to judge
14
+ rather than blame a model for a test it never sat. That verification compares two
15
+ strings for exact equality:
16
+
17
+ - the mirror's `benchedPromptSource`: `src/core/MessagingToneGate.ts:TONE_GATE_PROMPT_TEMPLATE`
18
+ - the registry's `source`: `src/core/MessagingToneGate.ts#TONE_GATE_PROMPT_TEMPLATE`
19
+
20
+ A colon against a hash. One character, on both benchmarked tasks. So
21
+ `registrySourceMatches` was `false` on every run, step 2 of the verdict ladder
22
+ fired, and every comparison returned `precondition-failed / hash-unverifiable` —
23
+ permanently.
24
+
25
+ **It never looked broken.** `precondition-failed` is a legitimate, designed
26
+ verdict: the correct answer when a benchmark is genuinely stale. The analysis
27
+ pass completed cleanly, emitted a valid verdict, and never errored. A
28
+ permanently blindfolded detector is output-identical to a correctly cautious one.
29
+
30
+ Fixed: the mirror's two source strings now match the registry, and a CI ratchet
31
+ (`tests/unit/benchmark-mirror-registry-agreement.test.ts`) asserts they stay
32
+ identical — plus that the benched prompt hash still matches the live template,
33
+ that every benchmarked task is registry-known, and that no task has empty
34
+ baselines.
35
+
36
+ **The comparison itself was deliberately not loosened.** Making `:` and `#`
37
+ interchangeable would have hidden the symptom while weakening a real safety
38
+ check — letting genuine benchmark/prompt mismatches through so the detector
39
+ could confidently blame models for tests they never sat. The strict comparison is
40
+ the guard. What was missing was anything keeping the two sides in step, and that
41
+ absence — not the typo — was the defect.
42
+
43
+ ## What to Tell Your User
44
+
45
+ If you've ever looked at the benchmark-divergence read and seen nothing useful,
46
+ this is why: it wasn't quiet because everything agreed, it was quiet because it
47
+ couldn't get past its own front door.
48
+
49
+ Expect its first real answers to be modest — mostly "not enough evidence yet"
50
+ until enough graded decisions accumulate. That's the system being careful, and
51
+ this time for the right reason rather than because of a punctuation mismatch.
52
+
53
+ Note this fix makes the detector *able* to answer; it doesn't turn it on. Whether
54
+ findings get recorded is still governed by its dry-run setting.
55
+
56
+ ## Summary of New Capabilities
57
+
58
+ - The Benchmark-Divergence Detector can reach a real verdict for the first time.
59
+ - A build-time invariant keeps the benchmark mirror and the prompt registry in
60
+ step, so a one-character drift can never again silently disable the subsystem.
61
+ - A drifted prompt hash now fails the build instead of quietly suppressing every
62
+ verdict.
63
+
64
+ ## Evidence
65
+
66
+ - `tests/unit/benchmark-mirror-registry-agreement.test.ts` (9 cases): source
67
+ equality, hash-vs-live-template, registry↔mirror task coverage both ways,
68
+ non-empty baselines, a fixture-is-real guard against vacuity, and a
69
+ behavioural pair proving the ladder's outcome flips on `registrySourceMatches`
70
+ alone (identical evidence → `precondition-failed` vs `aligned`, plus
71
+ `divergent-worse` on a genuinely worse rate).
72
+ - Mutation-tested: restoring the original `:` turns the ratchet red with a
73
+ message naming the separator.
74
+ - Live hashes computed and compared against the mirror before changing anything
75
+ — they match, ruling out prompt drift as the cause.
@@ -0,0 +1,144 @@
1
+ # Side-effects review — benchmark-source-match
2
+
3
+ **Change:** correct the two `benchedPromptSource` values in
4
+ `src/data/benchmarkPredictions.json` (`:` → `#`) so they match the
5
+ `PROMPT_TEMPLATE_REGISTRY` sources the analyzer compares them against, and add a
6
+ CI ratchet that makes the mismatch unshippable.
7
+
8
+ **Tier:** 1 (ELI16 + side-effects; a data correction plus a test — no new
9
+ runtime code path).
10
+
11
+ ---
12
+
13
+ ## The defect in one paragraph
14
+
15
+ `BenchmarkDivergenceAnalyzer.ts:423` computes
16
+ `registrySourceMatches = task.benchedPromptSource === registryEntry.source`.
17
+ The mirror wrote `src/core/MessagingToneGate.ts:TONE_GATE_PROMPT_TEMPLATE`; the
18
+ registry declares `src/core/MessagingToneGate.ts#TONE_GATE_PROMPT_TEMPLATE`. So
19
+ the flag was `false` for every task on every run, step 2 of the verdict ladder
20
+ fired, and the Benchmark-Divergence Detector returned
21
+ `precondition-failed / hash-unverifiable` for its entire shipped life. It has
22
+ never produced a single actionable verdict. Verified directly against the live
23
+ constants before changing anything.
24
+
25
+ ## 1. Over-block — what legitimate inputs does this reject that it shouldn't?
26
+
27
+ **At build time: one new way to fail, deliberately.** A mirror whose
28
+ `benchedPromptSource` or `benchedPromptHash` disagrees with the registry now
29
+ fails CI. That is the entire point, and both failure messages say exactly what to
30
+ do (`the registry uses '#', not ':'` / `re-capture the mirror; do NOT edit the
31
+ hash by hand`).
32
+
33
+ **At runtime: nothing.** This *unblocks* — it removes a precondition failure that
34
+ was firing on every comparison. No input that previously produced a verdict now
35
+ produces a different one; inputs that produced `precondition-failed` may now
36
+ produce a real verdict, which is the intent.
37
+
38
+ ## 2. Under-block — what failure modes does this still miss?
39
+
40
+ - **The detector may now say very little for a while.** Getting past the
41
+ precondition does not manufacture evidence: most comparisons will land on
42
+ `insufficient-evidence` until enough graded decisions accumulate. Correct
43
+ behaviour, and worth stating so "it's still not saying much" isn't read as
44
+ this fix having failed.
45
+ - **The mirror's per-model baselines are still whatever was last captured.** This
46
+ change does not re-capture them, and deliberately does not invent numbers for
47
+ models that were never benchmarked (see §6).
48
+ - **Other silent-precondition classes remain possible.** `stale-mirror` and
49
+ `prompt-drifted` are real, legitimate states. The new hash test converts one of
50
+ them (drift) into a loud build failure, but a mirror that ages past its
51
+ staleness bound will still quietly suppress verdicts — the same shape of
52
+ problem, one layer out. Not fixed here; named honestly.
53
+
54
+ ## 3. Level-of-abstraction fit
55
+
56
+ The fix is at the data layer because the data was wrong: the registry is
57
+ documented as authoritative (`benchedPromptSource must match this string or Q0
58
+ is hash-unverifiable`), so the mirror is what needed correcting.
59
+
60
+ The *guard* is at the build layer, which is the right place for an invariant
61
+ between two static files. It could not sensibly live at runtime — at runtime the
62
+ mismatch is already indistinguishable from a legitimately stale benchmark, which
63
+ is precisely why it survived.
64
+
65
+ ## 4. Signal vs authority compliance
66
+
67
+ `docs/signal-vs-authority.md`. Unchanged, and deliberately so.
68
+
69
+ The exact-match comparison in the analyzer is a **brittle check with real
70
+ authority** — it suppresses verdicts. That is the documented exemption class: a
71
+ false pass (comparing against a benchmark that does not describe the live
72
+ prompt) produces confident wrong claims about a model, while a false block
73
+ produces silence. Silence is the safe direction.
74
+
75
+ **I explicitly rejected the tempting fix.** Normalising the comparison so `:` and
76
+ `#` both match would have made the symptom disappear while weakening the guard —
77
+ trading a visible failure for a silent one, and letting genuine
78
+ benchmark/prompt mismatches through. The strict comparison stays; the mismatch
79
+ becomes unshippable instead.
80
+
81
+ The new test holds no runtime authority: it is a build-time assertion over two
82
+ static files.
83
+
84
+ ## 5. Interactions
85
+
86
+ - **The verdict ladder** — untouched. The change moves inputs past step 2; steps
87
+ 3–9 behave exactly as before. Both branches are pinned by the new behavioural
88
+ tests (same evidence, `registrySourceMatches` false vs true →
89
+ `precondition-failed` vs `aligned`).
90
+ - **`benchmarkDivergence.dryRun`** — orthogonal. This is why the detector never
91
+ *persisted* findings; the source mismatch is why it never *had* one worth
92
+ persisting. Fixing one without the other leaves the feature dark, and the
93
+ dryRun flip is the operator's, not this PR's.
94
+ - **The tone-gate prompt** — I suspected my own 2026-07-25 tone-gate change had
95
+ drifted the prompt hash and caused this. It had not: both hashes match live.
96
+ The new hash test now makes that class of drift a build failure rather than a
97
+ silent suppression, so a future prompt edit cannot repeat the worry.
98
+ - **No shadowing, no double-fire.** One comparison, one callsite.
99
+
100
+ ## 6. External surfaces
101
+
102
+ - `GET /benchmark-divergence` — no shape change. `summary.byVerdict` and
103
+ `findings` may become non-empty for the first time; every finding remains
104
+ `advisory: true` and gates nothing.
105
+ - No new route, config key, flag, env var, CLI surface, or message.
106
+ - **No fabricated data.** The mirror's per-model numbers are untouched. Adding
107
+ `claude-opus-5` / `claude-fable-5` baselines requires actually running the
108
+ benchmark against those models; inventing plausible pass rates would poison
109
+ the exact comparison this change exists to enable. Out of scope here and
110
+ called out rather than quietly skipped.
111
+
112
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
113
+
114
+ **Unified.** Both files are shipped source constants
115
+ (`src/data/`, published in `package.json` `files[]`, compiled into `dist/`), so
116
+ every machine holds byte-identical copies and computes the same
117
+ `registrySourceMatches`. There is no per-machine state, no durable write, no
118
+ notice, and no generated URL. The pool-merged read path is unaffected — peers
119
+ merge computed findings, not raw sources.
120
+
121
+ Before this fix the detector was uniformly blind across the fleet; after it, it
122
+ is uniformly able to compare. The posture does not change, only the verdict.
123
+
124
+ ## 8. Rollback cost
125
+
126
+ **Revert the commit.** No flag, no migration, no durable state, no agent-state
127
+ repair. Reverting restores the permanent `precondition-failed` behaviour — i.e.
128
+ the detector goes back to being silently blind, which is worth stating plainly
129
+ because that state is indistinguishable from healthy caution from the outside.
130
+
131
+ ## Second-pass review
132
+
133
+ **Not required** by the Phase-5 trigger list: no messaging/dispatch block-allow
134
+ decision, no session lifecycle, no compaction path, no coherence gate, trust
135
+ level, or idempotency check, and nothing named sentinel/guard/gate/watchdog. The
136
+ change is a two-character data correction plus a build-time assertion, and every
137
+ finding the affected subsystem emits is advisory by construction.
138
+
139
+ The claim that matters was verified empirically rather than argued: the live
140
+ hashes were computed and compared against the mirror (they match — my first
141
+ hypothesis was wrong), the two source strings were printed and diffed, the
142
+ ratchet was mutation-tested by restoring the original typo (it fails, naming the
143
+ separator), and the behavioural pair proves the ladder's outcome flips on that
144
+ flag alone.