Skip to content

T-KQ7W-note-pages-in-sdf

State: planning/draft · Impact: medium · Complexity: medium

M-YX34’s Notes deliverable is “Routes for the note kind and the N prefix, with wikilinks resolved and task lists rendered”. A note must open as a page in SDF, listed by genre, rendered as markdown, with its wikilinks going to real pages and its checklists showing their state. The acceptance target is N-YQVC-master-consolidation, the master checklist. Every screen reads the real API (T-1ODN); the views are read-only.

  • Pages under solutions/ontological/desktop/src-nuxt/app/pages/model/: tasks.vue, milestones.vue, and the generic browser entities/[type].vue (list in the secondary pane, via useScopedEntityList) with entities/[type]/[id].vue (detail via useEntityDetail in app/composables/useEntities.ts).
  • The front-end roster BROWSABLE_ENTITY_TYPES in app/utils/entityRegistry.ts (L25-35) has no notes. resolveEntityLink builds on that roster (BY_PREFIX), so N ids resolve to null today. C already resolves to /model/entities/capabilities/<id> (pinned by the “links a capability wikilink” test in entityRegistry.test.ts), so the doc comment above resolveEntityLink (“C… -> null, gated on M-0012”) is stale and must be fixed in this task.
  • Body rendering: app/components/entities/EntityBodySection.vue mounts MdViewer with entityBodyRenderOptions and entityBodyComponents from app/utils/entityBodyRenderOptions.ts. There resolveLink: (target) => ({ kind: 'missing', display: target }) marks every wikilink missing (no href, class wikilink-missing). The resolver is module-level and stable, so it cannot see the document’s project.
  • Task lists: entityBodyComponents maps 'input.checkbox' to ReadOnlyTaskCheckbox, which renders a disabled <input type="checkbox"> whose checked comes from the node. So the state displays and clicking does nothing. Task-list CSS is in packages/ts/obsidian-md/src/theme.css.
  • EntityBodySection.vue offers an Edit mode when a save is passed (canEdit). The note page must not offer it.
  • The note schema (lib/model/entities/note/schema.ts) has genre (8 values) and optional parent (a note wikilink). The list rows get both fields from T-1ODN.
  • N-YQVC has genre: plan, 58 [[ wikilinks, and - [x] task lines.
  • Resolver outcomes available from @sksizer/obsidian-md (LinkResolution.kind in packages/ts/obsidian-md/src/types.ts): note, attachment, missing, external. There is no “plain text” kind.

Notes open at /model/entities/notes and /model/entities/notes/<id> through the generic browser. The list groups rows by genre. The detail renders the body with wikilinks that go to the right page (carrying ?project=), checkboxes that show their state, and a parent link to the hub note. N-YQVC renders fully.

  1. Add { type: 'notes', prefix: 'N', label: 'Notes' } to BROWSABLE_ENTITY_TYPES in entityRegistry.ts. This makes N resolve in resolveEntityLink and parseWikiText, so the parent and related frontmatter chips link too. Fix the stale C comment. This task owns that comment fix; T-14JA edits the same file’s neighbours but leaves the comment to this task and fixes only the fixtures.ts header. The Model nav is generated from BROWSABLE_ENTITY_TYPES (plugins/register.ts), so this entry also adds a Notes nav entry.
  2. Add a pure helper groupByGenre(rows) (in entityRegistry.ts or a new util with a test): rows grouped by genre, genres in NOTE_GENRES order, null genre last, rows in id order.
  3. Render the grouping in the list for notes only (a section per genre inside EntityListPanel or [type].vue); other types keep their flat list.
  4. Make body links resolve. Replace the module-level resolver with a factory entityBodyRenderOptionsFor(project) that is memoized per project id, so the options identity stays stable. It calls resolveEntityLink(target, project): a route gives { kind: 'note', path: route, display: target }; null gives { kind: 'missing', ... }. entityBodyProvider.resolveLink must use the same function (its doc says they share one). Decision: an unknown kind (for example glossary) keeps the dead look (missing); no plain-text kind or CSS rule is added.
  5. Navigate inside the app. WikilinkAnchor (packages/ts/obsidian-md/src/vue/components/) calls preventDefault on a plain click and reports it as link-click, which MdViewer re-emits as @link-click with { resolution, event }; a resolved href alone does not navigate. So EntityBodySection.vue adds @link-click on MdViewer: when resolution.kind === 'note' and resolution.path is set, call navigateTo(resolution.path) (router push, no reload). Modified clicks fall through to the browser.
  6. Task checkboxes need no new code. entityBodyComponents already maps 'input.checkbox' to ReadOnlyTaskCheckbox, which reads checked from the node, and that path already renders task bodies. N-YQVC has 59 - [ ] and - [x] lines. The live check (AC-6) is the verification; if it shows a box missing, fix ReadOnlyTaskCheckbox in that same PR.
  7. Pass no save for notes in [type]/[id].vue so no Edit button shows.
  8. parent shows as a link through the existing frontmatter table: it renders wikilink chips through parseWikiText, which resolves them once N is on the roster (step 1). No separate header link is added; AC-8 checks it.
  9. Vitest cases for resolveEntityLink('N-YQVC', 'p1'), the resolver factory, groupByGenre.
AreaNote
solutions/ontological/desktop/src-nuxt/app/utils/entityRegistry.tsRoster, N link, genre helper
solutions/ontological/desktop/src-nuxt/app/utils/entityRegistry.test.tsPure-helper tests
solutions/ontological/desktop/src-nuxt/app/utils/entityBodyRenderOptions.tsProject-aware resolver, task boxes
solutions/ontological/desktop/src-nuxt/app/components/entities/EntityBodySection.vuePass the resolver options
solutions/ontological/desktop/src-nuxt/app/components/entities/EntityListPanel.vueGenre sections
solutions/ontological/desktop/src-nuxt/app/pages/model/entities/[type].vueList wiring
solutions/ontological/desktop/src-nuxt/app/pages/model/entities/[type]/[id].vueRead-only note detail
  • AC-1: resolveEntityLink('N-YQVC', 'p1') returns /model/entities/notes/N-YQVC?project=p1; vitest.
  • AC-2: groupByGenre orders groups by NOTE_GENRES, puts null genre last, and keeps id order inside a group; vitest.
  • AC-3: The body resolver returns a note resolution with the project-carrying route for N, D, T, M, C targets, and missing for an unknown kind; vitest.
  • AC-4: The resolver factory returns the same object for the same project id; vitest.
  • AC-5: Against sdf-serve, /model/entities/notes lists notes grouped by genre, and the Model nav shows a Notes entry.
  • AC-6: Against sdf-serve, the N-YQVC page shows its - [x] and - [ ] items as disabled checkboxes with the right state, and clicking one changes nothing and sends no request.
  • AC-7: On that page a N-... link opens the other note without a page reload, with ?project= kept on the URL.
  • AC-8: A note with a parent links to it from the frontmatter table; no Edit button shows on a note.
  • AC-9: Styles use only --d-* tokens; no raw colour values are added.
  • AC-10: The resolveEntityLink doc comment in entityRegistry.ts no longer says C… → null.

CI is the typecheck; vue-tsc is never run locally (no nuxi typecheck either). Local verification is vitest plus nuxt generate plus a run against sdf-serve, the headless server from open PR #2546. Every /api/* request through sdf-serve carries the x-platform-token header; there is no tokenless read there. Styles use only --d-* design tokens (the vocabulary is in packages/ts/ui/docs/design-system.md section 2, values in packages/ts/ui/app/assets/css/tokens.css; decision docs/planning/decisions/D-DLNG-design-language.md).

Commands, from solutions/ontological/desktop/src-nuxt:

  • bunx vitest run app/utils/entityRegistry.test.ts (and any new util test)
  • bun run generate (runs nuxt generate)
  • Start sdf-serve with moon run sdf:serve (127.0.0.1:16175). Paste the token (the file path it prints at startup, or SDF_PLATFORM_TOKEN) in Settings. Open /model/entities/notes/N-YQVC?project=<id> and check AC-5 to AC-8 by eye.
  • Writing: no Edit mode, no checkbox toggling (reading mode listens for no task-toggle).
  • A note tree view or graph; parent is one link.
  • Capability, milestone, task and roadmap pages (other M-YX34 tasks).
  • Bespoke note creation or the adoption wizard.
  • T-1ODN: list rows with genre and parent, and the notes route.
  • Open PR #2546 for sdf-serve (live check only).

Found while scoping M-YX34’s Notes deliverable.

T-1ODN


← Back to Tasks