instar 1.3.416 → 1.3.418

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-07T23:08:24.008Z",
5
- "instarVersion": "1.3.416",
4
+ "generatedAt": "2026-06-07T23:51:53.400Z",
5
+ "instarVersion": "1.3.418",
6
6
  "entryCount": 199,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
14
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
23
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
32
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
41
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
50
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
59
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
68
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
77
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
86
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
95
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
104
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
113
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
122
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
131
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
140
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
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": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
149
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1538,7 +1538,7 @@
1538
1538
  "type": "subsystem",
1539
1539
  "domain": "updates",
1540
1540
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1541
- "contentHash": "b086e0a128b4785908844ebb86e015403fa5bbc4063b30f46f3dffd8333695bb",
1541
+ "contentHash": "d268663ca7bf97eeb12783de48762c8cd6b98f922cfc25d1c3bc5b3e6ac1cdd7",
1542
1542
  "since": "2025-01-01"
1543
1543
  },
1544
1544
  "subsystem:scheduler": {
@@ -519,7 +519,7 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
519
519
  - Cancel: \`curl -X DELETE -H "Authorization: Bearer $AUTH" http://localhost:${port}/secrets/pending/TOKEN\`
520
520
  - **Security**: One-time link, expires after 15 minutes, CSRF-protected. The moment a secret is SUBMITTED it is also persisted store-first to the durable AES-256-GCM encrypted SecretStore — so it survives session restarts, compaction, and cross-machine handoff instead of evaporating with the in-memory copy. Retrieval transparently falls back to the durable copy, and a successful consume deletes both. (Opt out with \`secrets.persistDrops: false\` in \`.instar/config.json\`.)
521
521
  - **Multi-field support**: Request multiple values at once by passing a \`fields\` array (e.g., username + password).
522
- - **When to use** (PROACTIVE this is the trigger): the moment a user offers to give you a credential (API key, password, token) or you realize you need one, use Secret Drop. It is the ONLY correct way to collect a secret. NEVER accept it pasted into Telegram or chat, and NEVER create a local file (e.g. \`.instar/secrets/foo.env\`) and ask the user to edit/paste into it that defeats the one-time, in-memory, never-on-disk guarantee and asks the user to edit files (which you must never do). Always issue a Secret Drop one-time link instead.
522
+ - **When to use — AGENT-RETRIEVES-FIRST; Secret Drop is the LAST resort** (PROACTIVE): When you need a credential, FIRST try to fetch it yourself from an account or service you already have access to — your encrypted vault (\`secret-get.mjs\`), a Vercel project you can read (\`vercel env pull\`), GitHub (\`gh\`), a cloud console, etc. You have full account access and standing operator approval; a secret already sitting in one of your own accounts is yours to fetch — do NOT make the user produce it. Use Secret Drop ONLY when you genuinely cannot reach the secret yourself (an operator-only credential the user actually holds). Even then, never assume the user has it on hand: either mint the one-time Secret Drop link, OR walk them through obtaining it in a mobile-friendly, step-by-step way. When a user proactively OFFERS a credential, Secret Drop is the correct way to collect it NEVER accept it pasted into Telegram or chat, and NEVER create a local file (e.g. \`.instar/secrets/foo.env\`) and ask the user to edit/paste into it (that defeats the one-time, in-memory, never-on-disk guarantee and asks the user to edit files, which you must never do). The anti-pattern this corrects (2026-06-07 UX violation): issuing a Secret Drop for a webhook secret that was readable from the operator's OWN Vercel project — the agent should have pulled it itself instead of asking.
523
523
 
524
524
  **Session Boot Self-Knowledge** — Your session-start context includes an auto-injected \`<session-self-knowledge>\` block: the NAMES of secrets in your encrypted vault (never values) + self-asserted operational facts about this agent/machine. (Rides the developmentAgent gate until the fleet flip.)
525
525
  - **The rule**: a secret named in your boot block is ALREADY in your vault — retrieve it with \`node .instar/scripts/secret-get.mjs <name>\` (pipe stdout straight into the consuming command, e.g. \`... github_token | gh auth login --with-token\` — NEVER echo the value into chat/transcripts) instead of asking the user to re-send it. Only re-ask if you have evidence it is invalid (expired/revoked/decrypt-failed).
@@ -0,0 +1,24 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The CLAUDE.md Secret Drop guidance now defaults to **agent-retrieves-first**: when an agent needs a credential, it first tries to fetch it itself from an account/service it already has access to (the encrypted vault, a Vercel project via `vercel env pull`, GitHub via `gh`, a cloud console). Secret Drop — or asking the user — is now the **last resort**, used only when the secret genuinely lives somewhere the agent cannot reach, and even then mobile-friendly and step-by-step. The prior wording told agents Secret Drop was "the ONLY correct way to collect a secret … the moment you realize you need one," which threw avoidable work at the user for secrets the agent could fetch itself. When a user proactively *offers* a credential, Secret Drop remains the correct collection mechanism.
9
+
10
+ Applied to all three Migration-Parity surfaces — the template (new inits), the migrator inject-block (agents missing the section), and a new idempotent content-sniff patch that rewrites the old harmful trigger for already-deployed agents.
11
+
12
+ ## What to Tell Your User
13
+
14
+ Nothing you need to do. Behind the scenes, your agent now fetches secrets it can already reach on its own instead of asking you for them — so you should get fewer "please submit this secret" prompts for credentials that live in accounts the agent can access. It will still ask you (securely) only when a secret genuinely isn't reachable any other way.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ No new endpoint, command, or config. A standards/guidance correction: agents default to retrieving secrets themselves; Secret Drop is the documented last resort.
19
+
20
+ ## Evidence
21
+
22
+ - 21/21 unit tests green in `tests/unit/PostUpdateMigrator-secretDropHardenedRetrieve.test.ts` (3 new: trigger-rewrite, idempotent, fresh-inject-carries-new-wording; 18 pre-existing unchanged). `npx tsc --noEmit` clean.
23
+ - Origin (causal autopsy): **process-gap** — the wrong default was baked into the template/standard, so every agent inherited it. Live trigger: a Secret Drop issued for `INSTAR_WEBHOOK_SECRET` that was readable from the operator's own Vercel project (`the-portal`), flagged by the operator as a UX violation (2026-06-07, topic 12476).
24
+ - Migration Parity verified across template + inject-block + existing-agent content-sniff patch.
@@ -0,0 +1,47 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Adds a **boot health beacon** — the durable cure for the 2026-06-07 "server
9
+ temporarily down" restart loop (topic 21816 root cause #1, "Liveness Before Load").
10
+ The server boot loads large TopicMemory/SemanticMemory + reconciles sessions BEFORE
11
+ AgentServer binds its port, so for minutes nothing answers `/health` and the
12
+ supervisor can mistake a slow boot for a dead process → restart-before-boot loop.
13
+
14
+ `BootHealthBeacon` (`src/server/BootHealthBeacon.ts`) is a minimal HTTP listener
15
+ that answers `/health` from the very start of boot and is closed at the handoff
16
+ just before the real server binds (force-closing sockets so there's no EADDRINUSE).
17
+ Wired in `commands/server.ts`, gated by `monitoring.bootHealthBeacon.enabled`
18
+ (default OFF). The startupGrace bump (#979) covers the window until this is enabled.
19
+
20
+ ## What to Tell Your User
21
+
22
+ If an agent ever sat in a restart loop right after an update on a busy machine,
23
+ showing "server temporarily down" — this is the deeper, permanent fix: the server
24
+ now (when enabled) reports it's alive from the first second of boot, so a slow
25
+ startup can't be mistaken for a crash. Ships off; rolled out carefully.
26
+
27
+ ## Summary of New Capabilities
28
+
29
+ - `monitoring.bootHealthBeacon.enabled` (default false): when true, a minimal
30
+ `/health` responder answers during boot and hands the port to the real server at
31
+ listen time. Off ⇒ no behavior change.
32
+
33
+ ## Evidence
34
+
35
+ `tests/unit/BootHealthBeacon.test.ts` (4 tests, all passing — incl. the port
36
+ handoff). `tsc --noEmit` clean. Boot wiring placed in the universal foreground boot
37
+ path (daemon re-execs into `--foreground`, verified). causalAutopsy: latent — the
38
+ health-bound-after-heavy-load boot order was always present, harmful only once
39
+ memory/session volume on a loaded box pushed boot past the supervisor's window.
40
+
41
+ ## Scope (honest)
42
+
43
+ Ships DARK (default off) — zero behavior change until enabled. Additive: a new
44
+ isolated module + an import + two guarded blocks in the boot + an optional config
45
+ field. NOT a risky whole-boot reorder. The interim grace bump (#979) already
46
+ stopped the live loop; this is the durable belt-and-suspenders. Live canary
47
+ verification (flag on, watch /health during a real boot) is the rollout step.
@@ -0,0 +1,79 @@
1
+ # Side-Effects Review — health-first boot (boot health beacon)
2
+
3
+ **Version / slug:** `health-first-boot`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `Echo`
6
+ **Tier:** 1 (ships DARK behind `monitoring.bootHealthBeacon.enabled`, default OFF — zero behavior change until enabled; additive; both-sides tested)
7
+ **Second-pass reviewer:** `Echo (self) — Tier-1; dark/off-by-default, additive, isolated module; the boot-wiring placement was carefully traced (foreground/daemon fork resolved)`
8
+
9
+ ## Summary of the change
10
+
11
+ The durable cure for the 2026-06-07 "server temporarily down" restart loop (topic
12
+ 21816, root cause #1 — "Liveness Before Load"). The server boot loads large
13
+ TopicMemory/SemanticMemory + reconciles dozens of sessions BEFORE AgentServer
14
+ binds its port, so for ~5-6 min under load nothing answers `/health` and the
15
+ supervisor can mistake a slow boot for a dead process → restart-before-boot loop.
16
+
17
+ Adds `BootHealthBeacon` (`src/server/BootHealthBeacon.ts`): a minimal HTTP listener
18
+ that answers `/health` 200 (and 503 `warming` to everything else) from the very
19
+ start of boot. Wired in `commands/server.ts`: started right after `setupServerLog`
20
+ (early, common/universal boot path — daemon mode re-execs into `--foreground`,
21
+ verified at server.ts:12463), and **closed at the handoff immediately before**
22
+ `server.start()` (AgentServer's listen). `stop()` force-closes lingering sockets +
23
+ awaits the socket close, so the real `listen` cannot hit EADDRINUSE and the gap is
24
+ sub-second. Config flag `monitoring.bootHealthBeacon.enabled` (default OFF) +
25
+ type + ConfigDefaults. The startupGrace bump (#979) covers the window until this is
26
+ turned on.
27
+
28
+ ## Decision-point inventory
29
+
30
+ - Enabled? `monitoring.bootHealthBeacon.enabled` — default OFF; absent ⇒ off (read
31
+ via optional chaining). The only gate.
32
+ - Where to start/stop the beacon (boot-order placement) — the load-bearing
33
+ decision; see Blast radius.
34
+
35
+ ## 1. Beacon fails to start
36
+
37
+ Wrapped in try/catch — non-fatal. Boot proceeds without the beacon (the grace bump
38
+ still covers the window). The server is never blocked from booting by a beacon
39
+ problem. Both guards (start + stop) log the error and are marked
40
+ `@silent-fallback-ok` (intentional best-effort fallback, not a silent swallow) so
41
+ the no-silent-fallbacks ratchet stays at its baseline.
42
+
43
+ ## 2. Handoff race (EADDRINUSE on the real listen)
44
+
45
+ `stop()` calls `server.close()` AND `closeAllConnections()` and awaits the `close`
46
+ event, so the port is released before `server.start()` binds it. `keepAliveTimeout=1`
47
+ prevents an idle keep-alive socket from holding the port. The unit test asserts a
48
+ real server can bind the same port immediately after `stop()`. The `stop()` call is
49
+ also try/caught so a stop failure still lets the real server attempt to bind.
50
+
51
+ ## 3. Wrong boot-order placement (silent no-op)
52
+
53
+ The start is placed in the **common** boot path: the `if (options.foreground)`
54
+ block is the universal server boot — daemon mode spawns the server with
55
+ `--foreground` (server.ts:12463), so every real server runs it. `bootBeacon` is
56
+ declared at the foreground-block body scope (indent-4), in scope at both the start
57
+ (after setupServerLog) and the stop (before server.start at the same scope). Started
58
+ before the heavy memory/session loads, so it covers the whole window.
59
+
60
+ ## 4. Blast radius
61
+
62
+ DARK (default off) ⇒ zero behavior change for every existing and new agent until the
63
+ flag is explicitly set. When enabled: one extra short-lived HTTP listener during
64
+ boot that is closed before the real server binds. It only ever *adds* a liveness
65
+ answer during boot; it cannot make a healthy server look unhealthy. Rollout:
66
+ dark → canary on Echo (flip flag, watch one boot) → fleet.
67
+
68
+ ## 5. Rollback
69
+
70
+ Set the flag off (or absent) ⇒ fully inert. Code revert is clean (new module + an
71
+ import + two guarded blocks + an optional config field). No state/format change.
72
+
73
+ ## 6. Tests
74
+
75
+ `tests/unit/BootHealthBeacon.test.ts` (4): /health→200 ok while booting; everything
76
+ else→503 warming; **stop() releases the port so a real server binds it immediately**
77
+ (the handoff); start/stop idempotent. tsc clean. The boot wiring is exercised by the
78
+ existing server e2e on the default (off) path (no behavior change); live canary
79
+ verification (flag on, observe /health during a real boot) is the rollout step.
@@ -0,0 +1,24 @@
1
+ # Side-Effects Review — Secret-Retrieval-First Standard
2
+
3
+ **Version / slug:** `secret-retrieval-first-standard`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `echo`
6
+ **Tier:** `1` (docs/template + idempotent migration; no runtime behavior, no deps/routes/stores)
7
+ **Second-pass reviewer:** `not-required (Tier-1 guidance/template change; correctness self-owned + covered by 3 unit tests)`
8
+
9
+ ## Summary of the change
10
+ Inverts the CLAUDE.md Secret Drop "When to use" guidance from "use Secret Drop the moment you need a credential — the ONLY correct way" to **agent-retrieves-first; Secret Drop is the last resort**. Applied across all three Migration-Parity surfaces: the template (`generateClaudeMd`), the migrator inject-block (agents missing the section), and a new content-sniff patch in `migrateClaudeMd` that rewrites the harmful trigger for already-deployed agents.
11
+
12
+ Files: `src/scaffold/templates.ts` (template guidance), `src/core/PostUpdateMigrator.ts` (inject-block text + new content-sniff patch), `tests/unit/PostUpdateMigrator-secretDropHardenedRetrieve.test.ts` (+3 tests), `docs/specs/secret-retrieval-first-standard.md` (+ .eli16).
13
+
14
+ ## Decision-point inventory
15
+ - **Runtime behavior change?** None. This is agent-facing guidance text only — no code path, route, store, config, or scheduler is touched. Secret Drop itself (endpoints, retrieve script, durability) is unchanged.
16
+ - **New dependency / state / route / config?** None → trips none of the SqliteRegistry-wiring / feature-delivery-completeness / docs-coverage(new-class) guard classes.
17
+ - **Migration parity?** Satisfied on all three surfaces (template for new inits; inject-block for agents lacking the section; content-sniff patch for agents with the old section). The content-sniff patch is **idempotent** — it anchors on the stable old phrase `It is the ONLY correct way to collect a secret.` and skips once `AGENT-RETRIEVES-FIRST` / the new wording is present. Unit-tested (rewrite / idempotent / fresh-inject).
18
+ - **Silent fallbacks?** None added. No new `try/catch`; pure string edits + one guarded `content.replace`.
19
+ - **Shadow-capability slicer (AGENTS.md for Codex/Gemini)?** Inherits the corrected CLAUDE.md text automatically (the slicer copies sections from CLAUDE.md) — no separate edit needed; this is a positive side-effect (shadows stop carrying the wrong default too).
20
+ - **Secret-handling safety baked into the new guidance:** explicitly tells agents to extract only the needed var, never print the value, and delete multi-secret temp files immediately — codifying the safe-retrieval discipline I followed pulling the value from `the-portal` env.
21
+ - **Rollback?** Trivial — revert the three edits; guidance returns to prior wording, no state to unwind.
22
+
23
+ ## Why ship
24
+ A wrong default in the template propagates to every agent (and every shadow). Justin flagged it as a UX violation (2026-06-07) and directed the standards amendment. Fixing it in the artifact agents read — not by per-agent willpower — is the Structure > Willpower path.