agent-bios 0.13.0 → 0.15.0

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.
Files changed (36) hide show
  1. package/README.md +2 -2
  2. package/claude/CLAUDE.md +8 -8
  3. package/claude/guides/claude-prompting.md +59 -7
  4. package/claude/guides/cli-multi-model-workflow.md +6 -1
  5. package/claude/guides/coding-staged-workflow.md +12 -0
  6. package/claude/guides/gpt-prompting.md +60 -4
  7. package/claude/guides/learning-flow.md +4 -1
  8. package/claude/guides/llm-capability-boundary-patterns.md +8 -0
  9. package/claude/guides/review-request.md +13 -0
  10. package/claude/guides/session-distill-workflow.md +21 -9
  11. package/claude/guides/tooling-gotchas.md +181 -14
  12. package/claude/guides/verification-discipline.md +71 -3
  13. package/claude/hooks/tooling-gotchas-hook.py +50 -0
  14. package/codex/AGENTS.md +8 -8
  15. package/codex/guides/claude-prompting.md +59 -7
  16. package/codex/guides/cli-multi-model-workflow.md +6 -1
  17. package/codex/guides/coding-staged-workflow.md +12 -0
  18. package/codex/guides/gpt-prompting.md +60 -4
  19. package/codex/guides/learning-flow.md +4 -1
  20. package/codex/guides/llm-capability-boundary-patterns.md +8 -0
  21. package/codex/guides/review-request.md +13 -0
  22. package/codex/guides/session-distill-workflow.md +21 -9
  23. package/codex/guides/tooling-gotchas.md +181 -14
  24. package/codex/guides/verification-discipline.md +71 -3
  25. package/compose/corpus-state.py +1170 -0
  26. package/compose/write-update-cache.py +53 -0
  27. package/install.sh +198 -11
  28. package/launch/agent-launch.py +112 -6
  29. package/launch/agent-launch.zsh +109 -6
  30. package/launch/i18n/en.toml +1 -0
  31. package/launch/i18n/ja.toml +1 -0
  32. package/launch/i18n/ko.toml +1 -0
  33. package/learn/collect-learning.py +593 -62
  34. package/learn/redact.py +2 -1
  35. package/package.json +4 -2
  36. package/provenance.json +1 -1
@@ -15,6 +15,14 @@ core_rules:
15
15
  - make tool descriptions prescriptive about when to call, not only what the tool does
16
16
  - require progress claims to be audited against a tool result from the same session
17
17
  - name the boundary explicitly — what to do without asking, and what to stop and ask about
18
+ derived_at: 2026-09-01
19
+ source_pins:
20
+ - doc: prompting-claude-opus-5
21
+ sha256: 65be3e0b437cbe23cc41bb4f9b7a5031c5a71cd49ab91ec4d19c62738762b086
22
+ pinned_at: 2026-09-01
23
+ - doc: claude-prompting-best-practices
24
+ sha256: 476ddc2744812dced0b520c8f628aecb52df52babdaf82ee5a0b10f25f5bcbdb
25
+ pinned_at: 2026-09-01
18
26
  targets:
19
27
  - claude-fable-5
20
28
  - claude-opus-5
@@ -68,7 +76,12 @@ pick the path.
68
76
  - Delegation: say when *not* to delegate, and cap the spawn count. The helm
69
77
  binding reaches for subagents readily — the reverse of the binding it replaced
70
78
  — and every spawn rebuilds context, reports back, and is then re-read, so
71
- unbounded delegation multiplies cost and latency. File-based memory and custom
79
+ unbounded delegation multiplies cost and latency. Where the harness offers
80
+ deterministic caps, prefer them to prose: under Claude Code and the Agent SDK
81
+ these are `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`,
82
+ `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`, and the SDK's `max_budget_usd` — a
83
+ limit the model cannot talk itself past. Confirm the harness version supports
84
+ them before relying on it. File-based memory and custom
72
85
  tools are the opposite case: they still need an explicit when-to-use trigger.
73
86
  - Autonomous runs with no human watching: say so. Otherwise it asks permission
74
87
  it does not need and blocks. Grant autonomy on minor choices (naming,
@@ -107,7 +120,9 @@ pick the path.
107
120
  treating a quiet call as a hang.
108
121
  - Do not add "summarize every N tool calls" scaffolding — this tier narrates on
109
122
  its own. If it narrates too much for a coding agent, set a silence default
110
- instead: text only on a finding, a direction change, or a blocker.
123
+ instead: text only on a finding, a direction change, or a blocker. Describe the
124
+ cadence you want by example; a positive description of the style outperforms a
125
+ list of what not to do.
111
126
  - Length is a prompting lever, not an effort lever. This tier writes longer
112
127
  answers and longer files than its predecessors, and lowering `effort` does not
113
128
  reliably shorten visible output — only an explicit instruction does. Calibrate
@@ -121,6 +136,36 @@ pick the path.
121
136
  work they did not watch. Lead with the outcome; drop the working shorthand.
122
137
  - Do not show a remaining-context countdown. This tier can start conserving and
123
138
  suggest a fresh session instead of finishing.
139
+ - Re-validate prompt-side vision workarounds carried from older bindings; this
140
+ tier is strong on charts, documents, diagrams, and UI replication, and the
141
+ workaround may now be the thing costing quality. Tools that let it crop and
142
+ visually verify beat thinking alone here.
143
+ - Instruction following stays consistent across the full context window, so a
144
+ rule does not need restating near the end to survive a long session.
145
+
146
+ ## Running with thinking disabled
147
+
148
+ Disabling thinking is accepted only at `high` effort or below, and it is usually
149
+ the wrong lever: thinking on at `low` effort generally beats thinking off at
150
+ comparable cost. Reach for lower effort before reaching for the switch.
151
+
152
+ Two artifacts appear when it is off, and both are prompt-fixable:
153
+
154
+ - A tool call written as **user-facing text** instead of a structured call. The
155
+ turn completes, the call never runs, and in an agentic loop the leaked text
156
+ stays in history and contaminates later turns. Most common on tool-heavy work.
157
+ - Internal XML tags leaking into the visible response.
158
+
159
+ One instruction mitigates both — permission to speak before a call, an out when
160
+ no tool fits, and a general ban on internal tags:
161
+
162
+ > When you use a tool, you may say a brief sentence first. If no tool can express
163
+ > what the user asked for, say so instead of guessing. Do not include internal or
164
+ > system XML tags in your response.
165
+
166
+ Two traps. Naming the tags specifically is **less** effective than the general
167
+ form. And if a prompt anywhere tells this tier not to think or not to reason,
168
+ delete it: that instruction increases tag leakage rather than suppressing it.
124
169
 
125
170
  ## Prompt assembly checklist
126
171
 
@@ -134,8 +179,15 @@ pick the path.
134
179
 
135
180
  ## Sources
136
181
 
137
- Derived from the vendor's published guidance for the `targets` models above.
138
- When a `targets` model changes, re-derive this guide from current vendor
139
- guidance rather than editing around the old rules prompting guidance is
140
- version-bound. `launch/check-prompting-targets.sh` fails when the launch config
141
- binds a model this guide does not list.
182
+ Derived from the vendor's `prompting-claude-opus-5` and
183
+ `claude-prompting-best-practices` documents, at the exact bytes whose hashes are
184
+ recorded in `source_pins` above. The pin is what makes a later vendor edit
185
+ detectable rather than remembered.
186
+
187
+ Prompting guidance is version-bound — this generation inverted advice the last one
188
+ gave — so when a `targets` model changes, re-derive from the current documents
189
+ rather than editing around the old rules.
190
+ `launch/check-prompting-targets.sh` fails when the launch config binds a model
191
+ this guide does not list; that check is about **naming**, and a model added to
192
+ `targets:` satisfies it forever. Whether the guidance was actually re-derived is
193
+ not decidable and is gated nowhere.
@@ -106,7 +106,7 @@ Instruction/config reach is per invocation. A rule in AGENTS.md cannot bind a he
106
106
  - Run deterministic gates before LLM review. Funnel SWEEP finders → WORKHORSE judgments → FRONTIER triage/verdicts.
107
107
  - On family collapse, record the downgrade and label clean verdicts PROPOSED until diversity is restored.
108
108
  - A silent/dead lens is incomplete, never clean. Confirm liveness from usage/error/report evidence; rerun, swap provider, or report PROPOSED.
109
- - Kind labels do not guarantee distinct backends: wrappers and rate-limit fallbacks can silently route two "different-kind" verifiers to the same model/provider. Before trusting diversity on a high-stakes verdict, confirm each verifier's actual backing model from live process or usage evidence; on collapse, treat the pair as one kind and label PROPOSED.
109
+ - Kind labels do not guarantee distinct backends: wrappers and rate-limit fallbacks can silently route two "different-kind" verifiers to the same model/provider. Before trusting diversity on a high-stakes verdict, confirm each verifier's actual backing model from live process or usage evidence; on collapse, treat the pair as one kind and label PROPOSED. Runners recording what ran need the same read: identity taken from the target at execution time, never a runner-side literal, and asserted equal to what was requested — fallback seats pass existence checks.
110
110
 
111
111
  ### Review Independence
112
112
 
@@ -124,6 +124,7 @@ How much independence a review actually bought, as an ordinal grade per reviewer
124
124
  - The floor still requires **at least two distinct perspectives**; one pass on the main's own seat is self-review with extra steps.
125
125
  - Multiple ready methods are **coverage, not diversity**. Distinct labels do not prove the perspectives differed.
126
126
  - **Achieved is not available.** What can be projected before a review runs is `projected`; a clean verdict without a receipt evidencing a fresh dispatch, the declared packet, a non-empty result and the exact seat is `PROPOSED`, never ACHIEVED. A model echo is not a receipt.
127
+ - **Evidence access is its own axis.** When every reviewer saw only the blind packet, convergence — even across providers — is evidence about the packet's framing, omissions included. Before adopting a converged verdict resting on a code seat, a measured fact, or a constraint list, route one seat with live read access to falsify those facts: a lone dissent citing a real constraint outweighs a blind majority, and the missing fact returns to the packet. It sits beside the ladder, not on it.
127
128
 
128
129
  ## Dual-Provider Design Drafts
129
130
 
@@ -136,11 +137,14 @@ How much independence a review actually bought, as an ordinal grade per reviewer
136
137
  - The parent owns per-item completion and a **code-level circuit breaker**. For dispatchers you do not control, verify equivalent protection or attend the run.
137
138
  - Default breaker: halt after 3 consecutive cross-item provider limit/auth/transport failures after bounded backoff. Persist undone items and alert or swap provider.
138
139
  - Item-specific failures are poison items: cap at 2–3 attempts, then dead-letter them as complete-with-failure. Resume only unfinished/invalid items; whole-batch reruns require cheap idempotence.
140
+ - An enumeration run is done only when its collected count is asserted against the source's own reported total for the same filter. Classify retriable failures by class — any server-side transient — rather than an enumerated code list, since an omitted code drops items silently; persist which batches failed and reconcile them before declaring completion; and treat a mismatch, or a total from a differently scoped population, as a defect rather than a footnote. A declared partial or sampled scope is outside this.
139
141
  - Persist per-item outcome, token, and cost records for recalibration.
142
+ - Before releasing a metered batch past its first item, use that item to probe the batch machinery, not the item logic: run it end to end through the real runner to its side effect, then confirm every value the later analysis depends on — treatment knob, run identity, cost — reached the persisted record through the expected channel. On the first failures read raw run logs, not the runner's status classifier, which infers causes from missing outputs. A cheap idempotent batch needs no gate.
140
143
 
141
144
  ## Halt And Resume
142
145
 
143
146
  - Resume-first from artifacts that parse, pass schema, and match their recorded source/config/HEAD fingerprint; unverifiable means invalid.
147
+ - A cache-hit or fingerprint predicate must cover every value that shapes the artifact's content — the upstream input's content identity, caps, templates, model ids, config — never existence, mtime, or size alone; when adding a new output-shaping value, inspect the key's pre-image in the same change and assert the key moves when the value moves. Before re-running because an upstream input changed, invalidate intermediates whose predicate omits that input's identity: a regenerate over existence-keyed caches re-derives from the old input.
144
148
  - Resubmit one invalid unit unless failures are broadly correlated, which is structural and halts the run.
145
149
  - Treat halt→continue as normal operation.
146
150
  - Treat tool-managed temp/cache output locations as ephemeral — they are garbage-collected on the tool's own schedule. Copy any artifact a pending or handed-off decision depends on into a project-owned durable path before relying on it later.
@@ -150,6 +154,7 @@ How much independence a review actually bought, as an ordinal grade per reviewer
150
154
 
151
155
  - Sessions bind to their starting directory. Use the CLI's native relocation/resume mechanism; never copy transcript files.
152
156
  - For a new worktree, relocate natively or write a handoff and start fresh. Re-integrate branches serially and re-verify after each merge.
157
+ - A conflict-free merge with a green build is evidence about text, not placement. When the base side restructured the surrounding code — regrouped sections, split modules, new per-variant containers — locate each merged addition in the new structure and confirm its scope still matches its container's: a global setting must not sit inside a variant-specific container, and no duplicate or orphaned copy may remain. A merge onto an unchanged layout needs only the ordinary green-state check.
153
158
  - Mark superseded worktrees/handoffs dead so later resume cannot select them.
154
159
  - After resume/clear/relocation, verify pwd, branch, and HEAD against the pinned handoff before acting.
155
160
  - Attribute a parallel session's action (commit, branch, resource) by execution evidence in that session's own transcript, never by token mentions — shared handoff/memory files inject the same tokens into every session's context.
@@ -75,6 +75,18 @@ patching downstream: compensating code keeps accumulating around bad inputs, and
75
75
  another instance of the same defect. The first says go upstream to where the value is produced.
76
76
  The second says the instances are a class — single-source the value and fix the class, because
77
77
  patching them one at a time is a queue that refills.
78
+ **Supplying a missing shared dependency wakes every consumer, not just the one you are fixing.** When
79
+ a repair supplies a value many paths read and that was absent — a secret, a packaged file —
80
+ enumerate those consumers and say what each starts doing: metered calls, external writes,
81
+ user-visible output. Where that onset exceeds the feature under repair, hand the list to the owner
82
+ as a decision, not a line in the fix. Consumers that are all read-only and free need no gate.
83
+
84
+ **Measure a flip before you design its activation.** When a version bump, default change, or
85
+ severity re-mapping is coming, flip it, run the full suite, classify every failure (cascade,
86
+ pinned control, true detection, real regression), and restore — that count is the activation's
87
+ blast radius. Re-mapping a level obliges enumerating every reader of that field, since one level
88
+ commonly gates shipping, repair, retry, and display at once. A deferred defect is pinned as a
89
+ strict expected failure, never a silent pass.
78
90
 
79
91
  ## Review Loop
80
92
 
@@ -15,6 +15,14 @@ core_rules:
15
15
  - replace blanket ALWAYS/NEVER with decision rules naming the condition each choice applies under
16
16
  - fix the prompt before raising effort — weak output usually means a missing success criterion, dependency rule, tool-routing rule, or verification loop
17
17
  - prompting habits carried from older gpt models cost tokens and can cost accuracy
18
+ derived_at: 2026-09-01
19
+ source_pins:
20
+ - doc: prompt-guidance-gpt-5p6
21
+ sha256: 46181efec9fd1160ef537b0379282a14c1ba32380f2f8149a805128253c1115a
22
+ pinned_at: 2026-09-01
23
+ - doc: latest-model
24
+ sha256: 48f61f648eab971334f6076bc61478d0f2bcd7a50111064722eba267a0f98d61
25
+ pinned_at: 2026-09-01
18
26
  targets:
19
27
  - gpt-5.6-sol
20
28
  - gpt-5.6-terra
@@ -85,9 +93,50 @@ Compose in this order; omit any block that would not change the artifact.
85
93
  - Prefer a self-contained packet over resuming a long history: it is cheaper to
86
94
  reason about and cheaper to cache.
87
95
 
96
+ ## Programmatic tool calling
97
+
98
+ A bounded stage where code processes several tool results and returns a much smaller
99
+ structured result. The qualifier is **reduction**, not parallelism: multiple, parallel,
100
+ or dependent calls alone do not justify it.
101
+
102
+ - Use it for filtering, joining, sorting, ranking, deduplication and aggregation;
103
+ batching across many similar records; repeated deterministic validation; and large
104
+ structured results reducible to a compact schema.
105
+ - Prefer direct calls when one call suffices, when intermediate outputs are already
106
+ small, when each result may change the next decision, when an action needs approval,
107
+ when the answer must preserve citations or native artifacts, or when semantic
108
+ judgment sits between calls.
109
+ - A generic "use programmatic tool calling efficiently" does nothing. State the bounded
110
+ stage, the eligible tools, the output schema, the retry limit, the stop condition, and
111
+ the handoff back to direct judgment. If both routes are needed, define one handoff and
112
+ say not to switch routes or repeat completed work.
113
+ - **Test both outputs.** The program's result and the final assistant message are
114
+ separate; a program can return the right records while the message drops a required
115
+ field, citation, or caveat.
116
+ - Compare the two routes on the same tasks, and count lower token/latency/cost as an
117
+ improvement only when the response still passes the existing evals.
118
+
88
119
  ## Working rules
89
120
 
90
121
  - One clear task per run, with an explicit output contract.
122
+ - **Read the assembled prompt for contradictions.** This tier follows a prompt contract
123
+ closely, so two rules that disagree destabilize it more than a missing rule does —
124
+ the opposite of the intuition that more instruction is safer.
125
+ - State each authority rule once. Repeating "ask first", "do not mutate", or "wait for
126
+ approval" produces approval requests for safe, expected actions.
127
+ - Name the current layer of work — research, design, implementation, review, external
128
+ coordination — on long-running tasks, so the model does not move between layers
129
+ silently.
130
+ - Persisted reasoning is not a free optimization. It helps while the objective and
131
+ priorities hold; once they move, stale reasoning adds tokens and anchors the model to
132
+ a superseded approach. Compact at milestones, not every turn, and treat compacted
133
+ items as opaque.
134
+ - Set the default detail level through the API (`text.verbosity`) and keep the prompt
135
+ for task-specific length and structure; a prompt-only length rule has to be restated
136
+ everywhere.
137
+ - Preserve explicit user values. Where the right value is implicit, give decision
138
+ criteria and let the model reason from context or schema rather than installing
139
+ universal defaults or keyword maps.
91
140
  - Keep reusable prefixes stable and avoid churn in large system prompts. Add
92
141
  explicit cache breakpoints only where they measurably improve cache behavior —
93
142
  a cache write costs 1.25× the uncached input rate, so read the cached-token
@@ -110,9 +159,16 @@ Compose in this order; omit any block that would not change the artifact.
110
159
 
111
160
  ## Sources
112
161
 
113
- Derived from the vendor's published prompting guidance for the `targets` models
114
- above. When a `targets` model changes, re-derive this guide from current vendor
115
- guidance rather than editing around the old rules prompting guidance is
116
- version-bound, and the previous generation's advice inverted on this one.
162
+ Derived from the vendor's `prompt-guidance-gpt-5p6` and `latest-model`
163
+ documents, at the exact bytes whose hashes are recorded in `source_pins` above.
164
+ The pin is what makes a later vendor edit detectable rather than remembered.
165
+
166
+ Prompting guidance is version-bound and the previous generation's advice inverted
167
+ on this one, so when a `targets` model changes, re-derive from the current
168
+ documents rather than editing around the old rules.
169
+ `launch/check-prompting-targets.sh` fails when the launch config binds a model
170
+ this guide does not list; that check is about **naming**, and a model added to
171
+ `targets:` satisfies it forever. Whether the guidance was actually re-derived is
172
+ not decidable and is gated nowhere.
117
173
  `launch/check-prompting-targets.sh` fails when the launch config binds a model
118
174
  this guide does not list.
@@ -103,4 +103,7 @@ payload — do not work around the validation.
103
103
  - Single-session capture only; cross-session mining is `distill!` (curator).
104
104
  - Mechanization (hook/gate/enforcement) is deferred to curation — record intent, don't build it.
105
105
  - Type-G principle manufacture is curator-only.
106
- - Transport (upload to the org) lands in Phase 2; Phase 1 writes locally.
106
+ - Transport (upload to the org) is best-effort after the local write: it runs only
107
+ when the `~/.config/agent-bios/{ingest-url,token}` slot is set, which is the
108
+ only source there is. A default install sets nothing, so nothing leaves the
109
+ machine; an org fills the slot through its own wrapper.
@@ -314,6 +314,14 @@ Retries are safe for pure generation and validation. They are not automatically
314
314
  safe for external side effects. Use idempotency keys, locks, duplicate detection,
315
315
  or compensation plans where needed.
316
316
 
317
+ A stage that can re-run on the same record must not read the field it writes.
318
+ On a re-run (reclassification, backfill, retry) an input field that is also
319
+ its output feeds the model its prior answer, and the value drifts from the
320
+ source silently. Keep the captured original immutable, write derived values to
321
+ their own field, and treat `original ?? current` as migration, not design.
322
+ Audit its siblings: one harmless only because its selection rule skips
323
+ overwritten rows is a latent instance.
324
+
317
325
  ## Single Source Of Truth And Schema Evolution
318
326
 
319
327
  Hybrid enforcement creates drift risk. A single constraint can appear in prompt
@@ -122,6 +122,12 @@ design; do not treat missing implementation as a defect." A session given exactl
122
122
  that instruction returned zero findings and proved it had looked, anchored on
123
123
  both sides of the comparison. A session not given it filed unimplemented code as
124
124
  blockers, and the user caught it manually.
125
+ The target also has a revision. Name the commit or content hash the packet
126
+ was dispatched on, and hold the artifact still until every reviewer on
127
+ that revision has returned. When a fix must land while a lens is still in
128
+ flight, map the returned findings against the pinned revision before
129
+ counting them: a finding whose anchor text no longer exists is stale,
130
+ closed by that mapping rather than re-fixed, and never tallied as open.
125
131
 
126
132
  ## Bundle the consumer, not just the artifact
127
133
 
@@ -226,6 +232,13 @@ Two consequences for anyone consuming a review:
226
232
  count was scoped to the material section, at which point 16% of the same
227
233
  findings turned out to have reached the reader explicitly flagged
228
234
  non-material. Read the verdict field, not the mention.
235
+ - Count the emitted item list against every total the harness reports —
236
+ findings count, verdict tally, per-item decision log — before triaging.
237
+ Zero findings is only the extreme case: any shortfall means items were
238
+ dropped in aggregation, and the dropped set is not random, since a merge
239
+ or filter tends to lose a whole class. Recover the difference from the
240
+ raw per-item record and triage the union; with no raw record the
241
+ deliverable is incomplete, not clean.
229
242
 
230
243
  ## Trust an empty result only when it cites what it checked
231
244
 
@@ -49,15 +49,27 @@ Run in order; each stage reads the previous stage's `out/`:
49
49
  Claude sidechain/sdk-cli/agentId).
50
50
  2. `digest.py` — one secret-redacted digest per session with deterministic
51
51
  6-criteria signals. Screen ALL digests; triage orders, never drops.
52
- 3. Provider-affine screening against the concatenated live baseline
53
- (CLAUDE.md + guides): `screen-claude.js` (Claude sessions) and
54
- `screen-codex.js` (Codex sessions), both dynamic-workflow scripts.
55
- Novelty is judged against real baseline text, not memory.
56
- 4. `consolidate.js`dedup + independent novelty verification. Rank by
57
- strength (recurrence × materiality), never by self-reported confidence.
58
- 5. `bundle_final.py` tiered bundle. Merge new candidates into
59
- `ledger.json` by cluster identity so recurrence accumulates across
60
- windows (incubated items promote when they re-occur).
52
+ 3. `batch.py` the baseline blob (`claude/CLAUDE.md` + every guide, the
53
+ repo's canonical corpus) and per-provider batches; writes
54
+ `out/batch_index.json`, which the screeners take as their `args`.
55
+ 4. Provider-affine screening against that baseline: `screen-claude.js`
56
+ (Claude sessions; a Workflow script pass the index as `args`, one
57
+ WORKHORSE screener per batch) and `screen-codex.py` (Codex sessions;
58
+ one hermetic read-only `codex exec` per batch, packet on stdin). Novelty
59
+ is judged against real baseline text, not memory. Then `collect.py`
60
+ unions the two outputs into `out/candidates-all.json` and fails when a
61
+ provider's screened set is smaller than its batch.
62
+ 5. `consolidate.js` (Workflow; `args` = baseline, candidates path, count,
63
+ and the ledger's `{id, lesson}` list) — dedup + independent novelty
64
+ verification, then a match pass naming which survivor recurs an
65
+ existing ledger entry. Rank by strength (recurrence × materiality),
66
+ never by self-reported confidence. Save its return value as
67
+ `out/consolidated.json`.
68
+ 6. `bundle_final.py` — tiered bundle. `merge-ledger.py --window-end <date>`
69
+ (dry-run; `--apply` writes) merges survivors into `ledger.json`: a
70
+ recurrence gains the window's sessions under `recurrence`, a new lesson
71
+ becomes a `candidate` entry — so recurrence accumulates across windows
72
+ and incubated items promote when they re-occur.
61
73
 
62
74
  ## Stage 2 — Review with the user
63
75
 
@@ -40,28 +40,47 @@ depends on it, pin it explicitly instead of trusting the environment.
40
40
  shells resolve functions/aliases first, programmatic spawns resolve raw
41
41
  PATH, and a same-named package can shadow a system tool with silent empty
42
42
  output. Before trusting a result across execution contexts, confirm the
43
- resolved target (`type -a`, absolute path).
43
+ resolved target (`type -a`, absolute path). A missing prefix wrapper fails
44
+ the same silent way — GNU `timeout` is routinely absent on BSD-derived
45
+ systems — so confirm the wrapper too.
44
46
  - **Cloud CLI context**: gcloud/aws/kubectl/terraform carry mutable ambient
45
47
  context (active project, profile, cluster) that drifts between sessions.
46
48
  Before the first environment-affecting command — or right after a resume —
47
49
  verify it against intent, then pin the target explicitly on every command
48
50
  (`--project`, `--profile`, `--context`) rather than fixing the global
49
- default once.
51
+ default once. A forge CLI (`gh`/`glab`) reads its repository from the
52
+ checkout's remotes too: with a fork plus an upstream it can answer for the
53
+ wrong repo, so pass `--repo` wherever the answer feeds a decision.
50
54
  - **Installed is not running**: a live process keeps its old code until
51
55
  restarted or reloaded. When confirming an update, config change, or
52
56
  dependency bump took effect, don't stop at the on-disk artifact — confirm
53
57
  the running process's actual version/behavior or force a restart.
58
+ - **Producer newer than consumer**: when a deployed binary validates an
59
+ artifact you produce (a signed config or manifest), produce and verify it
60
+ with the producer tooling checked out at the exact commit that binary was
61
+ built from — a local verify with current-tree tooling proves only that
62
+ newer tooling accepts it. Confirm the consumer's build commit from image
63
+ provenance, not the current branch; any version mismatch is a release
64
+ blocker. A consumer rebuilt from the same commit needs only ordinary
65
+ verification.
66
+ - **A dev-labelled datastore target is a claim**: a localhost URL or
67
+ exported override is no evidence of a non-production target — a local port
68
+ can proxy into the only real instance, and a tool's config loader can
69
+ re-load a dotenv over your exported value. Before the first writing
70
+ command (migration, seeder), print what the connection reaches from inside
71
+ the tool's own path and assert it is the intended target; where the loader
72
+ is untrustworthy, extract the DDL and apply it yourself.
54
73
 
55
74
  ## Shell execution traps
56
75
 
57
76
  - **Pipe exit masking**: `$?` after a pipeline reflects only the last stage;
58
- a real failure in the command under test is masked by a successful
59
- `tail`/`grep`/`jq` and reads as a false green. Capture the tested stage's
60
- own status: run it unpiped, store `$?` immediately, or use
61
- `set -o pipefail`/`PIPESTATUS` noting pipefail breaks legitimate
62
- early-exit consumers (`cmd | head -1` → SIGPIPE 141), so it is a per-command
63
- choice, not a global default. Does not apply when the final stage IS the
64
- assertion (`cmd | grep -q pattern`).
77
+ a real failure upstream is masked by a successful `tail`/`grep`/`jq`,
78
+ reading green. Capture the tested stage's own status: run it unpiped,
79
+ store `$?` immediately, or use `set -o pipefail`/`PIPESTATUS` — a
80
+ per-command choice, since pipefail breaks early-exit consumers (`cmd |
81
+ head -1`, `grep -q` on a long producer → SIGPIPE 141). The
82
+ final-stage-assertion exemption (`cmd | grep -q pattern`) holds only
83
+ without pipefail; under it, capture output and check its status first.
65
84
  - **Passthrough arguments in a CLI you author**: an option meant to carry
66
85
  another command's own flags cannot use a greedy-but-dash-stopping arity —
67
86
  Python's `nargs="+"` ends at the first token starting with `-`, so the
@@ -71,6 +90,13 @@ depends on it, pin it explicitly instead of trusting the environment.
71
90
  second, separate trap: argparse consumes it as its own positional marker
72
91
  before the remainder sees it, so the form every caller reaches for first is
73
92
  the one that breaks — normalize it out of `argv` before parsing.
93
+ - **CLI flag probes that execute**: probe a CLI only with invocations that
94
+ cannot do real work — a help form, or the candidate flag paired with a
95
+ control flag that forbids execution (dry-run, an invalid required
96
+ argument). Never run a subcommand bare, and assume a value after a flag
97
+ may be read as positional input: a boolean flag does not consume it, so it
98
+ falls through and runs. Tell a boolean from an unregistered flag by the
99
+ parser's error, not by the run succeeding.
74
100
  - **Reserved parameter names**: assigning to reserved shell names (`UID`,
75
101
  `EUID`, `GID`, `PPID`) can invoke the bound system behavior instead of
76
102
  storing a value — silently changing process credentials mid-script. Use
@@ -105,6 +131,14 @@ depends on it, pin it explicitly instead of trusting the environment.
105
131
  timestamp resolution (mutation testing). Clear the cache or run no-cache
106
132
  per iteration, and re-confirm the unmutated baseline still passes after a
107
133
  cache clear.
134
+ - **Transport limits are measured on the wire payload, in the provider's
135
+ unit**: take the unit and value from the provider's rejection or a live
136
+ probe, never from docs or a variable's name, and measure the serialized
137
+ payload the consumer receives — after encoding and wrappers — not the
138
+ object you assembled. A character count against a byte limit undercounts
139
+ multibyte text, hiding while inputs are ASCII; an item count bounds no
140
+ size. Enforce at one dispatch chokepoint, deriving every budget from that
141
+ constant.
108
142
 
109
143
  ## Git operations
110
144
 
@@ -131,12 +165,31 @@ depends on it, pin it explicitly instead of trusting the environment.
131
165
  restore from that. The same asymmetry makes the restore step fragile: if the
132
166
  probe can time out or abort, the restore must not be the next command in the
133
167
  same invocation — put it where a failure cannot skip it.
168
+ - **An ignore rule can swallow a durable record**: before treating a path as
169
+ durable — a new ledger, a cited authority — run `git check-ignore -v
170
+ <path>` and `git ls-files --error-unmatch <path>`. Broad runtime-state
171
+ patterns (`*.jsonl`, `runs/`, `out/`) absorb a new file, and a tracked
172
+ file pointing at an ignored path is an authority that exists in one
173
+ checkout only. Fix with a negation rule proven by a sibling that stays
174
+ ignored; genuinely ephemeral output stays ignored.
134
175
  - **Dirty-worktree pulls**: before pulling into a worktree with
135
176
  staged/unstaged/untracked changes, fetch first and compare incoming paths
136
177
  against every dirty path; on overlap or a non-fast-forward, stop and clear
137
178
  the conflict risk (stash, commit, ask). Otherwise pull `--ff-only`, confirm
138
179
  dirty changes survived, and regenerate any local derived artifacts whose
139
180
  inputs were updated.
181
+ - **A split series is proven commit by commit**: order them by dependency
182
+ and check each out into a throwaway worktree to run the build, tests, and
183
+ gates before pushing. Green only at the tip hides a broken bisect point
184
+ and a commit that cannot be reverted alone — usually a rename or shared
185
+ hunk in the wrong commit. If a handoff cites the branch's hashes, merge
186
+ with a merge commit: squash and rebase rewrite every hash.
187
+ - **A shared tree holds other operators' work**: a commit you did not make, a file the
188
+ editor reports changed on disk, a staged path you never added, one more field than
189
+ your predicted post-state — treat an unexplained delta as someone else's work, not
190
+ noise. Before a sweeping write (`git add -A`/`.`, `commit -a`, `stash`, `clean`,
191
+ `reset --hard`), attribute it (`git status`, reflog timestamps, other live sessions)
192
+ and then act only on what you can prove is yours — add by name.
140
193
 
141
194
  ## Config, secrets, and managed services
142
195
 
@@ -151,6 +204,13 @@ depends on it, pin it explicitly instead of trusting the environment.
151
204
  leaving stale, unreferenced definitions live. After updating, re-read the
152
205
  resource, check definitions and active references separately, and remove
153
206
  the orphans explicitly.
207
+ - **Derive a new revision from the live one, not from a template**: a
208
+ replace-semantics update drops every field the command does not restate,
209
+ and wrappers commonly default mounted secrets to off. Render the exact set
210
+ the command will send, derived from the live resource, and diff it field
211
+ by field; a field that disappears, or an operational value that moves
212
+ backward, is a blocker to explain, not a default to accept. Re-read the
213
+ resource afterwards, since a command rarely labels its semantics.
154
214
  - **A new revision is not live traffic**: on a runtime that pins traffic to a
155
215
  named revision (e.g. Cloud Run with a fixed split), `gcloud run deploy` (or
156
216
  the equivalent) creates the new revision but shifts no traffic to it — the
@@ -158,23 +218,101 @@ depends on it, pin it explicitly instead of trusting the environment.
158
218
  update-traffic`. Read the "deploy succeeded" message as "a revision exists",
159
219
  not "the new code is serving"; verify the live traffic split before
160
220
  concluding the deploy took effect.
161
- - **Perimeter controls need the enforcement point's own logs**: an agent-side
162
- fetch is not an independent external observer its egress IP and caching
163
- path are opaque, and it may share the protected network or serve a stale
164
- cached response. Verify allow AND deny directions from the load balancer /
165
- firewall's own logs, and check for a front-side cache/CDN separately.
221
+ - **Job logs outlive the execution**: a managed job that has run more than
222
+ once under one name including one deleted and recreated with the same
223
+ name returns the earlier incarnations' output when its logs are read by
224
+ job name. Scope every read to the execution id you received at launch and
225
+ confirm the timestamp window covers that run. An unscoped read merges
226
+ prior runs into the present and yields confident false diagnoses that a
227
+ scoped read reverses.
228
+ - **Dispatch status is not execution**: a CLI `--wait` returning or timing
229
+ out, a scheduler reporting success, a trigger accepted without error —
230
+ each reports what the dispatcher saw, not whether the target ran or what
231
+ state it reached. Before retrying or declaring done, re-derive the state
232
+ from the target's own record (its execution describe, the handler's logs),
233
+ matched to the run by id, and keep a manual probe distinguishable from the
234
+ scheduled one. A blind re-launch is a duplicate execution with side
235
+ effects.
236
+ - **An apply cut off before confirmation is unconfirmed** — neither done nor
237
+ un-run: when a multi-statement side-effecting apply (migration, batch
238
+ write) loses its confirmation channel, enumerate which target objects
239
+ already exist in the store, and plan the rerun from that partial state; a
240
+ naive rerun half-fails on "already exists" and leaves a second partial
241
+ state. Where the runner surfaces only exit status, route the object list
242
+ out through a deliberate failure. A transactional or provably idempotent
243
+ apply needs only the confirmation.
244
+ - **A traffic rollback is not a config rollback**: on a revision-pinned
245
+ runtime, sending traffic back to the previous revision restores behavior
246
+ but leaves the added env var or secret binding in the service template,
247
+ where the next deploy re-enables it silently. Count a rollback complete
248
+ only when the traffic split and the service spec are both back to the
249
+ prior state — re-read the spec and remove the change explicitly. Runtimes
250
+ that redeploy the prior spec itself (immutable-artifact, GitOps) have no
251
+ such gap.
252
+ - **Perimeter controls need the enforcement point's own logs**: an
253
+ agent-side fetch is not an independent observer — its egress IP and
254
+ caching path are opaque, and it may share the protected network or serve a
255
+ stale cached response. Verify allow AND deny directions from those logs,
256
+ and check for a front-side cache/CDN separately. Aim the probe at an
257
+ in-unit sentinel the app answers without credentials: a denial the app
258
+ produces anyway passes with the control off, and a redirect into it is a
259
+ bypass.
260
+ - **Tightening exposure is a behavior change for external clients**: switching
261
+ ingress mode, adding an allowlist, or requiring auth is not safe when
262
+ callers live outside your redeploy. Enumerate which clients reach the
263
+ endpoint and by which hostname, verify from a client's vantage, and
264
+ confirm inbound volume did not fall to zero — clients you cut off raise no
265
+ error on your side, so enforcement-point logs alone can sever ingestion
266
+ silently. Callers you redeploy in the same change need only the ordinary
267
+ deploy check.
166
268
  - **Smoke limits outlive the smoke test**: item caps, sample sizes, and row
167
269
  limits left in env vars/flags/config make a later "full-scale" run silently
168
270
  succeed on a slice. Clearing or explicitly verifying their absence is a
169
271
  precondition of declaring a full run.
272
+ - **A remote handle is valid only when it was read**: a row index in a sheet
273
+ that auto-sorts, a downloaded copy of a hosted file — each moves between
274
+ your read and your write. Before writing, re-establish the target from the
275
+ live source: re-locate the row by its key column, not a remembered
276
+ position, and assert the key matches after the write; compare the remote's
277
+ version against the copy you edited, re-downloading and reapplying on a
278
+ move. Local single-writer files need none of this.
279
+ - **Packaging and ignore rules are judged against paths and environments, not your tree**: before
280
+ a release, pack the real tarball, install it clean with lifecycle scripts
281
+ ON, and smoke it — a postinstall hook fine in the repo can delete the
282
+ shipped runtime where the build toolchain is absent. After moving or
283
+ renaming a directory, every ignore rule is void for the new paths:
284
+ re-check there and read the staged diff's file count, since old-path
285
+ patterns stop matching and excluded data enters the stage.
170
286
  - **Shared live config has concurrent writers**: before concluding your edit
171
287
  to a shared state/config file was lost or corrupting, rule out concurrent
172
288
  writers with a short live observation (mtime plus the fields you changed),
173
289
  and scope merge/union operations to the intended fields only.
290
+ - **Uniform failure is structural — read the persisted reason, then check the built artifact**: when
291
+ every item in a batch fails and the per-item error is persisted outside
292
+ the log (a status column, a result record), read it before blaming keys,
293
+ quota, or model availability. And when code reads sibling files from its
294
+ working directory, prove they exist inside the built image by listing or
295
+ hashing them there: a selective copy passes every repo-side check and
296
+ fails only at runtime.
174
297
  - **Production probes expose data**: default diagnostic queries against
175
298
  production stores to read-only server-side aggregation (counts, types,
176
299
  presence, hashes) — never pull raw payloads into logs, prompts, or
177
300
  transcripts — and delete scratch probe resources after the decision.
301
+ - **Build-context ignore patterns anchor at the root**: in a `.dockerignore`
302
+ or any root-anchored filter, a bare filename matches only at the context
303
+ root and never in a subdirectory, and an extension glob misses the
304
+ same-purpose credential file carrying another extension. Never conclude a
305
+ shipped image is secret-free from the patterns — list the built artifact's
306
+ own filesystem for credential-shaped files (env files, keys,
307
+ service-account JSON) as a named negative control, repeated whenever the
308
+ build context or ignore file changes.
309
+ - **A revoke is grant-wide, not token-wide**: revoking anything issued under
310
+ a client id the user's live sessions share invalidates those sessions too,
311
+ and the failure surfaces later, elsewhere, with no re-auth prompt. A probe
312
+ may clean up only what it alone owns — use minimum scopes and a dedicated
313
+ client id, and let a probe token expire rather than revoking it. Where a
314
+ revoke on a shared grant is unavoidable, state the blast radius and time
315
+ it with the user.
178
316
 
179
317
  ## Own what you spawn
180
318
 
@@ -186,3 +324,32 @@ Instance of the global rule: own the full lifecycle of what you create.
186
324
  orphans the real child), and await exit. An unref'd child handle or open
187
325
  stdin pipe keeps the parent's event loop alive and hangs otherwise-complete
188
326
  commands.
327
+ - **A handle issued to a human is a commitment**: once a consent URL is
328
+ handed over, the listener behind it must not be restarted, re-ported, or
329
+ replaced while the person may still act — keep it alive until the callback
330
+ lands, or say plainly that the link is dead. The handler captures the
331
+ credential write-once and ignores later hits, since a browser's favicon
332
+ request clears a naive one. Before asking a human to click again, drive
333
+ the handler with a simulated callback.
334
+ - **A stop is confirmed at the sink, not in the process list**: a kill that
335
+ misses one descendant lets that stage finish and publish, and the process
336
+ list looks clean either way. After stopping a multi-stage run, list the
337
+ output sink for anything written after the stop instant and roll it back
338
+ as contaminated. Read the rollback path's retention — noncurrent-version
339
+ expiry is a recovery window, not a backup — and snapshot before a risky
340
+ run, choosing the restore point by timestamp.
341
+ - **Detach what must outlive the call**: a process started inside a harness
342
+ tool call belongs to that call's process group: a trailing `&` is reaped
343
+ when the call returns, and the harness may signal the group when another
344
+ background task finishes. Launch anything meant to outlive one call
345
+ through the harness's background facility or fully detached
346
+ (nohup/setsid), writing progress to durable files a resume can read. A
347
+ zero-byte output file means it never survived. Detached still means owned
348
+ — PID file and stop path.
349
+ - **Name-substring lookup is not a liveness check**: `pgrep -f <name>` and
350
+ `ps | grep <name>` match the argv of the shell running the query itself,
351
+ and match unrelated processes carrying the same name — another session, a
352
+ sibling dispatch, the launcher's own plan text. To decide whether a
353
+ dispatched job is alive, use the PID or handle captured at launch, its
354
+ process-group state, or growth of its own output artifact. Substring
355
+ lookup is for discovery only, confirmed against one of those first.