@thebassclef/lite 0.1.0 → 0.1.2

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 (163) hide show
  1. package/dist/cli.cjs +2 -0
  2. package/dist/cli.js +2 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/package.json +1 -1
  7. package/substrate/.bassclef/lite-manifest.json +999 -92
  8. package/substrate/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
  9. package/substrate/.claude/hooks/longrun-prep-compounding-sequence-check.sh +492 -0
  10. package/substrate/.claude/hooks/pre-commit-gate.sh +1 -2
  11. package/substrate/.claude/hooks/turn-prose-kiss-check.sh +30 -1
  12. package/substrate/.claude/luminaries/glenford-myers.md +230 -0
  13. package/substrate/.claude/luminaries/hunt-thomas.md +115 -0
  14. package/substrate/.claude/luminaries/hyrum-wright.md +94 -0
  15. package/substrate/.claude/luminaries/michael-feathers.md +2 -2
  16. package/substrate/.claude/luminaries/tony-hoare.md +170 -0
  17. package/substrate/.claude/luminaries/vaughn-vernon.md +50 -0
  18. package/substrate/.claude/luminaries/w-edwards-deming.md +158 -0
  19. package/substrate/.claude/rules/accessor-library-discipline.md +138 -0
  20. package/substrate/.claude/rules/adr-discipline.md +120 -0
  21. package/substrate/.claude/rules/api-conventions.md +125 -0
  22. package/substrate/.claude/rules/bootstrap-pair-discipline.md +141 -0
  23. package/substrate/.claude/rules/cold-adopter-harness-discipline.md +129 -0
  24. package/substrate/.claude/rules/compounding-axis-fresh-analysis.md +188 -0
  25. package/substrate/.claude/rules/compounding-sequence-fresh-analysis.md +188 -0
  26. package/substrate/.claude/rules/defensive-bash.md +68 -0
  27. package/substrate/.claude/rules/deferred-actions.md +233 -0
  28. package/substrate/.claude/rules/github-issue-flash-tweet.md +156 -0
  29. package/substrate/.claude/rules/hook-wire-on-author.md +103 -0
  30. package/substrate/.claude/rules/iteration-bet-brief-completeness.md +54 -0
  31. package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +3 -3
  32. package/substrate/.claude/rules/longrun-prep-plan-doc-compression.md +89 -0
  33. package/substrate/.claude/rules/loop-discipline.md +81 -0
  34. package/substrate/.claude/rules/manual-prod-approval.md +100 -0
  35. package/substrate/.claude/rules/marker-enrichment-discipline.md +99 -0
  36. package/substrate/.claude/rules/mobile-ephemeral-session.md +109 -0
  37. package/substrate/.claude/rules/new-dependency-check.md +51 -0
  38. package/substrate/.claude/rules/option-label-discipline.md +108 -0
  39. package/substrate/.claude/rules/pattern-annotation.md +100 -0
  40. package/substrate/.claude/rules/plain-english-discipline.md +11 -9
  41. package/substrate/.claude/rules/plan-enumeration-needs-value-props.md +211 -0
  42. package/substrate/.claude/rules/pr-title-shape.md +161 -0
  43. package/substrate/.claude/rules/prototype-workflow.md +65 -0
  44. package/substrate/.claude/rules/reserved-skill-names.md +123 -0
  45. package/substrate/.claude/rules/schema-management.md +49 -0
  46. package/substrate/.claude/rules/security.md +37 -0
  47. package/substrate/.claude/rules/skill-composition-declarations.md +124 -0
  48. package/substrate/.claude/rules/skill-description-clarity.md +247 -0
  49. package/substrate/.claude/rules/skill-procedure-step-list.md +137 -0
  50. package/substrate/.claude/rules/stuck-signal-diagnostic.md +140 -0
  51. package/substrate/.claude/rules/substrate-config-schema.md +98 -0
  52. package/substrate/.claude/rules/test-list-discipline.md +175 -0
  53. package/substrate/.claude/rules/test-sufficiency.md +210 -0
  54. package/substrate/.claude/rules/testing-tier-config.md +145 -0
  55. package/substrate/.claude/rules/testing.md +38 -0
  56. package/substrate/.claude/rules/turn-estimate-grounding.md +134 -0
  57. package/substrate/.claude/rules/visual-hierarchy.md +437 -0
  58. package/substrate/.claude/rules/we-dont-break-adopters.md +126 -0
  59. package/substrate/.claude/rules/wu-sequencing-compounds.md +145 -0
  60. package/substrate/.claude/skills/build/SKILL.md +1 -1
  61. package/substrate/.claude/skills/chronicle/SKILL.md +55 -0
  62. package/substrate/.claude/skills/clean-artifacts/SKILL.md +249 -0
  63. package/substrate/.claude/skills/decompose/SKILL.md +1 -1
  64. package/substrate/.claude/skills/diagnose/SKILL.md +1 -1
  65. package/substrate/.claude/skills/feynman/SKILL.md +90 -0
  66. package/substrate/.claude/skills/howdoi/SKILL.md +1 -1
  67. package/substrate/.claude/skills/ia-model/SKILL.md +1 -1
  68. package/substrate/.claude/skills/interaction-design/SKILL.md +1 -1
  69. package/substrate/.claude/skills/interpret-input/SKILL.md +8 -8
  70. package/substrate/.claude/skills/journal/SKILL.md +209 -0
  71. package/substrate/.claude/skills/kiss/SKILL.md +1 -1
  72. package/substrate/.claude/skills/launch/SKILL.md +14 -23
  73. package/substrate/.claude/skills/lean-canvas/SKILL.md +1 -1
  74. package/substrate/.claude/skills/longrun/SKILL.md +45 -8
  75. package/substrate/.claude/skills/luminary/SKILL.md +1 -1
  76. package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +1 -1
  77. package/substrate/.claude/skills/onboard-repo/SKILL.md +143 -709
  78. package/substrate/.claude/skills/pattern-review/SKILL.md +1 -1
  79. package/substrate/.claude/skills/personas/SKILL.md +5 -5
  80. package/substrate/.claude/skills/promote/SKILL.md +1 -1
  81. package/substrate/.claude/skills/requirement/SKILL.md +1 -1
  82. package/substrate/.claude/skills/retro/SKILL.md +1 -1
  83. package/substrate/.claude/skills/riff/SKILL.md +1 -1
  84. package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +1 -1
  85. package/substrate/.claude/skills/session-end/SKILL.md +1 -1
  86. package/substrate/.claude/skills/session-log/SKILL.md +3 -3
  87. package/substrate/.claude/skills/skills/SKILL.md +1 -1
  88. package/substrate/.claude/skills/spec/SKILL.md +1 -1
  89. package/substrate/.claude/skills/sprint/SKILL.md +1 -1
  90. package/substrate/.claude/skills/stage/SKILL.md +1 -1
  91. package/substrate/.claude/skills/state-a-problem/SKILL.md +1 -1
  92. package/substrate/.claude/skills/temperance/SKILL.md +1 -1
  93. package/substrate/.claude/skills/use-case/SKILL.md +1 -1
  94. package/substrate/.claude/skills/user-stories/SKILL.md +1 -1
  95. package/substrate/.claude/skills/value-prop/SKILL.md +1 -1
  96. package/substrate/.claude/skills/verify/SKILL.md +1 -1
  97. package/substrate/.claude/skills/visual-review/SKILL.md +503 -0
  98. package/substrate/.claude/skills/whats-the-plan/SKILL.md +202 -0
  99. package/substrate/.claude/skills/whereami/SKILL.md +2 -2
  100. package/substrate/CONTRIBUTING.md +1 -1
  101. package/substrate/README.md +5 -5
  102. package/substrate/lib/prose-scan-boundary.sh +171 -0
  103. package/substrate/lib/tier-check.sh +50 -1
  104. package/substrate/lib/tier-dependency-audit.sh +159 -4
  105. package/substrate/presence/install/bassclef-sync.template.sh +1 -1
  106. package/substrate/scripts/generate-lite-manifest.sh +21 -5
  107. package/substrate/standards/adr-template.md +86 -0
  108. package/substrate/standards/api-conventions/nextjs.md +84 -0
  109. package/substrate/standards/artifact-composition.md +209 -0
  110. package/substrate/standards/bash-hook-safety.md +246 -0
  111. package/substrate/standards/branch-stacking.md +408 -0
  112. package/substrate/standards/code-safety-principles.md +176 -0
  113. package/substrate/standards/composer-prerequisites.md +155 -0
  114. package/substrate/standards/dependency-discipline/cargo.md +39 -0
  115. package/substrate/standards/dependency-discipline/gem.md +43 -0
  116. package/substrate/standards/dependency-discipline/go-mod.md +41 -0
  117. package/substrate/standards/dependency-discipline/npm.md +42 -0
  118. package/substrate/standards/dependency-discipline/pip.md +42 -0
  119. package/substrate/standards/deployment-topology/ec2-tailscale.md +225 -0
  120. package/substrate/standards/deployment-topology.md +69 -0
  121. package/substrate/standards/docs-sync-allowlist.md +4 -4
  122. package/substrate/standards/domain-and-dns.md +145 -0
  123. package/substrate/standards/frontend-stack.md +67 -0
  124. package/substrate/standards/frontmatter-schema.md +154 -0
  125. package/substrate/standards/hook-injection-discipline.md +202 -0
  126. package/substrate/standards/hook-install-class.md +215 -0
  127. package/substrate/standards/input-handler-interface.md +152 -0
  128. package/substrate/standards/lite-manifest-schema-changes.md +60 -0
  129. package/substrate/standards/luminary-matching.md +105 -0
  130. package/substrate/standards/migration-discipline/active-record.md +50 -0
  131. package/substrate/standards/migration-discipline/alembic.md +43 -0
  132. package/substrate/standards/migration-discipline/gorm.md +50 -0
  133. package/substrate/standards/migration-discipline/prisma.md +53 -0
  134. package/substrate/standards/migration-discipline/sqlalchemy.md +51 -0
  135. package/substrate/standards/mobile-ephemeral-session.md +167 -0
  136. package/substrate/standards/model-routing-discipline.md +160 -0
  137. package/substrate/standards/persona-schema.md +229 -0
  138. package/substrate/standards/pluggable-luminaries.md +323 -0
  139. package/substrate/standards/pr-body-discipline.md +115 -0
  140. package/substrate/standards/preview-state-schema.md +189 -0
  141. package/substrate/standards/reserved-skill-names.md +120 -0
  142. package/substrate/standards/scannable-multi-option-output.md +261 -0
  143. package/substrate/standards/sdlc-gates/typescript.md +57 -0
  144. package/substrate/standards/session-board.md +256 -0
  145. package/substrate/standards/state-spine-contract.md +255 -0
  146. package/substrate/standards/steering-hints/kiss-words.md +11 -0
  147. package/substrate/standards/substrate-config-schema.md +267 -0
  148. package/substrate/standards/tier-dependency-analysis.md +1 -1
  149. package/substrate/standards/tier-tag-schema.md +1 -1
  150. package/substrate/standards/two-layer-config.md +99 -0
  151. package/substrate/standards/use-case-format.md +292 -0
  152. package/substrate/standards/user-story-invest.md +268 -0
  153. package/substrate/standards/velocity-and-appetite.md +229 -0
  154. package/substrate/standards/voice-input-pattern.md +119 -0
  155. package/substrate/standards/worktree-management.md +211 -0
  156. package/substrate/templates/chronicle-template.md +75 -0
  157. package/substrate/templates/memory-proposal-template.md +77 -0
  158. package/substrate/templates/persona-template.md +200 -0
  159. package/substrate/templates/pr-faq.md +45 -0
  160. package/substrate/templates/secret-rotation-template.md +162 -0
  161. package/substrate/templates/spec-template.md +131 -0
  162. package/substrate/templates/use-case-template.md +194 -0
  163. package/substrate/templates/user-story-template.md +107 -0
@@ -0,0 +1,255 @@
1
+ ---
2
+ tier: lite
3
+ description: "The interface contract for lib/state.sh — the typed accessor library over bassclef's state spine."
4
+ ---
5
+
6
+ # State Spine Accessor Contract
7
+
8
+ The interface contract for `lib/state.sh` — the typed accessor library
9
+ over bassclef's state spine. Repository pattern (Fowler PoEAA): hides
10
+ storage backend (JSON-on-git for v0; cxdb for opt-in adopters per
11
+ bassclef#300) from consumers via a stable accessor surface.
12
+
13
+ This standard is the contract. The implementation is `lib/state.sh`.
14
+ Adapter discipline (per canvas Stage 3 §"Adapter discipline") preserves
15
+ the swap surface — when cxdb adoption ships, the implementation changes
16
+ but this contract does not.
17
+
18
+ ## Sources read
19
+
20
+ - `docs/iteration-bets/2026-04-27-state-spine-v0.md` §"WU-2 Typed accessor library" — procedure + acceptance
21
+ - `strategy/canvases/2026-04-26-state-spine.md` v4 — accessor discipline (replay-determinism); pattern-set (Repository/Facade); cxdb-adapter exit criteria
22
+ - `architecture/decisions/ADR-015-state-schema-format.md` — JSON Schema only for v0 (no Zod runtime)
23
+ - `standards/state-spine.md` — entity catalog (17 v0 + Persona); storage shapes (3 — A/B/C); replay-determinism rule; write-once-immutability rule
24
+ - All 18 v0 entity schemas in `standards/state-spine/schemas/` — define what each accessor returns
25
+ - `.claude/luminaries/martin-fowler.md` — Repository pattern + Strangler Fig
26
+ - `.claude/rules/diagnosis.md` — error-shape conventions (return non-zero + stderr message; never silent failure)
27
+
28
+ ## What I'm NOT reading (with reason)
29
+
30
+ - cxdb / Dolt vendor docs — out of v0 scope (Track B)
31
+ - `extract-session-telemetry.sh` line-by-line — WU-5's pre-read; this contract defines the surface telemetry will consume, not telemetry itself
32
+
33
+ ## Naming convention
34
+
35
+ ```
36
+ state_<entity>_<verb>[_<modifier>]
37
+ ```
38
+
39
+ - **entity** — kebab-case entity name from state-spine.md (e.g., `whereami`, `iteration_bet`, `deferred_action`, `chronicle`, `marker`)
40
+ - **verb** — operation (bassclef set below)
41
+ - **modifier** — optional qualifier for special-purpose accessors
42
+
43
+ Examples:
44
+ - `state_whereami_get` — get the singleton
45
+ - `state_iteration_bet_list` — list all bets
46
+ - `state_marker_count` — count markers (with optional filter args)
47
+ - `state_chronicle_gate_evidence` — special-purpose: extract gates_fired from a chronicle
48
+ - `state_deferred_action_pending` — special-purpose: list pending actions matching capabilities
49
+
50
+ ## Verb vocabulary
51
+
52
+ Stable set. Extend via this contract (with a paired schema-side rationale).
53
+
54
+ | Verb | Semantics | Allowed for |
55
+ |---|---|---|
56
+ | `get` | Single entity by id; returns JSON to stdout, 1 to stderr if not found | All entities |
57
+ | `list` | Collection (optional filter args); returns JSON array to stdout (empty array `[]` if none) | All entities |
58
+ | `count` | Counter (optional filter args); returns integer to stdout | All entities |
59
+ | `add` | Append a new entity; takes JSON on stdin, writes file, returns id to stdout | Write-many entities (Marker, Chronicle, Decomposition, InputArtifact, Session, Gate, InboxWorkItem, TemplateInstance, DeferredAction) |
60
+ | `set` | Update field on singleton; takes field + value, validates against schema, writes | Singletons only (Whereami, SubstrateConfig, PreviewState, BassclefPlatform) |
61
+ | `update_status` | Change status field; validates new value against entity's status enum | Mutable-status entities (IterationBet, Step, InboxWorkItem, DeferredAction) |
62
+ | `render` | Generate operator-readable markdown from JSON authoritative source | Singletons (Whereami, SubstrateConfig, PreviewState) |
63
+
64
+ Forbidden verbs: any mutation on Markers, Chronicles, Discoveries,
65
+ Sessions (write-once-immutable per Helland — see canvas §"Accessor
66
+ discipline"). Updates produce NEW records; readers consider the latest
67
+ non-superseded record per business-key.
68
+
69
+ ## Return semantics
70
+
71
+ | Outcome | Stdout | Stderr | Exit code |
72
+ |---|---|---|---|
73
+ | Success (single entity) | JSON object | (empty) | 0 |
74
+ | Success (list) | JSON array (possibly empty) | (empty) | 0 |
75
+ | Success (count) | integer | (empty) | 0 |
76
+ | Success (add) | new id | (empty) | 0 |
77
+ | Not found | (empty) | (empty) | 1 |
78
+ | Invalid input | (empty) | error message | 2 |
79
+ | Schema validation failed | (empty) | jq/ajv error | 3 |
80
+ | File system error | (empty) | error message | 4 |
81
+ | Unsupported entity / verb | (empty) | error message | 5 |
82
+
83
+ Consumers check exit code; non-zero is failure. Never silent — error
84
+ messages always go to stderr per `.claude/rules/diagnosis.md`
85
+ ("Step 0 — Reproduce" requires the failure to surface).
86
+
87
+ ## Replay-determinism rule (canvas v4 SWF mining)
88
+
89
+ Counters and computed state derived from history on every call. **Never
90
+ cache derived values as side state.**
91
+
92
+ Concretely:
93
+ - `state_marker_count [category] [since-N-sessions]` reads the Marker
94
+ collection + computes; no `latest_count` field stored anywhere
95
+ - `state_chronicle_gate_evidence <id>` derives from session's marker
96
+ history at chronicle write time, not maintained out-of-band
97
+ - `state_whereami_recompute` regenerates the Whereami singleton from
98
+ collection state; the JSON sidecar at `docs/whereami.json` is a
99
+ cache, not authority
100
+
101
+ This is the bassclef analog of SWF's "decider must be idempotent on
102
+ replay." Same input history → same output, deterministically. Failing
103
+ at this is what produced bassclef#296 (compliance counter floor-lift).
104
+
105
+ ## Write-once-immutability rule (Helland)
106
+
107
+ Markers, Chronicles, Discoveries, Sessions are write-once. Once
108
+ committed:
109
+ - Filename never changes (UUID for Markers; ID-based for others)
110
+ - Body content never changes
111
+ - Updates produce NEW records that supersede the prior (via
112
+ `supersedes` field per the Marker schema)
113
+
114
+ Accessors that mutate (`add`) write atomic — file lands or fails. No
115
+ partial writes. Use temp-file + rename pattern.
116
+
117
+ Accessors that don't mutate (`get`, `list`, `count`, `update_status`)
118
+ operate on whatever's on disk; consumers responsible for any
119
+ serializability they need (out of v0 scope; cxdb upgrade addresses for
120
+ concurrent fanout).
121
+
122
+ ## Storage-shape extraction (per state-spine.md §"Storage format")
123
+
124
+ The accessor handles all three on-disk shapes via entity-type-aware
125
+ extraction:
126
+
127
+ ### Shape A entities (singleton JSON authoritative + markdown rendered)
128
+
129
+ ```bash
130
+ state_whereami_get() { cat docs/whereami.json; }
131
+ state_whereami_set <field> <value> # jq update + atomic rename
132
+ state_whereami_render # JSON → markdown (with auto-generated banner)
133
+ ```
134
+
135
+ ### Shape B entities (markdown + YAML frontmatter + body)
136
+
137
+ ```bash
138
+ state_iteration_bet_get <slug> {
139
+ # Extract YAML frontmatter, convert to JSON
140
+ awk '/^---$/{c++; next} c==1' docs/iteration-bets/$slug.md | yq2json
141
+ }
142
+ ```
143
+
144
+ `yq2json` is implemented as `python3 -c "import sys,yaml,json; print(json.dumps(yaml.safe_load(sys.stdin), default=str))"` (yaml + json stdlib, available everywhere).
145
+
146
+ ### Shape C entities (pure JSON)
147
+
148
+ ```bash
149
+ state_marker_get <uuid> {
150
+ # Find by UUID across category dirs
151
+ find state/markers -name "${uuid}.json" -type f -print -quit | xargs cat
152
+ }
153
+ ```
154
+
155
+ ### Shape D entities (pure YAML at sibling-repo root) — added bassclef#462
156
+
157
+ ```bash
158
+ state_platform_get [dot.path.key] {
159
+ # Resolves file via BASSCLEF_PLATFORM_CONFIG_PATH env or default
160
+ # ~/src/sunj-labs/platform-config/bassclef-platform.yml; converts
161
+ # YAML to JSON; if a key is given, jq-walks the path.
162
+ python3 -c "import yaml,json; print(json.dumps(yaml.safe_load(open('$path'))))" \
163
+ | jq -r --arg key "$key" 'getpath($key | split("."))'
164
+ }
165
+ state_platform_path # returns the resolved file path (no read)
166
+ ```
167
+
168
+ ## Special-purpose accessors (v0 hot-path consumers)
169
+
170
+ Beyond generic verbs, the following exist for known v0 consumers:
171
+
172
+ | Accessor | Returns | Consumer |
173
+ |---|---|---|
174
+ | `state_marker_count [category] [since-days]` | int | `extract-session-telemetry.sh` (WU-5); `40-gate-compliance.sh` (WU-6). v0 since-days = mtime-based; v1 will redefine as session-boundary-mapped per canvas v4 SWF mining. Accepts both `.json` (spine) and `.marker` (legacy verify-markers) extensions. |
175
+ | `state_chronicle_list [--recent N]` | newline-separated chronicle IDs (lex order) | `extract-session-telemetry.sh` (WU-5); `/sprint`, `/chronicle` (WU-7). Tries `chronicle/` then `docs/chronicle/`. |
176
+ | `state_chronicle_gate_evidence <id>` | JSON of `gates_fired` frontmatter array | `extract-session-telemetry.sh` (WU-5) — frontmatter-only. Legacy chronicles with body-table Gate Evidence return `[]`; consumers may parse markdown body directly per `accessor-library-discipline.md` §"What this rule allows". |
177
+ | `state_session_recent <N>` | JSON array of recent N sessions | `/sprint`, `/chronicle` (WU-7) |
178
+ | `state_step_for_branch <branch-name>` | JSON of Step | status checks; `/longrun checkpoint` |
179
+ | `state_deferred_action_pending [requires-capability...]` | JSON array of resolvable entries (capability-filtered) | `60-deferred-actions.sh` (WU-6) |
180
+ | `state_deferred_action_list [pending\|completed\|all]` | JSON array of all entries in scope (no capability filter) | `/state` skill (WU-8); ad-hoc inspection |
181
+ | `state_iteration_bet_active` | JSON of currently-active bet (or empty if none) | `/sprint` (WU-7) |
182
+ | `state_iteration_bet_list` | JSON array of all bets (lexicographic order) | `/state` skill (WU-8) |
183
+ | `state_reference_get <type> <id>` | JSON of referenced entity (resolves typed cross-refs) | validator (WU-3); render (WU-7) |
184
+ | `state_reference_check <type> <id>` | exit 0 if exists, 1 if dangling | validator (WU-3) |
185
+ | `state_validate <path>` | empty stdout on success; BLOCK message on stderr if schema violation | `/state` skill (WU-8); ad-hoc operator validation |
186
+ | `state_roadmap_get <slug>` | JSON of roadmap frontmatter | `/sprint`, `/longrun` first-turn orientation (bassclef#337 WU-4) |
187
+ | `state_roadmap_next_pending <slug>` | JSON of next claimable WU (depends_on satisfied + status=pending) | claim_wu's default arg path |
188
+ | `state_platform_get [dot.path]` | JSON object (whole file) or scalar (when dot-path given) | `/provision-deploy-host` (bassclef#457), `/secrets-bootstrap` (bassclef#461), `/scaffold-stack` (bassclef#460), `/bind-subdomain` (existing — V2 reads zone via this rather than per-repo substrate.config); reads sibling-repo `bassclef-platform.yml` |
189
+ | `state_platform_path` | filesystem path string | tooling that displays where state_platform_get reads from without reading |
190
+ | `state_roadmap_claim_wu <slug> [wu-slug] [session-id]` | JSON of claimed WU; advances `last_event` with `task-claimed` (bassclef#349 tail-1) | distributed agent coordination — atomic claim via flock |
191
+ | `state_roadmap_release_wu <slug> <wu-slug> [event] [refs-json]` | JSON of new `last_event`; advances `last_event` with completion | distributed agent coordination — completion |
192
+ | `state_roadmap_abandon_wu <slug> <wu-slug> [reason] [--terminal]` | JSON of new `last_event`; advances `last_event` with `task-abandoned` (bassclef#349 tail-2) | scope-change exit path; default returns to pending, `--terminal` marks abandoned |
193
+ | `state_roadmap_add_task <slug> <wu-slug> <issue> <wu-id> <title> [depends_on-json]` | JSON of new task; advances `last_event` with `task-added` (bassclef#349 tail-3) | proper accessor entry point for populating roadmap task list — replaces hand-edits per `accessor-library-discipline.md` |
194
+
195
+ ## Adapter discipline — preserved swap surface
196
+
197
+ Per canvas Stage 3 §"Adapter discipline" (7 exit criteria):
198
+
199
+ 1. **Accessor library is the ONLY consumer of storage backend APIs.**
200
+ No skill/hook/rule/script invokes `cat docs/whereami.json` directly
201
+ when an accessor exists. Enforced via `accessor-library-discipline.md`
202
+ rule (paired with this contract; ships in same PR as `lib/state.sh`).
203
+ 2. **Accessor surface exposes only operations expressible in BOTH
204
+ backends** (JSON-on-git AND cxdb). No JSON-on-git-specific features
205
+ (e.g., `find`-based glob queries, jq paths in public surface) leak
206
+ into the contract. cxdb-adopter would re-implement these accessors
207
+ against Turn DAG + Blob CAS; surface stays unchanged.
208
+ 3. **JSON spine remains writable from cxdb.** When cxdb adoption ships,
209
+ `state_marker_add` etc. continue to write JSON files (cxdb is a
210
+ read-side projection); JSON files in git are still authoritative.
211
+ 4. **Contract is schema-first, not implementation-first.** Entity
212
+ definitions live in `standards/state-spine/schemas/`. cxdb's Type
213
+ Registry would be loaded FROM bassclef's schema, not derived.
214
+ 5. **A working cxdb fork is maintained** when adopted. (Out of v0 scope.)
215
+ 6. **Migration tooling (cxdb → Dolt) is designable from the entity
216
+ model.** (Out of v0 scope; ADR bassclef#300 placeholder.)
217
+ 7. **Dolt-as-fallback design is sketched in the cxdb ADR.** (Out of
218
+ v0 scope.)
219
+
220
+ For v0: criteria 1-4 apply now. They constrain `lib/state.sh` design
221
+ even though only criterion 1 is enforceable in v0 (the rule).
222
+
223
+ ## Test coverage requirement
224
+
225
+ ≥95% test coverage on `lib/state.sh` per step-2 acceptance. Test scaffold
226
+ at `scripts/tests/state.test.sh` per existing bassclef bash-test
227
+ pattern (`scripts/tests/bind-subdomain.test.sh`).
228
+
229
+ Each accessor has at minimum:
230
+ - Happy path (successful return)
231
+ - Not-found path (exit 1, empty stdout)
232
+ - Invalid-input path (exit 2, stderr message)
233
+ - Schema-validation path where applicable (exit 3)
234
+
235
+ ## Versioning
236
+
237
+ Accessor surface versioned via this standard. Breaking changes
238
+ (removing accessors, changing return shapes, changing exit codes) are
239
+ v1 changes — ship as `state_v1.sh` alongside `state.sh` during
240
+ deprecation window per Fowler expand-and-contract.
241
+
242
+ Adding new accessors is non-breaking; can land in v0 patches.
243
+
244
+ ## Relationship to other standards
245
+
246
+ - `standards/state-spine.md` — entity catalog + storage shapes; this
247
+ contract operates on
248
+ - `standards/branch-stacking.md` — Stack entity uses retarget protocol;
249
+ WU-2 PR will need this on merge
250
+ - `.claude/rules/state-schema-validation.md` (paired with WU-3) — write-time
251
+ validation; this contract's `add`/`set`/`update_status` accessors invoke
252
+ the validator before writing
253
+ - `.claude/rules/accessor-library-discipline.md` (paired with this
254
+ standard) — enforces "no skill/hook/rule reads state directly; all
255
+ access goes through `lib/state.sh`"
@@ -0,0 +1,11 @@
1
+ ---
2
+ tier: lite
3
+ hint_id: kiss-words
4
+ priority: high
5
+ boundaries: [prompt-submit, skill-end, state-write]
6
+ token_budget: 50
7
+ refresh_interval_turns: 5
8
+ description: Write at grade 8. Cap grade 10. Short sentences. Subject-verb-object. Drop bassclef-only words per standards/bassclef-internal-jargon.md. Keep standard tech words (API, hook, PR, schema).
9
+ ---
10
+
11
+ Write at grade 8. Cap grade 10. Short sentences. Subject-verb-object. Drop bassclef-only words per standards/bassclef-internal-jargon.md. Keep standard tech words (API, hook, PR, schema).
@@ -0,0 +1,267 @@
1
+ ---
2
+ tier: lite
3
+ description: substrate.config.md is the single source of truth for external resource references in any bassclef-substrate repo.
4
+ ---
5
+
6
+ # Substrate Config Schema
7
+
8
+ `substrate.config.md` is the **single source of truth** for external
9
+ resource references in any bassclef-substrate repo. Functionally, it
10
+ is to bassclef what `.env` is to runtime code — the one place agents
11
+ look for "where is X" without guessing, without consulting memory, and
12
+ without hardcoding.
13
+
14
+ ## Why this exists
15
+
16
+ Before this standard: resource references lived in three places —
17
+ `substrate.config.md`, project memory, and hardcoded in skills. Agents
18
+ had to check all three, confused them routinely, and produced wrong
19
+ pushes (drafts pushed to corpus doc, etc.).
20
+
21
+ Single-source-of-truth eliminates the ambiguity. Skills read only from
22
+ `substrate.config.md`. Memory references resources only by field name,
23
+ never by raw ID.
24
+
25
+ ## Typed suffix convention
26
+
27
+ Every resource field in `substrate.config.md` uses a typed suffix so
28
+ the agent never has to interpret the value:
29
+
30
+ | Suffix | Meaning | Examples |
31
+ |--------|---------|----------|
32
+ | `*_doc_id` | Google Doc ID (a string that goes after `/document/d/`) | `journal_doc_id`, `changelog_doc_id`, `brand_corpus_doc_id` |
33
+ | `*_sheet_id` | Google Sheets ID | `metrics_sheet_id` |
34
+ | `*_url` | Full URL (http/https) | `staging_url`, `grafana_url`, `langfuse_url` |
35
+ | `*_host` | Host without scheme | `db_host`, `redis_host` |
36
+ | `*_repo` | GitHub repo reference (`owner/name`) | `parent_repo`, `deploy_repo` |
37
+ | `*_repos` | Comma-separated list of GitHub repo references | `bassclef_evolution_child_repos` |
38
+ | `*_path` | Filesystem path (absolute preferred) | `shared_artifacts_path` |
39
+ | `*_channel_id` | Slack/Discord channel | `alerts_channel_id` |
40
+ | `*_project_id` | Linear/Jira/Asana project | `linear_project_id` |
41
+ | `*_token_name` | **Name of env var** holding a secret (never the secret itself) | `gh_token_name`, `anthropic_key_name` |
42
+ | `*_reviewers` | GitHub usernames (comma-separated) for approval gates | `prod_approval_reviewers` |
43
+ | `*_topology` | Architectural choice per `deployment-topology.md` | `staging_topology` |
44
+
45
+ **Secrets NEVER in `substrate.config.md`.** That file is committed to
46
+ git. Secrets live in `.env` (gitignored) or a secret manager. The
47
+ convention stores the *name* of the env var (e.g.,
48
+ `gh_token_name: GH_TOKEN`) so agents know which variable to read at
49
+ runtime.
50
+
51
+ **Secret lifecycle is tracked separately** in `substrate.secrets.md`
52
+ (schema: `standards/state-spine/schemas/substrate-secrets.schema.json`;
53
+ purpose: `standards/secrets-lifecycle.md`). That file holds rotation
54
+ cadence, expiry dates, runbook paths, and health-check commands —
55
+ references and metadata only, never values. The two files cross-reference
56
+ each other; `substrate.config.md` answers *where* a resource lives,
57
+ `substrate.secrets.md` answers *when* a credential expires and *how* to
58
+ rotate it.
59
+
60
+ ## Single-source-of-truth rule
61
+
62
+ 1. **External resource IDs live ONLY in `substrate.config.md`.** Any
63
+ Google Doc ID, URL, repo reference, or similar pointer is a field
64
+ in this file.
65
+ 2. **Project memory references resources ONLY by field name**, never
66
+ by raw value. `brand_corpus_doc_id` is a valid memory reference;
67
+ `1gps7mmEYBCud...` is not.
68
+ 3. **Skills and hooks read ONLY from `substrate.config.md`** for
69
+ resource lookups. No hardcoded IDs in skill files, hook scripts,
70
+ or agent definitions.
71
+ 4. **If an agent needs a resource that isn't in
72
+ `substrate.config.md`**, the agent prompts the operator to add it
73
+ with a typed field name. Do not hardcode. Do not cache in memory.
74
+ 5. **Scaffolding on new repos prompts for each known field** during
75
+ `/autonomous start` setup.
76
+
77
+ ## Known fields (extensible)
78
+
79
+ These fields are recognized by bassclef skills. Not all are required;
80
+ uncommented defaults shown.
81
+
82
+ ```yaml
83
+ # === Artifacts ===
84
+ journal_doc_id: [per-repo draft Google Doc — pushes from /journal + session-end]
85
+ changelog_doc_id: [per-repo weekly changelog Google Doc — pushes from /release-notes]
86
+ brand_corpus_doc_id: [cross-repo brand team corpus — pushes from /journal-export]
87
+
88
+ # === Environments ===
89
+ deploy_targets:
90
+ local: true # always available
91
+ staging: false # URL when configured
92
+ prod: false # URL when configured (hard gate — human-approved)
93
+
94
+ # === Integrations (optional, per-project) ===
95
+ langfuse_url: [tracing dashboard URL, if used]
96
+ grafana_url: [metrics dashboard URL, if used]
97
+ linear_project_id: [Linear project for ticket sync, if used]
98
+
99
+ # === Bassclef substrate (bassclef repo only) ===
100
+ # Consumer repos scanned by session-reflection for bassclef-evolution
101
+ # issues. Keep in sync with .github/workflows/bassclef-template-sync.yml
102
+ # matrix. Fallback when field absent: poa only.
103
+ bassclef_evolution_child_repos: [comma-separated list of owner/name]
104
+
105
+ # === Budget ===
106
+ budget:
107
+ session_ceiling: [API burst $/session]
108
+ iteration_ceiling: [API burst $/iteration]
109
+ warning_threshold: 75%
110
+
111
+ # === Secret references (names only, not values) ===
112
+ anthropic_key_name: ANTHROPIC_API_KEY # env var name, not the key
113
+ gh_token_name: GH_TOKEN # env var name, not the token
114
+
115
+ # === Hosting platform (REQUIRED in any consumer that ships a UI) ===
116
+ #
117
+ # Drives which deploy_* fields apply AND which adapter `/bind-subdomain`
118
+ # loads. Every consumer running `/preview-build` or shipping production
119
+ # UI MUST set this — the bassclef default is `amplify` per ADR-008
120
+ # (frontend-stack) + POA + quorum precedent (single-provider portfolio
121
+ # reduces operator cognitive load; AWS-native; cheap port to existing
122
+ # AWS auth).
123
+ #
124
+ # Enum values (all five are valid; not all have shipped adapters yet):
125
+ # - amplify: use amplify_app_id + amplify_region + amplify_branch
126
+ # (bassclef-recommended default; adapters live)
127
+ # - ec2-tailscale: use deploy_host + deploy_user + deploy_path (POA pattern)
128
+ # - vercel: adapter not yet shipped — schema reserves the slot
129
+ # - netlify: adapter not yet shipped — schema reserves the slot
130
+ # - cloudflare-pages: adapter not yet shipped — schema reserves the slot
131
+ # - none: consumer explicitly opts out of preview/prototype
132
+ # deployment. `/bind-subdomain` and `/launch-preview`
133
+ # refuse on `none` unless --override given. Use for
134
+ # docs-only repos (e.g., bassclef itself) or repos
135
+ # that ship no UI surface.
136
+ hosting_platform: amplify # bassclef default; pick from enum above
137
+
138
+ # --- Production tier (optional; declare when production differs from prototype) ---
139
+ #
140
+ # Per-tier hosting was added in bassclef#458 to resolve the POA case:
141
+ # POA's prototypes deploy to amplify, but POA's production runs on
142
+ # ec2-tailscale (per ADR-009) and predates the prototype pipeline.
143
+ # Without `production_hosting_platform`, hosting_platform=amplify
144
+ # implies POA's whole app is on amplify — wrong.
145
+ #
146
+ # `production_hosting_platform` is DECLARATIVE. /launch-preview and
147
+ # /bind-subdomain operate on the prototype tier only and do not read
148
+ # this field. It documents the production tier so operators (and
149
+ # future tooling) know the production deploy is a separate concern.
150
+ #
151
+ # When unset, production tier inherits hosting_platform.
152
+ production_hosting_platform: ec2-tailscale # only set when production differs from prototype
153
+
154
+ # --- Amplify-specific (when hosting_platform=amplify) ---
155
+ #
156
+ # `amplify_app_id` is the provisioning-indicator field (bassclef#523).
157
+ # Set by `/provision-deploy-host` on success when the Amplify app is
158
+ # created. Composer pre-flight (lib/composer-preflight.sh Check 6) reads
159
+ # this field to verify provisioning happened — when missing or set to a
160
+ # bracketed placeholder shape, /preview-build is BLOCKED with three-path
161
+ # remediation (run /provision-deploy-host inline / re-dispatch with
162
+ # --no-launch / explicit defer). Replaces the silent-defer-bind class
163
+ # that caused POA's 2026-05-05 mobile session to merge variants but
164
+ # never bind a subdomain.
165
+ amplify_app_id: [e.g., d154l5usyc80nk]
166
+ amplify_region: [e.g., eu-north-1]
167
+ amplify_branch: [branch bound to domain, default: main]
168
+
169
+ # --- EC2 + Tailscale-specific (when hosting_platform=ec2-tailscale) ---
170
+ # See standards/deployment-topology.md for the SENTINEL_bassclef_pattern.
171
+ #
172
+ # `deploy_host` is the provisioning-indicator field (bassclef#523) —
173
+ # Composer pre-flight Check 6 reads it to verify provisioning happened
174
+ # (parallel to amplify_app_id for amplify). Same three-path remediation
175
+ # applies when missing.
176
+ deploy_host: [Tailscale hostname of prod box]
177
+ deploy_user: [SSH user on prod box]
178
+ deploy_path: [absolute path on box, e.g., /opt/poa]
179
+ staging_deploy_host: [same or different Tailscale host]
180
+ staging_deploy_path: [absolute path, e.g., /opt/poa-staging]
181
+ staging_topology: same-box | separate-box # Option A or B
182
+ tailscale_tag: [CI tag, e.g., tag:ci]
183
+ backup_path: [absolute path, e.g., /opt/backups]
184
+ prod_approval_reviewers: [GitHub usernames comma-separated]
185
+
186
+ # === Domain + DNS (when app binds a friendly URL) ===
187
+ # See standards/domain-and-dns.md. Optional — skip if using platform
188
+ # default URL (e.g., *.amplifyapp.com). Binding is automated via the
189
+ # /bind-subdomain skill.
190
+ subdomain: [e.g., myapp.apps.example.com]
191
+ dns_provider: [cloudflare | route53] # v1 supports cloudflare
192
+ dns_zone: [e.g., example.com]
193
+ cloudflare_token_env: [env var name holding CF API token, e.g., CLOUDFLARE_API_TOKEN]
194
+ ```
195
+
196
+ ## Migration from anti-patterns
197
+
198
+ ### Anti-pattern 1: raw IDs in project memory
199
+
200
+ **Before**:
201
+ ```markdown
202
+ # memory/reference_brand_corpus.md
203
+ The brand team corpus lives at 1gps7mmEYBCud462Pn_DNf2mXa5Bj58NMjXUUDqWGIh0.
204
+ ```
205
+
206
+ **After**:
207
+ ```markdown
208
+ # memory/reference_brand_corpus.md
209
+ The brand team corpus is configured as `brand_corpus_doc_id` in
210
+ substrate.config.md. Agents should always read from there, never
211
+ reference the raw ID directly.
212
+ ```
213
+
214
+ ### Anti-pattern 2: hardcoded IDs in skills
215
+
216
+ **Before** (in `.claude/skills/journal-export/SKILL.md`):
217
+ ```bash
218
+ npx tsx scripts/push-to-gdoc.ts \
219
+ --file docs/journal-corpus/corpus.md \
220
+ --doc-id 1gps7mmEYBCud462Pn_DNf2mXa5Bj58NMjXUUDqWGIh0
221
+ ```
222
+
223
+ **After**:
224
+ ```bash
225
+ DOC_ID=$(grep "^brand_corpus_doc_id:" substrate.config.md | awk '{print $2}')
226
+ npx tsx scripts/push-to-gdoc.ts \
227
+ --file docs/journal-corpus/corpus.md \
228
+ --doc-id "$DOC_ID"
229
+ ```
230
+
231
+ Or equivalently, skills document the field name in prose and require
232
+ the agent to look it up at runtime:
233
+
234
+ ```markdown
235
+ ## Step 7: Push to Google Docs
236
+
237
+ Push to `brand_corpus_doc_id` from `substrate.config.md`:
238
+
239
+ \`\`\`bash
240
+ npx tsx scripts/push-to-gdoc.ts --file docs/journal-corpus/corpus.md \
241
+ --doc-id $(grep "^brand_corpus_doc_id:" substrate.config.md | awk '{print $2}')
242
+ \`\`\`
243
+ ```
244
+
245
+ ### Anti-pattern 3: scattered fields
246
+
247
+ If an app repo adds a new resource (e.g., a Retool dashboard URL)
248
+ and stores it in a README comment, an inline skill comment, or a
249
+ hook variable — that's the anti-pattern. All such values go in
250
+ `substrate.config.md` with the typed suffix.
251
+
252
+ ## Related rules
253
+
254
+ - `.claude/rules/substrate-config-schema.md` — enforces this standard
255
+ at agent behavior level (read from config, don't hardcode, don't
256
+ cache in memory)
257
+ - `.claude/skills/autonomous/SKILL.md` — prompts for each known field
258
+ during scaffold
259
+ - `.claude/skills/substrate-check/SKILL.md` — validates substrate.config.md
260
+ has required fields for the repo type
261
+
262
+ ## Versioning
263
+
264
+ When bassclef adds a new known field type, the schema here is the
265
+ authoritative list. App repos update their `substrate.config.md` to
266
+ add the new field during next `/autonomous start` scaffold pass (the
267
+ skill surfaces missing fields and prompts for values).
@@ -144,7 +144,7 @@ Bucket 2 outputs from single-tier and combined-tier agree for that tier's legit
144
144
  - Consumed by `.claude/skills/tier-dependency-audit/SKILL.md` — user-invocable wrapper
145
145
  - Composed with `scripts/release-to-bassclef.sh` — the ACTUAL set comes from `--dry-run`
146
146
  - Composed with `.claude/rules/we-dont-break-adopters.md` (ADR-031) — the audit surfaces adopter-observable classes for careful handling
147
- - Composed with `.claude/rules/mechanism-fidelity.md` — the subsystem IS the mechanism paired with tier-tag-schema
147
+ - Composed with `.claude/rules/mechanism-fidelity.md` (standard tier) — the subsystem IS the mechanism paired with tier-tag-schema
148
148
 
149
149
  ## Anchor luminaries
150
150
 
@@ -117,7 +117,7 @@ Prior default-ship rule for non-md/sh files (superseded by this table 2026-08-20
117
117
 
118
118
  Files whose path matches an entry in `standards/path-exclusion-registry.json` are excluded from every release regardless of any inner `tier:` value. The path wins. Consumers (release script, audit tools) read the registry as the single source of truth for path-based exclusion classes: `session-runtime`, `operator-private`, `test-only`, `operator-internal-rd`, `prototype`, `config-per-repo`, `ephemeral-transient`.
119
119
 
120
- See `standards/path-exclusion-registry.md` for classes + rationale per entry + how to add a new exclusion.
120
+ The path exclusion registry (operator-only) tracks classes + rationale per entry + how to add a new exclusion.
121
121
 
122
122
  The path-exclusion registry supersedes the prior inline `case` statement in `scripts/release-to-bassclef.sh` L415-460. The refactor to read the registry ships as a separate PR after this schema amendment.
123
123
 
@@ -0,0 +1,99 @@
1
+ ---
2
+ tier: lite
3
+ description: "Bassclef's config splits into two layers."
4
+ ---
5
+
6
+ # Two-Layer Config — Shared vs Operator
7
+
8
+ Bassclef's config splits into two layers. The **shared layer** is committed and identity-agnostic — every adopter sees it. The **operator layer** is gitignored and per-person — never committed, never shipped to adopters.
9
+
10
+ This standard exists because the line between "what bassclef needs" and "what one operator has set up" was blurry before the 2026-05-23 cold-adopter run. Operator-specific paths, allow lists, and preferences leaked into shared config. Adopters would have inherited the operator's identity on first clone.
11
+
12
+ ## The two layers
13
+
14
+ ### Shared layer (committed)
15
+
16
+ - `.claude/settings.json`
17
+ - `CLAUDE.md`
18
+ - `README.md`
19
+ - All skills, hooks, rules, standards under `.claude/` and root dirs
20
+ - All ADRs, decompositions, design docs
21
+
22
+ **Rules for the shared layer:**
23
+
24
+ 1. Identity-agnostic. No absolute paths to specific home directories.
25
+ 2. No personal allow-list entries (broad npm grants, macOS process control, etc.).
26
+ 3. No "sunj-labs" references except in attribution.
27
+ 4. Tested against cold-adopter personas (`strategy/personas/`) before publication.
28
+
29
+ ### Operator layer (gitignored)
30
+
31
+ - `.claude/settings.local.json`
32
+ - `CLAUDE.local.md` (optional, if operator wants per-machine context)
33
+ - `.env.local`
34
+ - Anything ending in `.local`
35
+
36
+ **Rules for the operator layer:**
37
+
38
+ 1. Holds operator-specific allow lists, machine paths, personal aliases.
39
+ 2. Never committed. `.gitignore` enforces this by listing the files explicitly.
40
+ 3. Each contributor creates their own. The shared `.gitignore` block tells them which files to create.
41
+ 4. Where convenience accumulates — broad `Bash(rm *)` grants, machine-specific paths, etc.
42
+
43
+ ## Mechanical enforcement
44
+
45
+ `.claude/hooks/pre-commit-gate.sh` includes a CCF-3 absolute-path guard. It runs on every `git commit` and BLOCKs when any staged non-exempt file contains `/Users/<name>` or `/home/<name>` patterns.
46
+
47
+ **Exempt paths** (where these patterns are legitimate — documentation, audits, test fixtures):
48
+
49
+ - `.claude/rules/`, `.claude/hooks/`, `.claude/skills/`, `.claude/luminaries/`, `.claude/agents/`
50
+ - `standards/`, `architecture/`, `design/`
51
+ - `docs/` (all subdirs)
52
+ - `chronicle/`, `strategy/`
53
+ - `scripts/tests/`
54
+
55
+ **Non-exempt** (where the guard fires): everything else. Most importantly `.claude/settings.json`, top-level configs, source code under `src/` or `lib/`.
56
+
57
+ When the guard fires, it points to `.claude/settings.local.json` as the right home for the offending entry.
58
+
59
+ ## Override
60
+
61
+ `SKIP_OPERATOR_PATHS=1 git commit` — logged via `trace-helper.sh`. Use only for genuine cases where the absolute path must live in the shared layer (rare). Document the rationale in the commit message.
62
+
63
+ ## What this fixes
64
+
65
+ Before this standard:
66
+
67
+ - `.claude/settings.json` shipped `Bash(rm /Users/<operator>/src/<org>/bassclef/*)` — F70 in the 2026-05-23 cold-adopter run. Every public clone would have inherited that operator-identity line.
68
+ - Allow-list entries reflected operator workflow rather than adopter safety — F73 in the same run.
69
+
70
+ After this standard:
71
+
72
+ - F70 is removed from the committed `.claude/settings.json`.
73
+ - The hook prevents the class from recurring.
74
+ - New operator-convenience entries go to `.claude/settings.local.json`.
75
+
76
+ ## When to add a new field to the operator layer
77
+
78
+ Any of these signals mean it belongs in `settings.local.json`, not `settings.json`:
79
+
80
+ - Contains an absolute path matching `/Users/<name>` or `/home/<name>`.
81
+ - Grants a broad permission (`Bash(rm *)`, `Bash(npm*)`, `Bash(pkill*)`) that an adopter on a first session would not be expected to want.
82
+ - References operator-specific tools or paths (`/Applications/Tailscale.app/...`).
83
+ - Encodes machine-specific config (hostnames, ports tied to a specific dev setup).
84
+
85
+ When in doubt, default to the operator layer. It's cheaper to promote a setting from `settings.local.json` to `settings.json` later than to ship operator identity to every adopter.
86
+
87
+ ## Sources read
88
+
89
+ - `docs/adoption-runs/2026-05-23-cold-adopter-1.md` — the cold-adopter run record (PR #735)
90
+ - Operator handoff CCF-3 + Step 5 Issue 4 — the policy specification
91
+ - F70 (operator path leak in committed `.claude/settings.json`)
92
+ - F73 (allow-list grants reflect operator workflow rather than adopter safety)
93
+ - `.claude/hooks/pre-commit-gate.sh` — the mechanical enforcement
94
+ - `.claude/rules/blocked-items.md` — the resolve-or-defer protocol the BLOCKED signal slots into
95
+
96
+ ## Closes
97
+
98
+ - bassclef#740 (CCF-3 — two-layer config policy)
99
+ - bassclef#738 (Pre-launch cleanup — F70 instance)