Plan session manifest simplification

This commit is contained in:
2026-09-03 00:48:46 +00:00
parent c98b4ef4ef
commit 49324d3f35

View File

@@ -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/<run_id>/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:<relative-path>` 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/<run_id>/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/<run_id>/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.