instar 1.3.1249 → 1.3.1250
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh +28 -8
- package/.claude/skills/autonomous/scripts/setup-autonomous.sh +39 -5
- package/dist/core/PostUpdateMigrator.d.ts +6 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +68 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +19 -19
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/{1.3.1249.md → 1.3.1250.md} +24 -0
- package/upgrades/side-effects/autonomous-auth-vault-resolve.md +180 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1250",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/audits/phase-b/f10-triage.md",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "9d8e4e883e348a23f831acecf4ccf189799d1720dfa1b3ece88970908ac35d46",
|
|
3
3
|
"registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1250"
|
|
5
5
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-09-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-09-21T20:47:12.436Z",
|
|
5
|
+
"instarVersion": "1.3.1250",
|
|
6
6
|
"entryCount": 203,
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
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": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:telegram-origin-guard": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "coherence",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "coherence",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:free-text-guard": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "safety",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:claim-intercept": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "coherence",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"hook:claim-intercept-response": {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"domain": "coherence",
|
|
138
138
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
139
139
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
140
|
-
"contentHash": "
|
|
140
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
141
141
|
"since": "2025-01-01"
|
|
142
142
|
},
|
|
143
143
|
"hook:stop-gate-router": {
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"domain": "safety",
|
|
147
147
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
148
148
|
"installedPath": ".instar/hooks/instar/stop-gate-router.js",
|
|
149
|
-
"contentHash": "
|
|
149
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
150
150
|
"since": "2025-01-01"
|
|
151
151
|
},
|
|
152
152
|
"hook:auto-approve-permissions": {
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"domain": "safety",
|
|
156
156
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
157
157
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
158
|
-
"contentHash": "
|
|
158
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
159
159
|
"since": "2025-01-01"
|
|
160
160
|
},
|
|
161
161
|
"job:health-check": {
|
|
@@ -1571,7 +1571,7 @@
|
|
|
1571
1571
|
"type": "subsystem",
|
|
1572
1572
|
"domain": "updates",
|
|
1573
1573
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1574
|
-
"contentHash": "
|
|
1574
|
+
"contentHash": "1444a86dc90dd560739c7eae26ef90f8d3876e313da6a505b96668a84b105e0a",
|
|
1575
1575
|
"since": "2025-01-01"
|
|
1576
1576
|
},
|
|
1577
1577
|
"subsystem:scheduler": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1250",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/audits/phase-b/f10-triage.md",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "9d8e4e883e348a23f831acecf4ccf189799d1720dfa1b3ece88970908ac35d46",
|
|
3
3
|
"registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1250"
|
|
5
5
|
}
|
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
|
|
6
6
|
## What Changed
|
|
7
7
|
|
|
8
|
+
Autonomous-run setup and its stop hook resolved the local server's bearer token
|
|
9
|
+
by reading `config.json.authToken` inline. On vault-migrated agents that field
|
|
10
|
+
is the SecretMigrator placeholder, so every call from those scripts was refused
|
|
11
|
+
— and on an admission-enforcing install a new run sat `preparing` forever with
|
|
12
|
+
no message. Both scripts now resolve the token vault-aware (config string first,
|
|
13
|
+
else `secret-get.mjs`), a refused registration prints a clear error (fatal only
|
|
14
|
+
where admission is required to arm), and a pre-existing `pipefail`+`grep -c`
|
|
15
|
+
trap that could kill setup silently is fixed. Existing agents receive both
|
|
16
|
+
scripts through PostUpdateMigrator marker bumps (`VAULT_AUTH_RESOLVE`);
|
|
17
|
+
customized copies are skipped, never overwritten.
|
|
18
|
+
|
|
8
19
|
Codex quota readings are now LIVE. Until now the only source was the session log the codex CLI writes after each completed turn, which has a structural limit: the number is only as fresh as the last time something ran on the account, and a WALLED account — where no turn completes — produces no record at all. That is why an idle account sat on a days-old number and why an exhausted account could show nothing whatsoever.
|
|
9
20
|
|
|
10
21
|
The codex CLI's app-server protocol exposes `account/rateLimits/read` — the exact call its own `/status` screen makes: a metadata fetch answered by OpenAI's backend without running a model turn. No tokens, no quota, measured at 450–850ms per account. A new reader (`codexLiveRateLimitReader`) speaks the protocol — spawn `codex app-server` against the account's config home, one initialize handshake, one read, kill — and maps the answer into the existing snapshot shape with `source: 'codex-app-server'`.
|
|
@@ -66,6 +77,10 @@ This is presentation only. No routing, placement, load-shedding, proactive-swap
|
|
|
66
77
|
|
|
67
78
|
## What to Tell Your User
|
|
68
79
|
|
|
80
|
+
If you start a long unattended work session and its setup can't actually take
|
|
81
|
+
hold, I now tell you immediately with a plain reason — instead of you
|
|
82
|
+
discovering the next day that nothing ever ran.
|
|
83
|
+
|
|
69
84
|
Your Codex usage bars are now live. Before, the number could only update when something actually ran on an account, so an idle account showed a days-old reading and an account that had hit its weekly wall showed nothing at all. Now every poll asks Codex directly — the same question its own status screen asks — and that costs nothing: no tokens, no quota. Walled accounts show their true 100% with the real reset time instead of a blank card.
|
|
70
85
|
|
|
71
86
|
If anything ever goes wrong with the live check, the dashboard quietly falls back to the old log-reading method, so the worst case is a stale number clearly labelled with its age — never a missing or wrong one.
|
|
@@ -90,6 +105,11 @@ Your Subscriptions dashboard now shows each account's quota bar in green, amber
|
|
|
90
105
|
|
|
91
106
|
## Summary of New Capabilities
|
|
92
107
|
|
|
108
|
+
- Autonomous setup + stop hook work on vault-migrated agents (token from the vault).
|
|
109
|
+
- A refused run registration is loud, and stops setup where arming is impossible.
|
|
110
|
+
- A silent shell-trap death in setup's concurrency fallback is fixed.
|
|
111
|
+
- Both fixes reach deployed agents via migration.
|
|
112
|
+
|
|
93
113
|
- Live, zero-spend Codex quota via `codex app-server`'s `account/rateLimits/read` — the poller and `GET /codex/usage` are live-first with rollout-tail fallback.
|
|
94
114
|
- Walled accounts (which write no rollout records) now report their true utilization and reset time.
|
|
95
115
|
- Provenance on every reading: `source: 'codex-app-server'` (live) vs `'codex-rollout'` (fallback), through the pool, the route, and WS5.2 replication.
|
|
@@ -121,6 +141,10 @@ Your Subscriptions dashboard now shows each account's quota bar in green, amber
|
|
|
121
141
|
|
|
122
142
|
## Evidence
|
|
123
143
|
|
|
144
|
+
- Unit `tests/unit/autonomous-setup-vault-auth.test.ts` (4 passing): runs the REAL script against a real HTTP server — the vault value reaches the server when config holds the placeholder; config string wins; enforcing + 403 aborts loudly with no state file; enforcing + unreachable still starts `preparing` (contract preserved, also covers the pipefail fix).
|
|
145
|
+
- Unit `tests/unit/PostUpdateMigrator-vaultAuthResolve.test.ts` (5 passing): the genuine pre-change blobs (pinned by commit) are re-deployed idempotently; the pinned predecessor SHA matches the real PREPARATION_CARRIER-era hook; customized copies are skipped by name.
|
|
146
|
+
- All 12 existing stop-hook suites (142 tests) and the 6 other setup-consuming suites (40 tests) pass against the modified scripts.
|
|
147
|
+
|
|
124
148
|
- Live, through the built dist against all five real Codex config homes (2026-09-20): justin@sagemindai.io 100% walled · dawn@sagemindai.io 100% walled (previously structurally unreadable) · headley.justin@gmail.com 100% walled · amrch 86% · adriana 96% — 450–850ms each, all `source=codex-app-server`, zero quota consumed (verified: the walled accounts answered while at 100%).
|
|
125
149
|
- Protocol ground truth captured from `codex app-server generate-json-schema` (codex-cli 0.153.4).
|
|
126
150
|
- Unit `tests/unit/codexLiveRateLimitReader.test.ts` (13 passing): response mapping, the walled-account marker, foreign-limit-family refusal, windowless and malformed windows, handshake order, and every failure shape → null (initialize refused, read error, silent child hitting the deadline, early child exit, spawn throw), plus the composition factory's both sides.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Side-Effects Review — Autonomous setup/hook: vault-aware auth + loud registration refusal
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `autonomous-auth-vault-resolve`
|
|
4
|
+
**Date:** `2026-09-21`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `independent reviewer subagent (see appended section)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`setup-autonomous.sh` and `autonomous-stop-hook.sh` read the server bearer token
|
|
11
|
+
with an inline `python3` read of `config.json.authToken`. On a vault-migrated
|
|
12
|
+
agent that field is the SecretMigrator placeholder (`{"secret": true}`), so every
|
|
13
|
+
server call from both scripts 403'd. On an admission-enforcing install
|
|
14
|
+
(windowRunLiveness enforcing), the refused registration left the run `preparing`
|
|
15
|
+
forever with no message — the 2026-09-19 silent no-start (ACT-030). This change:
|
|
16
|
+
|
|
17
|
+
- adds `resolve_auth_token()` (marker `VAULT_AUTH_RESOLVE`) to both scripts:
|
|
18
|
+
config string first, else the vault via `.instar/scripts/secret-get.mjs`;
|
|
19
|
+
replaces 3 reads in setup + 8 in the hook;
|
|
20
|
+
- makes a REFUSED registration (401/403) loud, and FATAL only on an
|
|
21
|
+
admission-enforcing install (where an unregistered run structurally cannot
|
|
22
|
+
arm); unreachable-server behaviour is unchanged (best-effort, preparing);
|
|
23
|
+
- fixes a pre-existing `set -euo pipefail` + `grep -c` trap in the local
|
|
24
|
+
concurrency fallback that killed the whole setup silently (exit 1, zero
|
|
25
|
+
output) whenever the server was unreachable/refusing and no other topic had a
|
|
26
|
+
state file;
|
|
27
|
+
- ships both to existing agents via PostUpdateMigrator: a fingerprint-gated
|
|
28
|
+
marker bump for the setup (`W32_PREPARING_LIVENESS` → `VAULT_AUTH_RESOLVE`)
|
|
29
|
+
and an exact-stock-SHA replacement for the hook (predecessor hash pinned as
|
|
30
|
+
`AUTONOMOUS_STOP_HOOK_PREPARATION_CARRIER_SHA256`). Customized copies are
|
|
31
|
+
skipped by name, never overwritten.
|
|
32
|
+
|
|
33
|
+
## Decision-point inventory
|
|
34
|
+
|
|
35
|
+
- `setup-autonomous.sh` registration branch — **modify** — a 401/403 now aborts
|
|
36
|
+
setup on enforcing installs only; everywhere else it prints and proceeds
|
|
37
|
+
exactly as before. No new authority: the server's admission decision already
|
|
38
|
+
governed whether the run could arm; the script now surfaces it instead of
|
|
39
|
+
swallowing it.
|
|
40
|
+
- `autonomous-stop-hook.sh` — **no decision change** — same calls, correct
|
|
41
|
+
token; every fail-open/fail-closed path is untouched.
|
|
42
|
+
- PostUpdateMigrator — **extend** — two more marker-bump migrations in the
|
|
43
|
+
existing `migrateAutonomousStopHookTopicKeyed` chain.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 1. Over-block
|
|
48
|
+
|
|
49
|
+
- The new fatal branch triggers only when (a) the install resolved
|
|
50
|
+
admission-enforcing at setup time AND (b) the server answered 401/403. A
|
|
51
|
+
wrong-but-reachable server cannot spuriously abort a non-enforcing agent's
|
|
52
|
+
run (it now prints the two-line ERROR instead of the old "unavailable" line,
|
|
53
|
+
and proceeds). On the enforcing install, aborting IS the correct behaviour: the
|
|
54
|
+
alternative was a run that never arms.
|
|
55
|
+
- Config token precedence: a real string in config always wins, so no agent that
|
|
56
|
+
still keeps a plaintext token changes behaviour. No issue identified.
|
|
57
|
+
|
|
58
|
+
## 2. Under-block
|
|
59
|
+
|
|
60
|
+
- An enforcing install whose server is UNREACHABLE (not refusing) still writes a
|
|
61
|
+
`preparing` run, as designed — the preparation carrier owns that recovery.
|
|
62
|
+
Deliberately preserved (tested).
|
|
63
|
+
- A vault whose `secret-get.mjs` is missing/failing yields an empty token → the
|
|
64
|
+
server refuses → now loud. Previously the same state was silent.
|
|
65
|
+
|
|
66
|
+
## 3. Level-of-abstraction fit
|
|
67
|
+
|
|
68
|
+
Token resolution belongs in the scripts themselves: they run standalone (hook
|
|
69
|
+
under Claude Code's Stop event, setup from a session) with no TypeScript layer
|
|
70
|
+
in-process. The function mirrors the hardened secret-get contract rather than
|
|
71
|
+
re-implementing vault decryption.
|
|
72
|
+
|
|
73
|
+
## 4. Signal vs authority compliance
|
|
74
|
+
|
|
75
|
+
No new brittle authority. The fatal branch consumes the SERVER's authoritative
|
|
76
|
+
admission verdict; the script only stops pretending the verdict was a success.
|
|
77
|
+
|
|
78
|
+
## 5. Interactions
|
|
79
|
+
|
|
80
|
+
- `resolve_auth_token()` is called via command substitution, so no memoization:
|
|
81
|
+
each call spawns python3 (+node only when config holds no string). The hook
|
|
82
|
+
already spawns python3 at each of those 8 sites, so the added cost is the node
|
|
83
|
+
startup on vault-migrated agents (~100–200 ms per call, only on paths already
|
|
84
|
+
making a network call).
|
|
85
|
+
- The migrations run inside the existing `migrateAutonomousStopHookTopicKeyed`
|
|
86
|
+
chain, AFTER the older bumps: an agent several releases behind is first
|
|
87
|
+
re-deployed by an earlier bump (whose bundled bytes already include this fix),
|
|
88
|
+
and the new bumps early-return on the marker. Order-independent.
|
|
89
|
+
- `sign-lockfile`/release hashing consume bundled bytes generically; no test pins
|
|
90
|
+
the setup/hook SHA outside the migration allowlists (checked: the only exact
|
|
91
|
+
hash is the new predecessor constant + the historical allowlist, both
|
|
92
|
+
append-only).
|
|
93
|
+
|
|
94
|
+
## 6. External surfaces
|
|
95
|
+
|
|
96
|
+
None. The token still goes only to `localhost:<port>` in an Authorization
|
|
97
|
+
header. The vault value is never echoed (stdout of secret-get feeds the variable
|
|
98
|
+
only; `set -x` is not used in these scripts). Error messages name the HTTP code,
|
|
99
|
+
never the token.
|
|
100
|
+
|
|
101
|
+
## 7. Multi-machine posture
|
|
102
|
+
|
|
103
|
+
Machine-local BY DESIGN: each machine's scripts read that machine's config and
|
|
104
|
+
vault; runs are per-machine state. The migrations run on every machine's own
|
|
105
|
+
update pass, so the fleet converges machine by machine. No user-facing notices
|
|
106
|
+
are added beyond the setup's own stderr (read by the session that ran it).
|
|
107
|
+
|
|
108
|
+
## 8. Rollback cost
|
|
109
|
+
|
|
110
|
+
Revert the commit and release: the NEXT migration pass does not restore old
|
|
111
|
+
bytes (marker bumps only move forward), but the scripts are self-contained —
|
|
112
|
+
re-deploying the previous bundle via the same exact-hash path would need one
|
|
113
|
+
follow-on migration. Operationally, the fix is strictly additive (correct token,
|
|
114
|
+
louder errors); the plausible regression is the fatal branch, whose blast radius
|
|
115
|
+
is one refused setup with a printed reason, recoverable by re-running setup.
|
|
116
|
+
|
|
117
|
+
## Second-pass review
|
|
118
|
+
|
|
119
|
+
**Reviewer:** independent reviewer subagent
|
|
120
|
+
**Verdict:** Concur with the review — no blocking concerns. Two minor notes below (neither warrants a code change).
|
|
121
|
+
|
|
122
|
+
What was checked:
|
|
123
|
+
|
|
124
|
+
- **`resolve_auth_token()` leak/hang/wrong-value:** the value only ever reaches the
|
|
125
|
+
function's stdout (captured by `$(…)` at every call site) and a curl
|
|
126
|
+
`Authorization` header; neither script uses `set -x`; `secret-get.mjs` writes the
|
|
127
|
+
value to stdout only (single write, no trailing newline), diagnostics to stderr
|
|
128
|
+
(redirected to /dev/null here), and reads nothing from stdin — no prompt, no hang
|
|
129
|
+
path (python3 `-c` likewise cannot prompt). The placeholder is a real JSON object
|
|
130
|
+
(`SecretMigrator` line 89: `{ secret: true }`), so `isinstance(v,str)` correctly
|
|
131
|
+
yields empty rather than a printed dict; the vault key path is exactly `authToken`
|
|
132
|
+
(KNOWN_SECRET_FIELDS), matching the script's argument. Trailing newlines are
|
|
133
|
+
stripped by command substitution at every caller. Guard placement is safe in both
|
|
134
|
+
scripts: setup runs `set -euo pipefail` and every failure inside the function is
|
|
135
|
+
absorbed (`|| echo ""`, `|| true`, and a false `[[ -f … ]]` inside `if` returns 0,
|
|
136
|
+
so the function always exits 0); the stop hook runs `set -uo pipefail` (no `-e`,
|
|
137
|
+
confirmed at line 26), where the same guards are harmless.
|
|
138
|
+
- **Registration branch:** empirically verified that a connection-refused curl under
|
|
139
|
+
`-s … -w '\n%{http_code}' … || echo ""` yields `REG_CODE=000` and an empty body —
|
|
140
|
+
never 401/403 — so an unreachable server still lands in the unchanged
|
|
141
|
+
"registration unavailable" path (also covered by the fourth setup test). The fatal
|
|
142
|
+
branch requires `RUN_STATUS == "preparing"`, which at that point can only come from
|
|
143
|
+
the pre-existing LOCAL enforcing resolution (a 401/403 body carries no
|
|
144
|
+
`initialStatus`), so only admission-enforcing installs abort. The whole block is
|
|
145
|
+
inside `if [[ -n "$REPORT_TOPIC" ]]` — empty-topic behaviour untouched.
|
|
146
|
+
- **COUNT pipefail fix:** empirically verified under `set -euo pipefail` that
|
|
147
|
+
`COUNT=$(ls … | grep -cv …) || true` captures grep's `0` stdout on zero matches
|
|
148
|
+
(assignment happens regardless of exit status) and counts correctly (2) when other
|
|
149
|
+
topics' state files exist; the cap comparison then proceeds normally.
|
|
150
|
+
- **Migrations:** both are idempotent (marker-presence early-return; re-run asserted
|
|
151
|
+
byte-identical in the tests). Ordering is sound: the earlier hook/setup bumps
|
|
152
|
+
deploy the CURRENT bundled bytes (which contain `VAULT_AUTH_RESOLVE`), so the new
|
|
153
|
+
migrations early-return after them; conversely a PREPARATION_CARRIER-era stock hook
|
|
154
|
+
no-ops through `upgradePreparationCarrier` (marker present) and is caught by the
|
|
155
|
+
new exact-hash gate. Verified the pinned SHA `72027309…` equals the hook blob at
|
|
156
|
+
HEAD/origin-main AND at every other carrier-era commit touching the file
|
|
157
|
+
(bc5453d32, f7ee6efc6, 4272bda3b — all byte-identical), and older stock bytes are
|
|
158
|
+
in the append-only allowlist, which the new upgrade also accepts — so no
|
|
159
|
+
legitimately-stock lineage is stranded; only genuinely customized/unknown bytes
|
|
160
|
+
are skipped, with a named `result.skipped` row (visible, not silent). Executable
|
|
161
|
+
bit: temp-file written `mode: 0o755` + rename (hook) and `chmodSync 0o755` (setup
|
|
162
|
+
helper); asserted in the tests. Label and skip strings in the code match the test
|
|
163
|
+
expectations exactly. Both new test files run green (9/9).
|
|
164
|
+
- **Artifact accuracy:** the replaced-read counts (3 setup + 8 hook) match the diff;
|
|
165
|
+
the enforcing-only fatality, unreachable-server preservation, no-new-authority,
|
|
166
|
+
and rollback claims all match the code. Bonus not claimed by the artifact: the
|
|
167
|
+
hook's verification leak-scrub now greps for the REAL token on vault-migrated
|
|
168
|
+
agents instead of the placeholder string — a strict improvement.
|
|
169
|
+
|
|
170
|
+
Minor notes (non-blocking):
|
|
171
|
+
|
|
172
|
+
1. §1's "everywhere else it prints and proceeds exactly as before" is right about
|
|
173
|
+
*proceeding*, but the printed text on a non-enforcing 401/403 changes from the
|
|
174
|
+
"registration unavailable" line to the new two-line ERROR — intended loudness,
|
|
175
|
+
just not literally "as before".
|
|
176
|
+
2. The new setup comment says the local cap fallback ran "whenever the server was
|
|
177
|
+
unreachable/refusing"; a *refusing* server that returns JSON (`{"error":…}`)
|
|
178
|
+
actually parses `allowed` as `None`, which skips the `unknown` fallback branch —
|
|
179
|
+
pre-existing behaviour, unchanged by this diff; only the comment's wording is
|
|
180
|
+
slightly broad.
|