@thebassclef/lite 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +40 -6
- package/dist/cli.js +40 -6
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/substrate/.bassclef/lite-manifest.json +999 -92
- package/substrate/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
- package/substrate/.claude/hooks/longrun-prep-compounding-sequence-check.sh +492 -0
- package/substrate/.claude/hooks/pre-commit-gate.sh +1 -2
- package/substrate/.claude/hooks/turn-prose-kiss-check.sh +30 -1
- package/substrate/.claude/luminaries/glenford-myers.md +230 -0
- package/substrate/.claude/luminaries/hunt-thomas.md +115 -0
- package/substrate/.claude/luminaries/hyrum-wright.md +94 -0
- package/substrate/.claude/luminaries/michael-feathers.md +2 -2
- package/substrate/.claude/luminaries/tony-hoare.md +170 -0
- package/substrate/.claude/luminaries/vaughn-vernon.md +50 -0
- package/substrate/.claude/luminaries/w-edwards-deming.md +158 -0
- package/substrate/.claude/rules/accessor-library-discipline.md +138 -0
- package/substrate/.claude/rules/adr-discipline.md +120 -0
- package/substrate/.claude/rules/api-conventions.md +125 -0
- package/substrate/.claude/rules/bootstrap-pair-discipline.md +141 -0
- package/substrate/.claude/rules/cold-adopter-harness-discipline.md +129 -0
- package/substrate/.claude/rules/compounding-axis-fresh-analysis.md +188 -0
- package/substrate/.claude/rules/compounding-sequence-fresh-analysis.md +188 -0
- package/substrate/.claude/rules/defensive-bash.md +68 -0
- package/substrate/.claude/rules/deferred-actions.md +233 -0
- package/substrate/.claude/rules/github-issue-flash-tweet.md +156 -0
- package/substrate/.claude/rules/hook-wire-on-author.md +103 -0
- package/substrate/.claude/rules/iteration-bet-brief-completeness.md +54 -0
- package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +3 -3
- package/substrate/.claude/rules/longrun-prep-plan-doc-compression.md +89 -0
- package/substrate/.claude/rules/loop-discipline.md +81 -0
- package/substrate/.claude/rules/manual-prod-approval.md +100 -0
- package/substrate/.claude/rules/marker-enrichment-discipline.md +99 -0
- package/substrate/.claude/rules/mobile-ephemeral-session.md +109 -0
- package/substrate/.claude/rules/new-dependency-check.md +51 -0
- package/substrate/.claude/rules/option-label-discipline.md +108 -0
- package/substrate/.claude/rules/pattern-annotation.md +100 -0
- package/substrate/.claude/rules/plain-english-discipline.md +11 -9
- package/substrate/.claude/rules/plan-enumeration-needs-value-props.md +211 -0
- package/substrate/.claude/rules/pr-title-shape.md +161 -0
- package/substrate/.claude/rules/prototype-workflow.md +65 -0
- package/substrate/.claude/rules/reserved-skill-names.md +123 -0
- package/substrate/.claude/rules/schema-management.md +49 -0
- package/substrate/.claude/rules/security.md +37 -0
- package/substrate/.claude/rules/skill-composition-declarations.md +124 -0
- package/substrate/.claude/rules/skill-description-clarity.md +247 -0
- package/substrate/.claude/rules/skill-procedure-step-list.md +137 -0
- package/substrate/.claude/rules/stuck-signal-diagnostic.md +140 -0
- package/substrate/.claude/rules/substrate-config-schema.md +98 -0
- package/substrate/.claude/rules/test-list-discipline.md +175 -0
- package/substrate/.claude/rules/test-sufficiency.md +210 -0
- package/substrate/.claude/rules/testing-tier-config.md +145 -0
- package/substrate/.claude/rules/testing.md +38 -0
- package/substrate/.claude/rules/turn-estimate-grounding.md +134 -0
- package/substrate/.claude/rules/visual-hierarchy.md +437 -0
- package/substrate/.claude/rules/we-dont-break-adopters.md +126 -0
- package/substrate/.claude/rules/wu-sequencing-compounds.md +145 -0
- package/substrate/.claude/skills/build/SKILL.md +1 -1
- package/substrate/.claude/skills/chronicle/SKILL.md +55 -0
- package/substrate/.claude/skills/clean-artifacts/SKILL.md +249 -0
- package/substrate/.claude/skills/decompose/SKILL.md +1 -1
- package/substrate/.claude/skills/diagnose/SKILL.md +1 -1
- package/substrate/.claude/skills/feynman/SKILL.md +90 -0
- package/substrate/.claude/skills/howdoi/SKILL.md +1 -1
- package/substrate/.claude/skills/ia-model/SKILL.md +1 -1
- package/substrate/.claude/skills/interaction-design/SKILL.md +1 -1
- package/substrate/.claude/skills/interpret-input/SKILL.md +8 -8
- package/substrate/.claude/skills/journal/SKILL.md +209 -0
- package/substrate/.claude/skills/kiss/SKILL.md +1 -1
- package/substrate/.claude/skills/launch/SKILL.md +14 -23
- package/substrate/.claude/skills/lean-canvas/SKILL.md +1 -1
- package/substrate/.claude/skills/longrun/SKILL.md +45 -8
- package/substrate/.claude/skills/luminary/SKILL.md +1 -1
- package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +1 -1
- package/substrate/.claude/skills/onboard-repo/SKILL.md +143 -709
- package/substrate/.claude/skills/pattern-review/SKILL.md +1 -1
- package/substrate/.claude/skills/personas/SKILL.md +5 -5
- package/substrate/.claude/skills/promote/SKILL.md +1 -1
- package/substrate/.claude/skills/requirement/SKILL.md +1 -1
- package/substrate/.claude/skills/retro/SKILL.md +1 -1
- package/substrate/.claude/skills/riff/SKILL.md +1 -1
- package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +1 -1
- package/substrate/.claude/skills/session-end/SKILL.md +1 -1
- package/substrate/.claude/skills/session-log/SKILL.md +3 -3
- package/substrate/.claude/skills/skills/SKILL.md +1 -1
- package/substrate/.claude/skills/spec/SKILL.md +1 -1
- package/substrate/.claude/skills/sprint/SKILL.md +1 -1
- package/substrate/.claude/skills/stage/SKILL.md +1 -1
- package/substrate/.claude/skills/state-a-problem/SKILL.md +1 -1
- package/substrate/.claude/skills/temperance/SKILL.md +1 -1
- package/substrate/.claude/skills/use-case/SKILL.md +1 -1
- package/substrate/.claude/skills/user-stories/SKILL.md +1 -1
- package/substrate/.claude/skills/value-prop/SKILL.md +1 -1
- package/substrate/.claude/skills/verify/SKILL.md +1 -1
- package/substrate/.claude/skills/visual-review/SKILL.md +503 -0
- package/substrate/.claude/skills/whats-the-plan/SKILL.md +202 -0
- package/substrate/.claude/skills/whereami/SKILL.md +2 -2
- package/substrate/CONTRIBUTING.md +1 -1
- package/substrate/README.md +5 -5
- package/substrate/lib/prose-scan-boundary.sh +171 -0
- package/substrate/lib/tier-check.sh +50 -1
- package/substrate/lib/tier-dependency-audit.sh +159 -4
- package/substrate/presence/install/bassclef-sync.template.sh +1 -1
- package/substrate/scripts/generate-lite-manifest.sh +21 -5
- package/substrate/standards/adr-template.md +86 -0
- package/substrate/standards/api-conventions/nextjs.md +84 -0
- package/substrate/standards/artifact-composition.md +209 -0
- package/substrate/standards/bash-hook-safety.md +246 -0
- package/substrate/standards/branch-stacking.md +408 -0
- package/substrate/standards/code-safety-principles.md +176 -0
- package/substrate/standards/composer-prerequisites.md +155 -0
- package/substrate/standards/dependency-discipline/cargo.md +39 -0
- package/substrate/standards/dependency-discipline/gem.md +43 -0
- package/substrate/standards/dependency-discipline/go-mod.md +41 -0
- package/substrate/standards/dependency-discipline/npm.md +42 -0
- package/substrate/standards/dependency-discipline/pip.md +42 -0
- package/substrate/standards/deployment-topology/ec2-tailscale.md +225 -0
- package/substrate/standards/deployment-topology.md +69 -0
- package/substrate/standards/docs-sync-allowlist.md +4 -4
- package/substrate/standards/domain-and-dns.md +145 -0
- package/substrate/standards/frontend-stack.md +67 -0
- package/substrate/standards/frontmatter-schema.md +154 -0
- package/substrate/standards/hook-injection-discipline.md +202 -0
- package/substrate/standards/hook-install-class.md +215 -0
- package/substrate/standards/input-handler-interface.md +152 -0
- package/substrate/standards/lite-manifest-schema-changes.md +60 -0
- package/substrate/standards/luminary-matching.md +105 -0
- package/substrate/standards/migration-discipline/active-record.md +50 -0
- package/substrate/standards/migration-discipline/alembic.md +43 -0
- package/substrate/standards/migration-discipline/gorm.md +50 -0
- package/substrate/standards/migration-discipline/prisma.md +53 -0
- package/substrate/standards/migration-discipline/sqlalchemy.md +51 -0
- package/substrate/standards/mobile-ephemeral-session.md +167 -0
- package/substrate/standards/model-routing-discipline.md +160 -0
- package/substrate/standards/persona-schema.md +229 -0
- package/substrate/standards/pluggable-luminaries.md +323 -0
- package/substrate/standards/pr-body-discipline.md +115 -0
- package/substrate/standards/preview-state-schema.md +189 -0
- package/substrate/standards/reserved-skill-names.md +120 -0
- package/substrate/standards/scannable-multi-option-output.md +261 -0
- package/substrate/standards/sdlc-gates/typescript.md +57 -0
- package/substrate/standards/session-board.md +256 -0
- package/substrate/standards/state-spine-contract.md +255 -0
- package/substrate/standards/steering-hints/kiss-words.md +11 -0
- package/substrate/standards/substrate-config-schema.md +267 -0
- package/substrate/standards/tier-dependency-analysis.md +1 -1
- package/substrate/standards/tier-tag-schema.md +1 -1
- package/substrate/standards/two-layer-config.md +99 -0
- package/substrate/standards/use-case-format.md +292 -0
- package/substrate/standards/user-story-invest.md +268 -0
- package/substrate/standards/velocity-and-appetite.md +229 -0
- package/substrate/standards/voice-input-pattern.md +119 -0
- package/substrate/standards/worktree-management.md +211 -0
- package/substrate/templates/chronicle-template.md +75 -0
- package/substrate/templates/memory-proposal-template.md +77 -0
- package/substrate/templates/persona-template.md +200 -0
- package/substrate/templates/pr-faq.md +45 -0
- package/substrate/templates/secret-rotation-template.md +162 -0
- package/substrate/templates/spec-template.md +131 -0
- package/substrate/templates/use-case-template.md +194 -0
- package/substrate/templates/user-story-template.md +107 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: "This standard codifies the defensive coding discipline for bassclef's bash hooks (.claude/hooks/.sh) + supporting bash scripts (scripts/.sh, lib/*.sh)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Bash Hook Safety Standard
|
|
7
|
+
|
|
8
|
+
This standard codifies the defensive coding discipline for bassclef's bash hooks (`.claude/hooks/*.sh`) + supporting bash scripts (`scripts/*.sh`, `lib/*.sh`). It is the bash-specific instantiation of `standards/code-safety-principles.md`.
|
|
9
|
+
|
|
10
|
+
## Why this standard exists
|
|
11
|
+
|
|
12
|
+
Bassclef's hooks are bash scripts that fire on every tool call. They sit between the operator's intent and every Edit / Write / Bash invocation. A bug in a hook is amplified: every session in every consumer repo runs the hook on every tool call. Three months of substrate-evolution surfaced four same-shape failures (bassclef#1027, #1054, #1058, #1060) — all in bash code, all caught after PR open, all preventable by hooks at the moment of failure.
|
|
13
|
+
|
|
14
|
+
The existing `.claude/rules/security.md` is scoped to web-application source files (`.ts`, `.tsx`, `.json`, `.env`, `Dockerfile`). It does not cover `.sh`. This standard closes that gap with hook-specific discipline anchored to Saltzer & Schroeder's 8 principles per `@luminary saltzer-schroeder`.
|
|
15
|
+
|
|
16
|
+
## Anchors
|
|
17
|
+
|
|
18
|
+
- `@luminary saltzer-schroeder` — the 8 protection-mechanism principles this standard instantiates
|
|
19
|
+
- `@luminary john-ousterhout` — Deep modules + define-errors-out-of-existence framing for hook interface design
|
|
20
|
+
- `@luminary kent-beck` — TDD discipline for hooks (Tier 0 per `.claude/rules/testing-tier-config.md`)
|
|
21
|
+
- `standards/code-safety-principles.md` — language-agnostic principles this standard instantiates for bash
|
|
22
|
+
|
|
23
|
+
## The seven disciplines
|
|
24
|
+
|
|
25
|
+
### 1. Strict mode at the top
|
|
26
|
+
|
|
27
|
+
Every bash hook + script starts with:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
#!/bin/bash
|
|
31
|
+
set -euo pipefail
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `-e` exits on any command failure
|
|
35
|
+
- `-u` exits on undefined variable use
|
|
36
|
+
- `-o pipefail` makes pipelines fail if any stage fails (default is "last stage's exit code only")
|
|
37
|
+
|
|
38
|
+
INSTEAD of "I'll handle errors explicitly where they matter": strict mode makes errors loud by default. Explicit error handling overrides apply per-command via `command || true` or `command 2>/dev/null` with intent.
|
|
39
|
+
|
|
40
|
+
**Why mandatory**: bash's default behavior is "continue on error, use the empty string for undefined variables." Bassclef's hooks run in environments where silent failure causes incorrect downstream state. PR #1054 demonstrated this: `log()` function's quiet-mode toggle behavior depended on an unset variable being treated as false; strict mode would have surfaced the bug at write-time.
|
|
41
|
+
|
|
42
|
+
### 2. Quote every variable expansion
|
|
43
|
+
|
|
44
|
+
Every `$var` or `${var}` reference inside a string context gets double-quoted:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Correct
|
|
48
|
+
file_path="$1"
|
|
49
|
+
if [[ -f "$file_path" ]]; then
|
|
50
|
+
cat "$file_path"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Wrong — word-splits on spaces; glob-expands; breaks on empty
|
|
54
|
+
if [[ -f $1 ]]; then
|
|
55
|
+
cat $1
|
|
56
|
+
fi
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
INSTEAD of "I know this variable will never contain a space": quote universally. The cost of consistent quoting is zero; the cost of one missed quote in a path with a space is silent corruption.
|
|
60
|
+
|
|
61
|
+
**Exception**: `local` declarations of arrays + variables that intentionally word-split (rare; document with an inline comment).
|
|
62
|
+
|
|
63
|
+
### 3. `local` in functions
|
|
64
|
+
|
|
65
|
+
Every variable declared inside a function uses `local`:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
parse_config() {
|
|
69
|
+
local config_path="$1"
|
|
70
|
+
local mode="${2:-default}"
|
|
71
|
+
# ...
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
INSTEAD of relying on bash's default of global scope: `local` keeps function-internal state inside the function. A function that pollutes parent scope is a defect waiting to surface — the bug appears when a different caller reuses the same variable name.
|
|
76
|
+
|
|
77
|
+
### 4. Trap EXIT for cleanup
|
|
78
|
+
|
|
79
|
+
Hooks that create temporary files, lock files, or background processes register a trap for cleanup:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
TMP_DIR=$(mktemp -d)
|
|
83
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
84
|
+
|
|
85
|
+
# ... use $TMP_DIR ...
|
|
86
|
+
# Cleanup happens automatically on any exit path
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
INSTEAD of "I'll clean up at the end of the happy path": cleanup at every exit path including error paths and SIGINT. `trap '...' EXIT` runs the cleanup regardless of how the script exits.
|
|
90
|
+
|
|
91
|
+
For hooks specifically: clean up `/tmp` markers, release `flock`s, kill background `tee`s.
|
|
92
|
+
|
|
93
|
+
### 5. Explicit return codes
|
|
94
|
+
|
|
95
|
+
Hook exit codes carry meaning. Bassclef's hook protocol:
|
|
96
|
+
|
|
97
|
+
- `0` — allow the tool call (default)
|
|
98
|
+
- `1` — generic non-blocking failure (usually a bug in the hook itself; logged but doesn't block)
|
|
99
|
+
- `2` — BLOCK the tool call (the operator-facing surface)
|
|
100
|
+
- `>2` — reserved; treat as `1`
|
|
101
|
+
|
|
102
|
+
Every hook ends with explicit `exit 0` (or `exit 2` on block). Relying on bash's "exit code of last command" default produces silent breakage when refactors reorder statements.
|
|
103
|
+
INSTEAD of implicit "last-command exit code": explicit `exit N` at every termination point. Hook readers should see the exit value next to the BLOCK decision.
|
|
104
|
+
|
|
105
|
+
### 6. Glob-tolerance via fallthrough
|
|
106
|
+
|
|
107
|
+
Bash's `for f in pattern/*` fails silently when the pattern matches nothing — the loop body runs once with the literal pattern string. The shape that tolerates empty match:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
shopt -s nullglob # empty match = empty loop, not literal pattern
|
|
111
|
+
|
|
112
|
+
for f in "$dir"/*.json; do
|
|
113
|
+
process "$f"
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
shopt -u nullglob # restore default
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
INSTEAD of assuming a glob always matches: `nullglob` makes empty-match an empty loop. The hook handles "no files" naturally.
|
|
120
|
+
|
|
121
|
+
For one-off patterns: `[[ ${#files[@]} -gt 0 ]]` after assigning to an array via `files=("$dir"/*.json)`.
|
|
122
|
+
|
|
123
|
+
### 7. Audit emission at every exit path
|
|
124
|
+
|
|
125
|
+
Every hook emits a trace record before exit:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
source "$(dirname "$0")/../lib/trace-helper.sh"
|
|
129
|
+
|
|
130
|
+
# ... hook body ...
|
|
131
|
+
|
|
132
|
+
trace_record "hook-name" "decision" "context"
|
|
133
|
+
exit 0
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
INSTEAD of audit-only-on-block: audit on allow + block + override usage + skip path. Post-incident reconstruction needs the full trace.
|
|
137
|
+
|
|
138
|
+
## Common idioms
|
|
139
|
+
|
|
140
|
+
### `find | head` under `set -euo pipefail` — SIGPIPE kills the script
|
|
141
|
+
|
|
142
|
+
Under `set -euo pipefail`, piping `find` into `head -N` can silently kill the script when `find` produces more than N results. `head` closes stdin after N lines, `find` receives SIGPIPE from the closed pipe, `find` exits 141, and `pipefail` promotes 141 to the pipeline exit code. `set -e` then kills the script silently.
|
|
143
|
+
|
|
144
|
+
Anti-pattern:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
set -euo pipefail
|
|
148
|
+
broken=$(find . -type l \! -exec test -e {} \; -print 2>/dev/null | head -10)
|
|
149
|
+
# ^ script may exit here with no error output when find produces >10 results
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
INSTEAD — Option 5d (preferred): bash-native array truncation. No pipe means no SIGPIPE.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
set -euo pipefail
|
|
156
|
+
readarray -t all_broken < <(find . -type l \! -exec test -e {} \; -print 2>/dev/null)
|
|
157
|
+
broken="$(printf '%s\n' "${all_broken[@]:0:10}")"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Three alternatives, each with tradeoffs:
|
|
161
|
+
|
|
162
|
+
- **SIGPIPE catch** — `find ... 2>/dev/null | head -10 || true`. Swallows all pipeline errors including real ones; less specific than the SIGPIPE-only class.
|
|
163
|
+
- **No-pipe restructure** — `find ... -print | while read; do ... done` with an explicit counter break. More lines; keeps structural-code style.
|
|
164
|
+
- **Fallthrough with `|| true`** — cheapest to write; hides every non-zero pipeline exit; least safe under production loads.
|
|
165
|
+
|
|
166
|
+
Option 5d preserves the structural read shape AND removes the SIGPIPE vector at the source. Strictly stronger error propagation than SIGPIPE catch — the pipe never exists, so no pipe error class can fire.
|
|
167
|
+
|
|
168
|
+
Anchors:
|
|
169
|
+
|
|
170
|
+
- `@luminary linus-torvalds` — adopter contract on observable script behavior; silent-exit is worse than loud-fail
|
|
171
|
+
- `@luminary michael-feathers` — characterization test pins the FAIL contract (find-produces-N-plus-1 case) before the fix ships
|
|
172
|
+
|
|
173
|
+
Per sunj-labs/bassclef-upstream#912. Cure 4 shipped inside the #901 install-corrupts-tree epic; PR #892 carries the exemplar. See the ticket body for the second-AI consultation write-up + the linus lens shift from Option 1 (SIGPIPE catch) to Option 5d.
|
|
174
|
+
|
|
175
|
+
## The Saltzer & Schroeder stack-translation
|
|
176
|
+
|
|
177
|
+
This standard's seven disciplines instantiate Saltzer & Schroeder's 8 principles (per `@luminary saltzer-schroeder` stack-translation table):
|
|
178
|
+
|
|
179
|
+
| Saltzer & Schroeder principle | Bash discipline |
|
|
180
|
+
|---|---|
|
|
181
|
+
| Economy of mechanism | Hook body ≤200 lines; helpers in `lib/*.sh` |
|
|
182
|
+
| Fail-safe defaults | Strict mode `set -euo pipefail`; default `exit 2` on uncertainty |
|
|
183
|
+
| Complete mediation | PreToolUse fires on every matching call |
|
|
184
|
+
| Open design | Triggers documented in `docs/hooks-index.md`; BLOCK banners name the read path |
|
|
185
|
+
| Separation of privilege | Destructive hooks require multiple independent signals |
|
|
186
|
+
| Least privilege | `cd` only when needed; scope git/file ops to specific paths |
|
|
187
|
+
| Least common mechanism | Per-hook trace; per-hook test; no global state between hooks |
|
|
188
|
+
| Psychological acceptability | `SKIP_<HOOK>=1` per-call override; logged via trace-helper |
|
|
189
|
+
|
|
190
|
+
## Shellcheck
|
|
191
|
+
|
|
192
|
+
Every bash hook + script passes `shellcheck` (current version). Tier 0 strict-TDD discipline per `.claude/rules/testing-tier-config.md` extends to shellcheck: an edit that introduces a shellcheck finding fails CI per Phase X-4's shellcheck workflow.
|
|
193
|
+
|
|
194
|
+
**Local install**:
|
|
195
|
+
|
|
196
|
+
| OS | Command |
|
|
197
|
+
|---|---|
|
|
198
|
+
| macOS | `brew install shellcheck` |
|
|
199
|
+
| Ubuntu/Debian | `apt install shellcheck` |
|
|
200
|
+
| Fedora | `dnf install ShellCheck` |
|
|
201
|
+
| Arch | `pacman -S shellcheck` |
|
|
202
|
+
| Container builds | Add `shellcheck` to the base image |
|
|
203
|
+
|
|
204
|
+
**Local run**:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
shellcheck .claude/hooks/*.sh scripts/*.sh lib/*.sh
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Phase X-4** ships the CI workflow that runs shellcheck on every PR + a baseline allowlist (`.claude/hooks/shellcheck-allowlist.txt`) with 60-day grace through 2026-08-17 for existing findings.
|
|
211
|
+
|
|
212
|
+
## What this standard does NOT do
|
|
213
|
+
|
|
214
|
+
- Does not cover language interop (bash calling Python, Python calling bash) — handle at the boundary
|
|
215
|
+
- Does not specify which utilities to use (`gh` vs `curl` vs `jq` vs `yq`) — that is a stack-choice question
|
|
216
|
+
- Does not cover bash 4+ features absent from macOS's default install (`${var^^}` uppercase conversion, associative arrays) — bash 3.2 compatibility is the baseline.
|
|
217
|
+
INSTEAD of using a bash 4+ feature implicitly: opt in via explicit shebang line (`#!/usr/bin/env bash` with version check) or fallback shape.
|
|
218
|
+
|
|
219
|
+
## When this standard fires
|
|
220
|
+
|
|
221
|
+
| Surface | Check |
|
|
222
|
+
|---|---|
|
|
223
|
+
| New hook in `.claude/hooks/` | All 7 disciplines + shellcheck-clean + sibling test (Tier 0) |
|
|
224
|
+
| New script in `scripts/` | All 7 disciplines + shellcheck-clean (Tier 1) |
|
|
225
|
+
| Edit to existing hook | Same — Phase A's testing-tier hook BLOCKs without test mtime ≤ source mtime |
|
|
226
|
+
| Code review on PR touching `.sh` | Reviewer applies the 7 disciplines |
|
|
227
|
+
| `/security-review` skill invocation | Skill cites this standard for any `.sh` change |
|
|
228
|
+
|
|
229
|
+
## Refs
|
|
230
|
+
|
|
231
|
+
- `@luminary saltzer-schroeder` — anchor
|
|
232
|
+
- `@luminary john-ousterhout` — Deep modules framing for hook interface design
|
|
233
|
+
- `@luminary kent-beck` — TDD anchor; Tier 0 strict-TDD discipline applies
|
|
234
|
+
- `standards/code-safety-principles.md` — language-agnostic principles this standard instantiates
|
|
235
|
+
- `.claude/rules/destructive-operations.md` — agent self-assessment companion
|
|
236
|
+
- `.claude/rules/security.md` — web-layer rule (`.ts/.tsx/.json/.env/Dockerfile` scope); this standard extends to bash
|
|
237
|
+
- `.claude/rules/testing-tier-config.md` — Tier 0 strict-TDD discipline for hooks
|
|
238
|
+
- `.claude/rules/defensive-bash.md` — companion methodology rule (auto-loaded; points here)
|
|
239
|
+
- `.github/workflows/shellcheck.yml` (Phase X-4) — CI enforcement
|
|
240
|
+
- bassclef#1054 — `log()` quiet-mode bug (strict-mode would have caught at write-time)
|
|
241
|
+
- bassclef#1058 — auto-save scope hole (fail-safe-defaults + least-privilege violation)
|
|
242
|
+
- docs/iteration-bets/2026-06-17a-secure-coding-foundations-longrun.md — goal authoring this standard
|
|
243
|
+
|
|
244
|
+
## Retirement
|
|
245
|
+
|
|
246
|
+
This standard retires only if bassclef migrates off bash for its hook implementation language (e.g., adopting Python or Go for hooks). The 7 disciplines themselves remain valid; the language-specific instantiation changes.
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: Stacked atomic branches are the default for any iteration with N≥2 issues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Branch Stacking Standard
|
|
7
|
+
|
|
8
|
+
## Default for multi-issue iterations
|
|
9
|
+
|
|
10
|
+
**Stacked atomic branches are the default** for any iteration with N≥2
|
|
11
|
+
issues. One branch per issue, one PR per branch, each independently
|
|
12
|
+
reviewable and revertable. The `bundle` flag at `/autonomous start`
|
|
13
|
+
overrides this; see `.claude/rules/pr-strategy.md` for when bundling is
|
|
14
|
+
acceptable.
|
|
15
|
+
|
|
16
|
+
This is codified — the boot sequence does not ask "stacked or bundled?"
|
|
17
|
+
per session.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
Autonomous or multi-step sessions where work spans multiple logical units
|
|
22
|
+
that should be independently reviewable and revertable. This extends the
|
|
23
|
+
trunk-based model in `.claude/rules/branching.md` for multi-branch work.
|
|
24
|
+
|
|
25
|
+
Use this standard when:
|
|
26
|
+
- An agent (or agents) will produce more than one PR in a session
|
|
27
|
+
- Work has a natural decomposition into independent or sequenced units
|
|
28
|
+
- You want the ability to accept some branches and reject others
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Core principle
|
|
33
|
+
|
|
34
|
+
**Each branch = one intent.** A branch does one thing: "Add the data model"
|
|
35
|
+
or "Build the list view" — not "Add data model and list view and API routes."
|
|
36
|
+
|
|
37
|
+
If you can't describe a branch's intent in one sentence, split it.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Stack manifest
|
|
42
|
+
|
|
43
|
+
Before building, the agent writes a manifest declaring the planned stack.
|
|
44
|
+
This is the iteration's work breakdown and the Orchestrator's routing map.
|
|
45
|
+
|
|
46
|
+
**Location**: `docs/branch-stacks/YYYY-MM-DD-slug.md` in the working repo.
|
|
47
|
+
|
|
48
|
+
### Format
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
# Branch Stack: [name]
|
|
52
|
+
|
|
53
|
+
**Issue**: #NNN
|
|
54
|
+
**Iteration goal**: [path to iteration goal]
|
|
55
|
+
**Execution mode**: sequential | parallel | mixed
|
|
56
|
+
**Date**: YYYY-MM-DD
|
|
57
|
+
|
|
58
|
+
## Branches
|
|
59
|
+
|
|
60
|
+
| # | Branch | Intent | Depends on | Parallel-safe |
|
|
61
|
+
|---|--------|--------|-----------|---------------|
|
|
62
|
+
| 1 | feature/NNN-stack-1-data-model | CRM schema + migration | none | yes |
|
|
63
|
+
| 2 | feature/NNN-stack-2-api-routes | CRUD API for entities | stack-1 | no |
|
|
64
|
+
| 3 | feature/NNN-stack-3-list-view | List page UI | stack-1 | yes |
|
|
65
|
+
| 4 | feature/NNN-stack-4-detail-view | Detail page UI | stack-3 | no |
|
|
66
|
+
|
|
67
|
+
## Parallel groups
|
|
68
|
+
|
|
69
|
+
- Group A (no dependencies): stack-1
|
|
70
|
+
- Group B (after stack-1 merged): stack-2, stack-3 (parallel)
|
|
71
|
+
- Group C (after stack-3 merged): stack-4
|
|
72
|
+
|
|
73
|
+
## Acceptance criteria per branch
|
|
74
|
+
|
|
75
|
+
### stack-1: data-model
|
|
76
|
+
- [ ] Prisma schema with migration file
|
|
77
|
+
- [ ] prisma generate succeeds
|
|
78
|
+
- [ ] Seed script if needed
|
|
79
|
+
|
|
80
|
+
### stack-2: api-routes
|
|
81
|
+
- [ ] CRUD endpoints with tests
|
|
82
|
+
- [ ] Auth middleware applied
|
|
83
|
+
|
|
84
|
+
[... etc]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Execution modes
|
|
90
|
+
|
|
91
|
+
### Sequential (supervised sessions)
|
|
92
|
+
|
|
93
|
+
One agent, one branch at a time. Human checkpoint between branches.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Agent builds stack-1
|
|
97
|
+
→ PR opened → human reviews → approved → merge to main
|
|
98
|
+
Agent builds stack-2
|
|
99
|
+
→ PR opened → human reviews → approved → merge to main
|
|
100
|
+
[...]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Branch base**: Each branch is based on `main` (after the previous branch
|
|
104
|
+
is merged). This means each branch includes the accumulated work of prior
|
|
105
|
+
branches but is independently reviewable as a PR.
|
|
106
|
+
|
|
107
|
+
**Human checkpoint**: After each branch, the agent opens a PR and stops.
|
|
108
|
+
Human reviews. Approved → merge → agent proceeds. Rejected → agent adjusts
|
|
109
|
+
or the branch is discarded.
|
|
110
|
+
|
|
111
|
+
### Parallel (Cherny's worktree model)
|
|
112
|
+
|
|
113
|
+
Multiple agents in git worktrees (`claude -w`), each on its own branch,
|
|
114
|
+
building simultaneously. No dirty tree conflicts — each worktree is an
|
|
115
|
+
isolated copy of the repo.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
Orchestrator reads stack manifest
|
|
119
|
+
→ Independent branches fan out to parallel worktree agents
|
|
120
|
+
→ Dependent branches queue behind prerequisites
|
|
121
|
+
|
|
122
|
+
Agent A (worktree 1): stack-2-api-routes
|
|
123
|
+
Agent B (worktree 2): stack-3-list-view
|
|
124
|
+
[building simultaneously, no conflicts]
|
|
125
|
+
|
|
126
|
+
Each agent opens its own PR when done
|
|
127
|
+
Human reviews PRs after session (or Reviewer agent evaluates)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Branch base for parallel work**: Independent branches base off `main`.
|
|
131
|
+
When a branch depends on another (stack-4 depends on stack-3), it bases
|
|
132
|
+
off the dependency branch. The manifest makes this explicit.
|
|
133
|
+
|
|
134
|
+
**Worktree lifecycle**:
|
|
135
|
+
- Created by Orchestrator (or human) when fanning out parallel work
|
|
136
|
+
- Each worktree gets one branch, one agent
|
|
137
|
+
- On completion: agent opens PR, worktree is available for cleanup
|
|
138
|
+
- Merged worktrees: deleted automatically after merge
|
|
139
|
+
- Abandoned worktrees (no commits after 2 hours): flagged for cleanup
|
|
140
|
+
- Worktree cleanup command: `git worktree prune`
|
|
141
|
+
|
|
142
|
+
**Conflict detection**: If two parallel agents modify the same file,
|
|
143
|
+
the Orchestrator flags this to the human. Do not attempt auto-resolution —
|
|
144
|
+
file-level conflicts in parallel branches indicate a decomposition problem
|
|
145
|
+
(the branches weren't truly independent). Fix the manifest, not the merge.
|
|
146
|
+
|
|
147
|
+
### Mixed (common in practice)
|
|
148
|
+
|
|
149
|
+
Some branches are independent (parallelize), some are dependent (sequence).
|
|
150
|
+
The manifest's dependency graph determines which is which.
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Group A: stack-1 (alone, must complete first)
|
|
154
|
+
Group B: stack-2 + stack-3 (parallel, both depend on stack-1)
|
|
155
|
+
Group C: stack-4 (sequential, depends on stack-3)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The Orchestrator executes Group A, waits for merge, fans out Group B in
|
|
159
|
+
parallel worktrees, waits for Group B merges, then executes Group C.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Graceful unwind
|
|
164
|
+
|
|
165
|
+
If branch N is rejected:
|
|
166
|
+
- **Branches that depend on N** (per manifest): also discarded
|
|
167
|
+
- **Branches independent of N**: survive untouched
|
|
168
|
+
- **Agent never needs to untangle** — independence is designed in, not retrofitted
|
|
169
|
+
|
|
170
|
+
The dependency graph in the manifest makes this mechanical:
|
|
171
|
+
1. Look up what depends on N (transitively)
|
|
172
|
+
2. Discard N and all its dependents
|
|
173
|
+
3. Everything else is unaffected
|
|
174
|
+
|
|
175
|
+
This is why independence is the default and dependencies are the exception.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Squash merge — two protocols
|
|
180
|
+
|
|
181
|
+
When merging stacked PRs whose bases are other feature branches
|
|
182
|
+
(Graphite-style stack — common when the agent declares "depends on"
|
|
183
|
+
in the manifest), GitHub auto-closes dependent PRs the moment the
|
|
184
|
+
base branch is deleted. ("Cannot change the base branch of a closed
|
|
185
|
+
pull request.") Recovery requires re-creating each PR. Costs ~3-8
|
|
186
|
+
turns per stack. Observed 2026-04-18c (#178/#179/#180 cascade).
|
|
187
|
+
|
|
188
|
+
Two protocols handle this. Pick by **when** you can act:
|
|
189
|
+
|
|
190
|
+
| Protocol | When to use | Trade-off |
|
|
191
|
+
|----------|-------------|-----------|
|
|
192
|
+
| **Retarget-before-merge** (preferred) | You have access to the dependent PRs before merging stack-N | Cleanest — no auto-close, no recovery cost |
|
|
193
|
+
| **Rebase-after-merge** (fallback) | Auto-close already happened, OR you forgot to retarget | Recoverable but expensive — per-PR rebase + re-create |
|
|
194
|
+
|
|
195
|
+
If the iteration uses **base = main** for every branch (independence
|
|
196
|
+
designed in via manifest, no Graphite-style chaining), neither cascade
|
|
197
|
+
fires — but stacked PRs with declared dependencies almost always use
|
|
198
|
+
chained bases.
|
|
199
|
+
|
|
200
|
+
### Retarget-before-merge (preferred)
|
|
201
|
+
|
|
202
|
+
**Before** squash-merging PR N in a stack:
|
|
203
|
+
|
|
204
|
+
1. **Identify dependent PRs** — those whose `baseRefName` equals
|
|
205
|
+
PR N's `headRefName`. Use the helper script:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
scripts/check-stack-dependents.sh <PR-N-number>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
This lists open PRs that will auto-close if PR N merges and its
|
|
212
|
+
branch is deleted.
|
|
213
|
+
|
|
214
|
+
2. **Retarget each dependent to main** (or the stack root):
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
gh pr edit <dependent-PR-number> --base main
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The dependent PR survives the merge. Its diff may now show extra
|
|
221
|
+
commits (the work from PR N) until the dependent is rebased — but
|
|
222
|
+
it stays open.
|
|
223
|
+
|
|
224
|
+
3. **Merge PR N**:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
gh pr merge <PR-N-number> --squash --delete-branch
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Auto-close cascade does not fire because no other PR has PR N's
|
|
231
|
+
branch as base anymore.
|
|
232
|
+
|
|
233
|
+
4. **(Optional) Rebase dependent on top of merged main** if you want
|
|
234
|
+
the diff to show only the dependent's own work:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
git checkout <dependent-branch>
|
|
238
|
+
git pull origin main --rebase
|
|
239
|
+
git push --force-with-lease
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
5. **Repeat** for the next PR in stack order.
|
|
243
|
+
|
|
244
|
+
#### Why this works
|
|
245
|
+
|
|
246
|
+
The auto-close trigger is "base branch deleted on a closed/merged PR
|
|
247
|
+
where another PR depends on it." Retarget breaks the dependency
|
|
248
|
+
*before* the delete fires. The dependents continue tracking main; their
|
|
249
|
+
content is unchanged.
|
|
250
|
+
|
|
251
|
+
### Rebase-after-merge (fallback)
|
|
252
|
+
|
|
253
|
+
Use only if the cascade has already fired (dependent PRs show
|
|
254
|
+
"Closed — base branch was deleted") OR you forgot the retarget step.
|
|
255
|
+
|
|
256
|
+
After squash-merging PR N in a stack (without prior retarget):
|
|
257
|
+
|
|
258
|
+
1. **Pull updated main**: `git checkout main && git pull`
|
|
259
|
+
2. **Rebase the next branch**: `git checkout feature/next && git rebase main`
|
|
260
|
+
3. **Force push with lease**: `git push --force-with-lease`
|
|
261
|
+
(safe force push — fails if someone else pushed to the branch)
|
|
262
|
+
4. **If GitHub auto-closed the downstream PR**: re-create it pointing
|
|
263
|
+
at main, since the closed PR cannot be reopened with a new base:
|
|
264
|
+
```bash
|
|
265
|
+
gh pr create --base main --head feature/next \
|
|
266
|
+
--title "[same as closed PR]" \
|
|
267
|
+
--body "[same as closed PR, plus link to closed PR for context]"
|
|
268
|
+
```
|
|
269
|
+
Or merge locally:
|
|
270
|
+
```bash
|
|
271
|
+
git checkout main
|
|
272
|
+
git merge --squash feature/next
|
|
273
|
+
git commit -m "feat: description"
|
|
274
|
+
```
|
|
275
|
+
5. **Repeat** for remaining branches in stack order
|
|
276
|
+
|
|
277
|
+
#### Why this happens
|
|
278
|
+
|
|
279
|
+
Squash merge creates a single new commit on main that replaces all
|
|
280
|
+
commits from the branch. The next branch's base commits no longer exist
|
|
281
|
+
on main — they were squashed into one. GitHub sees a conflict because
|
|
282
|
+
the branch history diverged from main. Combined with branch deletion,
|
|
283
|
+
the auto-close cascade fires for any dependent PR.
|
|
284
|
+
|
|
285
|
+
### Auto-save checkpoint conflicts
|
|
286
|
+
|
|
287
|
+
If the auto-save launchd timer committed checkpoint files (e.g.,
|
|
288
|
+
`.test-baseline`) on feature branches during construction, these
|
|
289
|
+
checkpoints will conflict during rebase. Use `git rebase --skip` to
|
|
290
|
+
drop the checkpoint commits — they're not part of the real work.
|
|
291
|
+
|
|
292
|
+
The auto-save timer should be paused during autonomous sessions
|
|
293
|
+
(SESSION_LOCK check, see #62).
|
|
294
|
+
|
|
295
|
+
### Alternative: regular merge commits
|
|
296
|
+
|
|
297
|
+
Using regular merge commits (no squash) preserves branch relationships
|
|
298
|
+
and avoids the rebase cascade. Trade-off: messier main history with
|
|
299
|
+
merge commits. Squash is still preferred for a clean main, but the
|
|
300
|
+
rebase step is the cost.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Naming convention
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
feature/ISSUE-NNN-stack-N-short-description
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Examples:
|
|
311
|
+
- `feature/47-stack-1-crm-data-model`
|
|
312
|
+
- `feature/47-stack-2-crm-api-routes`
|
|
313
|
+
- `feature/47-stack-3-crm-list-view`
|
|
314
|
+
|
|
315
|
+
The `stack-N` segment makes merge ordering obvious in `git branch` output
|
|
316
|
+
and GitHub's PR list.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Per-branch verification
|
|
321
|
+
|
|
322
|
+
Each branch passes `/verify` independently before the PR is opened.
|
|
323
|
+
CI must pass on each branch in isolation. A branch that only works when
|
|
324
|
+
combined with another branch is not atomic — fix the decomposition.
|
|
325
|
+
|
|
326
|
+
Exception: Dependent branches (stack-4 depends on stack-3) are verified
|
|
327
|
+
against their base branch, not against main alone.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Automatic stack creation (via /autonomous)
|
|
332
|
+
|
|
333
|
+
When `/autonomous start` enters Construction, the Orchestrator runs a
|
|
334
|
+
five-step automation sequence (defined in strategy/autonomous-boot-sequence.md Step 9).
|
|
335
|
+
This section documents what the automation produces so agents know what
|
|
336
|
+
to expect when picking up a stack mid-session.
|
|
337
|
+
|
|
338
|
+
### What gets created automatically
|
|
339
|
+
|
|
340
|
+
**1. GitHub issues** — one per task, created via `gh issue create`.
|
|
341
|
+
Each issue includes: what, acceptance criteria, and a ref to the
|
|
342
|
+
iteration goal. Issue numbers are assigned before any branch is created.
|
|
343
|
+
|
|
344
|
+
**2. Stack manifest** — written to `docs/branch-stacks/YYYY-MM-DD-slug.md`
|
|
345
|
+
before any branch is created. The manifest is committed first so all
|
|
346
|
+
agents can find it.
|
|
347
|
+
|
|
348
|
+
**3. Branches** — created from main in dependency order, named
|
|
349
|
+
`feature/ISSUE-NNN-stack-N-short-description`.
|
|
350
|
+
|
|
351
|
+
### Automation invariants
|
|
352
|
+
|
|
353
|
+
- The manifest is always committed before branches are created.
|
|
354
|
+
If you see a branch without a manifest, the automation was interrupted.
|
|
355
|
+
- Issue numbers in the manifest are real GitHub issue numbers.
|
|
356
|
+
A placeholder NNN means the automation did not complete — finish it.
|
|
357
|
+
- Every branch bases from main, not from the previous branch.
|
|
358
|
+
Stacked rebases follow the squash-merge protocol in this document.
|
|
359
|
+
- The manifest is updated after each PR opens (status: pr-open) and
|
|
360
|
+
after each merge (status: merged). Pending = not yet started.
|
|
361
|
+
|
|
362
|
+
### Resuming an interrupted stack
|
|
363
|
+
|
|
364
|
+
If the automation was interrupted (crash, time budget exhausted, pause),
|
|
365
|
+
the next session reads:
|
|
366
|
+
|
|
367
|
+
1. `docs/branch-stacks/YYYY-MM-DD-slug.md` — what's done, what's pending
|
|
368
|
+
2. `docs/whereami.md` — branch_stack field points at the manifest
|
|
369
|
+
3. GitHub issues — open issues with no linked PR are pending branches
|
|
370
|
+
|
|
371
|
+
Resume from the first branch with status "pending" in the manifest.
|
|
372
|
+
Do not re-create issues or rewrite the manifest unless it is corrupted.
|
|
373
|
+
|
|
374
|
+
### Manual stack creation (non-autonomous sessions)
|
|
375
|
+
|
|
376
|
+
The standard still applies for manually created stacks — write the
|
|
377
|
+
manifest first, create issues, then branches. The automation does this
|
|
378
|
+
programmatically. Format and invariants are identical.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Integration with process framework
|
|
383
|
+
|
|
384
|
+
| Concept | Maps to |
|
|
385
|
+
|---------|---------|
|
|
386
|
+
| Branch stack | Iteration |
|
|
387
|
+
| Stack manifest | Iteration work breakdown |
|
|
388
|
+
| Individual branch | Task within iteration |
|
|
389
|
+
| Iteration goal | Governs the whole stack |
|
|
390
|
+
| Parallel groups | Orchestrator routing |
|
|
391
|
+
|
|
392
|
+
Individual branches do not need their own iteration goals. The stack-level
|
|
393
|
+
bet covers time budget, risk, and value for the entire body of work.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Relation to existing branching rules
|
|
398
|
+
|
|
399
|
+
This standard extends `.claude/rules/branching.md`. All existing rules
|
|
400
|
+
still apply:
|
|
401
|
+
- `main` is always deployable
|
|
402
|
+
- Every branch ties to a GitHub Issue (stack branches share the parent issue)
|
|
403
|
+
- Squash merge to main
|
|
404
|
+
- No branches older than 5 days
|
|
405
|
+
- Force push on feature branches is fine, never on main
|
|
406
|
+
|
|
407
|
+
The addition: branches can now be explicitly sequenced and parallelized
|
|
408
|
+
via a stack manifest, with graceful unwind as a first-class property.
|