Skip to content

feat(models): the MiniMax-M3 suit + model dispatch as a skill - #2712

Merged
POWERFULMOVES merged 1 commit into
mainfrom
feat/model-dispatch-skill-and-m3-suit
Aug 25, 2026
Merged

POWERFULMOVES merged 1 commit into
mainfrom
feat/model-dispatch-skill-and-m3-suit

Conversation

@POWERFULMOVES

Copy link
Copy Markdown
Owner

Summary

Operator triple (a)+(b), node-side (c) in the AGNOTE record:

  • MiniMax-M3 model suit — the primary MiniMax suit was missing entirely (suits stopped at m2.7 while profiles/sessions moved to M3 in June). Corrected Token-Plan surface (api.minimax.io), fallback chain m3 → m2.7 (1M) → m2.1 (100K), token-plan tiers, thinking-model note.
  • Model dispatch is now a skill — .claude/commands/model/{dispatch,list-suits,verify}: routes by reading suits/cascades/MODEL_FABRIC_CONTRACT (local-first is law, never memory), TensorZero in-network :3000, harness dispatch via pmoves.agent.task.v1, MiniMax case-sensitivity + key-custody boundary. Registered in $domain_tag_skill_map; skill_registry_validate.py OK.

Companion node-side work (this session, AGNOTE record)

  • fix(db): anon could execute as a superuser, and a rebuild would restore that #2707 (anon superuser-EXECUTE revoke): audited, merged, applied on SPARK — both assertion directions verified (anon f, service_role t)
  • Archon rebuild completed: rebuilt from submodule 944d31da; crash-loop root-caused to an upstream bundled-schema ordering bug (partial index idx_workflow_events_run_order referencing event_order runs ~250 statements before the ADD COLUMN IF NOT EXISTS that adds it, in one multi-statement query) — fixed on-DB in correct order; archon healthy, :3737/:8091 both 200
  • Verifier static gate 6/6 PASS on this branch

Testing

  • provider_verifier_gate.py --json: PASS 6/6
  • skill_registry_validate.py: OK
  • M3 suit YAML parses; aligns with minimax_edition.yaml + agent_signatures.yaml ids
  • Archon: db.postgres_schema_init_completed, 0 schema failures, endpoints 200

Record: AGNOTE4482PHI.t1.md — SPARK-KIMI::MODEL-DISPATCH-SKILL-ARCHON-REBUILD::2026-08-24.

💘 Generated with Crush

@coderabbitai

coderabbitai Bot commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e6c63f01-540e-496f-91b3-384e0a37d874


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added docs Documentation config pmoves/config(s)/ changes governance AGNOTE register / agent definitions / damage-control hooks labels Aug 24, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 304b04b4ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +35 to +36
api_key_env: MINIMAX_TOKEN_PLAN_API_KEY
api_base: https://api.minimax.io/v1 # corrected host; chatcompletion_v2 retired

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Expose the API base where the Kong seeder reads it

When make -C pmoves kong-seed parses this suit, kong_route_seeder._parse_model_suits() does not inspect token_plan.api_base; it only checks the top-level, model, model_suit, suit.base_url, and model_config.endpoint locations. The new M3 entry therefore falls back to _infer_api_base("minimax"), which still returns the retired https://api.minimax.chat/v1, so the generated MiniMax-M3 Kong route does not use the corrected host declared here. Move the value into the supported suit schema or extend the seeder to read the token-plan block.

Useful? React with 👍 / 👎.

- Blueprint-first implementation → kiloclaw lanes (glm-5.1 via Z.AI coding plan)
- Local/private → Ollama suits on the node's profile (`pmoves/config/profiles/*.yaml`)
- Harness-dispatched work → the bootstrap routing table (`pmoves/contracts/schemas/pmoves-bootstrap/example.cgp.yaml`), e.g. publish to `pmoves.agent.task.v1` with target `glm-5.1` / `hermes-3` / `mavis`
3. Gateway path when a suit routes through TensorZero: in-network base is `:3000` (3030 is host-only); check `http://localhost:3000/health` first.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Probe TensorZero on the published host port

When /model:dispatch runs from the normal repository host, Compose publishes TensorZero's container port 3000 as localhost:3030 (docker-compose.core.yml and TENSORZERO_HOST_URL both confirm this). Probing localhost:3000 will therefore either reject a healthy gateway or accidentally test an unrelated service, leading the dispatch workflow to choose the wrong surface or fallback. Use the configured host URL/default port 3030 for this host-side check while retaining port 3000 only for in-network consumers.

Useful? React with 👍 / 👎.

Operator triple from the 2026-08-24 session, part 1 (skill + suit):

- configs/model-suits/MiniMax-M3.yaml: the primary MiniMax suit was
  missing entirely — suits stopped at m2.7 while sessions and profiles
  moved to MiniMax-M3 in June 2026. Authored with the corrected Token
  Plan surface (api.minimax.io, OpenAI-compatible path), the m3 ->
  m2.7 (1M long-context) -> m2.1 (efficient) fallback chain, token
  plan tiers, and the thinking-model note (reasoning_content: budget
  output tokens accordingly).

- .claude/commands/model/{dispatch,list-suits,verify}: model dispatch
  is now a skill instead of tribal knowledge. dispatch routes by
  reading the suits, the provider cascades, and
  MODEL_FABRIC_CONTRACT.md (local-first order is law), covers the
  TensorZero in-network port (:3000), harness dispatch via
  pmoves.agent.task.v1, and the MiniMax boundaries (case-sensitive
  MiniMax-M3; a 401 on the correct path is key custody, not routing).
  list-suits cross-checks suits vs profiles vs signatures and flags
  drift. verify wraps the provider gates (MiniMax two-piece design).

- submodule_skill_registry.json: model skills registered in the
  $domain_tag_skill_map (llm, local-models); validator OK.

Companion node-side work this session (recorded in AGNOTE): #2707
anon/superuser EXECUTE revoke merged+applied both-assertion-verified;
archon rebuilt from the submodule and its upstream bundled-schema
ordering bug (partial index before the ALTER that adds the column it
references) diagnosed and worked around on-DB; archon healthy on
:3737/:8091.

💘 Generated with Crush
@POWERFULMOVES
POWERFULMOVES force-pushed the feat/model-dispatch-skill-and-m3-suit branch from 304b04b to 2c964b3 Compare August 25, 2026 04:55
@POWERFULMOVES
POWERFULMOVES merged commit e11fed5 into main Aug 25, 2026
27 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the feat/model-dispatch-skill-and-m3-suit branch August 25, 2026 05:08
POWERFULMOVES added a commit that referenced this pull request Aug 26, 2026
…er I took it

python-tests on the updated head reported exactly one new failure:
test_routing_fields_match_the_committed_snapshot. The snapshot does not exist
on main -- this PR introduces it -- and I generated it from an 18-suit tree.
Merging main brought in a 19th, MiniMax-M3 (#2712), so it went stale.

Regenerated only after proving it was an addition and not drift:

  old=18  new=19
  CHANGED: none      REMOVED: none      ADDED: ['MiniMax-M3']

All eighteen pre-existing routing identities are byte-identical, so acceptance
criterion 2 -- Kong sees the same model_id/provider/api_base/api_key_env --
still holds. The regeneration script refuses to write if the changed or removed
sets are non-empty, so a genuine re-parenting cannot be absorbed as "just an
addition"; that is the whole failure mode this snapshot exists to catch.

Also drops a hardcoded 18 from the docstring, which would have gone stale again
on the next suit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f
POWERFULMOVES added a commit that referenced this pull request Aug 26, 2026
…from eleven real observations (#2747)

* docs(spec): model-harness fitting — join the two halves the catalog already has

Design spec only. No schema or code changes.

The catalog already says a model and a harness are tuned to each other, in two
halves written separately and never joined:

  suits carrying cross_agent (fit)      9
  suits carrying harness_mappings (tune) 9
  suits carrying BOTH                    0
  distinct top-level schemas            7
  code reading either                   none

Fit without tuning is a verdict with no remedy; tuning without fit is a setting
with no address. Hence "fitting" rather than "suit" -- a suit is worn by one party.

## The fact worth surfacing

cross_agent already records harness bias, and nothing reads it:

  clawz=limited for gemma4-dense, minimax-m2.1, minimax-m2.7, nemotron-3-super,
  qwen3.6 -- every non-Claude model measured -- while the three current Claude
  suits are all-full and absent from that list.

Values in use: full x35, untested x6, limited x6, none x1. Someone measured the
tax a harness charges models it did not grow around, and it has never once
steered a routing decision.

## Scope

Schema unification, harness-reference validation, a controlled role vocabulary
(31 keys today, 22 singletons, `debugging` beside `deep_debugging`), the router
contract, and migration of all 18 suits.

Explicitly NOT retuning any model and NOT re-measuring any fit: migration
preserves recorded values exactly, and acceptance criterion 1 is a before/after
tuple diff, because the way a config schema change goes wrong is by quietly
losing a value nobody re-checks.

## Self-review caught one unverified claim

The draft proposed marking harnesses with `role_class: harness`, "using the
existing field rather than inventing one". Checked: role_classes is a declared
enum of planner/worker/reviewer -- a workflow role, not an entity kind -- so that
would have extended an enum with a category error. Replaced with the weaker and
truer requirement (a harness key must resolve to a registered agent) and moved
"does a harness marker earn its place" to open questions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* docs(spec): a role binds seams, not just sampling parameters

Reviewing the dsh documentation as directed. docs/capability-seams.md is the
reference the open question needed: ~28 swappable seams (ctx.llm, ctx.tools,
ctx.storage, ctx.credentials, ctx.systemPrompt, ctx.agentPresets, ctx.tokenMeter,
ctx.toolResultPruner), each declared by one package and filled by any of several
implementations. ctx.sessionPersistence states the principle outright:

  "Backends persist the same SessionEvent vocabulary; apps choose a backend at
   composition time."

A role IS that choice. temperature and top_p cannot express it, which is why the
first draft could not answer "should the caller do this, or should the ecosystem".

  drive a GUI            -> ctx.tools        pmoves-surf + mai_ui, not in-harness tools
  comb a large corpus    -> ctx.llm          a SPARK-local endpoint, cheap tool calls
  need an agent          -> ctx.agentPresets mint via archon
  OCR a medical set      -> ctx.llm          hf_agent / unsloth
  search library/drive   -> ctx.storage      the corpus-owning service

So fit gains a fifth value: `delegate` — capable, but the work belongs elsewhere,
and the binding names where. That turns "does 4090-CLAUDE do this, or does PMOVES"
from a per-session judgement call into a recorded, reviewable binding. It is the
only fit value that routes to a different SUBSTRATE rather than selecting a model,
so it is the only one that must name a target.

The economics are the argument: a caller's context window is a hard non-renewable
per-session constraint, while a local model's tool calls are close to free. A
fitting that routes bulk tool-work to the caller converts an abundant resource into
a scarce one. dsh already treats this as first-class — ctx.tokenMeter is "replay
token measurement" and ctx.toolResultPruner is "model-free tool-result pruning" —
so a fitting should be able to bind them.

Also resolves open question 1: fit is per-harness AND narrowable per role, both,
because the seam bindings differ by role. A role-level fit overrides the
harness-level one; harness-level with no override applies to all roles. Migration
of the 35 recorded cross_agent entries stays mechanical (they become harness-level).

Seam names are dsh's vocabulary; a PMOVES harness exposing no seams declares none
and carries sampling parameters only. Being seam-aware is not a precondition for
being fitted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* docs(spec): fit keeps observations, not a verdict — hand AND measured

Resolves open question 2: both, and the record keeps more than one.

A hand-recorded verdict carries judgement a benchmark cannot -- "tool-call parsing
assumes an Anthropic-shaped response" is not something a smoke run reports. A
measured verdict stays honest as models change, which hand-recording does not.
Neither supersedes the other, so `fit` stops being a bare scalar: each observation
carries its source (by / method / date / note) and a pairing may hold several.

The effective fit the router reads is the MOST CONSERVATIVE verdict among
observations, so one credible "this is worse than it looks" is never averaged away
by a benchmark that did not exercise the failing path.

Divergence between a hand verdict and a measured one is a signal worth surfacing
rather than a conflict to resolve silently -- and the lane stays open: a third
perspective, a paired node's review or another agent's run, APPENDS rather than
overwrites. That is what keeps this from becoming one authority's opinion frozen
into config.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* docs(spec): revised after b850 pair review — three findings changed the design

First exercise of the watch pairing (#2743). Verified b850's claims rather than
accepting them; two P1s reproduce and one finding invalidates the spec's premise.

## The premise was wrong

cross_agent is NOT the fit half. Its name is accurate -- it answers "which PMOVES
components can address this model" -- and its keys span agents (agent_zero, archon,
typer), a UI (a2ui), a launcher (pinokio) and two genuine harnesses (clawz,
kilocode). Harness fit is a third thing: what a harness costs a model that did not
grow around it.

So `fit` is now a NEW harness-only field seeded fresh, and cross_agent is left
byte-identical. The clawz signal -- full for Claude suits, `limited # Requires
adapter layer` for every non-Claude one -- survives intact and is still the
evidence. It is just two columns wide, not seven.

b850's own headline argument here (that `typer` was the Python CLI library, making
the data a category error) was RETRACTED by its author after the operator confirmed
typer is a TypeScript agent. The narrower argument survived without it.

## Acceptance criterion 1 could not have caught this

It was a before/after tuple diff proving no value changed -- which passes cleanly
WHILE every value silently changes meaning. That is this spec's own stated failure
mode in its harder form: nothing lost, the REFERENT moves, and a diff cannot see it.
Replaced with a structural criterion.

## Two P1s, both reproduced here

kong_route_seeder: every lookup is top-level or one of two known containers. A
`fitting:` root matches none, so every migrated file yields model_id=None, is
skipped, and every model drops out of Kong -- while Kong reports healthy, which it
has done at zero routes on a node before. Schema now EXTENDS model_suit rather than
re-parenting it.

orchestrator.py: routing_for() resolves wire_target and only then publishes
SUBJECT_TASK with target already set. A subscriber receives a decision, not a
request. Router is now request/reply BEFORE dispatch. (I nearly reported this
unreproducible -- my first grep hit libs/langextract/providers/orchestrator.py
instead of pmoves/tools/orchestrator.py.)

## Open questions 3 and 4 closed

3: dsh is a host attribute, not a fit key -- a dsh row means "whatever dsh hosted
that day", unfalsifiable, degrading as pinokio: full already has.
4: yes to a harness marker, as `kind:` on the registry entry. The reviewer made
itself the worked example: it resolved typer by name collision, wrote "decisive",
and retracted.

Also: no `untested` value. Absence reads as honestly unknown; `untested` reads as a
completed observation with a null result and survives for months looking like data.

Added a framing section -- fit is evidence with provenance, addressed to two
readers: the router deciding where work goes, and the MODEL deciding how to work
once it arrives. A permission bit serves only the first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* docs(plan): model-harness fitting — six tasks, Kong pinned first

Implementation plan for the approved spec. Scope-split: this plan covers the
fitting DATA and GATES; the router is a follow-on with its own testable
deliverable, because a plan that only pays off at the end is not one.

Task order is deliberate. Task 1 pins Kong's top-level routing identity BEFORE
anything changes, and mutation-checks that guard by nesting one suit under a new
root and watching it fail. That is the regression the original schema would have
caused, so it becomes a test rather than a caveat.

Tasks 2-4 build the vocabulary, the `kind: harness` marker and fit resolution.
Task 5 seeds the eleven genuine observations fresh — and asserts cross_agent is
byte-identical, because a value-diff passes while the referent moves. Task 6 adds
the gate, mutation-checked three ways.

Self-review closed one gap: the spec's context-budget field and seam-binding fields
would have landed as config nothing reads — the exact defect the spec exists to
fix. Both are deferred to the router plan that consumes them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* test(kong): pin routing identity at the top level before the fitting change

A fitting schema that re-parents name/provider/base_url/api_key_env makes every
lookup in _parse_model_suits miss, so each file is skipped for lacking a model_id
and every model drops out of Kong while Kong reports healthy. Mutation-checked:
nesting one suit under a new root fails this test.

* test(kong): add snapshot guard for routing field values

Finding 1 fix: Removed dead 'missing_id' assertion that could never fail.
_parse_model_suits only appends entries where both model_id and provider
are truthy, so all entries are guaranteed to have a model_id.

Finding 2 fix: Added test_routing_fields_match_the_committed_snapshot to
catch value drifts in any of the four routing fields. Presence and count
alone are not enough — a schema change that re-parents only base_url/
api_key_env leaves name/provider resolvable through the parser's fallback
chain, so the entry still appends and passes the count check, while Kong
silently falls back to inferred defaults instead of the file's real values.

Committed snapshot pmoves/tests/data/kong_route_identity.json pins all four
fields by value. Mutation-checked: changing one base_url fails the test,
correctly identifying the changed file.

* feat(fittings): controlled role vocabulary with supersedes

31 role keys existed across the suits, 22 appearing exactly once, with debugging
beside deep_debugging. A key with no permitted set cannot be validated and a router
cannot dispatch on free text.

supersedes carries consolidation without silently dropping the old name: a superseded
key still resolves and warns, so a rename is not a routing outage.

* feat(agents): kind: harness marks what a fitting may point at

Without an explicit entity kind the cross_agent key space silently mixed agents, a
UI, a launcher and two harnesses across 18 files and nothing caught it. A reviewer
with full repo access then resolved 'typer' to a same-named Python dependency,
called it decisive, and had to retract - a kind marker makes that unresolvable by
guessing.

Marks clawz and kilocode_glm only. agent_zero and archon are agent services and
a2ui is a UI; they appear in cross_agent for component compatibility and host no
model.

* feat(fittings): most-conservative fit resolution, no untested value

The router reads the most conservative verdict among observations so one credible
'this is worse than it looks' is never averaged away by a benchmark that did not
exercise the failing path.

No untested value exists: absence reads as honestly unknown, whereas untested reads
as a completed observation with a null result and survives for months looking like
data. An unknown verdict raises rather than resolving.

* feat(fittings): seed fit from the eleven genuine harness observations

Seeded fresh rather than migrated. cross_agent is byte-identical (pure
insertions, verified against origin/main) and keeps answering component
compatibility; a value-diff would have passed while the referent moved, so
the test asserts the field itself is unchanged.

Migration would also have carried the cross_agent spelling 'kilocode', which
does not resolve -- the registry key is kilocode_glm. Seeding fresh lets the
fit key be the resolvable one.

fit: is placed as a top-level key, sibling of cross_agent, in all nine files
-- not nested inside suit:/model_suit: as originally briefed. Four of the
nine targets (claude-sonnet, gemma4-dense, nemotron-3-super, qwen3.6) are
flat documents with no suit:/model_suit: mapping to nest inside, so top-level
placement is required for consistency across all nine and is safe for Kong
(the seeder reads suit containers directly, not a `fit` key).

Eleven observations: clawz full for four Claude suits, clawz limited for
five non-Claude suits carrying the recorded 'requires adapter layer' note,
kilocode_glm full for two. Every observation carries by/method/on.

Fixed a PyYAML 1.1 gotcha discovered while seeding: an unquoted `on:` key
parses as the boolean True, not the string "on" -- quoted as "on": in every
observation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* feat(gate): fittings must name a real harness and a known role

A fitting naming a harness that does not exist is a typo that silently disables
routing for that pair -- the failure class this repo keeps hitting. Same cross-check
shape the validator already runs for room owners, but an ERROR rather than a
warning: a room with a bad owner is still discoverable, an unroutable pairing is
invisible at read time.

Reads `fit` at the top level of each suit document (not nested under
model_suit/suit) -- four of the nine target files have no suit key at all, so
Task 5 seeded `fit:` at the document root for all of them.

Also forces UTF-8 on stdout/stderr: the report's em dash decoded as cp1252 on
Windows, corrupting subprocess-captured output for any caller (this gate's own
test suite included) that decodes strictly as UTF-8.

Mutation-checked by the tests: an unregistered harness key, an unknown role, and an
'untested' verdict each fail the gate.

* fix(test): make the fitting-gate fixture restore byte-exact

restore_victim read the backup as text and wrote it back as text, so Python
normalized CRLF to LF -- every run of test_fitting_gate.py left
qwen3.6.yaml showing modified in git status even though content parsed
identical. This repo holds a pristine-worktree norm; a file that's always
dirty is a file whose real changes stop being noticed.

Read/write bytes instead of text so the restore is exact regardless of what
the mutation step wrote. Also drops an unused `shutil` import carried over
from the brief's draft.

* fix(model-harness-fitting): close the gate's own vacuous-pass gaps (I1-I4, M1)

Final-review fix wave, all in gate/test/workflow code, none touching
pmoves/configs/model-suits/ or cross_agent:

- I1: test_fit_seed.py's cross_agent guard now counts comparisons and
  skips loudly (with an explicit reason) instead of silently passing when
  origin/main is unreachable, as it will be in CI under the default
  actions/checkout fetch-depth. Also switched from a parsed-YAML
  comparison to a raw-text one, matching what the test's name/docstring
  actually claims (byte-identical).
- I2: validate-agents-config.yml now watches the three inputs its
  validator reads (model-suits/*.yaml, model-roles.yaml, fittings.py).
- I3: the gate rejects an empty observation list, empty role map, and
  empty harness map -- each was `untested` under a different spelling.
- I4: the gate requires by/method/on provenance on every observation, and
  names the YAML 1.1 unquoted-`on:`-parses-as-boolean-True trap explicitly
  rather than just reporting the field as missing.
- M1: malformed fit shapes (the legacy scalar `fit: {harness: full}`, or
  observations written as a mapping instead of a list) now produce a gate
  error naming the file, instead of an uncaught AttributeError that
  aborted the whole validator run.

Added 8 new tests to test_fitting_gate.py covering each rejection case,
using the existing byte-exact restore_victim fixture.

* docs(spec): quote the "on" key — the examples were teaching a silent-data-loss bug

YAML 1.1, which PyYAML's safe_load implements, reads a bare `on` as the boolean
True. So `on: 2026-08-25` parses to the key True, and obs.get("on") returns None:
the provenance vanishes with no error and no missing-key warning, leaving a record
that looks complete and carries no date.

All five examples in this spec wrote it unquoted. An implementer hit it while
seeding the eleven observations and quoted it there; the whole-branch review then
raised it as finding I4, because the gate checked no provenance at all AND the
design doc was propagating the trap to anyone copying from it.

The gate now rejects both the missing-`on` case and a stray True key, with a
message naming the quoting specifically. This commit closes the other half: the
document no longer teaches what its own gate refuses. Added the reason inline so
the next reader does not tidy the quotes away — the same trap catches y, yes, no
and off.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* fix(fit-tests): partial reachability was still a silent pass (B850 review)

The I1 fix guarded the all-or-nothing case: if `origin/main` resolved for
none of the nine seeded files, the test skipped loudly instead of passing
having asserted nothing.

It did not guard the partial case. Per file the loop still did:

    if before.returncode != 0:
        continue

so a run where origin/main resolved for six of nine -- a partial fetch, a
file added on this branch, a rename landing on main mid-run -- compared the
reachable subset, never mentioned the rest, and reported green. `compared ==
0` was audible; `compared == 6` was indistinguishable from a full pass.

That is the same defect this branch exists to remove, one layer in.

The expected list is now named, unreachable files are collected, and the
count is asserted against it. The loud zero-skip is kept.

Proven able to fail, not just to pass: with one bogus stem appended to the
expected list the assertion fires and names it --

    only 9/10 suit files were compared against origin/main;
    unreachable: ['no-such-suit']

Restored, the fitting suite is 30 passed.

Found by B850 (Knuckles) reviewing #2747 against the code rather than the
diff. Two readers of the same diff would have shared the blind spot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* fix(fittings): an erased vocabulary passed the gate, and delegate routed nowhere

Two Codex findings on #2747, both the same shape: something reports success
while checking nothing.

1. load_roles() normalised a missing or empty `roles:` to `{}`. Every seeded
   fitting uses the `*` role, and resolve_role() honours `*` without consulting
   the mapping, so deleting the entire controlled vocabulary left the gate
   printing "OK -- registry/teams coupling clean". Measured: with `roles: {}`
   the gate exited 0 before, exits 1 now, and still exits 0 on the real file.
   Entry shapes are validated too -- a `supersedes` that does not parse is a
   routing outage that reads as a typo.

   Reported as a gate error rather than raised, per the note directly above the
   call site: an uncaught exception there would abort the run and suppress the
   registry report for every other file. Verified the other report lines still
   appear alongside the failure.

2. `delegate` was accepted with no destination. The spec already requires one
   (SS1b: "the only value that must name a target") because it selects a
   SUBSTRATE rather than a model -- the code had diverged from it. A router
   would have received a verdict that looked actionable and could not be
   honoured. Nothing is seeded with `delegate` today, which is why the
   requirement lands now: the ambiguity never enters the data.

10 new tests, all verified to fail against the previous fittings.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* docs(spec): "migration is mechanical" was false, and the harness-marker text was stale

Two Codex P1s on #2742, both places where the spec contradicted itself.

1. The migration paragraph said a `harness_mappings` block becomes
   `harnesses.<h>.roles` "under whichever harness the suit was written for" --
   and called that mechanical. It is not, and the same sentence says why: there
   is no source for `<h>`. Measured: all 9 files carrying `harness_mappings`
   record no harness at all -- zero `harness:` / `harness_id:` / `written_for:`
   across the nine. It also contradicted the schema block above it, which
   already said `harnesses` is seeded fresh and NOT migrated.

   Resolved uniformly: nothing is migrated. Both halves stay where they are,
   `harnesses` is seeded fresh, and a human names the harness because that is a
   fact about intent the files never recorded.

   This dissolves the second finding too. `cross_agent` keys stay component
   -compatibility claims rather than harness keys, so they are not subject to
   the resolution gate -- which is why `typer` and `pinokio` being absent from
   agent_registry.yaml does not fail it. Measured: the gate exits 0 today with
   both unregistered. The spec now says so instead of leaving a reader to infer
   that nine files were about to fail.

2. Section 2 still read "No harness marker is proposed, and the omission is
   deliberate" while open question 4 in the same document records it resolved
   the other way, and #2747 implements `kind: harness`. The reversal is now
   recorded rather than edited away, with what changed the answer: without a
   marker the key space mixes categories, and a reviewer with full repo access
   already resolved `typer` to a same-named Python dependency and retracted.

   States what is registered (clawz, kilocode_glm) and what is named but not yet
   registered (dsh #2740, claude_pmoves, claude_4090) -- the gate working, not a
   defect in it.

Adds acceptance criterion 1b so the untouched-harness_mappings claim is tested
rather than asserted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* fix(submodule): restore the jellyfin gitlink my own `git add -A` rolled back

526efb8 was a docs-only spec change, but `git add -A` in a worktree whose
submodule checkout is stale also staged the gitlink, silently reverting
Pmoves-Jellyfin-AI-Media-Stack from 83862ccc1 (set by #2732) back to e69e3f9d6.

Nothing in the diff view showed it -- that is the point of the gate, and
submodule-gitlink-gate caught it: "ROLLBACK (head is behind the base gitlink)".
Merging main did not fix it either, because the rollback was OUR side of the
merge, so it resolved silently in favour of the older commit.

Audited the other four branches touched this session for the same mistake;
none carry a gitlink change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

* test(kong): regenerate the routing snapshot for a suit main added after I took it

python-tests on the updated head reported exactly one new failure:
test_routing_fields_match_the_committed_snapshot. The snapshot does not exist
on main -- this PR introduces it -- and I generated it from an 18-suit tree.
Merging main brought in a 19th, MiniMax-M3 (#2712), so it went stale.

Regenerated only after proving it was an addition and not drift:

  old=18  new=19
  CHANGED: none      REMOVED: none      ADDED: ['MiniMax-M3']

All eighteen pre-existing routing identities are byte-identical, so acceptance
criterion 2 -- Kong sees the same model_id/provider/api_base/api_key_env --
still holds. The regeneration script refuses to write if the changed or removed
sets are non-empty, so a genuine re-parenting cannot be absorbed as "just an
addition"; that is the whole failure mode this snapshot exists to catch.

Also drops a hardcoded 18 from the docstring, which would have gone stale again
on the next suit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9mpK1ZFjexjthZbvcb94f

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config pmoves/config(s)/ changes docs Documentation governance AGNOTE register / agent definitions / damage-control hooks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant