instar 1.3.422 → 1.3.424

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 (60) hide show
  1. package/dashboard/index.html +121 -0
  2. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  3. package/dist/config/ConfigDefaults.js +8 -0
  4. package/dist/config/ConfigDefaults.js.map +1 -1
  5. package/dist/core/CircuitBreakingIntelligenceProvider.d.ts +10 -0
  6. package/dist/core/CircuitBreakingIntelligenceProvider.d.ts.map +1 -1
  7. package/dist/core/CircuitBreakingIntelligenceProvider.js +45 -8
  8. package/dist/core/CircuitBreakingIntelligenceProvider.js.map +1 -1
  9. package/dist/core/ClaudeCliIntelligenceProvider.d.ts.map +1 -1
  10. package/dist/core/ClaudeCliIntelligenceProvider.js +6 -0
  11. package/dist/core/ClaudeCliIntelligenceProvider.js.map +1 -1
  12. package/dist/core/CodexCliIntelligenceProvider.d.ts.map +1 -1
  13. package/dist/core/CodexCliIntelligenceProvider.js +9 -0
  14. package/dist/core/CodexCliIntelligenceProvider.js.map +1 -1
  15. package/dist/core/ExternalOperationGate.d.ts.map +1 -1
  16. package/dist/core/ExternalOperationGate.js +19 -3
  17. package/dist/core/ExternalOperationGate.js.map +1 -1
  18. package/dist/core/GeminiCliIntelligenceProvider.d.ts.map +1 -1
  19. package/dist/core/GeminiCliIntelligenceProvider.js +7 -0
  20. package/dist/core/GeminiCliIntelligenceProvider.js.map +1 -1
  21. package/dist/core/InteractivePoolIntelligenceProvider.d.ts.map +1 -1
  22. package/dist/core/InteractivePoolIntelligenceProvider.js +8 -0
  23. package/dist/core/InteractivePoolIntelligenceProvider.js.map +1 -1
  24. package/dist/core/MessageSentinel.d.ts.map +1 -1
  25. package/dist/core/MessageSentinel.js +7 -0
  26. package/dist/core/MessageSentinel.js.map +1 -1
  27. package/dist/core/PiCliIntelligenceProvider.d.ts.map +1 -1
  28. package/dist/core/PiCliIntelligenceProvider.js +20 -0
  29. package/dist/core/PiCliIntelligenceProvider.js.map +1 -1
  30. package/dist/core/PostUpdateMigrator.js +6 -6
  31. package/dist/core/PostUpdateMigrator.js.map +1 -1
  32. package/dist/core/types.d.ts +31 -0
  33. package/dist/core/types.d.ts.map +1 -1
  34. package/dist/core/types.js.map +1 -1
  35. package/dist/monitoring/CommitmentSentinel.d.ts.map +1 -1
  36. package/dist/monitoring/CommitmentSentinel.js +16 -0
  37. package/dist/monitoring/CommitmentSentinel.js.map +1 -1
  38. package/dist/monitoring/FeatureMetricsLedger.d.ts +16 -0
  39. package/dist/monitoring/FeatureMetricsLedger.d.ts.map +1 -1
  40. package/dist/monitoring/FeatureMetricsLedger.js +71 -2
  41. package/dist/monitoring/FeatureMetricsLedger.js.map +1 -1
  42. package/dist/scaffold/templates.d.ts.map +1 -1
  43. package/dist/scaffold/templates.js +4 -3
  44. package/dist/scaffold/templates.js.map +1 -1
  45. package/dist/server/AgentServer.d.ts +1 -0
  46. package/dist/server/AgentServer.d.ts.map +1 -1
  47. package/dist/server/AgentServer.js +27 -0
  48. package/dist/server/AgentServer.js.map +1 -1
  49. package/dist/threadline/ContentClassifier.d.ts.map +1 -1
  50. package/dist/threadline/ContentClassifier.js +23 -6
  51. package/dist/threadline/ContentClassifier.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/data/builtin-manifest.json +20 -20
  54. package/src/scaffold/templates.ts +4 -3
  55. package/upgrades/1.3.423.md +28 -0
  56. package/upgrades/1.3.424.md +28 -0
  57. package/upgrades/eli16/llm-fallback-failclosed.md +33 -0
  58. package/upgrades/eli16/observable-intelligence-llm-activity.md +26 -0
  59. package/upgrades/side-effects/llm-fallback-failclosed.md +37 -0
  60. package/upgrades/side-effects/observable-intelligence-llm-activity.md +25 -0
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-08T01:50:28.381Z",
5
- "instarVersion": "1.3.422",
4
+ "generatedAt": "2026-06-08T04:23:21.250Z",
5
+ "instarVersion": "1.3.424",
6
6
  "entryCount": 199,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
14
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
15
15
  "since": "2025-01-01"
16
16
  },
17
17
  "hook:dangerous-command-guard": {
@@ -20,7 +20,7 @@
20
20
  "domain": "safety",
21
21
  "sourcePath": "src/core/PostUpdateMigrator.ts",
22
22
  "installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
23
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
23
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
24
24
  "since": "2025-01-01"
25
25
  },
26
26
  "hook:grounding-before-messaging": {
@@ -29,7 +29,7 @@
29
29
  "domain": "safety",
30
30
  "sourcePath": "src/core/PostUpdateMigrator.ts",
31
31
  "installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
32
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
32
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
33
33
  "since": "2025-01-01"
34
34
  },
35
35
  "hook:compaction-recovery": {
@@ -38,7 +38,7 @@
38
38
  "domain": "identity",
39
39
  "sourcePath": "src/core/PostUpdateMigrator.ts",
40
40
  "installedPath": ".instar/hooks/instar/compaction-recovery.sh",
41
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
41
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
42
42
  "since": "2025-01-01"
43
43
  },
44
44
  "hook:external-operation-gate": {
@@ -47,7 +47,7 @@
47
47
  "domain": "safety",
48
48
  "sourcePath": "src/core/PostUpdateMigrator.ts",
49
49
  "installedPath": ".instar/hooks/instar/external-operation-gate.js",
50
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
50
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
51
51
  "since": "2025-01-01"
52
52
  },
53
53
  "hook:deferral-detector": {
@@ -56,7 +56,7 @@
56
56
  "domain": "safety",
57
57
  "sourcePath": "src/core/PostUpdateMigrator.ts",
58
58
  "installedPath": ".instar/hooks/instar/deferral-detector.js",
59
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
59
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
60
60
  "since": "2025-01-01"
61
61
  },
62
62
  "hook:self-stop-guard": {
@@ -65,7 +65,7 @@
65
65
  "domain": "coherence",
66
66
  "sourcePath": "src/core/PostUpdateMigrator.ts",
67
67
  "installedPath": ".instar/hooks/instar/self-stop-guard.js",
68
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
68
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
69
69
  "since": "2025-01-01"
70
70
  },
71
71
  "hook:post-action-reflection": {
@@ -74,7 +74,7 @@
74
74
  "domain": "evolution",
75
75
  "sourcePath": "src/core/PostUpdateMigrator.ts",
76
76
  "installedPath": ".instar/hooks/instar/post-action-reflection.js",
77
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
77
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
78
78
  "since": "2025-01-01"
79
79
  },
80
80
  "hook:external-communication-guard": {
@@ -83,7 +83,7 @@
83
83
  "domain": "safety",
84
84
  "sourcePath": "src/core/PostUpdateMigrator.ts",
85
85
  "installedPath": ".instar/hooks/instar/external-communication-guard.js",
86
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
86
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
87
87
  "since": "2025-01-01"
88
88
  },
89
89
  "hook:scope-coherence-collector": {
@@ -92,7 +92,7 @@
92
92
  "domain": "coherence",
93
93
  "sourcePath": "src/core/PostUpdateMigrator.ts",
94
94
  "installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
95
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
95
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
96
96
  "since": "2025-01-01"
97
97
  },
98
98
  "hook:scope-coherence-checkpoint": {
@@ -101,7 +101,7 @@
101
101
  "domain": "coherence",
102
102
  "sourcePath": "src/core/PostUpdateMigrator.ts",
103
103
  "installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
104
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
104
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
105
105
  "since": "2025-01-01"
106
106
  },
107
107
  "hook:free-text-guard": {
@@ -110,7 +110,7 @@
110
110
  "domain": "safety",
111
111
  "sourcePath": "src/core/PostUpdateMigrator.ts",
112
112
  "installedPath": ".instar/hooks/instar/free-text-guard.sh",
113
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
113
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
114
114
  "since": "2025-01-01"
115
115
  },
116
116
  "hook:claim-intercept": {
@@ -119,7 +119,7 @@
119
119
  "domain": "coherence",
120
120
  "sourcePath": "src/core/PostUpdateMigrator.ts",
121
121
  "installedPath": ".instar/hooks/instar/claim-intercept.js",
122
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
122
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
123
123
  "since": "2025-01-01"
124
124
  },
125
125
  "hook:claim-intercept-response": {
@@ -128,7 +128,7 @@
128
128
  "domain": "coherence",
129
129
  "sourcePath": "src/core/PostUpdateMigrator.ts",
130
130
  "installedPath": ".instar/hooks/instar/claim-intercept-response.js",
131
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
131
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
132
132
  "since": "2025-01-01"
133
133
  },
134
134
  "hook:stop-gate-router": {
@@ -137,7 +137,7 @@
137
137
  "domain": "safety",
138
138
  "sourcePath": "src/core/PostUpdateMigrator.ts",
139
139
  "installedPath": ".instar/hooks/instar/stop-gate-router.js",
140
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
140
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
141
141
  "since": "2025-01-01"
142
142
  },
143
143
  "hook:auto-approve-permissions": {
@@ -146,7 +146,7 @@
146
146
  "domain": "safety",
147
147
  "sourcePath": "src/core/PostUpdateMigrator.ts",
148
148
  "installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
149
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
149
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1506,7 +1506,7 @@
1506
1506
  "type": "subsystem",
1507
1507
  "domain": "server",
1508
1508
  "sourcePath": "src/server/AgentServer.ts",
1509
- "contentHash": "1b7d450ba6a4b4793a0497d93dde540c42227edb34d6b6fd92ab641c76b64438",
1509
+ "contentHash": "e07f73675b7bafbe48a0392568e9582a697ef9836691e5483add48393a3bc7cc",
1510
1510
  "since": "2025-01-01"
1511
1511
  },
1512
1512
  "subsystem:session-manager": {
@@ -1538,7 +1538,7 @@
1538
1538
  "type": "subsystem",
1539
1539
  "domain": "updates",
1540
1540
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1541
- "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
1541
+ "contentHash": "6462f37482e82b16ab0d525e4924c9ad41b908ac148d48fe8d8aee705b3993ec",
1542
1542
  "since": "2025-01-01"
1543
1543
  },
1544
1544
  "subsystem:scheduler": {
@@ -702,10 +702,11 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
702
702
  - **Dashboard**: the **Subscriptions tab** shows live quota bars (5h + weekly + reset countdown), status, and the Pending Logins panel — share the dashboard URL + PIN.
703
703
  - **When to use** (PROACTIVE): "how much quota is left across my accounts?" / "am I about to hit a limit?" → \`GET /subscription-pool\`; the user wants to add another subscription → drive the enrollment wizard (never ask them to paste a token); a long job is at risk of a quota wall → the continuity guarantee + \`/swap\` keep it alive. Single-account pools are a no-op.
704
704
 
705
- **Per-Feature LLM Metrics** — See what each of your LLM-driven gates/sentinels actually costs and how often it fires, so tuning them is evidence-based (which to thin, which to strengthen). Read-only observability (like token usage) — it never gates anything.
705
+ **Per-Feature LLM Metrics & LLM Activity (Observable Intelligence)** — Audit what each of your LLM-driven gates/sentinels actually does: WHICH provider + model ran it, how often it ACTED (fired) vs found nothing (noop), how often it was skipped to save rate limits (shed), cost, and latency. This is the *Observable Intelligence* standard — no autonomous AI action the system takes is allowed to be invisible. Read-only observability — it never gates anything.
706
706
  - Check: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/metrics/features?sinceHours=24"\`
707
- - Returns \`{ totals, features: [{ feature, calls, tokensIn, tokensOut, fired, noop, fireRate, p50LatencyMs, p95LatencyMs, ... }] }\` — one row per system (e.g. MessagingToneGate, CoherenceReviewer). Filter with \`?feature=<name>\`.
708
- - **When to use**: when asked "which checks cost the most / fire the least?", "is this gate worth it?", or before tuning a sentinel/gate read the numbers instead of guessing. (Spec: \`docs/specs/llm-feature-metrics-spec.md\`.)
707
+ - Returns \`{ totals, features: [{ feature, frameworks, models, calls, realCalls, tokensIn, tokensOut, fired, noop, shed, fireRate, p50LatencyMs, p95LatencyMs, ... }] }\` — one row per system (e.g. MessagingToneGate, MessageSentinel). \`frameworks\`/\`models\` = which provider(s) actually served the call; \`fireRate\` = how often it acts; \`shed\` = skipped by the rate-limit guard. Filter with \`?feature=<name>\`.
708
+ - **Dashboard:** the **LLM Activity** tab renders all of this in plain language over a 24h / 7d / 30d windowpoint the user there rather than pasting curl output.
709
+ - **When to use** (PROACTIVE): "which provider is this sentinel running on?" / "are the sentinels actually doing real work or just being skipped?" / "which checks cost the most or fire the least?" / before tuning a sentinel or gate → read the numbers (\`frameworks\`/\`models\` for provider, \`fireRate\` for effectiveness, \`shed\` for skip rate) instead of guessing. Bounded retention (~30 days; tune \`monitoring.featureMetrics.retentionDays\`). (Specs: \`docs/specs/observable-intelligence.md\`, \`docs/specs/llm-feature-metrics-spec.md\`.)
709
710
 
710
711
  **Resource Usage (CPU + memory + rate-limit events)** — Durable per-agent record of what you actually consume, mirroring the TokenLedger. Read-only observability — it never gates. Two parts:
711
712
  - **CPU + memory** (Phase B): your server process and every running session are sampled continuously for CPU% and memory (RSS). Check current + windowed (avg/peak) usage, broken down per source plus an aggregate: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/resources/summary?sinceHours=1"\` → \`{ sampleCount, sources: [{ source, currentCpuPercent, currentRssBytes, avgCpuPercent, peakCpuPercent, peakRssBytes, ... }] }\` (\`source\` is \`agent-server\`, \`session:<id>\`, or \`aggregate\`). Recent raw samples: \`GET /resources/samples?sinceHours=1&source=aggregate&limit=20\`. The dashboard "Resource Usage" tab renders all of this in plain language.
@@ -0,0 +1,28 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Two safety-gating LLM fallbacks flipped from fail-OPEN to fail-CLOSED, implementing the new "No Silent Degradation to Brittle Fallback" standard:
9
+ - `ExternalOperationGate.consultLLM`: on LLM failure (rate-limit/circuit-open/timeout) it returned `proceed` — now returns `show-plan` (require approval). A risky op the LLM would have escalated can no longer slip through while the LLM is down.
10
+ - `ContentClassifier` (A2A outbound-leak gate): on parse-fail or error it returned `safe` — now returns `sensitive`, so unverifiable content is held, not shipped to a peer.
11
+
12
+ Also lands `docs/specs/no-silent-degradation-to-brittle-fallback.md`: the standard + the "Iterative Audit to Convergence" standard + round-1 audit (2 dangerous fail-open gates fixed here; provider-swap + lint + re-audit + throwaway-agent are the follow-ups).
13
+
14
+ ## What to Tell Your User
15
+
16
+ - "I hardened two safety checks: when the AI behind them is rate-limited or down, they now pause for your approval (or hold the content) instead of silently allowing the action. The honest tradeoff is that during a heavy AI rate-limit, a few more operations will wait for your OK — that's the safe direction, and I'm adding an automatic swap-to-another-AI-provider so it happens less often."
17
+
18
+ ## Summary of New Capabilities
19
+
20
+ | Capability | How to Use |
21
+ |-----------|-----------|
22
+ | Operations gate fails closed on LLM failure | Automatic. On AI failure the gate requires a plan/approval instead of proceeding. |
23
+ | A2A leak gate fails closed on LLM failure | Automatic. Unverifiable outbound content is held as sensitive, not shipped. |
24
+ | No-Silent-Degradation + Iterative-Audit standards | docs/specs/no-silent-degradation-to-brittle-fallback.md |
25
+
26
+ ## Evidence
27
+
28
+ Before: with the LLM rate-limited (circuit open), `ExternalOperationGate` returned `proceed` for any op its deterministic floor didn't catch, and `ContentClassifier` returned `safe` for any content it couldn't classify. Surfaced live during the EXO 3.0 harness rate-limit. After: both fail closed (`show-plan` / `sensitive`). Regression tests: ExternalOperationGate "FAILS CLOSED to show-plan", ContentClassifier "FAILS CLOSED to sensitive" (parse-fail + throw). 98 unit tests green; tsc clean.
@@ -0,0 +1,28 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ The per-feature LLM metrics ledger now records, for every call the system makes on its own behalf (sentinels, gates, reflectors, background checks), **which provider + model actually ran it** and **whether the check acted (fired) or found nothing (noop)** — closing two long-standing blind spots: the `model` column was never populated, and the `fired` verdict was deferred to a "Phase 2" that never shipped, so codex/gemini calls were unattributable and every completed call read as a no-op. Recording is enforced at the single funnel (`CircuitBreakingIntelligenceProvider`) via two additive, optional seams on `IntelligenceOptions` — `onModel` (every provider surfaces its resolved model/framework, independent of token usage) and `classifyVerdict` (the caller classifies act-vs-no-act). A new **LLM Activity** dashboard tab renders it in plain language over a 24h/7d/30d window. Bounded retention (default 30 days, `monitoring.featureMetrics.retentionDays`) ages the audit trail out so it is never hoarded forever.
9
+
10
+ ## What to Tell Your User
11
+
12
+ You can now audit what your agent's "autopilot" is actually doing: open the **LLM Activity** dashboard tab to see, per check, which AI provider ran it, how often it acted on something vs. found nothing, how often it was skipped to save rate limits, and what it cost — over time. This is the new *Observable Intelligence* standard: no autonomous AI action the system takes is allowed to be invisible. Nothing for you to do; it takes effect on the next restart.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - `/metrics/features` rows now include `frameworks[]`, `models[]`, real `fired`/`fireRate`, and `shed` — answering "which provider ran this sentinel?" and "is it doing real work or just being skipped?".
17
+ - New **LLM Activity** dashboard tab (read-only) over a selectable window.
18
+ - `IntelligenceOptions.onModel` + `classifyVerdict` seams; every provider (Claude/Codex/Gemini/Pi/InteractivePool) surfaces its model/framework; `MessageSentinel` + `CommitmentSentinel` classify their verdicts.
19
+ - Bounded retention via `FeatureMetricsLedger.pruneOlderThan` + `monitoring.featureMetrics.retentionDays` (default 30).
20
+ - New constitutional standard *Observable Intelligence — No Autonomous LLM Action Is Unauditable* (proposed, pending ratification) + spec `docs/specs/observable-intelligence.md`.
21
+
22
+ ## Evidence
23
+
24
+ `tests/unit/FeatureMetricsLedger.test.ts` (12, +4: framework rollup, prune, idempotent column add), `tests/unit/CircuitBreaking-feature-metrics-tap.test.ts` (19, +7: onModel/classifyVerdict/error-path attribution + real-ledger rollup), `tests/integration/metrics-features-routes.test.ts` (+1: provider/model/fired through the route), `tests/e2e/metrics-features-lifecycle.test.ts` green; no-silent-fallbacks ratchet + feature-delivery-completeness parity green; `tsc` clean.
25
+
26
+ ## Scope (honest)
27
+
28
+ Provider/model attribution + the fired/noop verdict are recorded for all providers. Per-call **token cost** is captured where the provider surfaces it (Claude, Pi); codex/gemini exec output carries no usage block, so their per-call tokens stay null (model/framework + outcome are still recorded; account-level codex cost is visible via `/codex/usage`) — per-call token parsing for those via their `--json` modes is a bounded follow-up. Read-only observability throughout: it never gates, blocks, or mutates the path it observes.
@@ -0,0 +1,33 @@
1
+ # Fail-Closed for LLM Safety Gates — Plain-English Overview
2
+
3
+ > The one-line version: two safety gates that asked an AI for a yes/no were quietly saying "yes, go ahead" whenever the AI was unavailable — now they say "wait for approval" instead.
4
+
5
+ ## The problem in one breath
6
+
7
+ When an AI model makes a safety decision and the model is rate-limited or down, the worst possible answer is to silently fall back to a permissive default — it looks protected but isn't. Two of our gates did exactly that: on an AI failure they returned the *go-ahead* answer.
8
+
9
+ ## What already exists
10
+
11
+ - **The operations safety-gate** — checks risky external operations (sending email, deleting things) and decides: proceed, show-a-plan-first, or block. It was built after an agent autonomously deleted 200 emails.
12
+ - **The outbound-leak gate** — checks content an agent is about to send to another agent for leaks (secrets, system prompts, private data) and decides: safe, sensitive, or blocked.
13
+
14
+ ## What this adds
15
+
16
+ Both gates now **fail closed** when the AI can't answer:
17
+
18
+ - The operations gate, on AI failure, returns **"show a plan first"** (require approval) instead of **"proceed"**. A risky operation the AI would have escalated can no longer slip through silently while the AI is down.
19
+ - The outbound-leak gate, on AI failure (unparseable reply OR error), returns **"sensitive"** instead of **"safe"**, so unverifiable content is held instead of silently shipped to a peer.
20
+
21
+ It also lands the **"No Silent Degradation to Brittle Fallback"** standard (when an AI gates a real action, swap providers or fail closed — never silently degrade to a weak check) and the **"Iterative Audit to Convergence"** standard (audit → fix → re-audit until a pass finds nothing new).
22
+
23
+ ## The safeguards
24
+
25
+ **Prevents fake-safety.** A gate that silently downgrades to a permissive default is more dangerous than no gate, because it looks like it's protecting you. Failing closed removes that illusion.
26
+
27
+ **No behavior change when the AI is healthy.** A complete, parseable AI verdict behaves exactly as before — these changes only affect the failure path.
28
+
29
+ **Honest tradeoff.** During a heavy AI rate-limit, more operations will pause for approval instead of silently proceeding. That's the safe direction, and the planned provider-swap (try another AI before failing) will shrink how often it happens.
30
+
31
+ ## What ships when
32
+
33
+ This PR is the two gate-flips + the standard. Next: a shared provider-swap so gates try another AI provider before failing closed, a lint that flags new silent-fallbacks in gating paths, a re-audit to convergence, and a throwaway sandbox agent for adversarial behavioral testing.
@@ -0,0 +1,26 @@
1
+ # Observable Intelligence — in plain language
2
+
3
+ ## The problem
4
+
5
+ Your agent has a bunch of little "autopilot" helpers running in the background — the things we call sentinels and gates. They watch your messages, decide whether something needs action, and quietly handle housekeeping. Each one can ask an AI model a quick question to make its call.
6
+
7
+ Someone asked a simple, fair question: *"Which AI provider are these helpers actually using, and are they even doing any real work?"* And the honest answer was: **we couldn't fully tell.** The log that's supposed to track this had two holes in it:
8
+
9
+ 1. It never wrote down **which AI** ran each check. So if you'd switched your sentinels over to a different provider (say, Codex instead of Claude), the log couldn't prove it.
10
+ 2. It never wrote down whether a check **actually did something** versus just looked and found nothing. So every check looked identical in the data — you couldn't tell a hard-working guard from a useless one.
11
+
12
+ A helper that acts on your behalf but can't show what it chose to do is a helper you can't hold accountable. That's the gap this closes.
13
+
14
+ ## What changed
15
+
16
+ Now, every time one of these helpers asks an AI a question, the system writes down: **which provider and model answered, whether the helper acted or found nothing, whether it got skipped to save on rate limits, how much it cost, and how long it took.** It records this at one shared "chokepoint" that every helper already passes through — so it covers all of them automatically, today and in the future, with nothing to remember.
17
+
18
+ There's a new **"LLM Activity" tab** in your dashboard that shows all of this in plain English: one row per helper, over a window you pick (last day, week, or month). You can finally see, at a glance, which helpers earn their keep and which are mostly idle or skipped.
19
+
20
+ ## The balance
21
+
22
+ We don't keep this log forever — that would just be hoarding. It's kept about a month (you can change that), then old entries age out. Long enough to spot trends, not so long it piles up.
23
+
24
+ ## Is it risky?
25
+
26
+ No. This only **watches** — it never blocks, changes, or slows down anything the helpers do. If the new tracking ever hiccupped, the helper would carry on exactly as before. It's all extra, additive recording, fully covered by tests.
@@ -0,0 +1,37 @@
1
+ # Side-Effects Review — Fail-closed for LLM safety gates
2
+
3
+ **Version / slug:** `llm-fallback-failclosed`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `Echo`
6
+ **Second-pass reviewer:** `not required (Tier-1)`
7
+
8
+ ## Summary of the change
9
+ Two safety-gating LLM fallbacks flipped from fail-OPEN to fail-CLOSED:
10
+ `src/core/ExternalOperationGate.ts` `consultLLM` catch: `proceed` → `show-plan`.
11
+ `src/threadline/ContentClassifier.ts` parse-fail + error catch: `safe` → `sensitive`.
12
+ Plus `docs/specs/no-silent-degradation-to-brittle-fallback.md` (the standard + round-1 audit). Regression tests updated in both unit suites.
13
+
14
+ ## Decision-point inventory
15
+ - `ExternalOperationGate.consultLLM` LLM-failure branch — modify (proceed→show-plan)
16
+ - `ContentClassifier` parse-fail + error branches — modify (safe→sensitive)
17
+
18
+ ## 1. Over-block
19
+ On LLM failure (rate-limit/circuit-open/timeout), operations now require a plan/approval and outbound A2A content is held as sensitive. During a heavy LLM outage this WILL pause more ops for approval and hold more A2A messages than before — intentional (fail-closed). Healthy-LLM behavior is unchanged. The planned provider-swap reduces failure frequency.
20
+
21
+ ## 2. Under-block
22
+ Strictly reduces under-block: the previous fail-open silently allowed risky ops / shipped unverifiable content when the LLM was down. That hole is closed.
23
+
24
+ ## 3. Data / state
25
+ None. Pure decision-value changes; no new files (except docs), no schema, no migration.
26
+
27
+ ## 4. Performance
28
+ None. Same code path; only the returned verdict on the already-existing failure branch changes.
29
+
30
+ ## 5. Failure modes
31
+ This change IS the failure-mode hardening. The fail-closed verdicts (show-plan, sensitive) are existing valid values handled downstream. No new throw paths.
32
+
33
+ ## 6. Security / auth
34
+ Hardens two trust boundaries: the external-operation gate (autonomous-deletion incident origin) and the A2A outbound-leak gate. No new endpoints/capabilities.
35
+
36
+ ## 7. Migration / compatibility
37
+ No migration. Behavior takes effect on next deploy; existing agents get the safer fail-closed posture automatically. No agent-installed file changes.
@@ -0,0 +1,25 @@
1
+ # Side-effects review — Observable Intelligence / LLM Activity
2
+
3
+ **Tier:** 1 (large but purely additive, read-only observability; no existing behavior changes; reversible; full 3-tier tests). Risk floor flags "new capability" — declared below floor with this rationale, recorded in the decision audit.
4
+
5
+ ## Surface touched
6
+
7
+ - `IntelligenceOptions` gains two **optional** callbacks (`onModel`, `classifyVerdict`). Additive: every existing caller is byte-identical (evaluate() still returns `Promise<string>`).
8
+ - `CircuitBreakingIntelligenceProvider` (the single funnel) captures model/framework + classifies the verdict and records them. Pure side-channel — wrapped in try/catch; a throw in either callback cannot change what `evaluate()` returns or break the observed path.
9
+ - Five providers (Claude/Codex/Gemini/Pi/InteractivePool) each call `onModel` once per call. Each call is try/caught (`@silent-fallback-ok`) so it can never break the LLM path.
10
+ - Two sentinels (MessageSentinel, CommitmentSentinel) pass a `classifyVerdict`; the classification reuses their existing parse and defaults to noop on throw.
11
+ - `FeatureMetricsLedger`: new `framework` column via idempotent pragma-guarded `ALTER TABLE ADD COLUMN` (existing DBs migrate at open, no data loss); new `pruneOlderThan`; rollup gains `frameworks[]`/`models[]`.
12
+ - `AgentServer`: a retention prune timer (boot + every 6h, `unref`'d), cleared at shutdown.
13
+
14
+ ## Risks considered
15
+
16
+ - **Schema migration**: covered by a unit test that opens an old-schema DB and confirms the column is added without losing the legacy row. The ALTER is pragma-guarded and idempotent.
17
+ - **Performance**: recording is one extra SQLite insert per call (already happening) plus two cheap callback invocations. No new network calls.
18
+ - **Retention deletion**: `pruneOlderThan` only deletes rows older than the cutoff; fail-open (a failed prune leaves rows for the next tick). Default 30d, configurable, `0` disables.
19
+ - **Observability never gates**: same guarantee as TokenLedger. A failed metric write, failed prune, or thrown callback degrades silently; the LLM path is unaffected.
20
+ - **No new HTTP route** (reuses `/metrics/features`), so no new auth/route surface. Dashboard tab is read-only.
21
+ - **Migration parity**: existing agents get the enhanced CLAUDE.md section via the existing `/metrics/features` migrateClaudeMd block (enhanced in place, idempotent — verified by `PostUpdateMigrator-metricsFeatures.test.ts`); new agents via the template.
22
+
23
+ ## Constitutional fit
24
+
25
+ Implements the proposed **Observable Intelligence** standard (pending operator ratification); balanced by Responsible-Resource bounded retention. Sharpens the existing **Observability** standard.