instar 1.3.415 → 1.3.417

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.
@@ -0,0 +1,73 @@
1
+ # Side-Effects Review — lint: ban blocking process scans on the runtime hot path
2
+
3
+ **Version / slug:** `lint-no-blocking-process-scans`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `Echo`
6
+ **Tier:** 1 (a new CI lint + comment-only src annotations + a test; no behavior change, no API/route/config/migration)
7
+ **Second-pass reviewer:** `Echo (self) — Tier-1; preventive gate, no runtime behavior change`
8
+
9
+ ## Summary of the change
10
+
11
+ Adds `scripts/lint-no-blocking-process-scans.js` (wired into `npm run lint`): in
12
+ `src/monitoring/` and `src/server/`, a SYNCHRONOUS child-process call
13
+ (`spawnSync`/`execSync`/`execFileSync`) whose command literal is a process-
14
+ enumeration tool (`ps`/`pgrep`/`lsof`/`pkill`) now fails CI. This is post-mortem
15
+ standard #3 for the 2026-06-07 "server temporarily down" incident (topic 21816):
16
+ synchronous `ps`/`lsof` scans on a cadence blocked the event loop and starved
17
+ `/health` under load → the supervisor restarted an alive server → the loop.
18
+ #972 fixed SessionWatchdog; this lint stops the class from being re-introduced.
19
+
20
+ The two existing in-dir call sites are `lsof` one-shots, allowlisted with inline
21
+ `// lint-allow-blocking-scan:` justifications (comment-only edits):
22
+ - `SessionRecovery.ts` — targeted `lsof -p <pid>` (single process, 5s timeout),
23
+ runs once during a session's JSONL recovery, not on a cadence.
24
+ - `agentWorktreeGit.ts` — full-cwd `lsof` in AgentWorktreeReaper, which ships
25
+ dark + dry-run by default (not on any live agent's hot path); 15s timeout;
26
+ async conversion noted as a follow-up.
27
+
28
+ ## Decision-point inventory
29
+
30
+ - The only decision: which sync calls to fail CI on. Scoped to the documented
31
+ load-sensitive enumeration commands (`ps`/`pgrep`/`lsof`/`pkill`) in the two
32
+ runtime hot dirs. tmux/git calls are deliberately NOT covered (bounded, fast,
33
+ ubiquitous — converting them is a separate, bigger concern and not this
34
+ incident's cause).
35
+
36
+ ## 1. False positives (flagging a safe call)
37
+
38
+ A genuinely one-shot, bounded sync scan is excused by an inline
39
+ `// lint-allow-blocking-scan: <reason>` (scanned up to 6 lines above the call to
40
+ allow a multi-line justification). The escape hatch requires a written reason, so
41
+ the decision is reviewed, not silent. Two current sites use it.
42
+
43
+ ## 2. False negatives (missing a real one)
44
+
45
+ Static detection matches a string-literal command. A sync scan that passes the
46
+ command via a variable (e.g. `execFileSync(file, args)` in `mcpProcessReaperDeps`)
47
+ is not caught — accepted: the lint is a ratchet against the common, copy-pasted
48
+ literal form; the variable-indirection cases are pre-existing and tracked. tmux
49
+ is intentionally out of scope.
50
+
51
+ ## 3. Level-of-abstraction fit
52
+
53
+ Correct: a CI lint in the existing `lint-no-*` family, modeled on
54
+ `lint-no-unfunneled-headless-launch.js`. Structure > Willpower — a future periodic
55
+ `spawnSync('ps')` fails the build instead of being discovered as a stall in prod.
56
+
57
+ ## 4. Blast radius
58
+
59
+ CI-only. No runtime code changes (the two src edits are comments). Cannot affect a
60
+ running agent. Worst case of a bug in the lint = a spurious CI failure, fixed by an
61
+ allowlist comment or a lint tweak — never a production impact.
62
+
63
+ ## 5. Rollback
64
+
65
+ Remove the script + the one `package.json` chain entry; revert the two comment
66
+ annotations. No state/format change.
67
+
68
+ ## 6. Tests
69
+
70
+ `tests/unit/lint-no-blocking-process-scans.test.ts` (5): flags sync ps; flags
71
+ spawnSync pgrep + execSync lsof; honours the inline allow justification; ignores
72
+ comment-only mentions + async/tmux calls; the real runtime tree is clean. The lint
73
+ also self-validated against a synthetic violation. tsc clean.
@@ -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.