v0.31.9 — Recursive Journey Hierarchy
Date: 2026-08-14
Highlights
- Allows journeys to form organizational trees of arbitrary depth using the
existingparent_journeymetadata contract, with no schema migration. - Rejects direct and indirect cycles before mutation and keeps malformed legacy
cycles bounded on read surfaces instead of hanging. - Renders the complete hierarchy recursively in
mm-journeys, Workspace
navigation, Current Scene, All Journeys, and journey selectors. - Shows complete root-to-selected lineage while keeping conversations, memories,
tasks, attachments, routing, Builder state, and Scene movement exact to each
journey. - Preserves stable journey ids and independent
project_pathvalues when a
journey or subtree moves; no filesystem content is inferred or moved. - Makes removal fail closed: parents with children and leaves with associated
records are refused in one transaction; only empty leaves can be removed. - Establishes a moving-target TypeScript strangler contract: Python may evolve
while it remains authority for an unported command, and each change becomes
explicit TS parity scope before authority transfers.
Where We Started
CV15 originally shipped a deliberately small one-level hierarchy. That was enough
to prove that parent-child relationships could organize the journey field without
merging context, and Current Scene then used that map to return cognitive
location. Real use exposed the remaining artificial boundary: life areas,
businesses, products, and projects naturally form deeper structures, while Mirror
refused a child beneath an existing child.
The TypeScript strangler introduced a second tension. Its original policy froze
new Python features so the migration target would stay stable. The principle was
coherent, but the migration is a long-running background effort; in practice the
freeze required product evolution to wait months for TS sequencing.
What Changed
JourneyService now validates a proposed parent by walking the complete ancestor
chain. A journey may sit at any depth, including beneath a node that already has
children. Reaching the journey itself rejects the move as a cycle; encountering a
pre-existing cycle rejects extending malformed ancestry. Reads track visited ids,
so corrupt rootless cycles remain visible and bounded.
Journey options carry depth and complete lineage. The textual journey list,
Workspace tree, Scene map, All Journeys view, and selection controls render
recursively. Selecting a deep node opens its full ancestor chain. Current Scene
returns the complete lineage and only immediate siblings, while all movement and
content queries remain scoped to the exact selected journey.
Movement changes only the moved node's parent_journey. Regression coverage and
an isolated smoke prove that identity ids and project_path values remain stable.
No directory is created, renamed, moved, or removed.
Removal gained a conservative domain operation without a public UI. Storage uses
an immediate transaction to check child journeys and every known associated
record before deleting the identity. This closes the check-then-delete race and
prevents implicit reparenting, orphaning, and cascades.
Navigator homologation created a third-level journey through ordinary Mirror
conversation. It also exposed a presentation defect: deep leading-space
indentation crossed Markdown's code-block boundary. Text trees now use
column-zero │ connectors at every depth, with regression coverage preventing a
return to fenced output.
Finally, the migration policy now transfers authority command by command. Python
continues to evolve where it still serves the product; CV22 must absorb the
current observable contract before claiming parity. Recursive journey reads are
assigned to CV22.E2.S5, and writes plus removal semantics to CV22.E4.
Conscious Exclusions
- No inherited context. Parentage does not merge documents, memories,
conversations, tasks, attachments, instructions, status, routing, search, or
Builder state. - No filesystem synchronization. Paths do not infer parentage, and parentage
does not create or move directories. - No automatic reparenting or cascade. Removing a parent with children is a
simple refusal. - No public journey-removal UI. The domain operation exists, but irreversible
user-facing removal requires separate product work. - No simultaneous TypeScript implementation. Parity obligations are explicit
in CV22, but this patch does not duplicate the feature before the relevant TS
read/write foundations exist. - No hierarchy watchers, aggregate status, or structural auto-repair. The
capability remains a simple organizational tree.
What We Learned
A stable migration target is valuable only while it does not make the product
stand still. The safer long-running strangler is not one with no drift; it is one
that makes drift explicit, captures observable contracts, and transfers authority
at clear command boundaries.
The homologation also reinforced that recursive behavior must be validated at the
rendering boundary, not only in the data model. The hierarchy was semantically
correct while Markdown made its deepest node look like code. Normal conversational
use found what green service tests could not.
Next Horizon
CV22 must absorb recursive journey behavior before its read and write commands
claim authority. Public journey removal may later build on the conservative
domain operation, but only with an explicit interaction and recovery design. The
product can now gather real evidence from deeper journey organization without
waiting for either horizon.