@davidorex/pi-context 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +12 -11
  3. package/dist/block-api.d.ts.map +1 -1
  4. package/dist/block-api.js +27 -2
  5. package/dist/block-api.js.map +1 -1
  6. package/dist/context-sdk.d.ts +71 -33
  7. package/dist/context-sdk.d.ts.map +1 -1
  8. package/dist/context-sdk.js +547 -149
  9. package/dist/context-sdk.js.map +1 -1
  10. package/dist/context.d.ts +153 -2
  11. package/dist/context.d.ts.map +1 -1
  12. package/dist/context.js +75 -5
  13. package/dist/context.js.map +1 -1
  14. package/dist/index.d.ts +71 -19
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +405 -94
  17. package/dist/index.js.map +1 -1
  18. package/dist/lens-view.d.ts +0 -5
  19. package/dist/lens-view.d.ts.map +1 -1
  20. package/dist/lens-view.js +43 -1
  21. package/dist/lens-view.js.map +1 -1
  22. package/dist/migration-registry-loader.d.ts +20 -12
  23. package/dist/migration-registry-loader.d.ts.map +1 -1
  24. package/dist/migration-registry-loader.js +46 -17
  25. package/dist/migration-registry-loader.js.map +1 -1
  26. package/dist/migrations-store.d.ts +45 -18
  27. package/dist/migrations-store.d.ts.map +1 -1
  28. package/dist/migrations-store.js +56 -22
  29. package/dist/migrations-store.js.map +1 -1
  30. package/dist/ops-registry.d.ts.map +1 -1
  31. package/dist/ops-registry.js +91 -118
  32. package/dist/ops-registry.js.map +1 -1
  33. package/dist/promote-item.d.ts.map +1 -1
  34. package/dist/promote-item.js +41 -12
  35. package/dist/promote-item.js.map +1 -1
  36. package/dist/roadmap-plan.d.ts +121 -99
  37. package/dist/roadmap-plan.d.ts.map +1 -1
  38. package/dist/roadmap-plan.js +281 -345
  39. package/dist/roadmap-plan.js.map +1 -1
  40. package/dist/status-vocab.d.ts +12 -2
  41. package/dist/status-vocab.d.ts.map +1 -1
  42. package/dist/status-vocab.js +14 -1
  43. package/dist/status-vocab.js.map +1 -1
  44. package/package.json +1 -1
  45. package/samples/blocks/milestone.json +3 -0
  46. package/samples/blocks/session-notes.json +1 -0
  47. package/samples/conception.json +308 -15
  48. package/samples/migrations.json +8 -0
  49. package/samples/schemas/context-contracts.schema.json +4 -0
  50. package/samples/schemas/conventions.schema.json +4 -0
  51. package/samples/schemas/decisions.schema.json +4 -0
  52. package/samples/schemas/features.schema.json +4 -0
  53. package/samples/schemas/framework-gaps.schema.json +4 -0
  54. package/samples/schemas/issues.schema.json +28 -0
  55. package/samples/schemas/layer-plans.schema.json +4 -0
  56. package/samples/schemas/milestone.schema.json +79 -0
  57. package/samples/schemas/phase.schema.json +4 -0
  58. package/samples/schemas/rationale.schema.json +4 -0
  59. package/samples/schemas/requirements.schema.json +4 -0
  60. package/samples/schemas/research.schema.json +4 -0
  61. package/samples/schemas/session-notes.schema.json +89 -0
  62. package/samples/schemas/spec-reviews.schema.json +4 -0
  63. package/samples/schemas/story.schema.json +8 -0
  64. package/samples/schemas/tasks.schema.json +4 -0
  65. package/samples/schemas/verification.schema.json +4 -0
  66. package/samples/schemas/work-orders.schema.json +4 -0
  67. package/schemas/config.schema.json +77 -3
  68. package/schemas/migrations.schema.json +25 -0
  69. package/skill-narrative.md +7 -5
  70. package/skills/pi-context/SKILL.md +44 -49
  71. package/skills/pi-context/references/bundled-resources.md +5 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,64 @@ All notable changes to this package are documented here. Format follows [Keep a
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.32.0] - 2026-07-05
8
+
9
+ - Ceremony-entry identity establishment: the substrate-lifecycle ceremonies that reach identity-stamping writes — `update` (live runs), `install`, and `resolve-blocked` — establish substrate identity at entry when `config.json` carries no `substrate_id`: one is minted (the same mint init uses), persisted through the sanctioned config write, and registered in the project registry before the ceremony's first stamping write, and the ceremony result reports it under `substrateIdEstablished`. A pre-identity substrate thereby heals on the sanctioned ceremony instead of refusing its populated-block version bump (the former mislabeled refusal), dry and live update runs agree on the outcome, and the two previously-skipped migrate-path tests are re-greened. An established identity is never re-minted (the on-disk id stays immutable), `--dryRun` establishes nothing (a preview performs no stamping write), and the block writer's own identity guard stays load-bearing for any write reaching it without identity.
10
+ - The rendered blocked report's trailing fix-items-then-resolve-blocked guidance renders only when at least one blocked entry actually persists a pending record (`validation-failed` / `no-migration-chain`); a report whose entries are all `write-failed` ends with the per-entry precondition guidance instead of a contradictory instruction to correct items that were never flagged invalid.
11
+ - Blocked-resync refusals are classified by cause: only an AJV validation failure reports reason `validation-failed`; any other throw at the resync write boundary (e.g. a substrate with no established `substrate_id` hitting the mandatory identity stamp, at either the same-version or version-bump arm) reports the new reason `write-failed` with the thrown message carried in the failures entry. A `write-failed` refusal inscribes no failure markers into the block file and persists no pending-blocked record — those consequences now fire only for genuine item-validation failures — and the rendered blocked report tells the operator the items were not flagged invalid instead of directing item fixes. `resolve-blocked`'s commit is now all-or-nothing: a throw partway through the commit restores every touched file byte-exact (migrations.json, the installed schema, the block file, config.json, the pending record) and reports the failure, where previously it could strand a partially-committed state (schema advanced, markers stripped, block unwritten, pending entry stale).
12
+ - `update`'s result makes per-component partial application legible in one place: an optional `partialApplication` field is populated exactly when the run both refused something (`blocked`, `refused`, or `conflicts` non-empty) and applied something (`resynced`, `migrated`, `merged`, `migrationsRegistered`, or any `registryAdditions` array non-empty) — carrying `applied`/`notApplied` mirrors of those channels plus a one-line summary naming what was applied alongside what was refused and why — so a run that blocks a schema while the additive registry propagation (or another schema's resync) lands no longer reads as a no-op. Computed for live and `--dryRun` runs (the preview reports the predicted partiality and declares itself a preview); a fully-clean or fully-refused run carries no field.
13
+ - The foreign-substrate config read feeding the relation porcelain's id index prefers the migration-aware loader over its prior raw parse, so a lagging-but-chained foreign config is read in its migrated shape — no reader of `config.json` sees a different shape than `loadConfig` where a chain resolves. Best-effort in two tiers: when the migration-aware load fails (unresolvable version, invalid), the raw parse is the fallback so the prefix invariant stays fed (a mis-filed foreign id keeps degrading to dangling rather than resolving); absent or unparsable still returns null.
14
+ - The composed `context-validate` verdict now covers block schema validity: a substrate-wide sweep validates every block that has both an installed schema and a block file against that schema — migration-aware when the envelope carries `schema_version` (a lagging version walks the registered chain; an unresolvable one surfaces), raw otherwise — and every failure lands as an ERROR naming the block, the failing item id, and the field/keyword (`block_schema_invalid`). Invalidity introduced without a write to the block (a schema resync, a hand edit) is no longer invisible behind a clean verdict. Pointer-less projects skip the sweep gracefully.
15
+ - `update`'s same-version resync arm re-validates populated blocks against the incoming catalog body BEFORE overwriting, and refuses on failure — the schema is reported `blocked` with per-item failures (reason `validation-failed`), the pending-blocked record and in-file failure markers follow the same flow as a version-bump refusal, and `--dryRun` predicts the same outcome. A same-version catalog change that narrows validity (a dropped property, an added required, a narrowed enum) can no longer silently invalidate existing items; compatible same-version changes still resync verbatim.
16
+ - The catalog story schema declares an optional `user_kind` on story items (the "As a `<user_kind>`" subject of the story statement), matching the field live stories carry.
17
+ - The bundled config schema is gated expand-contract at build time: `scripts/check-config-schema.ts` (pre-commit + CI, staged and `--base` modes diffing against the prior git revision) fails a non-additive `config.schema.json` change — a removed or renamed property key anywhere in the properties tree, or a new `required` entry on a pre-existing object — unless the same change set advances the schema `version` AND declares a packaged `config` migration reaching that version in `samples/migrations.json`. Additive changes (new optional fields, description/enum additions) pass untouched; a newly-added optional object's own initial requireds are additive by construction. New config fields land optional; removals/renames wait for a contract release paired with a migration.
18
+ - Envelope `schema_version` is live end-to-end: every block schema in the packaged catalog (`samples/schemas/`, 17 files; session-notes already declared it) admits an optional top-level `schema_version`, and `writeTypedFile` stamps every versioned-document envelope to the owning schema's current `version` on write — self-gated on the schema both declaring the property and carrying a `version`, so block writes, whole-block writes, `config.json` (converges to the bundled config schema version on its next sanctioned write, ending the permanently-persisted stale config version), and `migrations.json` all converge, while substrates whose installed schemas predate the property write unchanged until `/context update` lands it. With envelopes stamped, the previously-dormant read-time migration hook and pre-write version gate are active: an envelope claiming an older version is walked forward through the registered migration chain (read and write), and a version with no resolvable chain fails loud — the read throws and a write is refused with the block file left byte-unchanged.
19
+ - The packaged catalog (`samples/conception.json`) declares `role_direction` on the 17 relation_types that have a per-role consumer, so fresh `accept-all`/`install` substrates carry the orientation source of truth the deriver / rollup / roadmap / promote / write / read surfaces read. `as_parent` (primary at `edge.parent`): `task_depends_on_task`, `feature_depends_on_item`, `story_depends_on_story`, `requirement_depends_on_requirement`, `milestone_precedes_milestone`, `decision_supersedes_decision`, `research_supersedes_research`, `feature_contains_story`, `story_includes_item`. `as_child` (primary at `edge.child`): `task_gated_by_item`, `feature_gated_by_item`, `story_gated_by_item`, `decision_gated_by_item`, `phase_positioned_in_milestone`, `task_positioned_in_phase`, `item_derived_from_item`, `decision_derived_from_item`. The values are reverse-engineered from the convention already stored/consumed, so derived output is unchanged and the latent gate/rollup siblings are pre-empted; the other 27 relations (no role consumer) omit the field.
20
+ - The closure-table walk wrappers `walkLensDescendants` (`context-walk-descendants`) and `walkAncestorsByLens` (`walk-ancestors`) now SIGNAL a wrong-orientation query instead of silently returning `[]`. For a DISJOINT-kind relation (its `source_kinds` and `target_kinds` share no kind and neither is the `"*"` wildcard), a descendants walk is only meaningful from a SOURCE-kind id and an ancestors walk only from a TARGET-kind id; when the queried id resolves to a block that sits exclusively on the wrong end for the requested direction, the walk THROWS naming the correct op (a wrong-end `context-walk-descendants` points to `walk-ancestors`, and vice-versa). Same-kind / wildcard-endpoint relations, an unregistered relation, and an id that resolves to no block stay structurally un-disambiguatable and return `[]` as before; `find-references both` is symmetric and carries no signal.
21
+ - The relation-append porcelain (`append-relation` / `append-relations` ops + the `appendRelationByRef` / `appendRelationsByRef` SDK fns) accepts a ROLE-TYPED authoring form alongside the raw `{parent, child}` form: `--primary`/`--counter` (or `{primary, counter}` in an `append-relations` edge object) name the relation's semantic-role endpoints and are mapped to `parent`/`child` via the relation's declared `role_direction`. The two orientation pairs are mutually exclusive. For a relation that is BOTH role-bearing and orientation-ambiguous (its `source_kinds` and `target_kinds` overlap, including the `"*"` wildcard — e.g. a same-kind `task↔task` ordering relation), a bare `--parent`/`--child` append is now REJECTED with a message directing the author to `--primary`/`--counter`; the porcelain never guesses or auto-swaps. A role-less relation, or a role-bearing relation whose endpoint kinds are disjoint (self-orienting via the existing source/target-kind gate), is unaffected — its bare append still succeeds. Supplying `--primary`/`--counter` for a relation that declares no `role_direction` throws (there is no role to map).
22
+ - `promoteItem` orients the `item_derived_from_item` lineage edge it files into the destination substrate from that relation's declared `role_direction`: the SOURCE (the item derived from) is placed at the PRIMARY endpoint and the new-derived item at the COUNTER endpoint. `item_derived_from_item` is `as_child` (source at `edge.child`), reproducing the prior parent=new-derived / child=source layout; the `as_child` fallback preserves that layout when the destination config registers no `role_direction`. A destination declaring the relation `as_parent` mirrors the edge (parent=source, child=new-derived).
23
+ - The derived roadmap (`context-roadmap-load` / `context-roadmap-render` / `context-roadmap-validate`) reads the orientation of its three domain relations from their declared `role_direction` via the `primaryEndpoint`/`counterEndpoint` helpers rather than hardcoded parent/child picks: the precedes DAG treats the predecessor as the PRIMARY endpoint of `milestone_precedes_milestone` (fallback `as_parent`), and the phase/task membership tiers treat the container as the PRIMARY endpoint of `phase_positioned_in_milestone` / `task_positioned_in_phase` (fallback `as_child`). The former `MILESTONE_PRECEDES` / `PHASE_IN_MILESTONE` / `TASK_IN_PHASE` module constants are removed. With the stock (or absent) role_direction the derived order, membership, and validation output are unchanged; declaring a non-default `role_direction` reorients the roadmap accordingly.
24
+ - `currentState`'s config-declared membership rollups (`state_derivation.rollups`, e.g. the milestone rollup) read their container/member orientation from the membership relation's declared `role_direction` via the `primaryEndpoint`/`counterEndpoint` helpers: the CONTAINER (the rollup item) is the PRIMARY endpoint, the MEMBERS are the COUNTER endpoint. `phase_positioned_in_milestone` is `as_child` (container=milestone at `edge.child`, member=phase at `edge.parent`), reproducing the prior filter-child / map-parent selection exactly; a membership relation the config does not register with a `role_direction` defaults to `as_child` (the prior container=child convention). A `contains`-shaped (`as_parent`) membership relation now rolls up correctly (member read at the child endpoint) instead of finding zero members.
25
+ - `currentState` (the derivation behind `context-current-state` / `/context status`) partitions its `state_derivation.blocked_by` relations into gate-direction vs dependency-direction from each relation's declared `role_direction` rather than the former single `task_gated_by_item` string literal: a blocked_by relation declared `as_child` reads as a GATE (the waiting item at `edge.parent`, its gate target at `edge.child`), any other (`as_parent` or a relation the config does not register with a `role_direction`) reads as a DEPENDENCY (the item's prerequisites are the parents of edges whose child is the item). For the stock `blocked_by` set `{task_depends_on_task (as_parent), task_gated_by_item (as_child)}` the classification and the derived `blocked` / `nextActions` / `blockedBy` output are unchanged; the difference is that a same-shape gate sibling (`feature_/story_/decision_gated_by_item`) added to `blocked_by` now reads the correct gate direction by construction instead of the swapped dependency direction the literal-keyed deriver produced.
26
+ - Relation orientation — which endpoint holds a relation's PRIMARY semantic role (prerequisite/predecessor/gate for `ordering`, container for `membership`, source for `data_flow`) — is now declared once as config metadata rather than hardcoded per consumer. `config.relation_types[].role_direction` (`as_parent` | `as_child`, optional, reusing the existing invariant-direction vocabulary) names where the primary role sits: `as_parent`=`edge.parent`, `as_child`=`edge.child`. Two pure helpers `primaryEndpoint(edge, role_direction)` / `counterEndpoint(edge, role_direction)` (exported from `@davidorex/pi-context` and `@davidorex/pi-context/context-sdk`) read the endpoint under that declaration. The field is presence-gated — populated only for relations with a per-role consumer (deriver / rollup / roadmap / promote / write-orientation / read-signal); role-less relations omit it. The config schema advances to version 1.8.0 (the addition is optional; the packaged `samples/migrations.json` config chain carries a `1.0.0→1.8.0` identity migration, so a catalog-born config migrates cleanly and a config already declaring the field validates unchanged).
27
+ - The roadmap is a DERIVED view over the `milestone_precedes_milestone` relation, which the packaged catalog (`samples/conception.json`) now registers (category `ordering`, source/target `milestone`, modeled on `decision_supersedes_decision`): `context-roadmap-load` / `context-roadmap-render` / `context-roadmap-validate` take no parameters and derive the roadmap entirely from substrate state — milestone-block items topo-ordered by the authored precedes edges (order + cycles), each milestone carrying its derived status/phaseCount (currentState's config-declared milestone rollup), member phases via `phase_positioned_in_milestone`, per-phase tasks via `task_positioned_in_phase`, and per-phase + per-milestone status rollups. Adjacency in the loaded view and the rendered **Preceded by:** lines comes strictly from the authored edges, never inferred from order consecutive pairs. The filed design specified a precedes-CHAIN; the implementation generalizes chain → DAG (the approved delta): multiple starts and joins topo-order correctly, a linear chain being the degenerate case, and zero milestones is a valid empty view. The roadmap BLOCK is retired with the derivation: no `roadmap.json`, no ROADMAP- ids, no roadmap block kind — the `context-roadmap-list` op, the `/context roadmap-list` subcommand, the `loadRoadmap(cwd, roadmapId)` / `listRoadmaps` / `validateRoadmaps` / `PhaseSpec` / `RoadmapSpec` / `PhaseView` / `RoadmapView` exports, and the legacy `registry/schemas/roadmap.schema.json` fixture are removed (`/context roadmap-view` and `/context roadmap-validate` no longer take an id; the new exports are `loadRoadmap(cwd)`, `validateRoadmap`, `MilestoneRoadmapView`, `MilestoneView`, `PhaseRollupView`, `TaskRow`). Validation codes are rewired to the derived model: errors `roadmap_precedes_endpoint_missing` (a precedes-edge endpoint that is not a milestone-block item), `roadmap_milestone_cycle`, `roadmap_milestone_missing` (a `phase_positioned_in_milestone` edge whose child is not a known milestone); warning `roadmap_status_unknown_value`; and a new INFO tier — `roadmap_milestone_isolated` (a milestone with zero precedes edges while others are ordered) — that never affects the validation status (invalid iff any error, warnings iff any warning, else clean) and is excluded from the `context-validate` lens-validator merge, which contributes error-code issues only, block-framed `milestone`.
28
+ - The SKILL's `/context init` and `/context accept-all` descriptions state the ceremony's actual writes: init bootstraps the pointer + dirs, a vocabulary-empty SKELETON `config.json` (minted + registered `substrate_id`), and the seeded catalog `config` migration declarations; accept-all never overwrites a POPULATED config but DOES overwrite the init skeleton (preserving its on-disk `substrate_id`), and `config.json`'s `root` is written first at init and again at accept-all.
29
+ - `resyncSchema`'s internal collision-key separator is spelled as the `\u0000` escape sequence instead of a literal NUL byte — the produced runtime string is identical; `src/index.ts` (and the built `dist/index.js`) are plain text again for byte-sensitive tools.
30
+ - New `map_each` declarative-transform primitive (TransformOp, alongside rename/set/delete/coerce): addresses an ARRAY at a dotted `$`-path (absent path / non-array value no-op) and maps its elements in one of two modes — table mode replaces each string element through a lookup table, with an unmatched string becoming `{relation_type: <element>, item_endpoint: <fallback>}` under a `parent`/`child` fallback (default `parent`) and non-string elements passing through; set-on-each mode assigns a declared `field`=`value` on every object element (non-object elements skipped). The schema variant enforces table XOR field+value. Registered in `migrations.schema.json`, the `TransformOp` TS union, and the loader's op applicator; surfaced in the `write-schema-migration` op description.
31
+ - Config loading (`loadConfig` / `loadConfigForDir`) is migration-aware: when `config.json`'s `schema_version` differs from the bundled config schema's `version`, the substrate's registered `config` migration chain walks the data forward in memory before validation (the on-disk file is never rewritten); a mismatch with no resolvable chain throws (fail-fast — no raw-validate fallback). On version match the migration registry is never consulted.
32
+ - The packaged catalog (`samples/migrations.json`) ships a `config 1.0.0→1.7.0` identity migration declaration, and EVERY sanctioned ceremony entry point — `/context init` (`writeSkeletonConfig`), `/context accept-all` (`adoptConception`), `/context install` (`installContext`), `/context update` (`updateContext`), `/context check-status` (`checkStatus`), the `/context switch` existing-target and switch-back forms (`switchToExisting` / `switchToPrevious`, seeding the TARGET substrate right after the pointer flip), `/context resolve-conflict` (`resolveConflict`), and `/context resolve-blocked` (`resolveBlocked`) — seeds the catalog's `config` declarations into the substrate's `migrations.json` via the exported `seedCatalogConfigMigrationDecls(substrateDir, ctx?)` (idempotent: a present `(schemaName, fromVersion)` pair is never replaced; returns the appended edges) BEFORE its first config read, so catalog-born substrates and re-entered legacy substrates carry a resolvable config chain before any config read. The initial change seeded only init / accept-all / install; an adversarially-verified finding showed a lagging legacy substrate (1.0.0 config, no `migrations.json`) still threw on `update` / `check-status` / a pointer flip onto it — the class rule now applied is that every ceremony entry point seeds. `check-status` and a `--dryRun` update thereby perform this one idempotent seed write (the designed heal semantic, consistent with idempotent re-init healing) while remaining otherwise read-only. The seed helper is additionally a no-op on a NONEXISTENT substrate dir (guarded at its first statement, one guard covering every present and future call site): the seed heals substrates, it never materializes them — a bootstrap pointer naming a dir that was never created degrades with zero writes (no dir creation, no `migrations.json` residue) rather than the seed mkdir-ing the dir into existence; ceremonies that need the dir create it themselves before seeding — concretely, the WRITE-flavored ceremonies whose job is materializing config (`adoptConception` for accept-all, `writeSkeletonConfig` for init / switch -c) mkdir the substrate dir immediately before their seed call, so a first-touch accept-all on a pointer whose dir was never created still lands the seeded config chain before the config write, while the read-flavored ceremonies (check-status / update / switch-back onto a degenerate pointer) rely on the helper's no-op guard and write nothing. An EXISTING dir without a `config.json` remains seeded by design (mid-ceremony states such as init→accept-all need the seed before, and independent of, config presence).
33
+ - The `context-check-status` and `context-update` reflected op `description` strings state the seed-at-entry behavior: each names the one idempotent catalog-config-migration seed write performed before the first config read, with the drift report / `--dryRun` preview otherwise unchanged in their read-only framing.
34
+ - `seedCatalogConfigMigrationDecls` no-ops (returns `[]`, zero writes) when the substrate dir does not exist — the seed heals substrates, it never materializes them, so a read-flavored ceremony (`check-status`, `update`, a switch-back) invoked against a bootstrap pointer naming a nonexistent dir degrades exactly as before seeding existed (no dir creation, no `migrations.json` residue). The write-flavored ceremonies that legitimately materialize config (`accept-all`'s `adoptConception`, `init`'s `writeSkeletonConfig`) mkdir their substrate dir immediately before seeding, so a first-touch accept-all still lands the config chain before the config write.
35
+ - Every `migrations.json` write now invalidates the migration-registry cache at the write funnel (`writeMigrationsFileForDir`) rather than per mutation helper, so any write path through the store — including the new ceremony seeding — is cache-coherent in-process (fixes a staleness window where a registry warmed empty before a raw whole-file write kept serving the pre-write declarations).
36
+ - The packaged catalog (`samples/conception.json`) now registers the config vocabulary that shipped derivations already referenced but the catalog had not defined, so fresh `accept-all`/`install` substrates carry it and are internally consistent: relation_types `task_gated_by_item` (the blocking relation `state_derivation.blocked_by` already names), `task_advances_story` / `feature_advances_story` (the relations the `story-advancers` / `story-advancers-features` lenses project), `decision_derived_from_item` / `decision_escalates_underdetermined` (the relations the `decision-shows-derivation` invariant requires), and `session_touches_item`; the lenses `gaps-by-priority`, `features-by-status`, `story-advancers`, `story-advancers-features`; the invariant `decision-shows-derivation`; and the `session-notes` block kind (prefix `SESSION-`, array_key `sessions`) with its schema (`samples/schemas/session-notes.schema.json`), an empty starter block (`samples/blocks/session-notes.json`), and `session-notes` added to `installed_schemas` / `installed_blocks` so `install` materializes `session-notes.json`. A fresh catalog-built substrate now validates with no unregistered-relation reference and accepts `task_gated_by_item` / `task_advances_story` / `session_touches_item` edges.
37
+ - The packaged catalog (`samples/conception.json`) `state_derivation.next_ranked` push order is `tasks`, then `issues`, then `framework-gaps` — so `nextActions` (`context-current-state` / `/context status`) surfaces ready unblocked tasks ahead of open issues and open framework-gaps in the derived next-actions head (the deriver walks `next_ranked` in array order, then truncates to `head_size`). Each entry's content (kind, label, bucket, rank_field, rank_order, reason_template) is unchanged from before; only the entries' order in the array differs.
38
+ - The packaged catalog (`samples/conception.json`) now treats issues as a gap-sibling open-work kind: it ships relation_types `task_addresses_issue` (a task addressing an issue) and `issue_relates_to_issue` (an issue related to another issue); a `task-completed-issue-resolved` status-consistency invariant (warning) flagging a completed task whose `task_addresses_issue` target is not resolved; a `state_derivation.next_ranked` entry for `issues` (open issues ranked by `priority` critical→high→medium→low, surfaced in `nextActions` of `context-current-state` / `/context status` after tasks and before framework-gaps); and `issues-by-status` (open/resolved/deferred) + `issues-by-priority` (critical/high/medium/low) lenses. The issues schema (`samples/schemas/issues.schema.json`, version unchanged) additively gains an optional `resolved_at` (ISO-8601 resolution timestamp) field and an `x-lifecycle` block declaring the `status` states (open/resolved/deferred) and authority-gated transitions (open→resolved any, open→deferred user).
39
+ - Each `next_ranked` entry in the `state_derivation` registry now carries an optional `reason_template` (string) supplying the `reason` string `currentState` (`context-current-state` / `/context status`) emits for the items that entry surfaces in `nextActions`. The template substitutes `{rank_value}` (the item's `rank_field` value, or `unset` when absent) and `{id}` (the item id) literally where they appear. The packaged catalog ships the stock templates — `open gap (priority {rank_value})` on the priority-ranked `framework-gaps` entry and `unblocked planned task` on the topo `tasks` entry — so a custom `state_derivation` declaring non-`framework-gaps`/`tasks` kinds emits its own configured reason strings, and the `focus` fallback prefix is drawn from `focus_fallback.kind` (stock `phase`, yielding `phase: <id>`). The config schema is at version 1.7.0.
40
+ - A substrate whose config declares NO `state_derivation` makes `currentState` (`context-current-state` / `/context status`) report `focus: "state-derivation not configured"` with empty `inFlight` / `nextActions` / `blocked` / `milestones` — a signal distinct from a configured-but-empty substrate (which derives `focus: "no active focus."` with empty arrays). The derivation's in-flight kinds/bucket, focus fallback, next-actions ranking + order, blocking relation set, milestone rollup, and head-size cap are all read from the declared registry.
41
+ - `amend-config --registry state_derivation` addresses the `state_derivation` singleton per-key (a map-kind registry: its six top-level keys are the map entries), and `update` brings the catalog's whole `state_derivation` object into a substrate that lacks one while leaving an existing one untouched (merged whole, never body-merged).
42
+ - The packaged catalog (`samples/conception.json`) ships the stock `state_derivation` registry — `in_flight` over `tasks` at `in_progress`, `focus_fallback` on `phase` at `in_progress`, a `next_ranked` of `tasks` (topo) then priority-ranked `issues` then priority-ranked `framework-gaps` (P0..P3), `blocked_by` the `task_depends_on_task` + `task_gated_by_item` relations, a `milestone` rollup over `phase_positioned_in_milestone` (reached/planned), and `head_size` 15 — so fresh `accept-all`/`install` substrates carry the derivation declaration.
43
+ - `currentState` (the derivation behind `context-current-state` / `/context status`) derives its focus, in-flight set, next-actions ranking, blocked set, and milestone rollup from a new config-declared `state_derivation` registry rather than from values baked into the deriver. The registry is a singleton config object with six keys: `in_flight` (block kinds + status bucket counted as in-flight), `focus_fallback` (kind + bucket for the focus fallback when nothing is in-flight), `next_ranked` (the ordered cross-kind push order for next-actions; each entry selects a kind at a bucket and either ranks within itself via a named field + ordered value list or topo-orders over the blocking-relation graph), `blocked_by` (the relation_types whose edges contribute blockers), `rollups` (membership rollups such as milestones, with their complete/incomplete status strings), and `head_size` (the next-actions truncation cap). The packaged catalog (`samples/conception.json`) ships the stock registry — tasks/phase/issues/framework-gaps/milestone kinds, the `task_depends_on_task` + `task_gated_by_item` blocking relations, the `next_ranked` push order of `tasks` (topo) then priority-ranked `issues` then priority-ranked `framework-gaps` (P0..P3), and head size 15 — so fresh `accept-all`/`install` substrates carry it and the derived output is unchanged. A substrate whose config has no `state_derivation` reports `focus: "state-derivation not configured"` with empty arrays, distinguishing an un-configured substrate from a configured-but-empty one. `state_derivation` is addressable per-key through `amend-config --registry state_derivation` (a map-kind registry); `update` brings the whole object into a substrate that lacks it while leaving an existing one untouched. The config schema is at version 1.7.0.
44
+ - The packaged catalog ships an empty `milestone` starter block (`samples/blocks/milestone.json`, `{ "milestones": [] }`, matching the block kind's `data_path` `milestone.json`), so `install` / `context-install` materializes a `milestone.json` block in the substrate alongside the milestone schema.
45
+ - The packaged catalog (`samples/conception.json`) now ships a `milestone` block kind (prefix `MILE-`, array_key `milestones`, schema `samples/schemas/milestone.schema.json`) and its schema, so fresh `accept-all`/`install` substrates carry it. A milestone is a phase-rollup checkpoint with fields `id` (`MILE-NNN`), required `name`, required `status` (`planned` | `reached`), and an optional `release` grouping string. `status` is DERIVED, not authored: `currentState` (the derivation behind `context-current-state` / `/context status`) reports a milestone as `reached` when at least one phase is positioned in it via a `phase_positioned_in_milestone` edge (phase is the parent, milestone the child) and the parent phase of every such edge buckets to complete, and `planned` otherwise (covering no-phases and any-incomplete). The catalog also adds two membership relation_types — `phase_positioned_in_milestone` (phase → milestone, driving the rollup) and `story_includes_item` (story → any kind, the single relation expressing a story's scope) — and replaces the former `story_contains_task` with `story_includes_item`. A `status-consistency` invariant `reached-milestone-phases-complete` (severity error) backstops the derived state: a milestone whose own status buckets to complete must have the parent phase of every `phase_positioned_in_milestone` edge complete, surfaced by `context-validate`. `reached` maps to the complete status bucket in the default status vocabulary.
46
+ - `currentState` (the derivation behind `context-current-state` / `/context status`) now folds `task_gated_by_item` gates into task-readiness alongside the existing `task_depends_on_task` dependencies. A planned task carrying a `task_gated_by_item` edge to a target that has not reached the complete bucket is reported in `blocked` (the gate target id present in `blockedBy`, unioned with any unsatisfied dependency parents) and excluded from `nextActions`; a gate target of any kind reaching its complete status (gap→closed, decision→enacted, feature→complete, task→completed) releases the gate. Gate satisfaction reuses the same `bucket(target) === "complete"` check via the config-resolved status vocabulary that the status-consistency invariant engine uses — kind-general, no per-kind special-casing and no parallel completeness notion. A dangling gate target (id resolving to no item) is treated as satisfied/non-blocking, mirroring the dangling-dependency guard. Scope is the literal relation_type `task_gated_by_item`: `decision_gated_by_item` and other non-task `*_gated_by_item` edges do not alter `currentState`. A gate target in a terminal-abandoned status (`wontfix` / `superseded` / `cancelled`, which bucket to `unknown` rather than `complete`) keeps the gated task blocked; promoting such states to gate-releasing and generalizing the gate-aware derivation to all gate relation kinds is the config-driven refinement boundary, deferred. With no `task_gated_by_item` edges present the derivation output is unchanged.
47
+ - The packaged catalog (`samples/conception.json`) now ships three relation_types: `decision_raises_gap` (a decision raising a framework-gap), `decision_gated_by_item` (a decision enactment-gated by an item), and `gap_relates_to_gap` (a framework-gap related to another framework-gap), so fresh `accept-all`/`install` substrates carry them.
48
+ - The friendly-selector edge-write porcelain (`appendRelationByRef` / `appendRelationsByRef`) now validates each resolved edge against the relation_type registry at write time: an edge whose `relation_type` is not registered in `config.relation_types`, or whose resolved source/target endpoint block is not in that relation_type's declared `source_kinds` / `target_kinds`, throws and is never persisted (a batch is all-or-nothing — a single invalid edge rejects the whole `appendRelationsByRef` call before any write; `dryRun` rejects identically). A relation_type declaring neither `source_kinds` nor `target_kinds` is unchecked for endpoint kinds (presence-gated). This is the same registration + endpoint-kind check `context-validate` performs post-hoc, now factored into a shared `validateEdgeAgainstRegistry` helper invoked at both surfaces so write-time and validate-time verdicts are identical.
49
+
50
+ ### Documentation
51
+ - Edge orientation is documented across the surfaces the metadata change touches: the `append-relation` / `append-relations` op `description` + `promptSnippet` state the raw-vs-role-typed authoring forms and the ambiguous-bare-append reject; `context-walk-descendants` / `walk-ancestors` state the disjoint-kind wrong-orientation throw (naming the counterpart op); `replace-relation` states that it writes raw endpoints verbatim, bypassing the orientation gate (the re-orient affordance, `context-validate` after). The package README's relations section gains an "Edge orientation" paragraph (the `role_direction` source of truth + `primaryEndpoint`/`counterEndpoint` + authoring/read behavior), and `skill-narrative.md` gains the matching orientation prose; the root README's tool enumeration carried no orientation claim to correct. Regenerate `skills/pi-context/SKILL.md` (`npm run skills`) to pick up the changed op strings.
52
+ - Regenerated `skills/pi-context/SKILL.md` from the edge-orientation `skill-narrative.md` + op-string edits: the tool entries now carry the role-typed `append-relation`/`append-relations` authoring + ambiguous-bare-append reject, the `context-walk-descendants`/`walk-ancestors` disjoint-kind wrong-orientation throw, and the `replace-relation` raw-endpoint gate-bypass note.
53
+ - The `next_ranked` doc strings — the `config.schema.json` `next_ranked` `description`, the `next_ranked` field JSDoc in `context.ts`, and the `CurrentState.nextActions` field doc + `nextActions` deriver inline comment in `context-sdk.ts` — state the stock cross-kind push order as tasks (topo-ordered) then issues (priority-ranked) then framework-gaps (priority-ranked), matching the packaged catalog's `state_derivation.next_ranked` array order.
54
+ - The `context-current-state` op `description` + `promptSnippet` state that focus, in-flight, ranked next-actions, blocked, and milestone rollups all derive from the config-declared `state_derivation` registry (in-flight kinds + bucket, focus fallback, the ordered next-actions push order with per-entry field-ranking or topo ordering, the blocking relation set, the membership rollups with their status strings, and the head-size cap), and that a substrate without the registry reports focus 'state-derivation not configured'.
55
+ - Regenerated `skills/pi-context/SKILL.md` for the `context-current-state` op's config-declared `state_derivation` derivation surface — the tool entry now states that focus, in-flight, ranked next-actions, blocked, and milestone rollups all derive from the declared `state_derivation` registry and that a substrate without it reports focus 'state-derivation not configured'.
56
+ - Regenerated `skills/pi-context/SKILL.md` for the `context-current-state` op's gate-aware readiness surface — the tool entry now states that task readiness honors both `task_depends_on_task` dependencies and `task_gated_by_item` gates and that a gate target reaching its complete status releases the gate.
57
+ - Regenerated `skills/pi-context/SKILL.md` + `references/bundled-resources.md` for the milestone block kind (now listed in the installable blocks/schemas inventory) and the corrected `context-roadmap-load`/`render`/`validate` op strings — a phase's milestone is a MILE- block id whose satisfaction reads the milestone's derived `reached` (a pure phase-rollup over the parent phases of its `phase_positioned_in_milestone` edges; phase is the parent, milestone the child), with the validate codes collapsed to `roadmap_milestone_missing`.
58
+
59
+ ### Fixed
60
+ - `context-validate-relations` no longer reports `edge_parent_not_in_bins` for a content edge whose structured item parent rides a relation_type that also serves as an edge-materialization lens axis (a lens with `derived_from_field: null`, `bins: []`, e.g. `story-advancers` / `story-advancers-features`). `validateRelations` had applied the lens parent-in-bins contract to every edge matching a lens's relation_type, including the real content edges (task/feature → story), so structurally-correct advancer edges falsely invalidated the substrate. The bins check now applies only when the parent is a `lens_bin` endpoint — a genuine `lens_bin` parent not among the lens bins still errors; an item or legacy-string parent is validated on endpoint kind / existence only.
61
+ - `context-validate` again groups its edge-registry diagnostics by class — every relation_type-registration issue across all edges before every source/target-kind issue across all edges — matching the order surfaced before the `validateEdgeAgainstRegistry` refactor. That refactor's per-edge loop had interleaved the two classes (one edge's registration and kind issues, then the next edge's), changing the printed `issues[]` order; the merged loop now collects then partitions by class so the emission order is class-grouped again. Order-only — the set, count, wording, and severity of the issues are unchanged.
62
+ - Corrected the `phase_positioned_in_milestone` edge direction throughout the milestone phase-rollup: the phase is the edge PARENT and the milestone the CHILD (matching the relation_type registration `source_kinds: phase` / `target_kinds: milestone`, the closure parent=source/child=target convention, and the invariant's `direction: as_child` meaning the milestone is the child). The `currentState` `reached` deriver had selected edges where the milestone was the parent and read the child as the member phase; it now selects edges where the milestone is the child and reads the parent as the member phase, so a milestone derives `reached` only when at least one phase is positioned in it and the parent phase of every such edge buckets to complete. The schema, invariant message, op `description`, and roadmap fixtures that described the phase as the "child" are corrected to the parent-phase framing.
63
+ - Corrected the milestone block kind's `data_path` to `milestone.json` (matching the `data_path === canonical_id + ".json"` convention; `canonical_id` is `milestone`) and renamed the catalog starter block to `samples/blocks/milestone.json` accordingly. It had been authored as `milestones.json`, diverging from the convention.
64
+
7
65
  ## [0.31.0] - 2026-06-13
8
66
 
9
67
  ### Changed
package/README.md CHANGED
@@ -15,14 +15,14 @@ pi install npm:@davidorex/pi-context
15
15
  ```
16
16
  /context init <substrate-dir> # create the empty substrate skeleton
17
17
  /context install # reconcile <substrate-dir>/ against installed_* lists in config.json
18
- /context check-status # read-only: report which installed schemas are behind the catalog + the version gap (writes nothing)
18
+ /context check-status # read-only: report which installed schemas are behind the catalog + the version gap (writes nothing beyond the idempotent config-migration seed)
19
19
  /context update [--dryRun] # bring the installed schema model current with the catalog, preserving local edits (3-way merge); --dryRun previews
20
20
  /context resolve-conflict --schemaName <name> [--schema <reconciled>] # commit a reconciled merge conflict: write the resolved body + advance the merge base to the catalog
21
21
  ```
22
22
 
23
23
  `init` (and `switch -c`) is intentionally minimal: it writes the bootstrap pointer, the substrate/schemas dirs, and a minimal schema-valid **skeleton config** (`schema_version` + empty `block_kinds` + `root` + a minted, registered `substrate_id`) — no schemas, no starter blocks (ship-no-defaults). The skeleton is never-clobbered: an idempotent re-init leaves an existing config untouched. From the skeleton there are two onward paths: adopt the packaged conception with `/context accept-all` (overwrites a skeleton config, never a populated one; writes `config.json` from `samples/conception.json` and preserves the skeleton's `substrate_id`), then `/context install`; or build a custom vocabulary directly via `amend-config` / `write-schema` / `append-block-item` (no catalog adoption). The opt-in install ceremony copies the `installed_schemas` / `installed_blocks` declared in `config.json` from the package samples catalog (`samples/blocks/` and `samples/schemas/`); it is idempotent. Populated block data is never overwritten (reported as `preserved`), while empty or absent blocks get the catalog starter. Install records an **install baseline** (`config.installed_from`) — the catalog source + a per-schema content fingerprint of the installed schemas — for installed-vs-catalog drift detection; the baseline covers schemas only. The adopted conception also carries advisory (severity-`warning`) convention-articulation invariants: every decision, feature, and task should carry an `item_governed_by_convention` edge to a convention it follows, or an `item_acknowledges_missing_convention` edge to a missing-convention gap — `context-validate` reports an artifact articulating neither as a warning (not an error), so the advice surfaces without blocking writes.
24
24
 
25
- `/context update` is the drift-aware, customization-preserving path for bringing the installed schema model current with the catalog (it supersedes the former `/context install --update`). Per installed schema it consults the drift classification: an `in-sync` schema is a no-op; a `catalog-ahead` schema re-syncs through the migration-aware path; a `locally-modified` / `both-diverged` schema is reconciled by a deterministic 3-way merge of base (the as-installed schema body in the object store, keyed by the recorded baseline `content_hash`) × ours (the installed schema) × theirs (the catalog schema) — disjoint edits auto-merge so both the user's and the catalog's changes survive (`required` / `enum` / array-valued `type` nodes merge as sets), and a schema with irreconcilable per-path conflicts is left unmodified — the conflict set is returned in the op output (under `conflicts`) alongside a readable report, and the calling agent reconciles it then commits via `/context resolve-conflict` (no subordinate resolver is spawned). `update` also additively propagates catalog-new config-registry entries (`relation_types` / `invariants` / `block_kinds` / `lenses`) absent from the config, preserving every user-authored entry and any locally-diverged body of an existing entry (additive-only; the added ids are reported under `registryAdditions`). A version-bump `catalog-ahead` resync registers the shipped catalog migration chain's declarations into `migrations.json`, reported under `migrationsRegistered` (each `{ schema, from, to }`). `--dryRun` predicts the precise per-schema outcome (resync / migrate / block / merge / conflict) by running the forward-migration and re-validation in memory, alongside the config-registry entries that would be added and the migration declarations that would be registered, writing nothing. Preview drift first with `/context check-status`, which reports which installed schemas are behind the catalog and by what version gap.
25
+ `/context update` is the drift-aware, customization-preserving path for bringing the installed schema model current with the catalog (it supersedes the former `/context install --update`). Per installed schema it consults the drift classification: an `in-sync` schema is a no-op; a `catalog-ahead` schema re-syncs through the migration-aware path; a `locally-modified` / `both-diverged` schema is reconciled by a deterministic 3-way merge of base (the as-installed schema body in the object store, keyed by the recorded baseline `content_hash`) × ours (the installed schema) × theirs (the catalog schema) — disjoint edits auto-merge so both the user's and the catalog's changes survive (`required` / `enum` / array-valued `type` nodes merge as sets), and a schema with irreconcilable per-path conflicts is left unmodified — the conflict set is returned in the op output (under `conflicts`) alongside a readable report, and the calling agent reconciles it then commits via `/context resolve-conflict` (no subordinate resolver is spawned). `update` also additively propagates catalog-new config-registry entries (`relation_types` / `invariants` / `block_kinds` / `lenses`) absent from the config, preserving every user-authored entry and any locally-diverged body of an existing entry (additive-only; the added ids are reported under `registryAdditions`). A version-bump `catalog-ahead` resync registers the shipped catalog migration chain's declarations into `migrations.json`, reported under `migrationsRegistered` (each `{ schema, from, to }`). `--dryRun` predicts the precise per-schema outcome (resync / migrate / block / merge / conflict) by running the forward-migration and re-validation in memory, alongside the config-registry entries that would be added and the migration declarations that would be registered, writing nothing beyond the idempotent config-migration ceremony seed. Because update applies per-component (a blocked schema rolls back only itself; the registry propagation writes regardless), a run that refuses any schema while applying registry additions or other-schema resyncs reports the partiality under `partialApplication` — `applied`/`notApplied` mirrors of the result channels plus a one-line summary naming what was applied alongside what was refused and why — so a blocked run never reads as a no-op (`--dryRun` reports the predicted partiality in the same shape). The ceremonies that reach identity-stamping writes (update, install, resolve-blocked) establish substrate identity at entry: a config with no `substrate_id` gets one minted, persisted, and registered before the first stamping write — a pre-identity substrate heals on the sanctioned ceremony instead of refusing — reported under `substrateIdEstablished` (live runs only; an established identity is never re-minted). Preview drift first with `/context check-status`, which reports which installed schemas are behind the catalog and by what version gap.
26
26
 
27
27
  ## How It Works
28
28
 
@@ -75,9 +75,11 @@ Each substrate's `config.json` carries a `substrate_id` (pattern `sub-` + 16 hex
75
75
 
76
76
  All inter-item relationships are closure-table edges in `<substrate-dir>/relations.json` — `{parent, child, relation_type, ordinal?}` rows. Endpoints are dual-form: a legacy string (a canonical id, a lens bin name, or an `<alias>:<refname>` cross-substrate sentinel), or a structured `{kind:"item", oid, refname?, substrate_id?, content_hash?}` (where `substrate_id` marks a foreign endpoint), or a structured `{kind:"lens_bin", bin}` virtual parent. Embedded nested id-bearing arrays and FK-as-field are forbidden (`validateContext` flags `nested_id_bearing_array`); containment is a membership edge carrying `ordinal`. `promote-item` is the cross-substrate derivation tool (an item promoted into another registered substrate as a new content-addressed item).
77
77
 
78
+ **Edge orientation.** Storage is uniform (`edge.parent` = source endpoint, `edge.child` = target endpoint); which endpoint holds a relation's PRIMARY semantic role (prerequisite/predecessor/gate for `ordering`, container for `membership`, source for `data_flow`) is declared ONCE as `config.relation_types[].role_direction` (`as_parent` = primary at `edge.parent`, `as_child` = primary at `edge.child`; optional — set only for relations with a per-role consumer). The blocked/ready deriver, the milestone rollup, the derived roadmap, and `promote-item`'s lineage edge all read orientation from this field via the `primaryEndpoint`/`counterEndpoint` helpers rather than hardcoding parent/child. Authoring: `append-relation` / `append-relations` accept EITHER raw `--parent`/`--child` OR role-typed `--primary`/`--counter` (mapped to parent/child via `role_direction`); a bare `--parent`/`--child` append of a relation that is BOTH role-bearing and orientation-ambiguous (its source/target kinds overlap) is rejected in favor of `--primary`/`--counter`. Reading: a `context-walk-descendants` / `walk-ancestors` query on a disjoint-kind relation from the wrong endpoint THROWS naming the correct op instead of returning an ambiguous `[]`. `replace-relation` writes raw endpoints verbatim (bypassing the orientation gate) and is the re-orient affordance — run `context-validate` after.
79
+
78
80
  ### Schema versioning + migrations
79
81
 
80
- `<substrate-dir>/migrations.json` is the per-substrate migration registry. A schema `version` bump requires a companion migration declared via `write-schema-migration` — without one, reading or writing an item with an older `schema_version` throws a version mismatch. Migration kinds are `identity` (shape-compatible, no transform) or `declarative-transform` (a spec of rename/set/delete/coerce on dotted paths). The loaded registry walks items forward at the next read/write without a process restart.
82
+ `<substrate-dir>/migrations.json` is the per-substrate migration registry. A schema `version` bump requires a companion migration declared via `write-schema-migration` — without one, reading or writing an item with an older `schema_version` throws a version mismatch. Migration kinds are `identity` (shape-compatible, no transform) or `declarative-transform` (a spec of rename/set/delete/coerce/map_each on dotted paths; `map_each` addresses an array — table mode maps each string element through a lookup, with unmatched elements becoming `{relation_type, item_endpoint}` under a parent/child fallback, and set-on-each mode sets a field on every object element). The loaded registry walks items forward at the next read/write without a process restart. Config loading is migration-aware — a config whose `schema_version` lags the bundled schema is walked forward through the `config` migration chain in memory at load (the on-disk file is never rewritten); every substrate-lifecycle ceremony — `/context init`, `/context accept-all`, `/context install`, `/context update`, `/context check-status`, `/context switch` (the existing-target and switch-back forms; the target substrate is seeded right after the pointer flip), `/context resolve-conflict`, and `/context resolve-blocked` — seeds the catalog's `config` identity declaration into `migrations.json` (idempotent) before its first config read, and a version mismatch with no resolvable chain throws. The ceremonies that reach identity-stamping writes (update, install, resolve-blocked) also establish substrate identity at entry: a config carrying no `substrate_id` gets one minted, persisted, and registered before the first stamping write — a pre-identity substrate heals on the sanctioned ceremony instead of refusing — reported in the ceremony result under `substrateIdEstablished` (live runs only; an established identity is never re-minted). On the write side, versioned-document envelopes converge: every block schema declares an optional top-level `schema_version`, and the write path stamps it (config.json's and migrations.json's included) to the owning schema's current `version` on every sanctioned write — an incoming envelope claiming an older version is first walked forward through the registered chain (or refused with the file left byte-unchanged when no chain reaches the current version), then persisted at the current version; reads of a stamped block validate the whole envelope migration-aware. A substrate whose installed schemas predate the `schema_version` property keeps writing unchanged until `/context update` lands it. The bundled config schema itself evolves expand-contract: new fields land optional, and a non-additive change (a removed/renamed key, or a new required field on a pre-existing object) is refused by a build-time gate (`scripts/check-config-schema.ts`, pre-commit + CI) unless the same change advances the schema `version` and declares a packaged `config` migration reaching it.
81
83
 
82
84
  **Tools registered:** the tool surface grows with the package — read the generated `skills/pi-context/SKILL.md` for the current set, or call the `list-tools` tool at runtime (in-pi) / `grep pi.registerTool packages/pi-context/src/index.ts` (source). Families:
83
85
 
@@ -88,7 +90,7 @@ All inter-item relationships are closure-table edges in `<substrate-dir>/relatio
88
90
  - **Discovery/introspection** — `read-config`, `read-schema`, `read-samples-catalog`, `read-catalog-schema`, `list-tools`, `context-current-state`, `context-bootstrap-state`.
89
91
  - **Lifecycle/state** — `context-status`, `context-validate`, `context-validate-relations`, `complete-task` (gates on a passing `verification_verifies_item` edge — verification=parent, task=child).
90
92
  - **Substrate management** — `context-init`, `context-accept-all`, `context-install`, `context-switch`, `context-list`, `context-archive`.
91
- - **Roadmap** — `context-roadmap-load`, `context-roadmap-render`, `context-roadmap-validate`, `context-roadmap-list`.
93
+ - **Roadmap** — `context-roadmap-load`, `context-roadmap-render`, `context-roadmap-validate`: the derived roadmap over the `milestone_precedes_milestone` DAG — milestone-block items topo-ordered by the authored precedes edges, with per-milestone phase/task rollups; adjacency comes strictly from the edges, never inferred from order.
92
94
 
93
95
  The relation byRef ops (`append-relation` / `remove-relation` / `replace-relation` / `append-relations`) and `upsert-block-item` accept a `dryRun` flag: it resolves the operation and validates the prospective whole file under the SAME write-path validation, returning the would-decision (`{ ..., dryRun: true }`) while writing nothing. The same shared library path backs both the op (`--dryRun`) and the orchestrator scripts — one implementation, not a script-only preview.
94
96
 
@@ -101,21 +103,20 @@ The relation byRef ops (`append-relation` / `remove-relation` / `replace-relatio
101
103
  **Commands registered:**
102
104
  - `/context init <substrate-dir>` — bootstrap pointer + substrate/schemas dirs + a never-clobber skeleton `config.json` (schema-valid, empty of vocabulary, minted `substrate_id`); onward via accept-all OR amend-config / edit
103
105
  - `/context accept-all` — adopt `samples/conception.json` as `config.json` (idempotent; never overwrites an existing config)
104
- - `/context install` (CLI: `pi-context context-install [--update]`) — reconcile the substrate against `installed_schemas` / `installed_blocks` in `config.json` by copying assets from the samples catalog (skip-if-exists by default). Populated block data is never overwritten (reported as `preserved`), and empty or absent blocks get the catalog starter. Install also base-stamps each as-installed schema body into the object store and records an **install baseline** in `config.installed_from` — the catalog source (`name@version` + conception `schema_version`) plus a per-schema fingerprint (content hash + declared version) of the installed schemas — used for installed-vs-catalog drift detection. The baseline covers schemas only (blocks are user data); a re-install on an unchanged substrate is idempotent (byte-identical `config.json`, `at` preserved). (Bringing the installed schema model current is now `/context update`, below.)
105
- - `/context check-status` (CLI: `pi-context context-check-status`) — read-only: reports drift between the installed schemas and the catalog, reporting each as `in-sync` / `catalog-ahead` / `locally-modified` / `both-diverged` / `no-baseline` / `missing-catalog` / `missing-installed`, and for each schema behind the catalog (`catalog-ahead` / `both-diverged`) it surfaces `behind` and a `version_delta` — the baseline → catalog version pair (a declared version bump) or a content-only basis when the catalog body moved with the version string unchanged; writes nothing
106
+ - `/context install` (CLI: `pi-context context-install [--update]`) — reconcile the substrate against `installed_schemas` / `installed_blocks` in `config.json` by copying assets from the samples catalog (skip-if-exists by default). Populated block data is never overwritten (reported as `preserved`), and empty or absent blocks get the catalog starter. Install also base-stamps each as-installed schema body into the object store and records an **install baseline** in `config.installed_from` — the catalog source (`name@version` + conception `schema_version`) plus a per-schema fingerprint (content hash + declared version) of the installed schemas — used for installed-vs-catalog drift detection. The baseline covers schemas only (blocks are user data); a re-install on an unchanged substrate is idempotent (byte-identical `config.json`, `at` preserved). On a substrate whose config carries no `substrate_id`, install establishes the identity at entry (mint + persist + register) and reports it under `substrateIdEstablished`. (Bringing the installed schema model current is now `/context update`, below.)
107
+ - `/context check-status` (CLI: `pi-context context-check-status`) — read-only: reports drift between the installed schemas and the catalog, reporting each as `in-sync` / `catalog-ahead` / `locally-modified` / `both-diverged` / `no-baseline` / `missing-catalog` / `missing-installed`, and for each schema behind the catalog (`catalog-ahead` / `both-diverged`) it surfaces `behind` and a `version_delta` — the baseline → catalog version pair (a declared version bump) or a content-only basis when the catalog body moved with the version string unchanged; writes nothing beyond the idempotent ceremony seed of the catalog's `config` migration declarations into `migrations.json` (every substrate-lifecycle ceremony seeds before its first config read, so a version-lagging legacy substrate is diagnosable)
106
108
  - `read-catalog-schema` (CLI: `pi-context read-catalog-schema --kind <canonical_id>`) — read-only: fetches and prints the verbatim bundled catalog `*.schema.json` body for a named block kind (the raw JSON Schema — `properties` / `definitions` / `$id`, not the `read-samples-catalog` projection), so the body is diffable locally against the installed `<substrate>/schemas/<name>.schema.json` without hunting through `node_modules`. Package-intrinsic (reads the extension's bundled samples catalog, independent of any project substrate); mutates nothing. An unknown kind is an error
107
109
  - `validate-block-items` (CLI: `pi-context validate-block-items --block <name>`) — read-only: validates a block's items against the catalog schema version (forward-migrating in memory when the block lags the catalog version) and returns `{ block, from?, to?, valid, failures[] }`, each failure naming the item id, field, and constraint; writes nothing. An unknown block or a missing installed block file is an error
108
- - `/context update [--dryRun]` (CLI: `pi-context update [--dryRun]`) — bring the installed schema model current with the catalog, routing each schema by its drift state: `in-sync` no-op; `catalog-ahead` resync (migration-aware); `locally-modified` / `both-diverged` reconciled by a deterministic 3-way merge of base (the as-installed body in the object store, keyed by the baseline `content_hash`) × ours (installed schema) × theirs (catalog schema) — disjoint edits auto-merge (`required` / `enum` / array-`type` nodes merge as sets), and a schema with irreconcilable per-path conflicts is left unmodified — the conflict set is returned in the op output (under `conflicts`) alongside a readable report, and the calling agent reconciles it then commits via `/context resolve-conflict` (below; no subordinate resolver is spawned). Update also additively propagates catalog-new config-registry entries (`relation_types` / `invariants` / `block_kinds` / `lenses`) absent from the config, preserving user-authored entries and any locally-diverged body of an existing entry (reported under `registryAdditions`). A version-bump `catalog-ahead` resync registers the shipped catalog migration chain's declarations into `migrations.json`; these are reported under `migrationsRegistered` (each `{ schema, from, to }`). A `catalog-ahead` schema whose resync is refused (`blocked`) carries its diagnostic under `blockedDetail` (one entry per blocked schema): the refusal reason — `no-migration-chain` (no shipped chain reaches the catalog version) vs `validation-failed` (the forward-migrated items fail the catalog schema) — the installed→catalog version pair, and for a validation failure the per-item failures naming the failing item id, field, and constraint. A live block also persists a pending-blocked record (`pending-blocked.json`, pinning the target catalog schema + the chain reaching it) consumable by `/context resolve-blocked` (below): fix the named items (or widen the local schema) then run it to commit the resolution so a subsequent `update` converges instead of re-blocking. A `validation-failed` block additionally gets git-style failure markers written INTO the block file at the offending items (full-line `<<<<<<< BLOCKED …` / `>>>>>>> target: …` sentinels), pinning the pre-marker bytes; the schema and `migrations.json` stay byte-unchanged, and `/context resolve-blocked` strips the markers before re-validating. `--dryRun` predicts the precise per-schema outcome (resync / migrate / block / merge / conflict) by running the forward-migration and re-validation in memory, alongside the per-blocked-schema diagnostic detail, the config-registry entries that would be added, and the migration declarations that would be registered, and writes nothing (no markers). Each auto-merged / resynced schema refreshes its baseline so a follow-up `/context check-status` reports it `in-sync`; a schema left as a `conflict` is NOT brought current by update — it stays unmodified until `/context resolve-conflict` commits the reconciliation
110
+ - `/context update [--dryRun]` (CLI: `pi-context update [--dryRun]`) — bring the installed schema model current with the catalog, routing each schema by its drift state: `in-sync` no-op; `catalog-ahead` resync (migration-aware); `locally-modified` / `both-diverged` reconciled by a deterministic 3-way merge of base (the as-installed body in the object store, keyed by the baseline `content_hash`) × ours (installed schema) × theirs (catalog schema) — disjoint edits auto-merge (`required` / `enum` / array-`type` nodes merge as sets), and a schema with irreconcilable per-path conflicts is left unmodified — the conflict set is returned in the op output (under `conflicts`) alongside a readable report, and the calling agent reconciles it then commits via `/context resolve-conflict` (below; no subordinate resolver is spawned). Update also additively propagates catalog-new config-registry entries (`relation_types` / `invariants` / `block_kinds` / `lenses`) absent from the config, preserving user-authored entries and any locally-diverged body of an existing entry (reported under `registryAdditions`). A version-bump `catalog-ahead` resync registers the shipped catalog migration chain's declarations into `migrations.json`; these are reported under `migrationsRegistered` (each `{ schema, from, to }`). A `catalog-ahead` schema whose resync is refused (`blocked`) carries its diagnostic under `blockedDetail` (one entry per blocked schema): the refusal reason — `no-migration-chain` (no shipped chain reaches the catalog version) vs `validation-failed` (the forward-migrated items fail the catalog schema) vs `write-failed` (a non-validation throw at the write boundary, e.g. the block writer's duplicate-item-id guard; the failures entry carries the thrown message, the items were NOT flagged invalid, and no markers or pending-blocked record are produced) — the installed→catalog version pair, and for a validation failure the per-item failures naming the failing item id, field, and constraint. A live `validation-failed` block also persists a pending-blocked record (`pending-blocked.json`, pinning the target catalog schema + the chain reaching it) consumable by `/context resolve-blocked` (below): fix the named items (or widen the local schema) then run it to commit the resolution so a subsequent `update` converges instead of re-blocking. A `validation-failed` block additionally gets git-style failure markers written INTO the block file at the offending items (full-line `<<<<<<< BLOCKED …` / `>>>>>>> target: …` sentinels), pinning the pre-marker bytes; the schema and `migrations.json` stay byte-unchanged, and `/context resolve-blocked` strips the markers before re-validating. `--dryRun` predicts the precise per-schema outcome (resync / migrate / block / merge / conflict) by running the forward-migration and re-validation in memory, alongside the per-blocked-schema diagnostic detail, the config-registry entries that would be added, and the migration declarations that would be registered, and writes nothing beyond the idempotent config-migration ceremony seed (no markers). Each auto-merged / resynced schema refreshes its baseline so a follow-up `/context check-status` reports it `in-sync`; a schema left as a `conflict` is NOT brought current by update — it stays unmodified until `/context resolve-conflict` commits the reconciliation. A run that refuses any schema while applying registry additions or other-schema resyncs/migrations/merges additionally reports the partiality under `partialApplication` (`applied`/`notApplied` mirrors of the result channels + a one-line summary naming what was applied alongside what was refused and why), so a blocked run never reads as a no-op; `--dryRun` reports the predicted partiality in the same shape. On a substrate whose config carries no `substrate_id`, a LIVE update establishes the identity at entry — mints (the same `mintSubstrateId` init uses), persists it through the sanctioned config write, and registers it in the project registry — before its first identity-stamping write, so a pre-identity substrate heals on the ceremony instead of refusing; the run reports it under `substrateIdEstablished`, an established identity is never re-minted, and `--dryRun` (no stamping writes) establishes nothing
109
111
  - `/context resolve-conflict --schemaName <name> [--schema <reconciled>]` (CLI: `pi-context resolve-conflict --schemaName <name> [--schema <reconciled>]`) — commit the reconciliation of a merge conflict `update` surfaced. Run after reconciling a `both-diverged` conflict: it writes the reconciled schema body (meta-validated, atomic) AND advances the merge base for that schema to the catalog body, so the next `update` sees the schema as `locally-modified` and its deterministic merge takes the reconciled body (base === theirs → ours) — auto-merging with zero conflicts and preserving the resolution. Without advancing the base a bare `write-schema` leaves the baseline on the original pre-conflict body and `update` re-derives the same conflict on every run. If `--schema` is omitted the current on-disk schema is treated as already reconciled and only the base is advanced
110
- - `/context resolve-blocked --schemaName <name>` (CLI: `pi-context resolve-blocked --schemaName <name>`) — commit the resolution of a schema `update` blocked. Run after fixing the block's failing items (or widening the local schema): when the block file carries git-style failure markers (written by `update`), it strips the full-line marker sentinels first, then re-validates the corrected block against the pinned target schema from the pending-blocked record (forward-migrating in memory through the pinned chain when the block lags the target version); on pass it registers the chain declarations, writes the target schema, advances the block's `schema_version` envelope and the merge base to the target (so a subsequent `update` converges in-sync instead of re-blocking), and clears the pending entry; on fail it returns the remaining per-item failures and writes nothing (the pending record and the marker file stay intact for a retry)
112
+ - `/context resolve-blocked --schemaName <name>` (CLI: `pi-context resolve-blocked --schemaName <name>`) — commit the resolution of a schema `update` blocked. Run after fixing the block's failing items (or widening the local schema): when the block file carries git-style failure markers (written by `update`), it strips the full-line marker sentinels first, then re-validates the corrected block against the pinned target schema from the pending-blocked record (forward-migrating in memory through the pinned chain when the block lags the target version); on pass it registers the chain declarations, writes the target schema, advances the block's `schema_version` envelope and the merge base to the target (so a subsequent `update` converges in-sync instead of re-blocking), and clears the pending entry; on fail it returns the remaining per-item failures and writes nothing (the pending record and the marker file stay intact for a retry). The commit itself is all-or-nothing: a throw partway through it restores every touched file byte-exact — `migrations.json`, the installed schema, the block file, `config.json`, and the pending record — and reports the failure, never a partial commit. On a substrate whose config carries no `substrate_id`, resolve-blocked establishes the identity at entry (mint + persist + register) before the commit's stamping write and reports it under `substrateIdEstablished`
111
113
  - `/context view <lensId>` — render a configured lens (groupByLens projection) into the conversation as markdown
112
114
  - `/context lens-curate <lensId>` — surface bin-assignment suggestions for uncategorized items as a follow-up turn; the LLM persists chosen edges via `append-block-item` against `relations.json`
113
115
  - `/context status` — derived project state (source metrics, test counts, block summaries, git state)
114
116
  - `/context add-work` — extract structured items from conversation into typed blocks
115
117
  - `/context validate` — cross-block referential integrity checks
116
- - `/context roadmap-list` — list every roadmap in `<config.root>/roadmap.json` (id, title, status, phase count)
117
- - `/context roadmap-view <ROADMAP-id>` render a roadmap as pure-textual markdown (phase order, per-phase adjacency from authored `phase_depends_on` edges, status rollup, milestone resolution; no mermaid)
118
- - `/context roadmap-validate [ROADMAP-id]` — validate every roadmap (or one) and surface structured issues
118
+ - `/context roadmap-view` — render the derived roadmap as pure-textual markdown (milestone order over authored `milestone_precedes_milestone` edges, per-milestone phase/task rollups, adjacency strictly from edges; no mermaid)
119
+ - `/context roadmap-validate`validate the derived roadmap and surface structured issues (error/warning/info codes; info never affects status)
119
120
  - `/context switch <existing-dir> | -c <new-dir> | -` — flip the bootstrap pointer (to an existing substrate, bootstrap-new-and-flip, or back to `previous_contextDir`)
120
121
  - `/context list` — enumerate top-level dirs containing `config.json` (switchable substrates); marks the active one
121
122
  - `/context archive <dir>` — move a non-active substrate dir to `archive/<dir>/`
@@ -1 +1 @@
1
- {"version":3,"file":"block-api.d.ts","sourceRoot":"","sources":["../src/block-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block-api.d.ts","sourceRoot":"","sources":["../src/block-api.ts"],"names":[],"mappings":"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"}
package/dist/block-api.js CHANGED
@@ -804,6 +804,31 @@ export function writeTypedFile(filePath, schemaPath, data, ctx, errorLabel) {
804
804
  toWrite = stampItem(data, ctx, "create", declared);
805
805
  }
806
806
  }
807
+ // Parse the supplied schema once — the version stamp below and the
808
+ // post-validation object persistence both consume it.
809
+ const parsedSchema = schemaPath
810
+ ? JSON.parse(fs.readFileSync(schemaPath, "utf-8"))
811
+ : null;
812
+ // Envelope schema_version stamp (TASK-073; the FGAP-105 fold-locus lands
813
+ // generically here so EVERY versioned-document write converges — block
814
+ // wrappers, whole-block writes, config, migrations.json all funnel through
815
+ // writeTypedFile). When the schema declares a top-level `schema_version`
816
+ // property AND carries a `version` string, the envelope is stamped to the
817
+ // schema's current version — overwritten, never passed through, so the
818
+ // persisted version is truthful by construction (an incoming stale version
819
+ // has already been walked forward by the caller's migration gate). Self-
820
+ // gating: a schema that does not declare the property (or has no version)
821
+ // leaves the data untouched, so substrates whose installed schemas predate
822
+ // the property keep writing unchanged until `/context update` lands it.
823
+ if (parsedSchema && toWrite && typeof toWrite === "object" && !Array.isArray(toWrite)) {
824
+ const props = parsedSchema.properties;
825
+ if (props &&
826
+ typeof props === "object" &&
827
+ "schema_version" in props &&
828
+ typeof parsedSchema.version === "string") {
829
+ toWrite = { ...toWrite, schema_version: parsedSchema.version };
830
+ }
831
+ }
807
832
  // Validate before write (if a schema is supplied)
808
833
  if (schemaPath) {
809
834
  validateFromFile(schemaPath, toWrite, label);
@@ -816,9 +841,9 @@ export function writeTypedFile(filePath, schemaPath, data, ctx, errorLabel) {
816
841
  // Gated on schemaPath: a schema-less write carries no identity items, and
817
842
  // the per-item content_hash check protects the non-stamping config/registry/
818
843
  // relations/migrations writers (their items carry no content_hash).
819
- if (schemaPath) {
844
+ if (schemaPath && parsedSchema) {
820
845
  const substrateDir = path.dirname(filePath);
821
- const schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
846
+ const schema = parsedSchema;
822
847
  forEachBlockArray(toWrite, (arrayKey, arr) => {
823
848
  for (const item of arr) {
824
849
  if (item && typeof item === "object" && !Array.isArray(item)) {