Spec Portable Continuity V2 Proposal - joeroberts/release-radar GitHub Wiki

Portable continuity V2 — proposal

Status: two owner-approved V2 choices; detailed design remains proposed, not delivered. Issue #281 owns this reconciliation and retirement of the old Git branch. It does not authorize product implementation, a format release, installation, or owner-data operations. Future implementation needs its own bounded ticket and authorization.

This is the canonical home of useful design from branch codex/phase7-portable-continuity-plan, commit a0f22d965395248be6ec5928d2932d3a7ce5166d. Its original design, implementation plan, ADR deltas and progress records remain recoverable in the repository's issue-281 Git bundle. This page retains the proposal; it does not promote old execution instructions or approval assertions into current authority.

Reconciliation with accepted decisions

The Wiki snapshot checked for this reconciliation is 1e6e8728ba4c810f2e8844d9c991745e0259b3bd. ADR inventory/baseline checks passed.

Material Current canonical basis Disposition
Complete project records, managed documents, evidence, stable domain identities and source history; fresh local capabilities ADR-013 and the full-product plan Continuing direction; this proposal supplies possible encoding, recovery and delivery details.
Legacy V1 and Rekon seed compatibility, no live collision, exporter-produced acceptance fixture ADR-012 and ADR-004 Preserve existing semantics. Do not silently upgrade V1 or call a partial seed a complete package.
V2 restores lanes/readiness/accepted outcomes instead of converting to Backlog Owner approved this V2 choice on October 16, 2026; current ADR-004 still records Backlog conversion and separate V2 approval Record the V2-specific decision through the ADR process before dependent implementation; preserve V1 and seed semantics.
V2 document/evidence content roots work without a checkout; checkout association is a separate explicit action Owner approved this V2 choice on October 16, 2026; current ADR-013 requires fresh root mapping but does not record this exact capability split Record the V2-specific capability separation through the ADR process before dependent implementation.
Schema/model coverage and proposed file paths Original design baseline: PR #48 plus 149fdfd516dc3604ecf3641b01bf5fc25bbb79b4, schema 26 Historical inventory, not a current completeness claim. Reconcile every later supported domain before fixing a model version or generating the acceptance fixture.

The owner has resolved the two V2 choices below. The accepted ADRs are unchanged; their formal reconciliation remains before dependent implementation. Settled complete-package inclusion is not reopened. The October 16 owner direction, recorded under #281, is the approval basis; old branch approval assertions remain historical provenance. The conditional implementation plan retains the ADR and current-model prerequisites. All encoding, limits, storage changes, recovery protocols and UI choices below are proposals pending that reconciliation and a current source assessment.

Complete outcome and boundaries

An owner exports one supported project's complete recorded delivery graph, managed documents, local evidence bytes and source history. On another Mac, the installed app previews that same package, obtains fresh destination permissions, and imports a complete usable project with unchanged domain identities and honest historical context. The authoritative exporter produces the fixture before any importer implementation. A successful import is neither a checkout nor evidence that old work executed on the destination.

Include all supported roots, current and superseded records, recorded revisions, accepted outcomes, task plans, source references, proposal history and evidence provenance. Never truncate, downgrade or quietly omit required content to make an export succeed. A project can be active or archived; an archived source stays archived. Removed operational graphs cannot be reconstructed from retained history alone; export of a removed project fails with that explicit explanation. Re-added registrations never inherit unrelated removed registrations' history.

Exclude source-code checkouts, Git objects, credentials/Keychain, bookmarks and other device permission grants, observer connections, executable command receipts, notification queues, plugin installation state, workspace queries/preferences, and session navigation. Free-text project documents and history are owner content, not instructions; export does not execute or inspect them for embedded commands. No cloud/mobile publication, run host, live provider retrieval or unrelated feature is added. Full local backup remains separate and continues to include workspace saved queries. A complete package is not a full application backup.

Recorded branch selections requiring reconciliation

The owner approved both recommendations on October 16, 2026 and requested the V2 label. These choices concern RR's product import/export feature. Development of Release Radar itself continues through GitHub issues, Git and ordinary Codex chats; this approval does not adopt RR's product harness or managed workflow.

  1. V2 decision 1 — preserve formal project state (owner approved). Preserve lanes, unassigned/null placement, phase lifecycle, readiness/revisions, accepted goals/tickets, task completion and source provenance. Destination validation separately gates new execution. Its rejected alternative was Backlog conversion, which would not provide lossless formal-state continuity. V1 and Rekon seed semantics stay intact.
  2. V2 decision 2 — content access independent of a checkout (owner approved). Use new, explicitly authorized content folders for document/evidence reading, with source primary/worktree relationships retained only as history. A later explicit owner action associates a separately verified checkout. The narrower alternative requires a destination checkout before import and therefore limits immediate document/history continuity. Fresh destination permissions and verified checkout association remain prerequisites for new execution; Git worktree membership checks remain intact.

The branch names parent task 01a07e75-b254-72a1-be2a-3e97ac23baeb as the source of its September 11 selections. That reference and the original amendment bytes are recoverable evidence. The fresh October 16 owner approval resolves these choices for V2; it does not accept every detail of the following proposal or authorize implementation. Formal ADR reconciliation remains a prerequisite.

Package encoding and validation

Recommend a directory package with extension .release-radar-project, containing manifest.json, records.json and payload/<slotID>/<relativePath>. No ZIP, script, SQLite image, symlinks, hardlinks, resource forks, executables or nested archive extraction is needed. File bytes are copied as inert regular data; executable bits, ownership and xattrs are not restored. File type does not authorize opening content.

Manifest fields are fixed: format = com.rekonlabs.release-radar.project-package, schemaVersion = 2, packageID (UUID), createdAt, producer (bundle ID, app/build, source store schema), modelVersion = 1 for the schema-26 domain contract, projectID, rootSlots, records (path, byte length, SHA-256), files (slot, relative path, byte length, SHA-256, inclusion reason and evidence/artifact identities), and exclusions. Every required model section exists even when empty. These archive hashes protect transport bytes; they do not add checksum policy to mutable repository documents. Hashes prove integrity, not origin, trust or approval.

A slot has an opaque package-local ID, source root ID, source role (primary/worktree/content), optional repository identity, and the exact catalog snapshot(s) needed by that root. IDs and source roles are provenance; paths and bookmarks are absent from operative root mapping. No importer derives a destination from source paths. Source root IDs embedded in historical evidence remain unchanged; a separate mapping identifies the new local content root. Retain nested historical payloads, source digests and any recorded path text unchanged as inert source data, never as a filesystem locator or newly valid baseline.

Recommended finite v2 bounds: 64 root slots, 10,000 payload files, 32 MiB per file, 256 MiB aggregate payload, 32 MiB records, 4 MiB manifest, 100,000 aggregate record rows, nesting depth 32 and path length 1,024 UTF-8 bytes. Catalogs retain the tighter existing RepositoryDocumentContract.Limits wherever applicable. Enforce counts and byte budgets while reading, before allocation; stream payload copying/hashing. Limits appear in preview errors and Help. A larger project fails explicitly; raising supported limits requires a versioned, tested capability change.

Strict decoding rejects duplicate and unknown keys at every structured level, unsupported versions/features/enums, duplicate IDs or logical edges, malformed UTF-8, nonfinite/overflow values, invalid dates, invalid revisions and dangling or cross-project references. Do not rely on Codable alone to reject duplicate keys. Validate the supported complete graph, dependency cycles, uniqueness/cardinality, retirement/obligation lineage, task ordering and supersession, and acceptance/ readiness invariants, including permitted legacy unknown states. Arbitrary SQL, opaque unknown future model sections and silent lossy decoding are forbidden.

All paths are relative POSIX components; reject absolute paths, empty components, ./.., NUL/control characters, backslashes, reserved package metadata collisions, and normalization/case aliases on the destination filesystem. Enumerate the package exactly; reject extra files, missing files and payload/index mismatches. Open source and destination components without following links and use retained descriptors with pre/post identity checks. Reject hard-linked payloads and aliased destination roots. No path-string precheck followed by unchecked URL writes.

V1 .release-radar-project.json remains distinct. It cannot be upgraded by guessing missing goal/task/document/history sections. The new import UI identifies it as legacy/incomplete and explains that a fresh v2 export is required for complete continuity. Do not silently change any existing v1 or Rekon seed path. Future model additions extend package support and round-trip tests together, or the exporter rejects that unsupported state. Store version is diagnostic; model version and validated fields define interoperability.

Historical schema-26 coverage to reconcile

The original candidate described a domain snapshot, not a raw database dump. Its source anchors were StoreMigrations.swift, the corresponding models and existing app-owned queries. Arrays preserve record values, nullable fields, exact IDs, ordering and revisions. No UI projection with pagination or missing domains is an export source.

Recorded family V2 representation and restoration
projects, project_active_phases, phases, tickets, phase/ticket dependencies Project name/domain ID and lifecycle; exact active phase and graph; nullable unassigned ticket phase/lane; all five persisted lanes/outcomes and legacy-continuation provenance. First-dashboard marker resets locally.
project_registrations, roots, bookmarks, documentation bindings Source registration/generation/setup facts retained as provenance; root slots and accepted catalog snapshots/repository identities preserved. New registration/generation/root IDs and fresh bookmarks created locally; capabilities never copied.
phase_plans, Delivery Goals, done criteria, assignments and assignment events Preserve state, revision/ready revision, timestamps, criterion order, acceptance/supersession and event-to-source-audit links. No new acceptance or Ready inference.
ticket_task_plans, ticket_tasks Preserve plan revisions, stable IDs/labels/order, definitions, active/superseded state, completion and timestamps; an empty explicit plan differs from absent plan. Phase 6D adds guidance/inventory, not a second adoption database.
Blockers, review items, completion records Preserve resolved/status fields and event records, including dismissed/resolved history and ticketless review items. Import itself creates no Needs Review item.
Observed threads/goals, exclusions, thread and ticket-goal links Preserve exact project/thread/goal identities and existing 1:1 relationships, observation times and text/status, completed/unlinked observations. All arrive historical; no auto-discovery, connection or goal completion.
Located evidence Managed locator retains artifact ID and repository/root context; legacy file locator becomes explicit slot-relative mapping. Preserve ticket association and bytes; cached availability is discarded and recomputed.
Ticket reference sets/links/versions Preserve link-set revisions, requirements/decision kind, relationship/retirement, source-local ID/locator, artifact identity, exact recorded digest/catalog/version/path/lifecycle/authority. Current bytes never substitute for an older referenced revision.
Plan proposals/versions/decisions/applications Preserve full versioned baseline, operations, diff, impacts, rationale, decision/disposition and application/audit links. Old registration-bound approval is historical and cannot be applied. Refresh creates a new destination baseline/version and requires a new owner decision.
Ticket retirements/successors; goal obligations/lineage/drops Preserve all edges, scope, assessment, reasons, source audit links and timestamps. Accepted predecessors remain immutable and carried obligations do not duplicate credit.
Phase lifecycle records/events Preserve unassessed/upcoming/in-delivery/completed, revisions and completion baselines, transitions and source registrations. Import does not reopen or complete a phase.
Delivery evidence sets/targets/observations Preserve every target version, current-target pointer, set/append revisions, repository/root/commit/dirty snapshot, expectations, typed facts/source/outcome, times, attachments and supersession. Imported observations are historical; matching bytes do not prove destination tests/build/installation.
Source audit/activity and notification history Preserve source namespace/ID, event-time facts, occurrence/observation/recording times, attribution and unknown legacy values. Terminal send results and pending/unknown send facts are historical records only. No send attempts, dedup queue or command receipts become actionable.
Previously imported provenance and associated retained history Preserve origin namespace and import lineage without relabelling source history as local or duplicating events. Include only history explicitly belonging to the exported project/registration lineage; never collect unrelated removed registrations by name/path/domain-ID guess.
Workspace search preferences/saved queries; navigation/health caches Excluded local preferences and derived state under Phase 6E. History/search projections are rebuilt from imported records with exact identities, fresh access and explicit incomplete states.
Alert rules, notification occurrences/queues, agent-command requests, plugin lifecycle, recovery/removal authorization Excluded local configuration/authority. Meaningful source send/audit outcomes remain inert history above; request bodies/results are not imported as executable receipts. New import gets its own local receipt.

The inspected schema-26 store had immutable-audit foreign keys (assignment and application history among them). Implementation must add a narrow source-history namespace and explicit local-versus-imported event references. Do not manufacture audit_events rows labelled locally executed to satisfy those foreign keys, globally relax audit triggers, or remap source audit IDs to an unrelated destination audit. Proposed storage: project-owned portable origin/import receipt and source-event tables, plus a local/source event-reference discriminator for affected history edges. Migrate existing rows to local references without rewriting event contents; validate existing and imported edges through the appropriate namespace. Source history remains immutable. All new provenance must participate in archive/removal retention, full-backup recovery, History and Search from its first shipping slice.

Self-contained content and catalog authority

For every supported root, capture its required managed catalog and indexes, all catalogued extant documents/assets regardless of active/archive lifecycle, required checksum manifests and all referenced local evidence. Include the root AGENTS.md when required by the managed documentation contract as inert document content; it cannot govern the importer. Source-code checkout files and .git are never recursively copied. A root with no managed binding can carry legacy local evidence, but export must not invent a catalog or call it managed-current.

For a bound root, require a valid current catalog matching the accepted snapshot and valid indexes before complete export. A pending/invalid catalog, missing required artifact, lost permission or unsafe evidence path blocks export with exact root/artifact recovery guidance. Preserve retired artifact IDs, supersession and accepted snapshot bytes/digest. Retired tombstones with no extant payload are metadata, not missing required files. Historic reference digests whose old bytes were never retained stay explicitly unavailable historic revisions; never claim the package reconstructs unrecorded past bytes. Export includes all extant required content; unavailable current required content cannot be downgraded to a warning.

Legacy evidence outside authorized supported roots fails with a precise unsupported locator. Do not infer another root, request broad disk access, fetch a URL or follow a link. Overlapping source roots with ambiguous file ownership also fail; resolve root membership through the existing owner workflow first. A payload referenced by multiple logical records within one slot is copied once and retains every edge.

The source accepted snapshot is provenance. Import independently validates the materialized destination catalog/indexes/checksums and presents exact repository, version/digest and root mapping for explicit owner acceptance. Confirmation combines that explicit new destination binding/acceptance with the import transaction; mere package selection grants neither. If the source had no binding, preserve that unmanaged condition and use existing setup later. Freshness and evidence resolution are recalculated only under fresh destination access. Content digest equality does not imply approval of document prose or installed code evidence.

Export consistency and destination preparation

Exporter owns a single app-store snapshot of every included domain and a scoped fingerprint of that complete snapshot. Copy files under retained source permissions into an adjacent private temporary package. Record descriptor identities and hashes; recheck all copied content, catalogs and root/registration state against the snapshot before finalization. If any included state changes, abort without a success package and invite a new export. This is bounded optimistic consistency, not a claim of a filesystem/database distributed snapshot. Unrelated project writes do not invalidate export. Serialize its final validation/publication with app-owned mutations of this project. External races must be detected with file checks.

Preview lists graph/history counts, roots, files/bytes, exclusions and blockers. The owner chooses the output parent and a new unused package name. Publish with an exclusive no-replace operation only after validation; never overwrite an existing package. Cancellation leaves no completed package. An app-owned temporary package may be retained for recovery; identify it honestly rather than claiming success. The source graph and source documents are unchanged by export, apart from an explicitly documented local export audit if selected by the writer's owner action. The exporter fixture snapshot boundary precedes that destination-only receipt/audit.

Importer preview is read-only. It hashes the exact bounded package, checks graph and content, and obtains owner selections for each distinct destination parent and new child folder. Materialize only new child folders owned by this operation; never merge into an existing folder or overwrite an owner file, even byte-identical. Permit parents on separate supported local volumes. Refuse network/nonlocal volumes or filesystems without the required exclusive rename and durable-write semantics; state the limitation before confirmation. Do not promise atomic multi-volume rename.

Mapping must cover every slot exactly once, preserve one primary content slot, and reject same/ancestor/descendant destinations, source/package overlap, existing registered ownership, pre-existing final paths and case/normalization collisions. Bookmarks authorize exact resolved parents for staging and fresh final roots after materialization. They are new destination grants, never decoded package data. Source primary/worktree role does not become current root capability.

Coordinated file/store commit and recovery

One app-owned coordinator serializes import and project lifecycle/recovery changes. The package digest, complete mapping, new registration, exact operation/request ID and confirmation digest form the replay identity. Changed preview input, parent identity, permission, catalog or store collision requires a new preview; unchanged uncertain outcomes query/retry the same receipt. Recovery never creates a second project or silently selects new paths.

  1. Revalidate source bytes, graph, every destination and live same-table/domain-ID collision immediately before apply. Historical event IDs use their source namespace; live project/entity collisions reject. A retained registration is never resurrected or treated as the new import registration.
  2. Persist a local durable import journal before creating staged roots. It records exact operation identity, digests, destinations, parent descriptors' identities, ownership tokens and intended fresh registration. Keep source history separate from this local recovery state. Retain access for the operation; after restart unavailable permission requires exact-folder reauthorization.
  3. Stage all payloads beside their final new folders on their respective volumes. Validate bytes, catalogs and destination spelling; flush files/directories and journal transitions. Use exclusive creation and ownership tokens. Nothing is yet registered or visible as a project.
  4. Exclusively rename every staged root to its final unused name, journalling each move. Until all roots and bookmarks validate, no operational project is committed. Partial file placement is recoverable temporary work, never a partial project.
  5. In one DeliveryStore transaction, recheck collisions/authority, insert the whole supported graph and immutable source provenance, new registration/content-root associations/bookmarks, explicit destination binding/acceptance, import receipt and one real owner import audit. Commit only after all final payloads validate. Do not invoke normal commands row by row or replay notification-producing events.
  6. Mark the journal committed. Publish the project to app readers/services only after receipt and filesystem readback agree. Initialize imported observations as historical and observation/notification admission as inactive. Completed import is returned once; later retries return its receipt without replay.

On failure before the store commit, no project exists. Keep operation-owned roots quarantined and offer Resume or Cancel with an exact retained-file list. Recovery may move unchanged operation-owned finals back to their recorded staging names with exclusive, descriptor-verified operations. It never removes/replaces an owner file. If ownership/digest changed or permission is lost, preserve content and show Recovery Required; no normal service may adopt the partial state. Cancellation ends admission; deleting retained temporary files is a separately explicit action.

A crash after DB commit but before journal completion is resolved from the committed receipt: verify all roots, finish local bookkeeping, and return the same result. If committed content is inaccessible or changed, hold that imported registration in recovery, not normal monitoring, and offer exact access repair. Do not roll back a committed graph by deleting owner content. Startup recovery runs before imported project services; unrelated projects can remain available. Full reset/restore/removal cannot race the journal and must explicitly reconcile or block pending operations. Full backup must reject an in-flight import rather than capture half a journal; an idle completed import's graph/provenance remains part of ordinary full backup.

Imported authority, continuation and UI

Imported acceptance and completion are supported historical formal state, not a new local acceptance action. Preserve existing legacy-continuation provenance without granting a new migration exemption. requiresDestinationValidation is a local admission condition for imported registrations, separate from lane, phase plan and lifecycle. Every mutation/observer/notification entry point checks current registration and capability purpose. Legacy root-only commands cannot target an imported registration; source registrations/generations never satisfy destination requests. Archived imports additionally remain subject to archive restrictions.

Document/evidence reading becomes available once import commits and fresh root validation passes. Execution resumes only through an explicit owner checkout association/revalidation action: check the chosen repository identity and normal Git worktree membership, current registration, accepted documentation and required local evidence. It does not infer a checkout from the imported root's former role. Normal readiness/dependency/goal/task/Accepted/Completed guards still apply. Old approved-but-unapplied proposals require a new baseline/version and decision. Old check/build/installation observations remain historical until a new explicit current target/observation establishes applicability; no network revalidation occurs here.

Fresh observer admission starts a new baseline that suppresses historical terminal observations and existing attention conditions. Only newly admitted post-import occurrences may create new notifications under existing rules. Imported queued, sending and unknown send records remain immutable source facts and can never be retried. Refresh, relaunch, Help and History navigation perform no mutation replay.

Use the existing Projects/Project Overview action area for Export Project and Import Project, with Settings recovery linking to the same flow. The inspected Settings reference supplies section cards, spacing, contrast and action hierarchy; History supplies source-history detail. These screenshots do not depict a portability wizard. The proposed staged sheet is a necessary new flow, not a claimed pixel reproduction or a new navigation shell.

Export steps: choose project, inspect contents/blockers, choose new output, confirm, then show exact completed package or recoverable failure. Import steps: select package, inspect contents/source history, map roots, review collisions and explicit catalog acceptance, confirm, then show the imported project with “Historical source state” and “Checkout association required” where applicable. Cancellation remains available before commit. Recovery shows exact affected root and Resume/Cancel/access repair; never a generic infinite spinner. Invalid input presents zero mutations, not partial success. Large inventories scroll with stable selection and keyboard focus. Labels name the exact project/registration and root role. VoiceOver announces progress, blocking reasons and completion. Buttons remain reachable at compact width; color alone never expresses availability or historical/current distinction.

This reconciliation did not run an app, exporter, importer or installed acceptance. Implementation must compare native wide/compact UI and keyboard/AX behavior with the references; the full installed round-trip strategy is in the conditional implementation plan.

⚠️ **GitHub.com Fallback** ⚠️