From 801adb385d9b4bc2001ab1d2ee909186ab04edb5 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 10 Aug 2026 23:18:29 +0000 Subject: [PATCH] Reconcile lifecycle documentation --- docs/config.md | 9 ++++ docs/internal/artifacts.md | 13 ++++++ docs/internal/stage-analyze.md | 19 +++++++-- docs/internal/stage-publish.md | 5 ++- docs/internal/stage-render.md | 4 +- docs/operations.md | 8 ++++ docs/roadmap/implementation.md | 28 ++++++------ docs/troubleshooting.md | 2 +- internal/doccheck/doccheck_test.go | 68 ++++++++++++++++++++++++++++++ 9 files changed, 137 insertions(+), 19 deletions(-) diff --git a/docs/config.md b/docs/config.md index a4161f2..0764086 100644 --- a/docs/config.md +++ b/docs/config.md @@ -279,6 +279,15 @@ For each `pipeline.scriptorium.artifacts.`: Narratio adds `session_id=narratio-session-` to every Scriptorium request for sticky upstream LLM routing. If an artifact config sets `vars.session_id`, Narratio replaces that value before invoking Scriptorium. Use a different variable name if a prompt needs the raw Narratio session ID as content. +Without `--artifacts`, analyze executes enabled configured artifacts. With an +explicit `--artifacts` list, the exact named configured artifacts are the +one-invocation execution set even if their `enabled` values are false; the list +does not automatically include dependencies. Named artifacts must therefore be +configured with valid executable fields, and their configured dependencies must +already be available to analyze. This override affects analyze planning only; +publish uses the list only to filter configured +`narratio.artifact.` output rules. + For each artifact input `pipeline.scriptorium.artifacts..inputs.`: | Field | Type | Required | Rule | diff --git a/docs/internal/artifacts.md b/docs/internal/artifacts.md index 244ba8d..eb54a7c 100644 --- a/docs/internal/artifacts.md +++ b/docs/internal/artifacts.md @@ -45,6 +45,15 @@ ID. - `available`: local file exists and validates; - `provenance`: availability source. +Configured definitions are always registered. Without an explicit selection, +the effective analyze set contains enabled definitions. With `--artifacts`, the +exact named configured definitions become the effective set for that invocation, +regardless of their `enabled` value; dependencies are not added implicitly. +Availability is separate from executability: a non-executable configured output +may be reused from a canonical non-empty file, while an executable definition +is generated by analyze. Extraction entries are registered from configuration +and become available only after compatible extraction evidence is hydrated. + Current provenance values: - `generated.current_analyze_run` @@ -81,6 +90,10 @@ Previous-session sources (`narratio.previous_session.artifact.*`): - prefer manifest-backed previous-input paths; - fallback to existing previous-cache filesystem paths. +Source absence is evaluated by the consuming artifact input. An optional input +is omitted from that invocation; a required input fails resolution. This is +separate from a stage's lifecycle outcome. + Validation by content type: - transcript JSON built-ins: JSON with top-level `segments` array; diff --git a/docs/internal/stage-analyze.md b/docs/internal/stage-analyze.md index 001ba3d..4f74b30 100644 --- a/docs/internal/stage-analyze.md +++ b/docs/internal/stage-analyze.md @@ -8,13 +8,15 @@ Execute selected configured Scriptorium artifacts in dependency order and materi - configured artifacts from `pipeline.scriptorium.artifacts` - optional selected artifact keys supplied through the stage environment -- built-in/configured/previous-session source references in artifact inputs +- built-in, configured, extraction, and previous-session source references in + artifact inputs Supported source families: - built-ins: `narratio.transcript.*`, `narratio.bounds.session` - prepared stable inputs: `narratio.input.players`, `narratio.input.party`, `narratio.input.glossary` - configured artifacts: `narratio.artifact.` +- extraction lanes: `narratio.extraction.` - previous-session cache: `narratio.previous_session.artifact.` ## Outputs @@ -24,11 +26,22 @@ Supported source families: ## Key Behavior -- skips with metadata when Scriptorium config is missing or no executable artifacts remain. -- builds runtime artifact catalog (built-ins + configured artifacts). +- when Scriptorium is absent or no configured artifact is executable, completes + successfully with no outputs and records explanatory metadata. This is not an + explicit self-skip: both manifests record success, satisfy publish's + prerequisite, and an ordinary later run reuses the result until forced. +- builds a runtime artifact catalog containing built-ins, configured artifacts, + and configured extraction lanes. Extraction availability is hydrated only + from compatible successful extraction evidence. +- uses enabled configured artifacts by default. An explicit `--artifacts` + selection is a one-invocation override: it makes exactly the named configured + artifacts executable even when disabled, and does not automatically include + dependencies. A selected artifact's dependencies must instead already be + available to the catalog. - marks non-executable configured artifacts as reusable when output files already exist. - validates selected artifact dependency order (cycle-safe topo ordering). - resolves required/optional inputs per artifact source definition. +- omits an unavailable optional input; an unavailable required input fails. - resolves prepared stable input sources from `inputs/*.yml` materialized by `prepare`. - resolves previous-session sources from local `previous/` cache only. - runs optional render-debug, then artifact execution. diff --git a/docs/internal/stage-publish.md b/docs/internal/stage-publish.md index 9065193..590a658 100644 --- a/docs/internal/stage-publish.md +++ b/docs/internal/stage-publish.md @@ -25,7 +25,10 @@ Exact remote placement and the operator workflow belong in ## Key Behavior -- stage can self-skip when publish disabled or run upload disabled. +- when publishing or run upload is disabled, completes successfully with no + outputs and records explanatory metadata. This is not an explicit self-skip: + both manifests record success, and an ordinary later run reuses that result + until publish is forced. - validates prerequisite stage success and object-store availability. - derives a deterministic run-archive allowlist from the validated run `manifest.json`: declared run-local outputs, logs, generated configs, and the diff --git a/docs/internal/stage-render.md b/docs/internal/stage-render.md index 07cb964..314a780 100644 --- a/docs/internal/stage-render.md +++ b/docs/internal/stage-render.md @@ -20,7 +20,9 @@ Render Markdown transcript artifacts from normalized JSON transcripts via Seriat - resolves inputs manifest-first, then canonical fallback. - writes run-local outputs first, then materializes canonical session outputs. - records input provenance, output paths, adapter metadata, logs, and generated config refs. -- skips with stage metadata when `pipeline.render.enabled=false`. +- when `pipeline.render.enabled=false`, completes successfully with no outputs + and records explanatory metadata. This is not an explicit self-skip: both + manifests record success, and enabling render later requires a forced run. ## Failure Semantics diff --git a/docs/operations.md b/docs/operations.md index a754b31..f05d05c 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -92,6 +92,14 @@ Execution rules: repeated self-skip with the same reason and no outputs is stable and does not perpetually rerun downstream work. +An explicit self-skip is a durable `skipped` stage outcome that later runs +reconsider. It differs from successful no-output execution: disabled `render` +and `publish`, and absent or no-executable `analyze`, record `succeeded` with +metadata and no outputs. Ordinary later runs reuse those successful results; +force the affected stage after enabling or configuring it. Optional artifact +inputs are omitted only from the consuming artifact invocation and do not make +the stage self-skip. + Single-stage execution: ```bash diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 55316dd..c6766ce 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -12,7 +12,7 @@ into this document. The line ranges below are stable references to the evidence and acceptance criteria that the implementing agent must read for each stage. This plan owns remediation progress; a separate `audit.md` tracker is not needed. -All stages are pending when this plan is created. +All stages begin pending when this plan is created. | Stage | Summary | Primary findings | Status | | ---: | --- | --- | --- | @@ -36,18 +36,18 @@ All stages are pending when this plan is created. | 18 | Serialize restore transitions and make restored paths portable | RSK-006, RSK-008 | Completed | | 19 | Bind audio cache reuse to remote object identity | RSK-007 | Completed | | 20 | Unify previous-source readiness and eliminate duplicate transfers | COR-010, EFF-001 | Completed | -| 21 | Tighten configuration parsing, values, and expectations | COR-012–COR-015, TST-011, TST-014 | Pending | -| 22 | Make product configuration truthful and own remote temp files | COR-024, RSK-009, ARC-004 | Pending | -| 23 | Stream WhisperX uploads and make the adapter race-safe | COR-016, EFF-002, TST-001 | Pending | -| 24 | Correct prepare/transcribe transition semantics | COR-017–COR-019, TST-008 | Pending | -| 25 | Enforce output-path authority and shared singleton resolution | ARC-006, DUP-006 | Pending | -| 26 | Centralize typed extraction-bundle evidence | DUP-007 | Pending | -| 27 | Bind extraction reuse to direct transcript identity | COR-020, TST-009 | Pending | -| 28 | Establish one effective artifact set and catalog bootstrap | COR-022, ARC-007, DUP-008 | Pending | -| 29 | Make analyze resolution typed, optional, actionable, and deterministic | COR-021, COR-023, RSK-015, SIM-003, TST-010 | Pending | -| 30 | Remove misleading contracts and align Audita ownership | ARC-001, ARC-005, SIM-004, COM-003, COM-006 | Pending | -| 31 | Enforce CI validation and streamline the assembled test suite | TST-012, TST-015 | Pending | -| 32 | Reconcile lifecycle/analyze documentation and close the remediation | COM-002, COM-005 | Pending | +| 21 | Tighten configuration parsing, values, and expectations | COR-012–COR-015, TST-011, TST-014 | Completed | +| 22 | Make product configuration truthful and own remote temp files | COR-024, RSK-009, ARC-004 | Completed | +| 23 | Stream WhisperX uploads and make the adapter race-safe | COR-016, EFF-002, TST-001 | Completed | +| 24 | Correct prepare/transcribe transition semantics | COR-017–COR-019, TST-008 | Completed | +| 25 | Enforce output-path authority and shared singleton resolution | ARC-006, DUP-006 | Completed | +| 26 | Centralize typed extraction-bundle evidence | DUP-007 | Completed | +| 27 | Bind extraction reuse to direct transcript identity | COR-020, TST-009 | Completed | +| 28 | Establish one effective artifact set and catalog bootstrap | COR-022, ARC-007, DUP-008 | Completed | +| 29 | Make analyze resolution typed, optional, actionable, and deterministic | COR-021, COR-023, RSK-015, SIM-003, TST-010 | Completed | +| 30 | Remove misleading contracts and align Audita ownership | ARC-001, ARC-005, SIM-004, COM-003, COM-006 | Completed | +| 31 | Enforce CI validation and streamline the assembled test suite | TST-012, TST-015 | Completed | +| 32 | Reconcile lifecycle/analyze documentation and close the remediation | COM-002, COM-005 | Completed | ## Governing decisions @@ -1082,6 +1082,8 @@ documentation/example checks, verify clean generated/example state, inspect the final diff and repository status, and mark this stage complete only when no required remediation remains. +**Status:** Completed. + ## Finding traceability inventory This inventory assigns exactly one primary implementation stage to each confirmed diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 502bc9e..3806e66 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -436,7 +436,7 @@ Diagnostics: ```bash ls -la /path/to/secrets_dir -env | grep -E 'OBJECT_STORAGE|AWS|AUDITA|SCRIPTORIUM' +env | sed 's/=.*//' | grep -E 'OBJECT_STORAGE|AWS|AUDITA|SCRIPTORIUM' ``` Safe fix: diff --git a/internal/doccheck/doccheck_test.go b/internal/doccheck/doccheck_test.go index 3fe7131..1de5c6c 100644 --- a/internal/doccheck/doccheck_test.go +++ b/internal/doccheck/doccheck_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "regexp" + "strconv" "strings" "testing" @@ -65,6 +66,26 @@ func TestReleaseWorkflowRequiresValidation(t *testing.T) { } } +func TestRoadmapTraceabilityOwnersAreComplete(t *testing.T) { + root := repositoryRoot(t) + data, err := os.ReadFile(filepath.Join(root, "docs", "roadmap", "implementation.md")) + if err != nil { + t.Fatalf("read implementation roadmap: %v", err) + } + + statuses := roadmapSummaryStatuses(t, string(data)) + checked := 0 + for _, owner := range roadmapTraceabilityOwners(t, string(data)) { + checked++ + if statuses[owner] != "Completed" { + t.Errorf("traceability owner %d has status %q, want Completed", owner, statuses[owner]) + } + } + if checked == 0 { + t.Fatal("roadmap traceability inventory has no owners") + } +} + func repositoryRoot(t *testing.T) string { t.Helper() root, err := filepath.Abs(filepath.Join("..", "..")) @@ -124,6 +145,53 @@ func relativeToRoot(root, path string) string { return relative } +func roadmapSummaryStatuses(t *testing.T, document string) map[int]string { + t.Helper() + statuses := map[int]string{} + for _, line := range strings.Split(document, "\n") { + fields := strings.Split(line, "|") + if len(fields) != 6 { + continue + } + owner, err := strconv.Atoi(strings.TrimSpace(fields[1])) + if err != nil { + continue + } + statuses[owner] = strings.TrimSpace(fields[4]) + } + if len(statuses) == 0 { + t.Fatal("roadmap summary has no status entries") + } + return statuses +} + +func roadmapTraceabilityOwners(t *testing.T, document string) []int { + t.Helper() + const inventoryHeading = "## Finding traceability inventory" + const nextHeading = "## Open Questions" + start := strings.Index(document, inventoryHeading) + if start < 0 { + t.Fatal("roadmap traceability inventory is missing") + } + inventory := document[start+len(inventoryHeading):] + if end := strings.Index(inventory, nextHeading); end >= 0 { + inventory = inventory[:end] + } + + owners := []int{} + for _, line := range strings.Split(inventory, "\n") { + fields := strings.Split(line, "|") + if len(fields) != 4 { + continue + } + owner, err := strconv.Atoi(strings.TrimSpace(fields[2])) + if err == nil { + owners = append(owners, owner) + } + } + return owners +} + type woodpeckerWorkflow struct { Steps map[string]woodpeckerStep `yaml:"steps"` }