From 529480b4a5d1051081a2ab449c4751284628c5f1 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sat, 29 Aug 2026 14:11:39 -0400 Subject: [PATCH] =?UTF-8?q?fix(#3895):=20delete=20the=20mempalace-curator'?= =?UTF-8?q?s=20model=20frontmatter=20pin=20=E2=80=94=20the=20fleet's=20onl?= =?UTF-8?q?y=20hardcoded=20model=20(#4048)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(#3895): no shipped agent may hardcode a model frontmatter pin (failing first) * fix(#3895): delete the mempalace-curator's model frontmatter pin — the fleet's only hardcoded model Exactly one of the 34 shipped agents carried 'model: sonnet' in its frontmatter; every other agent resolves through the model-profile system. The ship:post dispatch (#2684) resolves per-hook and — per #2517 — deliberately OMITS model= on inherit so the agent inherits the orchestrator's model; the frontmatter pin intercepted that inherit case, silently forcing sonnet where all 33 siblings would inherit, and operators could not durably remove it (install rewrites live copies wholesale). Deleting the line changes nothing for default profiles — the catalog entry (model-catalog.json agents.gsd-mempalace-curator: golden/balanced sonnet, budget haiku) preserves today's behavior — while restoring model_overrides and inherit authority. Pinned by a new agent-frontmatter guard: no shipped agent may hardcode a model pin, and the catalog entry must keep existing so the pin's deletion can never orphan the agent. * chore(#3895): changeset fragment (pr number backfilled after PR creation) * chore(#3895): backfill changeset PR number (4048) --------- Co-authored-by: sim --- .changeset/kind-eagles-rally.md | 5 +++++ agents/gsd-mempalace-curator.md | 1 - tests/agent-frontmatter.test.cjs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .changeset/kind-eagles-rally.md diff --git a/.changeset/kind-eagles-rally.md b/.changeset/kind-eagles-rally.md new file mode 100644 index 000000000..520e07229 --- /dev/null +++ b/.changeset/kind-eagles-rally.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 4048 +--- +gsd-mempalace-curator no longer hardcodes model: sonnet in its frontmatter — the only pin in the 34-agent fleet; it intercepted the deliberate inherit case (agents inherit the orchestrator model when resolution is inherit) and operators could not durably remove it. Default profiles keep sonnet via the model catalog; model_overrides and inherit now work (#3895) diff --git a/agents/gsd-mempalace-curator.md b/agents/gsd-mempalace-curator.md index b42a1540e..a3c3e08d1 100644 --- a/agents/gsd-mempalace-curator.md +++ b/agents/gsd-mempalace-curator.md @@ -2,7 +2,6 @@ name: gsd-mempalace-curator description: Ship-time MemPalace curation — writes the session diary, proposes/creates cross-project tunnels, mirrors extract-learnings into the temporal KG, and runs wing-scoped drawer pruning. Spawned at ship:post by the mempalace capability. tools: Read, Bash, Grep, Glob -model: sonnet color: cyan --- diff --git a/tests/agent-frontmatter.test.cjs b/tests/agent-frontmatter.test.cjs index f9a80b21c..25bdf3952 100644 --- a/tests/agent-frontmatter.test.cjs +++ b/tests/agent-frontmatter.test.cjs @@ -246,6 +246,38 @@ describe('AGENT: required frontmatter fields', () => { } }); +// ─── Model resolution uniformity (#3895) ───────────────────────────────────── + +describe('MODEL: no agent hardcodes a model frontmatter pin', () => { + // Exactly one shipped agent (gsd-mempalace-curator) carried `model: sonnet` + // while the other 33 resolved through the model-profile system. The pin + // intercepted #2517's deliberate inherit case — the ship:post dispatch OMITS + // model= on inherit so the agent inherits the orchestrator's model, but the + // frontmatter pin silently forced sonnet there. The catalog entry + // (model-catalog.json: golden/balanced sonnet) preserves default-profile + // behavior; operators regain model_overrides + inherit authority. + test('no shipped agent frontmatter contains a model: pin', () => { + const offenders = []; + for (const agent of ALL_AGENTS) { + const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8'); + const frontmatter = content.split('---')[1] || ''; + if (/^model:/m.test(frontmatter)) offenders.push(agent); + } + assert.deepEqual( + offenders, [], + `agents must resolve models via the model-profile system, not a frontmatter pin (#3895): ${offenders.join(', ')}` + ); + }); + + test('the curator keeps its catalog entry (deleting the pin must not orphan the agent)', () => { + const catalog = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'gsd-core', 'bin', 'shared', 'model-catalog.json'), 'utf-8')); + const entry = catalog.agents && catalog.agents['gsd-mempalace-curator']; + assert.ok(entry, 'catalog entry for gsd-mempalace-curator must exist'); + assert.equal(entry.golden, 'sonnet', 'golden profile preserves the pinned behavior'); + assert.equal(entry.balanced, 'sonnet', 'balanced profile preserves the pinned behavior'); + }); +}); + // ─── Color Value Validation ────────────────────────────────────────────────── const VALID_AGENT_COLORS = new Set(['red', 'blue', 'green', 'yellow', 'purple', 'orange', 'pink', 'cyan']);