Plan runner lifecycle refactor
This commit is contained in:
@@ -1,396 +1,481 @@
|
|||||||
# Workstream 4 Implementation Plan
|
# Runner Lifecycle Refactoring Implementation Plan
|
||||||
|
|
||||||
## Purpose And Status
|
## Status And Purpose
|
||||||
|
|
||||||
This is the executable plan for [`refactoring.md`](refactoring.md), Workstream
|
This is the decision-complete implementation plan for Workstream 5, **Runner
|
||||||
4: **One durable local manifest authority**. Finding 2 of
|
lifecycle and pre-execution decisions**, in
|
||||||
[`contract-audit.md`](contract-audit.md) and rows H14, H15, H17, C02, and C03
|
[`refactoring.md`](refactoring.md). Workstreams 1 through 4 are complete.
|
||||||
of [`audit-decisions.md`](audit-decisions.md) own the approved decisions.
|
Workstream 5 is the next pending workstream and is the only feature scope of
|
||||||
|
this plan.
|
||||||
|
|
||||||
**Status: Completed**
|
The implementation must reduce the change blast and cognitive load of
|
||||||
|
`internal/app.executePlan` without changing the pipeline's observable behavior.
|
||||||
|
It must leave one explicit lifecycle owner, one session lock, one durable
|
||||||
|
session-manifest authority, a narrow shared planning/execution decision model,
|
||||||
|
and invocation-scoped test seams. It must not create a workflow engine, a
|
||||||
|
general dependency-injection framework, or new public extension points.
|
||||||
|
|
||||||
All five stages are completed. Workstreams 1 through 4 are complete.
|
The authoritative scope and target state are Workstream 5, the dependency
|
||||||
Workstreams 5 and later remain out of scope: do not decompose the runner into a
|
relationships, and the consolidated target state in
|
||||||
new lifecycle type, redesign pre-execution decisions, add per-artifact analyze
|
[`refactoring.md`](refactoring.md). The supporting audit decisions are H04,
|
||||||
checkpoints, split publish into separate transactions, add cleanup as a stage,
|
H07, H14, H15, H17, H34, and H35 in
|
||||||
or change remote lock policy while following this plan.
|
[`audit-decisions.md`](audit-decisions.md), with detailed analysis in
|
||||||
|
[`audit.md`](audit.md).
|
||||||
|
|
||||||
## Settled Implementation Decisions
|
## Scope And Fixed Decisions
|
||||||
|
|
||||||
- The session manifest is the only durable local progress ledger. It alone
|
- Keep the existing `internal/app` package boundary. Use private types,
|
||||||
records stage status, current artifacts, semantic evidence, diagnostics,
|
functions, and focused files; do not create a runner package or expose
|
||||||
failures, resume authority, restore authority, and publish authority.
|
lifecycle internals.
|
||||||
- Delete the structured invocation run manifest completely: its schema and
|
- Keep the session manifest as the sole durable local progress ledger. Run IDs,
|
||||||
types, store interface and methods, path helper, lifecycle mutations,
|
run directories, diagnostics, and `RunSummary` remain, but no second durable
|
||||||
terminal recovery, analyze projection, publish dependency, fixtures, tests,
|
invocation record may be introduced.
|
||||||
and current documentation all leave the repository.
|
- Preserve the canonical flat stage order, bounded contiguous execution,
|
||||||
- Do not replace it with another JSON summary, journal, database, or event log.
|
dependency-aware invalidation outside the selected range, stage-owned resume
|
||||||
Historical per-invocation state is not an operational requirement.
|
validation, self-skip semantics, force semantics, and current analyze
|
||||||
- Preserve run IDs. Every invocation still receives one before session state is
|
projection behavior.
|
||||||
initialized; it remains the identity used by the session manifest,
|
- Preserve the two prerequisite checks: a read-only check before persistent
|
||||||
run-local directory, adapter provenance, logs, generated configuration,
|
mutation and a second check against the manifest while holding the session
|
||||||
receipts, immutable publish prefix, command summary, and diagnostics.
|
lock.
|
||||||
- Explicitly create the canonical run directory once per invocation after the
|
- Keep lock acquisition and the deferred release visibly paired in the
|
||||||
session lock and identity checks. Removing the initial run-manifest save must
|
top-level lifecycle function. A release failure remains the final invocation
|
||||||
not make diagnostic writers responsible for accidentally creating the run
|
error when no earlier error exists and is joined with an earlier error
|
||||||
root. Directory-creation failure remains an invocation initialization error.
|
otherwise.
|
||||||
- `RunSummary` remains the immediate in-memory command result and retains
|
- Preserve manifest ordering: establish identity before adapter construction;
|
||||||
session ID, run ID, session manifest path, selected stage names, executed
|
persist `running` before invoking a stage; persist terminal stage state before
|
||||||
stages, and skipped stages. Remove only `RunManifestPath`; do not add a
|
moving to the next stage; and persist terminal invocation failures where the
|
||||||
replacement persistent summary.
|
current runner does so. Do not make diagnostics a persistence authority.
|
||||||
- A run-manifest write can no longer fail an otherwise valid pipeline action.
|
- Keep actual `Stage.Run` results, result validation, persistence, logging, and
|
||||||
Session-manifest transition and terminal-save failures remain correctness
|
failure handling execution-only. Planning may model a successful or
|
||||||
failures and continue to join with the originating error where applicable.
|
configured self-skipped outcome on a cloned manifest, but must never pretend
|
||||||
- Publish no longer opens or validates `runs/<run_id>/manifest.json`. When
|
that it observed a runtime result.
|
||||||
`upload_run` is enabled, it derives the current run root canonically and uses
|
- The shared pure decision value must describe only whether to run or skip and
|
||||||
the session manifest's recorded output, log, and generated-configuration
|
the pre-execution stale/invalidation work implied by recorded status, force,
|
||||||
references as an allowlist. It includes only safe regular files confined to
|
and normalized resume validation. Small transition helpers may be shared
|
||||||
the current run root and ignores records from earlier runs.
|
only where planning and execution perform the same manifest mutation.
|
||||||
- New remote commits do not upload or classify a run manifest. Keep
|
- Preserve analyze's current single end-of-stage projection/save boundary and
|
||||||
`RemoteArtifactTypeRunManifest` as a read-only wire value so already committed
|
rollback on save failure. Per-artifact checkpointing belongs to Workstream 6
|
||||||
and verified remote snapshots remain readable; it must have no local loader,
|
and is out of scope.
|
||||||
path, special publish branch, or newly emitted declaration. This preserves a
|
- Preserve post-publish cleanup and its durable obligation behavior until
|
||||||
durable remote protocol without retaining the local dual-authority model.
|
Workstream 9. This work may move the call into finalization and make its
|
||||||
- Preserve `RemoteArtifactTypeRunFile` for declared run-local diagnostics.
|
destructive function invocation-scoped, but must not turn cleanup into a
|
||||||
Publishing no current-run diagnostics is valid and must not require a
|
stage or change eligibility/retry semantics.
|
||||||
placeholder file.
|
- Continue using `stage.Env` for injected stage collaborators. Add only small
|
||||||
- Remove the invocation subset from `AnalyzeStateProjection` and from analyze
|
private dependency values for nondeterministic or external construction
|
||||||
execution. During this workstream, analyze still returns and persists one
|
boundaries that cannot be represented by `stage.Env`, and pass those values
|
||||||
validated reconciled session collection at the existing end-of-stage
|
explicitly per command or invocation.
|
||||||
boundary. Do not implement artifact-by-artifact persistence yet.
|
- Remove `executeStagesFn` and `runCommandFn`. Replace their tests with private
|
||||||
- Preserve the current safe behavior when the end-of-stage analyze manifest
|
command helpers that accept a pipeline executor value for that call. Do not
|
||||||
save fails: incidental output bytes do not establish authority, prior
|
migrate unrelated restore/config-loader globals in this workstream; their
|
||||||
in-memory analyze authority is restored, and the aggregate stage fails.
|
owners should adopt the same narrow pattern when later work touches them.
|
||||||
Workstream 6 will replace this with the approved checkpoint model.
|
- Replace the runner's mutable clock use with an invocation-scoped clock. A
|
||||||
- Preserve current stage ordering, force/invalidation rules, self-skip behavior,
|
normal immutable `nowUTC()` function may remain for unrelated command owners.
|
||||||
aggregate transition timing, cleanup obligations, remote commit ordering,
|
Route post-publish deletion through the invocation dependency value and
|
||||||
and command output except where they directly expose the removed run
|
remove `removeRunScopedDirFn`.
|
||||||
manifest.
|
- Preserve current CLI syntax, output, errors at their stable semantic level,
|
||||||
- Delete tests whose only contract is historical run-manifest persistence.
|
configuration behavior, workspace modes, secret loading/redaction, remote
|
||||||
Rewrite mixed tests around session state, command summaries, run-local
|
lock revalidation, Linux/macOS/Windows support, and offline operation.
|
||||||
diagnostics, or remote commit contents, and consolidate redundant mechanism
|
- Do not optimize for a particular private file layout or exact helper count.
|
||||||
assertions rather than recreating a second audit record in tests.
|
The finished top-level runner must nonetheless read as a short, explicit
|
||||||
- Historical release notes and completed audit documents remain unchanged.
|
sequence of preparation, lock ownership, locked initialization, composition,
|
||||||
Current architecture, CLI, operations, troubleshooting, and internal
|
stage execution, and finalization rather than forwarding all work to another
|
||||||
documentation must describe session-only authority.
|
monolith.
|
||||||
- Mark only Workstream 4 `Complete`, and only after all stages and final
|
- Mark only Workstream 5 `Complete`, and only after all stages and full
|
||||||
validation succeed.
|
validation succeed. Workstream 6 remains the next pending workstream.
|
||||||
|
|
||||||
## Instructions For Every Stage
|
## Instructions For Every Stage
|
||||||
|
|
||||||
Before each stage:
|
Before each stage:
|
||||||
|
|
||||||
1. Read `docs/development.md`, every file under `docs/policy/`, this plan,
|
1. Read `docs/development.md`, every document under `docs/policy/`, this plan,
|
||||||
Workstream 4 plus the dependency and target sections of
|
Workstream 5 plus the dependency and consolidated-target sections of
|
||||||
[`refactoring.md`](refactoring.md), Finding 2 and the Workstream-4-relevant
|
[`refactoring.md`](refactoring.md), and audit rows H04, H07, H14, H15, H17,
|
||||||
boundary in Finding 3 of [`contract-audit.md`](contract-audit.md), and rows
|
H34, and H35 in [`audit-decisions.md`](audit-decisions.md). Consult the
|
||||||
H14, H15, H17, C02, and C03 of
|
corresponding detailed findings in [`audit.md`](audit.md) when a boundary is
|
||||||
[`audit-decisions.md`](audit-decisions.md).
|
unclear.
|
||||||
2. Inspect the named implementation and focused tests. Prefer the codebase
|
2. Inspect the named production code and focused tests. Prefer the codebase
|
||||||
graph for Go discovery and text search for schemas, paths, fixtures,
|
knowledge graph for Go symbol discovery and call tracing; use text search for
|
||||||
documentation, and serialized field names.
|
documentation, fixtures, serialized fields, and global-variable assignments.
|
||||||
3. Confirm the worktree state and preserve unrelated changes. Do not enter a
|
3. Confirm the worktree state and preserve unrelated changes. Do not enter
|
||||||
later workstream merely because adjacent lifecycle, analyze, publish, or
|
Workstream 6 or Workstream 9 merely because analyze or cleanup code is
|
||||||
cleanup code would benefit from broader refactoring.
|
adjacent to runner lifecycle code.
|
||||||
|
|
||||||
During every stage:
|
During every stage:
|
||||||
|
|
||||||
- Keep the repository compiling and focused tests passing. A temporary
|
- Keep the repository compiling and focused tests passing. Do not leave both an
|
||||||
invocation projection or unused run-manifest domain type may remain only
|
old and new runner path active except for a temporary private delegation that
|
||||||
when the next numbered stage explicitly removes it; do not introduce a new
|
the next numbered stage explicitly removes.
|
||||||
compatibility facade.
|
- Preserve package ownership and acyclic dependency direction. Private state
|
||||||
- Preserve package ownership and acyclic dependency direction. Keep this a
|
should aggregate already-related values, not become a service locator.
|
||||||
deletion-oriented refactor inside the existing `app`, `stage`, `manifest`,
|
- Preserve error wrapping and joining where errors represent distinct failures.
|
||||||
and `artifacts` owners.
|
Do not freeze incidental complete error strings in new tests.
|
||||||
- Preserve the session lock, session-manifest atomic replacement, group
|
- Keep tests deterministic, offline, behavior-focused, and lean under
|
||||||
workspace modes, bounded I/O, no-follow publish sources, remote verification,
|
`docs/policy/testing.md`. Prefer existing real temporary filesystems and
|
||||||
secret redaction, and Linux/macOS/Windows support.
|
current adapter/storage fakes. Do not add mock choreography for private
|
||||||
- Update the canonical current-behavior document owned by a change in the same
|
lifecycle helpers.
|
||||||
stage. Do not edit historical release notes or completed audit findings.
|
- Update the canonical current-behavior document owned by a changed behavior in
|
||||||
- Keep tests offline, deterministic, and behavior-focused. Remove tests with
|
the same stage. Pure file movement or private extraction requires no user
|
||||||
the retired contract and retain consequential session-state, data-integrity,
|
documentation change.
|
||||||
recovery, and remote-commit coverage at the narrowest stable boundary.
|
- Run `gofmt` on changed Go files, focused tests for the changed boundary, and
|
||||||
- Run `gofmt` on changed Go files, focused tests, and `git diff --check`. Mark a
|
`git diff --check`. Mark a stage `Completed` only after its exit criteria pass.
|
||||||
stage `Completed` only after its exit criteria pass.
|
|
||||||
|
|
||||||
## Stage 1 — Decouple Publish From The Run Manifest
|
## Stage 1 — Unify Pre-Execution Decisions
|
||||||
|
|
||||||
**Status: Completed**
|
**Status: Pending**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Make publish consume only the session manifest and current run directory so the
|
Give planning and execution one pure representation of the decision made before
|
||||||
runner can stop producing a structured run manifest without losing useful
|
a stage attempt, while keeping planning predictions distinct from observed
|
||||||
diagnostic uploads.
|
runtime outcomes.
|
||||||
|
|
||||||
### Required Work
|
### Required Work
|
||||||
|
|
||||||
1. In `internal/stage/publish.go`, replace
|
1. In `internal/app/run_control.go` or a focused private file, replace the
|
||||||
`resolvePublishRunManifestPath` with canonical current-run-root resolution
|
current action-only decision with an unexported value that records:
|
||||||
based on resolved campaign, session ID, workspace root, and `m.RunID` using
|
`run` versus `skip`; whether the selected successful record must first be
|
||||||
`artifacts.SessionRunRootForCampaign`. Require that exact root to be a real
|
marked stale; the stage-owned reason for that stale transition; and the
|
||||||
directory and retain existing symlink/non-directory rejection.
|
application-owned invalidation reason, if any. Its constructor must be pure:
|
||||||
2. Remove opening, decoding, rewinding, and passing a run-manifest file. Change
|
it receives the prior manifest status, `force`, and an already normalized
|
||||||
current-run collection to inspect `manifest.Manifest` stage records and add
|
resume-validation result and does not mutate state, persist, log, read files,
|
||||||
only declared `ArchivePath`, fallback `LocalPath`, `Logs`, and
|
invoke a stage, or obtain the current time.
|
||||||
`GeneratedConfigs` that resolve within the selected current run root.
|
2. Encode these cases explicitly:
|
||||||
Records referring to canonical session files or an older run must not be
|
- a non-forced succeeded record with no validator result or a resumable
|
||||||
uploaded as current-run diagnostics.
|
result skips;
|
||||||
3. Make an empty current-run diagnostic set valid. Refactor the source-opening
|
- a non-forced succeeded record with a non-resumable result runs after the
|
||||||
helper so it opens each allowlisted current-run file directly, with the
|
selected record is staled with the validator's reason and succeeded
|
||||||
existing regular-file/no-follow and optional checksum verification. It must
|
dependents are invalidated with `staleReasonNotResumable`;
|
||||||
not require a distinguished manifest file.
|
- a forced stage runs and invalidates succeeded dependents with
|
||||||
4. Remove the `manifest.json` synthetic run-file entry and the special branch
|
`staleReasonForcedReplacement` when the attempt begins; and
|
||||||
that emits `RemoteArtifactTypeRunManifest`. Continue emitting ordinary
|
- absent, failed, stale, or skipped aggregate records run without inventing a
|
||||||
current-run diagnostics as `RemoteArtifactTypeRunFile` with deterministic
|
resume-stale transition.
|
||||||
`run:<relative-path>` source identities and destinations.
|
3. Add a small helper that applies only the identical pre-execution manifest
|
||||||
5. Preserve session-manifest commit generation, previous-cache uploads,
|
changes described by the decision at a caller-supplied timestamp. Retain the
|
||||||
configured published outputs, immutable upload verification, lock
|
existing fixed invalidation relation and stable application-owned reasons.
|
||||||
revalidation, commit upload, and pointer-last ordering unchanged.
|
The caller remains responsible for persistence and error context.
|
||||||
6. Rewrite focused publish tests and helpers to create a run root and populate
|
4. Use the decision constructor and application helper from both `Plan` and
|
||||||
session-manifest diagnostic references instead of writing a run manifest.
|
`executePlan`. Each caller may perform stage-owned resume validation before
|
||||||
Cover current-run logs/generated configuration/declared archive outputs,
|
constructing the decision. Preserve analyze planning's read-only artifact
|
||||||
exclusion of prior-run and session-canonical paths, empty diagnostics,
|
details when analyze is already a run candidate; those details are preview
|
||||||
symlink rejection, deterministic ordering, and absence of newly emitted
|
information, not an execution outcome.
|
||||||
`run_manifest` declarations. Retain existing upload integrity and pointer
|
5. Extract only the exact shared attempt/result mutations already identical in
|
||||||
tests without duplicating them.
|
both paths: beginning an attempt (`running` plus forced invalidation),
|
||||||
7. Update `docs/internal/stage-publish.md` and the run-upload portion of
|
applying a configured/runtime self-skip and its conditional invalidation,
|
||||||
`docs/operations.md`: the session manifest is the diagnostic allowlist, no
|
and applying a predicted/actual success and its conditional invalidation.
|
||||||
run manifest is uploaded, and `upload_run` may legitimately upload zero
|
Require callers to supply the actual or modeled outcome, outputs, semantic
|
||||||
run-local diagnostic files.
|
fingerprint, prior outcome, and timestamp. Do not put `Stage.Run`, result
|
||||||
|
validation, logging, or manifest saves in these helpers.
|
||||||
|
6. Rewrite `modelPlannedStageRun` around these values or delete it if the
|
||||||
|
resulting focused helpers make it redundant. Keep all planning mutation on
|
||||||
|
the cloned manifest.
|
||||||
|
7. Add table-driven decision tests for every status/force/resume combination
|
||||||
|
and focused parity tests proving that plan and execution produce the same
|
||||||
|
run/skip choice and dependent-stale effects for ordinary skip, non-resumable
|
||||||
|
success, forced replacement, unchanged self-skip, changed self-skip, and a
|
||||||
|
successful result replacing a non-success record. Assert durable state and
|
||||||
|
decision semantics, not private helper call order or exact timestamps.
|
||||||
|
|
||||||
### Exit Criteria
|
### Exit Criteria
|
||||||
|
|
||||||
- `go test ./internal/stage ./internal/artifacts` succeeds.
|
- `go test ./internal/app` succeeds.
|
||||||
- Publish succeeds when the current run directory exists but contains no run
|
- `Plan` and `executePlan` no longer independently encode the same
|
||||||
manifest and no diagnostics.
|
pre-execution stale/force decision sequence.
|
||||||
- Only session-manifest-declared files confined to the current run root become
|
- The decision constructor is pure, and actual stage outcomes and persistence
|
||||||
`run_file` transfers; older-run and incidental files do not.
|
remain outside it.
|
||||||
- New commits contain no `run_manifest` artifact, while remote decoding still
|
- Planning remains read-only and execution behavior is unchanged.
|
||||||
accepts that historical wire value.
|
|
||||||
- `git diff --check` succeeds.
|
- `git diff --check` succeeds.
|
||||||
|
|
||||||
## Stage 2 — Make Runner Persistence Session-Only
|
## Stage 2 — Establish The Invocation Runtime And Lock Lifecycle
|
||||||
|
|
||||||
**Status: Completed**
|
**Status: Pending**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Remove the second persistence transaction from invocation execution while
|
Make invocation state cohesive and make the top-level transaction order obvious
|
||||||
preserving the existing session-ledger lifecycle and immediate command result.
|
without hiding session-lock ownership.
|
||||||
|
|
||||||
### Required Work
|
### Required Work
|
||||||
|
|
||||||
1. Remove `RunOptions.RunManifestStore` and `RunSummary.RunManifestPath`. Keep
|
1. Introduce an unexported `invocationRuntime` (or equivalently narrow private
|
||||||
all remaining summary fields and run ID generation. Update direct callers
|
type) under `internal/app`. It should carry only state already shared across
|
||||||
and CLI rendering only if they refer to the removed path.
|
lifecycle phases: context, resolved configuration, bounded plan/stages,
|
||||||
2. In `executePlan`, delete run-manifest path resolution, construction,
|
normalized options, effective artifacts, run identity and canonical paths,
|
||||||
identity/config projection, initial save, per-stage action/running/skip/
|
`stage.Env`, manifest store, artifact store, loaded session manifest, and
|
||||||
failure/success saves, final success save, and every error path created only
|
summary accumulators. Do not expose it or let stages depend on it.
|
||||||
by those operations.
|
2. Extract unlocked preparation that performs the current read-only bounded
|
||||||
3. After acquiring the session lock, validating/restoring session state, and
|
prerequisite inspection, resolves effective artifacts, generates the run
|
||||||
resolving invocation identity, explicitly ensure the canonical
|
ID, resolves invocation identity, initializes/clones `stage.Env` fields, and
|
||||||
`SessionRunRootForCampaign` directory with the ordinary workspace directory
|
supplies default manifest/artifact stores and logger. Preserve the rule that
|
||||||
contract. Do not create `manifest.json` or another placeholder there.
|
injected `Env` values provide collaborators but never an alternate config,
|
||||||
4. Replace `persistTerminalFailure` with a narrowly named session-only helper.
|
selected-artifact set, or effective artifact set.
|
||||||
It must record the terminal failure in the session manifest when available,
|
3. Extract layout preparation separately. Keep `EnsureLayoutFor` before lock
|
||||||
atomically attempt the session save, preserve the originating error, and
|
acquisition as today, verify its manifest path against the canonical
|
||||||
join a session-save error without invoking any diagnostic store. Keep the
|
resolved path, and return enough state for the locked lifecycle.
|
||||||
distinct post-publish-cleanup failure behavior until its later workstream.
|
4. In the short top-level executor, acquire the session lock after unlocked
|
||||||
5. Simplify all runner failure paths to the new helper. Preserve the existing
|
preparation and visibly install one deferred release beside that acquisition.
|
||||||
order of session identity save, resume validation, running transition,
|
Preserve exact release-error joining behavior. Do not put lock ownership in
|
||||||
force invalidation, stage execution, success/failure/self-skip transition,
|
`invocationRuntime`, a constructor, or a helper whose lifetime is ambiguous.
|
||||||
session save, logging, and post-publish cleanup.
|
5. Extract locked initialization that checks the incomplete-restore marker,
|
||||||
6. Make `applyAnalyzeProjection` session-only at its application boundary so
|
loads and validates or creates the session manifest, rechecks bounded
|
||||||
the runner no longer needs a run-manifest value. The invocation subset may
|
prerequisites, applies identity and effective-configuration provenance,
|
||||||
remain temporarily inside validation until Stage 3 deletes it.
|
saves the identity transition, ensures the canonical run directory, and
|
||||||
7. Delete run-only helpers such as `invocationIdentity.applyToRunManifest`,
|
loads configured secrets. All steps after manifest availability that
|
||||||
`requestedStageNames`, `applyStageResultToRunManifest`,
|
currently record a terminal failure must continue to do so through the
|
||||||
`applyEffectiveConfigProvenanceToRun`, and
|
session-only failure helper.
|
||||||
`setRunStageSemanticConfig` once unused.
|
6. Keep pre-lock failures free of persistent mutation and keep all later
|
||||||
8. Rewrite runner, terminal-failure, semantic-resume, assembled-workflow, and
|
manifest transitions protected by the same held lock. Do not add rollback,
|
||||||
lifecycle tests that currently inject a `RunStore` or load
|
a second lock, or a second manifest authority.
|
||||||
`RunSummary.RunManifestPath`. Assert the durable outcome through the session
|
7. Adapt existing bounded-run, restore-marker, identity, run-directory,
|
||||||
manifest and the immediate invocation outcome through `RunSummary`.
|
terminal-failure, and lock-release tests to exercise the assembled lifecycle.
|
||||||
Preserve coverage for cancellation, collaborator/preflight failures,
|
Add coverage only if the two-check prerequisite ordering or lock-release
|
||||||
session-save failure joining, successful and failed stage transitions,
|
error behavior is not already credibly protected.
|
||||||
self-skip, force invalidation, semantic evidence, distinct run IDs, and
|
|
||||||
run-local diagnostic paths. Delete tests whose sole purpose was run-record
|
### Exit Criteria
|
||||||
creation, terminalization, or historical inspection.
|
|
||||||
9. Update `docs/policy/architecture.md`, `docs/cli.md`, and the runner portions
|
- `go test ./internal/app ./internal/artifacts ./internal/manifest` succeeds.
|
||||||
of `docs/internal/manifest.md`: one atomic session-manifest update is the
|
- The top-level executor visibly performs unlocked preparation, acquires and
|
||||||
only durable progress transaction; a run ID and run directory remain, but
|
defers release of exactly one session lock, initializes locked state, and
|
||||||
there is no invocation manifest or persistent command summary.
|
proceeds to execution.
|
||||||
|
- Invalid preflight requests create no persistent invocation state; the locked
|
||||||
|
prerequisite recheck still prevents races with a prior invocation.
|
||||||
|
- The private runtime has cohesive fields and no public or cross-package API.
|
||||||
|
- `git diff --check` succeeds.
|
||||||
|
|
||||||
|
## Stage 3 — Isolate Collaborator Composition
|
||||||
|
|
||||||
|
**Status: Pending**
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
|
||||||
|
Make production collaborator construction one bounded lifecycle phase that is
|
||||||
|
selective, testable per invocation, and independent of stage transitions.
|
||||||
|
|
||||||
|
### Required Work
|
||||||
|
|
||||||
|
1. Define a small unexported invocation dependency value with explicit defaults
|
||||||
|
for the nondeterministic and external construction boundaries used by this
|
||||||
|
runner: UTC time, run-ID generation, default adapter/object-store creation,
|
||||||
|
effective remote-lock loading/revalidation support, and post-publish scoped
|
||||||
|
removal. Include a field only where tests need control over a real external,
|
||||||
|
destructive, clock, or randomness boundary; continue injecting completed
|
||||||
|
stage collaborators through `stage.Env`.
|
||||||
|
2. Add a private executor variant that accepts that dependency value and have
|
||||||
|
the ordinary executor supply production defaults. Normalize missing fields
|
||||||
|
once at the entry boundary so lifecycle methods never fall back to mutable
|
||||||
|
package state. Do not export the dependency type or store it globally.
|
||||||
|
3. Route run-ID creation and every runner timestamp through the invocation
|
||||||
|
dependencies. Convert `nowUTC` to an ordinary function for unrelated
|
||||||
|
command owners if it no longer needs to be mutable; do not broaden this stage
|
||||||
|
into a restore lifecycle refactor.
|
||||||
|
4. Extract collaborator composition from the runner into one operation over the
|
||||||
|
invocation runtime. Preserve current selection gates exactly: WhisperX only
|
||||||
|
for `transcribe`; Seriatim only for `merge`, `normalize`, `trim`, or `render`;
|
||||||
|
Audita only for `polish`; Notarius only when selected extraction requires it;
|
||||||
|
Scriptorium only for `trim` or `analyze`; object storage only when selected
|
||||||
|
stages/effective artifacts require it; remote lock loading only when needed;
|
||||||
|
and the no-op notifier only for `notify`.
|
||||||
|
5. Preserve injected collaborators, secret-loaded environment behavior,
|
||||||
|
effective lock merging, and the publish-time revalidation closure. A
|
||||||
|
composition failure after identity initialization remains a persisted
|
||||||
|
terminal session failure with its existing useful context.
|
||||||
|
6. Route post-publish cleanup's scoped deletion through the invocation
|
||||||
|
dependency value and delete `removeRunScopedDirFn`. Preserve cleanup
|
||||||
|
obligation creation, per-target persistence, retry, and failure behavior.
|
||||||
|
7. Consolidate selective-composition tests into table-driven or focused
|
||||||
|
behavioral cases. Test that an unselected external boundary is not
|
||||||
|
constructed only where avoiding that construction is an operational
|
||||||
|
requirement; do not assert private helper ordering.
|
||||||
|
|
||||||
|
### Exit Criteria
|
||||||
|
|
||||||
|
- `go test ./internal/app` succeeds, including composition, remote-lock,
|
||||||
|
cleanup, and bounded-stage tests.
|
||||||
|
- Collaborator construction is absent from the top-level runner and stage loop,
|
||||||
|
but remains an application-owned production-composition concern.
|
||||||
|
- Runner time, randomness, external construction, and destructive cleanup are
|
||||||
|
controllable per invocation without mutable runner globals.
|
||||||
|
- Selected-stage composition and terminal-failure behavior remain unchanged.
|
||||||
|
- `git diff --check` succeeds.
|
||||||
|
|
||||||
|
## Stage 4 — Extract One-Stage Execution
|
||||||
|
|
||||||
|
**Status: Pending**
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
|
||||||
|
Give one private operation complete ownership of a single stage attempt while
|
||||||
|
preserving every durable transition and failure boundary.
|
||||||
|
|
||||||
|
### Required Work
|
||||||
|
|
||||||
|
1. Extract an operation on the invocation runtime that executes exactly one
|
||||||
|
selected stage and returns a small execution-owned outcome sufficient to
|
||||||
|
update the in-memory summary or stop the invocation. It may coordinate the
|
||||||
|
shared decision/transition helpers but must not select the next stage or
|
||||||
|
release the session lock.
|
||||||
|
2. Within that operation, preserve this order:
|
||||||
|
- compute the stage semantic fingerprint;
|
||||||
|
- run stage-owned resume validation when the recorded success is a skip
|
||||||
|
candidate;
|
||||||
|
- build and apply the pure pre-execution decision and persist any
|
||||||
|
non-resumable stale/invalidation transition;
|
||||||
|
- return a skip outcome without invoking the stage when still resumable;
|
||||||
|
- capture prior aggregate/analyze state, begin the attempt, persist
|
||||||
|
`running`, and then invoke `Stage.Run`;
|
||||||
|
- validate the stage result and any analyze projection;
|
||||||
|
- apply failure, self-skip, or success transitions and required dependent
|
||||||
|
invalidation; and
|
||||||
|
- persist the terminal state before returning.
|
||||||
|
3. Preserve failure semantics for semantic fingerprinting, resume validation,
|
||||||
|
invalidation, the pre-run save, stage execution, result validation,
|
||||||
|
self-skip/success saves, and terminal failure persistence. A failed stage or
|
||||||
|
persistence operation stops later stages. Distinct invalidation/save errors
|
||||||
|
remain joined with the originating failure.
|
||||||
|
4. Preserve current analyze behavior exactly: a valid partial failure
|
||||||
|
projection may be applied before recording failure; a successful projection
|
||||||
|
supplies aggregate outputs; and failure to save a successful projection
|
||||||
|
restores prior analyze authority before recording aggregate failure.
|
||||||
|
Introduce no callback/store dependency into `internal/stage`.
|
||||||
|
5. Keep manifest save calls explicit in the one-stage owner. Do not hide them in
|
||||||
|
generic state-machine hooks or teach `manifest.Store` orchestration policy.
|
||||||
|
6. Reduce the outer stage loop to call the one-stage operation, append its
|
||||||
|
executed/skipped classification, and stop on error. Preserve deterministic
|
||||||
|
`StageNames`, `Executed`, and `Skipped` order and current logging semantics.
|
||||||
|
7. Reconcile runner tests around observable manifest state, invocation summary,
|
||||||
|
stage calls, and errors. Preserve coverage for ordinary skip, force,
|
||||||
|
non-resumable state, self-skip, result validation, cancellation, downstream
|
||||||
|
invalidation outside a bounded range, save failures, analyze rollback, and
|
||||||
|
stopping after failure. Remove redundant tests that exist only to pin the old
|
||||||
|
monolithic control flow.
|
||||||
|
|
||||||
### Exit Criteria
|
### Exit Criteria
|
||||||
|
|
||||||
- `go test ./internal/app ./internal/stage ./internal/manifest` succeeds.
|
- `go test ./internal/app ./internal/stage ./internal/manifest` succeeds.
|
||||||
- `executePlan` creates no `runs/<run_id>/manifest.json` and exposes no run
|
- The stage loop contains no duplicated transition policy and one-stage
|
||||||
manifest store seam, while run IDs, run directories, diagnostics, session
|
execution has one clear persistence owner.
|
||||||
transitions, and summaries remain available.
|
- A later stage is never attempted after a stage or required manifest save
|
||||||
- A hypothetical diagnostic-record write cannot fail a stage because no such
|
fails, and no failed/interrupted attempt is presented as successful.
|
||||||
persistence operation exists; session-manifest failures remain visible and
|
- Analyze still uses its pre-Workstream-6 aggregate persistence boundary.
|
||||||
authoritative.
|
|
||||||
- Runner behavior tests obtain durable state only from the session manifest.
|
|
||||||
- `git diff --check` succeeds.
|
- `git diff --check` succeeds.
|
||||||
|
|
||||||
## Stage 3 — Remove Invocation-Only Analyze Projection
|
## Stage 5 — Isolate Finalization And Simplify The Lifecycle Owner
|
||||||
|
|
||||||
**Status: Completed**
|
**Status: Pending**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Give analyze one in-memory projection—the reconciled session collection—without
|
Complete the runner decomposition so the lifecycle and transaction boundaries
|
||||||
prematurely implementing Workstream 6 checkpoint semantics.
|
are easier to read than the former monolith.
|
||||||
|
|
||||||
### Required Work
|
### Required Work
|
||||||
|
|
||||||
1. Remove `Invocation` from `stage.AnalyzeStateProjection` and update its
|
1. Extract finalization that performs the current post-publish cleanup only
|
||||||
comment to describe only the reconciled session authority proposed for the
|
when publish actually executed, using the runtime's session manifest,
|
||||||
next session-manifest save. Retain the pointer wrapper so “no analyze update”
|
manifest path, environment, executed-stage list, and invocation-scoped
|
||||||
remains distinguishable from a valid empty collection.
|
deletion dependency. Preserve the special cleanup-failure persistence and
|
||||||
2. In `internal/stage/analyze.go`, delete the separate invocation-record map and
|
the fact that a committed remote publish remains authoritative.
|
||||||
every write, clone, or failure projection associated only with it. Successful
|
2. Build `RunSummary` from the runtime's resolved identity and ordered
|
||||||
and failed analyze results continue to return the complete reconciled
|
accumulators only after all selected stages and required cleanup complete.
|
||||||
session collection under the existing rules.
|
Continue returning no success summary on invocation failure.
|
||||||
3. Simplify `internal/app/analyze_projection.go`: validate and clone only the
|
3. Make the top-level executor an explicit sequence: unlocked preparation;
|
||||||
session collection, remove invocation/session subset comparison, apply only
|
layout preparation; visible lock acquisition/deferred release; locked state
|
||||||
the session collection, and derive aggregate analyze outputs only from that
|
initialization; collaborator composition; ordered one-stage execution; and
|
||||||
collection. Retain rejection of projections from non-analyze stages,
|
finalization/summary. It must retain meaningful error context at each phase
|
||||||
contradictory ordinary outputs, malformed records, and illegal skipped or
|
and must not delegate that entire sequence to a new monolithic helper.
|
||||||
error result shapes.
|
4. Place private lifecycle concerns in focused files according to ownership—for
|
||||||
4. Preserve `captureAnalyzeState` and `restoreAnalyzeState` for the current
|
example runtime/preparation, composition, stage execution, and finalization—
|
||||||
single-save boundary. Do not add manifest-store access to the analyze stage,
|
while keeping exact shared transition logic in `run_control.go`. Remove dead
|
||||||
persist inside its artifact loop, or change retry/force behavior in this
|
helpers, stale comments, duplicate state, and imports left by extraction.
|
||||||
stage.
|
5. Review the resulting runtime for service-locator growth. Remove fields used
|
||||||
5. Rewrite `analyze_projection_test.go`, analyze incremental tests, and mixed
|
by only one local operation unless retaining them materially clarifies the
|
||||||
runner tests around one reconciled session collection. Delete assertions
|
lifecycle. Keep collaborators in `stage.Env` and persistence/path policy in
|
||||||
about per-invocation artifact subsets. Retain behavior coverage for partial
|
their existing owners.
|
||||||
failure state, unrelated current records, invalid projections, persistence
|
6. Run focused assembled-workflow, cleanup, bounded-run, resume, manifest-save,
|
||||||
failure rollback, and aggregate output derivation.
|
and release-error tests. Add no tests for private file placement, helper
|
||||||
6. Update `docs/internal/stage-analyze.md` and the analyze-state section of
|
count, or line count.
|
||||||
`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
|
### Exit Criteria
|
||||||
|
|
||||||
- `go test ./internal/stage ./internal/app ./internal/manifest` succeeds.
|
- `go test ./internal/app ./internal/stage ./internal/manifest ./internal/artifacts`
|
||||||
- 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: Completed**
|
|
||||||
|
|
||||||
### 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.
|
succeeds.
|
||||||
- Except for the explicitly retained `RemoteArtifactTypeRunManifest` wire
|
- `executePlan` is a short, readable lifecycle owner with one visibly scoped
|
||||||
value and its remote-decoder compatibility test, searches for `RunManifest`,
|
lock and no nested stage state machine or collaborator-construction block.
|
||||||
`RunStore`, `CreateRun`, `LoadRun`, `SaveRun`, `RunManifestPath`,
|
- Cleanup remains a post-publish obligation with unchanged behavior, awaiting
|
||||||
`run_manifest.go`, and the local `runs/<run_id>/manifest.json` contract find
|
Workstream 9.
|
||||||
no current production or test implementation.
|
- The refactor has removed obsolete code rather than retaining parallel old and
|
||||||
- Session manifest schema validation and round trips remain fully covered.
|
new lifecycle paths.
|
||||||
- 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.
|
- `git diff --check` succeeds.
|
||||||
|
|
||||||
## Stage 5 — Reconcile Current Documentation And Close Workstream 4
|
## Stage 6 — Remove Global Runner Seams And Close Workstream 5
|
||||||
|
|
||||||
**Status: Completed**
|
**Status: Pending**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Prove the session-only target state across the repository and leave one accurate
|
Prove the target architecture through invocation-scoped command tests, accurate
|
||||||
implementation narrative for the next workstream.
|
current documentation, and complete repository validation.
|
||||||
|
|
||||||
### Required Work
|
### Required Work
|
||||||
|
|
||||||
1. Search current production code, tests, fixtures, examples, scripts, and
|
1. Introduce the smallest private command-level helper needed to pass a
|
||||||
nonhistorical documentation for run-manifest types, paths, JSON fields,
|
pipeline-executor function for one call through `Execute`, `Run`,
|
||||||
stores, publish classifications, invocation projections, and dual-save or
|
`RegenerateArtifacts`, and the single-stage command path. Public command
|
||||||
terminal-synchronization language. Remove stale surfaces or explain the
|
functions continue to use the production executor. The alias must still be
|
||||||
retained run ID/run directory without implying a structured record.
|
exactly equivalent to `run --force --from extract --through analyze` with
|
||||||
2. Reconcile canonical owners, especially `docs/policy/architecture.md`,
|
caller options forwarded under the existing rules.
|
||||||
`docs/cli.md`, `docs/operations.md`, `docs/troubleshooting.md`,
|
2. Delete `executeStagesFn` and `runCommandFn`. Rewrite affected CLI, profile,
|
||||||
`docs/internal/overview.md`, `docs/internal/manifest.md`,
|
remote-session, restore-workflow, assembled-workflow, bounded-run, alias, and
|
||||||
`docs/internal/stage-analyze.md`, `docs/internal/stage-extract.md`, and
|
artifact-selection tests to call the private command helper with an explicit
|
||||||
`docs/internal/stage-publish.md`. Keep schema definitions in the manifest
|
executor or to exercise the real assembled runner. Do not serialize tests
|
||||||
owner, filesystem/remote behavior in operations, and implementation details
|
around package-global save/replace/restore choreography.
|
||||||
in internal documents rather than duplicating them.
|
3. Confirm that `removeRunScopedDirFn` is gone and that runner tests do not
|
||||||
3. Do not edit immutable historical release notes or completed audit documents.
|
replace `nowUTC`. Inventory remaining mutable function variables in
|
||||||
Roadmap references may retain the phrase “run manifest” when describing the
|
`internal/app`; leave unrelated configuration-loading and restore seams for
|
||||||
problem and approved removal. Current instructions must not claim the file
|
their owning future work, but ensure no runner, run-command, alias, or
|
||||||
is produced or required.
|
post-publish-cleanup test mutates process-global behavior.
|
||||||
4. Review the affected test suite under `docs/policy/testing.md`. Consolidate
|
4. Review test value under `docs/policy/testing.md`. Consolidate duplicate
|
||||||
leftover tests that merely encode the deleted write choreography, while
|
command-wiring and lifecycle cases exposed by the new narrow seams while
|
||||||
retaining meaningful session durability, transition, recovery, current-run
|
retaining consequential lock, persistence, invalidation, recovery,
|
||||||
diagnostics, remote publication, and representative assembled-workflow
|
cancellation, external-boundary, and representative assembled-workflow
|
||||||
coverage.
|
coverage.
|
||||||
5. Update Workstream 4 in `refactoring.md` from `Pending` to `Complete` and
|
5. Update current internal documentation where ownership requires it:
|
||||||
update every stage plus the purpose/status section of this plan to
|
`docs/internal/overview.md` should summarize the explicit runner lifecycle;
|
||||||
`Completed` only after the target state and all checks are proven. Do not
|
`docs/internal/manifest.md` should describe the shared pre-execution decision
|
||||||
change later workstream statuses.
|
and single persistence owner without documenting private helper names; and
|
||||||
6. Run the complete repository validation from `docs/development.md`:
|
`docs/internal/adapters.md` should describe selective application-owned
|
||||||
|
composition. Update architecture policy only if implementation reveals a
|
||||||
|
normative boundary not already stated. Do not duplicate CLI/configuration
|
||||||
|
contracts or edit historical release documents and completed audit findings.
|
||||||
|
6. Search current code and documentation for stale claims about the monolithic
|
||||||
|
runner, independent plan/run decisions, or mutable runner seams. Remove only
|
||||||
|
inaccurate current-behavior text; roadmap and audit history remain valid.
|
||||||
|
7. Update Workstream 5 in `refactoring.md` from `Pending` to `Complete`, and
|
||||||
|
change all six stage statuses plus this plan's status to completed only after
|
||||||
|
the target state and all checks are proven. Leave Workstream 6 `Pending`.
|
||||||
|
8. Run the complete repository validation from `docs/development.md`:
|
||||||
`go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
|
`go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
|
||||||
`go test ./internal/doccheck`, and
|
`go test ./internal/doccheck`, and
|
||||||
`go test ./internal/config -run '^TestExamplesLoadAndValidate$'`. Run
|
`go test ./internal/config -run '^TestExamplesLoadAndValidate$'`. Also run
|
||||||
`git diff --check` and confirm the worktree contains only intended changes.
|
`git diff --check` and confirm the implementation commit leaves no unintended
|
||||||
|
worktree changes.
|
||||||
|
|
||||||
### Exit Criteria
|
### Exit Criteria
|
||||||
|
|
||||||
- The session manifest is the only structured durable local progress record;
|
- All repository-wide validation succeeds on Go 1.26.
|
||||||
no current code or documentation requires a run manifest.
|
- Planning and execution share one pure pre-execution decision model while
|
||||||
- Run IDs, canonical run directories, bounded diagnostics, generated
|
actual results and persistence remain execution-owned.
|
||||||
configuration, receipts, immediate summaries, immutable run prefixes, and
|
- The runner reads as an explicit lifecycle with one session lock and one
|
||||||
remote publication remain functional without a second progress transaction.
|
session-manifest authority.
|
||||||
- Publish uses session-manifest evidence, emits no new run-manifest artifact,
|
- Runner, run-command, alias, and cleanup tests use invocation-scoped
|
||||||
and still reads verified historical remote commits without interpreting their
|
dependencies rather than mutable package-global function substitution.
|
||||||
old diagnostic record.
|
- Current internal documentation accurately describes the implemented design
|
||||||
- All repository-wide validation succeeds on the maintained Go toolchain.
|
at the appropriate level.
|
||||||
- Workstream 4 and all five stages are marked `Complete`; Workstream 5 remains
|
- Workstream 5 and all six stages are marked `Complete`; Workstream 6 is the
|
||||||
the next pending workstream.
|
next pending workstream.
|
||||||
- `git status --short` is empty after the implementation commit.
|
- `git status --short` is empty after the implementation commit.
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
None. The approved audits, current architecture, and decisions above are
|
None. The approved audits, current policies, and Workstream 5 decisions resolve
|
||||||
sufficient to implement this workstream without further product or policy
|
the behavior, architecture, testability, and sequencing choices required for
|
||||||
choices.
|
implementation.
|
||||||
|
|||||||
Reference in New Issue
Block a user