T-1YSW-amend-d0001-solutions-tier
Status: closed/done · Impact: medium · Complexity: small
D-0001 fixes a two-plane placement model — apps/<name>/ for standalone
applications and packages/<eco>/ for repo-wide shared libraries — with no
home for a cluster of apps and packages that belong to ONE solution and are
shared only among themselves. Adopting the augmented family flat into that
model scattered a single-solution cluster across apps/ and packages/ts/
and forced the T-JCML convergence audit. Refine D-0001 in place to
introduce a third structural root, solutions/, plus a package-promotion
gradient, so a related cluster stages together and a package earns
packages/ by observed cross-solution use rather than by up-front guess.
| Location | Role today |
|---|---|
docs/planning/decisions/D-0001-project-structure.md | The project-structure ADR; its end-state tree names only apps/ and packages/<eco>/ — no solutions/ tier, and no placement-vs-sharing-scope gradient |
LIBRARIES.md | The bar a package clears to become a published derived library (stable API, docs, ownership, snapshot-mirror channel) |
apps/augmented-books/ | An augmented-family app adopted flat into apps/ |
apps/learn_web/ | An augmented-family app adopted flat into apps/ |
packages/ts/books/ | An augmented-family package adopted flat into packages/ts/, consumed only by the augmented apps |
packages/ts/entity/ | An augmented-family package adopted flat into packages/ts/, consumed only by the augmented apps |
Proposed
Section titled “Proposed”D-0001 gains, in place (no new sibling decision):
- a
solutions/sibling in the end-state tree, betweenapps/andpackages/, withsolutions/augmented/named as the first occupant; - a Placement and promotion subsection under Layout rules stating the three placement scopes and the two package-promotion gates;
- a solution bullet in the Summary vocabulary;
- a reference-migration note citing
augmented_booksas the worked example, pointing atT-C9RD; last_reviewed: 2026-07-19andrelatedlinks toT-C9RDand theLIBRARIESconcept.
Approach
Section titled “Approach”-
End-state tree (End-state target): add a
solutions/entry between theapps/andpackages/lines, worded:solutions/ mini-projects — a cluster of apps + packages that belong to ONE solution and are shared only within it; a nested {apps/, packages/{ts,rust}}. First occupant: solutions/augmented/. -
Placement and promotion subsection under Layout rules. State the three placement scopes by sharing scope:
apps/<name>/— a standalone application (shared with nothing);solutions/<s>/— related apps + packages shared WITHIN the one solution;packages/<eco>/— a package that spans 2+ apps OR solutions (shared repo-wide).
Add the workspace-membership note: solution-local packages stay workspace members — globbed from
solutions/*/apps/*,solutions/*/packages/ts/*,solutions/*/packages/rust/*— soworkspace:*/{ workspace = true }still resolves; the directory is a sharing-scope signal, not a resolution barrier.State the two promotion gates for a package’s home (it earns a wider home by observed use, name unchanged):
- tier 0 → 1 (solution-local →
packages/<eco>/): promote when a consumer OUTSIDE the origin solution imports it — a directory move plus a glob-membership change; resolution is unchanged because the package name does not move. - tier 1 → 2 (shared
packages/→ derived library): promote when it clears the derived-library bar (stable API, docs, ownership) perLIBRARIES.md.
Include the default rule verbatim: default a new cluster into
solutions/<name>/rather than scattering apps intoapps/and packages flat intopackages/; a package EARNSpackages/by being reached for outside its solution; a redundant solution-local package is retired/folded within its solution. -
Vocabulary bullet in the Summary: define a solution as a cluster of apps and packages that belong to one solution and are shared only within it — a nested
{apps/, packages/{ts,rust}}undersolutions/<name>/; a sharing scope narrower than repo-widepackages/and wider than a single app. -
Reference-migration note:
augmented_booksis the worked example — adopted flat intoapps/+packages/ts/, which scattered a single-solution cluster and forced the convergence audit (T-JCML, now superseded); thesolutions/staging tier answers that by letting relatedness be observed in place and packages earnpackages/by use. SeeT-C9RD. -
Frontmatter: bump
last_reviewedto2026-07-19; addrelatedlinks toT-C9RDand theLIBRARIESconcept. -
Update the living structure docs: add the
solutionglossary term (mint a TM-id) and cross-reference LIBRARIES.md’s channel as the tier-2 promotion target; regenerate the glossary/site (sdlc docs generate).
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
docs/planning/decisions/D-0001-project-structure.md | modify | Add solutions/ to the end-state tree; add the Placement and promotion subsection with both promotion gates and the workspace-signal note; add the solution vocabulary bullet; add the augmented_books reference-migration note pointing at T-C9RD; bump last_reviewed to 2026-07-19; add related links to T-C9RD and LIBRARIES |
LIBRARIES.md | modify | Cross-reference the promotion gradient — note the derived-library publish channel is the tier-2 promotion target above the solutions/→packages/ (tier-0→tier-1) move |
docs/planning/terms/ (new TM-<minted>-solution.md) | new | Add a solution glossary term mirroring the existing TM-000X architectural-vocabulary terms, so the generated glossary defines the new structural tier |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
solutions/appears in D-0001’s end-state tree betweenapps/andpackages/, described as a cluster of apps + packages shared only within one solution (a nested{apps/, packages/{ts,rust}}), namingsolutions/augmented/as the first occupant. - AC-2: A Placement and promotion subsection is present under
Layout rules and states BOTH promotion gates — the tier 0→1 gate
(a consumer outside the origin solution imports the package) and the
tier 1→2 gate (the package clears the derived-library bar per
LIBRARIES.md). - AC-3: A solution term is defined in the Summary vocabulary.
- AC-4:
sdlc entities validate docs/planning/decisions/D-0001-project-structure.mdexits 0. - AC-5: D-0001 carries a
relatedlink toT-C9RD(Task C). - AC-6: a
solutionglossary term exists and the regenerated glossary includes it; LIBRARIES.md cross-references the tier-0→1→2 promotion gradient.
Out of scope
Section titled “Out of scope”- Executing the migration itself — moving the augmented family into
solutions/augmented/isT-C9RD. - Deleting the clear-duplicate packages — that is
T-J5DI. - Minting a new sibling decision: this is an in-place refinement of D-0001, not a superseding ADR.
- The per-package share/fold evaluation the migrated packages still need (backlog B-6V5U / B-UEE4) — evaluated in place after the move.
Dependencies
Section titled “Dependencies”- none — this is a documentation-only refinement;
T-C9RDdepends on it, not the other way around.
Discovery context
Section titled “Discovery context”- The T-JCML convergence audit (PR #972) was superseded by the
solutions/staging approach: rather than an up-front audit, related packages move intosolutions/augmented/for in-place evaluation, and clear-duplicate findings are carried into the migration epic. This task fixes that approach in the structural ADR.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-07-19. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: agent-manual — read the rendered diff;
solutions/sits betweenapps/andpackages/in the end-state tree withaugmented/as first occupant. No checker asserts wording fidelity against the Approach. - AC-2: agent-manual —
### Placement and promotionpresent under Layout rules with the 3-scope table, the workspace-membership note, and a 2-row gate table. - AC-3: agent-manual — solution bullet added to the Summary vocabulary.
- AC-4: auto —
sdlc entities validate docs/planning/decisions/D-0001-project-structure.md→1/1 file(s) passed, exit 0. - AC-5: auto —
relatedcarriesT-C9RD; schema validation passes. - AC-6: auto —
TM-0015-solution.mdvalidates and appears in the regenerateddocs/glossary.md; LIBRARIES.md cross-reference verified agent-manual.
What worked
Section titled “What worked”sdlc term createminted TM-0015 and collision-checked it; no hand-picked id.- The task’s Approach was unusually prescriptive (near-verbatim wording per step), so the implementer needed no design conversation.
--diff-against-baselinecorrectly classified 8 of 20 rumdl findings as pre-existing, which is exactly the split it exists to make.
Friction and automation gaps
Section titled “Friction and automation gaps”- Pickup ran against a checkout 38 commits behind
origin/main, sosdlc task resolvereported not-found for all three requested tasks — the tasks existed only on the remote. Step 1 should fetch and compareHEADtoorigin/mainbefore resolving, and say “N commits behind” rather than “NO TASK FOUND”. → T-B5ZA-task-resolve-reports-behind-main preflight_permissions.tsdoes not recognizedefaultMode: auto, onlyacceptEditsandbypassPermissions, so an auto-mode operator sees a hard gap that is not real. Addautoto the recognized blanket modes. → T-DTAQ-preflight-probe-auto-mode-and-abs-globs- Absolute-path permission globs silently match nothing without a doubled leading slash
(
Write(//abs/path/**)). The probe should detect a single-slash absolute glob for the worktree path and say so, instead of reporting the grant as simply missing. → T-DTAQ-preflight-probe-auto-mode-and-abs-globs - Root
bun.lockwas stale onorigin/main(0ece84a3 bumped a package.json and committed only that app’s nested lockfile), socommit_worktree_init’sbun install --frozen-lockfilefailed and EVERY commit-to-main path was wedged. A CI gate asserting a frozen root install on main would have caught this at the source PR. → already addressed by PR #1007 (.github/workflows/lockfile-drift.yml); no task spawned. worktree-scope-guardcannot pass a root-level shared file:bun.lock,Cargo.lock, and rootpackage.jsonexist in all 92 worktrees, so any such commit false-positives. The carve-out list coversdocs/planning/tasks/and generated docs; it needs a root-shared-file carve-out too, or the fix is unlandable without the escape hatch. → T-QWJW-scope-guard-root-shared-file-carve-outquality baseline capture <sha>runs the verbs against the CURRENT working tree while keying the cache on<sha>. When main advanced between capture and gate, 10 findings in an untouched file (T-OLTA…) surfaced asnew-drift:and failed the gate. Capture must materialize the SHA’s tree (an off-SHA worktree) rather than measuring cwd. → T-7FPF-baseline-capture-against-origin-main-tree (linked, not spawned)- The baseline differ counts rumdl SUMMARY lines (
Issues: Found 18 issues in 5/972 files,Run rumdl fmt to automatically fix 14 of the 18) as findings, so a changed total is reported as 2 new findings. The differ should drop non-location-bearing lines. → T-BCNP-quality-gate-ignores-summary-and-corpus-lines (linked, not spawned) - Step 7’s
--baseline-dirdefault resolves from the worktree, not the superproject, so the gate could not find the captured baseline until the flag was passed explicitly. Already tracked by T-OLTA-task-work-step7-worktree-baseline-dir. - The full gate exceeds 10 minutes, past the inline command timeout, so both baseline captures had to be backgrounded. Worth either splitting a fast pre-PR subset or documenting that capture is a background-only step. → T-1HA7-fast-pre-pr-quality-subset
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-B5ZA-task-resolve-reports-behind-main (https://github.com/sksizer/dev/pull/1031) [open/ready] — Step 1 reports commits-behind instead of NO TASK FOUND, spawned.
- T-DTAQ-preflight-probe-auto-mode-and-abs-globs (https://github.com/sksizer/dev/pull/1025)
[open/ready] — probe recognizes
automode and flags single-slash absolute globs; folds two bullets, spawned. - T-QWJW-scope-guard-root-shared-file-carve-out (https://github.com/sksizer/dev/pull/1021)
[open/ready] — root-shared-file carve-out for
bun.lock/Cargo.lock/rootpackage.json, spawned. - T-1HA7-fast-pre-pr-quality-subset (https://github.com/sksizer/dev/pull/1028) [open/ready] — fast pre-PR quality subset for the 10-minute inline timeout; also covers the same bullet in T-J5DI-remove-clear-duplicate-augmented-packages, spawned.
- T-7FPF-baseline-capture-against-origin-main-tree [open/ready] — baseline capture measures cwd
while keying on
<sha>, linked. - T-BCNP-quality-gate-ignores-summary-and-corpus-lines [planning/backlog] — differ counts non-location-bearing SUMMARY lines, linked.
- T-OLTA-task-work-step7-worktree-baseline-dir [open/ready] — Step 7
--baseline-dirresolves from the worktree, linked.
The frozen-root-install bullet spawned nothing: PR #1007 already adds
.github/workflows/lockfile-drift.yml, which runs bun install --frozen-lockfile
at the repo root on any PR touching a package.json or bun.lock — the exact
gate the bullet asks for. That PR is open, not yet merged.