Exclude external paths from analysis fingerprints
This commit is contained in:
@@ -67,11 +67,10 @@ Supported source families:
|
||||
JSON payload and no map serialization. Configured artifacts are fingerprinted
|
||||
in deterministic dependency order.
|
||||
- fingerprints the normalized artifact key, prompt and profile identifiers,
|
||||
normalized Scriptorium executable and config logical identities, effective
|
||||
render-debug behavior, session-relative output identity, sorted dependency
|
||||
keys, ordered input declarations and semantic identities, validated current
|
||||
dependency-output identities, and sorted effective Scriptorium variables
|
||||
(including Narratio's sticky session variable).
|
||||
effective render-debug behavior, session-relative output identity, sorted
|
||||
dependency keys, ordered input declarations and semantic identities,
|
||||
validated current dependency-output identities, and sorted effective
|
||||
Scriptorium variables (including Narratio's sticky session variable).
|
||||
- provides read-only reconciliation that classifies each configured record as
|
||||
current, stale, missing, failed, legacy, or otherwise non-resumable, and
|
||||
separately identifies manifest records removed from current configuration.
|
||||
@@ -155,7 +154,7 @@ Supported source families:
|
||||
- input-identity resolution is read-only: it does not invoke adapters,
|
||||
materialize outputs, update status, or create run records.
|
||||
- fingerprints exclude timeouts, retries, timestamps, producer and Narratio run
|
||||
IDs, absolute executable/config/workspace roots, diagnostic locations, and
|
||||
IDs, executable and config paths, workspace roots, diagnostic locations, and
|
||||
executable or private transitive configuration contents. A change that is
|
||||
visible only inside Scriptorium—such as a file privately loaded by its config
|
||||
path—requires an explicit forced regeneration.
|
||||
|
||||
@@ -49,18 +49,12 @@ type analyzeDependencyOutputIdentity struct {
|
||||
// as SHA-256 input. It contains slices and fixed-field structs, never maps.
|
||||
type analyzeFingerprintPayload struct {
|
||||
Version int `json:"version"`
|
||||
Scriptorium analyzeFingerprintScriptorium `json:"scriptorium"`
|
||||
Artifact analyzeFingerprintArtifact `json:"artifact"`
|
||||
Inputs []analyzeFingerprintInput `json:"inputs"`
|
||||
DependencyOutputs []analyzeFingerprintDependencyOutput `json:"dependency_outputs"`
|
||||
Variables []analyzeFingerprintVariable `json:"variables"`
|
||||
}
|
||||
|
||||
type analyzeFingerprintScriptorium struct {
|
||||
ExecutableIdentity string `json:"executable_identity"`
|
||||
ConfigIdentity string `json:"config_identity"`
|
||||
}
|
||||
|
||||
type analyzeFingerprintArtifact struct {
|
||||
Key string `json:"key"`
|
||||
PromptID string `json:"prompt_id"`
|
||||
@@ -169,10 +163,6 @@ func computeAnalyzeArtifactFingerprint(
|
||||
}
|
||||
payload := analyzeFingerprintPayload{
|
||||
Version: manifest.AnalyzeFingerprintContractVersion,
|
||||
Scriptorium: analyzeFingerprintScriptorium{
|
||||
ExecutableIdentity: normalizedAnalyzeExternalPathIdentity(scriptoriumCfg.Binary),
|
||||
ConfigIdentity: normalizedAnalyzeExternalPathIdentity(scriptoriumCfg.ConfigPath),
|
||||
},
|
||||
Artifact: analyzeFingerprintArtifact{
|
||||
Key: key, PromptID: artifactCfg.PromptID, ProfileID: artifactCfg.ProfileID,
|
||||
EffectiveRenderDebug: resolveRenderDebugEnabled(scriptoriumCfg.RenderDebug, artifactCfg.RenderDebug),
|
||||
@@ -260,18 +250,6 @@ func normalizedAnalyzeDependencyKeys(values []string) []string {
|
||||
return result
|
||||
}
|
||||
|
||||
func normalizedAnalyzeExternalPathIdentity(value string) string {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return ""
|
||||
}
|
||||
cleaned := filepath.Clean(trimmed)
|
||||
if filepath.IsAbs(cleaned) {
|
||||
return filepath.Base(cleaned)
|
||||
}
|
||||
return filepath.ToSlash(cleaned)
|
||||
}
|
||||
|
||||
func normalizedAnalyzeOutputIdentity(value string) (string, error) {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
|
||||
@@ -18,8 +18,6 @@ func TestAnalyzeFingerprintCanonicalPayloadSensitivity(t *testing.T) {
|
||||
mutate func(*analyzeFingerprintPayload)
|
||||
}{
|
||||
{name: "version", mutate: func(p *analyzeFingerprintPayload) { p.Version++ }},
|
||||
{name: "scriptorium executable", mutate: func(p *analyzeFingerprintPayload) { p.Scriptorium.ExecutableIdentity = "other" }},
|
||||
{name: "scriptorium config", mutate: func(p *analyzeFingerprintPayload) { p.Scriptorium.ConfigIdentity = "other.yml" }},
|
||||
{name: "artifact key", mutate: func(p *analyzeFingerprintPayload) { p.Artifact.Key = "other" }},
|
||||
{name: "prompt", mutate: func(p *analyzeFingerprintPayload) { p.Artifact.PromptID = "prompt.changed" }},
|
||||
{name: "profile", mutate: func(p *analyzeFingerprintPayload) { p.Artifact.ProfileID = "profile.changed" }},
|
||||
@@ -87,7 +85,8 @@ func TestComputeAnalyzeFingerprintsIsDeterministicAcrossIncidentalDifferences(t
|
||||
{name: "producer run", options: fingerprintFixtureOptions{producerRunID: "run-b", binary: "/opt/a/scriptorium", configPath: "/etc/a/scriptorium.yml", topTimeout: "1m", artifactTimeout: "2m", updatedAt: time.Unix(100, 0).UTC()}},
|
||||
{name: "timestamp", options: fingerprintFixtureOptions{producerRunID: "run-a", binary: "/opt/a/scriptorium", configPath: "/etc/a/scriptorium.yml", topTimeout: "1m", artifactTimeout: "2m", updatedAt: time.Unix(999, 0).UTC()}},
|
||||
{name: "timeouts", options: fingerprintFixtureOptions{producerRunID: "run-a", binary: "/opt/a/scriptorium", configPath: "/etc/a/scriptorium.yml", topTimeout: "8m", artifactTimeout: "9m", updatedAt: time.Unix(100, 0).UTC()}},
|
||||
{name: "absolute executable and config paths", options: fingerprintFixtureOptions{producerRunID: "run-a", binary: "/srv/b/scriptorium", configPath: "/srv/b/scriptorium.yml", topTimeout: "1m", artifactTimeout: "2m", updatedAt: time.Unix(100, 0).UTC()}},
|
||||
{name: "absolute executable and config paths", options: fingerprintFixtureOptions{producerRunID: "run-a", binary: "/srv/b/scriptorium-v2", configPath: "/srv/b/alternate.yml", topTimeout: "1m", artifactTimeout: "2m", updatedAt: time.Unix(100, 0).UTC()}},
|
||||
{name: "relative executable and config paths", options: fingerprintFixtureOptions{producerRunID: "run-a", binary: "bin/scriptorium-v2", configPath: "config/alternate.yml", topTimeout: "1m", artifactTimeout: "2m", updatedAt: time.Unix(100, 0).UTC()}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -109,8 +108,6 @@ func TestComputeAnalyzeFingerprintsTracksEffectiveConfiguration(t *testing.T) {
|
||||
{name: "render debug", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", renderDebug: true}},
|
||||
{name: "output", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", outputPath: "artifacts/changed.md"}},
|
||||
{name: "effective variable", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", label: "changed"}},
|
||||
{name: "executable identity", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", binary: "/opt/bin/other"}},
|
||||
{name: "config identity", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", configPath: "/etc/scriptorium/other.yml"}},
|
||||
{name: "dependency bytes", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "other\n"}},
|
||||
{name: "optional input appears", options: fingerprintFixtureOptions{producerRunID: "run-a", dependencyBody: "notes\n", includePlayers: true}},
|
||||
}
|
||||
@@ -170,9 +167,6 @@ func analyzeFingerprintPayloadFixture() analyzeFingerprintPayload {
|
||||
}
|
||||
return analyzeFingerprintPayload{
|
||||
Version: manifest.AnalyzeFingerprintContractVersion,
|
||||
Scriptorium: analyzeFingerprintScriptorium{
|
||||
ExecutableIdentity: "scriptorium", ConfigIdentity: "config.yml",
|
||||
},
|
||||
Artifact: analyzeFingerprintArtifact{
|
||||
Key: "session_recap", PromptID: "dnd.session_recap", ProfileID: "local",
|
||||
EffectiveRenderDebug: true, OutputIdentity: "artifacts/session_recap.md",
|
||||
|
||||
Reference in New Issue
Block a user