Execute incremental analysis artifact plans

This commit is contained in:
2026-08-29 19:43:28 +00:00
parent 6abdd67bb5
commit 99f4f9a0db
13 changed files with 613 additions and 211 deletions

View File

@@ -291,6 +291,41 @@ func (c *ArtifactCatalog) MarkAvailableGenerated(sourceID, path string) error {
return c.markAvailable(sourceID, path, ArtifactProvenanceGeneratedCurrentAnalyzeRun)
}
// MarkAvailableGeneratedEvidence marks one source as available from the
// current analyze invocation and retains the semantic output identity needed
// by later scheduled dependents.
func (c *ArtifactCatalog) MarkAvailableGeneratedEvidence(
sourceID, path, producerRunID, checksum string,
size int64,
contract *artifactmodel.ContractMetadata,
) error {
producerRunID = strings.TrimSpace(producerRunID)
checksum = strings.TrimSpace(checksum)
if err := ValidateRunIdentity(producerRunID); err != nil {
return fmt.Errorf("generated artifact producer run id: %w", err)
}
if err := validateSHA256(checksum); err != nil {
return fmt.Errorf("generated artifact checksum: %w", err)
}
if size <= 0 {
return fmt.Errorf("generated artifact size must be positive")
}
if contract == nil || strings.TrimSpace(contract.MediaType) == "" ||
strings.TrimSpace(contract.SchemaID) == "" || strings.TrimSpace(contract.SchemaVersion) == "" {
return fmt.Errorf("generated artifact contract is incomplete")
}
if err := c.markAvailable(sourceID, path, ArtifactProvenanceGeneratedCurrentAnalyzeRun); err != nil {
return err
}
entry := c.entries[strings.TrimSpace(sourceID)]
entry.ProducerRunID = producerRunID
entry.Checksum = checksum
entry.Size = size
entry.Contract = cloneArtifactContract(contract)
c.entries[entry.SourceID] = entry
return nil
}
func (c *ArtifactCatalog) markAvailableFromExtractManifest(
sourceID, path, producerRunID, checksum string,
size int64,

View File

@@ -1,6 +1,11 @@
package artifacts
import "testing"
import (
"strings"
"testing"
"gitea.maximumdirect.net/eric/narratio/internal/artifactmodel"
)
func TestArtifactCatalogRegisterBuiltInsAndLookup(t *testing.T) {
catalog := NewArtifactCatalog()
@@ -179,6 +184,30 @@ func TestArtifactCatalogMarkAvailableGenerated(t *testing.T) {
}
}
func TestArtifactCatalogMarkAvailableGeneratedEvidence(t *testing.T) {
catalog := NewArtifactCatalog()
if err := catalog.RegisterConfiguredArtifacts(map[string]ConfiguredArtifactDefinition{
"session_recap": {Enabled: true, OutputPath: "artifacts/session_recap.md"},
}); err != nil {
t.Fatal(err)
}
sourceID, _ := catalog.SourceIDForConfiguredKey("session_recap")
contract := &artifactmodel.ContractMetadata{
MediaType: "text/markdown", SchemaID: "narratio.session_recap", SchemaVersion: "1",
}
checksum := strings.Repeat("a", 64)
if err := catalog.MarkAvailableGeneratedEvidence(
sourceID, "/tmp/session_recap.md", "run-1", checksum, 42, contract,
); err != nil {
t.Fatal(err)
}
entry, _ := catalog.Lookup(sourceID)
if !entry.Available || entry.ProducerRunID != "run-1" || entry.Checksum != checksum || entry.Size != 42 ||
entry.Contract == nil || *entry.Contract != *contract {
t.Fatalf("generated evidence entry = %#v", entry)
}
}
func TestArtifactCatalogLookupPlannedButUnavailable(t *testing.T) {
catalog := NewArtifactCatalog()
if err := catalog.RegisterConfiguredArtifacts(