Tasks 002 — Monorepo wiring
Execution skill: superpowers:subagent-driven-development — one implementer per task, then a two-stage review (spec compliance, then code quality). superpowers:test-driven-development applies inside every task: no production code before a failing test that demands it. Reach for superpowers:systematic-debugging on any surprise rather than guessing.
Derived from plan.md (approved). Each task is small, independently verifiable, and reviewed as its own diff. Split where a reviewer could reject one task while approving its neighbour — not where the work merely changes subject. A task is done only when it satisfies the definition of done in CLAUDE.md.
Global Constraints in plan.md apply to every task and are not repeated per task.
T1 — Adopt Biome as the sole linter and formatter
Satisfies: R5, R6 (lint half), P2 #3, SC4.
- [ ] RED: create
tests/monorepo/wiring.test.tswith a caseSC4/R5: Biome is the only linter and formatterasserting:biome.jsonexists; rootpackage.jsonhas scriptslint=biome check .andformat=biome check --write .;@biomejs/biomeis indevDependencies; and neithereslintnorprettierappears anywhere inpackage.jsonorpnpm-lock.yaml. Runpnpm exec vitest run tests/monorepo/wiring.test.ts— watch it FAIL becausebiome.jsonand the scripts do not exist yet. - [ ] GREEN: add
@biomejs/biome@2.5.5todevDependenciesandpnpm install; createbiome.json(formatter: 2-space indent, single quotes, semicolons always;assist.source.organizeImportson;vcs: { enabled: true, clientKind: "git", useIgnoreFile: true }so it honours.gitignoreand skipsnode_modules/dist/.vitepress/cache); add thelintandformatscripts. Rerun — PASS. - [ ] REFACTOR: none expected.
- [ ] Confirm the test has teeth — remove
@biomejs/biomefromdevDependencies(or rename thelintscript), watch the case fail, restore. - [ ] Commit (
chore: adopt Biome as sole linter and formatter). - [ ] Formatting pass, as its own commit: run
pnpm format, review the diff (existing files gain semicolons / sorted imports — expected on.vitepress/config.mts,scripts/new-spec.ts,tests/workflow/*), confirmpnpm lintexits 0, then commit (style: format repository with Biome).
Verified by: tests/monorepo/wiring.test.ts › SC4/R5: Biome is the only linter and formatter; pnpm lint exits 0.
T2 — Split tsconfig.base.json out of tsconfig.json
Satisfies: R2, R3.
- [ ] RED: add to
tests/monorepo/wiring.test.tsa caseR2/R3: tsconfig base split, root extends and stays noEmit with packages includedasserting:tsconfig.base.jsonexists and holds exactly the strictness keys (strict,noUncheckedIndexedAccess,noImplicitOverride,noFallthroughCasesInSwitch,exactOptionalPropertyTypes,verbatimModuleSyntax,skipLibCheck) and none oflib/module/types; roottsconfig.jsonhasextends: "./tsconfig.base.json",noEmit: true, and anincludecontainingpackages/**/*.ts. Run the file — watch it FAIL. - [ ] GREEN: create
tsconfig.base.jsonwith the strictness keys only; edittsconfig.jsontoextendsit, keep the Node profile (target: ES2023,lib: ["ES2023"],module/moduleResolution: nodenext,types: ["node"]), keepallowImportingTsExtensionsandnoEmit, and widenincludeto addpackages/**/*.ts. Rerun the case — PASS. - [ ] REFACTOR: none.
- [ ] Confirm teeth — delete the
extendsline, watch the case fail, restore. - [ ] Run
pnpm typecheck— exit 0 (scripts/ and tests/ still typecheck under the reconstituted config). - [ ] Run
pnpm format, then commit (chore: split tsconfig.base from tsconfig).
Verified by: tests/monorepo/wiring.test.ts › R2/R3: tsconfig base split…; pnpm typecheck exits 0.
T3 — Seed the @gw2priory/domain package (source-only, self-tested)
Satisfies: R1, R4, R7, R9, P1 #2, P1 #3, SC1.
- [ ] RED: create
packages/domain/package.json(name: "@gw2priory/domain",private: true,type: "module",version: "0.0.0",exports: { ".": "./src/index.ts" }); createvitest.config.tswithinclude: ['packages/**/*.test.ts', 'tests/**/*.test.ts']; write the co-located testpackages/domain/src/index.test.ts(P1 #3: brands an item idandP1 #3: netSellPrice takes the 15% TP tax off—itemId(19721) === 19721,netSellPrice(100) === 85) importing from./index.ts.pnpm install, then runpnpm test— watch it FAIL because./index.tsdoes not exist. - [ ] GREEN: write
packages/domain/src/index.tsexportingItemId(branded),itemId(), andnetSellPrice(gross) => Math.floor(gross * 0.85)exactly as inplan.md› Data & contracts. Rerunpnpm test— the co-located test PASSES. - [ ] Add to
tests/monorepo/wiring.test.tsa caseSC1/R1/R7/R9: packages are private, source-only via exports, under @gw2priory, and emit no distscanning everypackages/*:private: true,exports["."]ends in.ts, name starts@gw2priory/, and nodist/directory exists. It should pass immediately fordomain. - [ ] REFACTOR: none.
- [ ] Confirm teeth — change
0.85to0.75, watch the co-located test fail, restore. - [ ] Run
pnpm typecheck— exit 0, now coveringpackages/domain(P1 #2: no emit produced). - [ ] Run
pnpm format(keep the tree Biome-clean), then commit (feat: seed @gw2priory/domain package).
Verified by: packages/domain/src/index.test.ts (P1 #3 cases); tests/monorepo/wiring.test.ts › SC1/R1/R7/R9: packages are private, source-only…; pnpm typecheck exits 0.
T4 — Consume the package across the workspace (the F3 guard)
Satisfies: P1 #1, P1 #4, R8, SC3.
- [ ] RED: create
tests/monorepo/resolution.test.tswith a caseP1 #1/#4, R8, SC3: @gw2priory/domain resolves by name across the workspacethat imports{ itemId, netSellPrice, type ItemId }from@gw2priory/domainby name and asserts on them (netSellPrice(1000) === 850). Runpnpm exec vitest run tests/monorepo/resolution.test.ts— watch it FAIL withCannot find package '@gw2priory/domain'. Confirm that is the reason (the F3 finding: the workspace glob alone does not link the package), not a typo in the specifier. - [ ] GREEN: add
"@gw2priory/domain": "workspace:*"to the rootpackage.jsondevDependencies;pnpm install(createsnode_modules/@gw2priory/domain -> ../packages/domain); rerun — PASS. - [ ] REFACTOR: none.
- [ ] Confirm teeth — remove the
workspace:*dep andpnpm install, watch the case fail with the sameCannot find package, then restore andpnpm install. - [ ] Run
pnpm typecheck— exit 0 (tscnow resolves the by-name import too). - [ ] Run
pnpm format, then commit (feat: consume @gw2priory/domain across the workspace).
Verified by: tests/monorepo/resolution.test.ts › P1 #1/#4, R8, SC3: …; pnpm typecheck exits 0.
T5 — Lock the remaining invariants and fill traceability
Satisfies: R6 (orchestration half), SC5, SC7; final verification of SC2, SC6, R10.
- [ ] RED: add to
tests/monorepo/wiring.test.tstwo cases:SC5/R6: no build or cache orchestration tool is present(noturbo,nx,@nrwl/*,@moonrepo/*,moon, orrushinpackage.jsonorpnpm-lock.yaml) andSC7: the spec 002 traceability table is complete(parsespecs/002-monorepo-wiring/spec.md’s traceability table — no empty Test cells, and every test name it lists is found as a string in some file undertests/**orpackages/**). Run — theSC7case FAILS because the table cells are still empty. - [ ] GREEN: fill the Test column of
spec.md’s traceability table with the test names delivered in T1–T4 and this task (each row → itsdescribe/itname). Rerun — PASS. - [ ] REFACTOR: none.
- [ ] Confirm teeth — blank one table cell, watch the
SC7case fail, restore. - [ ] Full verification (the step-5 command runs behind
SC2/SC6/R10):pnpm typecheckexits 0 (SC2),pnpm lintexits 0,pnpm testis fully green includingtests/workflow/*(spec 001 suite intact —SC6/R10), andfind docs/superpowers -type f | wc -lprints0(SC6). - [ ] Run
pnpm format, then commit (specs: fill spec 002 traceability and lock wiring invariants).
Verified by: tests/monorepo/wiring.test.ts › SC5/R6: … and SC7: …; a clean pnpm typecheck, pnpm lint, and pnpm test; zero files under docs/superpowers/.
Notes
Staging area for decisions and surprises found during implementation — including anything that turned out differently from what plan.md assumed. Move each one into spec.md, research.md, or docs/ before closing the feature; this section is not a home.
- Environment quirk (this sandbox):
node/pnpmare not on the defaultPATH; they live at/opt/homebrew/bin. Prefixexport PATH="/opt/homebrew/bin:$PATH"when a command reportscommand not found. - After T1, every task runs
pnpm formatbefore its commit sopnpm lintstays green throughout. - Graduation (for step 6): the source-package convention + the
workspace:*precondition, and Biome as the chosen linter/formatter, are the two findingsresearch.mdflagged to move intodocs/architecture/— do not let the branch close without them.