instar 1.3.705 → 1.3.707
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +16 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +20 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/componentCategories.d.ts.map +1 -1
- package/dist/core/componentCategories.js +22 -0
- package/dist/core/componentCategories.js.map +1 -1
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/guardAcceptedFallbacks.d.ts +48 -0
- package/dist/monitoring/guardAcceptedFallbacks.d.ts.map +1 -0
- package/dist/monitoring/guardAcceptedFallbacks.js +106 -0
- package/dist/monitoring/guardAcceptedFallbacks.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts +25 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +48 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/monitoring/guardPostureView.d.ts +23 -0
- package/dist/monitoring/guardPostureView.d.ts.map +1 -1
- package/dist/monitoring/guardPostureView.js +66 -0
- package/dist/monitoring/guardPostureView.js.map +1 -1
- package/dist/monitoring/probes/GuardPostureProbe.d.ts +13 -2
- package/dist/monitoring/probes/GuardPostureProbe.d.ts.map +1 -1
- package/dist/monitoring/probes/GuardPostureProbe.js +143 -40
- package/dist/monitoring/probes/GuardPostureProbe.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +46 -1
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +63 -63
- package/src/data/state-coherence-registry.json +18 -0
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.706.md +80 -0
- package/upgrades/1.3.707.md +65 -0
- package/upgrades/side-effects/g3-dark-but-load-bearing-guards.md +143 -0
- package/upgrades/side-effects/llm-routing-register-uncategorized-components.md +100 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: minor -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The guard-posture inventory (`GET /guards`) can now express that a DARK feature
|
|
9
|
+
is load-bearing — that a critical path depends on it — instead of treating it as
|
|
10
|
+
an ordinary optional dark feature that sits quiet while the path it should guard
|
|
11
|
+
runs unguarded. This is the guard-layer arm of the ratified "A Dark Feature Guards
|
|
12
|
+
Nothing" standard, and it closes the gap the 2026-07-01 silent-loss postmortem
|
|
13
|
+
named (operator message delivery depended on dark guards, and nothing surfaced it).
|
|
14
|
+
|
|
15
|
+
A guard declared `loadBearing` in the manifest now carries a `criticalPath` label
|
|
16
|
+
on every row, and when it sits silently unguarded it is classified one of three
|
|
17
|
+
ways:
|
|
18
|
+
- `loadBearingGap` — LOUD. A critical path is unguarded. It alerts on its OWN
|
|
19
|
+
attention episode track (`guard-posture-loadbearing:ep-N`), so a long-lived gap
|
|
20
|
+
can never mask an acute load-shed on another guard.
|
|
21
|
+
- `loadBearingSoaking` — a dry-run guard graduating within a bounded, code-constant
|
|
22
|
+
soak window. Surfaced on `/guards` only, no alert; it LAPSES to a loud gap if it
|
|
23
|
+
stalls past the window.
|
|
24
|
+
- `loadBearingAccepted` — an owned, PIN-authenticated operator acceptance is on
|
|
25
|
+
record. Full suppression + a visible accepted-risk row.
|
|
26
|
+
|
|
27
|
+
New route (dashboard-PIN-gated, `owner` + `reason` both required):
|
|
28
|
+
`POST`/`DELETE /guards/:key/accept-fallback`. The initial curated load-bearing set
|
|
29
|
+
is small and conservative: the durable inbound-message queue and the stranded-topic
|
|
30
|
+
sentinel, both on the operator-message-delivery critical path.
|
|
31
|
+
|
|
32
|
+
The classifier stays observe-only — it never gates, blocks, or disables anything,
|
|
33
|
+
and `/guards` is byte-identical for a consumer that ignores the new fields. Rollback
|
|
34
|
+
lever for the alert: `monitoring.guardPostureProbe.alertLoadBearingGaps` (the
|
|
35
|
+
classification stays either way).
|
|
36
|
+
|
|
37
|
+
## What to Tell Your User
|
|
38
|
+
|
|
39
|
+
I can now tell you when a critical safety system is turned off but something
|
|
40
|
+
important actually depends on it — instead of it quietly staying dark. If that
|
|
41
|
+
happens I will flag it clearly and give you three ways to resolve it: turn the
|
|
42
|
+
guard on, let it finish a short grace period while it is being rolled out, or have
|
|
43
|
+
you formally accept the risk (which I record with your name and reason so it is a
|
|
44
|
+
real decision, not a shrug). Accepting a risk needs your dashboard PIN — I cannot
|
|
45
|
+
do it on your behalf. If you ever ask "why is a critical guard flagged as a gap?",
|
|
46
|
+
that is this feature at work.
|
|
47
|
+
|
|
48
|
+
## Summary of New Capabilities
|
|
49
|
+
|
|
50
|
+
- `GET /guards` rows gain `loadBearing`, `criticalPath`, `loadBearingGap`,
|
|
51
|
+
`loadBearingSoaking`, `loadBearingAccepted`, and `acceptedFallbackReason`; the
|
|
52
|
+
summary and the capacity heartbeat gain `loadBearingGapKeys`,
|
|
53
|
+
`loadBearingSoakingKeys`, and `loadBearingAcceptedKeys`.
|
|
54
|
+
- `POST /guards/:key/accept-fallback` (dashboard-PIN-gated; `owner` + `reason`
|
|
55
|
+
required) records an owned per-machine acceptance; `DELETE` revokes it and
|
|
56
|
+
reopens the gap.
|
|
57
|
+
- The GuardPostureProbe raises a load-bearing gap on its own bounded, per-episode
|
|
58
|
+
attention topic, separate from the acute load-shed track (no masking).
|
|
59
|
+
- Per-machine by design: accepting a risk on one machine never silences a peer's
|
|
60
|
+
gap; a peer's critical-path label is looked up from the local, fleet-uniform
|
|
61
|
+
manifest.
|
|
62
|
+
|
|
63
|
+
## Evidence
|
|
64
|
+
|
|
65
|
+
Before: on an agent where a load-bearing feature ships dark (e.g. the inbound-message
|
|
66
|
+
queue with `enabled:false`), `GET /guards` reported it identically to any optional
|
|
67
|
+
dark feature — an `off:dark-default` row with no signal that a critical path depended
|
|
68
|
+
on it, so nothing ever surfaced the exposure (the postmortem's silent-loss shape).
|
|
69
|
+
|
|
70
|
+
After (verified over the real HTTP route + real disk in the Tier-3 e2e): the same
|
|
71
|
+
dark guard's `/guards` row now carries `loadBearing:true`, a `criticalPath` string,
|
|
72
|
+
and `loadBearingGap:true`, and the summary lists it under `loadBearingGapKeys`.
|
|
73
|
+
`POST /guards/:key/accept-fallback` with a valid PIN + owner + reason flips the row to
|
|
74
|
+
`loadBearingAccepted` (gap cleared, reason visible); `DELETE` reopens the gap, and both
|
|
75
|
+
survive a fresh-server "reboot" reading the same durable per-machine record. The
|
|
76
|
+
masking regression drives the REAL `createAttentionItem` funnel and asserts an acute
|
|
77
|
+
off-runtime-divergent guard surfaces while a load-bearing-gap episode has been open —
|
|
78
|
+
and an inert-lever test proves the funnel dedups by item id, so the separate episode
|
|
79
|
+
track (not a healthKey change) is what carries the fix. `npx tsc --noEmit` clean and
|
|
80
|
+
`npm run lint` exit 0.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Thirteen background LLM call sites that were quietly running on the default
|
|
9
|
+
framework (Claude) now route off-Claude with their peers. The framework router
|
|
10
|
+
picks a provider by a component's category; these thirteen were absent from the
|
|
11
|
+
category map, so they resolved to `other` and fell back to Claude — burning
|
|
12
|
+
Anthropic quota while near-identical siblings routed to the cheaper, less
|
|
13
|
+
rate-limited off-Claude providers.
|
|
14
|
+
|
|
15
|
+
They were the pinned `WIRING_EXCLUSIONS` backlog explicitly deferred from the
|
|
16
|
+
token-audit PR ("each needs its own deliberate routing decision"). This is that
|
|
17
|
+
decision: each is registered by function — `InputClassifier`,
|
|
18
|
+
`SessionSummarySentinel`, `TelegramAdapter` (sentinel; `TelegramAdapter` also fixes
|
|
19
|
+
an asymmetry versus the already-registered `SlackAdapter` alert-suppression judge);
|
|
20
|
+
`ResumeValidator` (gate); and `Usher`, `TopicIntentExtractor`, `PreCompactionFlush`,
|
|
21
|
+
`TreeSynthesis`, `LLMConflictResolver`, `openConversationBrief`, `a2a-checkin`,
|
|
22
|
+
`correction-learning`, `mentor-stage-b` (reflector).
|
|
23
|
+
|
|
24
|
+
`WIRING_EXCLUSIONS` now holds only the five components that route via an explicit
|
|
25
|
+
`attribution.category` and are correctly map-unregistered. The existing wiring
|
|
26
|
+
ratchet remains the drift guard against future recurrence. Additive and fully
|
|
27
|
+
reversible; no new logic, no new decision authority.
|
|
28
|
+
|
|
29
|
+
## What to Tell Your User
|
|
30
|
+
|
|
31
|
+
Thirteen of my small background AI helpers — the ones that classify messages,
|
|
32
|
+
summarize sessions, extract facts before compaction, and similar housekeeping —
|
|
33
|
+
were quietly running on Claude instead of the cheaper providers the rest of my
|
|
34
|
+
background checks use. That was burning Claude subscription quota (the scarce,
|
|
35
|
+
rate-limited resource) on work that never needed it. They now route off Claude
|
|
36
|
+
like their peers, so more of your Claude quota stays available for the
|
|
37
|
+
conversations and heavy work where it matters. Nothing changes in what these
|
|
38
|
+
helpers do — only which provider quietly runs them.
|
|
39
|
+
|
|
40
|
+
## Summary of New Capabilities
|
|
41
|
+
|
|
42
|
+
None — no new API routes, config keys, or user-facing behavior. This is a
|
|
43
|
+
routing-map completion: 13 existing internal LLM call sites now resolve to their
|
|
44
|
+
proper category (`sentinel`/`gate`/`reflector`) so the existing
|
|
45
|
+
Provider-Fallback Default Policy routes them off Claude. Operators can still
|
|
46
|
+
override any of them per-agent via `sessions.componentFrameworks.overrides`.
|
|
47
|
+
|
|
48
|
+
## Evidence
|
|
49
|
+
|
|
50
|
+
Before: `GET /intelligence/routing` on a live agent showed these 13 components
|
|
51
|
+
absent from the known-components registry, and `categoryForComponent()` in the
|
|
52
|
+
deployed dist resolved each to `'other'` → the agent default framework (Claude).
|
|
53
|
+
Verified against the deployed code during the 2026-07-01 LLM Routing Registry
|
|
54
|
+
audit (docs/LLM-ROUTING-REGISTRY.md), not just the source branch — each of the
|
|
55
|
+
13 calls `.evaluate()` with an `attribution.component` that had no map entry and
|
|
56
|
+
no explicit `attribution.category`, while siblings like `SlackAdapter` (mapped)
|
|
57
|
+
routed off-Claude.
|
|
58
|
+
|
|
59
|
+
After: `categoryForComponent('InputClassifier')` → `'sentinel'` (and likewise
|
|
60
|
+
for all 13; `'TelegramAdapter'` now matches the already-mapped `SlackAdapter`).
|
|
61
|
+
The wiring ratchet (`tests/unit/llm-attribution-ratchet.test.ts`) proves both
|
|
62
|
+
directions over the real source tree: every literal `attribution.component` in
|
|
63
|
+
`src/` resolves to a registered category or a pinned explicit-category
|
|
64
|
+
exception, and every remaining exception genuinely resolves to `'other'`. The
|
|
65
|
+
router, integration, and e2e routing suites are green unchanged.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Side-Effects Review — G3 Dark-but-Load-Bearing Guard Classification
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `g3-dark-but-load-bearing-guards`
|
|
4
|
+
**Date:** `2026-07-01`
|
|
5
|
+
**Author:** Echo (autonomous)
|
|
6
|
+
**Spec:** `docs/specs/g3-dark-but-load-bearing-guards.md` (review-convergence 2026-07-02, 6 iterations, cross-model codex GPT-5.5; approved:true)
|
|
7
|
+
**Parent principle:** A Dark Feature Guards Nothing (STANDARDS-REGISTRY.md, ratified 2026-07-01 PR #1316)
|
|
8
|
+
**Second-pass reviewer:** not-required (Tier 2; observe-only classifier + one PIN-gated suppress route; no new gating/blocking decision, byte-identical `/guards` for a consumer ignoring the new fields)
|
|
9
|
+
|
|
10
|
+
## Summary of the change
|
|
11
|
+
|
|
12
|
+
The `/guards` inventory could not express "this dark feature is load-bearing" — a
|
|
13
|
+
feature that ships DARK but that a CRITICAL PATH depends on was indistinguishable
|
|
14
|
+
from a genuinely-optional dark feature. It sat quiet while the path it should guard
|
|
15
|
+
ran unguarded (the 2026-07-01 silent-loss postmortem's case study: operator message
|
|
16
|
+
delivery depended on dark guards, and nothing surfaced it).
|
|
17
|
+
|
|
18
|
+
G3 adds an optional `loadBearing`/`criticalPath`/`soakWindowDays`/`declaredLoadBearingAt`
|
|
19
|
+
manifest declaration and classifies a load-bearing guard in a silent-unguarded posture
|
|
20
|
+
into ONE of three states — `loadBearingGap` (loud, its OWN attention channel),
|
|
21
|
+
`loadBearingSoaking` (graduate arm, no attention item), `loadBearingAccepted` (owned,
|
|
22
|
+
PIN-authenticated operator acceptance). `criticalPath` travels on EVERY anomaly of a
|
|
23
|
+
load-bearing guard. Pure classifier, observe-only — it never gates.
|
|
24
|
+
|
|
25
|
+
### Files added
|
|
26
|
+
- `src/monitoring/guardAcceptedFallbacks.ts` — ALL disk I/O for the per-machine
|
|
27
|
+
operator-accept store (`state/guard-accepted-fallbacks.json`, keyed
|
|
28
|
+
`<machineId>:<guardKey>`). Keeps the classifier PURE: the caller reads/scopes
|
|
29
|
+
once and threads the map in. Missing/corrupt file ⇒ empty map (safe direction).
|
|
30
|
+
- Tests: `tests/unit/monitoring/guard-posture-loadbearing.test.ts`,
|
|
31
|
+
`tests/unit/monitoring/guard-posture-probe-loadbearing.test.ts`,
|
|
32
|
+
`tests/integration/guards-accept-fallback-route.test.ts`,
|
|
33
|
+
`tests/e2e/guards-loadbearing-lifecycle.test.ts`,
|
|
34
|
+
`tests/unit/PostUpdateMigrator-guardLoadBearingSection.test.ts`.
|
|
35
|
+
|
|
36
|
+
### Files modified
|
|
37
|
+
- `src/monitoring/guardManifest.ts` — 4 optional fields; the two NEW manifest lints
|
|
38
|
+
(`validateGuardManifest`); the curated initial load-bearing set (inboundQueue +
|
|
39
|
+
strandedTopicSentinel, both operator-message-delivery critical-path, 30-day soak
|
|
40
|
+
window declared 2026-07-01).
|
|
41
|
+
- `src/monitoring/guardPostureView.ts` — the SIX new row fields + three-state
|
|
42
|
+
precedence (accepted → soaking-within-window → gap) on a threaded `now`; both
|
|
43
|
+
`deriveGuardRow` and `buildGuardInventory` stay PURE (accept map threaded via
|
|
44
|
+
`DeriveInput`/`opts`); `ROW_FIELD_ALLOWLIST` extended with all six by name; summary
|
|
45
|
+
+ heartbeat gain the three key-lists.
|
|
46
|
+
- `src/monitoring/probes/GuardPostureProbe.ts` — the SEPARATE `load-bearing-gap`
|
|
47
|
+
episode track (own `openEpisodeId`/`episodeEmitted`/anomalies + item-id namespace
|
|
48
|
+
`guard-posture-loadbearing:ep-N`); acute close condition tests `currentAcute` (not
|
|
49
|
+
the shared set); `load-bearing-gap` class pushed in both evaluate paths; criticalPath
|
|
50
|
+
on all load-bearing anomalies; `alertLoadBearingGaps` sub-flag (default-on).
|
|
51
|
+
- `src/core/types.ts` — the 3 optional key-list fields on `GuardPostureSummary`.
|
|
52
|
+
- `src/server/routes.ts` — GET /guards threads the accept map + now; the PIN-gated
|
|
53
|
+
`POST`/`DELETE /guards/:key/accept-fallback` route (owner+reason required).
|
|
54
|
+
- `src/commands/server.ts` — all 3 `buildGuardInventory` call sites thread the accept
|
|
55
|
+
map + now (route, probe `getLocalPosture`, heartbeat `selfGuardPosture`); the probe's
|
|
56
|
+
`alertLoadBearingGaps` sub-flag resolved from config (default true).
|
|
57
|
+
- `src/scaffold/templates.ts` + `src/core/PostUpdateMigrator.ts` — Agent Awareness +
|
|
58
|
+
Migration Parity (content-sniffed on `loadBearingGap`).
|
|
59
|
+
- `src/data/state-coherence-registry.json` — the new `guard-accepted-fallbacks`
|
|
60
|
+
store category + a `resolution`-class retention policy.
|
|
61
|
+
|
|
62
|
+
## Decision-point inventory
|
|
63
|
+
|
|
64
|
+
- **Added — one PIN-gated route** (`POST/DELETE /guards/:key/accept-fallback`): the
|
|
65
|
+
ONLY new decision surface. It SUPPRESSES a safety SIGNAL for a named operator; it
|
|
66
|
+
never allows/blocks an action. Gated by `checkMandatePin` (Know Your Principal — a
|
|
67
|
+
Bearer token cannot accept a safety risk); `owner` AND `reason` both REQUIRED (400
|
|
68
|
+
otherwise); a non-load-bearing key is 404.
|
|
69
|
+
- **Added — classifier flags**: `deriveGuardRow` sets orthogonal FLAGS; the nine
|
|
70
|
+
`GuardEffectiveState` values + the normative precedence table are UNCHANGED. No new
|
|
71
|
+
effective state, so the nine-state contract cannot regress.
|
|
72
|
+
- **Added — probe anomaly class** `load-bearing-gap` on its OWN episode track.
|
|
73
|
+
Observe-only: the probe only ever calls the attention funnel; never gates.
|
|
74
|
+
- No agent-to-user message-flow gate is added.
|
|
75
|
+
|
|
76
|
+
## Roll-up across the seven review dimensions
|
|
77
|
+
|
|
78
|
+
1. **Over-block**: none. The classifier adds flags; `/guards` is byte-identical for a
|
|
79
|
+
consumer ignoring the new fields. The accept route only suppresses a signal — it
|
|
80
|
+
loosens nothing and blocks nothing. The alert has a rollback sub-flag
|
|
81
|
+
(`alertLoadBearingGaps:false`) that keeps the classification.
|
|
82
|
+
2. **Under-block**: none. No gate was loosened. A load-bearing dark guard is now MORE
|
|
83
|
+
visible, not less. Soaking only defers the alert within a bounded, code-constant
|
|
84
|
+
window; a typo'd `declaredLoadBearingAt` falls to the LOUD gap (safe direction).
|
|
85
|
+
3. **Masking**: the round-3/round-4 fix. `load-bearing-gap` is a designed long-lived
|
|
86
|
+
anomaly; running it on a SEPARATE episode track (its own item-id namespace) means a
|
|
87
|
+
week-open gap can never hold the acute track's episode open. The regression test
|
|
88
|
+
drives the REAL `createAttentionItem` funnel and asserts an acute off-runtime-divergent
|
|
89
|
+
surfaces while the lb episode is open; the inert-lever test proves the funnel dedups
|
|
90
|
+
by ID, so a healthKey-only split would leave masking intact.
|
|
91
|
+
4. **Multi-machine**: classification is per-machine (an accept on machine A never
|
|
92
|
+
silences a peer's gap — proven by test). Manifest fields are fleet-uniform constants;
|
|
93
|
+
a peer's criticalPath is looked up from the local manifest. The heartbeat carries the
|
|
94
|
+
three key-lists (Array.isArray-guarded for an un-upgraded peer). The 3rd-site fix: the
|
|
95
|
+
heartbeat compute threads the local accept map, so an accepted guard never ships to
|
|
96
|
+
peers as a false gap.
|
|
97
|
+
5. **Purity / I/O layering**: `deriveGuardRow` AND `buildGuardInventory` gain no `fs`.
|
|
98
|
+
The caller reads the accept file ONCE per inventory build and threads the scoped map;
|
|
99
|
+
the new `guardAcceptedFallbacks.ts` module owns all disk I/O. One accept-file read per
|
|
100
|
+
inventory build, never per guard.
|
|
101
|
+
6. **Bounded Notification Surface**: each track surfaces as ONE bounded, coalesced,
|
|
102
|
+
per-episode class-level forum topic (two class-level topics max, never per-guard).
|
|
103
|
+
Soaking pushes NO attention item.
|
|
104
|
+
7. **Migration Parity / Agent Awareness**: the manifest ships as code (reaches existing
|
|
105
|
+
agents automatically); the CLAUDE.md vocabulary + accept route reach existing agents
|
|
106
|
+
via a content-sniffed `migrateClaudeMd` addendum; new agents get it in `generateClaudeMd`.
|
|
107
|
+
Migration idempotency + parity covered by a dedicated test.
|
|
108
|
+
|
|
109
|
+
## Rollout / rollback
|
|
110
|
+
|
|
111
|
+
Classification + route + separate-track wiring ship ALWAYS-ON as pure observability
|
|
112
|
+
(additive, never gating). The probe ALERT on `load-bearing-gap` rides the existing
|
|
113
|
+
GuardPostureProbe enablement + the `monitoring.guardPostureProbe.alertLoadBearingGaps`
|
|
114
|
+
sub-flag (default-on; soak windows are code constants). Rollback = set the sub-flag
|
|
115
|
+
false; `/guards` keeps the classification. The accept store is a per-machine JSON file;
|
|
116
|
+
DELETE scopes to the operator record only, never the manifest soak constant.
|
|
117
|
+
|
|
118
|
+
## Test evidence
|
|
119
|
+
|
|
120
|
+
`npx tsc --noEmit` clean; full `npm run lint` exit 0. New tests green: 21 unit
|
|
121
|
+
(classification/lints/allowlist/key-lists/purity), 9 probe-track unit (separate track,
|
|
122
|
+
masking regression against the real funnel, inert-lever guard, soaking-silent,
|
|
123
|
+
criticalPath, heartbeat array-guard, per-machine independence, alert rollback), 7
|
|
124
|
+
integration (PIN gate, owner-required, accept clears gap, DELETE-revoke survives reboot),
|
|
125
|
+
3 e2e (feature-alive: six fields + accept route mounted). Existing guard/posture suites
|
|
126
|
+
(monitoring 260, guard integration+e2e 51, server+migrator 27, parity+discoverability 170)
|
|
127
|
+
all pass.
|
|
128
|
+
|
|
129
|
+
## Post-review fixes (2026-07-02)
|
|
130
|
+
|
|
131
|
+
- Rebased onto JKHeadley/main after PR #1317 (silent-loss fix) merged. #1317's
|
|
132
|
+
rejected-enumeration + wiring gate on `routes.ts`/`server.ts`/`types.ts` and G3's
|
|
133
|
+
additive edits compose cleanly (adjacent, non-overlapping edits; tsc + `npm run lint`
|
|
134
|
+
clean post-rebase; the guard/posture suite re-run green).
|
|
135
|
+
- CI's full sharded suite caught two mechanical guard-tracking failures the loaded-box
|
|
136
|
+
local run (exit 144) missed. Neither weakens a guard:
|
|
137
|
+
1. `no-silent-fallbacks` (492 > baseline 491): `readAcceptedFallbacks`'s
|
|
138
|
+
missing/corrupt-file catch in `guardAcceptedFallbacks.ts` is annotated
|
|
139
|
+
`@silent-fallback-ok` — an empty map is the SAFE direction (no phantom accept can
|
|
140
|
+
suppress a real load-bearing gap). Threshold NOT bumped; count back to 491.
|
|
141
|
+
2. `feature-delivery-completeness`: the migrator's new `loadBearingGap` content-sniff
|
|
142
|
+
section is registered in `legacyMigratorSections` (migrator-only behavioral
|
|
143
|
+
awareness, also emitted inline by `generateClaudeMd` so a fresh init self-matches).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Side-Effects Review — Register 13 uncategorized LLM components
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `llm-routing-register-uncategorized-components`
|
|
4
|
+
**Date:** `2026-07-01`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Adds 13 previously-unregistered LLM call-site component names to `COMPONENT_CATEGORY`
|
|
11
|
+
in `src/core/componentCategories.ts`, each tagged `sentinel` / `gate` / `reflector`
|
|
12
|
+
by function, so the framework router resolves them to a real category instead of
|
|
13
|
+
`other` (which falls back to the agent default framework, Claude). Correspondingly
|
|
14
|
+
removes those 13 names from the `WIRING_EXCLUSIONS` pinned backlog in
|
|
15
|
+
`tests/unit/llm-attribution-ratchet.test.ts`, leaving only the 5 components that
|
|
16
|
+
route via an explicit `attribution.category` (so they correctly stay map-unregistered).
|
|
17
|
+
Files touched: `src/core/componentCategories.ts`, `tests/unit/llm-attribution-ratchet.test.ts`.
|
|
18
|
+
The change interacts with one decision point — the router's category resolution
|
|
19
|
+
(`categoryForComponent`) — but only feeds it more data; it adds no branching logic.
|
|
20
|
+
|
|
21
|
+
## Decision-point inventory
|
|
22
|
+
|
|
23
|
+
- `categoryForComponent` (src/core/componentCategories.ts) — **pass-through** — unchanged
|
|
24
|
+
function; this change only adds rows to the map it reads. No control-flow edit.
|
|
25
|
+
- `IntelligenceRouter.resolveFramework` (per-component framework routing) — **pass-through** —
|
|
26
|
+
consumes the category; unchanged. The 13 components now resolve to their category's
|
|
27
|
+
configured framework instead of the default, which is the intended effect.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. Over-block
|
|
32
|
+
|
|
33
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
34
|
+
|
|
35
|
+
No block/allow surface — over-block not applicable. This is a routing-map data change,
|
|
36
|
+
not a gate. It changes WHICH provider runs a call, never WHETHER the call is allowed.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. Under-block
|
|
41
|
+
|
|
42
|
+
**What failure modes does this still miss?**
|
|
43
|
+
|
|
44
|
+
No block/allow surface — under-block not applicable. The change cannot make any gate
|
|
45
|
+
more permissive; gate *authority* is untouched. (The one `gate`-category addition,
|
|
46
|
+
ResumeValidator, keeps its existing behavior; only its provider changes.)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. Wrong-provider / routing correctness
|
|
51
|
+
|
|
52
|
+
**Could a component now route to a provider that can't serve it correctly?**
|
|
53
|
+
|
|
54
|
+
Low risk. All 13 join categories (`sentinel`/`gate`/`reflector`) that the
|
|
55
|
+
Provider-Fallback Default Policy already routes off-Claude for dozens of live
|
|
56
|
+
components — the target providers (codex-cli → pi-cli → gemini-cli, Claude last)
|
|
57
|
+
are production-exercised. A rate-limited or missing framework degrades via the
|
|
58
|
+
existing per-framework circuit breaker + fallback chain (unchanged). No component
|
|
59
|
+
routes to a provider class not already in use for its category.
|
|
60
|
+
|
|
61
|
+
The one behavioral nuance: components that make *nuanced/critical* judgments
|
|
62
|
+
(e.g. LLMConflictResolver resolving divergent multi-machine state) now run on a
|
|
63
|
+
non-Claude reasoning-capable model (gpt-5.5 via codex) rather than Claude. This is
|
|
64
|
+
aligned with the operator directive to prefer subsidized non-Claude subscriptions,
|
|
65
|
+
and gpt-5.5 is reasoning-capable. A later nature-based routing pass (operator-reviewed)
|
|
66
|
+
will refine per-task model tiers; this change does not lock that in.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 4. Reversibility / rollback
|
|
71
|
+
|
|
72
|
+
Fully reversible: remove the 13 rows from `COMPONENT_CATEGORY` (and restore them to
|
|
73
|
+
`WIRING_EXCLUSIONS`) and routing returns to the prior state. No migration, no state
|
|
74
|
+
schema change, no persisted data. An operator can also override any single component
|
|
75
|
+
per-agent via `sessions.componentFrameworks.overrides` without touching this map.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 5. Blast radius
|
|
80
|
+
|
|
81
|
+
Fleet-wide once shipped (it's a core map), but strictly additive and category-consistent.
|
|
82
|
+
No new code paths execute; the router simply finds a category where it previously found
|
|
83
|
+
none. Existing tests cover it: the wiring ratchet (`llm-attribution-ratchet.test.ts`)
|
|
84
|
+
proves every live `.evaluate()` component now resolves, `intelligence-router.test.ts` and
|
|
85
|
+
the integration/e2e routing suites remain green. Signal-vs-authority: N/A — no detector
|
|
86
|
+
and no authority is added or modified; this is a data-map completion.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 6. Test coverage
|
|
91
|
+
|
|
92
|
+
- `tests/unit/llm-attribution-ratchet.test.ts` — the drift guard; asserts every literal
|
|
93
|
+
`attribution.component` in `src/` resolves to a registered category or a pinned
|
|
94
|
+
(explicit-category) exception, AND that every pinned exception still resolves to `other`.
|
|
95
|
+
Both sides green after the change.
|
|
96
|
+
- `tests/unit/intelligence-router.test.ts`, `tests/unit/standards-coverage-component-category.test.ts`,
|
|
97
|
+
`tests/integration/intelligence-routing-routes.test.ts`,
|
|
98
|
+
`tests/integration/provider-fallback-default-routing.test.ts` — all green.
|
|
99
|
+
- No NEW test added: the existing ratchet already IS the structural guard for this
|
|
100
|
+
invariant (adding a duplicate would be noise).
|