feat(replay): record runtime identity; label compatibility; analyse first divergence

Snapshots, replays and experiments now record the runtime they ran under:
build (module version, VCS commit, modified tree, commit time, Go version,
platform), schema version, a digest of the non-secret configuration that
ignores secret and credential changes, personality version, policy digest,
model routing including per-mind overrides, prompt versions, deterministic
subsystem versions and timezone. A replay compares its identity with the
snapshot's and is an exact-candidate, a different-build (differences
listed) or incompatible (schema differs; the replay stops before running).
The first non-exact step is analysed into events only in the recording,
events only in the replay, and the components they belong to, labelled as
inferred; live model calls are named as their own source of difference.
Migration 0022 is additive; unrecorded identities are reported as such.
This commit is contained in:
Andy Dixon
2026-08-20 21:11:27 +01:00
parent 37b9f0e2f5
commit 522de3b026
18 changed files with 648 additions and 51 deletions
+41 -1
View File
@@ -1,5 +1,45 @@
// Package version exposes build information injected at link time.
// Package version exposes build information injected at link time and
// recorded by the Go toolchain, so replays and experiments can say which
// code produced them.
package version
import (
"runtime"
"runtime/debug"
)
// Version is set via -ldflags "-X github.com/andydixon/noema/internal/version.Version=...".
var Version = "dev"
// Build describes the running binary.
type Build struct {
Version string `json:"version"`
Commit string `json:"commit,omitempty"` // VCS revision when built from a checkout
Modified bool `json:"modified,omitempty"` // working tree was dirty at build time
BuildTime string `json:"build_time,omitempty"` // VCS commit time (reproducible; not the wall clock of the build)
GoVersion string `json:"go_version"`
OS string `json:"os"`
Arch string `json:"arch"`
}
// Info reads the build record. Missing VCS data (a build from a source
// archive rather than a checkout) is left blank, never invented.
func Info() Build {
b := Build{Version: Version, GoVersion: runtime.Version(), OS: runtime.GOOS, Arch: runtime.GOARCH}
if bi, ok := debug.ReadBuildInfo(); ok {
if b.Version == "dev" && bi.Main.Version != "" && bi.Main.Version != "(devel)" {
b.Version = bi.Main.Version
}
for _, s := range bi.Settings {
switch s.Key {
case "vcs.revision":
b.Commit = s.Value
case "vcs.modified":
b.Modified = s.Value == "true"
case "vcs.time":
b.BuildTime = s.Value
}
}
}
return b
}