From 8ab7d550a7d5b260b8fa41b4f8bf1230df812988 Mon Sep 17 00:00:00 2001 From: review Date: Fri, 6 Nov 2026 01:10:51 +0700 Subject: [PATCH] ci: commit the gitignored migration fixtures and stop the config cache leaking across homes `go test ./...` failed on every checkout of main, and only on CI, because of two independent bugs. 1. The migration fixtures were never committed. `.gitignore` had an unanchored `AGENTS.md` rule under "local agent/editor tooling", which also matched the fake agent homes under `internal/migrate/testdata` (nanobot, openclaw, openhuman, zeroclaw, nanoclaw all ship their own AGENTS.md, and OpenHuman's memory.db fell under `*.db`). The files existed only on the machine that wrote the goldens, so every golden test that rendered them failed everywhere else. Anchoring the rule to `/AGENTS.md` and un-ignoring the fixture `.db` restores them, and this commit adds the fixture files themselves. Fixture contents were rewritten to the byte lengths the committed goldens record (113/42/42/80 chars, and the two role prompts), so the only golden lines that move are the `sha=`/`prompt_sha=` fingerprints those bytes feed. No assertion, expectation or status changed: every item is still ready/conflict exactly as before. 2. `config.Load()` served its cached config without checking which home it came from. Tests that set ANTARES_HOME per test got the previous test's config, so `TestDevicePairCLI` read the port from `TestDaemonStateRoundTripAndStaleCleanup`'s config.yaml (1 instead of 18999) and failed depending on test order. The cache now records the home and config path it was loaded from and only serves itself while both still match. This is a real bug outside tests too: anything that changes ANTARES_HOME or ANTARES_PROFILE in-process got stale settings. Co-Authored-By: Claude Code --- .gitignore | 8 +++++++- internal/config/load.go | 12 +++++++++++- internal/migrate/testdata/golden/openclaw_plan.txt | 4 ++-- .../nanobot/home/.nanobot/workspace/AGENTS.md | 5 +++++ internal/migrate/testdata/nanobot/plan.golden | 2 +- .../testdata/nanoclaw/v2/groups/main/CLAUDE.local.md | 1 + .../openclaw/home/.openclaw/work-ws/AGENTS.md | 3 +++ .../openclaw/home/.openclaw/workspace/AGENTS.md | 3 +++ .../home/.openhuman/users/u_123/workspace/AGENTS.md | 3 +++ .../users/u_123/workspace/memory/memory.db | 0 internal/migrate/testdata/openhuman/plan.golden | 2 +- internal/migrate/testdata/zeroclaw/plan_v3.golden | 4 ++-- .../zeroclaw/v3/agents/coder/workspace/AGENTS.md | 4 ++++ .../zeroclaw/v3/agents/default/workspace/AGENTS.md | 5 +++++ 14 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 internal/migrate/testdata/nanobot/home/.nanobot/workspace/AGENTS.md create mode 100644 internal/migrate/testdata/nanoclaw/v2/groups/main/CLAUDE.local.md create mode 100644 internal/migrate/testdata/openclaw/home/.openclaw/work-ws/AGENTS.md create mode 100644 internal/migrate/testdata/openclaw/home/.openclaw/workspace/AGENTS.md create mode 100644 internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/AGENTS.md create mode 100644 internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/memory/memory.db create mode 100644 internal/migrate/testdata/zeroclaw/v3/agents/coder/workspace/AGENTS.md create mode 100644 internal/migrate/testdata/zeroclaw/v3/agents/default/workspace/AGENTS.md diff --git a/.gitignore b/.gitignore index a3bca706..66725dc6 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,9 @@ web/src/sample/ .env.local # Migration fixtures are fake homes of other agents; their .env files hold fake keys. !internal/migrate/testdata/**/.env +# OpenHuman keeps its memory in a SQLite file; the fixture needs it present so +# the planner reports the "memory.db is not imported" warning. +!internal/migrate/testdata/**/memory.db /tuishot # Local agent/editor tooling (not part of the project) @@ -32,7 +35,10 @@ web/src/sample/ .opencode/ .mcp.json opencode.json -AGENTS.md +# Anchored: the migration fixtures are fake homes of other agents and include +# AGENTS.md/CLAUDE.local.md files. An unanchored rule here once kept them out of +# every checkout, so the migrate golden tests failed on CI and nowhere local. +/AGENTS.md .worktrees/ .superpowers/ .codegraph/ diff --git a/internal/config/load.go b/internal/config/load.go index 2084c170..ed0629a6 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -15,6 +15,13 @@ import ( var ( mu sync.RWMutex loaded *Config + // loadedHome and loadedPath record the state directory and config file the + // cached config was read from. Load only serves the cache while both still + // match, so a process (or a test) that moves ANTARES_HOME gets its own + // configuration instead of the previous directory's — the stale port from + // one test's config used to leak into the next. + loadedHome string + loadedPath string // saveMu serialises writes to the config file. Concurrent saves (e.g. a // rapid run of model switches, or a model switch overlapping a raw config // save) would otherwise race on the temp file and the rename, corrupting @@ -25,8 +32,9 @@ var ( // Load reads defaults, merges the profile YAML file, then applies env overrides. // It is safe to call repeatedly; the result is cached until Reload or Save. func Load() (*Config, error) { + home, path := Home(), ConfigFile() mu.RLock() - if loaded != nil { + if loaded != nil && loadedHome == home && loadedPath == path { c := loaded.Clone() mu.RUnlock() return c, nil @@ -61,6 +69,7 @@ func Reload() (*Config, error) { mu.Lock() loaded = cfg.Clone() + loadedHome, loadedPath = Home(), path mu.Unlock() return cfg, nil } @@ -90,6 +99,7 @@ func SaveNormalizedAt(path string, cfg *Config) error { } mu.Lock() loaded = cfg.Clone() + loadedHome, loadedPath = Home(), path mu.Unlock() return nil } diff --git a/internal/migrate/testdata/golden/openclaw_plan.txt b/internal/migrate/testdata/golden/openclaw_plan.txt index cc681380..3c4fb95e 100644 --- a/internal/migrate/testdata/golden/openclaw_plan.txt +++ b/internal/migrate/testdata/golden/openclaw_plan.txt @@ -49,7 +49,7 @@ summary: 9 providers · model · soul · instructions · user profile · 3 memor [agents_md] agents_md:file "AGENTS.md" status=conflict selected=false detail: from AGENTS.md + BOOT.md · 68 chars reason: Antares already has a custom AGENTS.md (replace or append) - text: from=AGENTS.md + BOOT.md sha=8bff4f1541f6 + text: from=AGENTS.md + BOOT.md sha=c43c7bdeeac0 [user_md] user_md:file "USER.md" status=ready selected=true detail: from USER.md · 41 chars @@ -139,4 +139,4 @@ summary: 9 providers · model · soul · instructions · user profile · 3 memor [role] role:work "Work" status=ready selected=true detail: OpenClaw agent work - role: name=work title="Work" model=openai/gpt-5 prompt_sha=db747aabfa12 + role: name=work title="Work" model=openai/gpt-5 prompt_sha=632c27a4a321 diff --git a/internal/migrate/testdata/nanobot/home/.nanobot/workspace/AGENTS.md b/internal/migrate/testdata/nanobot/home/.nanobot/workspace/AGENTS.md new file mode 100644 index 00000000..7131bad6 --- /dev/null +++ b/internal/migrate/testdata/nanobot/home/.nanobot/workspace/AGENTS.md @@ -0,0 +1,5 @@ +# Instructions + +- Reply in the user's language. +- Keep answers short and clear. +- Ask before running any command. diff --git a/internal/migrate/testdata/nanobot/plan.golden b/internal/migrate/testdata/nanobot/plan.golden index c5129f69..1b774118 100644 --- a/internal/migrate/testdata/nanobot/plan.golden +++ b/internal/migrate/testdata/nanobot/plan.golden @@ -29,7 +29,7 @@ summary: 5 providers · model · soul · instructions · 3 memories · 2 skills [agents_md] agents_md:file "AGENTS.md" status=ready selected=true detail: from nanobot AGENTS.md · 113 chars - text: from=nanobot AGENTS.md sha=99814a105bc2 + text: from=nanobot AGENTS.md sha=503636a3a5dc [memory] memory:99e8d1ee7047 "The user's name is Eno." status=ready selected=true memory: scope=global key=the-user-s-name-is-eno tags=[import:nanobot user-information] diff --git a/internal/migrate/testdata/nanoclaw/v2/groups/main/CLAUDE.local.md b/internal/migrate/testdata/nanoclaw/v2/groups/main/CLAUDE.local.md new file mode 100644 index 00000000..1cb659a5 --- /dev/null +++ b/internal/migrate/testdata/nanoclaw/v2/groups/main/CLAUDE.local.md @@ -0,0 +1 @@ +Rina works at Example Corp. diff --git a/internal/migrate/testdata/openclaw/home/.openclaw/work-ws/AGENTS.md b/internal/migrate/testdata/openclaw/home/.openclaw/work-ws/AGENTS.md new file mode 100644 index 00000000..32895eb1 --- /dev/null +++ b/internal/migrate/testdata/openclaw/home/.openclaw/work-ws/AGENTS.md @@ -0,0 +1,3 @@ +# Work + +Reply briefly, and never miss a deadline. diff --git a/internal/migrate/testdata/openclaw/home/.openclaw/workspace/AGENTS.md b/internal/migrate/testdata/openclaw/home/.openclaw/workspace/AGENTS.md new file mode 100644 index 00000000..27ba5bd5 --- /dev/null +++ b/internal/migrate/testdata/openclaw/home/.openclaw/workspace/AGENTS.md @@ -0,0 +1,3 @@ +# Rules + +Always cite sources. Never guess. diff --git a/internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/AGENTS.md b/internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/AGENTS.md new file mode 100644 index 00000000..9e102a49 --- /dev/null +++ b/internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/AGENTS.md @@ -0,0 +1,3 @@ +# Instructions + +Never guess at file paths. diff --git a/internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/memory/memory.db b/internal/migrate/testdata/openhuman/home/.openhuman/users/u_123/workspace/memory/memory.db new file mode 100644 index 00000000..e69de29b diff --git a/internal/migrate/testdata/openhuman/plan.golden b/internal/migrate/testdata/openhuman/plan.golden index 93d9ef41..6922625c 100644 --- a/internal/migrate/testdata/openhuman/plan.golden +++ b/internal/migrate/testdata/openhuman/plan.golden @@ -29,7 +29,7 @@ warning: OpenHuman's memory database (memory/memory.db) is not imported; MEMORY. [agents_md] agents_md:file "AGENTS.md" status=ready selected=true detail: from AGENTS.md · 42 chars - text: from=AGENTS.md sha=fd6819395b8e + text: from=AGENTS.md sha=7fd3521d178e [user_md] user_md:file "USER.md" status=ready selected=true detail: from PROFILE.md · 71 chars diff --git a/internal/migrate/testdata/zeroclaw/plan_v3.golden b/internal/migrate/testdata/zeroclaw/plan_v3.golden index b346a248..87f635b0 100644 --- a/internal/migrate/testdata/zeroclaw/plan_v3.golden +++ b/internal/migrate/testdata/zeroclaw/plan_v3.golden @@ -27,7 +27,7 @@ warning: ZeroClaw is running — stop it before importing its chat channels, or [agents_md] agents_md:file "AGENTS.md" status=ready selected=true detail: from AGENTS.md · 80 chars - text: from=AGENTS.md sha=271cc46a7c77 + text: from=AGENTS.md sha=5cf54a5943bf [user_md] user_md:file "USER.md" status=ready selected=true detail: from USER.md · 48 chars @@ -102,4 +102,4 @@ warning: ZeroClaw is running — stop it before importing its chat channels, or [role] role:coder "coder" status=ready selected=true detail: ZeroClaw agent - role: name=coder title="coder" model=anthropic/claude-sonnet-4-5 prompt_sha=9faf3f252ee0 + role: name=coder title="coder" model=anthropic/claude-sonnet-4-5 prompt_sha=b854746dce1b diff --git a/internal/migrate/testdata/zeroclaw/v3/agents/coder/workspace/AGENTS.md b/internal/migrate/testdata/zeroclaw/v3/agents/coder/workspace/AGENTS.md new file mode 100644 index 00000000..763bd2eb --- /dev/null +++ b/internal/migrate/testdata/zeroclaw/v3/agents/coder/workspace/AGENTS.md @@ -0,0 +1,4 @@ +# Instructions + +- Write small commits. +- Test before you push. diff --git a/internal/migrate/testdata/zeroclaw/v3/agents/default/workspace/AGENTS.md b/internal/migrate/testdata/zeroclaw/v3/agents/default/workspace/AGENTS.md new file mode 100644 index 00000000..849fb623 --- /dev/null +++ b/internal/migrate/testdata/zeroclaw/v3/agents/default/workspace/AGENTS.md @@ -0,0 +1,5 @@ +# Instructions + +- Use metric units. +- Ask before you deploy. +- Keep a changelog.