First implementation milestone of the agent-first coverage architecture
(ADR-020, PRD 2026-05-13). Lands the keystone — coverage bands as a
typed declaration in feature.manifest.ts plus a helper that derives
vitest threshold shapes from them.
New file packages/core-shared/src/conformance/coverage.ts (self-
contained, no relative imports — loadable at vitest config time):
- CoverageBand / CoverageBands / CoverageManifest / VitestThresholds
types
- DEFAULT_COVERAGE_BANDS (baseline 80/75/80/80; entities 100/100/100/
100; use-cases + controllers 100/95/100/100) — matches ADR-011
- DEFAULT_MUTATION_SCORE (80) + DEFAULT_MUTATION_TARGETS (entities +
use-cases)
- getCoverageBands / getMutationConfig — manifest -> resolved bands,
with default fallback for missing layers
- vitestThresholdsFromBands / vitestThresholdsFromManifest — convert
to vitest's coverage.thresholds shape with the layer-to-glob
mapping
define-feature.ts gains the optional coverage field on FeatureManifest
(imports its type from coverage.ts to avoid a relative-import cycle
at config-load time).
Exposed via two subpaths: @repo/core-shared/conformance (re-exports
for source/test code) and @repo/core-shared/conformance/coverage
(direct subpath safe to load from vitest configs, bypasses the index
re-export chain that Node ESM doesn't auto-extension-resolve).
Auth wired as proof-of-concept:
- packages/auth/src/feature.manifest.ts declares its coverage section
- packages/auth/vitest.config.ts imports the helper +
DEFAULT_COVERAGE_BANDS and emits thresholds via
vitestThresholdsFromBands(DEFAULT_COVERAGE_BANDS) — no more
hand-maintained per-glob thresholds block.
Verified: 175/175 tests pass; 14/14 typechecks clean; auth coverage
green (21 tests, 93.77% overall, all per-layer 100% bands hold).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Architecture record for the agent-first coverage initiative seeded by
the 2026-05-13 PRD. Captures the durable decisions:
- 4-layer architecture (L0 vitest, L1 diff, L2 aggregate, L3 mutation)
- Manifest-driven coverage band as single source of truth (vitest +
assertFeatureConformance + pnpm coverage:diff all read from it)
- Cover-the-diff (changed lines), not cover-the-new-code
- Committed coverage/summary.json (no SaaS), trend via git log
- Mutation testing scoped to entities + use-cases, on-demand only
- Machine-first output format (JSON stdout, human stderr)
Glossary gets a new "Coverage" section with 7 entries (coverage band,
L0-L3 layers, diff coverage, mutation testing, mutation score,
coverage/summary.json), plus two relationship rows and a flagged
ambiguity for "coverage" qualifiers.
prompt-context.sh hook gets a 9th keyword group — when a prompt
mentions coverage / uncovered / lcov / mutation / stryker, the
relevant ADR + guide path are injected as additional context for
the turn.
This is the documentation layer of the coverage epic. Implementation
(manifest schema, vitest auto-derive, scripts, boot assertion,
mutation tooling) lands in subsequent stories.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the brainstorm convergence (2026-05-13) into a draft PRD that
seeds the implementation epic. Decisions captured:
- 4-layer coverage architecture (L0 vitest thresholds, L1 diff coverage,
L2 aggregate summary.json, L3 mutation testing on entities + use-cases)
- Manifest-driven coverage band as the single source of truth — vitest
config, assertFeatureConformance boot check, and pnpm coverage:diff
all derive expectations from feature.manifest.ts
- Cover-the-diff (every changed line exercised) not cover-the-new-code
- Aggregate trend committed as coverage/summary.json; no SaaS dep
- Stryker for mutation, on-demand only, NOT in default pnpm test
L0 verification findings (also captured in the PRD):
- auth / blog / marketing-pages: green (100% layer bands hold)
- navigation: real test gaps in entities + controllers (~86%)
- media: missing @vitest/coverage-v8 dep + vitest.config has no
coverage block at all (entirely absent — the most extreme case of
the duplication problem the manifest-driven keystone eliminates)
Status remains draft until the human review pass. Decomposer will
refuse to run on draft.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Project-level Claude Code hooks committed to .claude/settings.json with
scripts under .claude/hooks/. Three tiers:
Tier 1 — hard guards (exit 2 to block the tool call):
- bash-guard.sh: blocks bypass flags (verify-skip, sign-skip), forceful
push variants, destructive resets, force clean, working-tree-wipe
checkouts/restores, force branch delete, amend, and rm -rf against
root or home. Reinforces CLAUDE.md Git Safety Protocol.
- generator-first-nudge.sh: blocks creating a new top-level
packages/<name> or apps/<name> directory by hand. Allows working
inside an existing package. Reinforces the non-negotiable
generator-first rule.
Tier 2 — context injection (stdout becomes additional context):
- session-start.sh: prints glossary, AGENTS.md, workflow CLI, and
conformance pointers on session boot.
- prompt-context.sh: keyword-matches the user prompt against eight
concept groups (events, realtime, audit, instrumentation, manifest,
workflow, DI, boundaries) and injects the relevant ADR + rule
pointers for the turn.
Tier 3 — side-effect automation:
- post-manifest-edit.sh: when Edit/Write touches feature.manifest.ts,
prints the manifest-first ordering reminder plus the per-feature
verify commands.
- stop-check-manifest-tests.sh: at agent Stop time, if the working
tree has manifest changes but no sibling test changes, exits 2 to
force continuation. Loop-guarded via stop_hook_active.
All hooks are bash + jq, use CLAUDE_PROJECT_DIR for safety, and were
smoke-tested end-to-end (block + allow paths both verified).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously .claude/settings.local.json was only excluded by the user's
global ~/.config/git/ignore — fresh clones of this template would have
accidentally committed per-user Claude Code settings. Add an explicit
project-level rule (*.local, *.local.*, **/settings.local.json) so the
template ships with the protection baked in.
Also strips two missed "phase" residuals from
core-shared/instrumentation/otel/init-server-node.ts (the word leaked
through the earlier sweep — generic future-work qualifier, not a
setup-history reference, but cleaner without it).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs/glossary.md is the shared vocabulary source for humans and agents.
Resolves every cross-cutting term used in this repo (feature, use case,
manifest, slice, conformance, dispatch, ...) with one-sentence definitions,
relationships, and flagged ambiguities. Linked from CLAUDE.md "Read First"
and AGENTS.md preamble so every session loads it early.
.claude/skills/ installs four mattpocock skills adapted to this monorepo:
- to-prd: writes to docs/work/prds/ with the repo's PRD frontmatter +
merged user-stories/implementation/testing sections
- grill-with-docs: points at docs/decisions/ + docs/glossary.md; adds
feature.manifest.ts + conformance-rule cross-checks
- grill-me: minor — adds pnpm work / fallow / manifest shortcuts
- handoff: adds the repo's specific don't-duplicate artifacts list
Also fixes a missed "Phase-1" residual in CLAUDE.md's Read First section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Final sweep for setup-process bookkeeping not caught by template-reset-v1.
ADRs drop Plan-N qualifiers; spec collapses the historical 11-phase
migration table; scaffolding guide drops "Phase added" column; comment
prefixes referencing R-numbers in test describes / eslint inline comments
are normalized. Architecture-level rule IDs (R40, R52, E0, J0, etc.) are
preserved where they serve as stable cross-references in ADRs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mark epic + story status done, check all task boxes, rebuild _state.json.
All checks green: typecheck, tests (360 passing), lint, turbo boundaries.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Regenerate audit + realtime core-package e2e snapshots (template
Phase-label changes altered file hashes)
- Fix pre-existing lint error in auth authentication.service.ts:
rename unused params to _user / _sessionId, drop stale eslint-disable
comments that were on wrong lines
- Mark story tasks 1-9 done; rebuild _state.json
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename docs/decisions/adr-012-lazar-conformance.md → adr-012-feature-conventions.md
- Strip "Lazar", "Plan 8/9/10/11", "refactor-logs" refs from all ADRs,
architecture docs, HTML explainers, and feature/core AGENTS.md files
- Update all incoming links in docs/, packages/*/AGENTS.md, HTML explainers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the decision to adopt @ai-hero/sandcastle as the orchestration
substrate for agent-driven development in this template. Records the
8-point decision (workspace dep, .sandcastle/ prompts, Dockerfile,
dispatch.mjs orchestrator, planning vs execute modes, generator-first
reviewer check, bring-your-own-key, per-task max-attempts), the four
alternatives considered (bare CLI / Copilot Workspace / custom-from-
scratch / no orchestrator), and four trade-offs (external dep, token
cost, Docker dependency, manual state mutation in v1).
Surfaces the decision at the top of README.md and AGENTS.md so new
contributors see the agent-driven framing before they hit the package
map or daily commands.
Adds a "Using Sandcastle for agent dispatch" section between the gate
table and Troubleshooting. Covers when to use / not use sandcastle,
prerequisites (Docker + agent API key + .sandcastle/ config), the
dispatch flow, a worked end-to-end example (plan → execute → review →
manual state mutation), troubleshooting (env vars, Docker, timeouts,
rejection modes), and a cost-aware planning-only variant.