- New scripts/work/bump-updated-timestamps.mjs stamps the `updated:`
frontmatter field to the current ISO 8601 UTC timestamp on every
staged docs/work/**/*.md file. Idempotent; adds the field after
`created:` if missing.
- .husky/pre-commit invokes the bump script as step 2 (before
rebuild-state) so _state.json sees the fresh timestamp.
- Backfill all existing work docs (4 PRDs + 3 epics + 21 stories):
* created: promoted from \`YYYY-MM-DD\` -> ISO timestamp using
git log --diff-filter=A on each file (first-commit date for
stories that had no \`created:\` line, midnight UTC for PRDs
and epics that had date-only created).
* updated: added from \`git log -1 --format=%aI\` on each file
(last-commit timestamp); will be re-stamped to "now" by the
pre-commit hook on this commit.
Stories that had no \`created:\` line now get one.
3.3 KiB
3.3 KiB
id, epic, title, type, status, feature, depends-on, blocks, created, updated
| id | epic | title | type | status | feature | depends-on | blocks | created | updated | |
|---|---|---|---|---|---|---|---|---|---|---|
| 02-migrate-feature-binders | 2026-05-13-binder-wrap-helper | Migrate all five feature binders to wireUseCase | technical-story | done | auth, blog, media, marketing-pages, navigation |
|
2026-05-13T19:17:10+02:00 | 2026-05-14T19:10:35.370Z |
Goal
Replace every inline withSpan + withCapture (+ withAudit) block in each feature's bind-production.ts and bind-dev-seed.ts with a call to wireUseCase. Existing binder-level and integration tests must continue to pass unchanged. Each feature migrates in its own commit.
Why
The five inline wrapping clone groups are the top source of duplication reported by pnpm fallow. Moving to wireUseCase eliminates all five clone groups and leaves each binder as decision content only (which adapter, which mode, which symbol).
Done when
- All 10 binder files (
auth ×2,blog ×2,media ×2,marketing-pages ×2,navigation ×2) callwireUseCasefor every use case binding; no inlinewithSpan + withCaptureblocks remain for use cases. assertFeatureConformanceat the tail of eachbind-production.tscontinues to accept all wired use cases (brands present, manifest entries match).pnpm typecheck && pnpm test && pnpm lint && pnpm conformance && pnpm fallow:audit && pnpm coverage:diffpass after each per-feature commit.pnpm fallow dupesno longer shows the five binder-pair clone groups in its output.
In scope
packages/auth/src/di/bind-production.ts+bind-dev-seed.ts— 3 use cases (signIn, signUp, signOut).packages/blog/src/di/bind-production.ts+bind-dev-seed.ts— 3 use cases (getArticles, getArticleBySlug, createArticle).packages/media/src/di/bind-production.ts+bind-dev-seed.ts— 3 use cases (getMedia, listMedia, deleteMedia).packages/marketing-pages/src/di/bind-production.ts+bind-dev-seed.ts— 2 use cases (getPageBySlug, getSiteSettings).packages/navigation/src/di/bind-production.ts+bind-dev-seed.ts— 1 use case (getHeader).- If any binder's existing tests assert on internal wrapping shape rather than observable behaviour, refactor those assertions to test through the helper's contract (same commit as the binder change).
Out of scope
- Controller bindings — covered by the helper per the PRD but deferred to a follow-up if scope is a concern.
- Repository and service bindings — stay as direct
.toConstantValue()calls. - Apps'
bindAll()dispatcher — untouched.
Tasks
- Migrate
authbinders (bind-production.ts+bind-dev-seed.ts) towireUseCasefor all 3 use cases (signIn, signUp, signOut); all gates pass on this commit. - Migrate
blogbinders towireUseCasefor all 3 use cases (getArticles, getArticleBySlug, createArticle); all gates pass on this commit. - Migrate
mediabinders towireUseCasefor all 3 use cases (getMedia, listMedia, deleteMedia); all gates pass on this commit. - Migrate
marketing-pagesbinders towireUseCasefor both use cases (getPageBySlug, getSiteSettings); all gates pass on this commit. - Migrate
navigationbinders towireUseCasefor the single use case (getHeader); all gates pass on this commit; verifypnpm fallow dupesno longer surfaces the five binder-pair clone groups.