# Audit Remediation Implementation Plan ## Purpose and status This document is the executable roadmap for remediating the confirmed findings in [`audit-findings.md`](audit-findings.md) and the concrete gaps found during the post-implementation code review. It is written for a `gpt-5.6-terra` coding agent that will implement exactly one pending stage per prompt, in order. The audit is an immutable requirements and evidence ledger. Do not edit `audit-findings.md` or reinterpret its accepted findings. Stages 1–32 completed the original audit-remediation plan and are summarized below instead of retaining their now-obsolete implementation instructions. The repository history and audit remain the detailed evidence for that work. Stages 33–35 address follow-up review findings in the completed implementation. They are implementation gaps in the original remediation rather than new entries in the immutable audit ledger. They do not require the implementing agent to read the full audit or any audit line range. ## Stage status and completed summaries | Stage | Outcome or pending work | Source | Status | | ---: | --- | --- | --- | | 1 | Aligned architecture policy and filesystem modes with collaborative, group-owned workspaces while preserving private API-key handling. | RSK-004 | Completed | | 2 | Enforced portable safe-segment identifiers and added path/source fuzz coverage. | COR-002, TST-013 | Completed | | 3 | Consolidated crash-durable atomic file replacement behind shared file-operation primitives. | RSK-002, DUP-001, DUP-005 | Completed | | 4 | Added confined, no-follow destination and download/install operations. | COR-003, DUP-003, TST-003 | Completed | | 5 | Confined recursive cleanup and replaced existence-based sentinel locks with OS-held locks. | RSK-003 | Completed | | 6 | Made API-key acquisition private, bounded, regular-file-only, and no-follow. | RSK-010 | Completed | | 7 | Bounded and verified externally produced adapter and stage result files. | RSK-013, TST-007 | Completed | | 8 | Added owned subprocess-tree cancellation, timeout, and forced termination. | RSK-011 | Completed | | 9 | Added streaming secret redaction and bounded subprocess diagnostic capture. | RSK-012 | Completed | | 10 | Confined publish archive reads to validated workspace sources. | COR-005 | Completed | | 11 | Established singular manifest and run identity ownership. | COR-001, TST-006 | Completed | | 12 | Centralized handled terminal-failure persistence and removed competing failure paths. | RSK-001, TST-002, SIM-001, COM-001 | Completed | | 13 | Introduced immutable remote commit manifests, a final current pointer, and an isolated removable legacy reader. | ARC-003 | Completed | | 14 | Switched publishing to immutable commits, deterministic mappings, and a final pointer update. | COR-004, COR-011, DUP-002, TST-004 | Completed | | 15 | Made remote locks generation-safe and rejected non-progressing storage pagination. | RSK-005, RSK-014 | Completed | | 16 | Persisted retryable post-commit cleanup obligations. | COR-006, COR-007 | Completed | | 17 | Bound restore and status to one verified committed snapshot and rejected conflicting state. | COR-008, COR-009, TST-005 | Completed | | 18 | Serialized restore transitions, persisted interrupted-restore state, and made restored paths portable. | RSK-006, RSK-008 | Completed | | 19 | Bound reusable audio cache entries to remote object identity. | RSK-007 | Completed | | 20 | Unified previous-source readiness and eliminated duplicate transfers. | COR-010, EFF-001 | Completed | | 21 | Tightened configuration parsing, validation, value domains, and test expectations. | COR-012–COR-015, TST-011, TST-014 | Completed | | 22 | Made product configuration truthful and assigned lifecycle ownership for downloaded temporary files. | COR-024, RSK-009, ARC-004 | Completed | | 23 | Streamed WhisperX uploads and made its transport bounded, retry-correct, and race-safe. | COR-016, EFF-002, TST-001 | Completed | | 24 | Corrected prepare/transcribe transition, retry, and optional-output semantics. | COR-017–COR-019, TST-008 | Completed | | 25 | Enforced authoritative output paths and shared singleton resolution. | ARC-006, DUP-006 | Completed | | 26 | Centralized typed extraction-bundle evidence. | DUP-007 | Completed | | 27 | Bound extraction reuse to direct transcript identity and explicit freshness evidence. | COR-020, TST-009 | Completed | | 28 | Established one effective artifact set and deterministic catalog bootstrap behavior. | COR-022, ARC-007, DUP-008 | Completed | | 29 | Made analyze input resolution typed, optional, actionable, and deterministic. | COR-021, COR-023, RSK-015, SIM-003, TST-010 | Completed | | 30 | Removed misleading contracts and placed static Audita policy in adapter construction. | ARC-001, ARC-005, SIM-004, COM-003, COM-006 | Completed | | 31 | Enforced repository-wide CI/release validation and streamlined redundant test matrices. | TST-012, TST-015 | Completed | | 32 | Reconciled lifecycle/analyze documentation and closed the original audit traceability inventory. | COM-002, COM-005 | Completed | | 33 | Confine diagnostic log destinations and eliminate pathname-based tail reads. | Follow-up review | Completed | | 34 | Dispose of owned subprocess descendants after natural leader exit. | Follow-up review | Completed | | 35 | Bound remote current-state and lock control-plane reads. | Follow-up review | Completed | Completed stages must not be reimplemented wholesale. A pending stage may adjust their code only where its stated remediation requires it. ## Governing decisions The following decisions are settled requirements, not questions for the implementing agent: 1. Ordinary Narratio and Notarius campaign/session data is deliberately shareable, not private or sensitive. Group-owned, group-writable workspaces are an operational requirement. API keys are the only sensitive data handled by these applications and must remain private. 2. On POSIX systems, Narratio-managed ordinary workspace directories and files should converge on setgid `02775` and `0664` respectively, inheriting the workspace's existing group. API-key directories and files must be `0700` and `0600`. Do not add ownership-changing behavior or assume Narratio may `chown`. Windows behavior must preserve the same collaboration/security intent using the platform's available guarantees and explicit operational guidance. 3. Remote current-state publication uses an immutable run-scoped commit manifest selected by one final pointer update. Readers may accept coherent legacy state, but all compatibility code must remain isolated behind a clearly named boundary, covered by dedicated tests, and carry an in-code removal comment. New writers must never produce the legacy format. 4. Explicit notification no-op is supported. Configured notification backends or recipients are rejected until a real provider exists. 5. External-data limits are runaway safeguards, not normal operating limits. Each limit must be a named, centrally discoverable constant in the package that owns the contract and at least an order of magnitude above expected ordinary data. Every limit error must identify the enforcing adapter or contract, the configured byte limit, and what exceeded it. Hard whole-disk protection remains an operations concern implemented with filesystem, service, container, or volume quotas rather than output-root polling. 6. Narratio owns the complete process group or job created for every external command. Leader completion does not transfer ownership of surviving descendants. `Run` must not return while an owned descendant can continue running, including when the leader exits successfully or closes its streams. 7. Diagnostic tails are derived only from content that passed through the streaming redactor. Diagnostic files use the same confined, no-follow mutation guarantees as other workspace destinations; a pathname must not be reopened to obtain an error tail after execution. 8. Remote current pointers, commit manifests, selected session manifests, and lock documents are bounded while being read. Object metadata may reject an oversized value early but cannot replace enforcement against the actual byte stream. Limits for these small control-plane contracts are separate from limits for intentionally large artifact payloads. 9. Retain every accepted-risk disposition in the audit. In particular, do not turn abrupt process-death detection into a distributed liveness system, add rollback of arbitrary external side effects, or introduce generic speculative abstractions rejected by the audit. 10. CI must run ordinary tests, the full race suite, vet, build, and example/docs checks on every change and release path; shuffled tests run on a schedule. Add native macOS/Windows jobs only when authoritative Woodpecker runner labels and usable runners are available. Do not invent labels. Cross-compilation is useful but does not count as native filesystem or process evidence. ## Instructions for every pending stage For each implementation prompt, the coding agent must: 1. Read `docs/development.md`, then the current-behavior documents and source files named by that stage. Follow the task-specific reading guide in `docs/development.md`. Stages 33–35 do not require reading `audit-findings.md`; do not reread or modify the immutable audit ledger. 2. Inspect the current tree before editing. Earlier stages may have changed names and ownership boundaries. Use the repository knowledge graph first for code discovery and call tracing, then text search for documentation, string literals, configuration, and evidence the graph cannot supply. 3. Confirm the worktree state and preserve unrelated user changes. Do not rewrite or amend earlier commits unless explicitly instructed. 4. Implement the stage completely, including production code, focused regression tests, platform-specific implementations where applicable, current-behavior documentation, and removal of code made obsolete by the stage. Do not leave a second competing path or defer required tests to a later stage unless this plan explicitly says so. 5. Prefer typed, owner-specific contracts and existing package ownership. Keep policy at the owner and reusable mechanism in `internal/fileops`, storage, or the relevant adapter package. Do not create a generic abstraction solely because two call sites look similar. 6. Treat path, race, process-lifecycle, and size checks as production behavior. Validation followed by an unsafe pathname operation or unbounded read is not a completed fix. Unsupported safe behavior must fail closed with an actionable error. 7. Run focused tests while developing, then run at minimum: ```sh go test ./... go test -race ./... go vet ./... go build ./... go test ./internal/doccheck go test ./internal/config -run '^TestExamplesLoadAndValidate$' ``` Run the platform build/test checks named by the stage. Do not require live cloud or third-party services. 8. Compare the final diff with the stage goal and exit criteria. Update only that stage's row in the status table from `Pending` to `Completed`, adding the implementing commit hash if the workflow supplies one. Do not mark a stage complete while a required check is failing or required behavior is missing. ## Stage 33 — Confine diagnostic log destinations and eliminate pathname-based tail reads **Read first:** `docs/policy/architecture.md`, `docs/policy/testing.md`, `docs/internal/adapters.md`, `docs/internal/workspace.md`, and the current subprocess diagnostic and confined file-operation implementations and tests. **Depends on:** Completed Stages 3, 4, and 9. **Goal:** Prevent diagnostic log setup from following a replaceable leaf symlink or mutating a file outside the intended workspace, and ensure error diagnostics cannot be redirected to read unrelated or secret content after a command runs. **Work:** - Replace direct diagnostic `os.Create` use with the established confined, no-follow destination mechanism. Validate the leaf as part of the mutation, reject symlink and non-regular destinations, preserve group-workspace modes, and retain the platform-specific safety guarantees established by Stage 4. A prior ancestor check followed by an ordinary pathname create is not sufficient. - Remove pathname reopening from diagnostic-tail construction. Retain a small, bounded per-stream tail from bytes that have already passed through streaming redaction, preferably in the diagnostic writer itself, and obtain failure diagnostics from that retained state after redaction has been flushed. Do not read the log path again in the error path. - Preserve stdout/stderr file behavior, shared-path behavior, byte caps, split- chunk secret redaction, capture-limit signaling, and group collaboration modes. Do not create an unbounded in-memory copy of either stream. - Keep API-key values out of persisted logs and every returned error even if a workspace peer renames or replaces a diagnostic pathname while the process is running. - Remove obsolete pathname-tail helpers and update current-behavior documentation only if the existing documentation describes the replaced mechanism. **Tests and exit criteria:** Add adversarial tests proving that an existing log leaf symlink is rejected without truncating its target; a non-regular leaf is rejected; pathname replacement after the log is opened cannot inject foreign content into a returned error; and a known credential remains absent from files and errors across split writes. Cover separate and shared stdout/stderr paths, exact diagnostic caps, and cap-plus-one behavior. Run focused subprocess and file-operation tests under `-race`, plus Linux, macOS, and Windows cross-builds for affected packages. Native platform tests remain conditional on available runners. **Status:** Completed. ## Stage 34 — Dispose of owned subprocess descendants after natural leader exit **Read first:** `docs/policy/architecture.md`, `docs/policy/testing.md`, `docs/internal/adapters.md`, the subprocess run/process-tree implementations for Unix and Windows, and all process-tree test helpers. **Depends on:** Completed Stage 8 and Stage 33. **Goal:** Close the lifecycle gap in which `cmd.Wait` can complete before a descendant in Narratio's process group or Windows job exits, allowing that descendant to outlive `Run` after either a successful or failed leader exit. **Work:** - Route the normal `cmd.Wait` completion branch through bounded owned-tree disposal before `Run` returns. Apply the ownership rule for successful exits, non-zero exits, and `exec.ErrWaitDelay`, not only cancellation, timeout, or diagnostic-cap paths. - On Unix, detect and gracefully terminate any remaining process-group members, wait only for the existing bounded grace period, then forcefully terminate survivors. Treat an already-empty group as success and avoid imposing the grace delay on ordinary commands with no descendants. - On Windows, preserve job-object kill-on-close semantics and ensure natural leader completion closes/disposes the job before return. Keep handles and goroutines bounded on every exit path. - Consolidate terminal cleanup so races among context cancellation, capture-limit signaling, and leader completion cannot skip disposal or produce unsafe double ownership. Preserve timeout/cancellation classification and join actionable cleanup failures without hiding the original command result. - Treat a descendant that deliberately leaves the owned process group or job as outside this stage; do not build a system-wide process discovery mechanism. **Tests and exit criteria:** Extend the real subprocess helper with cases where a leader exits zero while a descendant (a) retains inherited streams and (b) redirects or closes them, plus a non-zero leader case. Prove `Run` completes within bounded time and no descendant reaches a delayed sentinel after return. Retain cancellation, timeout, and capture-limit coverage and run the subprocess suite repeatedly, shuffled, and under `-race`. Cross-build the affected packages for Linux, macOS, and Windows; run native platform tests only where runners are actually available. **Status:** Completed. ## Stage 35 — Bound remote current-state and lock control-plane reads **Read first:** `docs/policy/architecture.md`, `docs/policy/testing.md`, `docs/internal/storage.md`, `docs/internal/artifacts.md`, `docs/internal/command-restore.md`, the current-state commit reader, remote lock loader, object-store contract and implementations, and their stateful fakes and tests. **Depends on:** Completed Stages 13–17. **Goal:** Prevent corrupt, misconfigured, or hostile object storage from forcing unbounded temporary-disk or memory consumption before small remote control-plane objects can be parsed or verified. **Work:** - Inventory the new-protocol read paths for the mutable current pointer, immutable commit manifest, selected session manifest, and remote lock document. Include the isolated legacy current-state reader only where it accepts equivalent small control objects. Do not apply these limits to intentionally large published artifact payloads. - Define generous, documented, centrally discoverable constants in the packages that own each control-plane contract. Use separate policy constants where the credible sizes differ; do not embed numeric limits at call sites or replace the owner policies with one unexplained global limit. - Stream each object through an enforcing `limit+1` read before parsing or retaining it. Reject oversized metadata before transfer when available, but still enforce the limit against actual bytes because metadata can be missing, stale, or inaccurate. Avoid downloading these small objects unboundedly to a temporary file and then calling `os.ReadFile` or `io.ReadAll`. - Preserve immutable commit checksum, declared-size, generation/ETag, identity, and pointer-selection validation. Ensure the metadata used for validation belongs to the opened object version; do not weaken coherence while removing the temporary download path. - Every over-limit error must identify the responsible control-plane contract, object category, key or safe storage context, and configured byte limit without including credentials. Maintain cancellation and reader-close behavior on all exits. - Factor a bounded storage-read mechanism only if it has a clear storage-layer invariant; retain the owner-specific constants and errors in the artifact and remote-lock owners. **Tests and exit criteria:** Add exact-limit and limit-plus-one cases for each object category, including inaccurate/absent size metadata, short reads, cancellation, malformed JSON/YAML, checksum or generation mismatch, and readers that verify they are closed. Prove oversized current-state downloads do not create unbounded temporary files and oversized lock documents are rejected without unbounded allocation. Retain coherent legacy-reader tests and stateful S3/fake ordering and conditional-write tests. Run focused storage, artifacts, app, restore, and publish tests under `-race`, followed by the complete repository validation. **Status:** Completed. ## Finding traceability inventory This inventory remains the closed traceability record for Stages 1–32. A pending follow-up stage may strengthen the implementation of an original stage, but does not change the immutable finding disposition or create a second audit finding. | Finding(s) | Primary stage | | --- | ---: | | COR-001 | 11 | | COR-002 | 2 | | COR-003 | 4 | | COR-004 | 14 | | COR-005 | 10 | | COR-006, COR-007 | 16 | | COR-008, COR-009 | 17 | | COR-010 | 20 | | COR-011 | 14 | | COR-012, COR-013, COR-014, COR-015 | 21 | | COR-016 | 23 | | COR-017, COR-018, COR-019 | 24 | | COR-020 | 27 | | COR-021, COR-023 | 29 | | COR-022 | 28 | | COR-024 | 22 | | RSK-001 | 12 | | RSK-002 | 3 | | RSK-003 | 5 | | RSK-004 | 1 | | RSK-005 | 15 | | RSK-006, RSK-008 | 18 | | RSK-007 | 19 | | RSK-009 | 22 | | RSK-010 | 6 | | RSK-011 | 8 | | RSK-012 | 9 | | RSK-013 | 7 | | RSK-014 | 15 | | RSK-015 | 29 | | EFF-001 | 20 | | EFF-002 | 23 | | ARC-001 | 30 | | ARC-003 | 13 | | ARC-004 | 22 | | ARC-005 | 30 | | ARC-006 | 25 | | ARC-007 | 28 | | TST-001 | 23 | | TST-002 | 12 | | TST-003 | 4 | | TST-004 | 14 | | TST-005 | 17 | | TST-006 | 11 | | TST-007 | 7 | | TST-008 | 24 | | TST-009 | 27 | | TST-010 | 28 | | TST-011, TST-014 | 21 | | TST-012, TST-015 | 31 | | TST-013 | 2 | | DUP-001, DUP-005 | 3 | | DUP-002 | 14 | | DUP-003 | 4 | | DUP-006 | 25 | | DUP-007 | 26 | | DUP-008 | 28 | | SIM-001 | 12 | | SIM-003 | 29 | | SIM-004 | 30 | | COM-001 | 12 | | COM-002, COM-005 | 32 | | COM-003, COM-006 | 30 | The remaining confirmed IDs have non-independent dispositions and must not receive separate implementation work: ARC-002 and COM-004 are merged into COM-002; SIM-002 is merged into DUP-007; DUP-004 is rejected. Their audit rationale remains authoritative. ## Follow-up review traceability | Review finding | Remediation stage | Source | | --- | ---: | --- | | Diagnostic leaf symlinks and pathname-reopened tails bypass confinement/redaction guarantees | 33 | Post-implementation review | | Unix descendants survive natural leader exit | 34 | Post-implementation review | | Remote current-state and lock control objects are read without acquisition limits | 35 | Post-implementation review | ## Open Questions None. The remediation behavior and ownership decisions are specified above. Native macOS/Windows runtime validation remains contingent on external runner availability, but cross-build requirements and the rule against inventing runner labels make implementation decision-complete.