feat: archive setup-history epics + plans + refactor-logs to .archive/

This commit is contained in:
2026-05-13 09:43:49 +02:00
parent dca69afe97
commit 075b729266
86 changed files with 1 additions and 49643 deletions

View File

@@ -1,401 +1,6 @@
{
"updated_at": "2026-05-13T07:43:11.219Z",
"updated_at": "2026-05-13T07:43:50.648Z",
"epics": {
"agent-workflow-docs-v1": {
"status": "done",
"title": "Agent-workflow docs rollout",
"stories": {
"01-docs-rewrite": {
"status": "done",
"title": "Surface conformance system across top-level docs",
"ac_total": 8,
"ac_completed": 8,
"depends_on": [],
"blocks": []
}
}
},
"conformance-hardening-v1": {
"status": "done",
"title": "Conformance hardening v1 — AST manifest parsing + dev-seed boot assertion",
"stories": {
"01-ast-manifest-source": {
"status": "done",
"title": "Replace regex manifest source parser with AST",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [],
"blocks": [
"02-dev-seed-assertion"
]
},
"02-dev-seed-assertion": {
"status": "done",
"title": "Extend assertFeatureConformance to all bind-dev-seed paths",
"ac_total": 6,
"ac_completed": 6,
"depends_on": [
"01-ast-manifest-source"
],
"blocks": []
}
}
},
"conformance-system-v1": {
"status": "done",
"title": "Conformance system v1",
"stories": {
"01-define-feature-helper": {
"status": "done",
"title": "defineFeature helper + Instrumented/Captured/Audited brands",
"ac_total": 9,
"ac_completed": 9,
"depends_on": [],
"blocks": [
"02-boot-assertions"
]
},
"02-boot-assertions": {
"status": "done",
"title": "assertFeatureConformance + boot wiring",
"ac_total": 11,
"ac_completed": 11,
"depends_on": [
"01-define-feature-helper"
],
"blocks": [
"03-eslint-rules"
]
},
"03-a-structural-eslint-rules": {
"status": "done",
"title": "Structural ESLint rules (feature-must-have-manifest, usecase-must-have-test-file, required-cores-installed)",
"ac_total": 10,
"ac_completed": 10,
"depends_on": [
"02-boot-assertions"
],
"blocks": [
"03-b-ast-aware-eslint-rules"
]
},
"03-b-ast-eslint-rules": {
"status": "done",
"title": "AST-aware ESLint rules (no-undeclared-event-publish, no-undeclared-audit)",
"ac_total": 8,
"ac_completed": 8,
"depends_on": [
"03-a-structural-eslint-rules"
],
"blocks": [
"04-ci-drift-gate"
]
},
"04-ci-drift-gate": {
"status": "done",
"title": "CI drift gate — pnpm conformance with cross-feature event closure",
"ac_total": 6,
"ac_completed": 6,
"depends_on": [
"03-b-ast-eslint-rules"
],
"blocks": [
"05-generator-updates"
]
},
"05-generator-updates": {
"status": "done",
"title": "Generator updates — emit feature.manifest.ts + self-asserting bind-production",
"ac_total": 7,
"ac_completed": 7,
"depends_on": [
"04-ci-drift-gate"
],
"blocks": [
"06-feature-migrations"
]
},
"06-feature-migrations": {
"status": "done",
"title": "Migrate blog/media/navigation/marketing-pages to conformance pattern",
"ac_total": 7,
"ac_completed": 7,
"depends_on": [
"05-generator-updates"
],
"blocks": []
}
}
},
"dag-and-readiness-v1": {
"status": "done",
"title": "DAG + readiness — depends-on / blocks parsing",
"stories": {
"01-extended-state": {
"status": "done",
"title": "Frontmatter array parsing + extended state shape",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [],
"blocks": [
"02-dag-computation"
]
},
"02-dag-computation": {
"status": "done",
"title": "DAG computation — ready + blocked story sets",
"ac_total": 3,
"ac_completed": 3,
"depends_on": [
"01-extended-state"
],
"blocks": [
"03-cli-subcommands"
]
},
"03-cli-subcommands": {
"status": "done",
"title": "CLI ready / blocked subcommands",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [
"02-dag-computation"
],
"blocks": []
}
}
},
"docs-and-runbook-v1": {
"status": "done",
"title": "Developer runbook + post-Fallow doc sweep",
"stories": {
"01-runbook": {
"status": "done",
"title": "docs/guides/runbook.md — day-1 onboarding",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [],
"blocks": [
"02-doc-sweep"
]
},
"02-doc-sweep": {
"status": "done",
"title": "README + CLAUDE.md + .env.example sweep",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [
"01-runbook"
],
"blocks": []
}
}
},
"elicitation-prompts-v1": {
"status": "done",
"title": "Elicitation + dispatch prompt templates",
"stories": {
"01-sandcastle-scaffold": {
"status": "done",
"title": ".sandcastle/ directory + README + .env.example + .gitignore",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [],
"blocks": [
"02-elicitation-prompts",
"03-dispatch-prompts"
]
},
"02-elicitation-prompts": {
"status": "done",
"title": "PRD + ADR elicitation prompt templates",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"01-sandcastle-scaffold"
],
"blocks": []
},
"03-dispatch-prompts": {
"status": "done",
"title": "Decomposer + implementer + reviewer prompt templates",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"01-sandcastle-scaffold"
],
"blocks": []
}
}
},
"fallow-integration-v1": {
"status": "done",
"title": "Fallow integration v1 — whole-codebase static analysis as 5th gate",
"stories": {
"01-fallow-install": {
"status": "done",
"title": "Install fallow + create .fallowrc.json",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [],
"blocks": [
"02-pnpm-turbo-wiring"
]
},
"02-pnpm-turbo-wiring": {
"status": "done",
"title": "pnpm script + turbo task wiring",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"01-fallow-install"
],
"blocks": [
"03-ci-integration"
]
},
"03-ci-integration": {
"status": "done",
"title": "CI workflow runs pnpm fallow",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"02-pnpm-turbo-wiring"
],
"blocks": [
"04-docs-and-prompts"
]
},
"04-docs-and-prompts": {
"status": "done",
"title": "Docs + agent prompt updates",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [
"03-ci-integration"
],
"blocks": []
}
}
},
"frontend-conformance-v1": {
"status": "done",
"title": "Frontend conformance rules v1",
"stories": {
"01-frontend-rules": {
"status": "done",
"title": "Three structural frontend conformance ESLint rules",
"ac_total": 6,
"ac_completed": 6,
"depends_on": [],
"blocks": []
}
}
},
"pre-commit-hooks-v1": {
"status": "done",
"title": "Pre-commit hooks v1 — husky + fast conformance gates on commit",
"stories": {
"01-husky-install": {
"status": "done",
"title": "Install husky + lint-staged",
"ac_total": 3,
"ac_completed": 3,
"depends_on": [],
"blocks": [
"02-pre-commit-hook"
]
},
"02-pre-commit-hook": {
"status": "done",
"title": "Pre-commit hook script",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"01-husky-install"
],
"blocks": [
"03-state-sync-guard"
]
},
"03-state-sync-guard": {
"status": "done",
"title": "State-sync guard + tests",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"02-pre-commit-hook"
],
"blocks": []
}
}
},
"sandcastle-dispatch-v1": {
"status": "done",
"title": "Sandcastle dispatch v1 — pnpm work dispatch with planning + execute modes",
"stories": {
"01-sandcastle-install": {
"status": "done",
"title": "Install @ai-hero/sandcastle + Dockerfile",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [],
"blocks": [
"02-dispatch-planner"
]
},
"02-dispatch-planner": {
"status": "done",
"title": "Dispatch planner — finds next ready bullet, prints plan",
"ac_total": 3,
"ac_completed": 3,
"depends_on": [
"01-sandcastle-install"
],
"blocks": [
"03-dispatch-execute",
"04-dispatch-cli-wiring"
]
},
"03-dispatch-execute": {
"status": "done",
"title": "Dispatch execute mode — invoke sandcastle.run for impl + review",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"02-dispatch-planner"
],
"blocks": [
"04-dispatch-cli-wiring"
]
},
"04-dispatch-cli-wiring": {
"status": "done",
"title": "pnpm work dispatch CLI wiring + smoke tests",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"02-dispatch-planner",
"03-dispatch-execute"
],
"blocks": []
}
}
},
"sandcastle-subscription-auth-v1": {
"status": "done",
"title": "Sandcastle subscription auth as primary flow",
"stories": {
"01-subscription-first": {
"status": "done",
"title": "Subscription-first dispatch — mount ~/.claude, install claude CLI, docs",
"ac_total": 8,
"ac_completed": 8,
"depends_on": [],
"blocks": []
}
}
},
"template-reset-v1": {
"status": "in-progress",
"title": "Template reset — strip setup-process noise + archive history",
@@ -409,58 +14,6 @@
"blocks": []
}
}
},
"visual-regression-v1": {
"status": "done",
"title": "Visual regression v1 — Playwright screenshot infrastructure",
"stories": {
"01-playwright-install": {
"status": "done",
"title": "Install @playwright/test + playwright.config.ts",
"ac_total": 3,
"ac_completed": 3,
"depends_on": [],
"blocks": [
"02-storybook-visual-tests"
]
},
"02-storybook-visual-tests": {
"status": "done",
"title": "Visual test harness in apps/storybook",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"01-playwright-install"
],
"blocks": [
"03-ci-integration"
]
},
"03-ci-integration": {
"status": "done",
"title": "CI workflow runs pnpm test:visual",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"02-storybook-visual-tests"
],
"blocks": []
}
}
},
"work-system-v1": {
"status": "done",
"title": "Work system v1 (MVP) — state tracking + pnpm work CLI",
"stories": {
"01-state-builder-and-cli": {
"status": "done",
"title": "State builder + pnpm work CLI",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [],
"blocks": []
}
}
}
},
"ready": [

View File

@@ -1,42 +0,0 @@
---
id: 01-docs-rewrite
epic: agent-workflow-docs-v1
title: Surface conformance system across top-level docs
type: technical-story
status: done
feature: docs
depends-on: []
blocks: []
---
## Goal
Update CLAUDE.md, AGENTS.md, and four guides so agents picking up this
repo discover and follow the manifest-first workflow by default.
## Done when
- CLAUDE.md has a "Conformance system" section + manifest-first ordering
added to Key Conventions
- AGENTS.md's per-feature conventions mention the manifest contract
- adding-a-feature.md updated to the 4-step ordering
- scaffolding-a-feature.md notes the manifest emission + boot assertion
- tdd-workflow.md links to the conformance enforcement
- New conformance-quickref.md exists as a single-page agent reference
## In scope
Mechanical doc updates pointing at existing artifacts (the design doc, the
feature-conformance-explainer.html, the actual rules / wrappers / script
already merged).
## Out of scope
- Rewriting the existing architecture docs (already in place)
- Updating per-package AGENTS.md inside packages/*
## Tasks
- [x] Epic + story scaffold
- [x] CLAUDE.md update
- [x] AGENTS.md update
- [x] adding-a-feature.md update
- [x] scaffolding-a-feature.md update
- [x] tdd-workflow.md update
- [x] conformance-quickref.md (new)
- [x] Final verification + closeout

View File

@@ -1,36 +0,0 @@
---
id: agent-workflow-docs-v1
prd: null
title: Agent-workflow docs rollout
type: epic
status: done
features: [docs]
created: 2026-05-13
---
## Goal
Surface the conformance-system-v1 mechanics across CLAUDE.md, AGENTS.md,
and the feature-development guides so agents picking up this codebase
follow the manifest-first workflow by default.
## Why
The conformance system is the substrate, but agents read the top-level
docs first. Until the docs say "feature.manifest.ts exists, here's what
it does, here's how the gates fire," the system stays invisible to
agents iterating on this repo for the first time.
## In scope
- CLAUDE.md: add conformance system section + manifest-first ordering
- AGENTS.md: add manifest convention to per-package conventions
- docs/guides/adding-a-feature.md: update workflow to manifest → contracts → tests → code
- docs/guides/scaffolding-a-feature.md: note that generator now emits manifest + boot assertion
- docs/guides/tdd-workflow.md: link conformance system as the enforcement layer
- New docs/guides/conformance-quickref.md: ~80-line agent-facing reference
## Out of scope
- Frontend-conformance docs (next epic)
- Work-system-v1 docs (those land with the work-system epic)
- Editing the original conformance design docs (already in place)
## Stories
- [x] [01 — Surface conformance system across CLAUDE.md / AGENTS.md / guides](01-docs-rewrite/_story.md)

View File

@@ -1,33 +0,0 @@
---
id: 01-ast-manifest-source
epic: conformance-hardening-v1
title: Replace regex manifest source parser with AST
type: technical-story
status: done
feature: core-eslint
depends-on: []
blocks: [02-dev-seed-assertion]
---
## Goal
`readManifestSource` in `_manifest-source.js` returns the same shape but
uses `@typescript-eslint/parser` AST traversal instead of regex.
## In scope
- Rewrite `readManifestSource` to delegate to a new `parseManifestFully`
in `_manifest-ast.js` that returns `{ name, requiredCores, useCases }`
- Existing 4 tests for `readManifestSource` must still pass
- Add tests covering the previously-fragile cases: `name:` in JSDoc,
single-quoted strings, manifest declared with `let` instead of `const`
## Out of scope
- Changing the `_manifest-source.js` exports surface (filesystem helpers
`manifestPathForFeature` and `featureRootForFile` stay untouched)
- Changing any rule's behaviour beyond the parsing path
## Tasks
- [x] Epic + story scaffold
- [x] Extend `_manifest-ast.js` with `parseManifestFully`
- [x] Switch `readManifestSource` to delegate to `parseManifestFully`
- [x] Add edge-case tests
- [x] Verify all rules still pass; commit

View File

@@ -1,29 +0,0 @@
---
id: 02-dev-seed-assertion
epic: conformance-hardening-v1
title: Extend assertFeatureConformance to all bind-dev-seed paths
type: technical-story
status: done
feature: <cross-feature>
depends-on: [01-ast-manifest-source]
blocks: []
---
## Goal
Each feature's `bind-dev-seed.ts` calls `assertFeatureConformance(...)`
at its tail, matching the bind-production pattern.
## In scope
- Update bind-dev-seed.ts in auth, blog, media, navigation, marketing-pages
- Each gets the same import + tail call as its bind-production sibling
## Out of scope
- Behavioural changes to dev-seed binders
## Tasks
- [x] Update auth bind-dev-seed
- [x] Update blog bind-dev-seed
- [x] Update media bind-dev-seed
- [x] Update navigation bind-dev-seed
- [x] Update marketing-pages bind-dev-seed
- [x] Verify pnpm test passes

View File

@@ -1,27 +0,0 @@
---
id: conformance-hardening-v1
prd: null
title: Conformance hardening v1 — AST manifest parsing + dev-seed boot assertion
type: epic
status: done
features: [core-eslint, auth, blog, media, navigation, marketing-pages]
created: 2026-05-13
---
## Goal
Tighten two known fragilities in conformance-system-v1:
1. `_manifest-source.js` uses regex for `name` + `requiredCores` extraction —
replace with AST parsing for correctness (comments, quote styles, edge cases)
2. Boot assertion only runs at the production binder's tail. Dev mode
(`USE_DEV_SEED=true`) skips it. Extend to dev-seed paths.
## Why
- The regex false-match concern was flagged by the milestone iii.a final
reviewer and held only by today's convention; a future manifest with
a `// name: "x"` comment would break `required-cores-installed`.
- `pnpm dev` is the inner loop. Drift in dev-seed binders is currently
invisible until production boot — too late.
## Stories
- [x] [01 — AST-based manifest source parser](01-ast-manifest-source/_story.md)
- [x] [02 — Dev-seed boot assertion across all 5 features](02-dev-seed-assertion/_story.md)

View File

@@ -1,49 +0,0 @@
---
id: 01-define-feature-helper
epic: conformance-system-v1
title: defineFeature helper + Instrumented/Captured/Audited brands
type: technical-story
status: done
feature: core-shared
depends-on: []
blocks: [02-boot-assertions]
---
## Goal
Manifest helper + brand types enable type-level enforcement that every
use-case binding is wrapped with `withSpan` + `withCapture`
(and `withAudit` when mutating with audits declared).
## Why
Compile-time feedback is the cheapest layer and the foundation every other
milestone reads.
## Done when
Compile-time TS2322 fires when an unwrapped factory is bound through
`ProductionUseCase<...>`, and `auth.signIn` is rebound through the new slot.
## In scope
- `Instrumented<F>` and `Captured<F>` brand types in `@repo/core-shared/conformance`
- Brand attachment in `withSpan` and `withCapture`
- `Audited<F>` brand and `withAudit` wrapper in `@repo/core-audit`
- `defineFeature` helper + `FeatureManifest` / `UseCaseManifest` types
- `ProductionUseCase<I, O, M>` branded slot type
- `authManifest` declaring `signIn`, `signUp`, `signOut`
- `auth.signIn` rebound through the branded slot
## Out of scope
- `auth.signUp` / `auth.signOut` rebinding through branded slots (separate tasks within this story or a follow-up story; signUp requires `Audited<F>` once we declare its `audits`)
- Boot-time `assertConformance` (story 02)
- ESLint rules reading the manifest (story 03)
- Generator emitting manifest stubs (story 05)
## Tasks
- [x] Brand types: `Instrumented<F>` and `Captured<F>`
- [x] `withSpan` attaches `Instrumented`
- [x] `withCapture` attaches `Captured`
- [x] `defineFeature` helper + manifest types
- [x] `ProductionUseCase<I, O, M>` slot type
- [x] `withAudit` wrapper + `Audited` brand
- [x] `authManifest` declaration
- [x] `auth.signIn` rebound through branded slot
- [x] Negative test: unwrapped factory rejected at type level

View File

@@ -1,65 +0,0 @@
---
id: 02-boot-assertions
epic: conformance-system-v1
title: assertFeatureConformance + boot wiring
type: technical-story
status: done
feature: core-shared
depends-on: [01-define-feature-helper]
blocks: [03-eslint-rules]
---
## Goal
Runtime boot-time verification that every manifest-declared use case is bound
through the brand-attaching wrappers. Each feature's `bindProductionX(ctx)`
self-asserts at the tail; `pnpm dev` refuses to boot on drift.
## Why
Type casts can mask unwrapped factories; manifest edits can drift from
binders without TypeScript noticing. Boot assertions catch what the type
system can't see — at zero cost during the inner agent feedback loop, and
synchronously at startup so failures fire loudly.
## Done when
- `withSpan`, `withCapture`, `withAudit` attach non-enumerable runtime markers
matching the type-level brand names
- `assertFeatureConformance(container, manifest, symbols, ctx)` resolves each
manifest use case and throws `ConformanceError` on a missing brand
- `auth.bindProductionAuth(ctx)` self-asserts at the tail
- `pnpm dev` boots cleanly for the existing `auth` wiring; rebinding `signIn`
with an unwrapped factory causes `pnpm dev` to throw at startup
## In scope
- Runtime marker attachment via `Object.defineProperty(fn, "__brand", { … })`
(non-enumerable, non-writable, non-configurable)
- `isInstrumented` / `isCaptured` / `isAudited` predicates
- `ConformanceError` class (extends `Error`)
- `assertFeatureConformance(container, manifest, symbols, ctx)` helper
- Wiring into `packages/auth/src/di/bind-production.ts` (tail-of-binder
self-assertion)
- `withAudit` upgraded from passthrough to a thin wrapper that attaches its
runtime brand without changing observable behaviour
## Out of scope
- `assertConformance` over a multi-feature container collection at the app's
`bindAll()` (current per-feature self-assertion is sufficient and
forward-compatible)
- Wiring boot assertions into `cms` and `web-tanstack` — neither has a
`bind-production.ts` yet; they'll inherit the check whenever they grow one
- Manifests for `blog`, `media`, `navigation`, `marketing-pages` (their
`bindProductionX` stays unchanged in this story)
- Automated audit recording driven by manifest `audits[]` declarations
(deferred to a later story)
## Tasks
- [x] Re-export `authManifest` from auth root barrel
- [x] TODO breadcrumb in `withAudit` pointing at future automation
- [x] Runtime marker helpers (`attachBrand`, `isInstrumented`, `isCaptured`, `isAudited`)
- [x] `withSpan` attaches runtime `__instrumented` marker
- [x] `withCapture` attaches runtime `__captured` marker
- [x] `withAudit` wraps + attaches runtime `__audited` marker
- [x] `ConformanceError` class
- [x] `assertFeatureConformance` helper + tests
- [x] Conformance barrel + subpath exports updated
- [x] `bindProductionAuth` self-asserts at the tail
- [x] Final verification + story closeout

View File

@@ -1,64 +0,0 @@
---
id: 03-a-structural-eslint-rules
epic: conformance-system-v1
title: Structural ESLint rules (feature-must-have-manifest, usecase-must-have-test-file, required-cores-installed)
type: technical-story
status: done
feature: core-eslint
depends-on: [02-boot-assertions]
blocks: [03-b-ast-aware-eslint-rules]
---
## Goal
Stand up the custom ESLint rule plugin in `@repo/core-eslint` and ship three
structural conformance rules that don't require cross-file AST analysis.
Editor + CLI feedback fires in <1s.
## Why
Boot-time assertion catches drift in bound use cases, but cannot catch:
- Features that exist on disk but have no manifest at all
- Use-case files lacking a sibling test file
- Manifest declaring required cores that aren't in `pnpm-workspace.yaml`
Structural ESLint rules surface these in the editor, before code is even
saved past lint-on-save.
## Done when
- Custom rule plugin exists at `packages/core-eslint/plugin.js`
- Three rules registered: `conformance/feature-must-have-manifest`,
`conformance/usecase-must-have-test-file`,
`conformance/required-cores-installed`
- Each rule has RuleTester tests with positive + negative cases
- `base.js` registers the plugin and enables the rules
- `pnpm lint` passes for the current monorepo state (rules tuned to today's
reality see Out of scope)
## In scope
- Custom rule plugin module at `packages/core-eslint/plugin.js`
- Rule modules in `packages/core-eslint/rules/*.js`
- Manifest text parser (`_manifest-source.js`) regex-based, sufficient for
literal `as const` manifests
- Workspace.yaml reader (`_workspace.js`)
- Rule integration into `base.js`
- Tests for each rule using ESLint's RuleTester
## Out of scope
- Cross-file AST analysis rules (`no-undeclared-event-publish`,
`no-undeclared-audit`) milestone iii.b
- Enforcement on features that don't yet have a manifest `feature-must-have-manifest`
ships as a WARNING today (only auth has a manifest); flips to ERROR after
blog/media/navigation/marketing-pages get manifests
- Manifest parser based on TypeScript compiler API regex is sufficient for
literal manifests; the AST path comes in iii.b
## Tasks
- [x] Story 03.a scaffold
- [x] Manifest source helper (`_manifest-source.js`)
- [x] Workspace helper (`_workspace.js`)
- [x] `feature-must-have-manifest` rule + tests
- [x] `usecase-must-have-test-file` rule + tests
- [x] `required-cores-installed` rule + tests
- [x] Plugin module + `exports` entry in `package.json`
- [x] Wire plugin into `base.js`
- [x] Verify `pnpm lint` passes against the monorepo
- [x] Final verification + story closeout

View File

@@ -1,45 +0,0 @@
---
id: 03-b-ast-eslint-rules
epic: conformance-system-v1
title: AST-aware ESLint rules (no-undeclared-event-publish, no-undeclared-audit)
type: technical-story
status: done
feature: core-eslint
depends-on: [03-a-structural-eslint-rules]
blocks: [04-ci-drift-gate]
---
## Goal
Ship two AST-aware rules that catch manifest ↔ use-case drift inside factory bodies:
- `no-undeclared-event-publish`: `bus.publish("X")` in a factory must match `manifest.useCases[name].publishes`
- `no-undeclared-audit`: `auditLog.record({ type: "X" })` must match `manifest.useCases[name].audits`
## Why
Boot assertion + structural rules can't see what happens inside a factory body. AST-aware rules catch publish/audit drift the moment a developer (or agent) saves the file.
## Done when
- Manifest AST parser extracts per-use-case publishes/audits arrays
- Two rules registered in the conformance plugin
- Tests cover positive (declared event) and negative (undeclared event) cases for each rule
- `pnpm lint` passes (auth's signUp has empty publishes/audits today → no false positives)
## In scope
- `_manifest-ast.js` helper using `@typescript-eslint/parser` to extract per-use-case arrays
- `_usecase-name.js` helper (file slug → camelCase use-case key)
- The two rules + RuleTester tests
- Plugin + base.js wiring
## Out of scope
- Bus / auditLog parameter detection beyond the conventional names `bus` and `auditLog`
- Detection of dynamic event names (`bus.publish(eventVar, payload)` is allowed without warning)
- Conditional / nested calls — rules only check top-level CallExpressions in factory bodies
## Tasks
- [x] Story 03.b scaffold
- [x] Manifest AST parser + tests
- [x] Use-case name helper + tests
- [x] `no-undeclared-event-publish` rule + tests
- [x] `no-undeclared-audit` rule + tests
- [x] Plugin update + base.js wiring
- [x] Verify `pnpm lint` passes
- [x] Final verification + story closeout (tick 03 + 03.b in epic)

View File

@@ -1,47 +0,0 @@
---
id: 04-ci-drift-gate
epic: conformance-system-v1
title: CI drift gate — pnpm conformance with cross-feature event closure
type: technical-story
status: done
feature: scripts
depends-on: [03-b-ast-eslint-rules]
blocks: [05-generator-updates]
---
## Goal
`pnpm conformance` aggregates cross-feature checks that no single-file
ESLint rule can perform — most importantly, event closure: every event
declared in any manifest's `consumes` must have at least one matching
`publishes` somewhere in the repo.
## Why
Per-file lint can't see cross-feature contracts. Without this gate, a
feature can declare it consumes `X` while no feature publishes `X`
silent until the broken handler is exercised in prod.
## Done when
- `pnpm conformance` exits 0 when manifests are consistent; non-zero
with a clear error message on orphan consumers
- Wired into `turbo.json` as the `conformance` task
- Wired into `.github/workflows/ci.yml` after `pnpm lint`
## In scope
- `scripts/conformance.mjs` — orphan-consumer check
- Tests via vitest
- turbo.json + CI wiring
## Out of scope
- Scaffold drift check (regenerate via `turbo gen feature`, diff against
on-disk state) — depends on generator updates landing
- Repository write outside use-cases check — separate concern
- Reverse check (orphan publishers — events nothing consumes) — many
events are intentionally "fire and forget"; not a closure violation
## Tasks
- [x] Story scaffold
- [x] `scripts/conformance.mjs` implementation
- [x] Tests for the script
- [x] Wire into root package.json + turbo.json
- [x] Wire into ci.yml
- [x] Final verification + closeout

View File

@@ -1,52 +0,0 @@
---
id: 05-generator-updates
epic: conformance-system-v1
title: Generator updates — emit feature.manifest.ts + self-asserting bind-production
type: technical-story
status: done
feature: turbo-generators
depends-on: [04-ci-drift-gate]
blocks: [06-feature-migrations]
---
## Goal
`pnpm turbo gen feature <name>` produces a feature that's conformance-
compliant out of the box: ships a `feature.manifest.ts` declaring the
scaffolded use case, and the scaffolded `bind-production.ts` calls
`assertFeatureConformance` at its tail.
## Why
Today, generating a new feature does NOT emit a manifest, so
`feature-must-have-manifest` would warn the moment the developer saves.
And `bindProductionX` doesn't self-assert. New features should be
conformance-ready by default.
## Done when
- `feature.manifest.ts.hbs` template exists, declaring the scaffolded
`getX` use case with mutates: false / empty arrays
- `bind-production.ts.hbs` imports `assertFeatureConformance` +
`<name>Manifest` and calls the assertion at the tail
- `config.ts` action emits the manifest file
- Running `pnpm turbo gen feature demo` into a tmp dir produces a
feature directory containing a valid `feature.manifest.ts`
- Existing snapshot tests pass (regenerate snapshots if needed)
## In scope
- Manifest template
- bind-production template update
- config.ts action wiring
- Snapshot regen
## Out of scope
- Multi-use-case feature scaffolding
- Generator changes to other generators (event/job/realtime)
- Backfilling manifests for existing features (milestone vi)
## Tasks
- [x] Story scaffold
- [x] feature.manifest.ts.hbs template
- [x] bind-production.ts.hbs update
- [x] config.ts action wiring
- [x] Run generator into tmp; verify shape
- [x] Snapshot regen (if needed) + verify tests pass
- [x] Final verification + closeout

View File

@@ -1,39 +0,0 @@
---
id: 06-feature-migrations
epic: conformance-system-v1
title: Migrate blog/media/navigation/marketing-pages to conformance pattern
type: technical-story
status: done
feature: <cross-feature>
depends-on: [05-generator-updates]
blocks: []
---
## Goal
Every feature in the repo has a manifest + a self-asserting bindProduction.
After this milestone, `feature-must-have-manifest` flips from WARN to ERROR.
## Why
Three of the four enforcement layers already exist; the only thing keeping
them from being fully effective is that 4 of 5 features still don't have
manifests. This story closes that gap.
## In scope
- `feature.manifest.ts` for blog / media / navigation / marketing-pages
- Manifest re-export from each feature's `src/index.ts`
- `bind-production.ts` update for each: imports + tail `assertFeatureConformance` call
- Flip `feature-must-have-manifest` from `warn` to `error` in base.js
## Out of scope
- Adding publishes/audits to existing use cases (declared empty for now)
- Cross-feature event wiring (blog→marketing welcome flows, etc.)
- Migrating realtime channels or jobs into manifests
## Tasks
- [x] Story scaffold
- [x] blog manifest + binding + re-export
- [x] media manifest + binding + re-export
- [x] navigation manifest + binding + re-export
- [x] marketing-pages manifest + binding + re-export
- [x] Flip feature-must-have-manifest to error
- [x] Final verification + closeout

View File

@@ -1,41 +0,0 @@
---
id: conformance-system-v1
prd: null
title: Conformance system v1
type: epic
status: done
features: [cross-cutting]
created: 2026-05-12
---
## Goal
Build the feature-conformance enforcement system so AI agents get layered,
sub-second feedback on drift between manifest and code.
## Why
See `docs/architecture/feature-conformance-explainer.html` and
`docs/architecture/agent-first-workflow-and-conformance.md`.
## In scope
- defineFeature helper + brand types
- assertConformance + boot wiring
- AST-aware ESLint rules
- CI drift gate
- Generator updates for manifest + contracts + test stubs
- Documentation rewrite (manifest-first workflow)
- Migration of auth feature as the reference
## Out of scope
- Migration of blog, media, navigation, marketing-pages (Phase 3)
- Sandcastle orchestration (Phase 2: work-system-v1 epic)
## Stories
- [x] [01 — defineFeature helper + Instrumented/Captured/Audited brands](01-define-feature-helper/_story.md)
- [x] [02 — `assertFeatureConformance` + boot wiring](02-boot-assertions/_story.md)
- [x] 03 — AST-aware ESLint rules (both halves shipped)
- [x] [03.a — Structural rules](03-a-structural-eslint-rules/_story.md)
- [x] [03.b — Manifest-aware AST rules](03-b-ast-eslint-rules/_story.md)
- [x] [04 — CI drift gate](04-ci-drift-gate/_story.md)
- [x] [05 — Generator updates](05-generator-updates/_story.md)
- [x] [06 — Migrate blog / media / navigation / marketing-pages](06-feature-migrations/_story.md)
- [x] 07 — Migrate auth feature reference (completed inline in milestone i; signIn through ProductionUseCase slot)

View File

@@ -1,17 +0,0 @@
---
id: 01-extended-state
epic: dag-and-readiness-v1
title: Frontmatter array parsing + extended state shape
type: technical-story
status: done
feature: scripts
depends-on: []
blocks: [02-dag-computation]
---
## Tasks
- [x] Story scaffold
- [x] Extend parseFrontmatter to parse array values like `depends-on: [a, b]`
- [x] Extend buildState to include depends_on + blocks per story entry
- [x] Update existing tests; add new array-parsing tests

View File

@@ -1,16 +0,0 @@
---
id: 02-dag-computation
epic: dag-and-readiness-v1
title: DAG computation — ready + blocked story sets
type: technical-story
status: done
feature: scripts
depends-on: [01-extended-state]
blocks: [03-cli-subcommands]
---
## Tasks
- [x] computeReadyBlocked(state) — pure function
- [x] Tests
- [x] Wire into buildState output

View File

@@ -1,18 +0,0 @@
---
id: 03-cli-subcommands
epic: dag-and-readiness-v1
title: CLI ready / blocked subcommands
type: technical-story
status: done
feature: scripts
depends-on: [02-dag-computation]
blocks: []
---
## Tasks
- [x] `pnpm work ready` — prints ready stories
- [x] `pnpm work blocked` — prints blocked stories with waiting_on
- [x] Update `pnpm work next` to use the ready set
- [x] CLI smoke tests
- [x] Final verification + closeout

View File

@@ -1,21 +0,0 @@
---
id: dag-and-readiness-v1
prd: null
title: DAG + readiness — depends-on / blocks parsing
type: epic
status: done
features: [scripts]
created: 2026-05-13
---
## Goal
Extend the state builder + CLI so `pnpm work next` / `pnpm work ready` /
`pnpm work blocked` answer "what's actually unblocked right now?"
from the depends-on graph instead of just the first non-done story.
## Stories
- [x] [01 — Frontmatter array parsing + extended state shape](01-extended-state/_story.md)
- [x] [02 — DAG computation: ready + blocked](02-dag-computation/_story.md)
- [x] [03 — CLI ready / blocked subcommands](03-cli-subcommands/_story.md)

View File

@@ -1,15 +0,0 @@
---
id: 01-runbook
epic: docs-and-runbook-v1
title: docs/guides/runbook.md — day-1 onboarding
type: technical-story
status: done
feature: docs
depends-on: []
blocks: [02-doc-sweep]
---
## Tasks
- [x] Story scaffold
- [x] Write docs/guides/runbook.md (sections: Prerequisites, First-time setup, Daily commands, Env vars, Agent-first workflow, Conformance gates reference, Troubleshooting, Where to read next)

View File

@@ -1,18 +0,0 @@
---
id: 02-doc-sweep
epic: docs-and-runbook-v1
title: README + CLAUDE.md + .env.example sweep
type: technical-story
status: done
feature: docs
depends-on: [01-runbook]
blocks: []
---
## Tasks
- [x] Update README.md to point at runbook + reflect 5 gates
- [x] Expand .env.example to cover all relevant env vars with comments
- [x] Sweep CLAUDE.md "Quick Start" for new commands (pnpm work, pnpm fallow, pnpm fallow:audit)
- [x] Add a "Conformance gates" reference line to docs/guides/conformance-quickref.md noting Fallow is the 5th
- [x] Final verification + closeout

View File

@@ -1,20 +0,0 @@
---
id: docs-and-runbook-v1
prd: null
title: Developer runbook + post-Fallow doc sweep
type: epic
status: done
features: [docs]
created: 2026-05-13
---
## Goal
Write the day-1 developer runbook + sweep top-level docs for staleness
against the now-shipped conformance-system, work-system, sandcastle,
and Fallow integration.
## Stories
- [x] [01 — Developer runbook](01-runbook/_story.md)
- [x] [02 — Doc sweep + .env.example expansion](02-doc-sweep/_story.md)

View File

@@ -1,17 +0,0 @@
---
id: 01-sandcastle-scaffold
epic: elicitation-prompts-v1
title: .sandcastle/ directory + README + .env.example + .gitignore
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-elicitation-prompts, 03-dispatch-prompts]
---
## Tasks
- [x] Story scaffold
- [x] Create .sandcastle/README.md
- [x] Create .sandcastle/.env.example
- [x] Create .sandcastle/.gitignore

View File

@@ -1,15 +0,0 @@
---
id: 02-elicitation-prompts
epic: elicitation-prompts-v1
title: PRD + ADR elicitation prompt templates
type: technical-story
status: done
feature: agent-prompts
depends-on: [01-sandcastle-scaffold]
blocks: []
---
## Tasks
- [x] prd-eliciter.prompt.md
- [x] adr-eliciter.prompt.md

View File

@@ -1,17 +0,0 @@
---
id: 03-dispatch-prompts
epic: elicitation-prompts-v1
title: Decomposer + implementer + reviewer prompt templates
type: technical-story
status: done
feature: agent-prompts
depends-on: [01-sandcastle-scaffold]
blocks: []
---
## Tasks
- [x] decomposer.prompt.md
- [x] implementer.prompt.md
- [x] reviewer.prompt.md
- [x] Final verification + closeout

View File

@@ -1,22 +0,0 @@
---
id: elicitation-prompts-v1
prd: null
title: Elicitation + dispatch prompt templates
type: epic
status: done
features: [tooling, agent-prompts]
created: 2026-05-13
---
## Goal
Ship five prompt templates under `.sandcastle/` so the future orchestrator
(and humans manually copy-pasting) can dispatch PRD elicitation, ADR
elicitation, decomposition, implementation, and review with a consistent
shape. Every template enforces the generator-first rule.
## Stories
- [x] [01 — .sandcastle/ scaffold + README](01-sandcastle-scaffold/_story.md)
- [x] [02 — PRD + ADR elicitation prompts](02-elicitation-prompts/_story.md)
- [x] [03 — Decomposer + implementer + reviewer prompts](03-dispatch-prompts/_story.md)

View File

@@ -1,17 +0,0 @@
---
id: 01-fallow-install
epic: fallow-integration-v1
title: Install fallow + create .fallowrc.json
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-pnpm-turbo-wiring]
---
## Tasks
- [x] Story scaffold
- [x] Add fallow to root devDependencies
- [x] Create .fallowrc.json with monorepo-aware config
- [x] Verify `pnpm exec fallow --version` works

View File

@@ -1,17 +0,0 @@
---
id: 02-pnpm-turbo-wiring
epic: fallow-integration-v1
title: pnpm script + turbo task wiring
type: technical-story
status: done
feature: tooling
depends-on: [01-fallow-install]
blocks: [03-ci-integration]
---
## Tasks
- [x] pnpm fallow script (runs all)
- [x] pnpm fallow:audit script (runs `fallow audit --base main`)
- [x] turbo.json task entry for fallow
- [x] Run `pnpm fallow` against current repo, capture findings, tune config

View File

@@ -1,15 +0,0 @@
---
id: 03-ci-integration
epic: fallow-integration-v1
title: CI workflow runs pnpm fallow
type: technical-story
status: done
feature: ci
depends-on: [02-pnpm-turbo-wiring]
blocks: [04-docs-and-prompts]
---
## Tasks
- [x] Add `pnpm fallow` step after `pnpm conformance` in ci.yml
- [x] Use --format annotations for inline GH PR comments

View File

@@ -1,18 +0,0 @@
---
id: 04-docs-and-prompts
epic: fallow-integration-v1
title: Docs + agent prompt updates
type: technical-story
status: done
feature: agent-prompts
depends-on: [03-ci-integration]
blocks: []
---
## Tasks
- [x] Update CLAUDE.md conformance-system section to list Fallow as 5th gate
- [x] Update docs/guides/conformance-quickref.md with Fallow row
- [x] Update .sandcastle/implementer.prompt.md: run `fallow audit` before commit
- [x] Update .sandcastle/reviewer.prompt.md: verify implementer ran fallow audit
- [x] Final verification + closeout

View File

@@ -1,28 +0,0 @@
---
id: fallow-integration-v1
prd: null
title: Fallow integration v1 — whole-codebase static analysis as 5th gate
type: epic
status: done
features: [tooling, ci, agent-prompts]
created: 2026-05-13
---
## Goal
Wire Fallow as the 5th conformance gate: install, configure, pnpm script,
turbo task, CI step, docs update, agent prompt update.
## Why
Fallow catches what file-local lint, type-check, manifest assertions, and
conformance event closure cannot — dead code, dupes, circular deps,
complexity hotspots, and AI-change drift. `fallow audit --base main` is
purpose-built for AI agents to self-validate before submission.
## Stories
- [x] [01 — Install fallow + .fallowrc.json](01-fallow-install/_story.md)
- [x] [02 — pnpm + turbo wiring](02-pnpm-turbo-wiring/_story.md)
- [x] [03 — CI workflow integration](03-ci-integration/_story.md)
- [x] [04 — Docs + agent prompt updates](04-docs-and-prompts/_story.md)

View File

@@ -1,42 +0,0 @@
---
id: 01-frontend-rules
epic: frontend-conformance-v1
title: Three structural frontend conformance ESLint rules
type: technical-story
status: done
feature: core-eslint
depends-on: []
blocks: []
---
## Goal
Three new rules under the `conformance/` plugin namespace:
`component-must-have-story`, `component-must-have-test`,
`atomic-tier-import-direction`. All ship as WARN initially because
no components exist in the repo today.
## Done when
- Three rules registered in `@repo/core-eslint/plugin`
- Each has RuleTester tests
- `base.js` registers them at WARN severity
- `pnpm lint` passes (zero firings expected today; rules activate when
first component lands)
## In scope
- Three new rule files in `packages/core-eslint/rules/`
- Plugin + base.js wiring
- Tests via RuleTester
## Out of scope
- Visual regression infrastructure (Playwright screenshots — separate plan)
- `story-must-cover-all-prop-variants` advisory rule
- Detection beyond filesystem siblings (no AST-level component-detection
heuristics)
## Tasks
- [x] Epic + story scaffold
- [x] `component-must-have-story` rule + tests
- [x] `component-must-have-test` rule + tests
- [x] `atomic-tier-import-direction` rule + tests
- [x] Plugin update + base.js wiring
- [x] Final verification + closeout

View File

@@ -1,22 +0,0 @@
---
id: frontend-conformance-v1
prd: null
title: Frontend conformance rules v1
type: epic
status: done
features: [core-eslint]
created: 2026-05-13
---
## Goal
Three structural ESLint rules for frontend component files: every
component has a sibling Storybook story, a sibling test, and respects
atomic-design tier direction (atoms can't import from organisms, etc.).
## Why
The frontend-work-shape guide describes these conventions; without
rules, they're advisory only. Ship them now so they activate the moment
core-ui or feature UI components land — preventing drift from day one.
## Stories
- [x] [01 — Frontend ESLint rules](01-frontend-rules/_story.md)

View File

@@ -1,28 +0,0 @@
---
id: 01-husky-install
epic: pre-commit-hooks-v1
title: Install husky + lint-staged
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-pre-commit-hook]
---
## Goal
husky + lint-staged are dependencies of the root workspace and the
`prepare` script wires the hooks on `pnpm install`.
## In scope
- Add husky + lint-staged to root devDependencies
- Add `prepare` script that runs `husky` (initialises `.husky/`)
- Create `.husky/` directory + the husky shim
- Add `lint-staged` config to root package.json
## Tasks
- [x] Story scaffold
- [x] Install husky + lint-staged + add scripts/config
- [x] Verify `pnpm install` initialises `.husky/`

View File

@@ -1,15 +0,0 @@
---
id: 02-pre-commit-hook
epic: pre-commit-hooks-v1
title: Pre-commit hook script
type: technical-story
status: done
feature: tooling
depends-on: [01-husky-install]
blocks: [03-state-sync-guard]
---
## Tasks
- [x] `.husky/pre-commit` runs lint-staged
- [x] Pre-commit also regenerates \_state.json when docs/work/ changes and re-stages it

View File

@@ -1,17 +0,0 @@
---
id: 03-state-sync-guard
epic: pre-commit-hooks-v1
title: State-sync guard + tests
type: technical-story
status: done
feature: tooling
depends-on: [02-pre-commit-hook]
blocks: []
---
## Tasks
- [x] `scripts/work/state-sync-guard.mjs` fails when \_state.json differs from rebuild output
- [x] Tests
- [x] Wire into pre-commit
- [x] Final verification + closeout

View File

@@ -1,27 +0,0 @@
---
id: pre-commit-hooks-v1
prd: null
title: Pre-commit hooks v1 — husky + fast conformance gates on commit
type: epic
status: done
features: [tooling]
created: 2026-05-13
---
## Goal
Install husky and wire pre-commit hooks that catch the cheap drift classes
before code leaves the developer's machine. Slow checks stay in CI.
## Why
Slip a manifest update without re-running `pnpm work rebuild-state` and
the committed \_state.json drifts from markdown reality. Forget to lint
and a broken commit lands. Pre-commit hooks shrink the cycle from "wait
for CI" to "wait one second".
## Stories
- [x] [01 — Install husky + lint-staged](01-husky-install/_story.md)
- [x] [02 — Pre-commit hook: lint-staged + state-sync](02-pre-commit-hook/_story.md)
- [x] [03 — State-sync guard script + tests](03-state-sync-guard/_story.md)

View File

@@ -1,17 +0,0 @@
---
id: 01-sandcastle-install
epic: sandcastle-dispatch-v1
title: Install @ai-hero/sandcastle + Dockerfile
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-dispatch-planner]
---
## Tasks
- [x] Story scaffold
- [x] Add @ai-hero/sandcastle to devDependencies
- [x] Create .sandcastle/Dockerfile (minimal node + pnpm)
- [x] Verify install + import resolves

View File

@@ -1,16 +0,0 @@
---
id: 02-dispatch-planner
epic: sandcastle-dispatch-v1
title: Dispatch planner — finds next ready bullet, prints plan
type: technical-story
status: done
feature: scripts
depends-on: [01-sandcastle-install]
blocks: [03-dispatch-execute, 04-dispatch-cli-wiring]
---
## Tasks
- [x] findNextTask() — returns { epic, story, bullet, storyContent } or null
- [x] Tests
- [x] CLI: printPlan() — prints the dispatch plan

View File

@@ -1,17 +0,0 @@
---
id: 03-dispatch-execute
epic: sandcastle-dispatch-v1
title: Dispatch execute mode — invoke sandcastle.run for impl + review
type: technical-story
status: done
feature: scripts
depends-on: [02-dispatch-planner]
blocks: [04-dispatch-cli-wiring]
---
## Tasks
- [x] dispatchImplementer() — calls sandcastle.run with implementer prompt
- [x] dispatchReviewer() — calls sandcastle.run with reviewer prompt + diff
- [x] applyReviewerDecision() — prints what state mutation WOULD happen
- [x] Tests with mocked sandcastle.run

View File

@@ -1,17 +0,0 @@
---
id: 04-dispatch-cli-wiring
epic: sandcastle-dispatch-v1
title: pnpm work dispatch CLI wiring + smoke tests
type: technical-story
status: done
feature: scripts
depends-on: [02-dispatch-planner, 03-dispatch-execute]
blocks: []
---
## Tasks
- [x] cli.mjs: add `dispatch` subcommand with `--execute` flag
- [x] CLI smoke tests
- [x] README / docs update
- [x] Final verification + closeout

View File

@@ -1,27 +0,0 @@
---
id: sandcastle-dispatch-v1
prd: null
title: Sandcastle dispatch v1 — pnpm work dispatch with planning + execute modes
type: epic
status: done
features: [tooling, scripts]
created: 2026-05-13
---
## Goal
Install `@ai-hero/sandcastle` + ship `pnpm work dispatch` that picks the
next ready AC bullet, prints the dispatch plan, and (with `--execute`)
invokes sandcastle to run the implementer then reviewer.
## Why
The orchestrator closes the loop: docs/work/ tracks state, `.sandcastle/`
holds the prompts, and dispatch.mjs connects them to sandcastle.
## Stories
- [x] [01 — Install @ai-hero/sandcastle + Dockerfile](01-sandcastle-install/_story.md)
- [x] [02 — Dispatch planner (default mode)](02-dispatch-planner/_story.md)
- [x] [03 — Dispatch execute mode (sandcastle.run integration)](03-dispatch-execute/_story.md)
- [x] [04 — pnpm work dispatch wiring + tests](04-dispatch-cli-wiring/_story.md)

View File

@@ -1,21 +0,0 @@
---
id: 01-subscription-first
epic: sandcastle-subscription-auth-v1
title: Subscription-first dispatch — mount ~/.claude, install claude CLI, docs
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: []
---
## Tasks
- [x] Story scaffold
- [x] Update .sandcastle/Dockerfile to install @anthropic-ai/claude-code CLI
- [x] Update scripts/work/dispatch.mjs: resolveClaudeAuth helper + sandbox mount + fallback to API key
- [x] Tests for resolveClaudeAuth
- [x] Update runbook "Using Sandcastle" section: subscription is primary flow
- [x] Update ADR-019: subscription auth as primary, API key as fallback
- [x] Update .env.example + .sandcastle/.env.example: reframe ANTHROPIC_API_KEY as fallback
- [x] Final verification + closeout

View File

@@ -1,29 +0,0 @@
---
id: sandcastle-subscription-auth-v1
prd: null
title: Sandcastle subscription auth as primary flow
type: epic
status: done
features: [tooling, ci]
created: 2026-05-13
---
## Goal
Subscription-based Claude Code auth (via host `~/.claude` mount) becomes
the default for `pnpm work dispatch --execute`. API-key auth remains as a
fallback. Works for any developer who has run `claude login` on their
host — zero per-user configuration in the repo.
## Why
The sandcastle community has explicitly rejected native subscription
support (issue #191, wontfix). But the host's `~/.claude/` directory
contains the logged-in session; mounting it into the sandbox lets the
container's Claude Code CLI use that session. This pattern is
environment-agnostic (each developer has their own `~/.claude`) and
spends zero per-task agent tokens for Pro/Max subscribers.
## Stories
- [x] [01 — Subscription-first dispatch + Dockerfile + docs](01-subscription-first/_story.md)

View File

@@ -1,16 +0,0 @@
---
id: 01-playwright-install
epic: visual-regression-v1
title: Install @playwright/test + playwright.config.ts
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-storybook-visual-tests]
---
## Tasks
- [x] Story scaffold
- [x] Add @playwright/test to root devDependencies
- [x] Create playwright.config.ts (single browser, fixed viewport, screenshot diff threshold)

View File

@@ -1,15 +0,0 @@
---
id: 02-storybook-visual-tests
epic: visual-regression-v1
title: Visual test harness in apps/storybook
type: technical-story
status: done
feature: tooling
depends-on: [01-playwright-install]
blocks: [03-ci-integration]
---
## Tasks
- [x] apps/storybook/tests/visual.spec.ts — iterates Storybook's stories.json
- [x] pnpm test:visual script at root

View File

@@ -1,15 +0,0 @@
---
id: 03-ci-integration
epic: visual-regression-v1
title: CI workflow runs pnpm test:visual
type: technical-story
status: done
feature: ci
depends-on: [02-storybook-visual-tests]
blocks: []
---
## Tasks
- [x] Add visual regression step to .github/workflows/ci.yml
- [x] Final verification + closeout

View File

@@ -1,27 +0,0 @@
---
id: visual-regression-v1
prd: null
title: Visual regression v1 — Playwright screenshot infrastructure
type: epic
status: done
features: [tooling, ci]
created: 2026-05-13
---
## Goal
Install Playwright and wire a screenshot test harness against Storybook so
the moment the first component+story lands, the visual regression gate
is already active.
## Why
Per the frontend-work-shape guide, visual regression is the CI gate that
locks in component appearance. Setting up the infrastructure now means
zero ramp-up when components arrive.
## Stories
- [x] [01 — Install Playwright + config](01-playwright-install/_story.md)
- [x] [02 — Storybook visual test harness](02-storybook-visual-tests/_story.md)
- [x] [03 — CI integration](03-ci-integration/_story.md)

View File

@@ -1,33 +0,0 @@
---
id: 01-state-builder-and-cli
epic: work-system-v1
title: State builder + pnpm work CLI
type: technical-story
status: done
feature: scripts
depends-on: []
blocks: []
---
## Goal
`pnpm work status` shows the current epic/story state across `docs/work/`.
`pnpm work next` prints the next unblocked story. `pnpm work rebuild-state`
regenerates `_state.json` from markdown.
## In scope
- `scripts/work/state-builder.mjs` — pure function, fully tested
- `scripts/work/cli.mjs` — argument dispatch + I/O wrapping the builder
- `docs/work/_state.json` — initial committed snapshot
- pnpm work script entry
## Out of scope
- Per-task state (tasks are markdown checkboxes, not separate entries)
- Orchestrator dispatch logic
- Dependency-graph analysis
## Tasks
- [x] Epic + story scaffold
- [x] state-builder.mjs + tests
- [x] cli.mjs + tests
- [x] _state.json initial commit + pnpm work script entry
- [x] Final verification + closeout

View File

@@ -1,28 +0,0 @@
---
id: work-system-v1
prd: null
title: Work system v1 (MVP) — state tracking + pnpm work CLI
type: epic
status: done
features: [scripts]
created: 2026-05-13
---
## Goal
Filesystem-only state tracking for `docs/work/` + a `pnpm work` CLI with
status / next / rebuild-state subcommands. Foundation for future
orchestration; no agent dispatch in v1.
## Why
Agents and humans both need a fast way to see "what's the next unblocked
work?" and "where are we?" — without scanning every story file by hand.
## Out of scope (v2+)
- Sandcastle / agent dispatch
- PRD and ADR elicitation skills
- Decomposer / implementer / reviewer prompts
- DAG analysis (depends-on / blocks)
- Pre-commit hooks (the state file is rebuilt manually for now)
## Stories
- [x] [01 — State builder + CLI](01-state-builder-and-cli/_story.md)