instar 1.3.209 → 1.3.211
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/skills/autonomous/SKILL.md +11 -3
- package/dist/core/CircuitBreakingIntelligenceProvider.d.ts +8 -0
- package/dist/core/CircuitBreakingIntelligenceProvider.d.ts.map +1 -1
- package/dist/core/CircuitBreakingIntelligenceProvider.js +20 -4
- package/dist/core/CircuitBreakingIntelligenceProvider.js.map +1 -1
- package/dist/core/ClaudeCliIntelligenceProvider.d.ts +19 -0
- package/dist/core/ClaudeCliIntelligenceProvider.d.ts.map +1 -1
- package/dist/core/ClaudeCliIntelligenceProvider.js +55 -3
- package/dist/core/ClaudeCliIntelligenceProvider.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +30 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/types.d.ts +15 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +20 -20
- package/upgrades/1.3.210.md +101 -0
- package/upgrades/1.3.211.md +63 -0
- package/upgrades/side-effects/autonomous-stop-hook-path-fix.md +156 -0
- package/upgrades/side-effects/iris-audit-token-accounting.md +125 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The autonomous-mode stop hook was being registered in `settings.json` at
|
|
9
|
+
`.instar/hooks/instar/autonomous-stop-hook.sh` — a path where the hook is **never
|
|
10
|
+
deployed**. The hook ships only in the skill directory
|
|
11
|
+
(`.claude/skills/autonomous/hooks/autonomous-stop-hook.sh`). So on every `Stop`
|
|
12
|
+
event the hook command hit a missing file, failed silently, and the autonomous
|
|
13
|
+
loop never re-injected the task list. The session stayed alive but stopped
|
|
14
|
+
self-continuing between turns — it only advanced when the user sent a message.
|
|
15
|
+
|
|
16
|
+
Three coordinated fixes:
|
|
17
|
+
|
|
18
|
+
1. **`.claude/skills/autonomous/SKILL.md` (Step 2a)** now registers the deployed
|
|
19
|
+
skill path and self-heals: it strips any prior (including wrong-path)
|
|
20
|
+
autonomous stop-hook entry and writes exactly one correct-path entry.
|
|
21
|
+
2. **`PostUpdateMigrator.ensureAutonomousStopHook()`** gained a repair pass that
|
|
22
|
+
rewrites any existing wrong-path registration in `settings.json` to the skill
|
|
23
|
+
path. Without it, the "already registered?" presence check treated the
|
|
24
|
+
wrong-path entry as present and never corrected it — so existing agents would
|
|
25
|
+
stay broken forever.
|
|
26
|
+
3. **`PostUpdateMigrator.migrateAutonomousStopHookTopicKeyed()`** re-deploys the
|
|
27
|
+
fixed `SKILL.md` to existing agents, gated on a marker unique to the corrected
|
|
28
|
+
prompt (stock prompts upgrade; customized prompts are left untouched).
|
|
29
|
+
|
|
30
|
+
## What to Tell Your User
|
|
31
|
+
|
|
32
|
+
If you ran an autonomous session and noticed it went quiet between turns —
|
|
33
|
+
continuing only when you messaged it, rather than driving itself forward — this
|
|
34
|
+
fixes the cause. The loop's re-engagement step was pointed at a file that was
|
|
35
|
+
never installed, so it silently did nothing each time the session tried to
|
|
36
|
+
continue. After this update the autonomous loop re-engages on its own as
|
|
37
|
+
intended, and any agent that already had the broken registration is repaired
|
|
38
|
+
automatically on update. No action is needed on your side.
|
|
39
|
+
|
|
40
|
+
## Summary of New Capabilities
|
|
41
|
+
|
|
42
|
+
- Autonomous sessions reliably self-continue between turns (the stop hook now
|
|
43
|
+
resolves to a file that actually exists).
|
|
44
|
+
- Existing agents with the broken registration are healed in place on update —
|
|
45
|
+
both the `settings.json` entry and the deployed skill prompt.
|
|
46
|
+
- The skill registration is now self-healing: activating autonomous mode always
|
|
47
|
+
ends with exactly one correct-path stop-hook entry, regardless of prior state.
|
|
48
|
+
|
|
49
|
+
## Evidence
|
|
50
|
+
|
|
51
|
+
- New unit suite `tests/unit/PostUpdateMigrator-autonomousHookPath.test.ts`
|
|
52
|
+
(9 tests): wrong-path → repaired; no duplicate added; siblings untouched;
|
|
53
|
+
already-correct → no-op; missing → registered; idempotent; SKILL.md content
|
|
54
|
+
asserts the corrected path + marker; topic-keyed migration re-deploys a stock
|
|
55
|
+
SKILL.md and skips a customized one.
|
|
56
|
+
- Empirical check of the SKILL.md Step 2a snippet against a settings file
|
|
57
|
+
carrying the wrong-path entry plus sibling hooks: the wrong entry is rewritten
|
|
58
|
+
to `bash ${CLAUDE_PROJECT_DIR}/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh`,
|
|
59
|
+
siblings are preserved, and a second run is a no-op (idempotent).
|
|
60
|
+
- Existing autonomous/migration suites stay green
|
|
61
|
+
(`autonomous-skill-deployment`, `PostUpdateMigrator-buildStopHook`,
|
|
62
|
+
`autonomous-stop-hook-notify`, `installCodexHooks`, `emit-session-clock` —
|
|
63
|
+
50 tests). `tsc --noEmit` clean.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Side-Effects Review — Autonomous loop re-engagement fix (stop-hook registration path)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `autonomous-stop-hook-path-fix`
|
|
4
|
+
**Date:** `2026-06-03`
|
|
5
|
+
**Author:** `Echo`
|
|
6
|
+
**Second-pass reviewer:** `Echo (self, single-pass — Tier-1 fix)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The autonomous-mode stop hook is what re-injects the task list on every `Stop`
|
|
11
|
+
event so an autonomous session keeps working between turns. It was registered in
|
|
12
|
+
`settings.json` at `.instar/hooks/instar/autonomous-stop-hook.sh`, but the hook
|
|
13
|
+
is only ever deployed to the skill dir (`.claude/skills/autonomous/hooks/`). The
|
|
14
|
+
registered path therefore pointed at a non-existent file: every `Stop` failed
|
|
15
|
+
silently and the loop never re-engaged. Files touched:
|
|
16
|
+
`.claude/skills/autonomous/SKILL.md` (Step 2a registration snippet),
|
|
17
|
+
`src/core/PostUpdateMigrator.ts` (`ensureAutonomousStopHook` repair pass +
|
|
18
|
+
`migrateAutonomousStopHookTopicKeyed` SKILL.md re-deploy), and a new unit suite.
|
|
19
|
+
The decision surface is purely *which file path is written into the Stop-hook
|
|
20
|
+
registration* — there is no message block/allow logic.
|
|
21
|
+
|
|
22
|
+
## Decision-point inventory
|
|
23
|
+
|
|
24
|
+
- `SKILL.md Step 2a registration` — modify — registers the deployed skill path
|
|
25
|
+
(was the never-deployed `.instar/hooks/instar/` path) and self-heals stale entries.
|
|
26
|
+
- `PostUpdateMigrator.ensureAutonomousStopHook` — modify — adds a repair pass that
|
|
27
|
+
rewrites wrong-path entries before the existing presence check.
|
|
28
|
+
- `PostUpdateMigrator.migrateAutonomousStopHookTopicKeyed` — modify — adds SKILL.md
|
|
29
|
+
to the marker-gated re-deploy list so existing agents receive the fixed prompt.
|
|
30
|
+
- No message-gating / block-allow decision point is touched.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. Over-block
|
|
35
|
+
|
|
36
|
+
No block/allow surface — over-block not applicable. The change only corrects a
|
|
37
|
+
filesystem path string in a hook registration; it never rejects any input.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Under-block
|
|
42
|
+
|
|
43
|
+
No block/allow surface — under-block not applicable. One adjacent correctness
|
|
44
|
+
note: the repair targets specifically the `.instar/hooks/instar/autonomous-stop-hook.sh`
|
|
45
|
+
wrong path. If a future custom registration used some *third* wrong path, the
|
|
46
|
+
repair would not catch it — but that path was never shipped by instar, so there
|
|
47
|
+
is nothing in the install base to miss. The registration helper still adds a
|
|
48
|
+
correct entry if none exists at all.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 3. Level-of-abstraction fit
|
|
53
|
+
|
|
54
|
+
Correct layer. This is a deterministic settings/file-path migration — exactly the
|
|
55
|
+
class `PostUpdateMigrator` owns (Migration Parity Standard). The SKILL.md snippet
|
|
56
|
+
is the install/activation-time registrar; the migrator is the in-place repair for
|
|
57
|
+
already-deployed agents. No reasoning/LLM layer is involved or appropriate: the
|
|
58
|
+
correct path is a fixed, known string, so a structural fix is the right tool (and
|
|
59
|
+
matches the sibling `build-stop-hook.sh` path-repair precedent).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 4. Signal vs authority compliance
|
|
64
|
+
|
|
65
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
66
|
+
|
|
67
|
+
- [x] No — this change has no block/allow surface.
|
|
68
|
+
|
|
69
|
+
It rewrites a hook-registration path in `settings.json`; it holds no message or
|
|
70
|
+
operation authority. The autonomous stop hook itself (unchanged here) remains the
|
|
71
|
+
authority for whether a session continues, and it is session-id-gated.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 5. Interactions
|
|
76
|
+
|
|
77
|
+
- **Shadowing:** The repair pass runs *before* the existing `hasAutonomousHook`
|
|
78
|
+
presence check inside `ensureAutonomousStopHook`. This is intentional and is the
|
|
79
|
+
core of the fix: previously the presence check matched the wrong-path entry and
|
|
80
|
+
short-circuited the correct registration, so the wrong path was permanent. After
|
|
81
|
+
repair, the entry already holds the correct path, so the presence check finds it
|
|
82
|
+
and adds no duplicate (verified by the "no duplicate" test).
|
|
83
|
+
- **Double-fire:** Two registrars exist — the SKILL.md Step 2a (activation-time,
|
|
84
|
+
dynamic add/remove) and `ensureAutonomousStopHook` (update-time, permanent). Both
|
|
85
|
+
now converge on the *same* command string, so they can no longer disagree or
|
|
86
|
+
produce two divergent entries. The SKILL.md snippet strips-then-appends, and the
|
|
87
|
+
migrator's presence check prevents duplicates; combined they always yield exactly
|
|
88
|
+
one correct entry (verified).
|
|
89
|
+
- **Races:** No shared concurrent state. `settings.json` is edited by the same
|
|
90
|
+
single-writer migration path as every other hook registration.
|
|
91
|
+
- **Feedback loops:** None. A one-time path correction; the corrected entry is a
|
|
92
|
+
fixed string, so subsequent passes are no-ops (idempotency verified).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 6. External surfaces
|
|
97
|
+
|
|
98
|
+
- **Other agents on the machine:** none — per-project `settings.json` only.
|
|
99
|
+
- **Install base:** existing agents are healed on next update (the intended
|
|
100
|
+
surface). The `migrateAutonomousStopHookTopicKeyed` re-deploy is marker-gated and
|
|
101
|
+
fingerprint-guarded, so a customized `SKILL.md` (missing the stock
|
|
102
|
+
`ALL_TASKS_COMPLETE` fingerprint) is left untouched — verified by test.
|
|
103
|
+
- **External systems (Telegram/Slack/GitHub/Cloudflare):** none.
|
|
104
|
+
- **Persistent state:** `.claude/settings.json` and the deployed `SKILL.md`. The
|
|
105
|
+
edit is convergent (always lands on the one correct entry), so re-running is safe.
|
|
106
|
+
- **Timing/runtime:** none — the migration is synchronous on the existing update path.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 7. Rollback cost
|
|
111
|
+
|
|
112
|
+
Pure code + template change. Back-out is `git revert` + ship the next patch. There
|
|
113
|
+
is one consideration: this migration *writes a corrected entry* into existing
|
|
114
|
+
agents' `settings.json`. A revert would stop applying the correction but would NOT
|
|
115
|
+
re-break already-corrected agents (the correct path resolves to a real file, so a
|
|
116
|
+
reverted build leaves them working). No data migration, no agent reset, no
|
|
117
|
+
user-visible regression during the rollback window. Worst case of the fix itself
|
|
118
|
+
being wrong: an agent ends up with a Stop-hook entry pointing at the skill path —
|
|
119
|
+
which is exactly where the file lives — so the failure mode of the fix is "it
|
|
120
|
+
works".
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Conclusion
|
|
125
|
+
|
|
126
|
+
The review produced no design changes. The fix is a narrow, deterministic path
|
|
127
|
+
correction with a self-healing registrar and an in-place repair migration that
|
|
128
|
+
satisfies the Migration Parity Standard for both the `settings.json` entry and the
|
|
129
|
+
deployed skill prompt. The only decision surface is a fixed path string, the
|
|
130
|
+
repair is idempotent and convergent, and the customized-prompt guard is preserved.
|
|
131
|
+
Clear to ship.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Second-pass review (if required)
|
|
136
|
+
|
|
137
|
+
**Reviewer:** Echo (self) — Tier-1 fix, single-pass per the tiered process.
|
|
138
|
+
**Independent read of the artifact: concur**
|
|
139
|
+
|
|
140
|
+
The change has no message-gating surface, the repair-before-presence-check
|
|
141
|
+
ordering is the load-bearing correctness point and is tested, and the Migration
|
|
142
|
+
Parity obligations (settings repair + marker-gated SKILL.md re-deploy + customized
|
|
143
|
+
guard) are all covered. No concerns.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Evidence pointers
|
|
148
|
+
|
|
149
|
+
- `tests/unit/PostUpdateMigrator-autonomousHookPath.test.ts` — 9 tests (repair,
|
|
150
|
+
no-duplicate, sibling-preservation, no-op-when-correct, register-when-missing,
|
|
151
|
+
idempotency, SKILL.md content marker, topic-keyed re-deploy + customized-skip).
|
|
152
|
+
- Empirical SKILL.md snippet run against a wrong-path settings fixture: wrong entry
|
|
153
|
+
rewritten to the skill path, siblings preserved, second run idempotent.
|
|
154
|
+
- Regression: `autonomous-skill-deployment`, `PostUpdateMigrator-buildStopHook`,
|
|
155
|
+
`autonomous-stop-hook-notify`, `installCodexHooks`, `emit-session-clock` — 50
|
|
156
|
+
tests green. `tsc --noEmit` clean.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Side-Effects Review — Iris-audit token usage accounting (PR B: item 1)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `iris-audit-token-accounting`
|
|
4
|
+
**Date:** `2026-06-02`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `convergence reviewers (shared spec) — concur`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
PR B of the Iris-audit spec (`docs/specs/iris-audit-session-observability.md`), item
|
|
11
|
+
1: make `/metrics/features` report real per-feature token usage instead of always 0.
|
|
12
|
+
`ClaudeCliIntelligenceProvider` switches `claude -p` from `--output-format text` to
|
|
13
|
+
`json` and parses the result object for the answer (`.result`) and `usage`; a new
|
|
14
|
+
additive optional `onUsage` callback on `IntelligenceOptions` surfaces the token
|
|
15
|
+
counts. `CircuitBreakingIntelligenceProvider` (the universal LLM funnel) passes an
|
|
16
|
+
`onUsage` that captures usage and forwards `tokensIn/tokensOut` into the existing
|
|
17
|
+
`FeatureMetricsLedger` tap. Files: `src/core/types.ts`, `src/core/
|
|
18
|
+
ClaudeCliIntelligenceProvider.ts`, `src/core/CircuitBreakingIntelligenceProvider.ts`,
|
|
19
|
+
plus tests. The decision points touched are observability-only — no gate changes.
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
- `IntelligenceOptions.onUsage` (types.ts) — **add** — optional callback; no decision
|
|
24
|
+
logic.
|
|
25
|
+
- `ClaudeCliIntelligenceProvider.evaluate` output parsing (ClaudeCliIntelligence
|
|
26
|
+
Provider.ts) — **modify** — text→json + `parseJsonResult`; affects the return-value
|
|
27
|
+
extraction for EVERY Claude-backed LLM call, but the returned text is unchanged.
|
|
28
|
+
- `CircuitBreakingIntelligenceProvider` metrics tap (CircuitBreakingIntelligence
|
|
29
|
+
Provider.ts) — **modify** — now forwards token counts; observability only.
|
|
30
|
+
|
|
31
|
+
## 1. Over-block
|
|
32
|
+
|
|
33
|
+
No block/allow surface — over-block not applicable. This is pure observability
|
|
34
|
+
plumbing; nothing is rejected.
|
|
35
|
+
|
|
36
|
+
## 2. Under-block
|
|
37
|
+
|
|
38
|
+
No block/allow surface — under-block not applicable. (If usage is ever absent or
|
|
39
|
+
unparseable, the only effect is that a call's token cost is omitted — recorded as the
|
|
40
|
+
pre-existing 0/null — never a wrong block.)
|
|
41
|
+
|
|
42
|
+
## 3. Level-of-abstraction fit
|
|
43
|
+
|
|
44
|
+
Right layer. Token usage originates in the provider that runs the CLI
|
|
45
|
+
(`ClaudeCliIntelligenceProvider`) — the only place it exists — and is surfaced via the
|
|
46
|
+
same `IntelligenceOptions` contract every provider already takes. The funnel
|
|
47
|
+
(`CircuitBreakingIntelligenceProvider`) is the established single chokepoint that
|
|
48
|
+
already records the per-feature metric; threading tokens through it instruments ALL
|
|
49
|
+
LLM features at once (Structure > Willpower) rather than each call site. The ledger is
|
|
50
|
+
reused unchanged (it already had token columns waiting for data).
|
|
51
|
+
|
|
52
|
+
## 4. Signal vs authority compliance
|
|
53
|
+
|
|
54
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
55
|
+
|
|
56
|
+
- [x] No — this change has no block/allow surface (it is observability: a signal
|
|
57
|
+
producer feeding the metrics ledger).
|
|
58
|
+
|
|
59
|
+
The metrics ledger is a read-only signal surface (`/metrics/features`); it never gates.
|
|
60
|
+
Token accounting strictly adds data; it holds no authority.
|
|
61
|
+
|
|
62
|
+
## 5. Interactions
|
|
63
|
+
|
|
64
|
+
- **Shadowing:** none — parsing happens inside `evaluate`'s existing resolve path; no
|
|
65
|
+
new check before/after another.
|
|
66
|
+
- **Double-fire:** `onUsage` fires at most once per successful call (only when usage
|
|
67
|
+
is present with non-zero tokens); the funnel composes with (does not clobber) any
|
|
68
|
+
caller-supplied `onUsage`.
|
|
69
|
+
- **Races:** none — synchronous parse within the call's own callback.
|
|
70
|
+
- **Feedback loops:** none — recorded metrics are read-only; nothing consumes them to
|
|
71
|
+
re-drive an LLM call.
|
|
72
|
+
|
|
73
|
+
## 6. External surfaces
|
|
74
|
+
|
|
75
|
+
- **The claude CLI invocation changes** from `--output-format text` to `json`. This is
|
|
76
|
+
the load-bearing risk: the return value is now extracted from `.result`. Mitigation:
|
|
77
|
+
`parseJsonResult` is defensive — non-JSON or missing `.result` falls back to the raw
|
|
78
|
+
trimmed stdout (the prior behavior), so a malformed/partial response degrades to
|
|
79
|
+
"answer without token accounting," never a crash or a JSON blob leaking to callers.
|
|
80
|
+
The empirical CLI shape was verified live (`{ result, usage:{ input_tokens,
|
|
81
|
+
cache_creation_input_tokens, cache_read_input_tokens, output_tokens } }`).
|
|
82
|
+
- **Rate-limit detection unaffected:** the circuit breaker's classifier reads
|
|
83
|
+
`stderr`, not stdout — the format switch does not touch it (verified in the provider;
|
|
84
|
+
the error path is unchanged).
|
|
85
|
+
- **Other agents / install base:** ships fleet-wide via update; every LLM-backed
|
|
86
|
+
feature's calls now carry token counts into `/metrics/features`. No behavior change
|
|
87
|
+
to what those features decide — only the cost telemetry becomes real.
|
|
88
|
+
- **Persistent state:** writes to the existing `FeatureMetricsLedger` SQLite token
|
|
89
|
+
columns (previously always null); no schema change (columns already existed).
|
|
90
|
+
|
|
91
|
+
## 7. Rollback cost
|
|
92
|
+
|
|
93
|
+
- **Hot-fix release:** pure code revert shipped as the next patch (revert the three
|
|
94
|
+
core files). No persistent-state migration — the ledger columns simply return to
|
|
95
|
+
null. No agent-state repair, no user-visible regression.
|
|
96
|
+
- The only externally-observable change is `claude -p --output-format json`; reverting
|
|
97
|
+
restores `text`. Because `parseJsonResult` already tolerates non-JSON, even a partial
|
|
98
|
+
rollout (some agents on json, some on text) is safe.
|
|
99
|
+
|
|
100
|
+
## Conclusion
|
|
101
|
+
|
|
102
|
+
The review produced no design changes — the change is additive, observability-only, and
|
|
103
|
+
defensively parsed. The single real risk (the CLI output-format switch) is contained by
|
|
104
|
+
the raw-stdout fallback and verified against the live CLI shape. Clear to ship. This is
|
|
105
|
+
the sibling of PR A under the same converged + approved spec.
|
|
106
|
+
|
|
107
|
+
## Second-pass review (if required)
|
|
108
|
+
|
|
109
|
+
**Reviewer:** the 3 spec convergence reviewers (shared spec) — concur on item 1's
|
|
110
|
+
design (additive onUsage side-channel, no evaluate() return-type change). The one
|
|
111
|
+
open question they raised — does onUsage fire on cache-only reads — is resolved here:
|
|
112
|
+
`parseJsonResult` sums cache_read/cache_creation INTO tokensIn (they are real input
|
|
113
|
+
cost) and fires whenever any count is non-zero, so cache-dominated calls are counted,
|
|
114
|
+
not dropped.
|
|
115
|
+
|
|
116
|
+
## Evidence pointers
|
|
117
|
+
|
|
118
|
+
- `tests/unit/ClaudeCliIntelligenceProvider-jsonParse.test.ts` — parser contract
|
|
119
|
+
(extract .result, sum input components, defensive fallbacks, onUsage firing rules).
|
|
120
|
+
- `tests/unit/CircuitBreaking-feature-metrics-tap.test.ts` — funnel forwards tokens to
|
|
121
|
+
the recorder, composes with caller onUsage, omits when absent, and sums into the real
|
|
122
|
+
ledger rollup (tokensIn/tokensOut no longer 0).
|
|
123
|
+
- Live CLI shape verified: `claude -p --model haiku --output-format json` →
|
|
124
|
+
`{ result:"ok", usage:{ input_tokens:10, output_tokens:41, ... } }`.
|
|
125
|
+
- `tsc --noEmit` clean.
|