Skip to content

RESEARCH — Adopt ordna as ledger substrate: task-view + ledger-cli retirement (ID-165.1)

RESEARCH — ID-165 Adopt ordna as ledger substrate

Section titled “RESEARCH — ID-165 Adopt ordna as ledger substrate”

Task: ID-165 — Adopt ordna as ledger substrate: task-view + ledger-cli retirement. Subtask: {165.1} RESEARCH. Author date: 23/07/2026. Status: research only — no spec, no migration, no retirement performed. The eight ratified decisions (kickoff intent-kickoff-id-165.md, feasibility session 22/07/2026) are treated as constraints throughout; anywhere the code contradicts one it is flagged, not worked around. Evidence base: ordna v0.3.0 source (git tag release: v0.3.0, commit 1ab8a912, 20/07/2026, cloned read-only), the live ledger JSONs, and the canonical + docs-site working trees at time of writing.

Supersession context: ID-164 is done (closed S491); its WP5 (“task-view decoupling + interim ledger simplification”) folds into this task. ID-163 is in_progress (spec-tier TECH+PLAN lane) — see §6 cutover sequencing.


1. Ordna capability verification against the eight ratified decisions

Section titled “1. Ordna capability verification against the eight ratified decisions”

Every feasibility claim from the seed was checked against the v0.3.0 source. Verdicts: all eight decisions are supported by the code as ratified — none contradicted. Two adjacent findings the decisions do not cover (priority-value coercion, status-set mapping) are in §5 and the open questions; they are migration-mapping gaps, not decision contradictions.

#DecisionVerdictEvidence
1No fork; consume @frehilm/ordna-core / -cli as dependenciesVerifiedBoth packages published at 0.3.0 on npm (npm view @frehilm/ordna-core version0.3.0; same for -cli). MIT (repo LICENSE). Core is a pure data layer with no UI imports (packages/core/src/); CLI re-exports the full core API (README §Packages).
2Ordna root = private docs-site checkoutVerifiedOrdna operates on process.cwd()createContext(cwd = process.cwd()) (packages/core/src/store.ts:64); config resolved from <cwd>/.ordna/config.yaml (config.ts:58). Running from the docs-site root keeps all task content in the private repo. Caveat: every ordna invocation is cwd-bound — see §5 issue I-3.
3tasks/ at docs-site repo root, not under src/content/VerifiedtasksDir default tasks, resolved relative to project root (config.ts:8, config.ts:92-94). Docs-site root has no existing tasks/ dir (checked 23/07/2026) — no collision. Astro content collections only scan src/content/, so ordna frontmatter never hits collection validation.
4storage: file; schema: ordna; statuses: [backlog, todo, doing, done]; idPrefix: id; zeroPaddedIds: 0VerifiedConfig schema accepts all values: statuses any string array min 1, idPrefix any string, zeroPaddedIds int 0–10, storage enum incl. file (default) (config.ts:7-18). formatId emits ${idPrefix}-${n} with no padding at 0 → id-165 exactly (ids.ts:4-8). Filename is <id>.md in ordna schema → tasks/id-165.md (storage/file-io.ts:68-81). First configured status is the default for new tasks (AGENTS.md §3 rules) → new items land in backlog unless -s passed. The backlog status name does not collide with schema: backlog (unrelated config axes).
5Backlog = status column, single id-spaceVerifiedID allocation scans tasksDir for the highest numeric id and increments (ids.ts:31-44) — one id-space across all statuses by construction. With 154 task records migrated (highest id-165), the next create allocates id-166; renumbered bl-* items simply continue the sequence. Promotion = status flip (ordna move <id> todo), no file move.
6Subtasks inside the parent task file; no child filesVerifiedParser splits the body on any ## heading and preserves arbitrary sections verbatim (parser.ts:77-105); writer re-emits every section (writer.ts:53-64). ###-level content (e.g. per-subtask blocks inside a ## Subtasks section) is preserved as section content — not separately parsed, which is exactly the no-hierarchy-extension posture decision 6 wants. Caveat on AC parsing: only the ## Acceptance Criteria section’s checkboxes are structurally parsed for board AC progress (parser.ts:116-125, aliases schema.ts:136-142) — per-subtask checklists elsewhere are preserved but invisible to the board counter (see OQ-6).
7Initiatives + retros exit the ledger system; initiative: extra-frontmatter keyVerifiedExtra frontmatter keys round-trip: schema is .passthrough() (schema.ts:176), unknown keys are collected into extra_frontmatter (parser.ts:127-137) and written back untouched (writer.ts:47-49); AGENTS.md states “Extra frontmatter keys are preserved on write but ignored by the board” (template §2). An initiative: key needs no ordna support at all.
8Direct agent writes; Coordinator owns done; CLI-only dependency gateVerifiedFile mode = plain markdown files, editable by anything (README §storage-modes table). The depends_on gate lives in moveTask in core (store.ts:147-174) and fires only when the target status is the LAST configured status (store.ts:155done in our four-status config), only via CLI/TUI/web code paths. Raw file edits bypass it entirely, confirming “gate discipline is convention” as ratified. updateTask (non-move patch) does not run the gate (store.ts:131-140).
ClaimVerdictEvidence
Extra frontmatter keys round-trip untouchedVerifiedschema.ts:146-176 (.passthrough()), parser.ts:127-137 (collectExtraFrontmatter), writer.ts:47-49 (re-emitted unless colliding with a canonical key). Nuance: keys whose names are known aliases (priority, status, labels, dependencies, created, updated, …, full list schema.ts:108-119) are NOT “extra” — they are normalised, and unknown values in them can be coerced (see §5 I-1).
idPrefix: id + zeroPaddedIds: 0 reproduces id-N exactlyVerifiedids.ts:4-8; parseId accepts id-165 back (ids.ts:10-16); filename id-165.md (file-io.ts:80).
Parser accepts arbitrary ## body sectionsVerifiedparser.ts:77-105 (splitSections — every ## heading becomes a Section; pre-heading content kept as a level-0 preamble). Round-trip normalises blank lines (sections re-joined with \n\n, content trimmed — writer.ts:53-64) but loses no content.
archived status built in and hidden from the boardVerifiedARCHIVED_STATUS = "archived" reserved sentinel, accepted by update/move regardless of config.statuses (storage/backend.ts:11-17). Hidden from board/all views and given its own sidebar bucket in both UIs: TUI Sidebar.tsx:40,106-107, App.tsx:192-194,233; web App.tsx:277-295,359. No dependency gate on archiving (it is not the terminal status).
storage: file default; hybrid a drop-in later upgradeVerifiedDefault file (config.ts:18). Hybrid keeps the identical on-disk layout and only adds a git-ref CAS id-allocator (refs/ordna/state) — README §hybrid; requires a git repo (store.ts:68-76), which the docs-site is. Switching later = edit storage: in config; task files unchanged. ORDNA_STORAGE env var overrides per-process (config.ts:84-87) — useful for CI.
Per-file markdown kills JSON size / server / CLI chattinessVerified by constructioncat tasks/id-165.md replaces show; board derived by reading the files (FileBackend.list, storage/backends/file.ts). At migrated scale (~350 files) a full-board list is a few hundred small file reads — no server, no cache, no budget shaping.

Also verified, relevant to WP1/WP5: CLI verb surface is init, list/ls, show, create, move, assign, attach, commit, web, board, skill (packages/cli/src/commands/); there is no body-edit verb and no delete verb — body edits and deletions are direct file operations, which matches decision 8. ordna commit stages tasks/ + commits, never auto-runs (AGENTS.md §4).


2. What exists today — retirement-surface inventory

Section titled “2. What exists today — retirement-surface inventory”

Headline inbound-reference counts (canonical repo, excluding scripts/ledger-* themselves and node_modules): ledger-cli appears on 150 lines across 46 files; task-view on 200 lines. Full file list held in the audit greps below; the per-surface breakdown:

SurfaceSizeNotes
scripts/ledger-cli.ts5,907 LOCThe mutation CLI. Journal verbs (journal, journal-search, append-journal) confirm journals live in subtask.details (header comments ledger-cli.ts:24-39,79).
scripts/ledger-server-lifecycle.ts803 LOCSpawns/pins the patch-server from .cache/task-view-<tag>/ (:208,254-255).
scripts/ledger-server-client.ts392 LOCHTTP client for the patch-server.
scripts/ledger-compact-done.ts179 LOCJournal compaction → ledgers/archive/ID-N-journals.md.
scripts/regen-mirrors.sh156 LOCPer-record mirror regeneration.
lib/ledger/ (4 modules + README)2,086 LOCThe vendored task-view surface — CLI-side validation oracle, byte-faithful copies of task-view packages/server/* (lib/ledger/README.md).
.claude/hooks/ledger-compact-session-end.sh~90 LOCSessionEnd compaction hook (spawn-avoidant, lock in shared .cache/). Not named in the kickoff — additional surface found.
.cache/task-view-v0.12.1-task-view/untrackedPresent in the primary checkout only (gitignored); absent from worktrees.

Already removed ahead of this task (commit 37042db1, 22/07/2026, owner-approved): all __tests__/scripts/ledger-* + __tests__/docs/*ledger* suites, ledger fixtures, scripts/ledger-differential-parity.ts, scripts/task-view-drift-age.ts, scripts/kh-output-budget.ts. The kickoff’s retirement list includes two files that no longer exist (ledger-differential-parity, task-view-drift-age) — nothing to do there except the dangling references below.

WorkflowLedger-facing?Finding
task-view-vendor-drift.ymlEntirelyRetire whole workflow. Already broken: it invokes scripts/task-view-drift-age.ts (task-view-vendor-drift.yml:37-38,374,390), deleted in 37042db1 — any PR touching the four watched schema files will hit a missing-script step. Non-blocking by design (OQ-T2), so it degrades quietly, but it is dead weight from day one of ID-165.
ci.yml quality-test jobOne stepLines 275-290 clone + provision task-view v0.12.1-task-view because “the ledger WRITE suites default to the server transport”. Those suites were all deleted in 37042db1the clone step is already vestigial and can go in the retirement sweep independent of cutover. No other ci.yml job touches ledgers.
schema-parity.ymlNoKickoff assumption contradicted — flagged, not worked around. schema-parity.yml is a manual-dispatch Supabase prod↔staging schema-dump diff (pg_dump --schema-only both DBs, python diff, artefact upload). It has no ledger-facing parts at all; it must NOT be touched by ID-165. The ledger-schema CI concern the kickoff likely meant is task-view-vendor-drift.yml (which watches lib/validation/{task-list,initiatives,backlog}-schema.ts, doc-link.ts, work-status.ts). Those lib/validation ledger-schema modules are themselves retirement candidates — a follow-on sweep item the kickoff doesn’t list (verify no non-ledger imports before removal).

2.3 Skills, agents, hooks, config referencing the old stack (canonical)

Section titled “2.3 Skills, agents, hooks, config referencing the old stack (canonical)”

46 files reference ledger-cli; the live (non-historical) ones:

  • Skills: update-ledgers (SKILL.md 281 + references 311 lines — see §7), handoff (1 ref), start-session (6 refs), research, recall-grounding, triage-finding (+ its references), propagate-workflow-change (+ references/surface-map.md — itself a map of this surface; will need re-authoring, not just patching), audit-skill/scripts/detect-drift.sh.
  • Legacy dev-workflow tree (.dev-workflow/sdlc/.claude/ agents + skills — task-planner/executor/checker, workflow-orchestration, implement-subtask, workflow-curator, shared-discipline/planner-reporting references): quarantined surface from ID-164; references here are stale-by-design, lowest priority.
  • Hooks/config: .claude/hooks/mempal-recall.sh, .claude/hooks/ledger-compact-session-end.sh, .claude/settings.json (4 permission-allowlist lines, incl. the S492 ledger-cli read shapes — commit 3013f2d6), .prettierignore:66-70 (ledger fixtures — fixtures already deleted, entry vestigial), tsconfig.ci.json:6-12 (comment-only).
  • Docs/other: CLAUDE.md Ledgers section + Orchestration bullet (“Workers never write the ledger in-branch” — inverted by decision 8), AGENTS.md, lib/client-config.ts + its test (comment-level), docs/reports/jscpd-report/.
  • Live: runbooks/local-development.md (patch-server client-name guard §, worktree provisioning § — :161-198,704-706), runbooks/ci.md (quality-test row :69, §4.4 side-workflow list :196, header note :7), reference/platform-context.md (retro pointer via ledger-cli show retro :71), reference/decision-register.md (context table only), the docs-site’s own .claude/ skills (grep hit), plus workflow-evaluation/friction-register.md.
  • Historical (do not patch): point-in-time spec dirs (id-34, id-90, id-92, id-113, id-115, …), _archive/ runbooks, operator-command reports.
  • The task-view repo itself (github.com/liam-jons/task-view) becomes orphaned once vendor-drift + the server spawn path go — archival of that repo is an owner decision outside canonical’s tree (OQ-10).

3. Migration-source inventory and shape analysis

Section titled “3. Migration-source inventory and shape analysis”

Counts measured 23/07/2026 against the live ledgers (${KH_PRIVATE_DOCS_DIR}/src/content/docs/ledgers/):

SourceRecordsSplitMirrors
task-list.json (2.9 MB)154 tasksdone 132, cancelled 4 → archived (136); open 18: in_progress 11, pending 4, blocked 1, deferred 1, spec_needed 1tasks/ 154
product-backlog.json (256 KB)197 itemsready 59, spec_needed 60, needs_research 20, parked 55, blocked 3 → all status: backlogbacklog/ 197
initiatives.json (64 KB)10 initiativesexit ledger system (decision 7)initiatives/ 10
product-retros.json (688 KB)105 retrosexit ledger system (decision 7)retros/ 105
ledgers/archive/105 ID-N-journals.md, 3.2 MBalready-compacted done-task journals — the pre-migration snapshot must include these

Post-migration tasks/ dir ≈ 351 files (154 + 197), of which 136 archived and ~197 backlog — the board’s visible working set is ~18 open tasks. Subtask volume: 1,422 subtasks total (max 51 on one task). Journal volume for open tasks (journals live in subtask.detailsledger-cli.ts:79): ~686 KB across the 18 open tasks, heavily skewed: id-132 ≈ 212 KB/48 subtasks, id-127 ≈ 145 KB, id-128 ≈ 86 KB, id-71 ≈ 86 KB, id-147 ≈ 52 KB, id-163 ≈ 49 KB. A verbatim carry of the largest would produce a ~200 KB+ task file — see OQ-4 on compaction depth.

3.1 Field-fidelity mapping (task record → ordna file)

Section titled “3.1 Field-fidelity mapping (task record → ordna file)”
Ledger fieldOrdna homeFidelity notes
id (“165”)id: id-165 frontmatter + filenameCrosswalk trivial for tasks; bl-* renumber needs the id-crosswalk file (decision 5).
title, descriptiontitle: frontmatter; ## Goal (ordna’s description section, alias schema.ts:121-126)Clean.
statusstatus:Mapping required — see OQ-1. Proposed: pending→todo, in_progress→doing, done/cancelled→archived, blocked/deferred/spec_needed→todo + qualifier. Unmapped statuses would render the task invisible on the board (columns are config.statuses only).
priority (must/should/could)priority: after mappingLossy if unmapped: priority is a known key; normalizePriority silently coerces anything outside high/medium/low to null (parser.ts:41-44; enum schema.ts:144). See §5 I-1 / OQ-2.
dependencies ([“164”])depends_on: [id-164]Convert to full ids; gate then works via CLI move.
subtasks[] (id/title/description/details/status/testStrategy/dependencies)## Subtasks section, per-subtask ### {N.M} blocks with status markers + AC checkboxesPreserved verbatim as section content (§1 decision 6). Board-parsed AC lives only in ## Acceptance Criteria — decide the aggregation convention (OQ-6).
journal threads (in subtask.details)## Progress (compacted)Full history goes to the canonical-archive snapshot, not the migrated file (kickoff WP2). Compaction depth = OQ-4.
status_note, priority_note, owner, effort_estimate, capability_theme, session_refs, commit_refs, cross_doc_linksextra frontmatter (round-trips, §1)Suggest a kh_ prefix is NOT needed — only alias-named keys are normalised; these names collide with nothing (schema.ts:108-119). owner and assignee are distinct keys — no collision.
updatedAt (ISO datetime)updated_at: (YYYY-MM-DD)Day-granularity only; ordna bumps it on every write (storage/backends/file.ts:144). Preserve the original ISO value in extra frontmatter at migration if wanted (cheap).
— (no created date exists)created_at:Backfill policy = OQ-3.
backlog track, type, notesextra frontmatter / ## NotesClean.

Per-record mirrors (initiatives/ 10, retros/ 105) are the ratified starting material for the plain-markdown conversion — already one file per record with frontmatter. The conversion is mostly a relocation + frontmatter trim, not a rewrite. Target locations = OQ-7.


4. Draft .ordna/config.yaml (per decision 4)

Section titled “4. Draft .ordna/config.yaml (per decision 4)”

To live at ${KH_PRIVATE_DOCS_DIR}/.ordna/config.yaml:

# ID-165 — ordna ledger substrate (decision 4 of the 22/07/2026 ratification).
storage: file # direct agent file access is the point; hybrid is the
# drop-in upgrade if parallel-create id collisions bite
# (same on-disk layout — config.ts:14-18, README §hybrid)
schema: ordna
statuses: [backlog, todo, doing, done] # first = default for new items;
# last = dependency-gated terminal (store.ts:155)
idPrefix: id # id-165 — ids.ts:4-8
zeroPaddedIds: 0
# webPort: 7420 # default; uncomment to pin a different port

Defaults deliberately not restated (tasksDir: tasks, attachment cap 25 MB). The archived status needs no config entry — it is a reserved sentinel (storage/backend.ts:11). ORDNA_STORAGE=file can pin the mode in any CI that runs ordna commands (config.ts:84-87).


5. Issues found (resolve-first vs build-on calls)

Section titled “5. Issues found (resolve-first vs build-on calls)”
  • I-1 — Priority coercion is silently lossy. Canonical uses MoSCoW (must/should/could); ordna’s known priority key admits only high/medium/low and nulls anything else on parse (parser.ts:41-44). An unmapped migration would erase every priority. Resolve at migration (it is a mapping bug waiting to happen, not a foundation to build on): either map must→high / should→medium / could→low, or move MoSCoW to an extra-frontmatter key — owner call, OQ-2.
  • I-2 — Status sets do not overlap. Seven task statuses + five backlog statuses collapse into four columns + archived. Tasks whose status is not in config.statuses (and not archived) appear in no board column (columns derive 1:1 from config — AGENTS.md §3; web App.tsx:295). Resolve at migration with an explicit mapping table (OQ-1); qualifiers survive as tags or extra frontmatter.
  • I-3 — Every ordna CLI invocation is cwd-bound to the docs-site root (store.ts:64; no --cwd/-C flag exists in the CLI). Agents working in canonical worktrees must cd "$KH_PRIVATE_DOCS_DIR" && ordna … (or a one-line alias/wrapper — within decision 1’s “trivial wrapper” allowance; anything beyond that escalates). Build-on — a documented convention in the adapted AGENTS.md suffices; no code needed. Reads need no CLI at all (cat $KH_PRIVATE_DOCS_DIR/tasks/id-165.md).
  • I-4 — task-view-vendor-drift.yml is already broken (references the deleted scripts/task-view-drift-age.ts — §2.2). Resolve-first candidate: it can be retired in WP3 immediately, before cutover, since the thing it guards (vendored schema parity) is itself condemned. Same for the vestigial ci.yml task-view clone step (tests it served were deleted in 37042db1).
  • I-5 — The kickoff’s schema-parity assumption is wrong (§2.2). schema-parity.yml is Supabase-only and out of scope. Flagged so WP3 doesn’t touch it; the ledger-schema modules under lib/validation/ are the actual follow-on sweep item (import-check before removal — work-status.ts in particular may have non-ledger consumers).
  • I-6 — File-mode id collisions on parallel creates are real but accepted by decision 4 (README §file “watch out for”). The docs-site is a git repo, so hybrid is available the day it bites. Build-on (ratified).
  • I-7 — Board AC counter only reads ## Acceptance Criteria (§1 decision 6 row). Build-on, but the subtask template convention must decide where checkboxes live (OQ-6) or board AC progress will read 0/0 forever.

Constraints: id-163 is the only in-flight spec lane (id-164 closed); ledger writes otherwise occur at session boundaries (open-task/status flips, journal appends via sessions) and via the SessionEnd compaction hook. A “write-freeze” therefore only has to cover active sessions, not wall-clock days.

  • Option A — single-window big-bang (recommended). Between sessions: (1) disable the SessionEnd compaction hook + declare freeze; (2) snapshot all four JSONs + ledgers/archive/ + mirrors to canonical-archive (complete journal history lives there — kickoff WP2); (3) run the migration script; (4) fidelity checks — record counts (154/197/10/105), id-crosswalk completeness, owner-approved spot-diff sample; (5) land .ordna/config.yaml + tasks/ in one docs-site commit; (6) flip the reference surfaces (CLAUDE.md, skills) in the same wave. Freeze window ≈ one working session. id-163 interplay: its record migrates like any open task; its next session simply starts on tasks/id-163.md. Risk: biggest single wave — mitigated by the snapshot being restorable and the old stack remaining in git history.
  • Option B — two-stage (archive first). Stage 1 (no freeze needed): migrate the 136 done/cancelled + 105 retros + 10 initiatives — content that receives no writes — and verify fidelity mechanics on the safe 80 %. Stage 2 (short freeze): the 18 open tasks + 197 backlog items + reference flips. Lower per-wave risk, but the ledgers and tasks/ coexist for the interim with a split read surface — every agent needs “which system holds this record?” logic for the gap. Only worth it if Option A’s spot-diff fails on first attempt.
  • Option C — parallel-run / dual-write. Rejected. Recreates exactly the parity-maintenance burden (mirror regen, differential parity) this task retires.

Sequencing note either way: retire the two already-dead CI surfaces (I-4) and the .prettierignore fixture entry now; retire ledger-cli + server + lib/ledger/ only after cutover verification (WP5 smoke: create via CLI, worker file-edit in-branch, merge, board reflects, move gate fires, cat from a worktree), since the freeze window depends on the old CLI staying functional until the snapshot is taken.

7. WP4 recommendation — update-ledgers: retire, don’t rewrite

Section titled “7. WP4 recommendation — update-ledgers: retire, don’t rewrite”

Recommendation: retire the skill; fold the canonical conventions into the adapted ordna AGENTS.md (WP1) in the docs-site. Rationale:

  • The skill + references (592 lines total) are ~90 % CLI mechanics that cease to exist: budget gates, record-set delta gates, exit envelopes, size-shaped reads, promote atomicity, mirror regen (SKILL.md:38-42, references/cli-mechanics.md).
  • Every remaining verb maps to a one-liner ordna already documents: create → ordna create (backlog default per config), promote → ordna move <id> todo, status flip → ordna move, delete → file removal, read → cat/ordna show. The bundled AGENTS.md (packages/cli/templates/AGENTS.md) covers all of them.
  • What is genuinely canonical is thin and belongs in the layered agent guidance decision-4/WP1 already commissions: Coordinator-gated done, Progress-append discipline, initiative: key, extra-frontmatter field glossary, the cwd convention (I-3), and the triage-finding hand-off (create-with-provenance becomes ordna create … + frontmatter keys). triage-finding keeps routing to that guidance; a separate CRUD skill would just restate it (the drift pattern audit-skill exists to kill).
  • One open dependency: triage-finding’s Create-mode currently invokes update-ledgers by name — WP4 must repoint it, and propagate-workflow-change’s surface-map.md needs re-authoring rather than patching (§2.3).
  • DR-089 (S490): plan/decomposition surface is the Intent workspace spec-note — {N.4} PLAN.md retired. Ordna task files must not grow a competing plan surface; ## Subtasks mirrors Intent decomposition (decision 6 aligns).
  • DR-086b/DR-087: canonical is PUBLIC; docs-site PRIVATE + citable — the root constraint behind decisions 2/3.
  • DR-070 (closed-task guard): status-check cited ids; reopens explicit — under ordna this becomes “check frontmatter status before citing”, worth carrying into the adapted AGENTS.md.
  • DR-009/DR-003 (mempalace single-writer / lock-free recall) — unaffected, but mempal-recall.sh greps ledger surfaces and is on the reference-update list.
  • ID-164 (done, closed S491) delivered the Intent substrate this rides on; its WP5 folds here (task status_note, kickoff preamble). ID-163 in flight (§6).
  • Memory recall: session digests S490–S492 confirm the Intent adoption arc; palace search for the 22/07 ordna feasibility session itself is low-signal (session likely not yet mined) — the kickoff seed is treated as the authoritative record of that ratification, which is what it declares itself to be.
  • The docs-site’s own CI/buildtasks/ at repo root is outside Astro’s collections, but the docs-site also runs vitest/playwright/knip-style tooling from root config; the WP1 task should confirm none glob the new dir (and add it to ignores where needed).
  • lib/validation ledger schemas + work-status.ts — the un-listed second half of the vendor surface (§5 I-5); import-graph check before deletion.
  • Session tooling still writing at teardown — the SessionEnd compaction hook will fire during the freeze window unless disabled first (§6 step 1); handoff / start-session skills embed ledger-cli read shapes and will error post-cutover if flipped late in the wave order.
  • settings.json permission allowlist — stale ledger-cli entries are harmless but the absence of ordna/cat tasks/ shapes will cause permission-prompt friction in the first post-cutover session; pre-add them.
  • updated_at day-granularity silently degrades the “which record moved last” signal updatedAt ISO timestamps provided; if any tooling sorts by it, preserve the original in extra frontmatter (§3.1).
  • The board’s default ordna invocation opens the TUI — fine for humans; agents should be steered to list/show/cat (non-interactive) in the adapted AGENTS.md, since a TUI launch in a background shell hangs exactly like supabase db push (CLAUDE.md environment note).
  • canonical-archive snapshot completeness — must include ledgers/archive/ (3.2 MB compacted journals) and the per-record mirrors, not just the four JSONs, or “the complete journal history lives there” is untrue.

Ranked most-likely first:

  1. Convention-only gate discipline erodes — decision 8 moves done-gating and Progress-append discipline from enforced server gates to convention. A worker flipping status: done by file edit bypasses the dependency gate silently (store.ts gate is CLI-path-only). Mitigation: the adapted AGENTS.md states the Coordinator-owns-done rule bluntly; the WP5 smoke verifies the CLI path; periodic grep -l "status: done" review in PRs is cheap if it ever bites.
  2. Reference-surface stragglers — 46 canonical files + live runbooks reference the old stack; any missed live surface (a skill invoking bun scripts/ledger-cli.ts post-retirement) fails hard mid-session. Mitigation: WP3’s dangling-reference grep after each removal (propagate-workflow-change discipline) + re-authoring surface-map.md from this inventory.
  3. Status/priority mapping regret — if OQ-1/OQ-2 are decided hastily, the collapse of parked/needs_research/deferred into backlog/todo + tags loses triage signal the backlog curation flow relies on; re-widening statuses later is config-only but re-tagging 197 files is a chore. Decide the mapping with the curation workflow in view, not just board aesthetics.
  4. Parallel-create id collision (I-6) — two same-instant ordna create calls in different worktrees both allocate id-366. Detectable at merge; fix is the documented hybrid flip. Low likelihood at current create rates.
#QuestionResearch’s suggested default
OQ-1Status mapping: task pending→todo; blocked/deferred/spec_needed→todo + tags: [blocked]/[deferred]/[spec-needed]? Backlog qualifiers (ready/spec_needed/needs_research/parked/blocked) → tags on status: backlog items?Yes to both — tags keep the board at four columns and survive round-trips.
OQ-2Priority: map must→high/should→medium/could→low, or keep MoSCoW in extra frontmatter?Map, and additionally preserve the original as kh_priority: at migration only (belt-and-braces, zero ongoing cost).
OQ-3created_at backfill: git-derived first-mirror date, updatedAt, or migration date?Migration date for archived; earliest session_refs/git date for open tasks if cheap, else migration date. Low stakes.
OQ-4## Progress compaction depth for open tasks (686 KB total; id-132 alone 212 KB)Per-subtask one-to-three-line outcome summaries + pointer to the canonical-archive snapshot; verbatim carry only for the active lane (id-163).
OQ-5Where does the id-crosswalk file live?${KH_PRIVATE_DOCS_DIR}/tasks/ID-CROSSWALK.md is self-describing and greppable next to the ids it maps; .ordna/ also acceptable.
OQ-6AC convention: single board-parsed ## Acceptance Criteria aggregating subtask-level criteria, with per-subtask checklists under ## Subtasks?Yes — board AC = task-level definition of done; subtask checklists stay narrative content.
OQ-7Target homes for initiatives (10) + retros (105) as plain docssrc/content/docs/initiatives/ exists as mirror source already — promote in place and drop ledger frontmatter; retros likewise under retros/.
OQ-8Confirm WP4 recommendation (§7): retire update-ledgers; conventions live in the adapted AGENTS.mdRetire.
OQ-9Cutover Option A vs B (§6)A, with B as the fallback if the spot-diff sample fails.
OQ-10Archive the external task-view repo (github.com/liam-jons/task-view) once orphaned?Owner call — outside canonical’s tree; a repo-archive (read-only) preserves the tags CI history references.