Remove legacy manifest provenance decoding
All checks were successful
ci/woodpecker/push/verify Pipeline was successful
All checks were successful
ci/woodpecker/push/verify Pipeline was successful
This commit is contained in:
@@ -23,11 +23,11 @@ portable opaque segments. Unsafe legacy identities are rejected with migration
|
||||
guidance rather than being normalized into a different workspace or remote
|
||||
namespace.
|
||||
|
||||
Decoding is strict at typed execution-state fields. Unknown informational fields
|
||||
inside `effective_config` are ignored so older selection labels can be read;
|
||||
unknown fields elsewhere are rejected. The schema version remains
|
||||
`narratio.session-manifest.v1` and there is no compatibility reader that
|
||||
silently drops retired execution state. Cleanup progress uses
|
||||
Decoding rejects unknown typed fields, including informational fields inside
|
||||
`effective_config` and its nested selection. The schema version remains
|
||||
`narratio.session-manifest.v1`; there is no compatibility reader that silently
|
||||
drops retired fields. See [overlay migration](../operations.md#migrating-manifest-overlay-provenance)
|
||||
for deliberate migration of retired selection provenance. Cleanup progress uses
|
||||
only the cleanup entry in `stages`.
|
||||
|
||||
Every persisted session manifest has a non-nil `stages` map. Each entry is
|
||||
|
||||
@@ -410,6 +410,30 @@ execute. Deleting Narratio's local reference snapshots does not invalidate a
|
||||
complete durable extraction; missing snapshots are reconstructed only when a
|
||||
later extraction actually runs.
|
||||
|
||||
## Migrating Manifest Overlay Provenance
|
||||
|
||||
The pipeline-selection rename is a clean cutover. Manifests containing
|
||||
`effective_config.selected_profile` are rejected by strict decoding; Narratio
|
||||
does not silently discard or translate that retired field.
|
||||
|
||||
Before using an affected local session with the new version:
|
||||
|
||||
1. Stop Narratio activity for the session and back up its manifest.
|
||||
2. Rename only `effective_config.selected_profile` to `selected_overlay`, keeping
|
||||
its `name` and `source`, or remove the retired informational member. If a
|
||||
current `selected_overlay` member already exists, retain it and remove the
|
||||
retired member rather than creating duplicate keys.
|
||||
3. Preserve the schema version, digest, stage records, checkpoint evidence,
|
||||
output references, and other session state. Retry the intended command.
|
||||
|
||||
This metadata is informational, not resume authority. Do not delete session
|
||||
progress or force all stages merely to perform this migration. Other unknown
|
||||
fields still require investigation rather than blanket removal.
|
||||
|
||||
Do not edit immutable remote committed snapshots. Restoring an older snapshot
|
||||
with retired provenance requires a compatible previous Narratio version, followed
|
||||
by migration of the restored local manifest before using the new version.
|
||||
|
||||
## Migrating Audita and Provider Credentials
|
||||
|
||||
This is a breaking clean cutover to Audita v2. Narratio does not translate an
|
||||
|
||||
@@ -93,8 +93,11 @@ newly written selection provenance use overlay terminology as well.
|
||||
|
||||
Maintain existing value-based digest and stage-reuse semantics; renaming
|
||||
informational selection provenance is not a reason to invalidate completed
|
||||
work or rewrite historical manifests. Update maintained examples and operator
|
||||
migration guidance for the directory and flag changes.
|
||||
work or automatically rewrite historical manifests. Strict manifest decoding
|
||||
rejects retired provenance fields; operators must deliberately migrate that
|
||||
informational member on a backed-up manifest, preserving execution/checkpoint
|
||||
state. Update maintained examples and operator migration guidance for the
|
||||
directory, flag, and provenance changes.
|
||||
|
||||
This rename does not apply to downstream model profiles, Scriptorium
|
||||
`profile_id`, Audita's proposal/validation profiles, or Notarius's
|
||||
|
||||
@@ -46,9 +46,11 @@ as base selection; do not add a persistent default selector or new precedence.
|
||||
|
||||
Rename newly written informational provenance to overlay terminology, including
|
||||
`selected_overlay` in manifest configuration provenance. Do not add a dual-field
|
||||
reader, rewrite historical manifests, or introduce a manifest-version rejection
|
||||
solely for this informational rename. Existing generic decoding behavior applies
|
||||
to old optional provenance; it does not become resume authority. Preserve
|
||||
reader, automatically rewrite historical manifests, or introduce a manifest-version
|
||||
rejection solely for this informational rename. Existing strict typed decoding
|
||||
rejects retired provenance fields. Document backed-up operator migration of
|
||||
that informational member without changing execution/checkpoint state; it does
|
||||
not become resume authority. Preserve
|
||||
semantic fingerprints and effective-value digest rules when values are unchanged.
|
||||
|
||||
Only Narratio pipeline configuration selection is renamed. Keep model/profile
|
||||
@@ -199,8 +201,9 @@ config commands in `internal/app/`; configuration provenance in
|
||||
directory is not a discovery fallback. Do not freeze incidental error wording.
|
||||
5. Verify unchanged effective values retain digest and stage-reuse behavior;
|
||||
only diagnostic source labels/paths and selected provenance terminology change.
|
||||
Test loading representative existing manifests without inventing a new
|
||||
invalidation or rejection gate for old optional selection metadata.
|
||||
Test current provenance round trips and strict rejection of unknown/retired
|
||||
provenance fields. Document deliberate operator migration; do not add a
|
||||
compatibility decoder, semantic invalidation rule, or schema-version gate.
|
||||
6. Run focused and full tests before proceeding so failures from the dependency
|
||||
and terminology change are separated from adapter migrations. No Audita or
|
||||
Notarius credential/CLI behavior changes in this stage.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Audita v2 and ConfigKit Migration Review Remediation
|
||||
|
||||
Status: Pending.
|
||||
Status: Complete.
|
||||
|
||||
Reviewed `83eaa96` through `fae18bf` against the approved clean-cutover decisions,
|
||||
[feature roadmap](audita.md), and [implementation plan](implementation.md).
|
||||
@@ -46,7 +46,14 @@ Required remediation:
|
||||
|
||||
## 2. Remove the unapproved manifest compatibility decoder
|
||||
|
||||
Priority: P2. Status: Pending.
|
||||
Priority: P2. Status: Complete.
|
||||
|
||||
Removed the permissive custom decoder; ordinary strict typed decoding now
|
||||
applies to provenance as well. Replaced historical-acceptance coverage with
|
||||
retired/unknown-field rejection tests, all of which failed before removal.
|
||||
Current provenance round-trip coverage remains intact. Corrected the roadmap,
|
||||
plan, internal contract, and operator guidance for narrow backed-up migration
|
||||
without discarding execution/checkpoint state or changing resume authority.
|
||||
|
||||
Location: `internal/manifest/manifest.go:79-89`,
|
||||
`internal/manifest/store_test.go:78`, and `docs/internal/manifest.md`'s decoding
|
||||
@@ -92,6 +99,8 @@ reader. Do not treat that exception as already granted.
|
||||
|
||||
## Review verification
|
||||
|
||||
The following records the original review, before remediation.
|
||||
|
||||
- Existing `go test ./...` passed.
|
||||
- Race tests passed for subprocess, Audita, Notarius, config, stage, app, and
|
||||
manifest packages after removing the temporary reproduction.
|
||||
@@ -105,6 +114,13 @@ shared named credential forwarding/redaction, a v2-only Audita subprocess
|
||||
adapter, ordinary reports as diagnostics, and versioned ordered-module polish
|
||||
evidence. No live model/provider runs were performed during this review.
|
||||
|
||||
## Migration remediation verification
|
||||
|
||||
Completed on 2026-09-25. Both new regressions failed before their respective
|
||||
fixes. After remediation, `go test ./...`, `go test -race ./...`,
|
||||
`go vet ./...`, `go build ./...`, documentation checks, maintained configuration
|
||||
example checks, and `git diff --check` passed. No live provider runs were needed.
|
||||
|
||||
## Historical completed transcription review
|
||||
|
||||
Status: Complete.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -76,18 +75,6 @@ type EffectiveConfigProvenance struct {
|
||||
EffectiveConfigDigest string `json:"effective_config_digest,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON accepts unknown informational provenance from older manifests.
|
||||
// The enclosing manifest and its execution state remain strictly decoded.
|
||||
func (p *EffectiveConfigProvenance) UnmarshalJSON(data []byte) error {
|
||||
type provenance EffectiveConfigProvenance
|
||||
var decoded provenance
|
||||
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
*p = EffectiveConfigProvenance(decoded)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectedOverlayProvenance identifies an explicitly or default-selected
|
||||
// pipeline overlay without recording overlay content.
|
||||
type SelectedOverlayProvenance struct {
|
||||
|
||||
@@ -75,18 +75,19 @@ func TestLocalStoreCreateSaveLoadRoundTrip(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalStoreLoadsManifestWithHistoricalSelectionProvenance(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "manifest.json")
|
||||
data := `{"schema_version":"narratio.session-manifest.v1","session_id":"2026-05-03","created_at":"2026-05-03T10:00:00Z","updated_at":"2026-05-03T10:00:00Z","effective_config":{"selected_profile":{"name":"testing","source":"explicit"},"effective_config_digest":"001122"},"stages":{}}`
|
||||
if err := os.WriteFile(path, []byte(data), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loaded, err := (&LocalStore{}).Load(context.Background(), path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if loaded.EffectiveConfig == nil || loaded.EffectiveConfig.EffectiveConfigDigest != "001122" || loaded.EffectiveConfig.SelectedOverlay != nil {
|
||||
t.Fatalf("historical informational provenance = %#v", loaded.EffectiveConfig)
|
||||
func TestLocalStoreRejectsUnknownProvenanceFields(t *testing.T) {
|
||||
for _, tc := range []struct{ name, provenance, field string }{
|
||||
{"retired selection", `{"selected_profile":{"name":"testing","source":"explicit"}}`, "selected_profile"},
|
||||
{"unknown provenance", `{"unexpected":true}`, "unexpected"},
|
||||
{"unknown selection field", `{"selected_overlay":{"name":"testing","source":"explicit","unexpected":true}}`, "unexpected"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data := `{"schema_version":"narratio.session-manifest.v1","session_id":"2026-05-03","created_at":"2026-05-03T10:00:00Z","updated_at":"2026-05-03T10:00:00Z","effective_config":` + tc.provenance + `,"stages":{}}`
|
||||
_, err := (&LocalStore{}).LoadReader(context.Background(), strings.NewReader(data))
|
||||
if err == nil || !strings.Contains(err.Error(), tc.field) {
|
||||
t.Fatalf("expected rejection identifying %q, got %v", tc.field, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user