KN-WORK-PATH-LIST-FREEZE.md markdown
475 lines 31.3 KB
Raw
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 11 days ago

frozen: true step: KN-WORK-PATH-LIST-a model: "Thinking (thinking-high)" date: 2026-08-18 branch: feat/kn-work-path-list-a status: thinking-freeze-2026-08-18 supersedes: "Freezes Knowtation learning-path persist + list/get so Scooling My Work can later show real Path rows and later Home→Work bind. Consumes Scooling F13 (current-state card overlay shipped; tip feat/ux-work-redirect-b) and the AGENT-WORK-CHAT-HOME-BIND park. Does not invent Live on Scooling My Work, Auto BRAIN-PAIR-b, put chat on Home, or replace the Home prompt. This freeze does not authorize KN-WORK-PATH-LIST-b Auto until freeze-review pass." evidence: "Scooling PRIMARY 2026-08-18 (ROADMAP F14; OVERSEER-HANDOVER NEXT Thinking KN-WORK-PATH-LIST-a). UX-WORK-REDIRECT-b BV r1 pass sha256:8c71d27d0e1ed5e0f61587cc4fa00c566cf872453a395eb10b44dd1075c20ee4. AGENT-WORK-CHAT park AGENT-WORK-CHAT-HOME-BIND in ~/scooling/docs/reviews/2026-08-14-agent-work-chat.md. Board freeze parked persist+list in ~/scooling/docs/reviews/2026-08-14-ux-work-board.md §3.1. Path drafts have no list or get today (createPrivateLearnerLoopDraft is one-shot)."

KN-WORK-PATH-LIST — Knowtation path persist + list/get

Ground truth for KN-WORK-PATH-LIST-b Auto. Downstream Auto may treat this document as ground truth without re-deriving. It does not edit Scooling, invent Live on Scooling My Work, put chat on Home, replace the Home prompt, start AGENT-WORK-CHAT-HOME-BIND, Auto BRAIN-PAIR-b, start KN-WORK-RUN-LIST, invent a conversation vault, flip PATH_WRITES_ENABLED to on, or admit path kinds to T5 self-apply.

phase: KN-WORK-PATH-LIST-a
outputs:
- id: kn-work-path-list
  path: docs/KN-WORK-PATH-LIST-FREEZE.md
  frozen: true
  notes: Dedicated learning_paths[] in hub_flow_store.json; list/get REST; Review-before-write persist gated default off. No Scooling harvest. No Home bind. No Live chip.
frozen_inputs:
- id: scooling-roadmap-f14
  path: ~/scooling/docs/ROADMAP.md
  notes: F14 owns this build; AGENT-WORK-CHAT-HOME-BIND stays parked until list/get exists
- id: scooling-handover-next
  path: ~/scooling/docs/OVERSEER-HANDOVER.md
  notes: PRIMARY Thinking KN-WORK-PATH-LIST-a; F13 current-state overlay shipped
- id: ux-work-redirect
  path: ~/scooling/docs/reviews/2026-08-18-ux-work-redirect.md
  notes: F13 freeze-review pass sha256:8c71d27d…; this-visit overlay; cold GET shows saved thread; T8 forbade path list/get in that tip
- id: ux-work-redirect-bv
  path: ~/scooling/docs/reviews/2026-08-18-ux-work-redirect-b-bv-round1-pass.md
  notes: F13b BV r1 pass; tip feat/ux-work-redirect-b; KN-WORK-PATH-LIST not started
- id: agent-work-chat
  path: ~/scooling/docs/reviews/2026-08-14-agent-work-chat.md
  notes: Parks AGENT-WORK-CHAT-HOME-BIND until KN-WORK-PATH-LIST; Path drafts have no list or get
- id: ux-work-board
  path: ~/scooling/docs/reviews/2026-08-14-ux-work-board.md
  notes: §3.1 Path drafts no list/get; parks KN-WORK-PATH-LIST persist+list; kinds Path·Run·Loop·Helper
- id: ux-work-live-rows
  path: ~/scooling/docs/reviews/2026-08-14-ux-work-live-rows.md
  notes: Session-bound Loop/Helper harvest pattern; samples fallback; Preview chip; no Path list
- id: launch-finish
  path: ~/scooling/docs/reviews/2026-08-18-launch-finish-assessment.md
  notes: KN-WORK-PATH-LIST unlocks real Path rows and Home→Work bind
- id: task-loop-store
  path: docs/TASK-LOOP-STORE-CONTRACT-2G-c.md
  notes: List/get + hub_flow_store.json vault-bucket pattern to copy; do not invent a second store file
- id: flow-store
  path: lib/flow/flow-store.mjs
  notes: getVaultFlowStore must default learning_paths to []
- id: flow-store-merge
  path: hub/bridge/external-agent-blob-store.mjs
  notes: mergeFlowStoreJson must union-merge learning_paths by path_id (CAPTURE-STORE-STALE-MERGE)
- id: task-loop-handlers
  path: lib/task/task-loop-handlers.mjs
  notes: Scope resolve + 404-not-leak list/get handler shape
- id: task-writes-gate
  path: lib/task/task-write.mjs
  notes: Env tri-state pattern only. getPathWritesEnabled lives in lib/path/path-write.mjs; do not edit this file.
- id: self-apply-kinds
  path: lib/hub-proposal-personal-self-apply.mjs
  notes: Path kinds stay off ADMITTED_* lists this Auto
- id: hosted-task-apply
  path: hub/gateway/task-approve-hosted.mjs
  notes: maybeApplyHostedTaskAfterApprove is the hook pattern to copy for paths
- id: learning-path-draft
  path: ~/scooling/src/adapters/types.ts
  notes: Scooling LearningPathDraft is title/summary/steps/runtimeDisclosure — not a store
- id: private-learner-loop
  path: ~/scooling/src/learnerLoop/privateLearnerLoop.ts
  notes: One-shot draft; no persist
- id: work-open-parser
  path: ~/scooling/src/work/workBoardSurface.ts
  notes: parseWorkOpenQuery accepts sample-path, sample-run, LOOP_ID_RE, DELEGATION_GRANT_ID_RE only — Scooling widens later
- id: work-copy
  path: ~/scooling/src/siteGuide/workCopy.ts
  notes: pathListHonesty is Path list is not ready.; pageStatus preview
- id: home-copy
  path: ~/scooling/src/siteGuide/homeCopy.ts
  notes: Home prompt stays What's on your mind? / Start a path
review_stamp:
  reviewed_at: '2026-08-18T17:20:17Z'
  verdict: pass
  reviewer_mode: agent
  reviewer_model: thinking-high
  reviewer_provider: local
  kit_version: 0.1.0
  artifact_digest: sha256:1354ed45531fc4dac329e989727deb9f9f4eb1ed17936a5d65c83b25cb8a1506
downstream:
- id: KN-WORK-PATH-LIST-b
  model: Auto
  consumes_as_ground_truth: true
  notes: Implement store + list/get + gated propose/apply. Starts only after freeze-review pass. Auto does not edit Scooling. Auto does not flip PATH_WRITES_ENABLED on. Auto does not Auto BRAIN-PAIR-b.
- id: AGENT-WORK-CHAT-HOME-BIND
  model: Thinking → Auto
  consumes_as_ground_truth: true
  notes: Later Scooling tip. Harvest Path rows + Home draft → work?open=path_…. Not this Knowtation tip.
- id: KN-WORK-RUN-LIST
  model: Thinking → Auto
  consumes_as_ground_truth: false
  notes: Parked. This freeze does not define run list/get.
tier3_gates:
- T1 Muse main or muse-mirror to GitHub main (SD-14) outside SD-21 land hygiene
- T2 Setting PATH_WRITES_ENABLED to an enabled literal in source or live env
- T3 Admitting path_create / path_update / path_archive to T5 personal self-apply
- T4 Flipping Scooling work pageStatus to live or inventing a Live chip
- T5 Home prompt replacement, a chat box on Home, or Home body work href (HOME-BIND)
- T6 BRAIN-PAIR-b pairing Auto
- T7 Any SCOOLING_STUDIO, SCOOLING_MEDIA, or SCOOLING_TASK_LOOP enabled assign
- T8 Feature to GitHub main / non-muse-mirror head

Auto must not build until freeze review pass. This Thinking tip does not implement routes. This Thinking tip does not flip any env.

Review record

Round Reviewer Verdict Resolution
0 Thinking (this session) draft Freeze authored from Scooling F14 + F13 BV pass + AGENT-WORK-CHAT-HOME-BIND park + task-loop list/get + flow-store merge
1 Freeze-review loop (thinking) findings R1-F1–F5 fixed below. CLI dry-run was already pass.
2 Freeze-review loop (thinking) findings R2-F1 fixed below.
3 Freeze-review loop (thinking) + ok review --freeze pass R1–R2 hold. Stale D3 frozen_input note aligned. CLI C checklist clean. Cleared for KN-WORK-PATH-LIST-b Auto. Auto must not edit Scooling, flip PATH_WRITES_ENABLED, or Auto BRAIN-PAIR-b. No human escalation.

Round 1 findings (cited — file+line)

ID Sev Cat Citation Finding Fix
R1-F1 MAJOR completeness docs/KN-WORK-PATH-LIST-FREEZE.md:300 (prior “existing approve path”) Self-hosted apply named a function but not the insert site. Auto could miss hub/server.mjs approve. §4.4 now locks the path branch next to reconcileApprovedTaskProposal on POST api/v1/proposals/:id/approve.
R1-F2 MAJOR completeness docs/KN-WORK-PATH-LIST-FREEZE.md:278 (prior path_update) Update index vs existing/replaced steps unbound. Auto could write current_step_index >= step_count. path_update now validates index against patched or existing steps; else PATH_STEP_INDEX_INVALID.
R1-F3 MAJOR consistency docs/KN-WORK-PATH-LIST-FREEZE.md:175 (prior D3) D3 said copy the tri-state “in lib/task/task-write.mjs”. Auto could edit task writes. D3: getPathWritesEnabled in lib/path/path-write.mjs only.
R1-F4 MINOR completeness docs/KN-WORK-PATH-LIST-FREEZE.md:199 (prior steps) source_document_ids omit vs required unbound. Omit or empty → [].
R1-F5 MINOR completeness docs/KN-WORK-PATH-LIST-FREEZE.md:175 (prior D2/D3) Concurrent update / base_state_id unbound. Auto could invent task lineage 409. D12 last-updated wins; no base_state_id.

Round 2 findings (cited — file+line)

ID Sev Cat Citation Finding Fix
R2-F1 MAJOR completeness hub/server.mjs:3264-3305; docs/KN-WORK-PATH-LIST-FREEZE.md:306 (prior review_queue-only) Self-hosted approve dispatches on proposal.source (TASK_PROPOSAL_SOURCE), not review_queue. Auto using only review_queue would never precheck/reconcile. PATH_PROPOSAL_SOURCE = "learning_path"; precheck before writeNote; reconcile after; hosted hook uses the same source.

Citation discipline

Every freeze-review finding MUST cite file+line (OVERSEER-KIT-SPEC §6). Do not trust uncited review output. HTTP routes in this doc omit the leading slash (api/v1/…) so the freeze mechanical gate does not treat them as absolute machine paths. Cross-repo paths use ~/scooling/…. Never leading-slash absolute paths.


0. Job (lock)

Knowtation becomes the filing cabinet for learning paths. A signed-in learner can later see real Path rows on Scooling My Work because Knowtation can list and get those paths. A later Home→Work bind can open one by id. Scooling stays Preview. Home stays the one-shot start. Chat stays on My Work.

In one sentence: persist structured paths in Knowtation, then list and get them, so Scooling does not have to invent a second ledger.


1. What is already true (do not re-derive)

Fact Where
Path drafts are one-shot createPrivateLearnerLoopDraft in ~/scooling/src/learnerLoop/privateLearnerLoop.ts — no list, no get
Draft shape learningPathDraftSchema in ~/scooling/src/adapters/types.tstitle, summary, steps[], runtimeDisclosure
Goal cap on Scooling validateLearningGoal max 180 in ~/scooling/src/learnerLoop/prompt.ts
My Work kinds Path · Run · Loop · Helper only (WORK_COPY.kinds)
Path rows today Sample Path Algebra through music only (?open=sample-path)
Loop/Helper harvest Session-bound; samples fallback; Preview chip (~/scooling/docs/reviews/2026-08-14-ux-work-live-rows.md)
open parser sample-path, sample-run, LOOP_ID_RE, DELEGATION_GRANT_ID_RE only (~/scooling/src/work/workBoardSurface.ts)
F13 card overlay This-visit reviewReady / sentToReview + last learner turn; Who's helping stays harvest; cold GET shows the saved thread
Home prompt What's on your mind? / Start a path — cold-start only
HOME-BIND park Carrying a Home draft onto a My Work thread waits for this list/get (~/scooling/docs/reviews/2026-08-14-agent-work-chat.md)
Path-list honesty Path list is not ready. (WORK_COPY.pathListHonesty)
Durable notes Review → Knowtation. Scooling is not a second library
Structured list/get pattern Task loops in hub_flow_store.json + GET api/v1/task-loops + GET api/v1/task-loops/:loop_id
Blob merge lesson mergeFlowStoreJson must union-merge new arrays by id or a warm lambda masks blob rows

Do not scan vault notes and call them Path rows. Review-approved markdown stays a note. The path record is a separate structured object that may point at a note.


2. Decisions (lock — do not reopen in Auto)

ID Decision Recorded default
D1 Store Dedicated learning_paths[] on the same hub_flow_store.json vault bucket as tasks / task_loops. No second JSON file. No note-search list.
D2 Id path_<token> with PATH_ID_RE ^path_[a-z0-9_]{1,48}$. Distinct from loop_, dgrnt_, run_, sample-path. Server mints on create as path_ plus 16 lowercase hex from crypto.randomBytes(8). Retry mint if that id already exists in the vault. Client cannot supply path_id on path_create.
D3 Reads vs writes List/get always authorized (JWT + vault + scope). Writes Review-before-write, gated PATH_WRITES_ENABLED default off. Implement getPathWritesEnabled in lib/path/path-write.mjs using the same env tri-state helper tasks use (1/true on, unset/false off). Do not edit lib/task/task-write.mjs. No path policy file.
D4 T5 Path kinds are not admitted to personal self-apply this Auto. Human approve → apply-approved hook. No scooling.path: fingerprint admit.
D5 Who's helping Not stored on the path record. F13 lock: Who's helping stays harvest. Get does not invent helper grants.
D6 Transcript Not stored. Turns stay Scooling request-carried this-visit. Path record is structured work state only.
D7 Seed No production starter fixture. Tests seed via store upsert. Empty list is honest.
D8 MCP / CLI / Hub chrome Parked. Hub REST + shared handlers only.
D9 Scooling harvest / HOME-BIND Parked. This Auto does not edit ~/scooling/. Consumer DTO in §8 is the later contract edge.
D10 Scope / workspace on create Default scope=personal, workspace_id=ws-personal (existing Scooling personal id). Project/org require matching visible scope else PATH_SCOPE_DENIED. v0 cannot change scope or workspace after create (PATH_SCOPE_IMMUTABLE).
D11 Archived List default omits archived. Get of an authorized archived path still returns the record. Archive does not delete the row or any vault note.
D12 Concurrency v0 last-updated wins on the same path_id. No base_state_id / lineage 409 this Auto.

3. Canonical record — knowtation.learning_path/v0

Field Type Req Rule
schema const yes knowtation.learning_path/v0
path_id string yes PATH_ID_RE
scope enum yes personal | project | org
status enum yes active | paused | archived
title string yes Untrusted display; trim; min 1; max 200
summary string yes Untrusted; trim; min 1; max 2000
goal string yes Untrusted learning goal; trim; min 1; max 180 (Scooling validateLearningGoal cap)
steps array yes Min 1, max 20. Each step: title (1–240), objective (1–240), source_document_ids string[] (omit or empty → []; max 16 items, each ^[A-Za-z0-9._:-]{1,128}$)
current_step_index int yes >= 0 and < steps.length. Default 0 on create
step_count int yes Server-derived steps.length. Never client-trusted as the only source
next_step_title string yes Server-derived steps[current_step_index].title
active_decisions string yes Untrusted; max 240; empty string allowed (Scooling later shows No decisions waiting.)
workspace_id string yes WORKSPACE_ID_RE ^[A-Za-z0-9._:-]{1,64}$. Create default ws-personal
note_path string | null yes Optional vault-relative note pointer. Null when absent. See §3.1
created / updated ISO8601 yes Server clock

runtimeDisclosure from the Scooling draft is not stored. It is mock-loop honesty, not path state.

3.1 note_path (optional pointer)

When present, note_path MUST be a vault-relative path:

  • no leading /, no ~, no \, no ://, no .. segment, no drive letter
  • max 256 chars
  • matches ^[A-Za-z0-9._/-]+\.md$

Invalid → 400 PATH_NOTE_PATH_INVALID. Path routes never call writeNote. They do not create, edit, or delete the note. Archive keeps the note.

3.2 Client projections

List summary (learningPathSummaryForClient) — no steps, no summary, no note_path:

schema, path_id, scope, status, title, goal, current_step_index, step_count, next_step_title, active_decisions, workspace_id, updated

Get (learningPathForClient) — full knowtation.learning_path/v0 including steps and note_path.

List response:

schema: knowtation.learning_path_list/v0
vault_id
effective_scope
paths: summary[]
truncated: boolean

Sort: updated descending, then path_id ascending (stable). Cap MAX_LEARNING_PATH_SUMMARIES = 200. limit query if present must be an integer 1–200; invalid → treat as 200.


4. Routes (lock)

Mount on self-hosted Hub, hosted bridge, and gateway proxy. Shared handlers in lib/path/path-handlers.mjs. Store in lib/path/path-store.mjs. Writes in lib/path/path-write.mjs.

Method Route Role Gate
GET api/v1/learning-paths viewer, editor, admin, evaluator JWT + vault. No write gate
GET api/v1/learning-paths/:path_id viewer, editor, admin, evaluator JWT + vault. No write gate
POST api/v1/learning-paths/proposals viewer, editor, admin, evaluator JWT + vault + PATH_WRITES_ENABLED. Propose only — apply stays after approve
POST api/v1/learning-paths/proposals/:proposal_id/apply-approved editor, admin (hosted bridge; session-bound like task apply-approved) JWT + vault + PATH_WRITES_ENABLED. Called by the approve hook, not by Scooling

Do not add route("work/:id") anywhere. Do not add Scooling routes.

4.1 List query

Reuse task-loop scope resolve (resolveHandlerVisibleScopes + resolveFlowScopeQuery from lib/flow/flow-scope.mjs / lib/flow/flow-handlers.mjs). Ambiguous scope → 400 PATH_SCOPE_AMBIGUOUS. Unauthorized requested scope403 PATH_SCOPE_DENIED.

Query Rule
scope optional personal | project | org
workspace_id optional; must match WORKSPACE_ID_RE or 400 BAD_REQUEST
status optional active | paused | archived. If omitted, return active and paused only
limit optional integer 1–200

No q= search. No client-supplied uid, vault field, or Bearer as a query.

4.2 Get

path_id that fails PATH_ID_RE, is missing, or is outside visible scope → 404 { code: "PATH_NOT_FOUND" }. Same code for all three. Do not distinguish "exists but not yours."

4.3 Propose body

proposal_kind closed allowlist: path_create | path_update | path_archive. Missing kind on POST defaults to path_create. Any other value → 400 BAD_REQUEST. No store write.

path_create

  • Fields: title, summary, goal, steps (required); current_step_index, active_decisions, scope, workspace_id, note_path, external_ref (optional)
  • Server mints path_id
  • Client path_id present → 400 PATH_ID_NOT_ALLOWED
  • Default scope personal, workspace ws-personal, current_step_index 0, active_decisions "", note_path null, status active
  • external_ref if present MUST match ^scooling\.path:[A-Za-z0-9._:-]{1,200}$ else 400 PATH_EXTERNAL_REF_INVALID. Persist when valid. Absence is allowed. Do not treat a valid ref as T5 admission.

path_update

  • path_id required (body). Must exist in scope or 404 PATH_NOT_FOUND (no leak)
  • Allowed patches: title, summary, goal, steps, current_step_index, active_decisions, status (active | paused only), note_path
  • scope or workspace_id in the body → 400 PATH_SCOPE_IMMUTABLE
  • status=archived on update → 400 BAD_REQUEST (use path_archive)
  • If steps is patched, re-derive step_count and next_step_title. If current_step_index is omitted, keep the existing index when it still fits; if it no longer fits → 400 PATH_STEP_INDEX_INVALID
  • If current_step_index is patched without steps, validate against the existing record's steps

path_archive

  • path_id required. Sets status=archived. Idempotent if already archived. Does not delete the row or the note.

Gate off → 403 PATH_WRITES_DISABLED. No proposal row. No store write. No canister create.

Propose roles: viewer, editor, admin, evaluator — same closed set as TASK_WRITE_ROLES in hub/server.mjs (viewer may propose; apply still waits for approve). Unauthenticated → 401.

Proposal path: meta/learning-paths/proposals/{proposal_id}.json (never pending). review_queue: learning-path. source: learning_path (PATH_PROPOSAL_SOURCE, copy TASK_PROPOSAL_SOURCE = "task"). Reuse existing createProposal / createProposalWithSession (session_bound from isSessionBoundActor). Do not invent a second proposal store or a new canister schema.

title, summary, goal, step title / objective, and active_decisions must contain no U+0000U+001F control characters after trim → else 400 PATH_TEXT_INVALID.

current_step_index missing steps or current_step_index >= steps.length or < 0400 PATH_STEP_INDEX_INVALID.

4.4 Apply

Self-hosted: hub/server.mjs POST api/v1/proposals/:id/approve already prechecks when proposal.source === TASK_PROPOSAL_SOURCE then reconciles after writeNote. Auto adds a path pair next to that task pair: if proposal.source === PATH_PROPOSAL_SOURCE (learning_path), run precheckApprovedPathProposal before writeNote (refuse the approve on precheck fail, same as tasks) and reconcileApprovedPathProposal after. Non-path proposals skip the path branch. Do not fold path apply into reconcileApprovedTaskProposal. Hosted classify uses the same source plus review_queue === "learning-path" and the §4.3 kind allowlist.

Hosted: maybeApplyHostedPathAfterApprove in hub/gateway/path-approve-hosted.mjs, wired next to the existing task/capture/media hooks in hub/gateway/server.mjs. The hook returns null unless the fetched proposal is a path proposal (review_queue === "learning-path" and proposal_kind in the §4.3 allowlist). It must not steal task / capture / media apply. On match it POSTs api/v1/learning-paths/proposals/:proposal_id/apply-approved on the bridge (copy maybeApplyHostedTaskAfterApprove). Bridge create + apply live in lib/path/path-hosted-proposal.mjs. Mutating bridge routes wrap withExternalProtocolBlobSync (same hub_flow_store.json file — do not add a new blob filename).

Apply when PATH_WRITES_ENABLED is off → 403 PATH_WRITES_DISABLED and no store write (including leftover proposals).

mergeFlowStoreJson in hub/bridge/external-agent-blob-store.mjs MUST add:

learning_paths: mergeById(localVault.learning_paths, blobVaultObj.learning_paths, 'path_id')

getVaultFlowStore MUST default missing learning_paths to [] (same as task_loops).

Do not "fix" orchestrator_graphs merge in this Auto.


5. Fail-closed rules

  1. No JWT → 401. No vault access → 403. Do not leak whether a path_id exists.
  2. Out-of-scope or unknown get → 404 PATH_NOT_FOUND.
  3. Write gate off → 403 PATH_WRITES_DISABLED on propose and apply-approved; zero store I/O beyond the gate read.
  4. Client-supplied path_id on create → 400. Client-supplied uid / vault / Bearer as a body field → ignore; never persist.
  5. Injection in title / summary / goal / step strings / active_decisions is stored as untrusted text only. No HTML render. No eval. No query concatenation.
  6. note_path traversal / absolute / URL → 400. Path routes never writeNote.
  7. source_document_ids are stored; list/get do not fetch those notes.
  8. Path kinds stay off ADMITTED_TASK_PROPOSAL_KINDS / flow / media allowlists. T5 path fingerprint → SELF_APPLY_NOT_ADMITTED (or the existing seam refuse). Do not add a path admit function.
  9. JSON.stringify of request, proposal, store row, and response MUST contain no tokens, cookies, Bearer, refresh material, or provider secrets.
  10. Do not print adapter mode, env names, or raw session material on any path response.
  11. Archive is not a delete. There is no path_delete kind this Auto.
  12. Empty list is paths: [], truncated: false — never a 500 and never a fabricated sample path.

6. What Auto must not change

  • Any path under ~/scooling/
  • Home prompt, Home body work-href lock, My Work Preview chip
  • F13 resolveWorkVisitCurrentState / this-visit overlay
  • Task / flow / media / docs-sync / delegation routes and gates
  • TASK_WRITES_ENABLED, FLOW_*, MEDIA_*, DOCS_OAUTH_*, SCOOLING_*
  • LOOP_ID_RE, DELEGATION_GRANT_ID_RE
  • Conversation vault, session-cookie transcript, localStorage turns
  • BRAIN-PAIR-b, presence, pairing, MuseHub F7, Parentier.org
  • Hub wizard chrome / MCP / CLI path commands
  • Production starter seed that would show as a learner Path

7. Test matrix (seven-tier) — KN-WORK-PATH-LIST-b consumes this

New files test/path-list-*.test.mjs (unit, integration, e2e, stress, data-integrity, performance, security). Command: node --test test/path-list-*.test.mjs.

Tier File Must prove
unit test/path-list-unit.test.mjs PATH_ID_RE; mint is path_ + 16 hex; reject client path_id; field caps; control-char PATH_TEXT_INVALID; PATH_STEP_INDEX_INVALID; note_path reject ../ and https://; default list omits archived; get returns archived; next_step_title / step_count derived; PATH_SCOPE_IMMUTABLE; unknown kind 400
integration test/path-list-integration.test.mjs upsert → list → get; scope deny; workspace filter; gate off propose 403 and store unchanged; gate on create propose then apply → get; update then archive; empty vault lists []
e2e test/path-list-e2e.test.mjs Hub/bridge/gateway walkthrough with fakes: GET list/get; POST propose; approve apply writes one path; blob hydrate then get; no Scooling file import
stress test/path-list-stress.test.mjs 200+ rows truncate; concurrent upsert same path_id last-updated wins; 20-step cap
data-integrity test/path-list-data-integrity.test.mjs mergeFlowStoreJson union by path_id (stale local must not mask blob); apply twice idempotent; archive keeps the row and does not delete note_path; restart load
performance test/path-list-performance.test.mjs List 200 + get 1 within local budget; no unbounded note scan
security test/path-list-security.test.mjs No token/Bearer in JSON; get unknown vs out-of-scope both 404 PATH_NOT_FOUND; create with foreign path_id rejected; note_path traversal 400; write gate off → no store write, no canister create, apply-approved also 403; path kinds not in T5 admit lists; external_ref malformed 400; no writeNote from path modules; hook returns null for task/capture/media proposals

Security tier MUST fail against a pre-fix stub that (a) returns 403 for out-of-scope get while 404 for missing, or (b) writes the store when PATH_WRITES_ENABLED is unset, or (c) includes a Bearer in the list JSON.


8. Later Scooling consumer (not this Auto)

Frozen so HOME-BIND / Path-row harvest does not re-derive the Hub shape. Do not implement in KN-WORK-PATH-LIST-b.

Later need Contract
Open id Scooling widens parseWorkOpenQuery to accept PATH_ID_RE in a later tip. Sample-path still always resolves.
Harvest row LivePathRow: openQuery (the Hub path_id after PATH_ID_RE), title, scope, status (active | paused), goal, currentStepIndex, stepCount, nextStepTitle, activeDecisions. Omit archived. Cap 8 is Scooling-side.
Saved thread (cold GET) Goal = goal; Active decisions = active_decisions or No decisions waiting.; Next step = next_step_title; Who's helping = existing harvest. F13 overlay still this-visit only and does not write the path.
Samples fallback Unchanged F1 rule: auth off / signed out / empty harvest → two samples. Never mix samples and live Path rows. Preview chip stays.
HOME-BIND After a path_create apply, open work?open=<path_id>. Home prompt stays What's on your mind? / Start a path. No chat box on Home.
Honesty Later Scooling tip may replace Path list is not ready. — not this Auto.

9. Auto file allowlist (KN-WORK-PATH-LIST-b)

Path Why
lib/path/** store, handlers, write, hosted proposal
hub/gateway/path-approve-hosted.mjs maybeApplyHostedPathAfterApprove
hub/gateway/server.mjs Proxy GET/POST prefixes + wire the approve hook
hub/bridge/path-routes.mjs Bridge list/get/propose + blob wrap
hub/bridge/server.mjs Register path routes
hub/bridge/external-agent-blob-store.mjs learning_paths mergeById only
lib/flow/flow-store.mjs Default learning_paths: []
lib/hub-proposal-personal-self-apply.mjs Refuse path kinds (no admit)
hub/server.mjs Self-hosted mounts
docs/HUB-API.md Honesty — new routes + gate default off
docs/openapi.yaml Route shapes
docs/PROPOSAL-LIFECYCLE.md learning-path queue note; T5 not admitted
docs/ROADMAP.md Status
docs/OVERSEER-HANDOVER.md NEXT
test/path-list-*.test.mjs Seven-tier
.env.example PATH_WRITES_ENABLED name only, if that file exists on the tip

Forbidden in this Auto

  • Any path under ~/scooling/
  • PATH_WRITES_ENABLED assigned enabled in source
  • T5 path fingerprint / admit
  • writeNote from lib/path/**
  • New blob filename
  • MCP / CLI / Hub wizard
  • orchestrator_graphs merge rewrite
  • BRAIN-PAIR / presence / Live chip / Home chat
  • KN-WORK-RUN-LIST

10. Out of scope

  • AGENT-WORK-CHAT-HOME-BIND (Scooling)
  • Scooling Path-row harvest / parseWorkOpenQuery widen
  • KN-WORK-RUN-LIST / getRun / live Run rows
  • Live model or agent runtime on My Work
  • Chat on Home / Home prompt replacement
  • BRAIN-PAIR-b (device not ready)
  • SOCIAL-OPEN-RANGE / Live threads
  • MuseHub F7
  • Conversation vault / cookie / localStorage transcript
  • Backfill of already-approved Review notes into learning_paths[]
  • Path delete / hard purge
  • Project/org harvest on Scooling (store supports the scopes; consumer stays personal later)

11. Definition of Done (KN-WORK-PATH-LIST-b)

  • [ ] Freeze-review pass before Auto starts
  • [ ] D1–D12 + §3–§5 implemented; PATH_WRITES_ENABLED default off
  • [ ] Seven-tier test/path-list-*.test.mjs green locally
  • [ ] Build verification pass before ROADMAP → DONE
  • [ ] No Scooling file edits
  • [ ] No secrets committed
  • [ ] Both governance docs updated together
  • [ ] Feature-branch hygiene; merge remains Tier 3 (or SD-21 land with no live flip)

12. Simple summary / technical summary

Simple: Knowtation will keep a real list of learning paths — the things you start from “what's on your mind?” — so My Work can later show your actual paths instead of only the sample. Starting a path on Home still does not jump to My Work in this step. Chat stays on My Work. Nothing is marked Live.

Technical: Add knowtation.learning_path/v0 rows in hub_flow_store.json learning_paths[]. Ship GET api/v1/learning-paths, GET api/v1/learning-paths/:path_id, and gated POST api/v1/learning-paths/proposals (path_create | path_update | path_archive). Hosted apply copies the task approve hook. Blob merge unions by path_id. T5 stays refused. Scooling harvest and HOME-BIND stay later tips.

Recommendation: Freeze this, pass review, then Auto KN-WORK-PATH-LIST-b on Knowtation only. Do not start Scooling harvest or Home bind until the seven-tier list/get is green and BV passes. Do not Auto pairing.

File History 1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 11 days ago