instar 1.3.751 → 1.3.753
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 +76 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +18 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/MoveIntentClassifier.d.ts +135 -0
- package/dist/core/MoveIntentClassifier.d.ts.map +1 -0
- package/dist/core/MoveIntentClassifier.js +284 -0
- package/dist/core/MoveIntentClassifier.js.map +1 -0
- package/dist/core/NicknameCommand.d.ts +23 -17
- package/dist/core/NicknameCommand.d.ts.map +1 -1
- package/dist/core/NicknameCommand.js +20 -65
- package/dist/core/NicknameCommand.js.map +1 -1
- package/dist/core/componentCategories.d.ts.map +1 -1
- package/dist/core/componentCategories.js +5 -0
- package/dist/core/componentCategories.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/frameworkSessionLaunch.js +1 -1
- package/dist/core/frameworkSessionLaunch.js.map +1 -1
- package/dist/core/machineCoherenceManifest.d.ts.map +1 -1
- package/dist/core/machineCoherenceManifest.js +1 -0
- package/dist/core/machineCoherenceManifest.js.map +1 -1
- package/dist/core/models.d.ts +1 -1
- package/dist/core/models.js +1 -1
- package/dist/data/llmBenchCoverage.d.ts.map +1 -1
- package/dist/data/llmBenchCoverage.js +6 -0
- package/dist/data/llmBenchCoverage.js.map +1 -1
- package/dist/providers/adapters/anthropic-headless/models.js +1 -1
- package/dist/providers/adapters/gemini-cli/models.d.ts +6 -5
- package/dist/providers/adapters/gemini-cli/models.d.ts.map +1 -1
- package/dist/providers/adapters/gemini-cli/models.js +7 -5
- package/dist/providers/adapters/gemini-cli/models.js.map +1 -1
- package/package.json +1 -1
- package/scripts/model-registry-freshness.manifest.json +5 -21
- package/src/data/builtin-manifest.json +2 -2
- package/src/data/llmBenchCoverage.ts +7 -0
- package/upgrades/1.3.752.md +27 -0
- package/upgrades/1.3.753.md +44 -0
- package/upgrades/side-effects/model-registry-current-pins.md +81 -0
- package/upgrades/side-effects/nickname-move-intent-llm-rebuild.md +160 -0
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
* `~/.gemini` OAuth):
|
|
9
9
|
* - `gemini -m gemini-2.5-flash "<prompt>"` → clean stdout, exit 0. This
|
|
10
10
|
* is the verified-working default and the `fast`/`balanced` tier.
|
|
11
|
-
* - `gemini-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* in sync with
|
|
11
|
+
* - `gemini-3.1-pro-preview` is the capable/heavy tier (current top usable Pro,
|
|
12
|
+
* verified reachable 2026-07-03 via the gemini CLI / OpenRouter / paid key).
|
|
13
|
+
* `gemini-2.5-pro` remains a recognized model id — still spawnable and a
|
|
14
|
+
* capacity fallback — kept in sync with the model-registry freshness manifest
|
|
15
|
+
* and `resolveModelForFramework('gemini-cli', …)`.
|
|
15
16
|
*
|
|
16
17
|
* Drift risk: model availability changes per Gemini version. This map is a
|
|
17
18
|
* Rule-3 surface; the authoritative-name check belongs in a dedicated canary
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
export const KNOWN_GEMINI_MODELS = [
|
|
21
22
|
'gemini-2.5-flash',
|
|
22
23
|
'gemini-2.5-pro',
|
|
24
|
+
'gemini-3.1-pro-preview',
|
|
23
25
|
];
|
|
24
26
|
export function isKnownGeminiModel(model) {
|
|
25
27
|
return typeof model === 'string' && KNOWN_GEMINI_MODELS.includes(model);
|
|
@@ -30,7 +32,7 @@ const TIER_TO_MODEL = {
|
|
|
30
32
|
// medium — balanced; same flash model (verified one-shot path).
|
|
31
33
|
balanced: 'gemini-2.5-flash',
|
|
32
34
|
// heavy — frontier; the pro tier for hard problems + main chat.
|
|
33
|
-
capable: 'gemini-
|
|
35
|
+
capable: 'gemini-3.1-pro-preview',
|
|
34
36
|
};
|
|
35
37
|
/** The default model when no tier or id is supplied. */
|
|
36
38
|
export const GEMINI_DEFAULT_MODEL = 'gemini-2.5-flash';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/providers/adapters/gemini-cli/models.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/providers/adapters/gemini-cli/models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,kBAAkB;IAClB,gBAAgB;IAChB,wBAAwB;CAChB,CAAC;AAIX,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,mBAAyC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,aAAa,GAAwC;IACzD,sDAAsD;IACtD,IAAI,EAAE,kBAAkB;IACxB,gEAAgE;IAChE,QAAQ,EAAE,kBAAkB;IAC5B,gEAAgE;IAChE,OAAO,EAAE,wBAAwB;CAClC,CAAC;AAEF,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAqB,kBAAkB,CAAC;AAEzE;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAA2C;IAC7E,IAAI,CAAC,WAAW;QAAE,OAAO,oBAAoB,CAAC;IAC9C,IAAI,WAAW,IAAI,aAAa,EAAE,CAAC;QACjC,OAAO,aAAa,CAAC,WAAwB,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"gemini-cli": {
|
|
24
24
|
"accessMethod": "gemini -m <model> (Homebrew formula, OAuth)",
|
|
25
25
|
"status": "alive-but-deprecated-formula",
|
|
26
|
-
"note": "Homebrew gemini-cli formula DEPRECATED (upstream-unsupported, disabled 2026-12-18). CLI v0.25.2 still runs.
|
|
26
|
+
"note": "Homebrew gemini-cli formula DEPRECATED (upstream-unsupported, disabled 2026-12-18). CLI v0.25.2 still runs. capable tier now pinned to gemini-3.1-pro-preview (verified reachable 2026-07-03 via the gemini CLI / OpenRouter / paid Gemini key); gemini-2.5-pro remains a recognized/spawnable model + capacity fallback. Migrate off the deprecated formula (npm @google/gemini-cli, or an OpenRouter/pi door)."
|
|
27
27
|
},
|
|
28
28
|
"pi-cli": {
|
|
29
29
|
"accessMethod": "pi --model <provider>/<id> (multi-provider: openai-codex, openrouter, ...)",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"claude-fable-5"
|
|
39
39
|
],
|
|
40
40
|
"anthropic-headless": [
|
|
41
|
-
"claude-opus-4-
|
|
41
|
+
"claude-opus-4-8",
|
|
42
42
|
"claude-sonnet-4-6",
|
|
43
43
|
"claude-haiku-4-5"
|
|
44
44
|
],
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"gpt-5.5"
|
|
47
47
|
],
|
|
48
48
|
"gemini-cli": [
|
|
49
|
-
"gemini-
|
|
49
|
+
"gemini-3.1-pro-preview"
|
|
50
50
|
]
|
|
51
51
|
},
|
|
52
52
|
"pins": [
|
|
@@ -83,22 +83,6 @@
|
|
|
83
83
|
"note": "DEFAULT_TIER_ESCALATION.frameworks['claude-code'] default + escalated ids."
|
|
84
84
|
}
|
|
85
85
|
],
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
"door": "gemini-cli",
|
|
89
|
-
"pin": "gemini-capable-tier",
|
|
90
|
-
"currentId": "gemini-2.5-pro",
|
|
91
|
-
"suspectedFrontier": "gemini-3-pro-preview",
|
|
92
|
-
"evidence": "gemini CLI v0.25.2 accepts gemini-3-pro-preview / gemini-3-flash-preview (in gemini-cli-core known-models); operator referenced 'Gemini 3-class'. Homebrew formula also deprecated (disabled 2026-12-18).",
|
|
93
|
-
"note": "OPERATOR TO CONFIRM exact frontier id before the pin+allowlist are updated. Also present at src/core/frameworkSessionLaunch.ts, src/commands/route.ts (KNOWN_MODELS), src/server/routes.ts."
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"door": "codex-cli",
|
|
97
|
-
"pin": "codex-capable-tier",
|
|
98
|
-
"currentId": "gpt-5.5",
|
|
99
|
-
"suspectedFrontier": "gpt-5.6 (Sol) — UNVERIFIED",
|
|
100
|
-
"evidence": "codex CLI NOT installed on this machine, so newer accepted ids could NOT be probed. Operator referenced 'GPT-5.6 Sol'.",
|
|
101
|
-
"note": "OPERATOR TO CONFIRM. Cannot verify from a live probe (codex door not installed)."
|
|
102
|
-
}
|
|
103
|
-
]
|
|
86
|
+
"$flaggedStaleNote": "Both prior flagged pins RESOLVED (operator-confirmed 2026-07-03): gemini capable swapped gemini-2.5-pro -> gemini-3.1-pro-preview (pin + allowlist updated in the same change); codex capable stays gpt-5.5 (GA flagship — gpt-5.6-sol is preview-only/gov-gated/unreachable, NOT pinned). Nothing pending confirmation.",
|
|
87
|
+
"flaggedStale": []
|
|
104
88
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-04T06:27:29.789Z",
|
|
5
|
+
"instarVersion": "1.3.753",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -48,6 +48,10 @@ export const LLM_BENCH_COVERAGE: Readonly<Record<string, BenchCoverage>> = {
|
|
|
48
48
|
exempt:
|
|
49
49
|
'judges a FIXED known-answer canary probe — the canary is its own benchmark; a bench task would re-test the same constant',
|
|
50
50
|
},
|
|
51
|
+
MoveIntentClassifier: {
|
|
52
|
+
exempt:
|
|
53
|
+
'ships its OWN dedicated discrimination benchmark — tests/unit/move-intent-discrimination.test.ts, a committed command-vs-discussion corpus run deterministically in CI PLUS an opt-in INSTAR_LIVE_MOVE_INTENT=1 real-model accuracy benchmark (the graduation gate before dryRun:false). A generic bench-harness task would re-test the same judgment less precisely (same rationale as InteractivePoolCanaryJudge: the co-located benchmark IS the benchmark). Spec: docs/specs/nickname-move-intent-llm-rebuild.md §Tests.',
|
|
54
|
+
},
|
|
51
55
|
|
|
52
56
|
// ── Covered by Wave 2 (authored 2026-07-02; tasks-wave2/ in the bench harness) ──
|
|
53
57
|
InputGuard: { task: 'input-guard-coherence' },
|
|
@@ -169,6 +173,7 @@ export const LLM_UNTRUSTED_INPUT: Readonly<Record<string, UntrustedInputFlag>> =
|
|
|
169
173
|
WarrantsReplyGate: true,
|
|
170
174
|
UnjustifiedStopGate: true,
|
|
171
175
|
MessagingToneGate: true, // reviews a draft that routinely quotes untrusted user/tool content
|
|
176
|
+
MoveIntentClassifier: true, // classifies an untrusted inbound user message + recent conversation context
|
|
172
177
|
CoherenceReviewer: true,
|
|
173
178
|
LLMSanitizer: true, // definitionally judges untrusted inbound content
|
|
174
179
|
OverrideDetector: true,
|
|
@@ -331,6 +336,7 @@ export const LLM_JUDGES_CLAIMS: Readonly<Record<string, JudgesClaimsFlag>> = {
|
|
|
331
336
|
IntegrationGate: false, // delegates to JobReflector.reflect(), no own callsite
|
|
332
337
|
ExternalOperationGate: false, // classifies operation mutability/reversibility, not a completion claim
|
|
333
338
|
WarrantsReplyGate: false, // "should I reply?" — not a completion/health claim
|
|
339
|
+
MoveIntentClassifier: false, // classifies a USER's move/pin intent over a message, not an agent/session claim of completion/health/credit
|
|
334
340
|
CoherenceGate: false, // no own callsite — flows through CoherenceReviewer
|
|
335
341
|
MessagingToneGate: false, // reviews outbound tone/leaks
|
|
336
342
|
CoherenceReviewer: false, // reviews outbound coherence
|
|
@@ -423,6 +429,7 @@ export const LLM_PARSER_CONTRACT: Readonly<Record<string, ParserContractFlag>> =
|
|
|
423
429
|
MessageSentinel: { pending: 'contract-wave-2' }, // closed intent set (pause / emergency / normal)
|
|
424
430
|
LLMSanitizer: { pending: 'contract-wave-2' }, // parses a closed sanitize verdict/decision
|
|
425
431
|
WarrantsReplyGate: { pending: 'contract-wave-2' }, // closed should-reply yes/no verdict
|
|
432
|
+
MoveIntentClassifier: { pending: 'contract-wave-2' }, // parses a closed move-intent verdict (isCommand + intent enum + targetNickname enum + confidence)
|
|
426
433
|
InputGuard: { pending: 'contract-wave-2' }, // closed input-coherence verdict
|
|
427
434
|
StallTriageNurse: { pending: 'contract-wave-2' }, // closed stall-triage diagnosis label
|
|
428
435
|
CommitmentSentinel: { pending: 'contract-wave-2' }, // closed commitment-detected verdict + structured envelope
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Corrected the stale "most capable" model-tier pins in the internal routing registry to the current, live-verified model IDs, and marked the model-registry freshness guard's two flagged items as resolved:
|
|
9
|
+
|
|
10
|
+
- **Gemini capable tier:** `gemini-2.5-pro` → `gemini-3.1-pro-preview` (the current top usable Gemini Pro; verified reachable via the Gemini CLI, OpenRouter, and a paid Gemini key). `gemini-2.5-pro` stays a recognized/spawnable model and a capacity fallback.
|
|
11
|
+
- **Claude Opus tier:** reconciled to `claude-opus-4-8` across both internal maps that had drifted apart (`src/core/models.ts` and the anthropic-headless adapter) — matching the running default and `ModelTierEscalation`.
|
|
12
|
+
- **OpenAI/Codex capable tier:** left unchanged at `gpt-5.5` (the GA flagship). The preview-only `gpt-5.6-sol` is intentionally not pinned.
|
|
13
|
+
- **Freshness manifest + routing doc:** the frontier allowlist now matches the corrected pins, the `flaggedStale` block is emptied (both prior pending items resolved), and `docs/LLM-ROUTING-REGISTRY.md` (capable row, Opus caveat, freshness note) is updated. The freshness lint now passes cleanly in both report and strict mode.
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
Your agent's heavy/"capable" internal work — spec review, cross-model review, and heavy-work model escalation — now points at current models (Gemini 3.1 Pro, Claude Opus 4.8) instead of older IDs that had quietly gone out of date. Nothing about how you interact with your agent changes; it just uses better-current models for the demanding internal jobs, and the built-in freshness check that watches for this kind of drift is now green.
|
|
18
|
+
|
|
19
|
+
## Summary of New Capabilities
|
|
20
|
+
|
|
21
|
+
No new capability or API. This is a maintenance correction of model-ID pins plus the matching freshness-manifest/doc updates. The model-registry freshness guard (report-only) reports zero findings after the change.
|
|
22
|
+
|
|
23
|
+
## Evidence
|
|
24
|
+
|
|
25
|
+
- `scripts/lint-model-registry-freshness.mjs` passes with zero findings and zero warnings in both report and strict mode after the change (all four pins drift-OK and in-allowlist; staleness OK).
|
|
26
|
+
- `tsc --noEmit` clean.
|
|
27
|
+
- Affected unit suites green: `geminiCapacityPolicy`, `gemini-cli-adapter`, `crossModelReviewer-piece3`, `model-registry-freshness` (incl. the shipped-manifest self-consistency test), `Models`, `routing-registry-freshness`, `frameworkSessionLaunch`, `modelTierEscalation-resolver` (185 tests total across the touched paths).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The "move/run/pin this on `<machine-nickname>`" recognizer — the thing that decides whether a
|
|
9
|
+
mid-conversation message is a command to move the session to another machine — was rebuilt from a keyword
|
|
10
|
+
verb-list into an LLM classifier (`src/core/MoveIntentClassifier.ts`). The old code (`TRANSFER_VERBS =
|
|
11
|
+
[move, transfer, run, continue, resume, keep, …]` × a preposition × a known nickname) hijacked the
|
|
12
|
+
operator's plain discussion **"keep the work on the laptop"** on 2026-07-03 — it matched the verb `keep`
|
|
13
|
+
and swallowed the message before the agent ever saw it. The new classifier infers move/pin intent from the
|
|
14
|
+
message **and** a bounded window of recent conversation, and constrains the target machine to a
|
|
15
|
+
known-nickname enum via **code-side validation of the model's emitted field** (never string-matching the
|
|
16
|
+
model's prose). It is the exemplar conversion under the constitutional standard *"Intelligence Infers,
|
|
17
|
+
Keywords Only Guard"* (parent: *"Intelligent Prompts — An LLM Gate Must Not String-Match"*). It **fails
|
|
18
|
+
open**: on any uncertainty — no provider, circuit-breaker open, timeout, unparseable/schema-violating
|
|
19
|
+
output, target-not-in-enum, or low confidence — the message passes straight through to the agent, never
|
|
20
|
+
hijacked. It ships **dev-gated dark on the fleet + dry-run first on a development agent** (it logs
|
|
21
|
+
would-hijack vs would-pass to `logs/move-intent.jsonl` and actuates nothing until a deliberate
|
|
22
|
+
`dryRun:false`). The keyword decision is removed from `NicknameCommand.ts` (only the `NicknameCommand` type,
|
|
23
|
+
consumed by the unchanged `TransferByNickname` planner, remains). Ships with a committed discrimination
|
|
24
|
+
corpus (command vs discussion both ways + guardrail + fail-open) — deterministic in CI plus an opt-in
|
|
25
|
+
`INSTAR_LIVE_MOVE_INTENT=1` real-model benchmark used as the graduation gate before actuation.
|
|
26
|
+
|
|
27
|
+
## What to Tell Your User
|
|
28
|
+
|
|
29
|
+
Nothing user-facing right now — this ships dark on the fleet and dry-run on a development agent, so no
|
|
30
|
+
behavior changes until it's deliberately graduated. If asked why the agent used to grab a message like
|
|
31
|
+
"keep the work on the laptop" as a machine-move command: that was a brittle keyword list, now replaced by
|
|
32
|
+
an LLM that judges intent from the message and its conversation context and errs toward *not* grabbing your
|
|
33
|
+
message when unsure. The move-by-nickname capability itself is a dev-only experimental feature (part of the
|
|
34
|
+
dark multi-machine session pool); only *how it recognizes your intent* changed.
|
|
35
|
+
|
|
36
|
+
## Summary of New Capabilities
|
|
37
|
+
|
|
38
|
+
- `src/core/MoveIntentClassifier.ts` — LLM-with-context move-intent recognizer (`classifyRelocationIntent`
|
|
39
|
+
+ `toNicknameCommand`); structured-output enum guardrail validated in code; fail-open on all uncertainty.
|
|
40
|
+
- Config `multiMachine.sessionPool.moveIntent` (`enabled` dev-gated; `dryRun:true`, `minConfidence:0.85`,
|
|
41
|
+
`timeoutMs:4000`, `contextWindowTurns:6`, `modelTier:'fast'`); registered in `DEV_GATED_FEATURES`.
|
|
42
|
+
- `logs/move-intent.jsonl` — machine-local dry-run soak log (LLM-engaged decisions only; 80-char preview).
|
|
43
|
+
- Committed discrimination corpus + opt-in real-model benchmark (`INSTAR_LIVE_MOVE_INTENT=1`), the
|
|
44
|
+
graduation gate before `dryRun:false`.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Side-Effects Review — Model-registry current-pins correction
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `model-registry-current-pins`
|
|
4
|
+
**Date:** 2026-07-03
|
|
5
|
+
**Author:** Echo (autonomous, instar-dev)
|
|
6
|
+
**Second-pass reviewer:** not-required (Tier 1 — value-only pin correction; no decision-point surface added)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Corrects stale "capable/frontier" model-tier pins to the current, live-verified IDs, and marks the model-registry freshness guard's two flagged-stale items as resolved. Concretely: the Gemini `capable` tier moves `gemini-2.5-pro` → `gemini-3.1-pro-preview` (`src/providers/adapters/gemini-cli/models.ts` TIER_TO_MODEL + the mirroring Gemini branch in `src/core/frameworkSessionLaunch.ts`); the Claude Opus tier is reconciled to `claude-opus-4-8` in the two disagreeing maps (`src/core/models.ts` ANTHROPIC_MODELS.opus and `src/providers/adapters/anthropic-headless/models.ts` API_MODEL_MAP.capable) — `ModelTierEscalation` already used `claude-opus-4-8`; the freshness manifest (`scripts/model-registry-freshness.manifest.json`) frontier allowlist is updated to match both new pins and its `flaggedStale` array is emptied; and the routing doc (`docs/LLM-ROUTING-REGISTRY.md`) capable row, opus caveat, and freshness note are updated. The Codex/OpenAI `capable` pin was already `gpt-5.5` (GA flagship) and is left unchanged — `gpt-5.6-sol` (preview-only/gov-gated) is intentionally NOT pinned. Three test files that asserted the old IDs are updated. No decision-point surface is added.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
This change touches no gate/block/filter/dispatch decision point. It edits the concrete model ID that abstract tier lookups return, and the metadata the (report-only, non-gating) freshness lint reads.
|
|
15
|
+
|
|
16
|
+
- Gemini `capable` tier pin — modify — `gemini-2.5-pro` → `gemini-3.1-pro-preview` (adapter map + frameworkSessionLaunch mirror).
|
|
17
|
+
- Claude Opus tier pin — modify — reconciled to `claude-opus-4-8` in `models.ts` + anthropic-headless adapter.
|
|
18
|
+
- Codex `capable` tier pin — pass-through — already `gpt-5.5`, unchanged.
|
|
19
|
+
- Freshness manifest allowlist + flaggedStale — modify — allowlist matched to new pins; flaggedStale emptied (both prior pending items resolved).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
No block/allow surface — over-block not applicable. The change edits model-ID values returned by tier lookups; it does not accept/reject any input.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. Under-block
|
|
30
|
+
|
|
31
|
+
No block/allow surface — under-block not applicable.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Level-of-abstraction fit
|
|
36
|
+
|
|
37
|
+
Correct layer. The tier→ID maps are the documented single source of truth for "which concrete model a tier resolves to" per provider door (the routing doc row #8 explicitly says "changing Claude models = edit this file, not config"). The freshness manifest is the intended single human-edit surface for the frontier allowlist. This change edits exactly those surfaces and nothing lower (no call-site hardcoding) or higher (no config/gate). The `KNOWN_GEMINI_MODELS` closed enum is the type domain for the Gemini tier map, so the new ID is added there (required for type-safety) rather than loosening the type.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 4. Signal vs authority compliance
|
|
42
|
+
|
|
43
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
44
|
+
|
|
45
|
+
- [x] No — this change has no block/allow surface.
|
|
46
|
+
|
|
47
|
+
It adds no authority. It changes which model ID a lookup returns. The freshness lint that reads the manifest remains a report-only signal (non-gating); this change resolves its flagged items rather than granting it any new authority.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 5. Interactions
|
|
52
|
+
|
|
53
|
+
- **Shadowing:** none. The pins are read the same way before and after.
|
|
54
|
+
- **crossModelReviewer coupling (intended):** `src/core/crossModelReviewer.ts` resolves its Gemini reviewer model via the shared `resolveCliModelFlag('capable')` (it has no independent hardcoded ID). So its Gemini reviewer now automatically uses `gemini-3.1-pro-preview` — which is precisely the freshness-guard's stated intent ("`gemini-2.5-pro` kept routing spec-review/converge work long after Gemini 3-class shipped"). The reviewer's *door* (framework = gemini-cli, tier = capable) is unchanged; only the concrete ID the capable tier resolves to is corrected. The reviewer's risk-item doc row (`docs/LLM-ROUTING-REGISTRY.md` line ~216) is intentionally left unchanged per the operator's scope boundary for this change — its model value follows the pin automatically.
|
|
55
|
+
- **Capacity fallback pool:** `KNOWN_GEMINI_MODELS` grows from 2 to 3 entries, so the Gemini capacity-exhaustion fallback picker now has `gemini-3.1-pro-preview` as an additional candidate; `gemini-2.5-pro` remains ordered ahead of it, so the default fallback-from-flash target is unchanged. The capacity/adapter/reviewer tests that encoded the 2-model world (and the old capable ID) are updated to match. The three unit tests (`crossModelReviewer-piece3`, `gemini-cli-adapter`, `geminiCapacityPolicy`) were updated in the original pin commit; a follow-up commit updates the two model-set-size assertions that were missed in `tests/integration/gemini-capacity-policy-integration.test.ts` and `tests/e2e/gemini-capacity-policy-lifecycle.test.ts` — the account-wide-defer spawn count moves 2→3 (flash→pro→`gemini-3.1-pro-preview` before the genuine account-wide defer) and the recorded last-exhausted stop-state model moves `gemini-2.5-pro`→`gemini-3.1-pro-preview` (the new final entry of the fallback iteration). No product-source change; these are pure test-expectation corrections tracking the model-set growth.
|
|
56
|
+
- **Spawn allowlist:** `src/server/routes.ts` uses `KNOWN_GEMINI_MODELS` as the accepted-model allowlist for explicitly spawning a Gemini session — keeping `gemini-2.5-pro` in the set (append, not replace) avoids rejecting a still-working model, and adds `gemini-3.1-pro-preview` as spawnable.
|
|
57
|
+
- **Double-fire / races:** none.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 6. External surfaces
|
|
62
|
+
|
|
63
|
+
Internal model selection only. Other agents/users/systems do not read these IDs directly. The change alters which model runs internal capable-tier work (spec review/converge, heavy-work escalation baseline, background headless calls) — a quality improvement, not a protocol/interface change. No timing or conversation-state dependence.
|
|
64
|
+
|
|
65
|
+
## 6b. Operator-surface quality
|
|
66
|
+
|
|
67
|
+
Not applicable — no operator surface (dashboard/CLI form/authorization surface) is touched by this change.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
72
|
+
|
|
73
|
+
Machine-local BY DESIGN, and identical on every machine. These pins are compiled source constants shipped in the release artifact (`dist/`), not per-machine state — so every machine running the same instar version resolves the same IDs. There is no per-machine divergence to replicate, no durable state to strand on topic transfer, and no generated URL involved. Not an agent-installed file (CLAUDE.md template / `.instar/config.json` default / hook), so the Migration Parity Standard imposes no migration: existing agents pick up the corrected pins on their normal version update, and no on-disk agent state carries the stale ID (the config default `DEFAULT_TIER_ESCALATION_CONFIG` and the CLAUDE.md template already reference `claude-opus-4-8`).
|
|
74
|
+
|
|
75
|
+
## 8. Rollback cost
|
|
76
|
+
|
|
77
|
+
Trivial. A plain `git revert` of the single commit restores the prior IDs, allowlist, and flaggedStale block; no data migration, no agent-state repair. The freshness manifest change is reversible in the same revert. Because the guard ships report-only (non-gating), even a mistaken pin cannot break CI on its own.
|
|
78
|
+
|
|
79
|
+
## Framework generality
|
|
80
|
+
|
|
81
|
+
This change is per-framework by construction: each provider door's `capable` pin is corrected independently in that door's own map (Gemini adapter, anthropic-headless adapter, Claude `models.ts`), and the touched `src/core/frameworkSessionLaunch.ts` edit is confined to the `gemini-cli` branch — mirroring the Gemini adapter's single source of truth — while the `claude-code`, `codex-cli`, and `pi-cli` branches are untouched. The abstraction (tier → concrete ID per framework) is preserved; no Claude-specific assumption is introduced, and codex-cli / gemini-cli remain correct (codex `capable` stays `gpt-5.5`; gemini `capable` becomes `gemini-3.1-pro-preview`). Standard: docs/STANDARDS-REGISTRY.md → "Framework-Agnostic — and Framework-Optimizing".
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Side-Effects Review — Move-Intent Recognizer: Keyword List → LLM-With-Context
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `nickname-move-intent-llm-rebuild`
|
|
4
|
+
**Date:** `2026-07-04`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `spec-converge round (codex-cli:gpt-5.5 + gemini-cli:gemini-2.5-pro + 4 internal reviewers)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Replaces the keyword verb-list decision in `NicknameCommand.recognizeNicknameCommand`
|
|
11
|
+
(`TRANSFER_VERBS = [move,…,run,continue,resume,keep]`) — which hijacked the operator's discussion message
|
|
12
|
+
"keep the work on the laptop" on 2026-07-03 — with an LLM classifier (`src/core/MoveIntentClassifier.ts`)
|
|
13
|
+
that infers "is this a move/pin command to <known machine>?" over the message + a bounded window of recent
|
|
14
|
+
conversation, guardrailed by code-side enum validation of the model-emitted `targetNickname`. Fail-OPEN on
|
|
15
|
+
any uncertainty (never hijack). Wired at `server.ts` `_tryNicknameRelocation` behind a dev-agent dark gate +
|
|
16
|
+
dry-run. The keyword decision is removed from `NicknameCommand.ts` (only the `NicknameCommand` type, consumed
|
|
17
|
+
by the unchanged `TransferByNickname` planner, remains). Files: `src/core/MoveIntentClassifier.ts` (new),
|
|
18
|
+
`src/core/NicknameCommand.ts`, `src/commands/server.ts`, `src/config/ConfigDefaults.ts`,
|
|
19
|
+
`src/core/devGatedFeatures.ts`, `src/core/componentCategories.ts`, `src/core/machineCoherenceManifest.ts`,
|
|
20
|
+
`docs/LLM-ROUTING-REGISTRY.md`, three test files + the wiring/line-map test updates.
|
|
21
|
+
|
|
22
|
+
## Decision-point inventory
|
|
23
|
+
|
|
24
|
+
- `_tryNicknameRelocation` (server.ts) — **modify** — the "is this a move command?" decision changes from
|
|
25
|
+
keyword-match to LLM classifier; the downstream `planTransferByNickname` actuator is pass-through (unchanged).
|
|
26
|
+
- `NicknameCommand.recognizeNicknameCommand` — **remove** — the keyword verb-list decision is deleted.
|
|
27
|
+
- `MoveIntentClassifier.classifyRelocationIntent` — **add** — the new LLM decision + code-side enum guardrail.
|
|
28
|
+
- `multiMachine.sessionPool.moveIntent` config — **add** — dev-gated dark, dry-run-first knobs.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 1. Over-block
|
|
33
|
+
|
|
34
|
+
The "block" surface here = hijacking a message (treating it as a move command, swallowing it). Over-block =
|
|
35
|
+
falsely hijacking discussion. This change's entire purpose is to REDUCE over-block: the classifier fails
|
|
36
|
+
open (only a high-confidence command with a resolved enum target hijacks), and ships dry-run so it hijacks
|
|
37
|
+
NOTHING during the soak. The residual over-block risk is a confidently-wrong model returning
|
|
38
|
+
`isCommand:true, confidence≥0.85` on discussion — bounded by the graduation-gate live benchmark (must pass
|
|
39
|
+
before `dryRun:false`) and the conservative threshold. Strictly less over-block than the keyword list, which
|
|
40
|
+
hijacked on any verb×preposition×nickname co-occurrence.
|
|
41
|
+
|
|
42
|
+
## 2. Under-block
|
|
43
|
+
|
|
44
|
+
Under-block = missing a genuine move command (it passes through to the agent). By design this is the SAFE
|
|
45
|
+
direction (fail-open). Known misses: (a) a purely deictic target with no nickname anywhere in the window
|
|
46
|
+
("send it to my desktop") — the prefilter skips → pass-through; (b) any fail-open path (provider down,
|
|
47
|
+
timeout, low confidence, malformed output). All are cheap (the user re-phrases); none cause harm. The old
|
|
48
|
+
keyword list ALSO under-blocked ("let's have the mini take this one" was missed) — this reduces it via
|
|
49
|
+
context-aware inference.
|
|
50
|
+
|
|
51
|
+
## 3. Level-of-abstraction fit
|
|
52
|
+
|
|
53
|
+
Correct layer. It is a smart AUTHORITY (LLM reasoning over message + conversation context), not a brittle
|
|
54
|
+
detector — exactly what the "Intelligence Infers, Keywords Only Guard" standard requires for a
|
|
55
|
+
what-did-they-mean judgment. The cheap deterministic prefilter is a genuine *pre-filter* (drops toward
|
|
56
|
+
pass-through only, never decides a command), matching `TopicIntentCapture`. It USES existing primitives
|
|
57
|
+
(shared `IntelligenceProvider`, `RelocationNicknameSet`, `TransferByNickname`) rather than re-implementing
|
|
58
|
+
them; it FEEDS the unchanged planner rather than running parallel to it.
|
|
59
|
+
|
|
60
|
+
## 4. Signal vs authority compliance
|
|
61
|
+
|
|
62
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
63
|
+
|
|
64
|
+
- [x] Yes — but the logic is a smart gate with full conversational context (LLM-backed with recent history).
|
|
65
|
+
|
|
66
|
+
The decision is an LLM reasoning over the message + a bounded conversation window — a smart gate, not a
|
|
67
|
+
brittle detector holding block authority. It replaces exactly the brittle-detector-with-authority
|
|
68
|
+
anti-pattern the standard forbids. It fails open, so even under provider failure it never asserts authority
|
|
69
|
+
it can't back.
|
|
70
|
+
|
|
71
|
+
## 5. Interactions
|
|
72
|
+
|
|
73
|
+
- **Shadowing:** `_tryNicknameRelocation` runs BEFORE `_sessionRouter.route()` (unchanged ordering) and only
|
|
74
|
+
when `_sessionPoolStage() !== 'dark'`. When it returns `handled:false` (the common case, and ALWAYS during
|
|
75
|
+
dry-run), routing proceeds normally — it cannot shadow the router. Verified by `transfer-activation-wiring.test.ts`.
|
|
76
|
+
- **Double-fire:** no. A message is classified once per inbound; a positive hijack returns early (`return`),
|
|
77
|
+
a pass-through continues to the router exactly once.
|
|
78
|
+
- **Races:** none new. The classifier is stateless; the only write is an append to `logs/move-intent.jsonl`
|
|
79
|
+
(best-effort, wrapped, never throws into the message path).
|
|
80
|
+
- **Feedback loops:** none. The classifier reads recent history but never writes conversation turns.
|
|
81
|
+
|
|
82
|
+
## 6. External surfaces
|
|
83
|
+
|
|
84
|
+
- **Other agents on the machine:** none — internal message-path classifier.
|
|
85
|
+
- **Install base:** dark on the fleet (dev-agent gate + the whole relocation path is already gated behind
|
|
86
|
+
`sessionPool != dark`, which ships dark). No fleet behavior change.
|
|
87
|
+
- **External systems:** one bounded fast-tier LLM call per nickname-mentioning candidate message, via the
|
|
88
|
+
shared `IntelligenceProvider` (spawn-cap + circuit-breaker + attribution). No new network dependency.
|
|
89
|
+
- **Persistent state:** `logs/move-intent.jsonl` — a new machine-local append-only observability log
|
|
90
|
+
(LLM-engaged decisions only; 80-char truncated preview; local, never synced). Consistent with all other
|
|
91
|
+
`logs/*.jsonl`.
|
|
92
|
+
- **Timing:** `timeoutMs` default 4000 bounds the worst-case pass-through delay for a candidate message.
|
|
93
|
+
- **Operator surface (Mobile-Complete):** No operator-facing actions added. The only operator interaction is
|
|
94
|
+
flipping `dryRun:false` / `modelTier` in config (already a standard config edit), plus reading the
|
|
95
|
+
dashboard **LLM Activity** tab (`/metrics/features`, already phone-accessible). N/A.
|
|
96
|
+
|
|
97
|
+
## 6b. Operator-surface quality
|
|
98
|
+
|
|
99
|
+
No operator surface — not applicable. This change touches no dashboard renderer, approval page, or
|
|
100
|
+
grant/revoke/secret-drop form (no `dashboard/*` or form files staged).
|
|
101
|
+
|
|
102
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
103
|
+
|
|
104
|
+
**Posture: machine-local BY DESIGN** — the classifier is stateless request-locality COMPUTE. It runs on the
|
|
105
|
+
machine that holds the topic (the lifeline forwards inbound to the holder), is a pure function of the
|
|
106
|
+
message + the live nickname registry + the provider, and has no durable cross-machine state to replicate.
|
|
107
|
+
The only durable artifact is `logs/move-intent.jsonl`, a machine-local observability log identical in
|
|
108
|
+
posture to `logs/sentinel-events.jsonl` / `logs/reaper-audit.jsonl` (pure per-machine observability).
|
|
109
|
+
|
|
110
|
+
- **User-facing notices / one-voice gating?** No — during dry-run it emits nothing to the user; when live it
|
|
111
|
+
produces the same single "Moving…" reply the existing keyword path did (unchanged), routed by the existing
|
|
112
|
+
single-owner path.
|
|
113
|
+
- **Durable state / strands on topic transfer?** The soak log is per-machine; a topic that transfers mid-soak
|
|
114
|
+
splits its would-hijack/would-pass evidence across machines. This is graduation-decision EVIDENCE, not user
|
|
115
|
+
data — at `dryRun:false` graduation the operator aggregates the per-machine logs (or scopes the soak to a
|
|
116
|
+
non-moving topic). No user data strands.
|
|
117
|
+
- **Generated URLs?** None.
|
|
118
|
+
|
|
119
|
+
Multi-dev note: the dev-agent gate resolves per-machine, so a multi-dev setup should activate
|
|
120
|
+
pool-consistently (documented in the spec Rollout §4) to avoid divergent behavior across topic-holding machines.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Migration parity
|
|
125
|
+
|
|
126
|
+
Config default `multiMachine.sessionPool.moveIntent` is added under the existing `sessionPool` block in
|
|
127
|
+
`ConfigDefaults.ts`; `applyDefaults`/`getMigrationDefaults` deep-merges it add-missing onto existing agents
|
|
128
|
+
(the documented sessionPool migration-parity path — verified: the whole config/migration test family, 1191
|
|
129
|
+
tests, stays green). `enabled` is OMITTED so `resolveDevAgentGate` decides (dark fleet / live dev);
|
|
130
|
+
registered in `DEV_GATED_FEATURES` (both-sides wiring test green). No hook/CLAUDE.md-template/skill changes
|
|
131
|
+
(the move-by-nickname capability is dev-only experimental behind the dark session pool, so no
|
|
132
|
+
Agent-Awareness template surface is added).
|
|
133
|
+
|
|
134
|
+
## Rollback
|
|
135
|
+
|
|
136
|
+
Pure revert. No schema/data migration to unwind. To disable without reverting: set
|
|
137
|
+
`multiMachine.sessionPool.moveIntent.enabled: false` in config (force-dark even on a dev agent), or leave the
|
|
138
|
+
session pool at `stage: dark` (the default) — either fully inerts the path. `logs/move-intent.jsonl` is
|
|
139
|
+
append-only observability and safe to delete.
|
|
140
|
+
|
|
141
|
+
## Risk
|
|
142
|
+
|
|
143
|
+
Low. Ships dark on the fleet AND dry-run-first on dev (logs would-hijack/would-pass, actuates nothing). The
|
|
144
|
+
change strictly REDUCES risk versus the shipped keyword recognizer (fail-open replaces false-positive
|
|
145
|
+
hijack). The residual risk (a confidently-wrong model once `dryRun:false`) is gated by the graduation-gate
|
|
146
|
+
live benchmark + user-role Live-Channel proof + the soak, all required before actuation. tsc clean; lint
|
|
147
|
+
clean; all three test tiers green including the discrimination corpus.
|
|
148
|
+
|
|
149
|
+
## Post-rebase addendum (2026-07-04)
|
|
150
|
+
|
|
151
|
+
Rebased onto current `main` (clean). The new LLM component `MoveIntentClassifier` was registered across the
|
|
152
|
+
LLM-coverage ratchets that landed on main (#1366 and the bench family): `src/data/llmBenchCoverage.ts` —
|
|
153
|
+
`LLM_UNTRUSTED_INPUT: true` (it reads untrusted user message + context), `LLM_JUDGES_CLAIMS: false` (it
|
|
154
|
+
classifies a USER's move intent, not an agent/session completion/health/credit claim), `LLM_PARSER_CONTRACT:
|
|
155
|
+
{ pending: 'contract-wave-2' }` (it parses a closed verdict), and `LLM_BENCH_COVERAGE: { exempt }` (it ships
|
|
156
|
+
its own discrimination benchmark). The keyword-intent-decision ratchet's baseline was decremented 6→5 and
|
|
157
|
+
`NicknameCommand.ts` removed from its `EXPECTED_OFFENDERS` (offender #2 converted — exactly what that ratchet
|
|
158
|
+
tracks). The `parseMoveIntentResponse` fail-open catch carries an `@silent-fallback-ok` marker (the
|
|
159
|
+
documented fail-open, surfaced via `result.source`/`reason` + the audit log, never a silent swallow). No
|
|
160
|
+
behavior change from these — they are the coverage/observability registrations a new LLM component requires.
|