Skip to content

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.

LocationRole today
docs/planning/decisions/D-0001-project-structure.mdThe project-structure ADR; its end-state tree names only apps/ and packages/<eco>/ — no solutions/ tier, and no placement-vs-sharing-scope gradient
LIBRARIES.mdThe 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

D-0001 gains, in place (no new sibling decision):

  • a solutions/ sibling in the end-state tree, between apps/ and packages/, with solutions/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_books as the worked example, pointing at T-C9RD;
  • last_reviewed: 2026-07-19 and related links to T-C9RD and the LIBRARIES concept.
  1. End-state tree (End-state target): add a solutions/ entry between the apps/ and packages/ 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/.

  2. 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/* — so workspace:* / { 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) per LIBRARIES.md.

    Include the default rule verbatim: default a new cluster into solutions/<name>/ rather than scattering apps into apps/ and packages flat into packages/; a package EARNS packages/ by being reached for outside its solution; a redundant solution-local package is retired/folded within its solution.

  3. 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}} under solutions/<name>/; a sharing scope narrower than repo-wide packages/ and wider than a single app.

  4. Reference-migration note: augmented_books is the worked example — adopted flat into apps/ + packages/ts/, which scattered a single-solution cluster and forced the convergence audit (T-JCML, now superseded); the solutions/ staging tier answers that by letting relatedness be observed in place and packages earn packages/ by use. See T-C9RD.

  5. Frontmatter: bump last_reviewed to 2026-07-19; add related links to T-C9RD and the LIBRARIES concept.

  6. Update the living structure docs: add the solution glossary 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).

LocationKindChange
docs/planning/decisions/D-0001-project-structure.mdmodifyAdd 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.mdmodifyCross-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)newAdd a solution glossary term mirroring the existing TM-000X architectural-vocabulary terms, so the generated glossary defines the new structural tier
  • AC-1: solutions/ appears in D-0001’s end-state tree between apps/ and packages/, described as a cluster of apps + packages shared only within one solution (a nested {apps/, packages/{ts,rust}}), naming solutions/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.md exits 0.
  • AC-5: D-0001 carries a related link to T-C9RD (Task C).
  • AC-6: a solution glossary term exists and the regenerated glossary includes it; LIBRARIES.md cross-references the tier-0→1→2 promotion gradient.
  • Executing the migration itself — moving the augmented family into solutions/augmented/ is T-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.
  • none — this is a documentation-only refinement; T-C9RD depends on it, not the other way around.
  • The T-JCML convergence audit (PR #972) was superseded by the solutions/ staging approach: rather than an up-front audit, related packages move into solutions/augmented/ for in-place evaluation, and clear-duplicate findings are carried into the migration epic. This task fixes that approach in the structural ADR.

Captured by /sdlc:task-work on 2026-07-19. PR: pending.

  • AC-1: agent-manual — read the rendered diff; solutions/ sits between apps/ and packages/ in the end-state tree with augmented/ as first occupant. No checker asserts wording fidelity against the Approach.
  • AC-2: agent-manual — ### Placement and promotion present 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.md1/1 file(s) passed, exit 0.
  • AC-5: auto — related carries T-C9RD; schema validation passes.
  • AC-6: auto — TM-0015-solution.md validates and appears in the regenerated docs/glossary.md; LIBRARIES.md cross-reference verified agent-manual.
  • sdlc term create minted 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-baseline correctly classified 8 of 20 rumdl findings as pre-existing, which is exactly the split it exists to make.
  • Pickup ran against a checkout 38 commits behind origin/main, so sdlc task resolve reported not-found for all three requested tasks — the tasks existed only on the remote. Step 1 should fetch and compare HEAD to origin/main before resolving, and say “N commits behind” rather than “NO TASK FOUND”. → T-B5ZA-task-resolve-reports-behind-main
  • preflight_permissions.ts does not recognize defaultMode: auto, only acceptEdits and bypassPermissions, so an auto-mode operator sees a hard gap that is not real. Add auto to 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.lock was stale on origin/main (0ece84a3 bumped a package.json and committed only that app’s nested lockfile), so commit_worktree_init’s bun install --frozen-lockfile failed 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-guard cannot pass a root-level shared file: bun.lock, Cargo.lock, and root package.json exist in all 92 worktrees, so any such commit false-positives. The carve-out list covers docs/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-out
  • quality 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 as new-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-dir default 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

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.


← Back to Tasks