chore(memory): journal + TODO + contract w2a — feat model-router wave 2-A
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# CONTRACT — model-router-w2a
|
||||
- date: 2026-10-09 | flow: feat | branch: feature/model-router-w2 (to start off develop)
|
||||
- status: active
|
||||
- wave: W2-A (mod, plan r2). W2-B (repo migration + docs/registries as its STEP 6/7) gets its own contract after the live probe.
|
||||
|
||||
## REQUEST (verbatim — IMMUTABLE)
|
||||
tu peux lancer la vague 2
|
||||
(TODO W2 line: 15 skills `Skill(effort-*)` → `route` tool calls; remove `skills/effort-*`, `lib/effort-pins.txt/.sh`, install/update steps, `effort:` frontmatter on skills and agents; repo agents into the mod's `agents` table (verify the spawn/first-step ordering first); `lib/model-gate.md` + `lib/model-check.sh` → mod rule; census tests repointed; `lib/effort-shift.md` rewritten; docs)
|
||||
|
||||
## CLARIFICATIONS
|
||||
(pass A: none — outcome, scope and constraints come from the TODO W2 line + plan `2026-10-08-model-router-mod.md` § Wave 2)
|
||||
Q: keep the five `effort-*` skills as typed floor levers? / A: "supprimer, j'utilise les commandes builtin si j'ai besoin" → deleted; the mod drops its `Skill(effort-*)` bridge and typed-slash floor code; `ultrathink` floor stays [gated 2026-10-09]
|
||||
Q: table rows = bare level next to phases, or phases only? / A: "le pin était là car pas encore de système de routage fiable; maintenant qu'il y en a un, soit on le supprime, soit tu les remanies pour que ça fonctionne encore mieux" → reworked: rows are PHASES by role (plan/reflect/implement/write/verify/judge/mechanical), no level rows; agents routed on both axes by the mod while on (model written at spawn from the phase tier, upward only); the tracked `model:`/`effort:` frontmatter STAYS as the census-locked off-state floor (plan r3, confirmation 1/8) [gated 2026-10-09]
|
||||
Q: orchestrators declare phases or effort only? / A: phases [gated 2026-10-09]
|
||||
Q: (mid-run, feater NEED-DECISION, CLASS internal) a skill WITHOUT a row loaded INSIDE a sub-agent: keep the old reset of that loop's effort, or leave the loop untouched like main (A5)? / A: leave the agent loop untouched too — one rule for both loops, an unrowed helper skill (find-docs) never wipes an agent row's effort [gated 2026-10-09]
|
||||
Q: GATE 1 cap (3 × ECARTS on test coverage of criterion 3 clauses, code correct ×3; last rows landed by a feater, unverified) / A: user "Accepter et commiter W2-A" — accepted on the three reports + 88-test kit suite; diagnosis: compound coverage criterion, not the code [gated 2026-10-09]
|
||||
Q: model gate fate? / A: slim include (self-check + STOP when the mod could not raise), `lib/model-check.sh` + test deleted [gated 2026-10-09]
|
||||
|
||||
## ACCEPTANCE CRITERIA
|
||||
1. The mod's kit suite is green, including the new tests of criteria 3-5.
|
||||
CHECK: cd mods/model-router && out="$(claude plugin test . 2>&1)" && printf '%s\n' "$out" | grep -qE '[0-9]+ pass' && printf '%s\n' "$out" | grep -qE '(^|[^0-9])0 fail' && ! printf '%s\n' "$out" | grep -qE '[1-9][0-9]* fail' && echo W2A-TESTS-GREEN
|
||||
EXPECT: W2A-TESTS-GREEN
|
||||
EVIDENCE: MET exit=0 marker-found :: W2A-TESTS-GREEN
|
||||
2. `DEFAULT_CONFIG.phases` has `write` at work/high and a new `apply` at work/low; `DEFAULT_CONFIG.skills` and `.agents` carry exactly the phase rows of plan r2 § Row tables (56 skill rows, 21 agent rows + Explore/Plan), every value a phase key; the "Built-ins only" comment is gone.
|
||||
CHECK: bash .claude/tasks/contracts/w2a-table-census.sh mods/model-router/hooks/register.ts
|
||||
EXPECT: W2A-TABLE-COMPLETE
|
||||
EVIDENCE: MET exit=0 marker-found :: W2A-TABLE-COMPLETE
|
||||
3. A user-typed slash of a rowed skill routes main to its row (name-bound marker from `prompt.submit`, origins composer|sdk|bridge, pending slot mid-turn, or no live/spawning sub-agent); a preload inside a live sub-agent without the marker leaves main; a skill WITHOUT a row leaves the route in force; a best-tier skill row lives in a separate `runMain` slot that survives `turn.complete` and later `route` calls, and is dropped by `/route clear`, `/route off`, a user-typed non-best rowed skill, or a user `/model`; the `Skill(effort-*)` bridge is not sticky. Covered by kit tests.
|
||||
4. Any rowed agent spawn (whatever `provider.plugin`) with `e.model` undefined gets the row's model written at spawn: full id resolved within the tier only and ranked ≥ the tier head (upward only); otherwise no write + one deduped log line; the row's effort applies on its loop from its first step unless the call carried `effort`; `fork`/`workflow` spawns and agents whose `agent.offer` source is a project definition are untouched; an override `agents: { name: null }` drops a row; the `route` tool answer always names the id the next main step runs on. Covered by kit tests.
|
||||
5. Typed-floor code removed: no `slashEffort`, `guardedSlash`, `'slash'` Source, `typed /effort-` floor word in `register.ts`; `EFFORT_SKILL`/`effortBridge` (tool.call bridge) and the `ultrathink` floor kept until W2-B; `/route` unchanged (existing tests still green).
|
||||
CHECK: ! grep -qE "slashEffort|guardedSlash|'slash'|typed /effort-" mods/model-router/hooks/register.ts && grep -q 'turnFloor' mods/model-router/hooks/register.ts && grep -q 'effortBridge' mods/model-router/hooks/register.ts && echo W2A-DEAD-CODE-GONE
|
||||
EXPECT: W2A-DEAD-CODE-GONE
|
||||
EVIDENCE: MET exit=0 marker-found :: W2A-DEAD-CODE-GONE
|
||||
7. `claude plugin validate` passes.
|
||||
CHECK: cd mods/model-router && claude plugin validate . 2>&1 | grep -qi 'valid' && echo W2A-VALID
|
||||
EXPECT: W2A-VALID
|
||||
EVIDENCE: MET exit=0 marker-found :: W2A-VALID
|
||||
6. `make test suite=lib/tests/mods.test.sh` green.
|
||||
CHECK: make test suite=lib/tests/mods.test.sh 2>&1 | tail -5 | grep -q 'mods' && ! make test suite=lib/tests/mods.test.sh 2>&1 | grep -q '^FAIL' && echo W2A-MODS-SUITE
|
||||
EXPECT: W2A-MODS-SUITE
|
||||
EVIDENCE: MET exit=0 marker-found :: W2A-MODS-SUITE
|
||||
|
||||
## FILE SCOPE
|
||||
mods/model-router/hooks/register.ts, mods/model-router/hooks/register.test.ts, .claude/tasks/contracts/w2a-table-census.sh (oracle, written by the orchestrator)
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# GATE 0 oracle, contract 2026-10-09-model-router-w2a: DEFAULT_CONFIG.skills
|
||||
# and .agents in register.ts hold exactly the plan's phase rows (plan
|
||||
# 2026-10-09-model-router-w2 § Row tables), every value a declared phase.
|
||||
# Prints W2A-TABLE-COMPLETE only when every assertion passes.
|
||||
set -u
|
||||
F="${1:?register.ts path}"
|
||||
python3 - "$F" <<'PY'
|
||||
import re, sys
|
||||
src = open(sys.argv[1]).read()
|
||||
m = re.search(r'const DEFAULT_CONFIG: Config = \{(.*?)\n\}\n', src, re.S)
|
||||
if not m: print("no DEFAULT_CONFIG block"); sys.exit(1)
|
||||
cfg = m.group(1)
|
||||
def block(name):
|
||||
b = re.search(r'\n ' + name + r': \{([^\n]*)\},', cfg) \
|
||||
or re.search(r'\n ' + name + r': \{(.*?)\n \}', cfg, re.S)
|
||||
if not b: print(f"no {name} block"); sys.exit(1)
|
||||
rows = re.findall(r"(?:^|[{,])\s*'?([A-Za-z0-9_-]+)'?:\s*'([a-z]+)'", b.group(1), re.M)
|
||||
return dict(rows)
|
||||
phases = set(
|
||||
re.findall(r"^\s*([a-z]+): \{ tier:", re.search(r'\n phases: \{(.*?)\n \}', cfg, re.S).group(1), re.M))
|
||||
want_skills = {}
|
||||
for ph, names in {
|
||||
'plan': 'ship-feature init-project onboard tour audit-delta analyze code-clean client-handover brainstorming writing-plans requesting-code-review 21st-ui-review',
|
||||
'reflect': 'feat hotfix bugfix refactor web-validate harden seo geo site-motion frontend-design emil-design-eng design-motion-principles 21st-ui-build scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal scroll-progress-timeline subagent-driven-development writing-skills deprecation-and-migration 21st-ai 21st-ui-explore',
|
||||
'implement': 'gitflow prune-memory pdf-translate ci-cd-and-automation observability-and-instrumentation test-driven-development',
|
||||
'apply': 'commit-change release-candidate doc capitalize close reconcile deploy',
|
||||
'mechanical': 'status profile plugin-check skills-perso using-git-worktrees 21st-cli-use 21st-registry 21st-design-sync',
|
||||
}.items():
|
||||
for n in names.split(): want_skills[n] = ph
|
||||
want_agents = {'Explore': 'explore', 'Plan': 'judge'}
|
||||
for ph, names in {
|
||||
'implement': 'feater bugfixer code-cleaner scaffolder onboarder',
|
||||
'write': 'commit-changer doc-syncer handover-doc-writer refactorer',
|
||||
'apply': 'hotfixer release-executor plugin-probe validator-analyzer',
|
||||
'verify': 'verifier security-auditor',
|
||||
'judge': 'plan-challenger plugin-advisor seo-analyzer geo-analyzer analyzer',
|
||||
'mechanical': 'status-reporter',
|
||||
}.items():
|
||||
for n in names.split(): want_agents[n] = ph
|
||||
ok = True
|
||||
for name, want in (('skills', want_skills), ('agents', want_agents)):
|
||||
got = block(name)
|
||||
for k in sorted(set(want) | set(got)):
|
||||
if want.get(k) != got.get(k):
|
||||
ok = False; print(f"{name}.{k}: want {want.get(k)} got {got.get(k)}")
|
||||
bad = {k: v for k, v in got.items() if v not in phases}
|
||||
if bad: ok = False; print(f"{name}: undeclared phases {bad}")
|
||||
if len(want_skills) != 56 or len(want_agents) != 23:
|
||||
ok = False; print(f"oracle self-check: {len(want_skills)} skill rows, {len(want_agents)} agent rows")
|
||||
if 'Built-ins only' in cfg: ok = False; print("stale comment 'Built-ins only'")
|
||||
ph = re.search(r'\n phases: \{(.*?)\n \}', cfg, re.S).group(1)
|
||||
for want in ("write: { tier: 'work', effort: 'high' }", "apply: { tier: 'work', effort: 'low' }"):
|
||||
if want not in ph: ok = False; print(f"phases: missing {want}")
|
||||
print("W2A-TABLE-COMPLETE" if ok else "W2A-TABLE-INCOMPLETE"); sys.exit(0 if ok else 1)
|
||||
PY
|
||||
Reference in New Issue
Block a user