T-4VNC-learning-p1-scaffold-solution
State: open/ready · Impact: high · Complexity: medium
Stand up the empty shape D-LIRI decides: a reader experience, a thin
product and two package stubs, all inside solutions/determined/, built
on the frame and determined’s native vault APIs only. Two of the
determined-local packages gain a consumer outside the solution here,
which is D-0001’s promotion trigger, so they move to packages/ts/ in
the same change. Every later phase lands inside this scaffold.
| Location | Role today |
|---|---|
solutions/determined/packages/vault-platform-client/ | @determined/vault-platform-client: the manifest and product types plus the ontogen-generated transport. Written by crates/determined-platform’s build.rs |
solutions/determined/packages/code-editor/ | @determined/code-editor: CodeSurface, a themed CodeMirror 6 layer with an extensions prop. Tier 0 |
solutions/determined/packages/obsidian-astro/ | @sksizer/obsidian-astro: vault to Astro content collections. Tier 0 |
solutions/determined/products/fitness/ | The reference product shape: extends @sksizer/app-frame, one experience, @determined/ui; ssr: false; no shell, no vaults layer |
solutions/determined/experiences/fitness/app/plugins/register.ts | The reference module registration: registerModule(defineModule(...)) |
dev-ports.yaml | The port registry. Books takes the next free number in determined’s 15000-15999 band |
.moon/workspace.yml | Project globs and the explicit solutions/determined/packages/* sources |
docs/LIBRARIES.md | The tier roster; promoted packages move from the tier 0 table to the tier 1 table |
Proposed
Section titled “Proposed”solutions/determined/ packages/book-model/ @determined/book-model — note kinds, exercise specs, contract corpus (stub) packages/runners/ @determined/runners — plain Vue, no Nuxt (stub) experiences/learning/ @determined/exp-learning — registers module `learning`, scope `scoped` products/books/ extends [app-frame, exp-learning, ui]; Tauri crate is the three-line mainpackages/ts/code-editor moved, name unchangedpackages/ts/obsidian-astro moved, name unchanged@determined/vault-platform-client stays where it is: it is a build
artifact of crates/determined-platform, so it belongs beside the crate
that writes it.
The experience renders one page: the vault roster through
vaultGetVaults, one vault’s doc list through vaultNoteGetDocs, and
one note through vaultNoteReadDoc into MdViewer. That proves the
native-API path end to end before any learning code exists. The product
builds for web and for Tauri.
Approach
Section titled “Approach”git mvcode-editorandobsidian-astrotopackages/ts/; update the moon sources,scripts/guard-raw-palette.tsanddocs/LIBRARIES.md. Names are unchanged, so no import moves.- Create the four projects above. The root workspaces and the moon
experience/product globs already cover
solutions/determined/; only the two packages need explicit moon sources, andCargo.toml’ssolutions/determined/products/*/src-taurimember already covers the books crate. - Write the experience:
register.tsafter fitness’s, one page under/apps/learning,useTransport<Transport>()for reads. No server routes, no new determined-platform code. - Write the product after
products/fitness, withhomeExperience: 'learning', thedetermineddeep-link scheme, and the next free port in the determined band. - Verify:
bun install --frozen-lockfile;moon run product-books:buildfor web andcargo build -p product-booksfor Tauri; the determined products still build with the promoted packages.
| Area | Note |
|---|---|
solutions/determined/packages/code-editor/ | git mv to packages/ts/code-editor/ |
solutions/determined/packages/obsidian-astro/ | git mv to packages/ts/obsidian-astro/ |
packages/ts/code-editor/ | Promoted package, name unchanged |
packages/ts/obsidian-astro/ | Promoted package, name unchanged |
solutions/determined/packages/{book-model,runners}/ | The two stubs |
solutions/determined/experiences/learning/ | The reader layer |
solutions/determined/products/books/ | The product and its Tauri crate |
.moon/workspace.yml | Two package sources; drop the two promoted ones |
dev-ports.yaml | product-books in the determined band |
docs/LIBRARIES.md | Two rows move to tier 1; a determined row for the two stubs |
solutions/determined/products/README.md | The books row and what it extends |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
moon run product-books:buildandcargo build -p product-booksboth pass; the app opens, lists the vaults in the roster, and renders one note. - AC-2:
git grep 'solutions/determined/packages/\(code-editor\|obsidian-astro\)'outsidedocs/planning/returns nothing; determined products build unchanged. - AC-3:
solutions/determined/experiences/learning/reads the vault API only through@determined/vault-platform-clientand adds no file undersolutions/determined/crates/. - AC-4:
bun install --frozen-lockfilepasses at root.
Out of scope
Section titled “Out of scope”- Any learning content, exercise, or progress code. Later phases.
@determined/shell. The product runs on the frame alone, as fitness does.- A
solutions/learning/tree.D-LIRIplaces books inside determined.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”D-LIRI, the decision this scaffold realizes.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-09-13. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: agent-manual —
moon run product-books:build(nuxt generate, prerenders/apps/learning),cargo build -p product-booksandmoon run product-books:checkall pass. The app was not launched; “opens, lists vaults, renders a note” is proven by build and typecheck only. deferred-user for the running window. - AC-2: auto — grep for the two old package paths outside
docs/planning/returns nothing (bun.lock and the system-graph lab fixtures excluded);moon run product-fitness:buildpasses. - AC-3: auto — the experience imports
@determined/vault-platform-clientand nothing else from determined; no file added undersolutions/determined/crates/. - AC-4: auto —
bun install --frozen-lockfileexits 0.
What worked
Section titled “What worked”- The fitness product and experience were a complete template: product manifest, transport plugin, Tauri crate shape and moon tags copied across with only names and ports changed.
- The generated transport’s method names were enough to write the page without touching the shell or the scope machinery.
Friction and automation gaps
Section titled “Friction and automation gaps”- Pre-commit took 4 to 12 minutes per commit, almost all of it
check_skill_docs.tsrendering every mermaid block through a headless browser regardless of what is staged — scope that gate to staged skill docs. → T-JL2Q-scope-skill-docs-gate-to-staged sdlc quality run --diff-against-baselineresolves.sdlc/quality-baselines/against the worktree whilebaseline capturewrites it to the main checkout, so the file had to be copied by hand — resolve the baseline directory against the common git dir. → T-OLTA-task-work-step7-worktree-baseline-dir- Two live relative paths (
tests/ui/mvux/vault-nodes.vaults.e2e.ts,experiences/fitness/tests/admin-registry.test.ts) resolved into the moved package by..segments and were invisible to a path grep — a move recipe should grep forresolve(and../reaches into the moved directory, or the repo should ban cross-package relative reaches. → T-U2JP-guard-cross-package-relative-reaches - The system-graph lab fixtures (
repo.json,repo-external.json,moon-facets.json) now describe a stale layout; regenerating is a 37,000-line diff that also invalidates hand-written counts inlab/fixtures/index.ts— a separate refresh chore, and a note on the fixtures README about when the snapshot is meant to be retaken. → T-ERF6-refresh-stale-system-graph-fixtures scripts/guard-project-shape.tsis already red onmain(product-suspenders,product-system-graphmatch no aspect), so the guard cannot ratchet — pre-existing, needs its baseline updated. → T-356Q-fix-guard-project-shape-baseline
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-JL2Q-scope-skill-docs-gate-to-staged (#2084) [open/ready] — spawned: scope check_skill_docs.ts’s mermaid-render gate to staged skill docs only.
- T-OLTA-task-work-step7-worktree-baseline-dir [open/ready] — linked: task-work Step 7’s quality-baseline-dir-from-worktree gap already tracked here (fifth independent observation).
- T-U2JP-guard-cross-package-relative-reaches (#2085) [open/ready] — spawned: move recipes should catch relative-path reaches into a moved directory.
- T-ERF6-refresh-stale-system-graph-fixtures (#2086) [open/ready] — spawned: refresh chore for stale system-graph lab fixtures after repo layout moves.
- T-356Q-fix-guard-project-shape-baseline (#2087) [open/ready] — spawned: guard-project-shape.ts baseline needs updating for product-suspenders and product-system-graph.