diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index a7eb5a3..85e8460 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,80 +1,78 @@ -# Workstream 3 Implementation Plan +# Workstream 4 Implementation Plan ## Purpose And Status This is the executable plan for [`refactoring.md`](refactoring.md), Workstream -3: **Canonical contracts and compatibility purge**. Finding 1 of -[`contract-audit.md`](contract-audit.md) and rows C01/H43 of -[`audit-decisions.md`](audit-decisions.md) own the approved decisions. +4: **One durable local manifest authority**. Finding 2 of +[`contract-audit.md`](contract-audit.md) and rows H14, H15, H17, C02, and C03 +of [`audit-decisions.md`](audit-decisions.md) own the approved decisions. -All seven stages are complete. Workstreams 1 through 3 are complete. -Workstreams 4 and later remain out of scope for this completed plan: it did not -remove the run manifest, redesign runner lifecycle, change analyze checkpoint -timing, replace locks, decompose publish, or add cleanup. +All five stages are pending and must be implemented in order. Each stage is +bounded for one `gpt-5.6-terra` prompt. Workstreams 1 through 3 are complete. +Workstreams 5 and later are out of scope: do not decompose the runner into a +new lifecycle type, redesign pre-execution decisions, add per-artifact analyze +checkpoints, split publish into separate transactions, add cleanup as a stage, +or change remote lock policy while following this plan. ## Settled Implementation Decisions -- Delete deprecated representations rather than renaming, wrapping, or - preserving them behind an internal compatibility facade. Historical releases - and completed audits remain unchanged. -- Give both currently persisted local JSON manifest types an explicit required - `schema_version`: `narratio.session-manifest.v1` for `Manifest` and - `narratio.run-manifest.v1` for `RunManifest`, with discoverable constants - in package `manifest`. Constructors set it; save and load validate it; - neither path fills in a missing or unsupported value. Workstream 4 may later - delete the versioned run-manifest model. -- Loaded current state may not acquire required schema, stage identity, stage - records, or analyze authority through normalization. Representation- - preserving normalization may remain. -- Every newly created `analyze` stage record in either manifest uses - `AnalyzeStateContractVersion`. An empty collection is valid current state. - Version zero, an unknown version, or aggregate-only authority is rejected. -- The only party input is a strict `narratio.party.v1` document selected by - required, campaign-owned `campaign.inputs.party_file`. Remove unversioned - parties, `campaign.inputs.players_file`, `session.inputs.players_file`, - and `session.inputs.party_file`; strict YAML decoding rejects those keys. -- Players remain the deterministic `narratio.players.v1` projection generated - from the party. Keep that prepared input, semantic identity, Notarius - reference role, and operator visibility; it is never separately configured. -- Simplify party runtime data to a canonical party and source provenance. - Remove `PartyMode`, both mode constants, the compatibility-only - `PartyDocument` shell, and `party_legacy.go`. `ParseParty` returns the - canonical representation directly. -- The only remote current selector is versioned `current/commit.json` and its - verified immutable commit. Pointer absence returns a typed - current-commit-pointer-missing error with publish/republish guidance. Do not - inspect `current/run_id.txt` or `current/manifest.json`. -- Successful current-state loads always contain a validated non-nil pointer, - commit, and committed session manifest. Keep `CurrentPointerKey` and the - immutable manifest key; remove legacy key names and duplicated fields. -- Restore uses only objects declared by the selected commit and never lists a - session prefix to reconstruct a snapshot. Preserve committed verification, - manifest-last installation, conflicts, and root-scoped safety. -- Previous-session hydration resolves each requested source exactly once from - the commit's unique `published_output` declaration. Derive its relative - destination from that declaration's immutable destination key. Do not consult - current config or previous-manifest outputs for alternate paths and do not - issue candidate `Exists` calls. -- A built-in artifact is authoritative only when its succeeded producer stage - has exactly one output matching registered source and kind, with safe path, - producer run ID, and checksum. Verify checksum and content. Remove canonical- - path and filename fallback; disk bytes alone never establish availability. -- Analyze authority comes only from the current versioned `AnalyzeArtifacts` - collection. Preserve fingerprints, dependencies, selection, force behavior, - and existing session/run projections until their later workstreams; remove - only aggregate-only and incidental-file compatibility here. -- Extraction availability continues to require current input and receipt - identity, canonical immutable paths, a complete configured source set, - checksums, contracts, and Notarius provenance. The manifest schema boundary - rejects older records; add no extraction migration reader. -- Unsupported state errors identify the missing/received and supported version - and provide concise migration guidance. Tests assert error categories and - small stable fragments, not full prose. -- Current docs must direct operators to replace legacy party config, move aside - and regenerate unsupported local state, restore a current committed snapshot - when authoritative, or republish healthy local state. Do not rewrite - historical documents. -- Mark only Workstream 3 `Complete`, and only after all stages and final +- The session manifest is the only durable local progress ledger. It alone + records stage status, current artifacts, semantic evidence, diagnostics, + failures, resume authority, restore authority, and publish authority. +- Delete the structured invocation run manifest completely: its schema and + types, store interface and methods, path helper, lifecycle mutations, + terminal recovery, analyze projection, publish dependency, fixtures, tests, + and current documentation all leave the repository. +- Do not replace it with another JSON summary, journal, database, or event log. + Historical per-invocation state is not an operational requirement. +- Preserve run IDs. Every invocation still receives one before session state is + initialized; it remains the identity used by the session manifest, + run-local directory, adapter provenance, logs, generated configuration, + receipts, immutable publish prefix, command summary, and diagnostics. +- Explicitly create the canonical run directory once per invocation after the + session lock and identity checks. Removing the initial run-manifest save must + not make diagnostic writers responsible for accidentally creating the run + root. Directory-creation failure remains an invocation initialization error. +- `RunSummary` remains the immediate in-memory command result and retains + session ID, run ID, session manifest path, selected stage names, executed + stages, and skipped stages. Remove only `RunManifestPath`; do not add a + replacement persistent summary. +- A run-manifest write can no longer fail an otherwise valid pipeline action. + Session-manifest transition and terminal-save failures remain correctness + failures and continue to join with the originating error where applicable. +- Publish no longer opens or validates `runs//manifest.json`. When + `upload_run` is enabled, it derives the current run root canonically and uses + the session manifest's recorded output, log, and generated-configuration + references as an allowlist. It includes only safe regular files confined to + the current run root and ignores records from earlier runs. +- New remote commits do not upload or classify a run manifest. Keep + `RemoteArtifactTypeRunManifest` as a read-only wire value so already committed + and verified remote snapshots remain readable; it must have no local loader, + path, special publish branch, or newly emitted declaration. This preserves a + durable remote protocol without retaining the local dual-authority model. +- Preserve `RemoteArtifactTypeRunFile` for declared run-local diagnostics. + Publishing no current-run diagnostics is valid and must not require a + placeholder file. +- Remove the invocation subset from `AnalyzeStateProjection` and from analyze + execution. During this workstream, analyze still returns and persists one + validated reconciled session collection at the existing end-of-stage + boundary. Do not implement artifact-by-artifact persistence yet. +- Preserve the current safe behavior when the end-of-stage analyze manifest + save fails: incidental output bytes do not establish authority, prior + in-memory analyze authority is restored, and the aggregate stage fails. + Workstream 6 will replace this with the approved checkpoint model. +- Preserve current stage ordering, force/invalidation rules, self-skip behavior, + aggregate transition timing, cleanup obligations, remote commit ordering, + and command output except where they directly expose the removed run + manifest. +- Delete tests whose only contract is historical run-manifest persistence. + Rewrite mixed tests around session state, command summaries, run-local + diagnostics, or remote commit contents, and consolidate redundant mechanism + assertions rather than recreating a second audit record in tests. +- Historical release notes and completed audit documents remain unchanged. + Current architecture, CLI, operations, troubleshooting, and internal + documentation must describe session-only authority. +- Mark only Workstream 4 `Complete`, and only after all stages and final validation succeed. ## Instructions For Every Stage @@ -82,334 +80,316 @@ timing, replace locks, decompose publish, or add cleanup. Before each stage: 1. Read `docs/development.md`, every file under `docs/policy/`, this plan, - Workstream 3 plus dependency/target sections of - [`refactoring.md`](refactoring.md), Finding 1 of - [`contract-audit.md`](contract-audit.md), and rows C01/H43 of + Workstream 4 plus the dependency and target sections of + [`refactoring.md`](refactoring.md), Finding 2 and the Workstream-4-relevant + boundary in Finding 3 of [`contract-audit.md`](contract-audit.md), and rows + H14, H15, H17, C02, and C03 of [`audit-decisions.md`](audit-decisions.md). -2. Inspect named implementation and focused tests. Prefer the codebase graph for - Go discovery and text search for fields, fixtures, examples, and docs. -3. Confirm worktree state and preserve unrelated changes. Do not enter a later - workstream because adjacent code would also benefit. +2. Inspect the named implementation and focused tests. Prefer the codebase + graph for Go discovery and text search for schemas, paths, fixtures, + documentation, and serialized field names. +3. Confirm the worktree state and preserve unrelated changes. Do not enter a + later workstream merely because adjacent lifecycle, analyze, publish, or + cleanup code would benefit from broader refactoring. During every stage: -- Keep the repository building and focused tests passing. Temporary current-only - migration structure is allowed only when a later stage explicitly removes - it; add no compatibility shim or automatic migration reader. -- Preserve package ownership, strict deterministic decoding, group workspace - behavior, bounded I/O, secret redaction, remote verification, restore safety, - and Linux/macOS/Windows support. -- Keep tests offline and behavior-focused. Delete tests only with their retired - contract. Update canonical current-behavior docs with the code change. -- Run `gofmt` on changed Go, focused tests, and `git diff --check`. Mark a - stage `Completed` only after all exit criteria pass. +- Keep the repository compiling and focused tests passing. A temporary + invocation projection or unused run-manifest domain type may remain only + when the next numbered stage explicitly removes it; do not introduce a new + compatibility facade. +- Preserve package ownership and acyclic dependency direction. Keep this a + deletion-oriented refactor inside the existing `app`, `stage`, `manifest`, + and `artifacts` owners. +- Preserve the session lock, session-manifest atomic replacement, group + workspace modes, bounded I/O, no-follow publish sources, remote verification, + secret redaction, and Linux/macOS/Windows support. +- Update the canonical current-behavior document owned by a change in the same + stage. Do not edit historical release notes or completed audit findings. +- Keep tests offline, deterministic, and behavior-focused. Remove tests with + the retired contract and retain consequential session-state, data-integrity, + recovery, and remote-commit coverage at the narrowest stable boundary. +- Run `gofmt` on changed Go files, focused tests, and `git diff --check`. Mark a + stage `Completed` only after its exit criteria pass. -## Stage 1 — Establish Explicit Current Manifest Schemas +## Stage 1 — Decouple Publish From The Run Manifest -**Status: Completed** +**Status: Pending** ### Goal -Create an unambiguous local-state boundary before removing downstream legacy -branches. +Make publish consume only the session manifest and current run directory so the +runner can stop producing a structured run manifest without losing useful +diagnostic uploads. ### Required Work -1. Add the settled schema constants and required `schema_version` fields in - `internal/manifest/manifest.go` and `run_manifest.go`; set them in - `New` and `NewRun`. -2. Require exact versions in `LocalStore.Save`, `LoadReader`, `SaveRun`, - and `LoadRunReader`. Missing/unknown versions return a clear migration - error. Saving a hand-built zero-value manifest fails rather than backfilling. -3. Require a non-nil stage map; reject nil stage entries and embedded stage - names that are empty or differ from their map keys. Remove load normalization - that synthesizes these required markers, retaining only harmless ordering or - cloning. -4. Make session and run `ensureStage` initialize the analyze contract version - and an empty collection for `analyze`. Make - `validateAnalyzeStageState` require that version for every present analyze - stage regardless of lifecycle status. Delete version-zero acceptance. -5. Update current test construction to use constructors or explicit markers. - Cover missing/supported/unknown versions, nil/mismatched stages, newly - created analyze state, empty current collections, and aggregate-only - rejection. -6. Update `docs/internal/manifest.md`, `docs/internal/artifacts.md`, - `docs/operations.md`, and `docs/troubleshooting.md` with schema and local - recovery guidance. Leave party/remote removal for their stages. +1. In `internal/stage/publish.go`, replace + `resolvePublishRunManifestPath` with canonical current-run-root resolution + based on resolved campaign, session ID, workspace root, and `m.RunID` using + `artifacts.SessionRunRootForCampaign`. Require that exact root to be a real + directory and retain existing symlink/non-directory rejection. +2. Remove opening, decoding, rewinding, and passing a run-manifest file. Change + current-run collection to inspect `manifest.Manifest` stage records and add + only declared `ArchivePath`, fallback `LocalPath`, `Logs`, and + `GeneratedConfigs` that resolve within the selected current run root. + Records referring to canonical session files or an older run must not be + uploaded as current-run diagnostics. +3. Make an empty current-run diagnostic set valid. Refactor the source-opening + helper so it opens each allowlisted current-run file directly, with the + existing regular-file/no-follow and optional checksum verification. It must + not require a distinguished manifest file. +4. Remove the `manifest.json` synthetic run-file entry and the special branch + that emits `RemoteArtifactTypeRunManifest`. Continue emitting ordinary + current-run diagnostics as `RemoteArtifactTypeRunFile` with deterministic + `run:` source identities and destinations. +5. Preserve session-manifest commit generation, previous-cache uploads, + configured published outputs, immutable upload verification, lock + revalidation, commit upload, and pointer-last ordering unchanged. +6. Rewrite focused publish tests and helpers to create a run root and populate + session-manifest diagnostic references instead of writing a run manifest. + Cover current-run logs/generated configuration/declared archive outputs, + exclusion of prior-run and session-canonical paths, empty diagnostics, + symlink rejection, deterministic ordering, and absence of newly emitted + `run_manifest` declarations. Retain existing upload integrity and pointer + tests without duplicating them. +7. Update `docs/internal/stage-publish.md` and the run-upload portion of + `docs/operations.md`: the session manifest is the diagnostic allowlist, no + run manifest is uploaded, and `upload_run` may legitimately upload zero + run-local diagnostic files. ### Exit Criteria -- `go test ./internal/manifest ./internal/artifacts ./internal/stage ./internal/app` +- `go test ./internal/stage ./internal/artifacts` succeeds. +- Publish succeeds when the current run directory exists but contains no run + manifest and no diagnostics. +- Only session-manifest-declared files confined to the current run root become + `run_file` transfers; older-run and incidental files do not. +- New commits contain no `run_manifest` artifact, while remote decoding still + accepts that historical wire value. +- `git diff --check` succeeds. + +## Stage 2 — Make Runner Persistence Session-Only + +**Status: Pending** + +### Goal + +Remove the second persistence transaction from invocation execution while +preserving the existing session-ledger lifecycle and immediate command result. + +### Required Work + +1. Remove `RunOptions.RunManifestStore` and `RunSummary.RunManifestPath`. Keep + all remaining summary fields and run ID generation. Update direct callers + and CLI rendering only if they refer to the removed path. +2. In `executePlan`, delete run-manifest path resolution, construction, + identity/config projection, initial save, per-stage action/running/skip/ + failure/success saves, final success save, and every error path created only + by those operations. +3. After acquiring the session lock, validating/restoring session state, and + resolving invocation identity, explicitly ensure the canonical + `SessionRunRootForCampaign` directory with the ordinary workspace directory + contract. Do not create `manifest.json` or another placeholder there. +4. Replace `persistTerminalFailure` with a narrowly named session-only helper. + It must record the terminal failure in the session manifest when available, + atomically attempt the session save, preserve the originating error, and + join a session-save error without invoking any diagnostic store. Keep the + distinct post-publish-cleanup failure behavior until its later workstream. +5. Simplify all runner failure paths to the new helper. Preserve the existing + order of session identity save, resume validation, running transition, + force invalidation, stage execution, success/failure/self-skip transition, + session save, logging, and post-publish cleanup. +6. Make `applyAnalyzeProjection` session-only at its application boundary so + the runner no longer needs a run-manifest value. The invocation subset may + remain temporarily inside validation until Stage 3 deletes it. +7. Delete run-only helpers such as `invocationIdentity.applyToRunManifest`, + `requestedStageNames`, `applyStageResultToRunManifest`, + `applyEffectiveConfigProvenanceToRun`, and + `setRunStageSemanticConfig` once unused. +8. Rewrite runner, terminal-failure, semantic-resume, assembled-workflow, and + lifecycle tests that currently inject a `RunStore` or load + `RunSummary.RunManifestPath`. Assert the durable outcome through the session + manifest and the immediate invocation outcome through `RunSummary`. + Preserve coverage for cancellation, collaborator/preflight failures, + session-save failure joining, successful and failed stage transitions, + self-skip, force invalidation, semantic evidence, distinct run IDs, and + run-local diagnostic paths. Delete tests whose sole purpose was run-record + creation, terminalization, or historical inspection. +9. Update `docs/policy/architecture.md`, `docs/cli.md`, and the runner portions + of `docs/internal/manifest.md`: one atomic session-manifest update is the + only durable progress transaction; a run ID and run directory remain, but + there is no invocation manifest or persistent command summary. + +### Exit Criteria + +- `go test ./internal/app ./internal/stage ./internal/manifest` succeeds. +- `executePlan` creates no `runs//manifest.json` and exposes no run + manifest store seam, while run IDs, run directories, diagnostics, session + transitions, and summaries remain available. +- A hypothetical diagnostic-record write cannot fail a stage because no such + persistence operation exists; session-manifest failures remain visible and + authoritative. +- Runner behavior tests obtain durable state only from the session manifest. +- `git diff --check` succeeds. + +## Stage 3 — Remove Invocation-Only Analyze Projection + +**Status: Pending** + +### Goal + +Give analyze one in-memory projection—the reconciled session collection—without +prematurely implementing Workstream 6 checkpoint semantics. + +### Required Work + +1. Remove `Invocation` from `stage.AnalyzeStateProjection` and update its + comment to describe only the reconciled session authority proposed for the + next session-manifest save. Retain the pointer wrapper so “no analyze update” + remains distinguishable from a valid empty collection. +2. In `internal/stage/analyze.go`, delete the separate invocation-record map and + every write, clone, or failure projection associated only with it. Successful + and failed analyze results continue to return the complete reconciled + session collection under the existing rules. +3. Simplify `internal/app/analyze_projection.go`: validate and clone only the + session collection, remove invocation/session subset comparison, apply only + the session collection, and derive aggregate analyze outputs only from that + collection. Retain rejection of projections from non-analyze stages, + contradictory ordinary outputs, malformed records, and illegal skipped or + error result shapes. +4. Preserve `captureAnalyzeState` and `restoreAnalyzeState` for the current + single-save boundary. Do not add manifest-store access to the analyze stage, + persist inside its artifact loop, or change retry/force behavior in this + stage. +5. Rewrite `analyze_projection_test.go`, analyze incremental tests, and mixed + runner tests around one reconciled session collection. Delete assertions + about per-invocation artifact subsets. Retain behavior coverage for partial + failure state, unrelated current records, invalid projections, persistence + failure rollback, and aggregate output derivation. +6. Update `docs/internal/stage-analyze.md` and the analyze-state section of + `docs/internal/manifest.md` to describe one session projection and clearly + leave per-artifact checkpointing as future roadmap work rather than current + behavior. + +### Exit Criteria + +- `go test ./internal/stage ./internal/app ./internal/manifest` succeeds. +- No production analyze type, result, validator, or test distinguishes session + state from an invocation artifact subset. +- Analyze still performs one end-of-stage session save, retains valid unrelated + records, persists its permitted failure projection, and restores prior + in-memory authority if that save fails. +- No Workstream 6 checkpoint callback or persistence loop has been introduced. +- `git diff --check` succeeds. + +## Stage 4 — Delete The Run-Manifest Domain Model + +**Status: Pending** + +### Goal + +Remove the now-unreferenced structured schema, persistence API, canonical file +path, and mechanism tests from their owning packages. + +### Required Work + +1. Delete `internal/manifest/run_manifest.go`, `RunManifestSchemaVersion`, + `RunManifest`, `RunStageRecord`, run status/action enums, constructors, + transition methods, and all run-only validation/normalization helpers. +2. Remove `manifest.RunStore` and `LocalStore.CreateRun`, `LoadRun`, + `LoadRunReader`, and `SaveRun`. Simplify imports and shared validation only + where the deleted run code made them unnecessary; do not weaken session + manifest validation. +3. Delete `artifacts.SessionRunManifestPathForCampaign` while retaining + `SessionRunsDirForCampaign` and `SessionRunRootForCampaign` as canonical + run-diagnostic and invocation-work paths. +4. Delete `run_manifest_test.go` and run-manifest-only store/path/schema tests. + Remove run-specific portions of otherwise valuable manifest, artifact, + semantic fingerprint, restore, operator, and publish fixtures. Do not replace + serialization round-trip tests for a format that no longer exists. +5. Keep the remote `run_manifest` artifact enum accepted only by remote commit + decoding/validation. Add a concise comment at its declaration explaining + that Narratio no longer emits or interprets it and retains the value solely + so immutable existing commits remain readable. No production symbol in + `manifest`, `app`, or `stage` may refer to it. +6. Update package comments or focused internal documentation affected by the + domain deletion in the same change. + +### Exit Criteria + +- `go test ./internal/manifest ./internal/artifacts ./internal/app ./internal/stage` succeeds. -- Both manifest kinds round-trip only with exact supported versions. -- A present analyze stage cannot round-trip without current per-artifact - versioning; an empty current collection can. -- Load does not synthesize required stage identity or authority. +- Except for the explicitly retained `RemoteArtifactTypeRunManifest` wire + value and its remote-decoder compatibility test, searches for `RunManifest`, + `RunStore`, `CreateRun`, `LoadRun`, `SaveRun`, `RunManifestPath`, + `run_manifest.go`, and the local `runs//manifest.json` contract find + no current production or test implementation. +- Session manifest schema validation and round trips remain fully covered. +- Existing remote commit documents containing the historical `run_manifest` + artifact type still decode and validate, but new publish plans cannot emit + it. - `git diff --check` succeeds. -## Stage 2 — Reject Unversioned Party Documents +## Stage 5 — Reconcile Current Documentation And Close Workstream 4 -**Status: Completed** +**Status: Pending** ### Goal -End interpretation of unversioned party files before removing the configuration -fields and mode shell that supported them. +Prove the session-only target state across the repository and leave one accurate +implementation narrative for the next workstream. ### Required Work -1. Make `ParseParty` require exactly `PartySchemaVersion` in the first and - only YAML document. Missing/unknown versions identify the supported schema; - retain strict malformed, duplicate, ambiguity, and trailing-document checks. -2. Delete `classifyLegacyPartyDocument`, `resolveLegacyParty`, and - `party_legacy.go`. For this stage only, the resolved mode shell may remain - so all packages compile, but production cannot construct legacy mode. -3. Simplify `resolvePartyInput` to return parsed canonical data and source - directly, with no classification branch. -4. Replace legacy parser/resolution tests with required-v1, missing/unknown - version, multi-document, strict-field, alias, identity/order, and - deterministic players-projection tests. -5. Update `docs/integrations/party.md`, the party section of - `docs/config.md`, `docs/internal/configuration.md`, and troubleshooting. - Do not yet claim removed config keys are unknown; Stage 3 changes structs. +1. Search current production code, tests, fixtures, examples, scripts, and + nonhistorical documentation for run-manifest types, paths, JSON fields, + stores, publish classifications, invocation projections, and dual-save or + terminal-synchronization language. Remove stale surfaces or explain the + retained run ID/run directory without implying a structured record. +2. Reconcile canonical owners, especially `docs/policy/architecture.md`, + `docs/cli.md`, `docs/operations.md`, `docs/troubleshooting.md`, + `docs/internal/overview.md`, `docs/internal/manifest.md`, + `docs/internal/stage-analyze.md`, `docs/internal/stage-extract.md`, and + `docs/internal/stage-publish.md`. Keep schema definitions in the manifest + owner, filesystem/remote behavior in operations, and implementation details + in internal documents rather than duplicating them. +3. Do not edit immutable historical release notes or completed audit documents. + Roadmap references may retain the phrase “run manifest” when describing the + problem and approved removal. Current instructions must not claim the file + is produced or required. +4. Review the affected test suite under `docs/policy/testing.md`. Consolidate + leftover tests that merely encode the deleted write choreography, while + retaining meaningful session durability, transition, recovery, current-run + diagnostics, remote publication, and representative assembled-workflow + coverage. +5. Update Workstream 4 in `refactoring.md` from `Pending` to `Complete` and + update every stage plus the purpose/status section of this plan to + `Completed` only after the target state and all checks are proven. Do not + change later workstream statuses. +6. Run the complete repository validation from `docs/development.md`: + `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`, + `go test ./internal/doccheck`, and + `go test ./internal/config -run '^TestExamplesLoadAndValidate$'`. Run + `git diff --check` and confirm the worktree contains only intended changes. ### Exit Criteria -- `go test ./internal/config ./internal/stage ./internal/app` succeeds. -- No production code classifies or resolves an unversioned party, and - `party_legacy.go` is absent. -- Unsupported party schema fails before family expansion or preparation. -- Canonical parsing and derived players output remain deterministic. -- `git diff --check` succeeds. - -## Stage 3 — Remove Legacy Party And Players Configuration - -**Status: Completed** - -### Goal - -Make one campaign party the only configured roster authority and players an -explicitly derived value. - -### Required Work - -1. Remove `PlayersFile` from `CampaignInputsConfig` and both `PlayersFile` - and `PartyFile` from `SessionInputsConfig`. Strict decode must reject all - three retired YAML paths as unknown unsupported fields. -2. Keep campaign `PartyFile` in resolved stable inputs. Represent generated - players as derived data, not a selectable `ResolvedInputFile`; introduce a - clearly named derived value if prepared-input consumers need one. -3. Remove `PartyMode`, both constants, `PartyDocument`, `IsCanonical`, - and all mode branches. Make `ResolvedParty` hold non-nil - `CanonicalParty` plus source provenance, and make `ParseParty` return - `*CanonicalParty`. -4. Simplify `mergeCampaignSession`, campaign-party loaders, resolved - validation, family expansion, effective digest/source reporting, and config - commands. Party selection always comes from campaign config. -5. Delete `internal/stage/prepare_legacy.go`. Simplify prepare/resume, - extraction references, and semantic contracts to copy canonical party and - render players. Preserve prepared paths, checksums, input kinds, Notarius - selectors, and meaningful `derived_from_party` provenance. -6. Make operator/source rendering show campaign party and derived players, with - no `legacy_player` role or separate player path. -7. Rewrite affected config, stage, app, template, profile, and command tests. - Add strict rejection for all retired keys and an integrated config/prepare - test proving one party produces both prepared documents. -8. Remove legacy roster text/fixtures from `docs/config.md`, `docs/cli.md`, - `docs/internal/configuration.md`, `docs/internal/stage-prepare.md`, - `docs/internal/stage-extract.md`, and `examples/`. - -### Exit Criteria - -- `go test ./internal/config ./internal/stage ./internal/app` succeeds. -- No production YAML tag accepts `players_file` or session `party_file`. -- No production `PartyMode`, `PartyDocument`, or legacy prepare symbol - remains. -- One campaign v1 party supplies both prepared party and derived players. -- Current docs/examples contain no legacy roster workflow. -- `git diff --check` succeeds. - -## Stage 4 — Make Remote Current State Commit-Only - -**Status: Completed** - -### Goal - -Make the versioned commit pointer the sole remote authority for status, restore, -and reuse. - -### Required Work - -1. Replace legacy missing errors with typed - `CurrentCommitPointerMissingError` keyed to - `S3CurrentCommitPointerKey`. `LoadCurrentState` returns it with - publish/republish guidance when absent and otherwise loads only committed - state. -2. Delete `current_state_legacy.go`, legacy limits, - `ResolveCurrentStateKeys`, and retired key helpers once callers are gone. - Retain current pointer/commit/session-manifest bounds. -3. Require non-nil pointer, commit, and manifest in `CurrentState`; keep - `CurrentPointerKey` and committed manifest key; remove - `CurrentRunIDKey` and legacy-oriented duplication. Update identity errors. -4. Mirror this in `app.RemoteCurrentState`, discovery, status, lock - inspection, restore, and helpers. Status may report missing pointer as not - published; malformed or unsupported current data remains an error. -5. Delete `buildLegacyRestoreActions`, legacy key mapping, prefix listing, and - checksum inference. Require committed restore planning while preserving - audio scope, verification, conflicts, reports, manifest-last order, and - installation safety. -6. Replace legacy fixtures with complete pointer/commit/manifest fixtures. - Cover missing pointer, bad versions/identity, undeclared/missing objects, - checksum/size/generation mismatch, and proof that restore neither lists nor - reads retired keys. -7. Remove legacy remote language from `docs/operations.md`, - `docs/troubleshooting.md`, `docs/internal/manifest.md`, - `docs/internal/artifacts.md`, `docs/internal/command-restore.md`, and - `docs/internal/stage-publish.md`; document republishing. - -### Exit Criteria - -- `go test ./internal/artifacts ./internal/app ./internal/stage` succeeds. -- Production never reads `current/manifest.json` or `current/run_id.txt`. -- Every successful current load has a verified pointer, commit, and manifest. -- Restore derives all remote scope from the commit without prefix listing. -- `git diff --check` succeeds. - -## Stage 5 — Resolve Previous Artifacts From Commit Declarations - -**Status: Completed** - -### Goal - -Use one deterministic source-to-object lookup per previous requirement without -path candidates or remote probing. - -### Required Work - -1. Rewrite `previouscache.Resolve` around guaranteed committed state. Require - the unique session-manifest declaration and always copy its checksum, size, - generation, and verified content into the plan. -2. For each sorted requirement, derive its canonical source ID and select its - unique `published_output`. Validate and strip the selected run's immutable - published-output prefix from `DestinationKey` to derive the local relative - path; never use current config or previous-manifest outputs for it. -3. Preserve required/optional behavior, deterministic ordering, safe local - paths, and checksum/size/generation metadata. -4. Delete legacy candidate/basename matching, manifest/config fallbacks, - candidate `Exists` calls, probing ambiguity errors, and unused derivation - helpers. Delete the test-only `BuildPlan` alias; call `Resolve`. -5. Test exact declarations, no candidate `Exists` or list calls, - required/optional outcomes, unsafe destinations, duplicate-source rejection, - and verified metadata through prepare/restore integration. -6. Update `docs/internal/stage-prepare.md`, - `docs/internal/command-restore.md`, `docs/internal/artifacts.md`, - `docs/operations.md`, and troubleshooting. - -### Exit Criteria - -- `go test ./internal/previouscache ./internal/stage ./internal/app` succeeds. -- Resolution contains no candidate, basename/config fallback, ambiguity probe, - or compatibility alias. -- Every hydration traces to one verified commit declaration. -- Optional absence skips and required absence fails without probing. -- `git diff --check` succeeds. - -## Stage 6 — Make Local Artifact Evidence Manifest-Only - -**Status: Completed** - -### Goal - -Remove aggregate and incidental paths so transcript, extraction, and analyze -consumers require current manifest evidence. - -### Required Work - -1. Rewrite `ResolveSessionArtifact` and its private candidate logic to require - a succeeded registered producer and exactly one output matching both - `Kind` and `SourceID`. Require safe path, producer run ID, and valid - checksum; verify checksum and registered content before returning. Reject - ambiguous/malformed evidence. -2. Delete `fallback.canonical_path`, canonical-path probing, filename - fallback, and old-candidate deduplication. Missing evidence remains typed - unavailable even when expected bytes exist. -3. Update render, extract input identity, transcript resolution, and analyze - built-in resolution to use this path while retaining stage context, content - checks, and semantic fingerprints. -4. Remove `analyzeReconciliationLegacy` and the version-zero reconciliation - branch. Unsupported in-memory state is non-resumable/corrupt, not legacy - state eligible for recovery. -5. Audit catalog hydration, analyze inputs, publish discovery, operator - inspection, and projections: configured analyze output authority comes only - from a current `AnalyzeArtifacts` record and its output evidence, never - aggregate outputs or configured paths. Do not implement Workstream 6 - checkpointing. -6. Retain only strict extraction proof in `InspectExtractionEvidence`: - succeeded stage, matching input, canonical bundle, receipt, exact lane set - plus index, verified JSON/checksums, contracts, and Notarius provenance. - Delete any acceptance of missing contract/provenance; do not redesign the - adapter. -7. Test that incidental files, aggregate-only analyze outputs, - missing/failed/stale/unselected records, mismatched checksums, and incomplete - extraction evidence remain unavailable. Retain positive coverage for all - built-in transcript sources, configured extraction lanes, and analyze - outputs. -8. Update `docs/internal/artifacts.md`, `docs/internal/stage-analyze.md`, - `docs/internal/stage-extract.md`, `docs/internal/stage-publish.md`, - `docs/internal/manifest.md`, `docs/config.md`, operations, and - troubleshooting without legacy/fallback language. - -### Exit Criteria - -- `go test ./internal/artifacts ./internal/manifest ./internal/stage ./internal/app` - succeeds. -- Disk files cannot establish transcript or analyze availability without - current evidence; aggregate analyze outputs cannot substitute. -- Extraction lacking receipt, contract, provenance, complete sources, or - verified bytes cannot hydrate the catalog. -- Positive current transcript/extraction/analyze/publish/operator flows work. -- `git diff --check` succeeds. - -## Stage 7 — Complete The Purge And Validate The Repository - -**Status: Completed** - -### Goal - -Remove residual compatibility material, validate the current-only architecture, -and close Workstream 3 without entering later work. - -### Required Work - -1. Search active code, tests, fixtures, examples, and current docs for retired - remote keys/readers, previous candidates, unversioned party modes, - `players_file`, session party overrides, aggregate analyze authority, - incidental artifact fallback, missing manifest schemas, and extraction - evidence without contract/provenance. -2. Delete unused constants, fields, types, errors, helpers, aliases, files, - fixtures, and imports belonging to those paths. Do not remove unrelated - adapter defaults, optional-input behavior, or later-workstream seams merely - because they use “fallback.” -3. Review canonical docs under the documentation policy for consistent current - behavior and actionable migration. Leave `docs/releases/`, audits, and - decision history unchanged. -4. Run `go test ./...`, `go test -race ./...`, `go vet ./...`, documented - docs/example validation, and supported Linux/macOS/Windows release builds. - Cross-builds prove compilation only. -5. Review tests against testing policy: retain rejection and positive tests at - every authority boundary without recreating deleted algorithms in tests. -6. Mark only Workstream 3 `Complete` in `refactoring.md` and all stages here - `Completed`. Accurately record unavailable native-platform evidence. - -### Exit Criteria - -- Full tests, race tests, vet, docs/examples, and release cross-builds succeed. -- No runtime branch accepts or infers a retired Workstream 3 representation. -- Each current manifest, party, remote snapshot, previous input, transcript, - extraction artifact, and analyze artifact has one documented authority. -- Only Workstream 3 is newly complete and `git diff --check` succeeds. +- The session manifest is the only structured durable local progress record; + no current code or documentation requires a run manifest. +- Run IDs, canonical run directories, bounded diagnostics, generated + configuration, receipts, immediate summaries, immutable run prefixes, and + remote publication remain functional without a second progress transaction. +- Publish uses session-manifest evidence, emits no new run-manifest artifact, + and still reads verified historical remote commits without interpreting their + old diagnostic record. +- All repository-wide validation succeeds on the maintained Go toolchain. +- Workstream 4 and all five stages are marked `Complete`; Workstream 5 remains + the next pending workstream. +- `git status --short` is empty after the implementation commit. ## Open Questions -None. The approved audits, roadmap, policies, and current implementation make -this plan decision-complete. +None. The approved audits, current architecture, and decisions above are +sufficient to implement this workstream without further product or policy +choices.