diff --git a/.github/workflows/git-policy.yml b/.github/workflows/git-policy.yml index 39b627f..fd49a1e 100644 --- a/.github/workflows/git-policy.yml +++ b/.github/workflows/git-policy.yml @@ -56,6 +56,8 @@ jobs: else node scripts/check-commit-message.mjs "$PR_TITLE" fi + - name: Check template cleanliness + run: cd code && npm run book:release-check validate-protected-push: if: github.event_name == 'push' @@ -79,3 +81,5 @@ jobs: else echo "No non-merge commits in range; nothing to validate." fi + - name: Check template cleanliness + run: cd code && npm run book:release-check diff --git a/ADOPT.md b/ADOPT.md index d250f7f..4ed0827 100644 --- a/ADOPT.md +++ b/ADOPT.md @@ -48,7 +48,7 @@ Every migrated file gets a frontmatter `description` — one plain-language line 1. Copy `code/tools/gen-book-index.mjs` and wire the script (see the `scripts` block in BoCode's `code/package.json`). If the project has no JavaScript tooling at all, a shell wrapper calling `node` is fine — the script is zero-dependency. 2. Optional, recommended: copy `scripts/check-commit-message.mjs` and `.githooks/`, then run `git config core.hooksPath .githooks`. -3. Optional: copy `.github/workflows/git-policy.yml`. **Check the branch names** — if the project's integration branch isn't `dev`, either ask the user to adopt the branch model or adapt the workflow's branch filters. Don't silently rewrite their branch model. +3. Optional: copy `.github/workflows/git-policy.yml`. **Check the branch names** — if the project's integration branch isn't `dev`, either ask the user to adopt the branch model or adapt the workflow's branch filters. Don't silently rewrite their branch model. Also **delete the "Check template cleanliness" step** — it enforces the BoCode template repository's own cleanliness rule (its ADR-004) and would fail on a real project's notes and changelogs. 4. Run the index generator: every book file must carry a `description` and every internal link must resolve; zero warnings is the only passing state. ## Step 5 — Install the skills diff --git a/AGENTS.md b/AGENTS.md index d296655..5ab1002 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,7 +47,7 @@ Git commits and branching strictly follow `book/guidelines/git-workflow.md`: eve ## code ↔ book interaction rules -1. **Before coding**: read `book/guidelines/` for the baseline; search `book/notes/learn/YYYY-MM/` for related experience. +1. **Before coding**: search `book/notes/learn/YYYY-MM/` for related experience, and consult only the guideline the task actually touches — the input pointers in `book/guidelines/README.md` route you. No blanket pre-reading. 2. **While coding**: new experience or pitfalls go straight into the current month's `book/notes/learn/YYYY-MM/`. 3. **After coding**: check the book — is the plan's status updated, is a summary needed, do new issues exist? 4. **Plans drive code**: `book/plans/` documents are the input to implementation. Read the plan, build in `code/`, write back to `book/`. @@ -55,15 +55,22 @@ Git commits and branching strictly follow `book/guidelines/git-workflow.md`: eve `changelogs/` and `notes/{summary,learn,issue}/` archive under `YYYY-MM/`; the month is a physical grouping, retrieval happens through `book/README.md`, frontmatter, and links. `book/` opens directly as an Obsidian vault. +This repository is the template itself, not an adopting project: knowledge work here lands in `book/docs/decisions/` ADRs — never in `notes/{learn,summary,issue,task}/`, `plans/`, or `changelogs/` entries. `cd code && npm run book:release-check` enforces the boundary (ADR-004). + +## Safe by default + +Local commands are disposable and have no production access — npm scripts, tests, builds, `git status/diff/log`, `npm run book:index`, `node scripts/check-commit-message.mjs`. Run them, fix failures, and rerun without asking. A human still owns anything touching production data or credentials, destructive operations, and every push to `main` (which never happens directly anyway). + ## Hard constraints - Step 0 (the structured requirements brief) is required before any code - No skipping between phases -- Phase 2 designs proceed only after user approval +- Phase 2 stops for the user only on real gaps — scope conflict, undetermined data shape, unclear external dependency — never just for confirmation - Problems found in Phase 5 / Phase 6 are **recorded, never fixed** - Feature work touches no code outside its scope: no opportunistic refactors, no new abstractions ## Tooling - `cd code && npm run book:index` — regenerate `book/README.md` after any book change (do not edit by hand; missing frontmatter `description` warns and exits 1) +- `cd code && npm run book:release-check` — verify the tree holds no instance working records; must be green before the `dev → main` release PR - `node scripts/check-commit-message.mjs ""` — validate a commit subject against Clean Commit diff --git a/book/README.md b/book/README.md index 9958955..34ba103 100644 --- a/book/README.md +++ b/book/README.md @@ -50,16 +50,18 @@ description: Master index of the book — the map of every document. Regenerate - [ADR-001-adopt-bocode.md](docs/decisions/ADR-001-adopt-bocode.md) — We run this repository on the BoCode workflow — book drives code, code writes back, six phases gate every feature - [ADR-002-adopt-bowrite.md](docs/decisions/ADR-002-adopt-bowrite.md) — We distill shuorenhua plus our own review patterns into bowrite (薄写), an in-repo writing skill — write thin, write well +- [ADR-003-intent-gates-vs-distrust-gates.md](docs/decisions/ADR-003-intent-gates-vs-distrust-gates.md) — We classify workflow gates by justification — intent gates stay hard, distrust gates soften as models improve; Phase 2 approval becomes gap-based stopping +- [ADR-004-template-free-of-instance-records.md](docs/decisions/ADR-004-template-free-of-instance-records.md) — This repository ships template content only — instance working records (notes entries, plans, changelog months) never enter it; a release check enforces the boundary - [README.md](docs/decisions/README.md) — How to write an ADR here — sections, naming, numbering, and when a decision needs a record ### guidelines/ -- [README.md](guidelines/README.md) — Index of the five guidelines — workflow, writing style, git, review checklist, plus the architecture and coding templates +- [README.md](guidelines/README.md) — Index of the five guidelines and the input pointer table — which guideline to read for which kind of task, with no blanket pre-reading - [architecture.md](guidelines/architecture.md) — Template for your project's long-term architecture rules — boundary invariants, module map, tech baseline, with a worked example of boundary-style rules - [coding-style.md](guidelines/coding-style.md) — Template for your project's coding baseline — the language-specific rules any contributor or agent must follow - [git-workflow.md](guidelines/git-workflow.md) — Clean Commit message format and Clean Flow branch, PR, and merge rules for solo and team development - [review-checklist.md](guidelines/review-checklist.md) — The eight code-review checks every change must pass — findings are recorded, never fixed in passing -- [workflow.md](guidelines/workflow.md) — Six-phase gate workflow with the seven code↔book interaction rules and the document routing table +- [workflow.md](guidelines/workflow.md) — Six-phase gate workflow with the eight code↔book interaction rules and the document routing table - [writing-style.md](guidelines/writing-style.md) — Plain-language writing standard for every book document — fidelity contract first, then minimal style rules, intensity levels, and a read-back check ### notes/ @@ -70,4 +72,4 @@ description: Master index of the book — the map of every document. Regenerate - [README.md](plans/README.md) — Plans directory usage — implementation plans land here after Phase 2 approval, with naming and the plan template - + diff --git a/book/docs/decisions/ADR-003-intent-gates-vs-distrust-gates.md b/book/docs/decisions/ADR-003-intent-gates-vs-distrust-gates.md new file mode 100644 index 0000000..6c17d0a --- /dev/null +++ b/book/docs/decisions/ADR-003-intent-gates-vs-distrust-gates.md @@ -0,0 +1,33 @@ +--- +description: We classify workflow gates by justification — intent gates stay hard, distrust gates soften as models improve; Phase 2 approval becomes gap-based stopping +--- + +# ADR-003: Separate intent gates from distrust gates + +## Status + +Accepted — applied 2026-09-14 in the capable-model workflow calibration. Amends the Phase 2 gate from ADR-001; the six-phase structure itself stands. + +## Context + +The workflow's gates were written when agent models needed firm rails: blanket pre-reading, prescribed step sequences, stops for confirmation. Capable models invert the economics — OpenAI's [Rethinking skills and prompts for GPT-6 Astra](https://developers.openai.com/blog/rethinking-skills-and-prompts-for-gpt-6-astra) documents the shift: scaffolding that helped weaker models now causes wrong routing, consumed context, premature stops, and halts on approvals the environment already allows. + +The gates had mixed justifications. Some exist because a human owns the decision (review integrity, scope discipline, production safety). Others exist only because weaker models couldn't be trusted to act (blanket design approval, prescribed coding loops, ask-before-running defaults). Only the second kind ages with model capability. + +## Decision + +Gates are classified by justification, and each class gets different maintenance: + +- **Intent gates — stay hard, model-independent**: Phase 5/6 record-never-fix (review must review what was built); Phase 3 scope discipline; production and credential safety; `main` merge-only. +- **Distrust-shaped rules — become defaults**: Phase 4's red-green-refactor loop is the default path; the mandatory part is the gate (all green, no weakened assertions, coverage matrix). Guideline reading is pointer-based (the input table in `guidelines/README.md`), never blanket. +- **Approval gates — become gap-based stops**: Phase 2 produces the full design and proceeds to Phase 3; it stops for the user only on real gaps — scope conflict, undetermined data shape, unclear external dependency — never just for confirmation. +- **Permissions flip to grant**: local commands are pre-approved (the safe-by-default block in AGENTS.md); agents run, fix, and rerun without asking. +- **Plans carry explicit done criteria** — the finish line that prevents premature stops. +- **Standing re-audit**: when the agent's model generation changes, re-audit AGENTS.md, `guidelines/`, and skills against this taxonomy. + +## Consequences + +- Capable agents move without halting on pre-approved actions or confirmations; tentative ones get an explicit finish line from the plan +- The human review point moves from "before any code exists" to "the delivered design plus the recorded review" — cheaper per feature, but a wrong design direction surfaces after implementation; Step 0 and the requirements brief carry more of the intent weight +- Weaker models lose some rails — projects pinned to a weak model may prefer stricter phrasing and should record that in their own ADR +- The re-audit rule is a recurring maintenance task; skipping it lets distrust gates quietly grow back diff --git a/book/docs/decisions/ADR-004-template-free-of-instance-records.md b/book/docs/decisions/ADR-004-template-free-of-instance-records.md new file mode 100644 index 0000000..1f60445 --- /dev/null +++ b/book/docs/decisions/ADR-004-template-free-of-instance-records.md @@ -0,0 +1,30 @@ +--- +description: This repository ships template content only — instance working records (notes entries, plans, changelog months) never enter it; a release check enforces the boundary +--- + +# ADR-004: Keep the template free of instance working records + +## Status + +Accepted — 2026-09-14. Enforced by `code/tools/check-template-clean.mjs` (`npm run book:release-check`), wired into `.github/workflows/git-policy.yml`. + +## Context + +BoCode is a template repository: adopters copy its skeleton into their projects and fill the book with their own records. The workflow this repo teaches treats `notes/{learn,summary,issue,task}/`, `plans/`, and `changelogs/YYYY-MM/` as the adopting project's knowledge base. This repository is not an adopting project — its product is the workflow itself. + +The first instance records appeared on 2026-09-14 (a learn entry and a changelog month from the capable-model calibration). Carried by the next `dev → main` merge — which by ADR-001 and the git rules only ever merges — they would ship to every adopter as leftovers. + +Alternative rejected: keep records on `dev`, strip them at merge time. Git merges carry the whole tree; main would receive them inside the merge commit and need a cleanup commit every release, and its history would still contain them. + +## Decision + +- This repository tracks **template content only**: guidelines, READMEs, `AGENTS.md`, ADRs, tooling, the generated index. ADRs double as this repo's own decision records and ship as worked examples. +- Instance working records — anything under `book/notes/{learn,summary,issue,task}/`, `book/plans/`, or `book/changelogs/` beyond the READMEs — are never committed here. This repo's experience distills into ADRs; raw process notes stay out of the tree (git history keeps anything already committed). +- `cd code && npm run book:release-check` fails when a guarded directory holds anything but its README; it runs in CI on every PR and push to `dev`/`main`, and manually before a release. +- Adopters are unaffected: `ADOPT.md` tells them not to copy the check — in a real project it would fail on the project's own notes. + +## Consequences + +- The released template stays clean; adopters see the conventions as instructions (READMEs), never as leftovers to delete +- This repository does not dogfood its own learn/plan/changelog conventions — accepted: its features are workflow changes, recorded as ADRs plus merge history +- The boundary needs naming when it stings: content that feels like both (a changelog of template changes, say) gets decided case by case and recorded here diff --git a/book/guidelines/README.md b/book/guidelines/README.md index e1dfb0e..671f00f 100644 --- a/book/guidelines/README.md +++ b/book/guidelines/README.md @@ -1,5 +1,5 @@ --- -description: Index of the five guidelines — workflow, writing style, git, review checklist, plus the architecture and coding templates +description: Index of the five guidelines and the input pointer table — which guideline to read for which kind of task, with no blanket pre-reading --- # Guidelines @@ -15,4 +15,18 @@ The project's development rules. Every contributor — including AI agents — f | `architecture.md` | Long-term architecture rules (template — replace per project) | | `coding-style.md` | Language-specific coding baseline (template — replace per project) | -Start with `workflow.md`; the others answer questions it raises. +## Input pointers — consult on demand, never blanket-read + +| When the task touches… | Read first | +|--------|-----------| +| Phases, gates, book sync | `workflow.md` | +| Module boundaries, data ownership, tech swaps | `architecture.md` | +| The current shape of modules and data flow | `../docs/architecture/` snapshots | +| Interface contracts | `../docs/api/` | +| Writing any book document | `writing-style.md` | +| Commits, branches, PRs, releases | `git-workflow.md` | +| Language-level code rules | `coding-style.md` | +| Reviewing a diff | `review-checklist.md` | +| Prior experience with this symptom or tech | search `../notes/learn/` by tag | + +First contact with the repo: read `workflow.md` once. After that, jump straight to the guideline the task touches — the table above routes you. diff --git a/book/guidelines/git-workflow.md b/book/guidelines/git-workflow.md index 2115250..714f9ad 100644 --- a/book/guidelines/git-workflow.md +++ b/book/guidelines/git-workflow.md @@ -114,7 +114,7 @@ git push origin dev When several people build the same feature, open the PR from `feature/user-profile` into `dev` and **Squash and merge** after checks; the squash subject uses Clean Commit too. Delete the work branch after merging. -When `dev` is stable, open the `dev → main` PR and choose **Create a merge commit** to preserve the integration boundary. The merge-commit subject is Clean Commit as well, e.g.: +When `dev` is stable, run `cd code && npm run book:release-check` first — the release ships template content only, and instance working records (note entries, plans, changelog months) fail the check (ADR-004). Then open the `dev → main` PR and choose **Create a merge commit** to preserve the integration boundary. The merge-commit subject is Clean Commit as well, e.g.: ```text 🚀 release: promote dev to main @@ -123,6 +123,7 @@ When `dev` is stable, open the `dev → main` PR and choose **Create a merge com ## Automation and platform settings - PRs into `dev`/`main` and pushes to them are checked by `.github/workflows/git-policy.yml` for branch direction and commit subjects; direct pushes to `dev` still pass Clean Commit validation. +- The same workflow runs `book:release-check` on every PR and push to `dev`/`main`; it fails the moment an instance working record enters the tree (ADR-004). - Run `git config core.hooksPath .githooks` once per clone to get the same `commit-msg` check locally. - Protect `main` on GitHub: require a PR from `dev`, status checks, and merge commits. Keep direct pushes to `dev` allowed for solo speed; team PRs still use squash merges. diff --git a/book/guidelines/workflow.md b/book/guidelines/workflow.md index 6f13cda..e093b9e 100644 --- a/book/guidelines/workflow.md +++ b/book/guidelines/workflow.md @@ -1,5 +1,5 @@ --- -description: Six-phase gate workflow with the seven code↔book interaction rules and the document routing table +description: Six-phase gate workflow with the eight code↔book interaction rules and the document routing table --- # Workflow @@ -12,7 +12,7 @@ Every feature moves through these phases in order. **No skipping.** |------|------|--------|------| | Step 0 | Structured requirements brief | Requirements brief | Every slot filled | | Phase 1 | Analysis | Impact map + risk list | No code changed | -| Phase 2 | Design | Data flow, file list, interfaces | **User approval required before Phase 3** | +| Phase 2 | Design | Data flow, file list, interfaces | Design complete; stop only on real gaps — scope conflict, undetermined data shape, unclear external dependency | | Phase 3 | Implementation | Code | Strictly per design; nothing outside scope | | Phase 4 | Testing | Test cases | All green; no weakened assertions | | Phase 5 | Code review | Review findings | Record only — no fixes | @@ -20,7 +20,9 @@ Every feature moves through these phases in order. **No skipping.** Step 0 comes before any code. Fill the brief: background, scope (what it affects, what it explicitly does **not** affect, and the boundaries), and the requirement itself. An empty "does not affect" list is the number-one cause of out-of-scope changes in Phase 3 — the exclusions slot is required. -Phase 4 runs test-first: write a failing test, write the minimum implementation that passes it, refactor with the test staying green. Coverage must include the normal path, boundary inputs (ranges, empty, extremes), error paths, and a regression check that existing behavior didn't break. +Phase 2 produces the full design — data flow, file list, interfaces — and proceeds; it stops for the user only when a real gap appears (scope conflict, undetermined data shape, unclear external dependency), never just for confirmation. + +Phase 4's hard part is the gate, not the sequence: all relevant tests green, no assertion weakened to get there, coverage of the normal path, boundary inputs (ranges, empty, extremes), error paths, and a regression check that existing behavior didn't break. Test-first (write a failing test → minimum implementation → refactor staying green) is the default loop — sequence the work however keeps the gate honest. Phases 5 and 6 share one discipline: **record, never fix.** A problem found during review or wrap-up goes into `notes/issue/` — fixing it is a separate, later task. Fixing in passing feels efficient and destroys the gate: the review no longer reviews what was built. @@ -51,13 +53,14 @@ Phases 5 and 6 share one discipline: **record, never fix.** A problem found duri ## Interaction rules -1. **Before coding** — read `guidelines/` for the baseline; search `notes/learn/` for related experience. +1. **Before coding** — search `notes/learn/` for related experience and consult only the guideline the task touches (the input pointers in `guidelines/README.md` route you); no blanket pre-reading. 2. **While coding** — something new learned or tripped over? Write it to `notes/learn/` immediately; future sessions (human or agent) benefit. 3. **After coding** — sync the book: plan status, summary, new issues, changelog, index. 4. **Plans drive code** — `book/plans/` is the input to implementation. The agent reads the plan, builds in `code/`, writes back to `book/`. 5. **Issues feed code** — `notes/issue/` records problems that become the direction of later iterations. 6. **The book compounds** — every feature should leave the book more complete than it found it. The book is both the agent's context and the human's reference manual. 7. **Refresh the index** — after any book change, run `cd code && npm run book:index` before wrapping up. New files must carry a frontmatter `description`, and internal links must resolve — either failing fails the build. +8. **Re-audit when the model changes** — scaffolding ages with model capability. When the agent's model generation changes, re-audit AGENTS.md, `guidelines/`, and skills against ADR-003's gate taxonomy: keep intent gates (record-never-fix, scope discipline), drop or soften gates that only exist from distrust of weaker models. ## Document routing diff --git a/book/plans/README.md b/book/plans/README.md index 00ecffe..2122092 100644 --- a/book/plans/README.md +++ b/book/plans/README.md @@ -4,7 +4,7 @@ description: Plans directory usage — implementation plans land here after Phas # Plans -Implementation plans live here. Each feature's detailed plan lands in this folder once its Phase 2 design is approved — the plan is the construction blueprint the agent builds from. +Implementation plans live here. Each feature's detailed plan lands in this folder once its Phase 2 design is settled — the plan is the construction blueprint the agent builds from. ## Naming @@ -35,6 +35,9 @@ status: draft | approved | in_progress | completed ## Test plan + +## Done criteria + ``` -A plan is executable as written: each step small enough to verify on its own. When the build finishes, flip `status` to `completed` — the plan then doubles as the record of what was intended, next to the summary of what happened. +A plan is executable as written: each step small enough to verify on its own. The done-criteria slot is the finish line — agents stop where the text stops, so an explicit finish line prevents premature stops. When it reads true, flip `status` to `completed`; the plan then doubles as the record of what was intended, next to the summary of what happened. diff --git a/code/package.json b/code/package.json index 5f8c191..922f68d 100644 --- a/code/package.json +++ b/code/package.json @@ -5,6 +5,7 @@ "type": "module", "description": "Project source tree. The only script here is the book index generator — this file has zero dependencies by design.", "scripts": { - "book:index": "node tools/gen-book-index.mjs" + "book:index": "node tools/gen-book-index.mjs", + "book:release-check": "node tools/check-template-clean.mjs" } } diff --git a/code/tools/check-template-clean.mjs b/code/tools/check-template-clean.mjs new file mode 100644 index 0000000..2157753 --- /dev/null +++ b/code/tools/check-template-clean.mjs @@ -0,0 +1,65 @@ +#!/usr/bin/env node +/** + * Guards the template boundary (ADR-004): this repository ships the BoCode + * template, not an adopting project's working records. The book's + * running-record directories must hold nothing but their READMEs. + * + * Usage: cd code && node tools/check-template-clean.mjs + * (or: npm run book:release-check) + * + * Guarded: book/changelogs, book/notes/{learn,summary,issue,task}, book/plans. + * This repo's own knowledge work lands in book/docs/decisions/ ADRs instead. + * Adopters do not copy this script — see ADOPT.md step 4. + * Zero dependencies; runs on plain Node (and bun). + */ +import { readdirSync } from "node:fs"; +import { join, dirname, relative } from "node:path"; +import { fileURLToPath } from "node:url"; + +const TOOLS_DIR = dirname(fileURLToPath(import.meta.url)); +const BOOK_ROOT = join(TOOLS_DIR, "..", "..", "book"); + +const GUARDED_DIRS = [ + "changelogs", + "notes/learn", + "notes/summary", + "notes/issue", + "notes/task", + "plans", +]; + +function walk(dir) { + const out = []; + for (const entry of readdirSync(dir, { withFileTypes: true })) { + if (entry.name.startsWith(".")) continue; + const full = join(dir, entry.name); + if (entry.isDirectory()) out.push(...walk(full)); + else out.push(full); + } + return out; +} + +const violations = []; + +for (const rel of GUARDED_DIRS) { + const base = join(BOOK_ROOT, rel); + let files; + try { + files = walk(base); + } catch { + continue; // directory absent — nothing to guard + } + for (const file of files) { + if (relative(base, file) === "README.md") continue; + violations.push(`book/${relative(BOOK_ROOT, file)}`); + } +} + +if (violations.length > 0) { + console.error(`Instance working records in the template tree (${violations.length}) — ADR-004 keeps this repository to template content:`); + for (const v of violations) console.error(` - ${v}`); + console.error("Distill the entry into an ADR (book/docs/decisions/) or move it out of the repository, then rerun. The dev→main release stays blocked until this check is green."); + process.exit(1); +} + +console.log("Template tree clean — guarded directories hold READMEs only (ADR-004).");