From a12995567e62e4d94a3416dcc40b00abc708fa35 Mon Sep 17 00:00:00 2001 From: AXIS Contributor Date: Tue, 29 Sep 2026 21:56:16 -0400 Subject: [PATCH 1/3] fix(version): print toolchain vcs commit when ldflags are empty axis version omitted commit and built time unless Make injected ldflags. A binary built with plain go build still carries vcs.revision and vcs.time. ResolvedCommit and ResolvedDate keep an ldflags value first and fall back to those settings. Phase tracking no longer calls v0.12.2 the current release, and the agent worklog is labeled as the 2026-06-04 log. --- cmd/axis/main.go | 8 +++---- docs/README.md | 2 +- docs/agent-worklog.md | 2 +- docs/phase-tracking.md | 2 +- internal/buildinfo/build.go | 38 ++++++++++++++++++++++++++++++++ internal/buildinfo/build_test.go | 37 +++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 internal/buildinfo/build_test.go diff --git a/cmd/axis/main.go b/cmd/axis/main.go index cd9c8faa..60366762 100644 --- a/cmd/axis/main.go +++ b/cmd/axis/main.go @@ -223,11 +223,11 @@ func versionCmd() *cobra.Command { ui.PrintLogo(out, Version) fmt.Fprintln(out) fmt.Fprintf(out, "axis %s\n", Version) - if buildinfo.Commit != "" { - fmt.Fprintf(out, " commit: %s\n", buildinfo.Commit) + if commit := buildinfo.ResolvedCommit(); commit != "" { + fmt.Fprintf(out, " commit: %s\n", commit) } - if buildinfo.Date != "" { - fmt.Fprintf(out, " built: %s\n", buildinfo.Date) + if built := buildinfo.ResolvedDate(); built != "" { + fmt.Fprintf(out, " built: %s\n", built) } goVer := buildinfo.GoVersion if goVer == "" { diff --git a/docs/README.md b/docs/README.md index 3246c553..08135632 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ ## Start Here - [Current State](current-state.md) — current orientation doc for the live repo, command surface, coverage snapshot, and known weak spots -- [Agent Worklog](agent-worklog.md) — active coordination surface, file ownership, and current task tracking +- [Agent Worklog](agent-worklog.md) — historical coordination log and file-ownership notes; not the current queue - [RAM Balancing Research](ram-balancing-research.md) — research-backed design note on how AXIS should model cluster RAM sharing and balancing ## Design Docs diff --git a/docs/agent-worklog.md b/docs/agent-worklog.md index 918438e1..af7cbbc7 100644 --- a/docs/agent-worklog.md +++ b/docs/agent-worklog.md @@ -1,6 +1,6 @@ # AXIS Agent Worklog -This file is the canonical coordination surface for active AXIS work. +Historical coordination log. The reviewed HEAD below is 2026-06-04. Live orientation is `docs/current-state.md`. The task tables are not the current queue. ## Coordination Contract diff --git a/docs/phase-tracking.md b/docs/phase-tracking.md index 2dc21880..201118c6 100644 --- a/docs/phase-tracking.md +++ b/docs/phase-tracking.md @@ -10,4 +10,4 @@ | Phase 6 | **Completed** | Trust-and-foundations work: GPU/storage/network enrichment, stable identity, and failure-memory placement signals | | Phase 7 | **Completed** | Runtime hardening: streamed `/run`, reservation durability, forwarded provenance, and discovery freshness | -Current release: **v0.12.2** +Phase completion is not the release record. The repo version constant is `internal/buildinfo/version.go`, repeated in the generated fact in `docs/current-state.md`. Published releases are on GitHub Releases. diff --git a/internal/buildinfo/build.go b/internal/buildinfo/build.go index 3a012194..37881028 100644 --- a/internal/buildinfo/build.go +++ b/internal/buildinfo/build.go @@ -1,13 +1,51 @@ package buildinfo +import "runtime/debug" + // Commit, Date, and GoVersion are set at build time via -ldflags. // Example: // // go build -ldflags "-X github.com/toasterbook88/axis/internal/buildinfo.Commit=abc1234 // -X github.com/toasterbook88/axis/internal/buildinfo.Date=2026-04-01T12:00:00Z // -X github.com/toasterbook88/axis/internal/buildinfo.GoVersion=go1.26.2" +// +// When those ldflags are empty, ResolvedCommit and ResolvedDate fall back to +// the vcs.revision and vcs.time settings the Go toolchain stamps into the binary. var ( Commit string Date string GoVersion string ) + +// ResolvedCommit returns the ldflags commit, or the toolchain vcs.revision. +func ResolvedCommit() string { + if Commit != "" { + return Commit + } + return setting("vcs.revision") +} + +// ResolvedDate returns the ldflags build time, or the toolchain vcs.time. +func ResolvedDate() string { + if Date != "" { + return Date + } + return setting("vcs.time") +} + +func setting(key string) string { + info, ok := debug.ReadBuildInfo() + if !ok || info == nil { + return "" + } + return settingFrom(info.Settings, key) +} + +func settingFrom(settings []debug.BuildSetting, key string) string { + for _, s := range settings { + if s.Key == key { + return s.Value + } + } + return "" +} diff --git a/internal/buildinfo/build_test.go b/internal/buildinfo/build_test.go new file mode 100644 index 00000000..ea65cc38 --- /dev/null +++ b/internal/buildinfo/build_test.go @@ -0,0 +1,37 @@ +package buildinfo + +import ( + "runtime/debug" + "testing" +) + +func TestResolvedCommitPrefersLdflags(t *testing.T) { + old := Commit + t.Cleanup(func() { Commit = old }) + Commit = "abc1234" + if got := ResolvedCommit(); got != "abc1234" { + t.Fatalf("ResolvedCommit() = %q, want ldflags value", got) + } +} + +func TestResolvedDatePrefersLdflags(t *testing.T) { + old := Date + t.Cleanup(func() { Date = old }) + Date = "2026-04-01T12:00:00Z" + if got := ResolvedDate(); got != "2026-04-01T12:00:00Z" { + t.Fatalf("ResolvedDate() = %q, want ldflags value", got) + } +} + +func TestSettingFrom(t *testing.T) { + settings := []debug.BuildSetting{{Key: "vcs.revision", Value: "deadbeef"}} + if got := settingFrom(settings, "vcs.revision"); got != "deadbeef" { + t.Fatalf("settingFrom() = %q", got) + } + if got := settingFrom(settings, "vcs.time"); got != "" { + t.Fatalf("missing key = %q, want empty", got) + } + if got := settingFrom(nil, "vcs.revision"); got != "" { + t.Fatalf("nil settings = %q, want empty", got) + } +} From 97c1c1da5cb66e79f53d13ebc1abe0afaafbe987 Mon Sep 17 00:00:00 2001 From: AXIS Contributor Date: Sun, 4 Oct 2026 16:30:26 -0400 Subject: [PATCH 2/3] fix(version): mark a dirty revision and keep the build clock A toolchain revision with vcs.modified prints a -dirty suffix. ResolvedDate returns only the ldflag build time, never vcs.time. --- internal/buildinfo/build.go | 40 ++++++++++++++++++++------------ internal/buildinfo/build_test.go | 27 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/internal/buildinfo/build.go b/internal/buildinfo/build.go index 37881028..ccaae87d 100644 --- a/internal/buildinfo/build.go +++ b/internal/buildinfo/build.go @@ -9,36 +9,46 @@ import "runtime/debug" // -X github.com/toasterbook88/axis/internal/buildinfo.Date=2026-04-01T12:00:00Z // -X github.com/toasterbook88/axis/internal/buildinfo.GoVersion=go1.26.2" // -// When those ldflags are empty, ResolvedCommit and ResolvedDate fall back to -// the vcs.revision and vcs.time settings the Go toolchain stamps into the binary. +// When the commit ldflag is empty, ResolvedCommit uses vcs.revision and +// appends -dirty when vcs.modified is true. ResolvedDate is only the ldflag +// build time. vcs.time is the revision time and is not a build time. var ( Commit string Date string GoVersion string ) -// ResolvedCommit returns the ldflags commit, or the toolchain vcs.revision. +// ResolvedCommit returns the ldflags commit, or the toolchain revision. +// A dirty toolchain revision is marked so it is not printed as a clean commit. func ResolvedCommit() string { if Commit != "" { return Commit } - return setting("vcs.revision") -} - -// ResolvedDate returns the ldflags build time, or the toolchain vcs.time. -func ResolvedDate() string { - if Date != "" { - return Date + info, ok := debug.ReadBuildInfo() + if !ok || info == nil { + return "" } - return setting("vcs.time") + return commitFromSettings(info.Settings) } -func setting(key string) string { - info, ok := debug.ReadBuildInfo() - if !ok || info == nil { +func commitFromSettings(settings []debug.BuildSetting) string { + rev := settingFrom(settings, "vcs.revision") + if rev == "" { return "" } - return settingFrom(info.Settings, key) + if settingFrom(settings, "vcs.modified") == "true" { + return rev + "-dirty" + } + return rev +} + +// ResolvedDate returns the ldflag build time. It does not use vcs.time. +func ResolvedDate() string { + return dateFromSettings(Date, nil) +} + +func dateFromSettings(date string, _ []debug.BuildSetting) string { + return date } func settingFrom(settings []debug.BuildSetting, key string) string { diff --git a/internal/buildinfo/build_test.go b/internal/buildinfo/build_test.go index ea65cc38..77eca684 100644 --- a/internal/buildinfo/build_test.go +++ b/internal/buildinfo/build_test.go @@ -23,6 +23,33 @@ func TestResolvedDatePrefersLdflags(t *testing.T) { } } +func TestCommitFromSettingsMarksADirtyTree(t *testing.T) { + settings := []debug.BuildSetting{ + {Key: "vcs.revision", Value: "abc1234"}, + {Key: "vcs.modified", Value: "true"}, + } + if got := commitFromSettings(settings); got != "abc1234-dirty" { + t.Fatalf("commitFromSettings() = %q, want dirty revision", got) + } + settings[1].Value = "false" + if got := commitFromSettings(settings); got != "abc1234" { + t.Fatalf("commitFromSettings() = %q, want clean revision", got) + } + if got := commitFromSettings([]debug.BuildSetting{{Key: "vcs.modified", Value: "true"}}); got != "" { + t.Fatalf("commitFromSettings() = %q, want empty without a revision", got) + } +} + +func TestDateFromSettingsIgnoresRevisionTime(t *testing.T) { + settings := []debug.BuildSetting{{Key: "vcs.time", Value: "2020-01-01T00:00:00Z"}} + if got := dateFromSettings("", settings); got != "" { + t.Fatalf("dateFromSettings() = %q, want empty build time", got) + } + if got := dateFromSettings("2026-04-01T12:00:00Z", settings); got != "2026-04-01T12:00:00Z" { + t.Fatalf("dateFromSettings() = %q, want ldflag build time", got) + } +} + func TestSettingFrom(t *testing.T) { settings := []debug.BuildSetting{{Key: "vcs.revision", Value: "deadbeef"}} if got := settingFrom(settings, "vcs.revision"); got != "deadbeef" { From 4095fdeaaec398cf9f3da1c6d562671bb2bef356 Mon Sep 17 00:00:00 2001 From: AXIS Contributor Date: Sun, 4 Oct 2026 17:45:56 -0400 Subject: [PATCH 3/3] docs(version): state the commit line and test the live resolver The runbook now matches ResolvedCommit: the ldflag wins, an empty ldflag prints vcs.revision with -dirty when the tree is modified, and built: stays the ldflag clock. The empty-ldflag tests compare the resolver to the toolchain settings. --- docs/runbooks/a2a-task-delegation.md | 12 ++++++++---- internal/buildinfo/build_test.go | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/docs/runbooks/a2a-task-delegation.md b/docs/runbooks/a2a-task-delegation.md index 4be95cc9..ce59b13b 100644 --- a/docs/runbooks/a2a-task-delegation.md +++ b/docs/runbooks/a2a-task-delegation.md @@ -106,7 +106,11 @@ curl -s -H "Authorization: Bearer $T" --unix-socket "$S" \ http://localhost/a2a/v1/tasks/pending # -> {"tasks":[]} ``` -`axis version` prints `buildinfo.Commit` baked into the binary you just executed -(`cmd/axis/main.go`, `internal/buildinfo`). It does not ask the running daemon who -it is. **`axis update` replaces the binary but does not restart a supervised -daemon** — check the process start time, or the API response, not `axis version`. +`axis version` prints `commit:` from the ldflag `buildinfo.Commit` when that +value is set (`cmd/axis/main.go`, `internal/buildinfo.ResolvedCommit`). A plain +build whose commit ldflag is empty prints `vcs.revision` and appends `-dirty` +when `vcs.modified` is true. `built:` is only the ldflag build time. +`vcs.time` is the revision time and is not a build time. The command does not +ask the running daemon who it is. **`axis update` replaces the binary but does +not restart a supervised daemon** — check the process start time, or the API +response, not `axis version`. diff --git a/internal/buildinfo/build_test.go b/internal/buildinfo/build_test.go index 77eca684..d04306f3 100644 --- a/internal/buildinfo/build_test.go +++ b/internal/buildinfo/build_test.go @@ -23,6 +23,29 @@ func TestResolvedDatePrefersLdflags(t *testing.T) { } } +func TestResolvedCommitEmptyLdflagMatchesToolchainSettings(t *testing.T) { + old := Commit + t.Cleanup(func() { Commit = old }) + Commit = "" + info, ok := debug.ReadBuildInfo() + if !ok || info == nil { + t.Fatal("ReadBuildInfo unavailable") + } + want := commitFromSettings(info.Settings) + if got := ResolvedCommit(); got != want { + t.Fatalf("ResolvedCommit() = %q, want toolchain settings %q", got, want) + } +} + +func TestResolvedDateEmptyLdflagStaysEmpty(t *testing.T) { + old := Date + t.Cleanup(func() { Date = old }) + Date = "" + if got := ResolvedDate(); got != "" { + t.Fatalf("ResolvedDate() = %q, want empty ldflag", got) + } +} + func TestCommitFromSettingsMarksADirtyTree(t *testing.T) { settings := []debug.BuildSetting{ {Key: "vcs.revision", Value: "abc1234"},