417 lines
21 KiB
Markdown
417 lines
21 KiB
Markdown
# Workstream 3 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.
|
|
|
|
All seven stages are pending and must be implemented in order. Each is bounded
|
|
for one `gpt-5.6-terra` prompt. Workstreams 1 and 2 are complete. Workstreams
|
|
4 and later are out of scope: do not remove the run manifest, redesign runner
|
|
lifecycle, change analyze checkpoint timing, replace locks, decompose publish,
|
|
or add cleanup 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
|
|
validation succeed.
|
|
|
|
## Instructions For Every Stage
|
|
|
|
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
|
|
[`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.
|
|
|
|
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.
|
|
|
|
## Stage 1 — Establish Explicit Current Manifest Schemas
|
|
|
|
**Status: Completed**
|
|
|
|
### Goal
|
|
|
|
Create an unambiguous local-state boundary before removing downstream legacy
|
|
branches.
|
|
|
|
### 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.
|
|
|
|
### Exit Criteria
|
|
|
|
- `go test ./internal/manifest ./internal/artifacts ./internal/stage ./internal/app`
|
|
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.
|
|
- `git diff --check` succeeds.
|
|
|
|
## Stage 2 — Reject Unversioned Party Documents
|
|
|
|
**Status: Completed**
|
|
|
|
### Goal
|
|
|
|
End interpretation of unversioned party files before removing the configuration
|
|
fields and mode shell that supported them.
|
|
|
|
### 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.
|
|
|
|
### 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: Pending**
|
|
|
|
### 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.
|
|
|
|
## Open Questions
|
|
|
|
None. The approved audits, roadmap, policies, and current implementation make
|
|
this plan decision-complete.
|