feat(models): the MiniMax-M3 suit + model dispatch as a skill - #2712
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
There was a problem hiding this comment.
💡 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".
| api_key_env: MINIMAX_TOKEN_PLAN_API_KEY | ||
| api_base: https://api.minimax.io/v1 # corrected host; chatcompletion_v2 retired |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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
304b04b to
2c964b3
Compare
…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
…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>
Summary
Operator triple (a)+(b), node-side (c) in the AGNOTE record:
MiniMax-M3model 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..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 viapmoves.agent.task.v1, MiniMax case-sensitivity + key-custody boundary. Registered in$domain_tag_skill_map;skill_registry_validate.pyOK.Companion node-side work (this session, AGNOTE record)
f, service_rolet)944d31da; crash-loop root-caused to an upstream bundled-schema ordering bug (partial indexidx_workflow_events_run_orderreferencingevent_orderruns ~250 statements before theADD COLUMN IF NOT EXISTSthat adds it, in one multi-statement query) — fixed on-DB in correct order; archon healthy,:3737/:8091both 200Testing
provider_verifier_gate.py --json: PASS 6/6skill_registry_validate.py: OKminimax_edition.yaml+agent_signatures.yamlidsdb.postgres_schema_init_completed, 0 schema failures, endpoints 200Record:
AGNOTE4482PHI.t1.md—SPARK-KIMI::MODEL-DISPATCH-SKILL-ARCHON-REBUILD::2026-08-24.💘 Generated with Crush