818 lines
50 KiB
Markdown
818 lines
50 KiB
Markdown
# Implementation Plan: Resilient Processing and Focused Reports
|
||
|
||
**Last updated:** 2026-09-24
|
||
|
||
**Status:** Ready for implementation; all stages below are pending. Planning only:
|
||
no implementation is claimed by this document.
|
||
|
||
## Scope and Execution Instructions
|
||
|
||
Implement the target in [resilience.md](resilience.md). User intent and product
|
||
policy belong there; the concrete choices and ordered steps below implement them.
|
||
Everything in [future.md](future.md) is excluded, especially domain-aware
|
||
regeneration, independent whole-pipeline traversal, and new empty-replacement or
|
||
segment-removal semantics. Keep the existing libraries, prompt text, retry/repair
|
||
budgets, chunk-size defaults, transcript formats, and domain acceptance rules.
|
||
|
||
This plan targets a gpt-5.6-terra coding agent. Execute Stage 1 through Stage 14 in
|
||
order. Each stage is a bounded implementation prompt. If assigned the full plan,
|
||
continue without intermediate permission rounds. If assigned one stage, complete
|
||
its scope and report the next stage. Record completion and actual validation
|
||
beneath each stage; do not mark deferred integration checks as passing.
|
||
|
||
Read `AGENTS.md`, [development guidance](../development.md), and every policy under
|
||
`docs/policy/`. Use graph-first discovery. Observe the [agent](../policy/agents.md),
|
||
[architecture](../policy/architecture.md), [testing](../policy/testing.md),
|
||
[documentation](../policy/documentation.md), and [release](../policy/release.md)
|
||
policies. The selected resilience behavior deliberately replaces the current
|
||
blanket runtime-failure cancellation and reporting contracts; update their
|
||
canonical descriptions as implementation lands.
|
||
|
||
These stages partition one refactor, not supported intermediate releases.
|
||
Intermediate commits need not build or run. Do not add temporary adapters,
|
||
compatibility shims, duplicate pipelines, or fake success results to keep them
|
||
working. Use real final types, reconnect their consumers in subsequent stages,
|
||
and record unavailable checks honestly. Commit coherent stages with plain-English
|
||
messages after appropriate checks under the standing agent policy.
|
||
|
||
Tests are deterministic, offline, and credential-independent. Prefer real internal
|
||
collaborators and controlled HTTP/transport/filesystem boundaries. Run focused
|
||
checks as their owning stage becomes testable, then the complete validation in
|
||
Stage 14. Do not duplicate a test matrix at every layer. No dependency upgrades,
|
||
upstream edits, paid calls, release publication, CI waiting, or unrelated timestamp
|
||
or normalization changes are authorized by this plan.
|
||
|
||
This replaces the completed library-adoption plan. Its historical completion
|
||
record is available with `git show cb405f6:docs/roadmap/implementation.md`.
|
||
Legacy references to that completion evidence do not imply this new plan is done.
|
||
|
||
## Concrete Design Decisions
|
||
|
||
### A. Settings, CLI, and Compatibility
|
||
|
||
Retain configuration version 2 and ConfigKit's file/overlay/visited-override
|
||
resolution. Add these settings:
|
||
|
||
| Setting | Default | CLI override | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `reporting.enabled` | `true` | `--reporting[=true\|false]` | Write the ordinary three-file report bundle. |
|
||
| `reporting.stdout_dir` | `.` | `--report-dir DIR` | Report destination when the transcript goes to stdout; relative to invocation working directory. |
|
||
| `diagnostics.debug` | `false` | `--debug[=true\|false]` | Persist detailed diagnostic artifacts. |
|
||
| `diagnostics.work_dir` | Existing default | Existing `--work-dir` | Parent of unique debug directories; used only with debug enabled. |
|
||
|
||
Register the new setting overrides through the same parser used by configuration
|
||
inspection commands. Only explicitly visited flags override resolved settings;
|
||
explicit false must override true in a file or overlay. Boolean overrides must
|
||
reach ConfigKit as booleans, not strings. `--reporting=false` is the sole reporting
|
||
disable spelling; do not add a parallel negative alias.
|
||
|
||
For file transcript output, always place reports in `filepath.Dir(outputPath)`.
|
||
`reporting.stdout_dir`/`--report-dir` have no effect in that mode, or when reporting
|
||
is disabled; help must say so. With stdout output, use the selected stdout report
|
||
directory, defaulting to the invocation working directory. Retain stdout support.
|
||
Configuration inspection performs no output-directory creation or permission
|
||
probes. At process destination selection, require a nonblank stdout report directory
|
||
only for reporting-enabled stdout runs, and a nonblank debug parent only when debug
|
||
is enabled. Perform filesystem checks only for destinations actually used.
|
||
|
||
Remove `--report-json`, `diagnostics.retention`, `--work-dir-retention`, their enum,
|
||
and old automatic retention logic. Debug directories are retained whenever debug
|
||
is enabled, on success or failure; otherwise none is created. No compatibility
|
||
aliases or legacy ordinary JSON report are required. Keep transcript/schema,
|
||
profile selection, and other existing settings unchanged. Do not reinterpret
|
||
`--output -`; existing omission of `--output` continues to select stdout.
|
||
|
||
### B. Processing Identity and State
|
||
|
||
Partition the normalized transcript exactly once in the runner, before entering
|
||
its module loop. Return that initial section inventory/summary to CLI reporting;
|
||
remove the separate pre-run CLI chunking pass. Preserve existing nil-config test
|
||
behavior and the chunker's handling of empty input and impossible constraints.
|
||
|
||
Keep an ordered slice of chunk states with immutable section index, segment IDs,
|
||
and initial section metadata, plus mutable segment text. A stage finishes across
|
||
chunks before the next starts. Apply approved corrections within their owning
|
||
chunk using the existing replacement policy and application checks, then carry
|
||
that text to the next stage. Recombine only for the final transcript. Chunking
|
||
estimates in the inventory describe the initial partition; later validation
|
||
budgets still estimate the current payload, not stale initial text.
|
||
|
||
Retain `ResolveModuleRunSpecs` instance names. Internal chunk, batch, and proposal
|
||
indices stay zero-based. Preserve the existing stage-wide proposal-index ordering:
|
||
chunk order followed by response proposal order, assigned independently of worker
|
||
completion order. A proposal's identity is its module instance plus proposal index,
|
||
with section index retained for attribution. Never join decisions by batch number
|
||
or provider call ID. Batch numbering is local to one validator in one chunk.
|
||
|
||
Represent each stage/chunk outcome as `not_started`, `completed`, or `interrupted`,
|
||
with applied-correction count, compact operation outcomes, and optional debug
|
||
records. `completed` means the unit reached a terminal processing outcome, not
|
||
that all model operations succeeded. Keep known inventory for unattempted units
|
||
on fatal failure. A model error can coexist with applied corrections and recoveries.
|
||
|
||
### C. Domain Outcomes and Model Failures
|
||
|
||
Introduce a small `internal/framework/outcomes` package for processing-owned
|
||
operation references, execution counts, reason codes, and outcomes. It must not
|
||
import reporting, CLI, providers, or the runner. Do not create a generic event bus,
|
||
workflow framework, or persistence interface in the processing model.
|
||
|
||
An operation reference contains module instance/key, section index, operation kind
|
||
(`proposal`, `validation`, or `validation_input`), optional validator name/order,
|
||
and optional batch index. Proposal operations occur once per work unit. An
|
||
oversized-input failure uses `validation_input` without a batch; consolidate such
|
||
items per validator invocation and record affected proposal indices. Ordinary
|
||
validation operations represent actual structured-client invocations, not retries.
|
||
|
||
Compact operation outcomes carry execution counts when available, terminal success
|
||
or failure, safe failure reason, and filtering details keyed by proposal identity.
|
||
Add them to module/validator results and preserve them on fatal returns. Keep
|
||
provider attempts, transient retries, and structural repairs distinct. Use a
|
||
presence/availability flag for execution counts rather than inventing totals if
|
||
an external client supplies none.
|
||
|
||
Keep typed Go errors for failures that require aborting the run. Extend
|
||
`structuredoutput.Failure` to distinguish a recoverable model-operation failure
|
||
from a fatal adapter/application failure and parent cancellation, with a stable
|
||
safe reason code and preserved `Unwrap` cause. Domain callers consume recoverable
|
||
failures into unsuccessful operation outcomes; they do not return them as fatal
|
||
runner errors. Bare/unclassified internal errors remain fatal.
|
||
|
||
Use this classification order at the adapter boundary:
|
||
|
||
| Condition | Result |
|
||
| --- | --- |
|
||
| Parent processing context is canceled or expired | Fatal cancellation; preserve parent cause. |
|
||
| Invalid output target, unknown embedded schema, prepared-target mismatch, missing/broken prompt/profile/schema asset, invalid request/configuration, or nil result without error | Fatal invariant/setup failure. |
|
||
| Local operation/attempt deadline while the parent is live | Recoverable `operation_timeout`. |
|
||
| Capacity rejection | Recoverable `capacity_exceeded`. |
|
||
| Transport error | Recoverable `transport_failed`. |
|
||
| Malformed provider HTTP response/envelope | Recoverable `provider_response_invalid`. |
|
||
| Provider HTTP failure, including non-retryable statuses | Recoverable `provider_failed`, with numeric status when available. |
|
||
| Retry exhaustion | Recoverable failure using its known underlying category; retain exhaustion and attempt counts as detail. |
|
||
| Returned output remains structurally invalid after permitted repairs | Recoverable `invalid_output_exhausted`. |
|
||
| Structurally accepted output has a model value that cannot fit its Go domain target, e.g. integer overflow (`json.UnmarshalTypeError`) | Recoverable `invalid_output`. |
|
||
| Other decoding/invariant failures or unknown library errors | Fatal; do not convert every exception into a successful no-op. |
|
||
|
||
Use `errors.Is`/`errors.As`, PromptKit's typed errors and terminal metadata, and the
|
||
phase of failure; never parse provider error text. Check known setup/invariant
|
||
causes before broad generation/validation wrappers. `ErrValidation` by itself is
|
||
not proof of repair exhaustion. A non-nil invalid result and known provider causes
|
||
must be distinguished from an embedded validation-contract defect. PromptKit
|
||
v0.11.0 exposes the required provider/transport/capacity and retry information;
|
||
no upstream change is part of this work.
|
||
|
||
Do not expose raw causes, provider messages, URLs, or prompt fragments in ordinary
|
||
reports. Use fixed safe explanations plus structured codes/status/counts. Redact
|
||
all configured backend credentials, including unselected backends, at output.
|
||
|
||
### D. Partial Validation and Safe Application
|
||
|
||
Every submitted candidate still receives exactly one decision per validator.
|
||
Represent model-unavailable candidates as explicit non-approved decisions with an
|
||
operation-failure disposition; distinguish them from valid editorial rejection.
|
||
This preserves cardinality and prevents accidental approval while allowing other
|
||
batches to return their genuine decisions. Keep decision-level details in debug;
|
||
ordinary errors group their operation failures by work unit.
|
||
|
||
On a recoverable batch failure, reject only that batch's candidates, record the
|
||
failed operation, and continue remaining batches and later validators for survivors.
|
||
Missing/duplicate/unknown decision indices invalidate that batch as a whole; do
|
||
not salvage a subset of an untrustworthy decision set or add semantic retries.
|
||
Reject oversized individual validation inputs without sending them, record a
|
||
`validation_input_too_large` failure, and still batch/process the other candidates.
|
||
A fatal error or parent cancellation instead stops the validator, retaining its
|
||
partial observations for diagnosis but never presenting unchecked candidates as
|
||
approved.
|
||
|
||
Retain every required validator in its current order. Only candidates approved by
|
||
all required validators reach `ApplyProposals`. Application stays deterministic
|
||
and may reject proposals made stale by earlier accepted corrections. A failed
|
||
batch does not roll back successful unrelated corrections. Fatal runs do not
|
||
publish a completed transcript; already committed earlier-stage state remains
|
||
available for partial diagnostic evidence.
|
||
|
||
Preserve current empty-replacement semantics: an empty replacement can remove a
|
||
span only if existing preview/application rules allow it and the segment remains
|
||
nonempty. Do not alter prompt/schema/deletion behavior under this plan.
|
||
|
||
### E. Recoveries and Counts
|
||
|
||
The adapter returns per-call execution counts in `structuredoutput.Response`,
|
||
including on error, using the terminal PromptKit observation. Callers determine
|
||
whether the final domain result was usable. The adapter alone must not declare
|
||
recovery merely because HTTP/schema handling succeeded.
|
||
|
||
Create at most one recovery record per successful logical model operation. Its
|
||
`reasons` list can contain `output_repaired`, `service_recovered`, and, for a
|
||
proposal response, `proposals_filtered`. If repair succeeded but its final domain
|
||
decision set is unusable, that operation is an error, with its repair/retry counts
|
||
in error details; it is not also a recovery. Earlier successful operations retain
|
||
their recoveries even if later operations in the unit fail.
|
||
|
||
Consolidate defective proposals filtered anywhere in that unit into the originating
|
||
proposal operation's recovery. Deduplicate affected proposal indices and retain
|
||
reason/count details; never add one recovery per rejected proposal or validator.
|
||
Recoveries from retries/repair and filtering of the same proposal response merge.
|
||
|
||
Classify existing rejection reasons deliberately:
|
||
|
||
- Filtering invalid target IDs, absent target/original text, empty original text,
|
||
invalid confidence, no-effect proposals, ambiguous original spans, and proposals
|
||
that would empty a segment contributes to `proposals_filtered`.
|
||
- Low confidence within the valid range, protected-term policy rejection, and
|
||
valid LLM editorial rejection are ordinary debug decisions, not recoveries.
|
||
- A proposal becoming stale or redundant because an earlier accepted proposal
|
||
changed the text is normal apply-time conflict resolution, not a model defect.
|
||
Compare applicability to the stage/chunk input snapshot when necessary; do not
|
||
relabel every apply-time skip as a recovery.
|
||
- Failure to validate because of size, invalid decision sets, or model availability
|
||
is an error, never a filtering recovery. Unexpected missing candidates or broken
|
||
cardinality in Audita's own assembled result is fatal internal failure.
|
||
|
||
Counts are derived once from processing outcomes:
|
||
|
||
- `work_units_total`: stage instances times initial chunks, zero for either empty set.
|
||
- `work_units_started`, `work_units_completed`, `work_units_interrupted`,
|
||
`work_units_not_started`: explicit states, not inferred from absent events.
|
||
- `work_units_with_errors`: distinct stage/chunk units with recoverable operation
|
||
failures; a partially successful unit counts once.
|
||
- `run_errors`: fatal errors outside that recoverable-unit count. A fatal error may
|
||
carry an origin operation reference without creating a duplicate unit error.
|
||
- `corrections_applied`: applied proposals, not replacement occurrences.
|
||
- `llm_operations`: actual structured-client invocations including pre-dispatch
|
||
failures; `proposal_responses`: structurally usable proposal responses.
|
||
- `recoveries`: unique successful operations with recovery reasons. Show counts
|
||
alongside `llm_operations`; for filtering-specific context show affected proposal
|
||
responses alongside `proposal_responses`. Do not create a single ambiguous
|
||
percentage or count repair generations as independent operations.
|
||
|
||
Reason summaries count records containing each reason. Explain that one recovery
|
||
can have multiple reasons, so those category counts need not sum to its total.
|
||
Knownness/completeness of usage and existing indexed execution aggregation remain
|
||
intact. Full token/timing/attempt evidence belongs in debug, not an expanded
|
||
ordinary report.
|
||
|
||
### F. Ordinary Output Schema and Markdown
|
||
|
||
Use explicit Audita DTOs in `core/reporting`, separate from runner/domain types;
|
||
`framework/processreport` maps processing state to those DTOs. Render YAML with
|
||
`yaml.v3` and explicit YAML tags. Do not export raw PromptKit types or serialize
|
||
errors with their causes. Schema version is integer `1` for these new document
|
||
names; this is not the former JSON process-report schema.
|
||
|
||
Both YAML documents have these envelope fields, in this order:
|
||
|
||
| Field | Definition |
|
||
| --- | --- |
|
||
| `schema` | `audita-errors` or `audita-recoveries` |
|
||
| `version` | `1` |
|
||
| `run_id` | Same run ID across reports/debug; generated once independently of debug directory creation. |
|
||
| `status` | `in_progress`, `completed`, or `failed`; model errors alone still yield `completed`. |
|
||
| `started_at`, `completed_at` | UTC RFC3339 strings; completion is null initially. |
|
||
| `summary` | Counts named in E, in that order. Unknown pre-processing counts are null; completed empty counts are zero. |
|
||
| `errors` or `recoveries` | Always an ordered sequence, including `[]` when empty. |
|
||
|
||
`errors` contains two record variants with explicit `scope`:
|
||
|
||
- `work_unit`: `stage_index`, `module_key`, `module_instance`, `chunk_index`,
|
||
`start_segment_id`, `end_segment_id`, `corrections_applied`, and `failures`.
|
||
Each failure contains `operation`, optional `validator`/`batch_index`, `reason`,
|
||
fixed safe `message`, sorted `proposal_indices` when known, and optional execution
|
||
counts (`provider_attempts`, `transient_retries`, `structural_repairs`,
|
||
`retries_exhausted`, `http_status`). Do not duplicate transcript text.
|
||
- `run`: `phase`, `reason`, safe `message`, and optional originating stage/chunk/
|
||
operation identity. Include primary fatal and secondary output-write failures
|
||
without pretending these are skipped LLM work units.
|
||
|
||
Each recovery contains stage/module/chunk identity as above, `operation`, optional
|
||
`validator`/`batch_index`, ordered `reasons`, fixed safe `message`, execution counts
|
||
when known, and `filtered_proposals` with sorted indices and reason/count entries
|
||
when filtering occurred. One record can describe both repairs and filtering.
|
||
|
||
Indices in YAML are zero-based. Display chunk and batch numbers as index + 1 in
|
||
Markdown/CLI, while retaining exact module-instance names. Order unit records by
|
||
configured stage order, then chunk index. Within units order proposal first, then
|
||
validators by chain order, input preparation before batches, then batch index.
|
||
Sort reason lists by code and proposal indices numerically. Render run errors in
|
||
lifecycle phase order with output paths sorted for same-phase secondary failures.
|
||
Use semantic identity for order; concurrent call IDs/timestamps do not determine
|
||
report row or event order.
|
||
|
||
`report.md` always has a title/run ID, status, concise correction/coverage/error/
|
||
recovery totals, input/output paths, and the two matrices. Stage columns follow
|
||
configured order; all chunks appear as rows, labeled with 1-based chunk number
|
||
and initial segment range. Error cells are 0 or 1 for completed units; recovery
|
||
cells are counts. Use `—` for not-started units and `n*` for interrupted units,
|
||
where n is the available count; include a fixed legend. Add totals and short
|
||
reason breakdowns and refer to the YAML files. An empty stage or chunk set gets
|
||
an explicit “No work units” sentence instead of an invalid empty table.
|
||
|
||
No adaptive width checks, row omission, table splitting, transcript excerpts, or
|
||
correction lists. Escape Markdown paths/labels, especially pipes, newlines, and
|
||
backticks. Timing values may differ between runs; ordering/layout given the same
|
||
snapshot are deterministic. Redact strings before presentation without corrupting
|
||
numeric/boolean fields or resurrecting the old unredacted fallback.
|
||
|
||
### G. Destination Lifecycle and Failure Semantics
|
||
|
||
An output session in `core/diagnostics` owns filesystem state; CLI composes it.
|
||
The runner and renderers perform no filesystem operations. Report directories
|
||
must exist, matching the existing transcript-output parent requirement; do not
|
||
silently create ordinary output parents. Debug parents may still be created by
|
||
the debug-directory writer.
|
||
|
||
After valid configuration/profile inspection, resolve paths and guard collisions
|
||
before any report truncation. Compare cleaned absolute paths, resolved existing
|
||
symlink targets/parents, and `os.SameFile` for existing files. Reject collisions
|
||
among the transcript output and the three enabled reports, and with transcript,
|
||
glossary, and known loaded configuration/profile source files. These checks
|
||
prevent self-overwrite, not hostile filesystem races; allow ordinary symlink use
|
||
and existing-output replacement. Return usage/configuration classification 2 for
|
||
conflicting destinations. Disabled report paths are not resolved, probed, created,
|
||
truncated, removed, or included in collision checks.
|
||
|
||
For file transcript output, verify an existing target can be opened for writing
|
||
without `O_TRUNC`; close it. Probe creation in its parent with a standard temporary
|
||
file and remove that probe. For an absent target probe the parent without leaving
|
||
an empty purported transcript. Validate target type and collisions first; do not
|
||
truncate an input or existing transcript during preflight. Stdout cannot be
|
||
preflighted this way; its eventual write error is fatal.
|
||
|
||
With reporting enabled, initialize all three final report paths with the same
|
||
`in_progress` run ID and empty event lists before input processing/model dispatch.
|
||
Return 1 immediately if initialization fails; do not invoke an LLM. Attempt to mark
|
||
already created reports failed when possible. A readable but invalid transcript
|
||
may then produce failed reports. Earlier configuration/profile failures may occur
|
||
before report initialization and need not produce a bundle.
|
||
|
||
At successful processing completion, fully encode output before writing it. Use
|
||
standard temporary-file/write/close/rename replacement within the destination
|
||
parent for each final file, cleaning owned temporary files on failure. This is
|
||
per-file replacement, not a multi-file atomic transaction or durability guarantee;
|
||
no fsync protocol, locks, journal, or automatic rollback system. Preserve existing
|
||
file-output permission behavior where applicable and never erase a successfully
|
||
published transcript because a later report fails.
|
||
|
||
Write the transcript first, then `errors.yml`, `recoveries.yml`, and `report.md`
|
||
last. Final write/close/rename errors are fatal even if preflight succeeded.
|
||
Attempt the other enabled report finalizations, collect safe secondary failures,
|
||
and make one bounded best-effort pass to write failed-status reports if finalization
|
||
failed. Never retry indefinitely or print the success completion message after a
|
||
required-output failure. Some files may retain an earlier/in-progress snapshot;
|
||
the nonzero exit and stderr identify incomplete finalization.
|
||
|
||
On a processing fatal error or cancellation, do not publish a completed transcript;
|
||
finalize partial reports as failed where possible. Root cancellation must not
|
||
prevent local report cleanup/finalization after workers have joined. Uncatchable
|
||
termination may leave `in_progress`; no resume machinery is added.
|
||
|
||
Debug remains optional evidence, not a condition for transcript success: failure
|
||
to create/write debug artifacts emits safe stderr diagnostics but does not change
|
||
processing or the exit status. Do not invent an error-bearing work unit for a debug
|
||
write failure. Required ordinary reports and transcript writes retain their fatal
|
||
semantics. Debug and reporting selections are independent.
|
||
|
||
### H. Debug Artifacts and CLI Completion
|
||
|
||
With debug enabled, create one unique child under `diagnostics.work_dir`, using the
|
||
run ID. Retain it on every outcome; no automatic cleanup/retention modes. Gate the
|
||
writers and directory creation, not merely cleanup. Empty diagnostics paths/nil
|
||
writers must propagate through module factory, proposals, and validators when off.
|
||
|
||
Keep useful current artifacts under debug: source/normalized snapshots, invocation,
|
||
redacted effective settings, config origins, selected profiles, chunking/normalization
|
||
summaries, correction/decision ledger, indexed execution/utilization data, and model
|
||
interaction payloads. Ensure all proposed candidates, including those later rejected
|
||
or unavailable, can be inspected when debug is on. Keep JSON where suitable; do not
|
||
retain the old ordinary process report as a compatibility output. Remove obsolete
|
||
models/helpers/tests rather than keeping dead serialization paths.
|
||
|
||
Full payload capture/persistence is not required for production summaries. Compact
|
||
operation state and necessary processing data remain available with both reporting
|
||
and debug off, so classification and CLI totals do not change. Use all configured
|
||
secrets for every writer, including debug snapshots, YAML, Markdown, and surfaced
|
||
messages. Do not assume metadata identifiers are safe merely because payloads
|
||
are absent.
|
||
|
||
Successful CLI stderr begins with the selected style, using exact semantic counts:
|
||
`Completed: N corrections applied; E work units with errors; R recoveries.`
|
||
Report locations and the debug location follow only when actually created. There
|
||
are no ordinary warning messages. Suppressing files does not suppress this brief
|
||
summary or fatal errors. Stdout remains transcript-only; with `--output`, stdout
|
||
is empty. Exit 0 means processing and all enabled required outputs completed;
|
||
exit 1 covers runtime/cancellation/output failure; exit 2 retains usage/configuration
|
||
classification. Reporting disabled removes only its file requirements.
|
||
|
||
## Stage 1 — Define Processing Outcomes and Contracts
|
||
|
||
**Completed 2026-09-24.** Added processing-owned operation identities, execution
|
||
counts with availability, safe outcome/recovery reasons, work states, explicit
|
||
decision dispositions, and typed recoverable/fatal/canceled failure classes. The
|
||
proposal, validator, and runner result boundaries now carry operation outcomes
|
||
instead of warning fields. `go test ./internal/framework/outcomes
|
||
./internal/framework/structuredoutput` and `git diff --check` passed. Tests of
|
||
contracts, validators, and runner are temporarily unavailable because existing
|
||
validator/runner consumers still use the removed warning fields; Stages 3, 4,
|
||
and 6 reconnect those consumers.
|
||
|
||
**Work:** Add the small outcome/reference/count types from B–E. Extend
|
||
`structuredoutput.Response` and `Failure`, module proposal results, validator
|
||
results/decisions, and runner output to carry actual processing outcomes. Replace
|
||
`StageWarning` at these boundaries with the final outcome model; do not alias the
|
||
old category to recoveries. Keep Go causes nonserializable and operation references
|
||
independent of report DTOs. Make invalid/unavailable decision disposition explicit.
|
||
|
||
**Touchpoints:** `internal/framework/structuredoutput`, `contracts`, `validators/models.go`,
|
||
`runner/runner.go`, and new `framework/outcomes`. Keep dependencies acyclic; shared
|
||
outcome types cannot import their consumers.
|
||
|
||
**Validation:** Focused tests for typed error matching and decision partition/cardinality
|
||
where behavior is introduced. Compile affected leaf packages. Record temporary
|
||
consumer compile failures for subsequent stages; do not add compatibility fields.
|
||
|
||
**Exit:** Contracts can express success, recoverable model failure, fatal failure,
|
||
partial validation, and recovery detail without any filesystem/report dependency.
|
||
|
||
## Stage 2 — Classify Model Failures and Return Execution Facts
|
||
|
||
**Completed 2026-09-24.** The PromptKit adapter now classifies parent
|
||
cancellation, setup defects, local deadlines, capacity, transport, provider
|
||
envelopes/statuses, exhausted invalid output, and domain decode overflow with
|
||
typed safe failures. It returns terminal attempt/retry/repair/status counts on
|
||
successful and failed calls, while preserving observation hooks and typed causes.
|
||
`go test ./internal/framework/llm -count=1`, its race suite, and
|
||
`git diff --check` passed. Whole-repository compilation remains deferred while
|
||
the warning consumers are reconnected in later stages.
|
||
|
||
**Work:** Implement C in `llm/adapter.go` using the pinned library's public types.
|
||
Capture terminal counts locally for each call and return them even on failure;
|
||
forward existing observation hooks without deriving recovery classifications in
|
||
the adapter. Preserve prepared-target checks, deadline-before-preparation, same
|
||
shared engine/capacity, typed causes, and safe messages. Handle parent cancellation
|
||
before local timeout classification. Keep metadata collection concurrency-safe.
|
||
|
||
**Validation:** Extend adapter behavioral tests for repaired success/counts,
|
||
exhausted invalid output, provider/transport/envelope/capacity failure, local versus
|
||
parent deadline/cancellation, preparation defects, and decode overflow. Reuse
|
||
existing retry/capacity tests rather than retesting PromptKit. Assert no additional
|
||
outer attempts and no provider text in safe errors.
|
||
|
||
**Exit:** Domain callers can distinguish skippable model work from fatal errors
|
||
without examining error strings; counts are available independently of debug.
|
||
|
||
## Stage 3 — Convert Proposal Failures and Classify Safe Filtering
|
||
|
||
**Completed 2026-09-24.** Proposal generation and the shared path used by all
|
||
four built-in modules now preserve one identified operation with terminal counts
|
||
on success, recoverable failure, and fatal return. Recoverable failures yield no
|
||
candidates; a valid empty response succeeds. A focused domain classifier separates
|
||
defective proposals from editorial rejection without changing deterministic
|
||
validator policy. Updated proposal, wrapper, and filtering tests are present.
|
||
`git diff --check` passed. Those tests and the existing four-module routing tests
|
||
cannot compile until the validator warning consumers are converted in Stage 4;
|
||
the attempted `go test` reports those exact stale-field errors.
|
||
|
||
**Work:** Update `proposal_generation.GenerateCandidates` and all four module
|
||
wrappers to preserve operation outcomes. A recoverable proposal call returns zero
|
||
candidates plus a failed operation, not a warning or fatal Go error. A valid empty
|
||
response is successful. Fatal errors retain their partial call facts and propagate.
|
||
Carry successful-call counts until domain filtering can consolidate its recovery.
|
||
|
||
Implement the explicit filtering/editorial distinction in E at the domain decision
|
||
boundary (a small reason classifier is sufficient). Preserve current deterministic
|
||
validators, thresholds, glossary protection, and empty-replacement behavior. Keep
|
||
payload diagnostics conditional on a supplied writer/path.
|
||
|
||
**Validation:** Proposal integration tests distinguish malformed exhaustion from
|
||
fatal setup and valid empty output; deterministic filtering tests cover a defective
|
||
proposal versus low-confidence/protected-term rejection. Reuse current four-module
|
||
routing tests to prove wrappers preserve outcomes and identities.
|
||
|
||
**Exit:** Proposal callers no longer abort for model failures, and filtering can be
|
||
attributed to the originating proposal response without treating normal rejection
|
||
as recovery.
|
||
|
||
## Stage 4 — Preserve Successful Validation Batches
|
||
|
||
**Completed 2026-09-24.** LLM validation now keeps successful batch decisions
|
||
around recoverable failed batches, emits explicit unavailable decisions for failed
|
||
or oversized inputs, and records one compact operation per client call plus one
|
||
consolidated oversized-input operation. Invalid decision sets fail their own
|
||
batch, and retry/repair recovery is recorded only after usable domain mapping.
|
||
Fatal failures retain earlier facts and stop later batches. Focused validator,
|
||
proposal, and four-module tests pass, as do validator/proposal race tests.
|
||
`git diff --check` passed. Runner compilation is still deferred because its old
|
||
warning fields are reconnected in Stage 6.
|
||
|
||
**Work:** Refactor `LLMBackedValidator.Validate`, input preparation, and response
|
||
mapping per D. Collect all successful batch decisions; on a recoverable failure
|
||
add non-approved unavailable decisions for that batch and continue. Keep invalid
|
||
index sets batch-scoped, oversized candidates excluded individually, and errors
|
||
separate from valid negative decisions. Record final domain outcome before declaring
|
||
service/repair recovery. Stop promptly on fatal errors/parent cancellation and
|
||
retain completed operation facts. Do not synthesize approval for remaining items.
|
||
|
||
**Validation:** One controlled multi-batch workflow proves successes before and
|
||
after a failed batch survive, and a later validator receives only survivors under
|
||
new batch numbering. Cover oversized individual input, missing/duplicate/unknown
|
||
indices, repaired-but-domain-invalid output, ordinary rejection, and fatal stop.
|
||
Use the existing estimator seam to force batches without brittle default budgets.
|
||
|
||
**Exit:** Every normally returned result has exactly one decision for each submitted
|
||
candidate; failed model batches do not discard unrelated decisions or bypass later
|
||
required validation.
|
||
|
||
## Stage 5 — Fix Chunk Boundaries for the Entire Run
|
||
|
||
**Completed 2026-09-24.** The runner now partitions once before the module loop,
|
||
returns the initial section inventory, applies approved corrections only inside
|
||
their identified sections, carries current text forward, and recombines the
|
||
transcript after processing. Tests cover substantial text growth, stable segment
|
||
membership, empty work, and impossible chunk constraints. `go test
|
||
./internal/core/chunking` and `git diff --check` passed. Runner tests remain
|
||
unavailable because warning-field consumers still fail compilation; Stage 6
|
||
replaces them with operation outcomes.
|
||
|
||
**Work:** Move the runner's chunking call before its stage loop. Own fixed chunk
|
||
states and initial inventory in runner output. Execute each module using the current
|
||
text of those same chunks, and apply fully approved candidates only within their
|
||
chunk. Keep stage barriers, initial chunk metadata, deterministic proposal indexing,
|
||
and final ordered recombination. Remove the redundant CLI chunk computation when
|
||
wiring its consumer, not by adding an interim second inventory. Preserve within-stage
|
||
proposal/validation concurrency and shared capacity; no new scheduler is required.
|
||
|
||
**Validation:** A multi-stage test deliberately grows text enough that old re-chunking
|
||
would alter membership; assert stable chunk/segment identity and next-stage current
|
||
text. Cover repeated modules, target-section selection, empty transcript/pipeline,
|
||
and application ordering with unchanged output-schema behavior.
|
||
|
||
**Exit:** The normalized transcript is partitioned once and domain processing does
|
||
not rely on report tables to maintain chunk state.
|
||
|
||
## Stage 6 — Integrate Partial Outcomes and Fatal Cancellation
|
||
|
||
**Completed 2026-09-24.** The runner now preserves per-section operation facts,
|
||
continues after recoverable model failures, applies only candidates approved by
|
||
every required validator, and retains completed observations on fatal cancellation.
|
||
It tracks explicit work-unit states and merges defective-proposal filtering with
|
||
an existing proposal recovery. Runner tests cover total proposal failure, mixed
|
||
validation outcomes, later modules, multiple failures in one unit, merged recovery,
|
||
and fatal cancellation. `go test -race ./internal/framework/runner
|
||
./internal/framework/llm` and `git diff --check` passed. Integrated reporting
|
||
checks remain deferred until the reporting stages.
|
||
|
||
**Work:** Update `collectSectionProposals`, `runModulePipeline`, and
|
||
`validateSectionCandidates` to consume the outcomes from Stages 3–4. Recoverable
|
||
failures never enter shared fatal cancellation. Preserve candidates through every
|
||
required validator by proposal index and apply successful survivors even when the
|
||
unit has errors. Never return unchecked `eligible` candidates as approved on an
|
||
error path. Propagate completed outcomes even if another worker cancels the stage;
|
||
do not drop buffered terminal evidence merely because the context is canceled.
|
||
|
||
Retain synchronized first-fatal-error ownership, immediate peer cancellation, worker
|
||
joining, and deterministic collection. Track not-started/interrupted/completed units
|
||
and the counts in E. On fatal stage exit do not apply incomplete validation results;
|
||
retain prior committed stages and honest partial observations. Aggregate proposal
|
||
filtering once, merge its reasons with any proposal retry/repair recovery, and
|
||
retain earlier recoveries when later operations fail.
|
||
|
||
**Validation:** Runner tests prove total model failure returns normalized output;
|
||
mixed batches apply only fully validated candidates; later stages still execute;
|
||
multiple operation failures count one affected unit; repaired-plus-filtered proposals
|
||
count once. Adapt the existing cancellation regression to a genuine fatal error:
|
||
model failures now continue, while fatal failure cancels active/pending calls,
|
||
retains the originating cause, joins workers, and preserves observations. Run
|
||
focused runner/runtime race tests when those packages are testable.
|
||
|
||
**Exit:** Processing fulfills the resilience contract independently of file output.
|
||
|
||
## Stage 7 — Add Reporting and Debug Settings and CLI Selection
|
||
|
||
**Completed 2026-09-24.** Version-2 settings now resolve reporting and debug
|
||
independently, with typed visited boolean overrides and destination selection
|
||
only for enabled reports. The old JSON-report and retention flags/settings were
|
||
removed; CLI entry points now carry a context from interrupt/SIGTERM handling.
|
||
ConfigKit tests and focused CLI parser tests cover defaults, overlay false
|
||
overrides, bare booleans, destination selection, and removed flags. `go test
|
||
./internal/core/config`, `go test internal/cli/config_input.go
|
||
internal/cli/config_input_test.go`, and `git diff --check` passed. Whole CLI tests
|
||
remain unavailable until Stage 8 replaces the report builder's warning fields.
|
||
|
||
**Work:** Implement A in `core/config/config.go`, `cli/config_input.go`, invocation
|
||
state, and usage text. Add boolean flags with visited-value overrides and update
|
||
safe effective-setting/provenance output. Remove the old external JSON report flag
|
||
and retention selection, including tests for their former semantics. Keep path
|
||
selection in CLI composition, not domain configuration resolution. Add context
|
||
plumbing through `cli.Run(ctx, args, stdout, stderr)` and process/runtime calls;
|
||
update direct callers and tests. In `cmd/audita`, use `signal.NotifyContext` for
|
||
interrupt/SIGTERM, with a small run function that defers stop before `os.Exit`.
|
||
Configuration help/inspection still creates no output files.
|
||
|
||
**Validation:** Parser/ConfigKit tests cover defaults, overlay true overridden by
|
||
CLI false, reporting/debug independence, stdout directory selection, ignored report
|
||
directory in file/disabled mode, removed flags/keys, and side-effect-free inspection.
|
||
No execution scheduler or output files are added in this stage.
|
||
|
||
**Exit:** Final settings/CLI contract is resolved without legacy aliases or accidental
|
||
filesystem requirements for disabled features.
|
||
|
||
## Stage 8 — Map Outcomes to Versioned YAML Reports
|
||
|
||
**Completed 2026-09-24.** The old ordinary JSON report DTO was replaced with
|
||
versioned errors/recoveries YAML DTOs and one processing snapshot. Mapping derives
|
||
nullable summary counts, grouped recoverable work-unit failures, run failures,
|
||
combined recovery reasons, and deterministic semantic order without raw causes or
|
||
transcript payloads. Tests cover partial and empty work, multiple failures,
|
||
initialization unknowns, ordered run errors, safe redaction, and YAML scalar
|
||
types. `go test ./internal/core/reporting ./internal/framework/processreport`
|
||
and `git diff --check` passed. CLI and diagnostics consumers of the removed JSON
|
||
schema remain to be reconnected in later stages.
|
||
|
||
**Work:** Replace ordinary report DTOs and assembly in `core/reporting` and
|
||
`framework/processreport` with F. Map actual runner state once into an immutable
|
||
report snapshot consumed by all presentations. Preserve debug-specific ledger and
|
||
indexed execution mapping only where useful; remove superseded ordinary JSON
|
||
models rather than maintaining two authoritative schemas. Implement YAML rendering
|
||
for initial, completed, and failed snapshots, explicit empty lists/null unavailable
|
||
counts, safe messages, stable ordering, and the two error record scopes.
|
||
|
||
Use existing shared redaction at the serialization boundary. Never marshal a raw
|
||
error cause or depend on typed decode of already-redacted timestamps/identifiers.
|
||
YAML numbers and booleans must retain their types even for numeric credentials.
|
||
|
||
**Validation:** Report tests use partial units, multiple underlying failures,
|
||
combined recovery reasons, no-work input, run-level failure, unavailable initialization
|
||
counts, and deterministic ordering despite reordered observations. Parse rendered
|
||
YAML to verify types/counts and redaction, including unselected/escaped credentials.
|
||
Preserve indexed aggregation and usage semantics in retained debug builders.
|
||
|
||
**Exit:** Both YAML documents truthfully describe the same processing snapshot with
|
||
no filesystem effects or verbose payload leakage.
|
||
|
||
## Stage 9 — Render the Fixed Markdown and CLI Summaries
|
||
|
||
**Work:** Render F/H from the Stage 8 snapshot. Produce both full matrices, totals,
|
||
fixed legends, short reason breakdowns, and safe file references. Display 1-based
|
||
chunk labels without changing machine identity. Include interrupted and unattempted
|
||
states and the no-work sentence. Provide a small shared summary formatter for CLI
|
||
counts; CLI stream/file wiring remains Stage 12. No width heuristics, percentage
|
||
thresholds, row omission, or extra export formats.
|
||
|
||
**Validation:** One representative Markdown golden fixture with explicit update
|
||
opt-in can protect the chosen layout; supplement with semantic checks for repeated
|
||
stages, partial/error-and-recovery cells, empty work, and escaped labels. Assert CLI
|
||
counts agree with YAML and that secrets never enter Markdown. Avoid snapshotting
|
||
wall-clock values or every incidental sentence.
|
||
|
||
**Exit:** Human-facing output is concise, deterministic, and generated from the same
|
||
truth as the structured output.
|
||
|
||
## Stage 10 — Implement Required Output Initialization and Finalization
|
||
|
||
**Work:** Add the output-session filesystem adapter described in G. Resolve active
|
||
paths, protect collisions before truncation, preflight transcript writes without
|
||
destroying existing content, initialize all enabled reports, and publish final files
|
||
using standard per-file replacement. Return structured primary/secondary errors
|
||
for CLI reporting. Track only files/probes created by this invocation for cleanup;
|
||
do not delete previous report files when reporting is disabled. Use ordinary file
|
||
permissions and no multi-file transaction or crash-recovery framework.
|
||
|
||
**Validation:** Real temporary-directory tests cover initialization failure before
|
||
a fake model is invoked, output/report/input collisions including existing aliases,
|
||
existing transcript preservation, overwrite behavior, absent parent, disabled reports
|
||
with an unusable report directory, stdout mode, final transcript/report failures,
|
||
and partial failed-status finalization. For permission failures use a narrow injected
|
||
file-operation seam when tests may run as root; do not rely solely on chmod.
|
||
|
||
**Exit:** Required output failures are detected early where possible and always
|
||
reported at finalization without erasing a completed transcript.
|
||
|
||
## Stage 11 — Make Debug Persistence Explicit and Independent
|
||
|
||
**Work:** Refactor `core/diagnostics` run-directory creation and all CLI/module/
|
||
proposal/validator writer wiring for H. Only debug creates the unique retained
|
||
run directory. Gate snapshots, interaction files, ledger, and full execution data
|
||
at the write source. Keep required ordinary reporting in its separate session.
|
||
Remove automatic retention and the old `never` semantics rather than leaving a
|
||
disabled cleanup path. Ensure debug contains all proposals and decisions needed
|
||
to diagnose filtering/unavailable results, not just applied changes.
|
||
|
||
All debug writers use the shared configured-secret redactor, including original
|
||
input snapshots; a raw source copy must not bypass it. Keep safe stderr reporting
|
||
of optional-debug write failures separate from model incidents and fatal output
|
||
errors. Debug write failures must not change correction decisions or abort the run.
|
||
|
||
**Validation:** Tests prove no debug directory/payload files with debug off, useful
|
||
retained evidence with debug on, redaction across snapshots/interactions, and no
|
||
outcome/exit changes caused by optional debug-write failure. Existing diagnostic
|
||
writer tests are retained or replaced according to behavior, not old filenames.
|
||
|
||
**Exit:** Debug-off never means “write and later delete”; reporting-off/debug-on and
|
||
reporting-on/debug-off both work without coupling their destinations.
|
||
|
||
## Stage 12 — Compose the Final CLI Run Lifecycle
|
||
|
||
**Work:** Replace the current monolithic process/report/retention flow with the
|
||
final composition: load/inspect settings, resolve and initialize required outputs,
|
||
optionally initialize debug, load/normalize input, run fixed-chunk processing,
|
||
render/finalize, and emit completion/failure output. Thread the caller context all
|
||
the way to runtime/runner. Keep phase labels and root versus local cancellation
|
||
clear. After joining workers, use available partial state to finalize failed reports
|
||
without treating cancellation as an instruction to abandon local cleanup.
|
||
|
||
Remove the old pre-run chunking pass and obtain chunk summary/inventory from the
|
||
runner. Honor G's finalization order and bounded failed-status rewrite. Do not
|
||
print success after required-output failure, invent report locations, or serialize
|
||
full corrections into production summaries. Exit 0 with normalized output when
|
||
all LLM operations fail; exit nonzero for genuine fatal/output failures. Both
|
||
reporting and debug disabled still produce the same transcript and CLI counts.
|
||
|
||
**Validation:** Extend actual subprocess fixtures for default file output, stdout
|
||
plus selected report directory, reports disabled, debug-only, all-model failure,
|
||
partial validation success, invalid input after initialization, and output failure
|
||
before dispatch. Inspect created files and streams, not only mocked return values.
|
||
Keep deeper batch/classifier matrices in their owning package tests.
|
||
|
||
**Exit:** The complete application implements the selected production behavior and
|
||
has no obsolete report/retention path keeping debug enabled implicitly.
|
||
|
||
## Stage 13 — Update Canonical Guidance, Examples, and Remove Obsolete Material
|
||
|
||
**Work:** Update `docs/cli.md`, `config.md`, `operations.md`, integration output/subprocess/
|
||
LLM contracts, internal pipeline/validators/LLM/diagnostics/overview guidance, README,
|
||
and maintained examples/migration guidance. Architecture policy must distinguish
|
||
recoverable model failures from fatal cancellation and acknowledge the intentional
|
||
reporting-contract replacement. Describe implemented behavior only outside roadmap.
|
||
|
||
Document the three ordinary files, explicit disable/debug controls, current-directory
|
||
stdout default, all-row matrices, partial successes, finalization failures, exit
|
||
semantics, and retained debug placement. Remove references to `--report-json`, old
|
||
retention modes, ordinary warning reports, and mandatory verbose artifacts. Resolve
|
||
the obsolete retention item in `runtime-behavior.md` without changing unrelated
|
||
input-timestamp policy. Correct older library-adoption links to completion evidence
|
||
so they identify their historical plan instead of claiming this plan is complete.
|
||
Leave `future.md` entries deferred. Do not turn ordinary zero-correction results
|
||
into an operator warning.
|
||
|
||
Remove dead warning types/serialization helpers, obsolete full-report fixtures,
|
||
and unused retention/report wiring identified by the graph and references. Keep
|
||
meaningful domain tests and useful debug evidence; do not delete coverage just to
|
||
hide a still-failing selected invariant.
|
||
|
||
**Validation:** Run maintained example/config inspection checks, affected-link and
|
||
whitespace checks, and focused tests only where cleanup changes behavior. Confirm
|
||
examples contain no credentials and configuration inspection produces no files.
|
||
|
||
**Exit:** Canonical docs and examples describe the final application, with no
|
||
competing current contract or implicit legacy compatibility promise.
|
||
|
||
## Stage 14 — Verify the Integrated Resilience Contract
|
||
|
||
**Work:** Audit every acceptance criterion in `resilience.md` against final code and
|
||
retained tests. Add only missing integration coverage. In particular verify the
|
||
following cross-component outcomes rather than relying solely on green leaf tests:
|
||
|
||
- Every proposal fails; separately proposals succeed but every required validation
|
||
fails. Both return encoded normalized output, completed status, and accurate
|
||
errors with no unsafe corrections. Subsequent stages still attempt their work.
|
||
- A failed batch between successful batches leaves valid survivors; later validation
|
||
re-batches those survivors, and repeated module instances keep distinct identities.
|
||
- Fixed chunks survive substantial text growth; corrections never cross chunk
|
||
ownership and final segment ordering/metadata are preserved.
|
||
- A recovered transport/repair operation plus filtering counts once; a repaired call
|
||
with invalid decision indices counts as an error; a later failed operation does
|
||
not erase earlier recoveries. Ordinary rejection is debug-only.
|
||
- Fatal cancellation reaches active and queued calls, joins workers, and produces
|
||
honest partial/failed reports without a purported complete transcript.
|
||
- All four reporting/debug combinations have equal transcript/summary outcomes;
|
||
inactive destinations are unused. No ordinary full payloads or raw secrets leak.
|
||
- Initial/final write failures produce the selected nonzero result, clean owned
|
||
temporary files, and do not destroy a previously produced transcript. Existing
|
||
outputs can be replaced intentionally; incompatible destination aliases fail
|
||
before truncation.
|
||
|
||
Run `go test ./...`, `go vet ./...`, and focused race tests for runner, LLM,
|
||
validators, reporting/output adapters, and subprocess packages. Build required
|
||
Linux amd64/arm64 binaries using `scripts/build-release.sh` with a valid placeholder
|
||
version and temporary output directory, without tagging or publishing. macOS arm64
|
||
is best effort and not a gate. No live provider, CI polling, or release-distribution
|
||
review belongs in this implementation sprint.
|
||
|
||
Record actual evidence, remaining limitations, and completed stage states here.
|
||
Only mark the feature implemented after the full final state is demonstrated.
|
||
Commit the completed unit under the agent policy; do not push or release.
|
||
|
||
**Exit:** Resilience, partial-success safety, classifications, output lifecycle,
|
||
and debug isolation are proven together in the assembled application.
|
||
|
||
## Open Questions
|
||
|
||
None required to begin implementation. The earlier interface questions are resolved
|
||
by A–H; internal helper names and file splits may vary without changing those
|
||
contracts. If inspection reveals a concrete contradiction in the pinned libraries
|
||
or an agreed requirement, document the question here with a recommended approach
|
||
and reasoning plus at least one viable alternative and reasoning before changing
|
||
that requirement. Do not reopen deferred features or add compatibility machinery
|
||
merely to avoid the selected refactoring.
|