1036 lines
79 KiB
Markdown
1036 lines
79 KiB
Markdown
# Codebase Audit Findings
|
|
|
|
Status: in progress
|
|
|
|
This document is the working ledger and final report for the audit defined by
|
|
the [audit plan](audit-plan.md) and [audit sequence](audit-sequence.md). The
|
|
audit is investigative: candidate findings below are not remediation changes.
|
|
|
|
## Audit Identity And Baseline
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| Audited revision | `74e2d21de5fb2ada0be5ef3fe9333e0d48ac7fb3` (`Close the completed roadmap documents`) |
|
|
| Branch | `main`, attached worktree |
|
|
| Initial worktree state | Untracked `docs/roadmap/audit-plan.md` and `docs/roadmap/audit-sequence.md`; no production or test changes |
|
|
| Audit date | 2026-08-10 UTC |
|
|
| Toolchain | `go version go1.26.5 linux/amd64` |
|
|
| Platform | `GOOS=linux`, `GOARCH=amd64` |
|
|
| Repository root | `/home/eric/Workspace/narratio` |
|
|
|
|
The two initial untracked files are the audit specification supplied for this
|
|
run. Adding this ledger and tracking those documents changes documentation
|
|
only; all implementation and test evidence remains pinned to the revision
|
|
above. If implementation or tests change, affected audit stages must be rerun
|
|
and this section must record the new revision.
|
|
|
|
### Baseline Commands
|
|
|
|
| Command | Result | Wall time | Evidence or limitation |
|
|
| --- | --- | --- | --- |
|
|
| `go test -count=1 ./...` | pass | 3.34 s | All 23 packages passed; `cmd/narratio` has no test files. |
|
|
| `go test -race -count=1 ./...` | fail | 55.65 s | Race in `internal/adapters/whisperx.(*FakeClient).Transcribe` at `fake.go:45`, reached concurrently by `TestTranscribeStageTranscribesPreparedAudio`; candidate `TST-001`. All packages reported before `internal/stage` passed. |
|
|
| `go vet ./...` | pass | 0.47 s | No diagnostics. |
|
|
| `go build -o "$audit_build_dir/narratio" ./cmd/narratio` | pass | 1.03 s | Built outside the repository in `/tmp/tmp.x11pJL7014`. |
|
|
| `go test -coverprofile="$audit_build_dir/coverage.out" ./...` | pass | 11.05 s | Diagnostic coverage only; no percentage is treated as a gate. |
|
|
|
|
Coverage ranged from 69.8% (`internal/manifest`) to 100% (`internal/logging`)
|
|
among tested packages. `cmd/narratio` reported 0% because it has no tests. The
|
|
remaining package results ranged from 70.1% to 88.1%. Stage 12 owns the
|
|
risk-based interpretation; these numbers are inventory signals only.
|
|
|
|
### Code Graph Freshness And Structural Inventory
|
|
|
|
The `narratio` graph was rebuilt in `moderate` mode after the revision was
|
|
pinned. Its branch record reports the exact audited HEAD, `main`, and the
|
|
repository root above. The index contains 2,407 nodes and 13,181 edges across
|
|
224 modeled files: 1,494 functions, 136 methods, 226 structs, 12 interfaces,
|
|
and 20 modeled package nodes. The moderate filter excluded documentation,
|
|
examples, `.git`, `.codex`, and `cmd/narratio`; the executable entry point was
|
|
therefore verified through `go list` and direct inspection instead of graph
|
|
evidence. Internal production code is represented at the pinned revision.
|
|
|
|
Repository inventory at that revision:
|
|
|
|
- 23 Go packages, including `cmd/narratio`;
|
|
- 221 tracked Go files and 95 tracked `_test.go` files;
|
|
- 278 tracked files total;
|
|
- one process entry point, `cmd/narratio/main.go`, delegating to
|
|
`internal/app.Execute`;
|
|
- 11 canonical stages returned by `internal/stage.All`; and
|
|
- 12 modeled interfaces, of which 11 are Narratio boundaries and one is the
|
|
private AWS S3 client seam.
|
|
|
|
Graph call tracing from `internal/app.Execute` confirms command dispatch into
|
|
run, single-stage, clean, and session-helper paths, followed by configuration,
|
|
artifact/path, manifest, stage, storage, restore, and cleanup owners. The
|
|
production import inventory shows no lower-level package importing
|
|
`internal/app`; apparent graph rollups such as `stage -> app`, `adapters -> app`,
|
|
and `config -> app` came from test relationships or graph classification and
|
|
are rejected as production dependency reversals at this mapping stage.
|
|
|
|
### Metric Signals For Later Review
|
|
|
|
These are prioritization signals, not findings:
|
|
|
|
| Signal | Evidence | Assigned review |
|
|
| --- | --- | --- |
|
|
| High fan-in | `app.Error` (207), stage `Run` symbols (151), `app.Execute` (108), `stage.sessionPathsForEnv` (105), `manifest.New` (72), `manifest.MarkStageSucceeded` (56), `app.executeStages` (48), `artifacts.S3SessionPrefix` (41), and `artifacts.SessionWorkDirForCampaign` (37) | Owning behavior stages, then Stage 11 |
|
|
| High complexity | `app.executeStages` cyclomatic 54/cognitive 96; `previouscache.BuildPlan` 22/38; `analyzeStage.Run` 20/27; `audita.NewSubprocessRunner` 17/25; `app.SessionInit` 20/21 | Stages 2, 5, 7, 10, then 11 |
|
|
| Exact similarity | `app.Analyze`/`app.Publish`, `manifest.Load`/`LoadRun`, `manifest.Create`/`CreateRun`, adapter constructors, and Seriatim fake methods | Owning behavior stages, then Stage 11 |
|
|
| Test-heavy hotspot noise | Several test functions and fakes rank highly in transitive-depth and fan-in results | Stage 12; do not infer production risk from the metric |
|
|
|
|
### Automation And Fixture Inventory
|
|
|
|
- `.woodpecker/release.yml` is tag-only release automation. It cross-builds
|
|
Linux, macOS, and Windows binaries with Go 1.25, then publishes release
|
|
assets. It does not run tests, race tests, vet, or example validation.
|
|
- `examples/` contains 19 maintained files: pipeline, campaign, session,
|
|
template, stable-input, and placeholder-audio fixtures. Configuration tests
|
|
are documented as their validation owner.
|
|
- No fuzz tests, golden files, golden-update switches, opt-in/live test tags, or
|
|
`go:generate` test mechanisms were found.
|
|
- Platform build constraints exist for the native no-replace directory tests
|
|
and unsupported-platform fallback in `internal/fileops`.
|
|
|
|
## Execution Coverage Ledger
|
|
|
|
| Stage | Status | Evidence and result |
|
|
| --- | --- | --- |
|
|
| 0: baseline | complete | Revision/environment pinned; graph refreshed; inventories and every prescribed baseline command recorded. `TST-001` owns the non-blocking race limitation. |
|
|
| 1: contract and boundary map | complete | Canonical contracts and focused internal docs read; ownership, stage-contract, lifecycle, scenario, area, and preliminary risk-to-test matrices recorded below. |
|
|
| 2: runner and manifest | complete | Full/single-stage entry paths, every lifecycle outcome, both manifest models/transitions, save disagreement states, canonical invalidation boundaries, and runner lock lifetime reviewed. Focused app/manifest test and race commands passed. Confirmed `COR-001` and `RSK-001`; assigned `DUP-001`, `SIM-001`, `COM-001`, `TST-002`, and lock-release details to later stages. |
|
|
| 3: paths and filesystem | complete | Canonical local/remote paths, every artifact source family, filesystem mutations, directory promotion, cleanup confinement, permissions, and lock mechanics reviewed. Focused normal and race commands passed. Confirmed `COR-002`, `COR-003`, `RSK-002`, `RSK-003`, and `RSK-004`; added `DUP-002` and `TST-003`, and refined `DUP-001`. |
|
|
| 4: publish and cleanup | not_started | Assigned remote commit and cleanup scenarios below. |
|
|
| 5: restore and previous state | not_started | Assigned restore and previous-cache scenarios below. |
|
|
| 6: configuration and composition | not_started | Assigned configuration, CLI composition, and process-boundary areas below. |
|
|
| 7: adapters and shared support | not_started | Assigned external-boundary and cancellation areas below. |
|
|
| 8: ordinary stages | not_started | Assigned prepare/transcript behavior and disabled-outcome questions below. |
|
|
| 9: extraction | not_started | Assigned extraction promotion, provenance, and resume scenario below. |
|
|
| 10: analyze and dependencies | not_started | Assigned artifact dependency/source and selection scenario below. |
|
|
| 11: maintainability | not_started | Seeded by graph complexity, similarity, and fan-in signals only. |
|
|
| 12: test policy | not_started | Seeded by intended owners and baseline execution observations. |
|
|
| 13: synthesis | not_started | No final ranking or accepted-risk decisions yet. |
|
|
|
|
## Area Coverage And Ownership
|
|
|
|
Every area in the audit plan has a primary execution owner. `assigned` means it
|
|
has been mapped but not behaviorally audited.
|
|
|
|
| Inspection area | Canonical implementation owner | Primary audit stage | Status |
|
|
| --- | --- | --- | --- |
|
|
| Process and application boundary | `cmd/narratio`, `internal/app` | 6 (runner lifecycle portions in 2; publish/restore portions in 4-5) | assigned |
|
|
| Stage registry and runner | `internal/stage`, `internal/app` | 2 | reviewed |
|
|
| Configuration | `internal/config` | 6 | assigned |
|
|
| Prepare and audio | `internal/stage`, `internal/audio`, `internal/previouscache` | 8 | assigned |
|
|
| Transcript stages | `internal/stage` plus tool adapters | 8 | assigned |
|
|
| Extraction | `internal/stage`, Notarius adapter, `internal/fileops` | 9 | assigned |
|
|
| Analyze and artifact dependencies | `internal/stage`, `internal/artifacts`, `internal/artifactpolicy` | 10 | assigned |
|
|
| Publish and cleanup | `internal/stage`, `internal/app` | 4 | assigned |
|
|
| Manifest state | `internal/manifest`, transition policy in `internal/app` | 2 | reviewed |
|
|
| Artifacts, paths, and policy | `internal/artifacts`, `internal/artifactpolicy`, `internal/pathsafe` | 3 (resolution consumption revisited in 10) | reviewed |
|
|
| Restore | `internal/app`, `internal/artifacts`, `internal/previouscache`, `internal/audio` | 5 | assigned |
|
|
| File operations | `internal/fileops`, `internal/pathsafe`, local artifact store | 3 (promotion vertical slice in 9) | reviewed |
|
|
| External adapters and storage | `internal/adapters`, `internal/audio` | 7 | assigned |
|
|
| Shared models and diagnostics | `internal/artifactmodel`, `internal/contracts`, `internal/logging` | 7 (maintainability revisited in 11) | assigned |
|
|
| Tests, examples, and automation | package test owners, `examples/`, `.woodpecker/` | 12 | assigned |
|
|
|
|
## Package And Interface Ownership Map
|
|
|
|
| Package | Owned contract or policy | Important boundaries | Audit owner |
|
|
| --- | --- | --- | --- |
|
|
| `cmd/narratio` | Process entry and exit; CLI delegates behavior to app | `main -> app.Execute` | 6 |
|
|
| `internal/app` | Command dispatch, composition, locking, planning, lifecycle, restore, cleanup, reporting | `Execute`, `executeStages`; consumes stage/artifact/manifest/adapter contracts | 2, 4-6 |
|
|
| `internal/config` | Strict discovery, defaults, resolve, template, and validation rules | Config models and load/resolve/validate functions | 6 |
|
|
| `internal/stage` | Canonical order and stage behavior | `Stage`, `ResumeValidator`, `Env`; adapter interfaces are injected | 2, 4, 8-10 |
|
|
| `internal/manifest` | Session/run models, transitions, validation, atomic persistence | `Store`; transition methods record but do not choose policy | 2 |
|
|
| `internal/artifacts` | Artifact identity/resolution, paths/keys, local store, remote current-state mechanics | `Store`; consumes explicit storage keys | 3, 5, 10 |
|
|
| `internal/artifactpolicy` | Configured source/destination identity and safety policy | Narrow validators used by config, artifacts, app, and stages | 3, 10 |
|
|
| `internal/artifactmodel` | Shared serialized artifact, contract, and provenance models | Data contract only | 3, 7 |
|
|
| `internal/pathsafe` | Confined relative path and destination mechanics | Narrow validation helpers; no stage policy | 3 |
|
|
| `internal/fileops` | Atomic files, copies, hashing, no-replace directory promotion | Filesystem mechanics receive explicit paths | 3, 9 |
|
|
| `internal/previouscache` | Deterministic previous-session requirement planning/materialization | Uses explicit object-store and artifact contracts | 5, 8, 10 |
|
|
| `internal/audio` | S3 audio spool/cache materialization | Uses `storage.ObjectStore`; no stage ordering | 5, 8 |
|
|
| `internal/contracts` | Bounds and shared JSON validation models | Data contract only | 7, 8 |
|
|
| `internal/logging` | Shared logger construction | `slog` composition | 7, 11 |
|
|
| `internal/adapters/whisperx` | WhisperX HTTP protocol | `Client` | 7 |
|
|
| `internal/adapters/seriatim` | Merge/normalize/trim/render subprocess protocol | `Runner` | 7 |
|
|
| `internal/adapters/audita` | Audita subprocess protocol | `Runner` | 7 |
|
|
| `internal/adapters/scriptorium` | Scriptorium run/render subprocess protocol | `Runner` | 7 |
|
|
| `internal/adapters/notarius` | Notarius invocation and receipt boundary | `Runner` | 7 (vertical behavior in 9) |
|
|
| `internal/adapters/notify` | Notification transport | `Sender` | 7 |
|
|
| `internal/adapters/storage` | Explicit bucket-relative object-store operations and S3 mechanics | `ObjectStore`; private `s3API` test seam | 7 |
|
|
| `internal/adapters/subprocess` | Shared bounded subprocess/config/log mechanics | Concrete helper package, not stage policy | 7 |
|
|
|
|
The graph reported no inbound production callers of `Stage.Declares`; text
|
|
search found definitions and test stubs but no production invocation. This
|
|
reduces the current impact of `ARC-001` but makes the interface's intended owner
|
|
and future use an explicit question rather than resolving the mismatch.
|
|
|
|
## Stage Contract Matrix
|
|
|
|
The table separates declared/static contracts from dynamic behavior. All
|
|
executed stages use the runner's session/run transitions. Unless noted, a
|
|
successful result records returned outputs, diagnostics, generated
|
|
configuration, and metadata; a different effective executed outcome can stale
|
|
succeeded downstream work, while force pre-stales succeeded downstream work.
|
|
|
|
| Order and stage | Inputs and outputs | Configuration and adapters | Skip/resume behavior | Materialization and manifest effects |
|
|
| --- | --- | --- | --- | --- |
|
|
| 1 `prepare` | Config, stable inputs, one audio mode, optional previous requirements -> canonical `inputs/**`, `audio/**`, optional `previous/**`, `manifest.inputs` | All resolved config; storage for S3/current previous state; audio/artifact/previous-cache services | No stage-specific resume validator or explicit self-skip | Writes canonical session inputs and deterministic input records; unlike processing stages, `Declares` labels produced canonical files as inputs. |
|
|
| 2 `transcribe` | Prepared FLAC files -> raw per-speaker JSON | WhisperX URL/language/retry/timeout/concurrency; `whisperx.Client` | Ordinary succeeded-record skip; no validator/self-skip | Bounded concurrent run-local writes, validation, then canonical transcript materialization. |
|
|
| 3 `merge` | Raw transcripts, speakers, autocorrect -> base transcript, optional report | Seriatim merge fields; `seriatim.Runner` | Ordinary succeeded-record skip | Normalized scratch inputs and run-local results validate before canonical transcript/report materialization. |
|
|
| 4 `polish` | Base transcript, glossary -> polished transcript, optional report | Audita fields/credential reference; `audita.Runner` | Ordinary succeeded-record skip | Run-local output, report, logs, and generated config; validates before canonical materialization. |
|
|
| 5 `normalize` | Polished transcript -> final transcript, optional report | Normalize plus Seriatim fields; `seriatim.Runner` | Ordinary succeeded-record skip | Manifest-first input; run-local validation then configurable canonical output/report. |
|
|
| 6 `trim` | Final transcript -> final-trimmed transcript and, when enabled, bounds | Trim, bounds, Scriptorium, and Seriatim fields; both runners when enabled | Disabled trim copies input and still succeeds; no explicit self-skip or resume validator | Run-local bounds/trim result validates then materializes; debug render is diagnostic, not output. |
|
|
| 7 `extract` | Final-trimmed source -> immutable index and configured lane outputs | Notarius executable/config/pipeline/timeout/output contracts; `notarius.Runner` | Disabled is explicit `notarius_disabled` self-skip; only current `ResumeValidator`; obsolete reruns, unsafe validation errors | Validates run-local receipt/bundle completely, promotes to unique immutable bundle, records checksums/contracts/provenance; identical repeated self-skip is stable. |
|
|
| 8 `render` | Final and final-trimmed JSON -> two Markdown transcripts | Render and Seriatim fields; `seriatim.Runner` | Disabled returns a zero-disposition result with skip metadata, therefore runner-level success rather than explicit self-skip; no validator | Run-local text validates non-empty before canonical materialization when enabled. |
|
|
| 9 `analyze` | Dynamic built-in, prepared, extraction, configured, and previous sources -> selected configured artifact outputs | Scriptorium artifact graph/selection; `scriptorium.Runner` | Missing config or no executable artifacts returns success with skip metadata; no validator | Topological run-local generation/reuse, validation, canonical outputs, deterministic metadata; static `Declares` omits dynamic outputs and several input families. |
|
|
| 10 `publish` | Session/run state, selected output rules, locks, previous cache -> remote run/output/current objects | Publish/storage/selection fields; `storage.ObjectStore` | Disabled publish or run upload returns success with skip metadata; force cannot bypass locks; no validator | Deterministic uploads; `current/manifest.json` before `current/run_id.txt`; commit metadata gates cleanup. Static prerequisites omit extract because disabled extraction is valid and lane resolution enforces required extraction state when selected. |
|
|
| 11 `notify` | No implemented persisted pipeline input/output | Optional `notify.Sender`; default no-op | Ordinary succeeded-record skip; no explicit self-skip or validator | Placeholder metadata and optional notification call; no returned output. `Declares` nevertheless advertises placeholder input/output paths. |
|
|
|
|
Configuration, adapters, skip policy, and dynamic outputs are not represented
|
|
by `IODecl`; their current canonical owners are the focused stage,
|
|
configuration, and integration contracts. Whether `IODecl` should remain a
|
|
partial display type or become an enforceable declaration is deferred as
|
|
`ARC-001`.
|
|
|
|
## Lifecycle Matrix
|
|
|
|
This began as the intended contract map and is now source-backed for both
|
|
durable ledgers by the Stage 2 review.
|
|
|
|
| Outcome | Session manifest intent | Invocation manifest intent | Downstream and next-invocation intent |
|
|
| --- | --- | --- | --- |
|
|
| First run | Pending/non-succeeded stage becomes running, then succeeded/failed/skipped; executing clears older result payload first | New run record; action `run`; terminal status records this invocation | Success enables later stages; failure stops current execution and an effective outcome change may stale succeeded downstream records. |
|
|
| Already-succeeded skip | Existing succeeded session record and payload remain unchanged, subject to resume validation | Action/status record a skip and stable reason for this invocation | Reusable result remains authoritative; pipeline continues. |
|
|
| Explicit self-skip | Session stage becomes skipped, clears older result payload, and may record bounded current skip details | Action was `run`, outcome is skipped with reason | Reconsidered later; a changed effective upstream outcome stales succeeded downstream work; identical extraction disabled skip is stable. |
|
|
| Failure | Current stage becomes failed with error; current output/log/config/metadata payload is cleared | Action `run`, failed outcome and overall failed run | Current execution stops; affected succeeded downstream work is intended to stale; later invocation reruns non-succeeded stages. |
|
|
| Interruption | Model admits `interrupted`, but production never writes it; process death leaves the last durable status `running` and the running transition has already cleared the target's prior result details | The run remains non-terminal at its last durable per-stage state; no load or startup reconciliation changes it | Non-succeeded session stages execute on the next included plan, so continuation is conservative; the old invocation record remains inaccurate under confirmed `RSK-001`. |
|
|
| Forced replacement | Target execution starts fresh; succeeded downstream records are pre-marked stale; current target payload clears on running | Force flag and `run` action recorded | Replacement result determines later execution; locks and safety policy remain authoritative. |
|
|
| Non-resumable success | Prior success becomes stale while retaining details long enough for diagnosis/validation, then running clears them | Current invocation records execution after validation rejects skip | Obsolete result reruns; unsafe inability to decide stops without silently replacing current success. |
|
|
| Successful rerun | Target becomes succeeded with only new outputs/diagnostics/config/metadata | Current invocation records its own new success; earlier run manifests remain unchanged | A rerun after a non-succeeded state stales succeeded downstream work; force already stales it before execution. The runner does not compare output contents; identical repeated self-skip is the narrow no-invalidation case. |
|
|
|
|
Stage 2 verified the matrix. The runner treats the session manifest as the only
|
|
cross-invocation decision source and each run manifest as a record of one
|
|
invocation. The resulting field behavior is:
|
|
|
|
- entering `running` clears the session stage's former outputs, logs, generated
|
|
configuration, metadata, completion, and error; success installs only the
|
|
current result and clears the stage error, while failure and self-skip clear
|
|
result data before bounded current skip diagnostics are reapplied;
|
|
- staling deliberately retains prior result data and timestamps for diagnosis,
|
|
changes status/error/updated time, and prevents the result from being reused;
|
|
- an already-succeeded skip does not mutate the session record; the run record
|
|
separately stores action `skip`, status `skipped`, and reason
|
|
`already_succeeded` without copying the reusable outputs;
|
|
- an executed self-skip stores action `run` and status `skipped` in the run
|
|
record, so it remains distinguishable from an idempotent skip;
|
|
- a stage failure marks the session stage and run stage failed, records the
|
|
error in both ledgers, makes the run overall failed, and stops execution;
|
|
- force is stored at run level and pre-stales all succeeded canonical
|
|
downstream stages; non-resumable validation first stales and saves the target
|
|
and succeeded downstream stages, then executes; and a successful execution
|
|
following any non-succeeded prior state stales remaining succeeded downstream
|
|
work; and
|
|
- the session-level `last_error` is retained as historical information after a
|
|
later success. No production reader treats it as current status; stage and
|
|
run status are the operative fields.
|
|
|
|
The invalidation helper derives position from the complete canonical registry,
|
|
not the selected plan. Consequently a single-stage replacement has the same
|
|
downstream effect as that stage in a full run. `prepare` can invalidate every
|
|
later succeeded stage and `notify` has no downstream target. Only succeeded
|
|
records need explicit staling: failed, skipped, stale, pending, running, and
|
|
interrupted records already execute on the next included plan.
|
|
|
|
### Runner Entry, Lock, And Persistence Conclusions
|
|
|
|
`Run` validates the assembled configuration and selection, builds the full
|
|
canonical plan, and delegates to `executeStages`. `RunStage`, `Analyze`, and
|
|
`Publish` select one canonical stage; the latter two force it. Single-stage
|
|
execution still uses the same lifecycle, session lock, invalidation, dual
|
|
manifests, cleanup check, and final run transition as a full run.
|
|
|
|
The session lock is acquired after layout creation and before the session
|
|
manifest is loaded, then held through stage execution, all manifest saves,
|
|
post-publish cleanup, and the final run save. A competing same-session runner
|
|
therefore cannot enter manifest decision-making while the first holds the lock.
|
|
The deferred release error is discarded. Whether close/unlink failures can
|
|
leave a blocking or misleading lock requires the filesystem implementation
|
|
review assigned to Stage 3; the assembled runner suite has no concurrent-runner
|
|
or release-failure case.
|
|
|
|
Both manifest stores use temp-file write, file sync, close, and same-directory
|
|
rename, so an error before rename leaves the prior individual file in place.
|
|
There is no atomic transaction or reconciliation protocol across the two
|
|
manifest files. The runner saves the run record first when
|
|
announcing execution, then saves the session record; for terminal outcomes it
|
|
saves the session authority first, then the run audit. The possible durable
|
|
states and their later interpretation are:
|
|
|
|
| Failure boundary | Durable state | Later invocation behavior |
|
|
| --- | --- | --- |
|
|
| New session or identity save fails before initial run save | No run record; session is absent or remains at its prior contents. An identity-save attempt mutates the in-memory identity and `updated_at`, but none of it becomes durable. | The command stops before a stage. A later invocation loads/creates from the last durable session state. |
|
|
| Initial run save fails after session identity save | Session points at the new run ID, but that run's audit file may not exist. | Session stage states still govern reuse; a later invocation creates a different run ID. |
|
|
| Resume validation reports unsafe/indeterminate | Session success is preserved, but the already-created run remains overall `running`. | The prior success remains authoritative and validation is attempted again; the abandoned run is never reconciled. |
|
|
| Saving non-resumable staleness fails | Run remains initially `running`; session remains at the prior success. No stage executes. | Validation is attempted again without silently replacing the prior success. |
|
|
| Saving an ordinary skip to the run file fails | Session remains succeeded; the run file remains at its preceding state. | The stage is safely reconsidered as another skip. |
|
|
| Run `running` save fails | Session is unchanged and the stage does not execute. | Session authority makes the next decision conservatively. |
|
|
| Session `running` save fails after the run save | Run stage is `running`; session remains at its prior state and the stage does not execute. Forced downstream staleness is not durable. | A non-succeeded target retries; a prior success skips unless force/resume validation again requires replacement. |
|
|
| Terminal session save fails after stage work | Both durable records remain `running`, although the stage may already have external or canonical effects. | The session stage reruns because `running` is not reusable. Stage-owned idempotency remains essential. |
|
|
| Terminal run save fails after terminal session save | Session has the authoritative success, skip, failure, and downstream state; run stays `running`. | Execution resumes safely from the session, but the historical run remains inaccurate. |
|
|
| Post-publish cleanup fails | Session stage outcomes remain terminal; a successful run save marks the invocation failed, while a failed run save leaves its prior overall `running` state. | A later invocation decides stages from the session and re-enters the cleanup gate; Stage 4 owns whether that retry is safe for every cleanup state. |
|
|
| Final overall run save fails | Session and per-stage run records are terminal, but overall run status remains `running`. | A later invocation skips or reruns from session state and does not repair the old run. |
|
|
|
|
Save errors are returned with both the stage error and persistence error when
|
|
both exist. The session store is injectable, but run persistence is a concrete
|
|
`LocalStore` outside the `manifest.Store` interface. This leaves the run-side
|
|
failure rows above unexercised by focused runner tests and makes centralized
|
|
terminalization/reconciliation harder to test.
|
|
|
|
### Lifecycle Scenario Conclusions
|
|
|
|
- Scenario 1 is functionally safe for reuse: a non-resumable success and its
|
|
succeeded downstream records are persisted stale before execution; a failed
|
|
rerun leaves the target failed and downstream stale; an ordinary retry runs
|
|
both. An inability to validate preserves the prior success rather than
|
|
replacing it. `RSK-001` records the inaccurate invocation audit left by that
|
|
controlled error.
|
|
- Scenario 2 is conservative and source-backed: force pre-stales succeeded
|
|
downstream work; failure and a changed effective outcome stale it; a changed
|
|
self-skip stales it; and an identical repeated self-skip does not. Here
|
|
identical means prior status skipped, zero outputs, and the same reason;
|
|
diagnostic/metadata differences are not compared. Disabled stages represented
|
|
as success remain reusable success, while an explicitly skipped downstream
|
|
stage is naturally reconsidered because only success is ever skipped. The
|
|
runner-level distinction is coherent; `ARC-002` remains assigned to Stages 4
|
|
and 8 for the stage-specific contract and wording.
|
|
- The lock portion of Scenario 10 is resolved at the application boundary:
|
|
acquisition occurs before manifest access and the lock spans the entire
|
|
mutation lifetime. Stage 3 must decide the ignored-release and underlying
|
|
lock-file questions.
|
|
|
|
## Cross-Boundary Scenario Assignments
|
|
|
|
| Scenario | Primary audit stage | Supporting packages and focused tests |
|
|
| --- | --- | --- |
|
|
| 1. Success becomes non-resumable, rerun fails, later reuse decision | 2 | `internal/app`, `internal/manifest`, `stage.ResumeValidator`; `runner_test.go`, `extract_lifecycle_test.go`, manifest transition tests |
|
|
| 2. Forced/changed upstream outcome with succeeded, self-skipped, disabled downstream | 2 | `internal/app`, `internal/stage`, `internal/manifest`; run-control, runner, extraction-lifecycle tests; disabled-stage detail revisited in 8 |
|
|
| 3. Extraction bundle followed by configuration/transitive-input change | 9 | Extract/resume, Notarius adapter, artifacts/fileops tests; downstream resolution revisited in 10 |
|
|
| 4. Published/restored/prepared previous state consumed locally by analyze | 5 | `internal/app`, `internal/previouscache`, `internal/audio`, `internal/artifacts`; restore/prepare tests; analyze consumption revisited in 10 |
|
|
| 5. Publish failure at every upload boundary, then status/restore/retry | 4 | Publish stage, storage fake/adapter, app status/restore; publish and operator-helper tests; restore interpretation revisited in 5 |
|
|
| 6. Restore identical/conflict/unsafe/cache/pre-manifest-install cases | 5 | Restore discovery/plan/execute/report, artifacts, previouscache, audio; restore test suite |
|
|
| 7. Cleanup after skipped/failed/locked/partial/committed publish | 4 | Publish metadata, post-publish cleanup, cleanup targets, pathsafe; publish/cleanup tests |
|
|
| 8. Cancellation through workers, HTTP, subprocess, storage, manifests | 7 | Adapter and subprocess tests; transcribe/stage tests in 8; runner reporting in 2 |
|
|
| 9. Disabled/unselected/reused/generated/extraction/previous source then publish filtering | 10 | Analyze, artifact catalog/resolver/policy, publish tests; config ownership in 6 and publish result in 4 |
|
|
| 10. Concurrent same-session invocation and lock cleanup failures | 3 | Runner lock lifetime in 2; local artifact store, path/file cleanup and lock tests in 3 |
|
|
|
|
## Preliminary Risk-To-Test Matrix
|
|
|
|
This matrix identifies intended owners only. It makes no sufficiency judgment.
|
|
|
|
| Architectural invariant or risk | Implementation owner | Intended test owner |
|
|
| --- | --- | --- |
|
|
| One deterministic canonical stage order | `internal/stage`, planner in `internal/app` | `internal/app/planner_test.go`, narrow registry tests |
|
|
| Session manifest is cross-invocation authority; run manifest is immutable invocation audit | `internal/app`, `internal/manifest` | Manifest transition tests plus assembled runner/run-stage tests |
|
|
| First run, skip, self-skip, failure, force, invalidation, and rerun transitions | `internal/app`, `internal/manifest` | App lifecycle tests as primary; manifest helpers own field mutation |
|
|
| Obsolete versus unsafe resume validation | Stage-specific `ResumeValidator`, runner | Extract resume tests plus runner integration tests |
|
|
| Run-local validation before canonical materialization | Individual stages and `run_local.go` | Focused stage package behavioral tests; fileops owns atomic mechanism |
|
|
| Strict config, defaults, identity, and cross-field validation | `internal/config` | Config package tests; example load/validation test samples assembly |
|
|
| Canonical path/key ownership and traversal confinement | Artifacts, artifactpolicy, pathsafe | Owning package tests; app/stage tests only for assembled policy |
|
|
| Immutable extraction promotion and provenance/checksum validation | Extract, fileops, artifacts, Notarius adapter | Fileops mechanism, extract behavior, artifact hydration, adapter contract tests |
|
|
| Deterministic artifact dependency and source resolution | Artifacts, artifactpolicy, analyze | Artifact/package tests and analyze package behavior tests |
|
|
| Previous-session consumption remains local in analyze | Previouscache/prepare/artifacts/analyze | Previouscache and prepare tests; one analyze boundary test for no remote call |
|
|
| Remote current pointer is publish's final commit point | Publish stage | Publish tests with stateful object-store fake; storage tests own transport only |
|
|
| Restore is confined, deterministic, conflict-safe, and installs manifest last | Restore app modules, artifacts/previouscache/audio | Restore plan/execution/workflow tests plus low-level path/file tests |
|
|
| Cleanup requires explicit scope and committed publish metadata | App cleanup modules, pathsafe | Cleanup-target and post-publish integration tests |
|
|
| Session single-writer lock and safe release | Local artifact store, app lifetime | Artifact local-store tests plus assembled concurrent runner tests |
|
|
| Adapter cancellation, error adaptation, and resource closure | Each adapter and shared subprocess package | Focused adapter boundary tests; stage tests sample propagation |
|
|
| Bounded deterministic transcription concurrency | Transcribe stage and WhisperX client | Stage concurrency/result-order tests; HTTP adapter retry/cancel tests |
|
|
| Secrets never persist or appear in diagnostics | Config/app composition and each adapter/logging boundary | Owning config/adapter tests plus selected assembled redaction checks |
|
|
| Default suite remains deterministic, offline, and credential-free | Every package; automation | Stage 12 repository-wide execution and test-policy audit |
|
|
|
|
Stage 2 test observations for this matrix:
|
|
|
|
| Risk | Existing focused protection | Gap or disposition |
|
|
| --- | --- | --- |
|
|
| Normal lifecycle and payload clearing | Manifest helper tests plus runner/run-stage/extraction-lifecycle tests cover first success, existing-success skip, force, failure, self-skip, repeated self-skip, unsafe and obsolete resume validation, retry, and canonical downstream invalidation. | Strong behavior coverage for successful persistence; no finding. |
|
|
| Session/run invocation identity | Per-invocation runner test asserts distinct run IDs, manifest paths, and the latest session `run_id`. | It does not assert refreshed local/spool/remote derived fields or reject loaded identity conflicts; required by `COR-001`. |
|
|
| Partial persistence and handled pre-stage errors | Session manifest is injectable and the unsafe-resume test proves old success is preserved. | Run persistence is concrete; no disagreement-boundary tests and no terminal run assertion on resume error; candidate `TST-002`. |
|
|
| Interruption and restart | Non-succeeded action logic and retry tests indirectly prove `running` is rerunnable. | No kill/reload normalization, reconciliation, or abandoned-run status test; confirmed `RSK-001`. |
|
|
| Same-session concurrency | Artifact store has focused lock tests. | No assembled concurrent runner or release-failure test; Stage 3 owns the mechanism and sufficiency decision. |
|
|
|
|
## Path, Artifact, Filesystem, And Lock Conclusions
|
|
|
|
### Canonical ownership and normalization
|
|
|
|
`internal/artifacts/paths.go` owns the campaign/session layout, run-local
|
|
layout, previous cache, Notarius bundle, spool, and audio-cache constructors.
|
|
`internal/artifacts/s3_keys.go` owns session/run/current and published-output
|
|
keys. `internal/pathsafe` is the shared lexical boundary for slash-normalized
|
|
relative destinations: it rejects empty, absolute, drive-qualified, traversal,
|
|
and leading-backslash forms, normalizes mixed separators, and verifies a
|
|
joined destination remains lexically under its root. `internal/artifactpolicy`
|
|
adds configured source/destination policy without performing filesystem I/O.
|
|
|
|
Most production callers consume those owners directly. Previous-cache planning
|
|
normalizes configured and manifest-derived relative paths before calling the
|
|
path constructor, and restore derives a normalized relative path before
|
|
installing it. One ad hoc reconstruction remains in publish:
|
|
`resolvePublishRunManifestSource` joins the literal `manifest.json` to an
|
|
already-derived run root instead of using the canonical run-manifest helper;
|
|
`DUP-002` assigns that maintainability decision to Stage 11.
|
|
|
|
The constructors themselves do not enforce that campaign, session, run, or
|
|
artifact-relative components are safe opaque segments. Configuration currently
|
|
checks session identifiers and campaign identity only for presence. As a
|
|
result, traversal-bearing operator identity reaches both local `filepath.Join`
|
|
and remote `path.Join`; `COR-002` records the concrete namespace escape. The
|
|
exported previous-artifact helper also promises a path under
|
|
`previous/artifacts` while accepting a traversal value, although its current
|
|
production callers validate first. That helper-level contract should be fixed
|
|
with the same boundary rather than treated as a separate defect.
|
|
|
|
### Artifact resolution
|
|
|
|
The complete resolution chain is deterministic and matches the documented
|
|
source-family distinctions:
|
|
|
|
- built-ins normalize against a fixed registry, prefer matching producer
|
|
outputs from the manifest, validate content shape, then use a canonical
|
|
session fallback; missing state returns `SessionArtifactNotFoundError`;
|
|
- configured sources resolve only through explicit runtime-catalog
|
|
availability, preserve generated-versus-disabled-file provenance, validate
|
|
non-empty text, and return the same typed missing condition when planned but
|
|
unavailable;
|
|
- extraction hydration requires a successful current extract record, exact
|
|
configured definitions, producer/receipt identity, compatible contract and
|
|
external provenance, confined regular files, a complete index/lane set, and
|
|
matching checksums before making any source available;
|
|
- previous-session planning sorts requirements and records, validates relative
|
|
cache destinations, loads current remote state with expected campaign,
|
|
session, and run identity, and hydrates only explicit remote objects into the
|
|
local cache. Analyze-time resolution is then local-only, preferring a
|
|
manifest input path before the documented filesystem fallback and returning
|
|
a typed missing error; and
|
|
- current-state loading has distinct typed missing-pointer and missing-manifest
|
|
errors, rejects empty or malformed state, and validates expected campaign,
|
|
session, and run identity or pointer/manifest run consistency.
|
|
|
|
Only extraction claims checksum/contract/external-provenance enforcement at
|
|
resolution time, and its implementation enforces all three. Built-in,
|
|
configured, and previous-cache resolvers enforce their documented content and
|
|
availability rules but do not re-hash ordinary manifest records. That is not a
|
|
Stage 3 contract mismatch; Stages 5 and 10 remain responsible for deciding
|
|
whether restore or analyze threat models require stronger trust than the
|
|
documented previous-cache fallback and manifest-aware built-in behavior.
|
|
|
|
### Filesystem mutation mechanics
|
|
|
|
The mutation inventory separates lexical policy from explicit-path mechanics:
|
|
|
|
| Mechanism | Normal-process atomicity and cleanup | Confinement and durability conclusion |
|
|
| --- | --- | --- |
|
|
| `WriteFileAtomic` | Same-directory temporary file; write, file sync, close, chmod, rename; removes a failed temporary file; replaces an existing destination where the platform rename permits it. | Accepts an explicit destination as intended, but follows symlinked destination ancestors and does not sync the parent after rename. |
|
|
| `CopyFileAtomicWithChecksum` / `CopyFileAtomic` | Opens the explicit source, copies and hashes through a same-directory temporary file, syncs/closes/chmods, then renames; prior destination survives failures before rename. | Does not require a regular source, follows source and destination symlinks, and does not sync the destination parent. Current canonical materialization callers validate content but inherit destination confinement and crash-durability findings. |
|
|
| `InstallDownloadedTempFile` | Chmods and renames a caller-supplied sibling temporary file; same-filesystem placement is established by current audio, previous-cache, and restore callers. | Does not sync the downloaded file or destination directory. The object-store downloads close their path-based files but expose no completed-data sync guarantee. |
|
|
| `PromoteDirectory` | Copies to a temporary sibling, permits only regular files/directories, uses confined source handles and identity checks, syncs files/directories, atomically installs without replacement, syncs the destination parent, cleans failures, and reports unsupported platforms before creating the promotion tree. | Source replacement, source symlinks/non-regular entries, existing or concurrently-created destinations, same-filesystem placement, and platform behavior are strongly handled. Destination ancestors remain path-based and can be symlinked or replaced. |
|
|
| Cleanup removal | Refuses empty roots/targets, lexical root deletion and traversal, wrong final-node type, and a final target that is a symlink. Missing targets are idempotent. | It does not inspect root or ancestor components and performs `RemoveAll` after a path-based check, so a symlinked ancestor can redirect deletion outside the root. |
|
|
|
|
Low-level file and storage helpers correctly accept explicit destinations and
|
|
do not infer stage, workspace, or cleanup policy. Policy belongs in their
|
|
callers. The current caller-side checks are lexical and final-node checks,
|
|
however, so they cannot prevent destination-ancestor symlink traversal or
|
|
replacement. `COR-003` consolidates the write, promotion-destination, and
|
|
destructive-cleanup variants under that single root cause; later stage and
|
|
adapter audits should reference it rather than duplicate it.
|
|
|
|
Single-file writers preserve the prior visible file on failures before rename,
|
|
but unlike directory promotion they do not sync the containing directory after
|
|
rename. Download installs additionally do not establish a file-sync boundary.
|
|
`RSK-002` records the resulting crash/power-loss durability gap for canonical
|
|
files and manifests. Stage 3 also confirmed that `DUP-001` duplicates this
|
|
same incomplete persistence sequence across both manifest save paths.
|
|
|
|
Runtime layout and copied/generated files use fixed requested modes `0755` and
|
|
`0644` subject to process umask, including transcripts, artifacts, logs,
|
|
manifests, and the lock. No operating contract requires a restrictive umask or
|
|
documents an ownership/mode boundary. `RSK-004` records the private-data
|
|
exposure risk rather than assuming a deployment-specific parent directory is
|
|
always restrictive.
|
|
|
|
### Lock scenario and focused tests
|
|
|
|
The local lock is an atomically created `O_CREATE|O_EXCL` sentinel. This is
|
|
sufficient to serialize two live contenders before either reads a manifest,
|
|
and the existing focused conflict test exercises that mechanism. It is not an
|
|
OS-owned advisory lock: any existing sentinel conflicts without interpreting
|
|
the recorded PID/time, process death cannot remove it, and recovery is manual.
|
|
Release closes then unlinks, but the runner discards its error. An unlink
|
|
failure can therefore let a command report success while every later invocation
|
|
is blocked. `RSK-003` resolves Scenario 10 and the Stage 2 release question.
|
|
|
|
Existing focused tests strongly cover lexical mixed-slash/traversal handling,
|
|
artifact-source ordering and typed missing states, extraction trust checks,
|
|
current-state identity, ordinary atomic replacement/temp cleanup, source-side
|
|
promotion races and special files, no-replace installation, permissions, and
|
|
basic lock acquire/conflict/release. They do not cover unsafe identity segments,
|
|
destination-ancestor symlinks or replacement, cleanup through a symlinked
|
|
ancestor, directory-sync/file-sync guarantees, stale-lock ownership/recovery,
|
|
release failure, or assembled concurrent runners. `TST-003` assigns a narrow
|
|
cross-package regression set to Stage 12; each confirmed finding below also
|
|
identifies its smallest behavior-level test.
|
|
|
|
## Confirmed Findings
|
|
|
|
### `COR-001`: session identity initialization preserves stale invocation paths and accepts conflicting identity
|
|
|
|
- Category: confirmed correctness defect.
|
|
- Locations/invariant: `internal/app/runner.go` in `ensureManifestIdentity` and
|
|
`syncRunManifestIdentityFromSession`; consumers include prepare's work/spool
|
|
resolution, publish's run prefix, and post-publish cleanup. The session and
|
|
invocation manifests must describe one internally consistent campaign,
|
|
session, and run.
|
|
- Evidence: every invocation replaces `Manifest.RunID`, but
|
|
`LocalWorkDir`, `LocalSpoolDir`, and `S3RunPrefix` are computed only when
|
|
empty. A second invocation therefore records run B while retaining paths and
|
|
the remote prefix derived from run A, and copies those stale values into run
|
|
B's manifest. The same helper fills an empty campaign but neither rejects nor
|
|
reconciles a loaded campaign/session that conflicts with the configured
|
|
manifest path. `TestExecuteStagesCreatesRunManifestPerInvocation` proves IDs
|
|
and run-manifest paths differ but does not assert the dependent identities.
|
|
- Realistic scenario: a forced second prepare writes through run A's work/spool
|
|
identity; a forced second publish can target run A's remote prefix while its
|
|
manifests claim run B. A misplaced or incorrectly restored manifest can also
|
|
make the runner hold session A's lock while stages derive paths from the
|
|
manifest's session B identity.
|
|
- Impact/likelihood/confidence: high integrity impact; stale derived identity
|
|
occurs on every ordinary second invocation after the fields are initialized,
|
|
while a conflicting loaded identity is less common; high confidence from the
|
|
assignment guards and direct consumers.
|
|
- Estimated remediation scope and owner: small-to-medium application/manifest
|
|
change. Define whether run-scoped locations belong in the session manifest,
|
|
recompute them as one identity unit whenever the run changes, and reject
|
|
configured/persisted campaign or session conflicts before stage execution.
|
|
- Test changes: extend the existing per-invocation test to load both manifests
|
|
and assert every run-derived field against run B; add a loaded-identity
|
|
mismatch test that proves no stage or cross-session path is touched. Stages 3
|
|
and 4 should add the path and remote-prefix boundary assertions after their
|
|
focused review.
|
|
- Dependencies: Stage 3 owns exact path confinement consequences, Stage 4 owns
|
|
publish/cleanup impact, Stage 5 owns restored-manifest provenance, and Stage
|
|
6 owns configuration identity validation. They should reference this root
|
|
finding rather than create duplicates.
|
|
|
|
### `COR-002`: unsafe identity components escape canonical local and remote namespaces
|
|
|
|
- Category: confirmed correctness/security defect.
|
|
- Locations/invariant: `internal/artifacts/paths.go` canonical constructors,
|
|
`internal/artifacts/s3_keys.go` in `S3SessionPrefix`, and
|
|
`internal/config/validate.go` in `validateCampaign`, `validateSession`, and
|
|
`validateSessionIdentifier`. Canonical identities must be opaque safe
|
|
segments, and traversal must not broaden local or remote operation scope.
|
|
- Evidence: campaign, session, and previous-session identifiers are checked
|
|
only for non-emptiness. Path/key constructors clean and join the raw values
|
|
without rejecting `.`/`..`, separators, drive forms, or traversal. A value
|
|
such as `../../outside` therefore changes the cleaned local workspace/spool
|
|
destination and the S3 namespace. `EnsureLayoutFor` also validates only
|
|
presence before creating the derived directories. The exported
|
|
`SessionPreviousArtifactPath*` helpers similarly claim an under-root result
|
|
but accept traversal; current production callers happen to validate their
|
|
relative artifact values first.
|
|
- Realistic scenario: an operator typo, generated session config, or untrusted
|
|
restored identity containing traversal makes prepare create/copy files
|
|
outside the intended workspace or spool root. Publish can read or write a
|
|
different campaign/session prefix, potentially colliding with unrelated
|
|
remote state.
|
|
- Impact/likelihood/confidence: high local and remote integrity/confidentiality
|
|
impact; low-to-moderate likelihood because ordinary date-like IDs are safe
|
|
but configuration is operator-controlled; high confidence from direct data
|
|
flow into canonical joins.
|
|
- Estimated remediation scope and owner: small-to-medium shared
|
|
config/artifacts change. Define one strict opaque-segment contract, validate
|
|
identities before layout/key construction, and make canonical helpers fail
|
|
closed rather than return an escaped path. Decide compatibility for existing
|
|
non-segment IDs explicitly in Stage 6.
|
|
- Test changes: table-test separator, traversal, absolute/drive, dot, and mixed-
|
|
slash identities at the configuration boundary; add artifacts tests proving
|
|
no local directory or S3 key can escape its expected namespace. Add a direct
|
|
unsafe-relative test for the exported previous-artifact constructor if it
|
|
remains public.
|
|
- Dependencies: Stage 6 owns configuration compatibility and validation.
|
|
`COR-001` separately owns conflicts among otherwise valid identities;
|
|
`COR-003` owns symlink-based escape after lexical identities are safe.
|
|
|
|
### `COR-003`: filesystem mutation confinement follows symlinked destination ancestors
|
|
|
|
- Category: confirmed correctness/security defect.
|
|
- Locations/invariant: lexical joins in `internal/pathsafe`, path-based writers
|
|
in `internal/fileops/fileops.go`, destination setup in
|
|
`internal/fileops/directory.go`, local layout/copy operations in
|
|
`internal/artifacts/local.go`, and cleanup validation/removal in
|
|
`internal/app/cleanup_targets.go`, `clean.go`, and
|
|
`post_publish_cleanup.go`. Writes, replacements, promotions, and deletions
|
|
must remain beneath an explicit root despite symlinks or replacement races.
|
|
- Evidence: lexical `Rel` checks cannot observe filesystem links. File writers
|
|
call `MkdirAll`/`CreateTemp`/`Rename` through destination paths. Promotion
|
|
strongly confines and identity-checks its source, but only path-checks the
|
|
destination parent before creating/installing the sibling tree. Cleanup
|
|
`Lstat`s only the final target and then calls `RemoveAll`; it neither rejects
|
|
a symlinked root/ancestor nor holds a confined directory handle. A target
|
|
such as `root/campaign/session`, where `campaign` is a symlink to an outside
|
|
tree, passes the lexical and final-node checks and deletes the outside
|
|
session directory. The analogous ancestor redirects writes and promotion.
|
|
- Realistic scenario: a stale, user-created, restored, or concurrently replaced
|
|
workspace component redirects prepare/materialization into another tree; a
|
|
later `clean session` or post-publish cleanup recursively removes data there.
|
|
The same gap permits a time-of-check/time-of-use replacement of a destination
|
|
ancestor.
|
|
- Impact/likelihood/confidence: critical destructive and confidentiality impact;
|
|
low-to-moderate likelihood depending on workspace ownership and multi-user
|
|
exposure; high confidence from the path-based checks and standard symlink
|
|
resolution semantics.
|
|
- Estimated remediation scope and owner: medium shared filesystem change. Use
|
|
root-relative directory handles/no-follow component traversal (with explicit
|
|
platform behavior) for mutations and deletion, and carry validated handles
|
|
through install/remove where feasible. Keep `fileops` policy-neutral by
|
|
passing an explicit root/destination capability rather than inferring stage
|
|
policy.
|
|
- Test changes: real-filesystem tests for a symlinked root, intermediate
|
|
component, destination parent replacement, and cleanup ancestor; assert an
|
|
outside sentinel survives and no outside temporary/output is created. Retain
|
|
the existing promotion source-race suite as the model for narrow hooks.
|
|
- Dependencies: Stages 4, 5, 7-9 must reference this finding for their concrete
|
|
cleanup, restore/download, adapter, stage-materialization, and extraction
|
|
consequences. `COR-002` owns lexical identity traversal separately.
|
|
|
|
### `RSK-001`: invocation audit records can remain indefinitely `running`
|
|
|
|
- Category: confirmed correctness/operational risk.
|
|
- Locations/invariant: `internal/app/runner.go` in `executeStages`,
|
|
`internal/manifest/store.go` normalization, and the unused production
|
|
`StatusInterrupted` model value. Every completed or handled invocation should
|
|
have an intelligible terminal audit outcome, while process interruption must
|
|
remain safely resumable.
|
|
- Evidence: the initial run manifest is saved with overall status `running`.
|
|
A resume-validator error returns directly without marking it failed; terminal
|
|
session-save and run-save failures leave the last run state running; and a
|
|
process death after either running save has the same effect. Neither load
|
|
normalizer converts running records to interrupted, and later invocations
|
|
consult only the session manifest and never reconcile older run manifests.
|
|
`StatusInterrupted` has no production writer. The existing resume-validation
|
|
error test checks preservation of the session success but not the run record.
|
|
- Realistic scenario: extraction resume validation encounters an unsafe or
|
|
unreadable receipt. The command returns a controlled error, the reusable
|
|
session result is correctly preserved, and the run audit file remains
|
|
`running` forever. A kill or persistence failure can leave analogous dual-
|
|
ledger disagreement.
|
|
- Impact/likelihood/confidence: medium operator/audit impact and low risk of
|
|
unsafe reuse because non-succeeded session stages rerun; moderate likelihood
|
|
over the life of a long-running pipeline; high confidence.
|
|
- Estimated remediation scope and owner: medium application/manifest change.
|
|
Terminalize handled post-creation errors when persistence is available and
|
|
define an explicit startup/status reconciliation policy for abandoned
|
|
running records. Preserve the current conservative session-authority rule.
|
|
- Test changes: extend the resume-validation error integration test to assert a
|
|
terminal failed run; add interruption/restart and injectable session/run-save
|
|
boundary cases. Filesystem crash durability itself remains a Stage 3 concern.
|
|
- Dependencies: `SIM-001` may provide one failure-finalization path and
|
|
`TST-002` records the missing persistence seam. Stage 5 should check how
|
|
status/restore presents abandoned runs; Stage 13 should decide whether true
|
|
process interruption is accepted risk after handled errors are fixed.
|
|
|
|
### `RSK-002`: single-file atomic replacement is not crash-durable
|
|
|
|
- Category: confirmed data-durability risk.
|
|
- Locations/invariant: `internal/fileops.WriteFileAtomic`,
|
|
`CopyFileAtomicWithChecksum`, `InstallDownloadedTempFile`, and both atomic
|
|
manifest-save sequences in `internal/manifest/store.go`. Successful canonical
|
|
files and durable ledgers must survive a crash/power-loss boundary consistent
|
|
with reported success.
|
|
- Evidence: writers that create their own temporary file sync its data before
|
|
rename, but none syncs the containing directory after rename. Download
|
|
callers close an initially empty sibling temp before object-store download,
|
|
and neither the download interface nor `InstallDownloadedTempFile` syncs the
|
|
completed file before rename. Directory promotion already demonstrates the
|
|
stronger sequence by syncing copied files, temporary directories, and the
|
|
destination parent after no-replace rename.
|
|
- Realistic scenario: a command reports a saved session/run manifest or
|
|
materialized canonical output, then the host loses power. The directory entry
|
|
rename is not durable and can disappear or expose filesystem-dependent state;
|
|
a downloaded restore/previous/audio file has an additional unsynced-data
|
|
window.
|
|
- Impact/likelihood/confidence: high integrity/recovery impact; low likelihood
|
|
per invocation but cumulative operational exposure; high confidence that the
|
|
sync calls are absent, with exact failure manifestation filesystem-dependent.
|
|
- Estimated remediation scope and owner: small-to-medium shared fileops and
|
|
manifest change. Centralize the durable temp-file install sequence, sync
|
|
completed downloads before install, then sync the parent directory with the
|
|
same explicit platform policy used by directory promotion.
|
|
- Test changes: introduce a narrow injectable sync/rename seam or ordered
|
|
filesystem-operation fake to assert file-sync-before-rename and directory-
|
|
sync-after-rename for write, copy, download install, and both manifest types;
|
|
retain real-filesystem overwrite/temp-cleanup tests for visible atomicity.
|
|
- Dependencies: `DUP-001` is the maintainability multiplier. Stages 5 and 7
|
|
should reference this root for restore/audio/storage download behavior rather
|
|
than create new durability findings.
|
|
|
|
### `RSK-003`: stale sentinel locks can block a session indefinitely and release failures are hidden
|
|
|
|
- Category: confirmed availability/operational risk.
|
|
- Locations/invariant: `internal/artifacts/local.go` lock acquisition/release,
|
|
the ignored deferred release in `internal/app/runner.go`, and the manual stale
|
|
lock procedure in `docs/troubleshooting.md`. A live same-session invocation
|
|
must exclude competitors, while completed or dead ownership must have a safe,
|
|
observable recovery path.
|
|
- Evidence: `O_CREATE|O_EXCL` correctly serializes live contenders, but any
|
|
existing `.lock` conflicts without checking whether its recorded PID/time is
|
|
live. Process death leaves the file forever. `ReleaseSessionLock` can report
|
|
close or unlink failure, but the runner defers it as `_ = ...`; an unlink
|
|
failure can therefore be reported as command success while the next run is
|
|
blocked. Recovery requires the operator to inspect process state and manually
|
|
delete the file.
|
|
- Realistic scenario: the process is killed or the filesystem rejects unlink
|
|
after a successful long run. Every later invocation for the session fails at
|
|
acquisition until an operator notices and safely removes the sentinel.
|
|
- Impact/likelihood/confidence: medium-to-high availability impact; moderate
|
|
lifetime likelihood for interruption and low likelihood for unlink failure;
|
|
high confidence. Mutual exclusion itself is sound in the ordinary live-
|
|
process case.
|
|
- Estimated remediation scope and owner: medium artifact-store/application
|
|
change. Prefer an OS-released lock while retaining useful metadata, or define
|
|
a conservative ownership/lease protocol; surface release failures without
|
|
obscuring an earlier command error and document automated versus manual
|
|
recovery.
|
|
- Test changes: add process/concurrency coverage for live exclusion and death
|
|
recovery, an injectable close/unlink failure proving the command cannot
|
|
silently succeed, and a subsequent-acquisition assertion. Do not encode
|
|
unsafe PID reuse assumptions in a unit test.
|
|
- Dependencies: `RSK-001` covers abandoned invocation audit state, not
|
|
exclusion. Stage 5 should check operator status presentation; Stage 12 owns
|
|
the smallest durable assembled-runner case.
|
|
|
|
### `RSK-004`: default runtime modes can expose private campaign material to other local users
|
|
|
|
- Category: confirmed security/operational risk.
|
|
- Locations/invariant: layout and mutation modes across
|
|
`internal/artifacts/local.go`, `internal/fileops`, stage/download writers, and
|
|
manifest persistence; security contract in `docs/policy/architecture.md`.
|
|
Transcripts, prompts, artifacts, reports, logs, and manifests are private
|
|
campaign material.
|
|
- Evidence: runtime directories request `0755` and files request `0644`, subject
|
|
only to ambient process umask. The default workspace is `/var/lib/narratio`;
|
|
Narratio can create its layout with those modes, and no operations contract
|
|
requires a restrictive umask, private parent, service-user ownership, or
|
|
configurable mode policy. Fixed-mode promotion also normalizes bundle files
|
|
to `0644` and directories to `0755`.
|
|
- Realistic scenario: a service or operator runs with the common `0022` umask
|
|
on a multi-user host. Other local accounts can traverse the workspace and
|
|
read transcripts, prompts, generated artifacts, diagnostics, and manifests.
|
|
- Impact/likelihood/confidence: high confidentiality impact; environment-
|
|
dependent but realistic likelihood; high confidence in requested modes and
|
|
documentation absence, moderate confidence in exposure on any particular
|
|
deployment because parent ACLs can mitigate it.
|
|
- Estimated remediation scope and owner: medium operations/configuration and
|
|
shared-writer change. Establish secure directory/file defaults, preserve
|
|
deliberate executability where needed, define ownership/ACL/umask
|
|
expectations, and provide an explicit compatibility/migration story.
|
|
- Test changes: assert privacy-oriented effective modes under a controlled
|
|
permissive umask for representative layout, manifest, artifact, log, and
|
|
promoted-bundle paths; document platform/ACL limitations instead of assuming
|
|
POSIX bits are universal.
|
|
- Dependencies: Stage 6 owns configuration/default compatibility, Stage 7 owns
|
|
adapter diagnostics, and Stage 13 should rank the risk against deployment
|
|
assumptions.
|
|
|
|
## Candidate Register
|
|
|
|
The remaining candidates require inspection by their named owners. Stages 2
|
|
and 3 have promoted their confirmed defects and risks into the register above.
|
|
|
|
### `ARC-001`: `IODecl` is not a complete or consistently classified stage contract
|
|
|
|
- Category: architectural boundary/ownership candidate.
|
|
- Evidence: `prepare.Declares` lists files it produces under `Inputs`;
|
|
`analyze.Declares` omits dynamic input families and has no outputs;
|
|
`publish.Declares` exposes only the manifest; and `notify.Declares` advertises
|
|
placeholder paths although its result has no persisted output. No production
|
|
caller of `Declares` was found.
|
|
- Contract tension: architecture says every stage declares required inputs,
|
|
produced output state, configuration, adapters, lifecycle, and failure
|
|
behavior; the Go interface declares only partial static artifacts.
|
|
- Realistic risk: a future planner, validator, or operator view could treat the
|
|
interface as authoritative and make incorrect dependency or readiness
|
|
decisions. Current likelihood appears low because the method has no
|
|
production caller.
|
|
- Confirmation owners: Stages 8-10 for dynamic contracts, then Stage 11 for
|
|
interface purpose/simplification. Smallest plausible outcome may be clearer
|
|
naming/documentation, a complete contract, or removal; do not choose yet.
|
|
|
|
### `ARC-002`: disabled-stage “skip” terminology spans two different durable outcomes
|
|
|
|
- Category: architectural/lifecycle ownership candidate.
|
|
- Evidence: production use of `StageDispositionSkipped` was found only in
|
|
extraction. Disabled render, absent/no-op analyze, and disabled publish return
|
|
zero-disposition results with skip metadata, which the runner treats as
|
|
success. Focused and operator docs use “skip” for several of these cases,
|
|
while manifest docs reserve self-skip for a durable skipped state.
|
|
- Realistic risk: maintainers or operator features may assume all disabled
|
|
outcomes clear state, are reconsidered, and invalidate downstream work in the
|
|
same way. Conversely, changing them to explicit self-skip could break valid
|
|
pipeline continuation or cleanup semantics.
|
|
- Confirmation owners: Stage 2 for runner truth table, Stage 4 for publish and
|
|
cleanup, Stage 8 for ordinary disabled stages. Treat wording and behavior as
|
|
unresolved until those flows are traced. Stage 2 confirmed that the two
|
|
outcomes are deliberate and internally distinguishable at runner level.
|
|
|
|
### `TST-001`: full race baseline fails in the concurrent transcribe test
|
|
|
|
- Category: test-suite execution candidate.
|
|
- Evidence: the race detector reported concurrent slice access in
|
|
`internal/adapters/whisperx/fake.go:45` from transcribe workers in
|
|
`TestTranscribeStageTranscribesPreparedAudio`.
|
|
- Observed impact: the canonical full race command exits nonzero, weakening its
|
|
signal for other packages. The report currently points to a test fake, not a
|
|
production data race.
|
|
- Confirmation owners: Stage 8 should inspect the worker/fake contract; Stage
|
|
12 should classify suite impact and the smallest durable fix. Do not change
|
|
the fake during this investigative stage.
|
|
|
|
### `TST-002`: runner tests cannot exercise invocation-manifest save failures
|
|
|
|
- Category: test-suite sufficiency candidate.
|
|
- Evidence: `Env.ManifestStore` injects only session `Create`, `Load`, and
|
|
`Save`; `executeStages` constructs a concrete `manifest.LocalStore` for run
|
|
creation and every `SaveRun`. Focused tests cover normal and stage-failure
|
|
transitions but no save disagreement row. The existing resume-validation
|
|
error test also omits the surviving run status.
|
|
- Realistic risk: future ordering or error-path changes can advertise a handled
|
|
invocation as running, lose the audit half of a terminal transition, or
|
|
weaken conservative retry behavior without an assembled test failing.
|
|
- Confirmation owner: Stage 12 should decide the smallest persistence seam and
|
|
representative boundary cases; avoid exhaustive choreography tests for every
|
|
mechanically identical save call.
|
|
|
|
### `DUP-001`: session save duplicates the shared atomic JSON writer
|
|
|
|
- Category: duplicated mechanism candidate.
|
|
- Evidence: `LocalStore.Save` contains its own temp/create/write/sync/close/
|
|
context-check/rename sequence, while `SaveRun` delegates the same mechanism
|
|
to `writeJSONAtomically`. Error prefixes differ, but the durability mechanism
|
|
is otherwise repeated. Stage 3 confirmed that both copies omit the same
|
|
parent-directory sync required by `RSK-002`.
|
|
- Realistic risk: a future durability, cleanup, permission, or platform fix may
|
|
reach only one manifest type, creating different guarantees for the two
|
|
ledgers.
|
|
- Confirmation owners: Stage 3 should compare filesystem guarantees and Stage
|
|
11 should decide whether sharing the helper preserves useful error context.
|
|
The filesystem comparison is complete; the simplification decision remains
|
|
assigned to Stage 11.
|
|
|
|
### `DUP-002`: publish reconstructs the canonical run-manifest path
|
|
|
|
- Category: duplicated path-ownership candidate.
|
|
- Evidence: `internal/stage/publish.go` in
|
|
`resolvePublishRunManifestSource` joins the literal `manifest.json` to an
|
|
already-derived run root, while `internal/artifacts` owns
|
|
`SessionRunManifestPath*` and the run-manifest path model. The same literal is
|
|
repeated when constructing the upload-relative record.
|
|
- Realistic risk: a layout/name change can update canonical path construction
|
|
without updating publish discovery, causing a completed run to fail publish
|
|
or upload the wrong record. Current values agree, so this is not a correctness
|
|
defect at the audited revision.
|
|
- Confirmation owner: Stage 11 should decide whether publish should receive the
|
|
canonical run-manifest path from its caller/model or use an artifacts helper;
|
|
preserve the explicit remote relative name separately if it is a protocol
|
|
constant.
|
|
|
|
### `TST-003`: filesystem safety tests omit destination and lock-recovery boundaries
|
|
|
|
- Category: test-suite sufficiency candidate.
|
|
- Evidence: focused path/file tests cover lexical traversal, mixed slashes,
|
|
ordinary atomic overwrite/cleanup, promotion source symlinks and replacement,
|
|
no-replace installation, and basic lock conflict/release. No test covers an
|
|
unsafe identity component, symlinked destination ancestor, destination-parent
|
|
replacement, cleanup through an ancestor symlink, file/directory sync order,
|
|
stale lock recovery, lock release failure, or concurrent assembled runners.
|
|
- Realistic risk: the confirmed `COR-002`, `COR-003`, `RSK-002`, and `RSK-003`
|
|
mechanisms can regress or be only partially repaired while a broad focused
|
|
suite remains green.
|
|
- Confirmation owner: Stage 12 should select one narrow behavior-level case per
|
|
distinct invariant and reuse shared low-level tests across callers. Avoid
|
|
duplicating every path spelling or persistence call sequence.
|
|
|
|
### `SIM-001`: runner terminalization and persistence ordering lack a narrow owner
|
|
|
|
- Category: simplification candidate.
|
|
- Evidence: `executeStages` is 274 lines with cyclomatic complexity 54 and
|
|
cognitive complexity 96. Much of the length is justified visible state-
|
|
machine ordering, but session-first terminal save, run-first running save,
|
|
result mapping, identity sync, and compound error handling are repeated
|
|
inline. The resume-validation return bypasses run terminalization.
|
|
- Realistic risk: adding another pre-stage or terminal error path can repeat the
|
|
abandoned-run behavior in `RSK-001`; extracting too broadly could instead
|
|
hide the critical order.
|
|
- Confirmation owner: Stage 11 should consider a small terminal failure helper
|
|
or typed transition operation only after Stages 3-10 settle ordering needs.
|
|
|
|
### `COM-001`: dual-ledger save order and partial-failure policy lack rationale
|
|
|
|
- Category: comment/clarity candidate.
|
|
- Evidence: the runner visibly saves run-before-session for `running` and
|
|
session-before-run for terminal outcomes, but no local comment explains which
|
|
file is authoritative, why the order differs, or how partial state is meant
|
|
to be interpreted.
|
|
- Realistic risk: a maintainer may make the calls symmetrical or reorder them,
|
|
inadvertently allowing a stage to execute without a durable running session
|
|
transition or preferring an audit record over resume authority.
|
|
- Confirmation owner: Stage 11, after any `SIM-001` restructuring. Prefer a
|
|
named operation that makes the invariant obvious; add a concise rationale
|
|
only where code structure cannot.
|
|
|
|
## Candidate Classification Log
|
|
|
|
| Candidate signal | Classification | Reason |
|
|
| --- | --- | --- |
|
|
| Graph rollups `stage -> app`, `adapters -> app`, `config -> app` | rejected as a production reversal at Stage 1 | `go list` production imports contain no lower-level import of `internal/app`; graph connections include tests and ambiguous package grouping. Reopen only with a concrete production edge. |
|
|
| Similar wrapper/manifest/adapter functions | deferred metric signals, not findings | Similarity alone does not establish duplicated policy; owning behavior stages must first establish contracts. |
|
|
| Coverage percentages | deferred diagnostic signals, not findings | Stage 12 must reason from risk and test ownership, not a numeric target. |
|
|
| Session `last_error` survives a later stage success | rejected as a current-state defect at Stage 2 | No production reader was found; current status and per-stage error are authoritative, so the field can serve as historical context. Reopen only if an operator surface treats it as the active error. |
|
|
| Minimal loaded-manifest status/timestamp validation | rejected as a standalone Stage 2 finding | Unknown/non-succeeded statuses fail conservatively into execution, nil maps/records are normalized, and no realistic unsafe caller was established. Configured-versus-persisted identity conflict is separately confirmed in `COR-001`. |
|
|
| Ignored runner lock-release error | confirmed as `RSK-003` at Stage 3 | The lock is an exclusive-create sentinel, not an OS-released lock. An unlink failure leaves the conflicting file while the runner suppresses the error; process death does the same without a release attempt. |
|
|
| Two durable meanings of “skip” | runner portion confirmed, stage-contract conclusion deferred | Run action/status distinguishes idempotent skip from executed self-skip. Stages 4 and 8 must determine whether successful disabled outcomes and their wording are intentional. |
|
|
| Exported previous-artifact helper accepts traversal | consolidated into `COR-002` | Current production callers normalize first, but the helper's under-root contract is false in isolation. The identity/relative-segment boundary should be repaired once rather than as separate caller bugs. |
|
|
| Built-in and previous resolvers do not re-hash manifest records | documented trust distinction; deferred to Stages 5 and 10 | Extraction explicitly requires checksum/contract/provenance validation and enforces it. Other source families explicitly use content validation and a previous-cache filesystem fallback; consumer/restore threat models must establish a stronger requirement before this becomes a finding. |
|
|
| Promotion destination is path-based while source is handle-confined | consolidated into `COR-003` | Source hardening is strong, but destination ancestors share the same symlink/replacement root cause as ordinary writers and cleanup. |
|
|
|
|
## Unresolved Questions And Follow-Up
|
|
|
|
- Should startup/status reconcile abandoned `running` invocation records, mark
|
|
them interrupted, or retain them as an explicitly accepted audit limitation?
|
|
- Do Stage 3 path mechanics and Stage 4 publish/cleanup behavior confirm every
|
|
concrete consequence of the stale run-derived fields in `COR-001`?
|
|
- Which cross-platform root-relative filesystem primitive should own the
|
|
symlink-safe mutation capability required by `COR-003` without moving stage
|
|
policy into low-level `fileops`?
|
|
- Should sentinel locking be replaced by an OS-released lock, or can a
|
|
conservative ownership/recovery protocol satisfy `RSK-003` across supported
|
|
platforms?
|
|
- Which existing identifier spellings constrain the strict segment validation
|
|
required by `COR-002`?
|
|
- Do deployment packaging and service definitions already enforce an umask,
|
|
ownership, or ACL that reduces `RSK-004`, and where should that contract be
|
|
documented and tested?
|
|
- Are disabled render/analyze/publish outcomes intentionally successful so
|
|
pipeline continuation and optional outputs work, and do all operator views
|
|
describe that distinction accurately?
|
|
- Is `IODecl` intended only for display/tests, or should it own enforceable
|
|
dependency declarations?
|
|
- Does publish's omission of extract from its static prerequisite list combine
|
|
safely with every configured extraction output rule and disabled extraction?
|
|
- Which native CI runner limitations explain the absence of validation jobs in
|
|
the tag-only release workflow? Stage 12 owns the automation conclusion.
|
|
|
|
No accepted risks or final audit conclusions are recorded yet.
|
|
|
|
## Completed-Stage Evidence
|
|
|
|
### Stage 0
|
|
|
|
- Contracts and records: development guide, audit plan and sequence, all policy
|
|
documents, repository/branch/toolchain state.
|
|
- Graph evidence: refreshed moderate index at exact HEAD; architecture,
|
|
interface, complexity, similarity, fan-in, and `Execute` call trace queries.
|
|
- Commands: every baseline command listed above; Go/package/file/test and
|
|
automation inventories.
|
|
- Candidates: `TST-001`; metric signals assigned to later owners.
|
|
- Explicit no-finding conclusion: no production dependency reversal into
|
|
`internal/app` was found in the package import inventory.
|
|
- Limitation disposition: the graph excludes the executable entry point, which
|
|
was verified directly; the race failure is owned by Stages 8 and 12 and does
|
|
not prevent read-only audit work.
|
|
|
|
### Stage 1
|
|
|
|
- Contracts reviewed: architecture, testing and documentation policy; internal
|
|
overview and every focused internal document; CLI, configuration,
|
|
operations, and every integration contract.
|
|
- Code/evidence reviewed: canonical registry and stage declarations; all
|
|
modeled interfaces; production import graph; application dispatch trace;
|
|
explicit self-skip usages; interrupted-state usages; focused test ownership
|
|
references.
|
|
- Outputs: package/interface ownership, area coverage, stage contract,
|
|
lifecycle, cross-boundary scenario, and preliminary risk-to-test matrices.
|
|
- Candidates: `ARC-001`, `ARC-002`, `RSK-001`; no candidate was confirmed from
|
|
mapping evidence alone.
|
|
- Explicit no-finding conclusion: the canonical stage order agrees across the
|
|
registry, internal overview, CLI, and operations contract.
|
|
- Follow-up: all unresolved behavior has a named owner in Stages 2-12; every
|
|
area and invariant has an implementation owner and intended test owner.
|
|
|
|
### Stage 2
|
|
|
|
- Contracts and code reviewed: planner and full/single-stage entry points;
|
|
`executeStages`, run-control and identity helpers; session/run manifest
|
|
models, creation, loading, validation, normalization, atomic persistence, and
|
|
every transition method; runner lock lifetime; focused internal manifest
|
|
documentation and Stage 1 matrices.
|
|
- Graph/source evidence: call traces into full and selected execution; all
|
|
identity-field consumers; manifest transition/save callers; status and
|
|
`last_error` usages; runner complexity and atomic-save similarity; complete
|
|
focused test-function inventory.
|
|
- Validation: `go test -count=1 ./internal/app ./internal/manifest` passed
|
|
(`internal/app` 0.708 s, `internal/manifest` 0.010 s; 1.60 s command wall
|
|
time). `go test -race -count=1 ./internal/app ./internal/manifest` passed
|
|
(`internal/app` 45.842 s, `internal/manifest` 1.026 s).
|
|
- Conclusions: every lifecycle cell and dual-save boundary is recorded above;
|
|
scenarios 1 and 2 are resolved at runner level; lock acquisition/lifetime is
|
|
resolved and release mechanics assigned to Stage 3. Confirmed `COR-001` and
|
|
`RSK-001`; added `DUP-001`, `SIM-001`, `COM-001`, and `TST-002` for named
|
|
later owners.
|
|
- Explicit no-finding conclusions: canonical invalidation works at both first
|
|
and last stage and is independent of selected-plan width; stale transitions
|
|
intentionally retain diagnosis data while running/failure/skip clear it;
|
|
session authority makes all enumerated disagreement states retry or reuse
|
|
conservatively; the runner's two skip forms are durably distinguishable.
|
|
|
|
### Stage 3
|
|
|
|
- Contracts and code reviewed: architecture/path/security policy; internal
|
|
artifacts, workspace, manifest, operations, and troubleshooting contracts;
|
|
all canonical local/S3/cache constructors; pathsafe and artifactpolicy;
|
|
built-in, configured, extraction, previous, and current-state resolution;
|
|
local-store layout/copy/lock code; atomic write/copy/download installation;
|
|
directory promotion and platform-specific no-replace/directory-sync support;
|
|
restore/audio/previous download callers; manual and post-publish cleanup.
|
|
- Graph/source evidence: canonical-helper and direct-mutation inventories;
|
|
callers of path/key, artifact-resolution, fileops, current-state, previous-
|
|
cache, and lock helpers; focused test-function inventories; fallback text
|
|
search for non-code policy and direct OS mutation sites where graph results
|
|
were insufficient.
|
|
- Validation: `go test -count=1 ./internal/artifacts
|
|
./internal/artifactpolicy ./internal/pathsafe ./internal/fileops` passed (0.98
|
|
s wall time). `go test -race -count=1 ./internal/artifacts
|
|
./internal/fileops` passed (2.25 s wall time).
|
|
- Conclusions: canonical owners and artifact resolution order are recorded
|
|
above; lexical normalization handles mixed separators, traversal, absolute,
|
|
and drive forms when callers invoke it; extraction source trust and source-
|
|
side promotion are strong; low-level helpers correctly consume explicit
|
|
destinations. Scenario 10 is resolved: live contenders are excluded, while
|
|
stale sentinel/release behavior is unsafe operationally.
|
|
- Findings: confirmed `COR-002`, `COR-003`, `RSK-002`, `RSK-003`, and
|
|
`RSK-004`; added `DUP-002` and `TST-003`; refined `DUP-001` with the shared
|
|
durability gap.
|
|
- Explicit no-finding conclusions: current-state helpers have typed missing
|
|
cases and strict identity checks; artifact resolution is deterministic and
|
|
matches its documented source-specific validation; promotion preserves an
|
|
existing/concurrent destination and rejects unsafe source trees; temporary
|
|
files/trees are cleaned on ordinary failures; unsupported promotion
|
|
platforms fail before creating a durable bundle; fileops does not infer
|
|
higher-level policy.
|
|
- Follow-up: Stages 4-10 should cite the shared confinement/durability roots for
|
|
concrete callers. Stages 5 and 10 must decide whether ordinary manifest and
|
|
previous-cache checksum trust is sufficient. Stages 6, 11, and 12 own
|
|
compatibility, simplification, and durable regression coverage respectively.
|