instar 1.3.764 → 1.3.765
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/core/ClaudeCliIntelligenceProvider.d.ts +15 -0
- package/dist/core/ClaudeCliIntelligenceProvider.d.ts.map +1 -1
- package/dist/core/ClaudeCliIntelligenceProvider.js +111 -23
- package/dist/core/ClaudeCliIntelligenceProvider.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +49 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/crossModelReviewer.d.ts +188 -9
- package/dist/core/crossModelReviewer.d.ts.map +1 -1
- package/dist/core/crossModelReviewer.js +360 -18
- package/dist/core/crossModelReviewer.js.map +1 -1
- package/dist/core/types.d.ts +14 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/package.json +1 -1
- package/scripts/model-registry-freshness.manifest.json +8 -0
- package/skills/spec-converge/SKILL.md +4 -2
- package/skills/spec-converge/scripts/cross-model-review.mjs +36 -6
- package/src/data/builtin-manifest.json +19 -19
- package/upgrades/1.3.765.md +63 -0
- package/upgrades/side-effects/reviewer-door-rewiring-inc1.md +198 -0
|
@@ -125,9 +125,33 @@ function readRepoFile(rel) {
|
|
|
125
125
|
return fs.readFileSync(abs, 'utf-8');
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Read the minimal reviewer config the module needs (REVIEWER-DOOR-REWIRING
|
|
130
|
+
* §1.5): the developmentAgent gate flag + the `specConverge.reviewers` block, so
|
|
131
|
+
* the Anthropic clean-door family resolves live-on-dev / dark-fleet. Best-effort:
|
|
132
|
+
* a missing/unparseable `.instar/config.json` ⇒ `{}` ⇒ fleet-dark (byte-identical
|
|
133
|
+
* `[codex, gemini]`). `.instar/config.json` is machine-local (no config
|
|
134
|
+
* replication in instar) — enabling the family is a per-machine edit.
|
|
135
|
+
*/
|
|
136
|
+
function loadReviewerConfig() {
|
|
137
|
+
try {
|
|
138
|
+
const cfgPath = path.join(ROOT, '.instar', 'config.json');
|
|
139
|
+
if (!fs.existsSync(cfgPath)) return {};
|
|
140
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
|
|
141
|
+
const out = {};
|
|
142
|
+
if (typeof cfg.developmentAgent === 'boolean') out.developmentAgent = cfg.developmentAgent;
|
|
143
|
+
if (cfg.specConverge && typeof cfg.specConverge === 'object') out.specConverge = cfg.specConverge;
|
|
144
|
+
return out;
|
|
145
|
+
} catch {
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
async function main() {
|
|
129
151
|
const { spec, context, detectOnly, hashOnly, family, stateDir, timeoutMs } = parseArgs();
|
|
130
152
|
const mod = await loadModule();
|
|
153
|
+
// Config-gate the Anthropic clean-door family (§1.5). Absent config ⇒ fleet-dark.
|
|
154
|
+
const reviewerConfig = loadReviewerConfig();
|
|
131
155
|
|
|
132
156
|
// ── --hash-only: the delta-gating hash of the spec's reviewable body ──
|
|
133
157
|
if (hashOnly) {
|
|
@@ -139,9 +163,9 @@ async function main() {
|
|
|
139
163
|
|
|
140
164
|
// ── --detect-only: report ALL available families (Piece 3) ──
|
|
141
165
|
if (detectOnly) {
|
|
142
|
-
const all = mod.detectAllCrossModelReviewers();
|
|
166
|
+
const all = mod.detectAllCrossModelReviewers({}, reviewerConfig);
|
|
143
167
|
// Back-compat: keep the old single-framework fields (first-match shape).
|
|
144
|
-
const first = mod.detectCrossModelReviewer();
|
|
168
|
+
const first = mod.detectCrossModelReviewer({}, reviewerConfig);
|
|
145
169
|
const report = {
|
|
146
170
|
available: all.length > 0,
|
|
147
171
|
frameworks: all,
|
|
@@ -152,10 +176,11 @@ async function main() {
|
|
|
152
176
|
// Record the activation observation into the durable standing-framework
|
|
153
177
|
// baseline when a state dir was provided. A record failure is surfaced in
|
|
154
178
|
// the JSON (fail-loud), never silently swallowed — a missing baseline
|
|
155
|
-
// would quietly weaken the externals-mandatory check.
|
|
179
|
+
// would quietly weaken the externals-mandatory check. Iterate the ACTIVE
|
|
180
|
+
// set so a config-disabled claude family is not recorded as present.
|
|
156
181
|
if (stateDir) {
|
|
157
182
|
const frameworks = {};
|
|
158
|
-
for (const entry of mod.
|
|
183
|
+
for (const entry of mod.resolveActiveReviewerFrameworks(reviewerConfig)) {
|
|
159
184
|
frameworks[entry.id] = all.some((d) => d.framework === entry.id);
|
|
160
185
|
}
|
|
161
186
|
try {
|
|
@@ -186,7 +211,10 @@ async function main() {
|
|
|
186
211
|
);
|
|
187
212
|
process.exit(0);
|
|
188
213
|
}
|
|
189
|
-
|
|
214
|
+
// Config gate (§1.5): a trusted-but-disabled family (the claude clean-door
|
|
215
|
+
// family on the fleet) is refused here — trusted-egress ≠ enabled.
|
|
216
|
+
const active = mod.resolveActiveReviewerFrameworks(reviewerConfig);
|
|
217
|
+
familyEntry = active.find((f) => f.id === family) ?? null;
|
|
190
218
|
if (!familyEntry) {
|
|
191
219
|
process.stdout.write(
|
|
192
220
|
JSON.stringify({
|
|
@@ -199,7 +227,7 @@ async function main() {
|
|
|
199
227
|
}
|
|
200
228
|
}
|
|
201
229
|
|
|
202
|
-
const detection = familyEntry ? familyEntry.detect() : mod.detectCrossModelReviewer();
|
|
230
|
+
const detection = familyEntry ? familyEntry.detect() : mod.detectCrossModelReviewer({}, reviewerConfig);
|
|
203
231
|
|
|
204
232
|
// Unavailable → print the unavailable flag, exit 0. Never block.
|
|
205
233
|
if (!detection.available) {
|
|
@@ -227,9 +255,11 @@ async function main() {
|
|
|
227
255
|
promptText: assembled.promptText,
|
|
228
256
|
timeoutMs: Number.isFinite(timeoutMs) ? timeoutMs : mod.REVIEW_TIMEOUT_MS,
|
|
229
257
|
detectionOverride: detection,
|
|
258
|
+
reviewerConfig,
|
|
230
259
|
})
|
|
231
260
|
: await mod.runCrossModelReview({
|
|
232
261
|
assembled,
|
|
262
|
+
config: reviewerConfig,
|
|
233
263
|
...(Number.isFinite(timeoutMs) ? { timeoutMs } : {}),
|
|
234
264
|
});
|
|
235
265
|
|
|
@@ -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-04T23:42:04.602Z",
|
|
5
|
+
"instarVersion": "1.3.765",
|
|
6
6
|
"entryCount": 202,
|
|
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": "
|
|
14
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
23
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
32
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
41
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
50
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
59
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
68
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
77
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
86
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
95
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
104
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
113
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
122
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
131
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
140
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
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": "
|
|
149
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
150
150
|
"since": "2025-01-01"
|
|
151
151
|
},
|
|
152
152
|
"job:health-check": {
|
|
@@ -1562,7 +1562,7 @@
|
|
|
1562
1562
|
"type": "subsystem",
|
|
1563
1563
|
"domain": "updates",
|
|
1564
1564
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1565
|
-
"contentHash": "
|
|
1565
|
+
"contentHash": "de95f71c64d605e358e30e39626a1c25ccfc1eabf480623febc3e2c7dbab948e",
|
|
1566
1566
|
"since": "2025-01-01"
|
|
1567
1567
|
},
|
|
1568
1568
|
"subsystem:scheduler": {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Added a third **spec-converge external reviewer family**: the strongest Anthropic model
|
|
9
|
+
(`claude-fable-5`) now reads a spec through the clean `claude -p` door — off the measured-penalized
|
|
10
|
+
`opus × coding-harness` pair (INSTAR-Bench v2: Opus-4.8-via-Claude-Code 81.7% vs clean-API 99.1%, a
|
|
11
|
+
17.4-point door penalty). This is **inc1** of REVIEWER-DOOR-REWIRING, and ships **dark on the fleet /
|
|
12
|
+
live on a development agent** (the `specConverge.reviewers.anthropic.enabled` developmentAgent gate —
|
|
13
|
+
absent config keeps today's exact `[codex, gemini]` behavior byte-for-byte).
|
|
14
|
+
|
|
15
|
+
The reviewer is a **clean-door second read, NOT a cross-model opinion** — it carries `crossFamily:
|
|
16
|
+
false` and books into its own `clean-door-anthropic-review` disclosure field, so a claude-only round
|
|
17
|
+
can never launder the `cross-model-review` flag. Because a spec under review is untrusted ~60KB text,
|
|
18
|
+
the call is **hardened to codex-door parity**: empty allowed-tools (`--allowedTools ''`, an allow-list
|
|
19
|
+
not a denylist), `--strict-mcp-config`, a neutral scratch cwd, the prompt via stdin (never argv), an
|
|
20
|
+
env allowlist that strips agent secrets (`INSTAR_AUTH_TOKEN`), and a runtime fail-closed preflight
|
|
21
|
+
that degrades (never runs unhardened) if the installed CLI lacks the flags. The model argument is the
|
|
22
|
+
CONCRETE frontier pin — never the tier word `'capable'`, which resolves to opus.
|
|
23
|
+
|
|
24
|
+
## What to Tell Your User
|
|
25
|
+
|
|
26
|
+
Nothing proactive — this is instar-developing-agent tooling that ships off on the fleet. If a user
|
|
27
|
+
asks why a spec-converge run now shows a "clean-door Anthropic review" line, or whether the strongest
|
|
28
|
+
Claude model reviews specs: on a development agent the spec is now also read by Fable 5 (the strongest
|
|
29
|
+
Claude model) through a clean door (separate from the six in-session reviewers), disclosed on its own line and never
|
|
30
|
+
counted as a cross-model opinion. It is dogfooded on the development agent first, before any wider
|
|
31
|
+
rollout; the "clean door" claim is scoped to *off the measured-penalized coding-harness door*, not
|
|
32
|
+
bench-verified-clean (that direct bench is a tracked follow-up).
|
|
33
|
+
|
|
34
|
+
## Summary of New Capabilities
|
|
35
|
+
|
|
36
|
+
- **`--family claude-code` clean-door reviewer** in spec-converge — config-gated
|
|
37
|
+
(`specConverge.reviewers.anthropic.enabled`, dev-on / fleet-dark); an optional
|
|
38
|
+
`specConverge.reviewers.anthropic.model` override is validated against the frontier accept-set
|
|
39
|
+
(a non-frontier concrete id like `claude-opus-4-8` is rejected, never silently honored).
|
|
40
|
+
- **Cross-model honesty guard** — `crossFamily` is threaded onto the reviewer registry,
|
|
41
|
+
`ReviewerResult`, and `CrossModelDetectionResult` (fail-closed on an unknown id); the aggregate
|
|
42
|
+
flag, both detection paths, and the 7-day externals-mandatory baseline all filter on
|
|
43
|
+
`crossFamily: true`, so the claude family can never masquerade as cross-model.
|
|
44
|
+
- **Inbound-safety hardening** for reviewing untrusted spec text (empty allowed-tools,
|
|
45
|
+
strict-mcp-config, neutral cwd, stdin prompt, env allowlist), verified by a STATE-level
|
|
46
|
+
zero-tool-execution test against the real Claude CLI.
|
|
47
|
+
- No behavior change while the family stays dark (the fleet default); this only makes the reviewer
|
|
48
|
+
reachable on a development agent.
|
|
49
|
+
|
|
50
|
+
## Evidence
|
|
51
|
+
|
|
52
|
+
- `tests/unit/crossModelReviewer-clean-door.test.ts` — detection (static presence reasons only),
|
|
53
|
+
model resolution (default pin, tier-word + non-frontier-override rejection), the §5 lockdown
|
|
54
|
+
battery (a–e), the required-`crossFamily`-field guard, per-family concrete-pin model-arg, and the
|
|
55
|
+
config-gate default (fleet-absent = exactly `[codex, gemini]`).
|
|
56
|
+
- `tests/unit/claude-reviewer-inbound-safety.test.ts` — hardened argv/env asserted deterministically
|
|
57
|
+
+ a live-claude-gated STATE test proving a benign tool-invoking payload creates ZERO files.
|
|
58
|
+
- `tests/unit/model-registry-freshness-reviewer-pin.test.ts` — the freshness-lint tooth on the
|
|
59
|
+
reviewer pin is NOT vacuous (a rotted constant fails the strict lint).
|
|
60
|
+
- `tests/integration/clean-door-reviewer-driver.test.ts` — the driver `--family`/`--detect-only`
|
|
61
|
+
paths: clean-door flag shape, trusted-but-disabled refusal, family-present-only-when-enabled.
|
|
62
|
+
- `tests/unit/PostUpdateMigrator-anthropicReviewerDisclosure.test.ts` — the SKILL.md content
|
|
63
|
+
migration reaches already-installed agents (idempotent, fingerprint-guarded).
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Side-Effects Review — Reviewer-Door Rewiring inc1 (Anthropic clean-door reviewer family)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `reviewer-door-rewiring-inc1`
|
|
4
|
+
**Date:** `2026-07-04`
|
|
5
|
+
**Author:** `echo (build hand)`
|
|
6
|
+
**Second-pass reviewer:** `not required (Tier-1: dark-on-fleet, config-reversible, no durable state / external side-effects; PR is the review surface)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
inc1 of REVIEWER-DOOR-REWIRING adds a third spec-converge external reviewer family — the strongest
|
|
11
|
+
Anthropic model (`claude-fable-5`) read through the clean `claude -p` door, off the measured-penalized
|
|
12
|
+
`opus × coding-harness` pair. It ships **dark on the fleet / live on a development agent** via the
|
|
13
|
+
`specConverge.reviewers.anthropic.enabled` developmentAgent gate; absent config keeps today's exact
|
|
14
|
+
`[codex, gemini]` behavior byte-for-byte. The family is a clean-door SECOND READ (`crossFamily: false`)
|
|
15
|
+
that books into its own `clean-door-anthropic-review` disclosure field and can never launder the
|
|
16
|
+
`cross-model-review` flag. Files touched: `src/core/crossModelReviewer.ts` (detection, model
|
|
17
|
+
resolution, registry entry, config gate, crossFamily plumbing, baseline-predicate swap, aggregate
|
|
18
|
+
filter, hardening preflight), `src/core/ClaudeCliIntelligenceProvider.ts` (reviewer-hardening
|
|
19
|
+
invocation + exported arg/env builders), `src/core/types.ts` (`IntelligenceOptions.reviewerHardening`),
|
|
20
|
+
`scripts/model-registry-freshness.manifest.json` (reviewer pin), `skills/spec-converge/scripts/cross-model-review.mjs`
|
|
21
|
+
(config gate), `skills/spec-converge/SKILL.md` (family + D7 disclosure), `src/core/PostUpdateMigrator.ts`
|
|
22
|
+
(SKILL.md content migration), `docs/LLM-ROUTING-REGISTRY.md` (stale `report`→`strict` line), plus five
|
|
23
|
+
test files + the converged spec docs.
|
|
24
|
+
|
|
25
|
+
## Decision-point inventory
|
|
26
|
+
|
|
27
|
+
- `SUPPORTED_REVIEWER_FRAMEWORKS` — **modify** — one new `claude-code` entry with REQUIRED `crossFamily: false`; codex remains the preference leader; existing ordering unchanged.
|
|
28
|
+
- `TRUSTED_REVIEWER_FRAMEWORKS` — **modify** — gains `claude-code`, COUPLED ATOMICALLY with the §5.4 baseline-predicate swap (`isTrustedReviewerFramework` → `isCrossFamilyReviewerFramework`).
|
|
29
|
+
- `ReviewerResult` / `CrossModelDetectionResult` — **modify** — gain a `crossFamily` field (populated from the registry; existing families byte-identical).
|
|
30
|
+
- `aggregateRoundOutcomes` / `detectCrossModelReviewer` / `detectAllCrossModelReviewers` / `wasNonClaudeFrameworkActiveWithin` — **modify** — gain `crossFamily` filtering (behavior for existing families byte-identical).
|
|
31
|
+
- `IntelligenceOptions.reviewerHardening` — **add** — the claude-provider inbound-safety lockdown option (other providers ignore it).
|
|
32
|
+
- `specConverge.reviewers.anthropic.{enabled,model}` config block — **add** — the developmentAgent gate + optional frontier-validated model override.
|
|
33
|
+
- No block/allow gate, no HTTP route, no scheduler job, no watcher is introduced or modified.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. Over-block
|
|
38
|
+
|
|
39
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
40
|
+
|
|
41
|
+
No user-message block/allow surface — over-block not applicable. The one rejection path is the config
|
|
42
|
+
model-override validator: a concrete-but-non-frontier id (e.g. `claude-opus-4-8`) is rejected with
|
|
43
|
+
`override-not-frontier`. This is *intended* (it prevents re-pinning the reviewer to the penalized opus
|
|
44
|
+
door); a legitimate frontier id (`claude-fable-5`) is accepted, and the default pin needs no override.
|
|
45
|
+
The `--family claude-code` refusal on the fleet (`no-supported-framework`) is intended dark-gating,
|
|
46
|
+
not over-block.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. Under-block
|
|
51
|
+
|
|
52
|
+
**What illegitimate inputs does this change let through that it shouldn't?**
|
|
53
|
+
|
|
54
|
+
The load-bearing under-block risk is the untrusted spec text reaching a tool/MCP execution path via the
|
|
55
|
+
`claude -p --setting-sources user` door (which loads user hooks + MCP servers and inherits full env).
|
|
56
|
+
§1.4 hardening closes this: empty allowed-tools + `--strict-mcp-config` + neutral scratch cwd + stdin
|
|
57
|
+
prompt + env allowlist, plus a fail-closed runtime preflight (`hardening-unsupported` → degrade, never
|
|
58
|
+
run unhardened). Verified by a STATE-level zero-tool-execution test against the real Claude CLI (a
|
|
59
|
+
benign tool-invoking payload creates NO file). The cross-model-honesty under-block (a claude-only run
|
|
60
|
+
masquerading as cross-model) is closed structurally by `crossFamily`-keyed filtering, fail-closed on an
|
|
61
|
+
unknown id, unit-locked.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 3. Level-of-abstraction fit
|
|
66
|
+
|
|
67
|
+
**Is the change at the right layer?**
|
|
68
|
+
|
|
69
|
+
Yes. The reviewer family is a registry entry in the existing `SUPPORTED_REVIEWER_FRAMEWORKS` seam (the
|
|
70
|
+
established extension point); the hardening is invocation options on the existing
|
|
71
|
+
`ClaudeCliIntelligenceProvider` (no new adapter class, no `IntelligenceFramework` union change); the gate
|
|
72
|
+
rides the standard `resolveDevAgentGate` funnel; the anti-rot pin rides the existing freshness-lint
|
|
73
|
+
manifest. No new subsystem, no new abstraction — the change reuses every existing seam.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 4. Signal vs authority compliance
|
|
78
|
+
|
|
79
|
+
**Does anything here gain blocking authority it shouldn't?**
|
|
80
|
+
|
|
81
|
+
No. Every reviewer (internal, external, clean-door) remains a SIGNAL into convergence synthesis; no
|
|
82
|
+
pass gains blocking authority; a degraded/unavailable family degrades loudly and convergence proceeds.
|
|
83
|
+
The config gate governs *availability of a signal source*, not any authority. The `crossFamily` guard
|
|
84
|
+
is a classification of what a signal COUNTS AS, not a block. The hardening preflight degrades (a signal
|
|
85
|
+
outcome), never blocks.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 5. Interactions
|
|
90
|
+
|
|
91
|
+
**What existing features does this change interact with, and how?**
|
|
92
|
+
|
|
93
|
+
- **Freshness lint** (`scripts/lint-model-registry-freshness.mjs`) — the new `claude-clean-door-reviewer-default`
|
|
94
|
+
pin is checked under strict enforcement; verified green + non-vacuity-tested.
|
|
95
|
+
- **subscription pool / circuit breaker / spawn cap** — the claude reviewer rides `buildIntelligenceProvider`,
|
|
96
|
+
so it inherits the spawn-cap funnel + per-framework breaker; quota pressure surfaces as `degraded:
|
|
97
|
+
rate-limited`. Quota-correlation honesty: the claude family draws on the SAME Anthropic pool as the
|
|
98
|
+
authoring session (called out in the spec, degrades loudly).
|
|
99
|
+
- **7-day externals-mandatory baseline** — the predicate swap keeps the mandatory check keyed on
|
|
100
|
+
cross-model families only; a claude-only activation never satisfies it (unit-locked).
|
|
101
|
+
- **PostUpdateMigrator** — the SKILL.md content migration reaches already-installed agents.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 6. External surfaces
|
|
106
|
+
|
|
107
|
+
**Does this change touch any external service, network call, filesystem path outside the project, or spawn?**
|
|
108
|
+
|
|
109
|
+
- **Egress:** the claude reviewer sends the spec text to Anthropic (or the operator's OWN configured
|
|
110
|
+
`ANTHROPIC_BASE_URL` proxy) — the SAME destination the authoring session already uses. ZERO new
|
|
111
|
+
egress destinations. No third-party aggregator (OpenRouter declined, §2).
|
|
112
|
+
- **Spawn:** one `claude -p` one-shot per round per available family (≤10 rounds), run in a neutral
|
|
113
|
+
mkdtemp scratch cwd with an allowlist env. The `--help` preflight is a cheap one-shot, cached
|
|
114
|
+
per-process.
|
|
115
|
+
- **Filesystem:** the reviewer pin adds a row to the in-repo freshness manifest. No paths outside the
|
|
116
|
+
project are written; the scratch cwd is under `os.tmpdir()`.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 6b. Operator-surface quality (Operator-Surface Quality standard)
|
|
121
|
+
|
|
122
|
+
No new operator-facing surface (no HTTP route, no dashboard tab, no user-facing config the operator
|
|
123
|
+
edits conversationally). The `specConverge.reviewers.*` config is instar-developing-agent tooling set
|
|
124
|
+
per-machine by a maintainer, documented in the spec + SKILL.md + the release fragment. Not applicable
|
|
125
|
+
beyond that.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
130
|
+
|
|
131
|
+
- **Reviewer availability (which families detect on this machine)** — machine-local BY DESIGN.
|
|
132
|
+
machine-local-justification: physical-credential-locality — each family's door is a per-disk CLI
|
|
133
|
+
login (claude OAuth config-home, `~/.codex/auth.json`, `~/.gemini/oauth_creds.json`); reachability
|
|
134
|
+
cannot replicate without replicating credentials, which is forbidden.
|
|
135
|
+
- **Config (`specConverge.reviewers.*`)** — machine-local.
|
|
136
|
+
machine-local-justification: physical-credential-locality — `.instar/config.json` has no replication
|
|
137
|
+
path in instar (not one of the stateSync stores), and the config selects which per-disk CLI door
|
|
138
|
+
(a machine-local credentialed login) the reviewer uses. Enabling the family on more than one machine
|
|
139
|
+
is a per-machine edit.
|
|
140
|
+
- **`state/framework-activation-history.jsonl`** — existing surface, unchanged; already machine-local
|
|
141
|
+
for the same reason (it records THIS machine's detections).
|
|
142
|
+
machine-local-justification: physical-credential-locality — a record of per-disk login availability.
|
|
143
|
+
- Convergence runs on one machine per run; no cross-machine notice, URL, or durable-topic surface is
|
|
144
|
+
added. No `unified` surface is infeasible-and-claimed (bidirectional check clear).
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 8. Rollback cost
|
|
149
|
+
|
|
150
|
+
**How hard is it to undo this change if it goes wrong?**
|
|
151
|
+
|
|
152
|
+
Trivial. The family ships dark on the fleet (absent config = byte-identical `[codex, gemini]`). Rollback
|
|
153
|
+
is a config flip (`specConverge.reviewers.anthropic.enabled: false`) or a revert of a docs/constants-only
|
|
154
|
+
change. No data migration, no durable state, no external side-effects. The freshness manifest `enforcement`
|
|
155
|
+
has its own documented `strict`→`report` rollback. The SKILL.md migration is idempotent + fingerprint-guarded
|
|
156
|
+
(a customized skill is never touched).
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Conclusion
|
|
161
|
+
|
|
162
|
+
**Ship / hold / needs second pass:** Ship (Tier-1). The change is dark-on-fleet, fully config-reversible,
|
|
163
|
+
adds no durable state or new external destination, and the two load-bearing risks (untrusted-text tool
|
|
164
|
+
execution; cross-model-flag laundering) are closed structurally and verified by tests — including a live
|
|
165
|
+
STATE-level zero-tool-execution proof against the real Claude CLI. Operator approval of the converged
|
|
166
|
+
spec (`approved: true`) is deliberately left to the operator per the run mandate.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Second-pass review (if required)
|
|
171
|
+
|
|
172
|
+
Not required — Tier-1 (dark-on-fleet, config-reversible, no durable/external side-effects). The PR is the
|
|
173
|
+
review surface. Note for the operator: this increment implements a CONVERGED-but-not-yet-approved spec;
|
|
174
|
+
if a Tier-2 re-land is desired post-approval, the trace can be re-cut with `--spec` + the approved tag.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Evidence pointers
|
|
179
|
+
|
|
180
|
+
- `tests/unit/crossModelReviewer-clean-door.test.ts` (28 tests) — detection, model resolution, §5
|
|
181
|
+
lockdown battery (a–e), required-crossFamily-field guard, per-family concrete-pin model-arg, config gate.
|
|
182
|
+
- `tests/unit/claude-reviewer-inbound-safety.test.ts` (7 tests, incl. live STATE) — hardened argv/env +
|
|
183
|
+
zero-tool-execution against the real Claude CLI.
|
|
184
|
+
- `tests/unit/model-registry-freshness-reviewer-pin.test.ts` (3 tests) — non-vacuity of the reviewer pin.
|
|
185
|
+
- `tests/integration/clean-door-reviewer-driver.test.ts` (7 tests) — driver `--family`/`--detect-only` paths.
|
|
186
|
+
- `tests/unit/PostUpdateMigrator-anthropicReviewerDisclosure.test.ts` (4 tests) — SKILL.md content migration.
|
|
187
|
+
- `node scripts/lint-model-registry-freshness.mjs` → PASS (strict). `node cross-model-review.mjs --detect-only`
|
|
188
|
+
→ `[codex, gemini]` (fleet-absent config, dark).
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Class-Closure Declaration (display-only mirror)
|
|
193
|
+
|
|
194
|
+
This change closes ONE instance of a class (a per-provider clean-door reviewer). The generalization —
|
|
195
|
+
a structured `{ provider, door, signalKind }` reviewer descriptor replacing the `crossFamily` boolean —
|
|
196
|
+
is tracked as a deferral (spec §8.5) for when a future reviewer breaks the binary Claude/non-Claude
|
|
197
|
+
taxonomy or the one-door-per-framework assumption. The paid-Gemini-key door + the direct `claude -p`
|
|
198
|
+
bench are tracked deferrals (spec §8.1/§8.3), registered as an evolution action at merge.
|