pi-smart-router 0.9.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -590,6 +590,11 @@ npm run routing:ingest-fc-rewardbench -- \
590
590
  --output /tmp/fc-rewardbench-pack.jsonl
591
591
 
592
592
  # Optional weak TwinRouterBench tier proxy (exclude from holdout ECE)
593
+ # Preferred input: checked-in CI subset (SP-199/SP-201); full-track after SP-200 is local-only.
594
+ npm run routing:ingest-twinrouterbench-weak -- \
595
+ --input tests/eval/corpus/twinrouterbench/ci-subset.json \
596
+ --output /tmp/trb-weak-from-ci-subset.jsonl
597
+
593
598
  npm run routing:ingest-twinrouterbench-weak -- \
594
599
  --input tests/eval/corpus/label-packs/twinrouterbench-weak/ci-fixture.jsonl \
595
600
  --output /tmp/trb-weak-pack.jsonl
@@ -604,6 +609,11 @@ npm run routing:calibration-dry-run
604
609
  # Operator packs (schema-valid JSONL)
605
610
  npm run routing:calibration-dry-run -- --packs /tmp/swe-gym-pack.jsonl /tmp/fc-rewardbench-pack.jsonl
606
611
 
612
+ # Warm-start: weak / exclude_from_holdout_ece rows join the **fit** pool only
613
+ npm run routing:calibration-dry-run -- \
614
+ --packs /tmp/swe-gym-pack.jsonl /tmp/trb-weak-from-ci-subset.jsonl \
615
+ --include-excluded-in-fit
616
+
607
617
  # Soft ECE advisory fail (threshold 0.25 calibrated ECE; not a release-gate absolute)
608
618
  npm run routing:calibration-dry-run -- --packs /tmp/swe-gym-pack.jsonl --enforce-soft-ece
609
619
  ```
@@ -615,9 +625,10 @@ Dry-run behavior:
615
625
  | < 30 ECE-eligible rows | `SAMPLE_STARVED` report-only (exit 0); no soft pass/fail |
616
626
  | ≥ 30 ECE-eligible rows | Fit logistic + isotonic; report `holdout_ece_raw` / `holdout_ece_calibrated` |
617
627
  | Rows with `exclude_from_holdout_ece` | Counted separately; **never** enter holdout ECE metrics (weak TwinRouterBench) |
628
+ | `--include-excluded-in-fit` | Weak rows may warm-start the fit pool; `ece_eligible` / holdout ECE stay verifier-grade |
618
629
  | Soft threshold | Advisory `0.25` calibrated ECE — **does not** change `config/release-gates.json` |
619
630
 
620
- **#96 / `modernbert_k4` advisory:** when deciding whether to enable ModernBERT K=4 heads, use **pack holdout ECE / Top-1 error on verifier-grade packs** (SWE-Gym + FC-RewardBench), not fixture-only QR. Weak TwinRouterBench rows are warm-start only. This task does **not** flip `modernbert_k4` defaults.
631
+ **#96 / `modernbert_k4` advisory:** when deciding whether to enable ModernBERT K=4 heads, use **pack holdout ECE / Top-1 error on verifier-grade packs** (SWE-Gym + FC-RewardBench), not fixture-only QR and **not** weak-fit ECE. Weak TwinRouterBench rows are warm-start only. This task does **not** flip `modernbert_k4` defaults. Go/no-go evidence (SP-204 / #113): [`spine-tasks/_authoring/release-v0.11.0/encoder-gonogo-artifact.md`](spine-tasks/_authoring/release-v0.11.0/encoder-gonogo-artifact.md).
621
632
 
622
633
  ### Operator tuning (frugality slider)
623
634
 
@@ -842,10 +853,10 @@ Contributors must run `npm run build` before publishing or consuming the library
842
853
  | `npm run routing:train-calibration` | Train routing calibration artifact bundle |
843
854
  | `npm run routing:train-p-success` | Train standalone `config/p-success-weights.json` (synthetic fixture by default) |
844
855
  | `npm run routing:verify-calibration` | Verify calibration bundle against benchmark prompts |
845
- | `npm run routing:calibration-dry-run` | Pack-fed isotonic dry-run: holdout ECE on label packs (CI fixtures by default) |
856
+ | `npm run routing:calibration-dry-run` | Pack-fed isotonic dry-run: holdout ECE on label packs (CI fixtures by default); optional `--include-excluded-in-fit` |
846
857
  | `npm run routing:ingest-swe-gym` | Convert SWE-Gym verifier-style JSONL → privacy-safe label pack |
847
858
  | `npm run routing:ingest-fc-rewardbench` | Convert FC-RewardBench JSONL → privacy-safe label pack |
848
- | `npm run routing:ingest-twinrouterbench-weak` | Convert TwinRouterBench weak tier labels → pack (exclude from ECE) |
859
+ | `npm run routing:ingest-twinrouterbench-weak` | Convert TwinRouterBench weak tier labels → pack (prefer `ci-subset.json`; exclude from ECE) |
849
860
  | `npm run routing:ingest-benchmarks` | Regenerate `config/benchmark-profiles.json` from leaderboard fixtures |
850
861
  | `npm run routing:verify-benchmark-profiles` | CI smoke: assert checked-in profiles match fixture ingest |
851
862
  | `npm run routing:eval-replay` | Counterfactual replay on eval trace fixtures |
@@ -853,6 +864,10 @@ Contributors must run `npm run build` before publishing or consuming the library
853
864
  | `npm run routing:eval-harness:smoke` | Harness summary JSON only (CI smoke; no network) |
854
865
  | `npm run routing:eval-harness:corpus-smoke` | Harness summary on TwinRouterBench CI corpus subset (`tests/eval/corpus/twinrouterbench`) |
855
866
  | `npm run routing:assert-release-gates:corpus-report` | Soft-feed: assert corpus vs absolute gates with `--report-only` (exit 0; does not gate releases) |
867
+ | `npm run routing:analyze-overrouting` | TwinRouterBench over-routing breakdown by stage / reason_code / tiers (#112; see `spine-tasks/_authoring/release-v0.11.0/over-routing-analysis.md`) |
868
+ | `npm run routing:twinrouterbench:full-track` | Local/nightly: pin fetch → full convert (no `--limit`) → harness + gates `--report-only` (gitignored cache) |
869
+ | `npm run routing:twinrouterbench:full-ingest` | Convert cached `question_bank.jsonl` → full static-track JSON (no `--limit`) |
870
+ | `npm run routing:twinrouterbench:full-report` | Harness summary + gates `--report-only` on cached full track |
856
871
  | `npm run routing:ingest-twinrouterbench` | Convert TwinRouterBench `question_bank.jsonl` → CI subset / full corpus JSON |
857
872
  | `npm run routing:ingest-llmrouterbench` | Convert LLMRouterBench BaselineRecord JSONL → static-track subset JSON |
858
873
  | `npm run routing:llmrouterbench-regret` | Offline regret / CS report on vendored LLMRouterBench subset (optional; not PR CI) |
@@ -874,7 +889,7 @@ npm run routing:eval-harness
874
889
  # CI-style summary only (default fixtures under tests/eval/fixtures)
875
890
  npm run routing:eval-harness:smoke
876
891
 
877
- # TwinRouterBench CI corpus subset (≤50 code/tool records; offline)
892
+ # TwinRouterBench CI corpus subset (≤150 code/tool records; offline)
878
893
  npm run routing:eval-harness:corpus-smoke
879
894
 
880
895
  # Custom fixture directory (includes TwinRouterBench static track subdirs)
@@ -882,24 +897,45 @@ npm run routing:eval-harness -- --fixtures tests/eval/fixtures
882
897
 
883
898
  # Counterfactual replay only (SP-151)
884
899
  npm run routing:eval-replay
900
+
901
+ # Full ~970-row static track (local / nightly only — do not check JSON into git)
902
+ npm run routing:twinrouterbench:full-track
885
903
  ```
886
904
 
887
- **CI smoke:** `.github/workflows/eval-harness-smoke.yml` runs on PRs that touch eval scripts, fixtures, or the workflow. It executes `routing:eval-harness:smoke`, `routing:eval-harness:corpus-smoke`, and eval unit tests — fast, offline, no provider network calls. Job timeout stays at 10 minutes.
905
+ **CI smoke:** `.github/workflows/eval-harness-smoke.yml` runs on PRs that touch eval scripts, fixtures, or the workflow. It executes `routing:eval-harness:smoke`, `routing:eval-harness:corpus-smoke`, and eval unit tests — fast, offline, no provider network calls. Job timeout stays at 10 minutes. The optional full-track nightly (`.github/workflows/twinrouterbench-full-nightly.yml`, `schedule` + `workflow_dispatch` only) is **not** on `pull_request` and must not be configured as a required status check — failures there do not gate PR CI or `release:functional-smoke`.
888
906
 
889
907
  **TwinRouterBench static track:** import step-level router-visible prefixes with execution-verified target tiers (`track: "static"`). The adapter in `scripts/eval/twinrouterbench-adapter.ts` converts static track records into native eval fixtures for the three-track harness. See `docs/gemini-research.md` §9 for methodology context.
890
908
 
891
- #### TwinRouterBench CI corpus (SP-186 / SP-187 / SP-188)
909
+ #### TwinRouterBench CI corpus (SP-186 / SP-187 / SP-188 / SP-199)
892
910
 
893
911
  | Item | Location / command |
894
912
  |------|--------------------|
895
913
  | **Pinned upstream** | CommonstackAI/TwinRouterBench `@430acecac71141de77afd8e5e13690d236d58e93` (Apache-2.0) |
896
- | **CI subset** | `tests/eval/corpus/twinrouterbench/ci-subset.json` (≤50 code/tool records) |
914
+ | **CI subset** | `tests/eval/corpus/twinrouterbench/ci-subset.json` (≤150 code/tool records) |
897
915
  | **Provenance** | `tests/eval/corpus/twinrouterbench/PROVENANCE.md` |
898
- | **Regenerate** | `npm run routing:ingest-twinrouterbench -- --input <question_bank.jsonl> --output tests/eval/corpus/twinrouterbench/ci-subset.json --limit 50 --prefer-code-tool` |
916
+ | **Regenerate** | `npm run routing:ingest-twinrouterbench -- --input <question_bank.jsonl> --output tests/eval/corpus/twinrouterbench/ci-subset.json --limit 150 --prefer-code-tool` |
899
917
  | **Harness smoke** | `npm run routing:eval-harness:corpus-smoke` |
900
918
  | **Gate soft-feed** | `npm run routing:assert-release-gates:corpus-report` |
919
+ | **Over-routing breakdown** | `npm run routing:analyze-overrouting` · [v0.11.0 analysis](spine-tasks/_authoring/release-v0.11.0/over-routing-analysis.md) (#112 / #95) |
920
+ | **Human QA protocol** | [`docs/qa/shadow-dogfood-protocol.md`](docs/qa/shadow-dogfood-protocol.md) · `npm run qa:shadow-dogfood` |
921
+
922
+ **Absolute release gates stay on default fixtures.** `npm run release:functional-smoke` continues to assert `tests/eval/fixtures` against `config/release-gates.json` — do not point it at the corpus without operator review. Today the corpus subset fails `mean_over_routing_rate_max` (≈0.85 vs absolute max 0.15); that gap is intentional soft signal for the [#95](https://github.com/beettlle/pi-smart-router/issues/95) public static-track acceptance criteria alongside live dogfood traces. Use `--fixtures tests/eval/corpus/twinrouterbench` (or the corpus-report script) for #95 public-track scoring; keep absolute threshold edits out of band until operators approve. For live shadow dogfood steps and sign-off, see the [shadow dogfood protocol](docs/qa/shadow-dogfood-protocol.md).
901
923
 
902
- **Absolute release gates stay on default fixtures.** `npm run release:functional-smoke` continues to assert `tests/eval/fixtures` against `config/release-gates.json` — do not point it at the corpus without operator review. Today the corpus subset fails `mean_over_routing_rate_max` (≈0.85 vs absolute max 0.15); that gap is intentional soft signal for the [#95](https://github.com/beettlle/pi-smart-router/issues/95) public static-track acceptance criteria alongside live dogfood traces. Use `--fixtures tests/eval/corpus/twinrouterbench` (or the corpus-report script) for #95 public-track scoring; keep absolute threshold edits out of band until operators approve.
924
+ #### TwinRouterBench full static track (SP-200 / #107)
925
+
926
+ First-class **local / optional nightly** path for the pinned ~970-row bank. **Do not check the full JSON into git.**
927
+
928
+ | Item | Location / command |
929
+ |------|--------------------|
930
+ | **One-shot** | `npm run routing:twinrouterbench:full-track` |
931
+ | **Cache (gitignored)** | `.pi-smart-router/eval-cache/twinrouterbench/` (override with `TRB_CACHE_DIR`) |
932
+ | **Steps** | pin fetch → `routing:ingest-twinrouterbench` **without** `--limit` → harness `--summary-only` + gates `--report-only` |
933
+ | **Nightly** | `.github/workflows/twinrouterbench-full-nightly.yml` (`schedule` + `workflow_dispatch`) — advisory only |
934
+ | **Provenance** | `tests/eval/corpus/twinrouterbench/PROVENANCE.md` |
935
+
936
+ PR corpus smoke remains the vendored ≤150 subset. Absolute `config/release-gates.json` thresholds and `release:functional-smoke` stay fixture-backed.
937
+
938
+ **[#95 dual-gate protocol](https://github.com/beettlle/pi-smart-router/issues/95):** (1) live shadow dogfood (`docs/qa/shadow-dogfood-protocol.md` · `npm run qa:shadow-dogfood`) and (2) public static-track soft-feed (CI subset report, or full-track report above). Neither path edits absolute release thresholds.
903
939
 
904
940
  **Deferred:** RouterBench classic (outcome-matrix) smoke is out of scope for SP-188; prefer TwinRouterBench static track + dogfood for #95.
905
941
 
@@ -932,6 +968,12 @@ npm run routing:community-bench -- \
932
968
  --output /tmp/community-bench-report.json \
933
969
  --email-file /tmp/community-bench-report.txt
934
970
 
971
+ # Optional Track B: labeled dogfood export → harness gates (skips if incomplete — never invents labels)
972
+ npm run routing:community-bench -- \
973
+ --dogfood-export tests/eval/dogfood-track-b/synthetic-labeled-export.json \
974
+ --output /tmp/community-bench-report.json \
975
+ --email-file /tmp/community-bench-report.txt
976
+
935
977
  # Optional Track C: offline LLMRouterBench regret/CS on the vendored subset (no full HF download)
936
978
  npm run routing:community-bench -- \
937
979
  --llmrouterbench \
@@ -941,7 +983,7 @@ npm run routing:community-bench -- \
941
983
 
942
984
  **How to send:**
943
985
 
944
- 1. **Email `.txt`** — open `/tmp/community-bench-report.txt` (or your `--email-file` path). It includes a `Subject:` line, privacy blurb, fingerprint, Track A PASS/FAIL, and optional Track C metrics. Paste into your mail client; attach `community-bench-report.json` if useful. Do **not** expect the CLI to send mail.
986
+ 1. **Email `.txt`** — open `/tmp/community-bench-report.txt` (or your `--email-file` path). It includes a `Subject:` line, privacy blurb, fingerprint, Track A PASS/FAIL, and optional Track B/C metrics. Paste into your mail client; attach `community-bench-report.json` if useful. Do **not** expect the CLI to send mail.
945
987
  2. **GitHub issue** — open the [maintainer contact](https://github.com/beettlle/pi-smart-router/issues/new?labels=community-bench) URL, or run with `--print-issue-body` and paste stdout into a new issue. Issues list: https://github.com/beettlle/pi-smart-router/issues
946
988
 
947
989
  **Tracks:**
@@ -949,7 +991,7 @@ npm run routing:community-bench -- \
949
991
  | Track | Corpus | When |
950
992
  |-------|--------|------|
951
993
  | **A (required)** | [TwinRouterBench CI corpus](#twinrouterbench-ci-corpus-sp-186--sp-187--sp-188) (`tests/eval/corpus/twinrouterbench`) | Always |
952
- | **B (optional)** | Dogfood export (`--dogfood-export PATH`) | Skips with an explicit reason until [#95](https://github.com/beettlle/pi-smart-router/issues/95) adapter lands — never invents labels |
994
+ | **B (optional)** | Labeled dogfood export (`--dogfood-export PATH`) | Runs when adapter + export present with required outcome labels (`success_label`, `min_tier`, `min_model_id`); skips with an explicit reason when incomplete — never invents labels. Example: `tests/eval/dogfood-track-b/synthetic-labeled-export.json` ([#111](https://github.com/beettlle/pi-smart-router/issues/111)) |
953
995
  | **C (optional)** | [LLMRouterBench offline subset](#llmrouterbench-offline-regret-sp-192--sp-193) (`tests/eval/corpus/llmrouterbench`) | `--llmrouterbench` or `--full`; offline only |
954
996
 
955
997
  PR CI does **not** download full TwinRouterBench / LLMRouterBench corpora. Absolute gate thresholds in `config/release-gates.json` are unchanged by this CLI.
@@ -1030,6 +1072,8 @@ npm run routing:verify-benchmark-profiles
1030
1072
 
1031
1073
  Tag-triggered publish via GitHub Actions (requires `NPMSECRET` repository secret). pi.dev gallery listing syncs automatically from npm (`pi-package` keyword); no separate submit step.
1032
1074
 
1075
+ **Scope composition:** use `/skill:router-release-operator` for themed release planning (not open-ended backlog cycles). **Patch** = docs + bugfixes only; **minor** = new capability (1–3 related issues under one theme). Budgets and audit rules: [`skills/router-release-operator/references/release-profiles.md`](skills/router-release-operator/references/release-profiles.md).
1076
+
1033
1077
  **Tier 0 functional smoke** (`release:functional-smoke`) runs before tag publish and chains:
1034
1078
 
1035
1079
  1. `routing:verify-calibration --skip-embed` — artifact shape + triage benchmark gates (no ONNX embedding)
@@ -7,8 +7,8 @@
7
7
  "livecodebench": "https://livecodebench.github.io/leaderboard.html",
8
8
  "bfcl": "https://gorilla.cs.berkeley.edu/leaderboard.html"
9
9
  },
10
- "scrape_date": "2026-07-11",
11
- "catalog_freeze_date": "2026-07-11"
10
+ "scrape_date": "2026-07-12",
11
+ "catalog_freeze_date": "2026-07-12"
12
12
  },
13
13
  "aliases": {
14
14
  "claude-3-5-sonnet": "claude-sonnet-4-6",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-smart-router",
3
- "version": "0.9.3",
3
+ "version": "0.11.0",
4
4
  "description": "Auto-model router middleware for the pi.dev coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -73,6 +73,10 @@
73
73
  "routing:eval-harness:smoke": "tsx scripts/eval/run-harness.ts --summary-only",
74
74
  "routing:eval-harness:corpus-smoke": "tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only",
75
75
  "routing:assert-release-gates:corpus-report": "tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only",
76
+ "routing:analyze-overrouting": "tsx scripts/eval/analyze-twinrouterbench-overrouting.ts",
77
+ "routing:twinrouterbench:full-ingest": "bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'",
78
+ "routing:twinrouterbench:full-report": "bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'",
79
+ "routing:twinrouterbench:full-track": "bash scripts/eval/twinrouterbench-full-track.sh",
76
80
  "routing:community-bench": "tsx scripts/eval/community-bench.ts",
77
81
  "routing:ingest-twinrouterbench": "tsx scripts/eval/ingest-twinrouterbench-corpus.ts",
78
82
  "routing:ingest-llmrouterbench": "tsx scripts/eval/ingest-llmrouterbench-subset.ts",
@@ -83,6 +87,7 @@
83
87
  "routing:capture-baseline": "tsx scripts/eval/capture-baseline.ts",
84
88
  "routing:test-projection": "npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts",
85
89
  "benchmark:encoder": "tsx scripts/benchmark-encoder-latency.ts",
90
+ "qa:shadow-dogfood": "bash scripts/qa/shadow-dogfood-session.sh",
86
91
  "verify:ci": "npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check"
87
92
  },
88
93
  "peerDependencies": {
@@ -14,13 +14,23 @@ Invoke explicitly: `/skill:router-backlog-orchestrator`
14
14
  **Compose with:**
15
15
  - pi-spine `create-spine-tasks` skill — packet structure and size rules
16
16
  - [`skills/spine-autonomous-operator/SKILL.md`](../spine-autonomous-operator/SKILL.md) — preflight, wave loop, recovery, pi-spine issue filing
17
+ - [`skills/router-release-operator/SKILL.md`](../router-release-operator/SKILL.md) — themed semver release composition and publish
17
18
  - [`.cursor/rules/spine-task-authoring.mdc`](../../.cursor/rules/spine-task-authoring.mdc) — PROMPT/STATUS contracts
18
19
  - [`.cursor/rules/spine-operator-cursor.mdc`](../../.cursor/rules/spine-operator-cursor.mdc) — spine CLI reference
19
20
 
21
+ ## Skill boundaries
22
+
23
+ | Concern | Owner |
24
+ |---------|-------|
25
+ | Development **cycle** triage (docs → 3–5 bugs → 1 feature) | This skill |
26
+ | Versioned **release** composition (theme, patch/minor/major, publish) | [`router-release-operator`](../router-release-operator/SKILL.md) |
27
+
28
+ When the operator asks for a versioned release (`release v0.x.y`, `patch release`, `minor release`, `ship to npm`), **do not** invent feature-patch scopes here. Optionally write a backlog snapshot, then **hand off** to `/skill:router-release-operator`.
29
+
20
30
  ## Success criteria
21
31
 
22
32
  1. Backlog plan approved by operator before batch start
23
- 2. Documentation issues processed before bugs; feature ratio **1 per 3–5 bugs**
33
+ 2. Documentation issues processed before bugs; feature ratio **1 per 3–5 bugs** (cycle policy only)
24
34
  3. New `SP-*` packets validate (`spine tasks validate pending`)
25
35
  4. Queued scope lands on `main` via gate + integrate
26
36
  5. Linked GitHub issues commented/closed when tasks complete
@@ -32,8 +42,10 @@ Invoke explicitly: `/skill:router-backlog-orchestrator`
32
42
  - **Never** start a batch without operator approval of the backlog plan table
33
43
  - **Never** claim batch/test success without CLI output
34
44
  - **Never** create XL tasks; split epics into S/M packets
45
+ - **Never** choose npm bump type or release profile from this skill — use `router-release-operator`
35
46
  - **Always** run docs bucket completely before bug/feature ratio units
36
47
  - **Always** link packets to GitHub issues in `## Source`
48
+ - **Always** hand off versioned release requests to `router-release-operator` after optional snapshot
37
49
 
38
50
  ## Phase 0 — Baseline
39
51
 
@@ -46,6 +58,8 @@ git status && git branch --show-current # must be main
46
58
 
47
59
  Stop if not on `main` or `gh`/`spine` unavailable.
48
60
 
61
+ **Release handoff:** if the invocation names a target version or patch/minor/major **release** (not a plain backlog cycle), stop after optional snapshot and invoke [`router-release-operator`](../router-release-operator/SKILL.md).
62
+
49
63
  Optional snapshot:
50
64
 
51
65
  ```bash
@@ -90,6 +104,8 @@ Dedup:
90
104
 
91
105
  ## Phase 3 — Prioritize
92
106
 
107
+ **Applies to development cycles only** — not versioned releases (see Skill boundaries).
108
+
93
109
  **Order:**
94
110
  1. All **documentation** issues
95
111
  2. **Bugs** — user-facing / CI blockers first, then wiring/refactors; decompose epics
@@ -100,6 +116,8 @@ Dedup:
100
116
  - Then **one ratio unit**: 3–5 bugs + 1 feature
101
117
  - Repeat until operator stops or backlog empty
102
118
 
119
+ If the operator’s goal for this invocation is **ship a release**, do not expand the ratio unit into a release scope — hand off to [`router-release-operator`](../router-release-operator/SKILL.md) with the intended theme/version.
120
+
103
121
  ## Phase 4 — Operator approval
104
122
 
105
123
  Present a **Backlog Plan** table before any writes:
@@ -143,6 +161,8 @@ Hand off to [`skills/spine-autonomous-operator/SKILL.md`](../spine-autonomous-op
143
161
 
144
162
  Do not advance waves until current wave is integrated on `main`.
145
163
 
164
+ If this cycle’s approved plan is explicitly a **release ship** (version bump / npm publish), stop cycle execution and continue under [`router-release-operator`](../router-release-operator/SKILL.md) (manifest, theme audit, `release:check`, publish gates).
165
+
146
166
  ## Phase 7 — Issue filing
147
167
 
148
168
  | Situation | Repo | Action |
@@ -177,7 +197,8 @@ Do not claim orchestrator success unless `npm run verify:ci` exits 0 and the tab
177
197
  ## Short prompt (resume)
178
198
 
179
199
  ```text
180
- Run router-backlog-orchestrator: collect GitHub + spine backlog classify
200
+ Run router-backlog-orchestrator: if operator asked for release vX.Y.Z / patch|minor,
201
+ hand off to router-release-operator. Else: collect GitHub + spine backlog → classify →
181
202
  prioritize (docs first, 3-5 bugs + 1 feature) → show plan → author SP packets →
182
203
  spine preflight → batch waves → file issues → final report.
183
204
  ```
@@ -2,6 +2,8 @@
2
2
 
3
3
  Use when classifying and ordering work in `router-backlog-orchestrator`.
4
4
 
5
+ **Scope:** development **cycle** planning only. Do **not** choose npm bump type (patch/minor/major) or release composition from this rubric — use [`router-release-operator` release profiles](../../router-release-operator/references/release-profiles.md).
6
+
5
7
  ## Buckets
6
8
 
7
9
  ### documentation
@@ -33,11 +35,14 @@ Use when classifying and ordering work in `router-backlog-orchestrator`.
33
35
 
34
36
  ## Feature-to-bug ratio
35
37
 
36
- After documentation bucket is empty for this cycle:
38
+ **Cycle policy** (not a release profile). After documentation bucket is empty for this cycle:
37
39
 
38
40
  - Queue **3 to 5 bugs**, then **exactly 1 feature**
39
41
  - One **ratio unit** per orchestrator invocation (default)
40
- - If fewer than 3 bugs remain, queue remaining bugs + 1 feature (or 0 features if none left)
42
+ - If fewer than 3 bugs remain, queue remaining bugs + at most 1 feature (or 0 features if none left)
43
+ - Empty or short bug queues are normal — do not invent fake bugs to fill a 3–5 quota for a **cycle**
44
+
45
+ Shipping that work as an npm version is a separate step: hand off to `router-release-operator` (patch = docs+bugs only; enhancements require **minor** + theme).
41
46
 
42
47
  ## Dedup rules
43
48
 
@@ -0,0 +1,292 @@
1
+ ---
2
+ name: router-release-operator
3
+ description: >-
4
+ End-to-end pi-smart-router release operator. Intakes GitHub issues and pending
5
+ spine tasks, composes a themed semver-profiled release (patch = docs+bugs only;
6
+ enhancements require minor), authors/audits packets, executes waves, and
7
+ publishes after operator approval. Use when asked to run a router release,
8
+ release vX.Y.Z, patch/minor/major for pi-smart-router, or ship to npm.
9
+ disable-model-invocation: true
10
+ compatibility: Requires gh CLI, spine CLI, git, Node >= 20. Run from pi-smart-router repo root on main.
11
+ ---
12
+
13
+ # Router Release Operator
14
+
15
+ You are the **pi-smart-router release operator**. Drive a **curated, themed release** from intake through publish: select work by **local** semver profiles, author/audit packets, execute batches, verify, and bump version — with **operator approval** before publish.
16
+
17
+ Invoke explicitly: `/skill:router-release-operator` or "release v0.10.0" / "patch release" / "minor release".
18
+
19
+ **Not** for executing all pending tasks or open-ended backlog cycles — use [`router-backlog-orchestrator`](../router-backlog-orchestrator/SKILL.md) for development cycles. This skill selects a **subset** fitting the release profile and theme.
20
+
21
+ ## Skill boundaries
22
+
23
+ | Concern | Delegate to |
24
+ |---------|-------------|
25
+ | Semver scope budgets / theme audit | [references/release-profiles.md](references/release-profiles.md) (**this repo — not pi-spine**) |
26
+ | Issue intake | [references/issue-intake-checklist.md](references/issue-intake-checklist.md) |
27
+ | Manifest format | [references/release-manifest-template.md](references/release-manifest-template.md) |
28
+ | PROMPT/STATUS/Contract authoring | `create-spine-tasks` + [packet-from-issue.md](../router-backlog-orchestrator/references/packet-from-issue.md) |
29
+ | Batch land / recovery / detached policy | pi-spine `spine-release-operator` Phase 4+ **or** `spine-autonomous-operator` + [`.cursor/rules/spine-operator-cursor.mdc`](../../.cursor/rules/spine-operator-cursor.mdc) |
30
+ | Cycle triage (docs → bugs → features) | [`router-backlog-orchestrator`](../router-backlog-orchestrator/SKILL.md) — hand off **here** when operator asks for a versioned release |
31
+
32
+ ## Success criteria
33
+
34
+ 1. Release manifest written with **theme** and operator-approved scope
35
+ 2. Profile audit **PASS** (or PASS with cap override only — never feature-in-patch OVERRIDE)
36
+ 3. All **release-scoped** tasks `.DONE` and integrated on `main`
37
+ 4. `spine preflight` green; **`npm run release:check` green (blocking)** on current `main`
38
+ 5. **CI workflow green on `HEAD`** before tag push
39
+ 6. Operator explicitly approved publish; version bumped and tag pushed (if approved)
40
+ 7. Final report with theme, composition table, deferred backlog, verification output
41
+
42
+ ## Hard rules
43
+
44
+ - **Never** hand-edit `.spine/batch-state.json` or `.spine/runtime/**`
45
+ - **Never** ship enhancements in a **patch** — reclassify as **minor** or drop (no OVERRIDE theater)
46
+ - **Never** omit the release **theme** or select work that contradicts it
47
+ - **Never** treat empty open-bug queue as audit failure — use `PASS (no open bugs)`
48
+ - **Never** run `npm version` or `git push --tags` without explicit operator approval
49
+ - **Never** run `npm version` / tag push when `npm run release:check` exits non-zero on current `main`
50
+ - **Never** run `npm version` / tag push when CI is not green on current `HEAD`
51
+ - **Always** parse target version / bump type **before** task selection (Phase 2)
52
+ - **Always** use [references/release-profiles.md](references/release-profiles.md) for budgets (not pi-spine profiles)
53
+ - **Always** prioritize documentation before enhancements within the theme
54
+ - **Always** run `spine gate approve` before `spine integrate`
55
+ - **Always** run `npm install` on `main` after successful integrate
56
+ - **Always** run post-integrate `npm run release:check` on `main` after each wave before the next wave or push
57
+ - **Never** judge `release:check` from `| tail` / `| head` alone — verify exit code
58
+ - **Do not** execute tasks outside the approved manifest scope
59
+ - **Do not** start a second batch while another is **running** on this repo
60
+ - **Release batches:** prefer detached `spine batch start|resume` (omit `--attached`); see spine-operator rules
61
+
62
+ ---
63
+
64
+ ## Pre-work — GitNexus index (recommended)
65
+
66
+ ```bash
67
+ cd <repo-root>
68
+ # Prefer: node .gitnexus/run.cjs analyze OR npx gitnexus analyze
69
+ gitnexus status # when available — Status up-to-date with HEAD
70
+ ```
71
+
72
+ If analyze fails, report and continue only if operator accepts stale index risk.
73
+
74
+ ---
75
+
76
+ ## Phase 0 — Baseline and target version
77
+
78
+ ```bash
79
+ cd <repo-root> # pi-smart-router root
80
+ spine --version && spine doctor
81
+ node -p "require('./package.json').version"
82
+ git status
83
+ git branch --show-current # must be main
84
+ ```
85
+
86
+ **Parse invocation** for target version or bump type — see [release-profiles.md](references/release-profiles.md).
87
+
88
+ If not on `main`, stop. If git is dirty, commit or stash hygiene before release work.
89
+
90
+ ---
91
+
92
+ ## Phase 1 — Intake inventory
93
+
94
+ Follow [references/issue-intake-checklist.md](references/issue-intake-checklist.md).
95
+
96
+ **GitHub** (`beettlle/pi-smart-router` only):
97
+
98
+ ```bash
99
+ gh issue list --repo beettlle/pi-smart-router --state open --limit 100 \
100
+ --json number,title,labels,body
101
+ ```
102
+
103
+ **Pending tasks:**
104
+
105
+ ```bash
106
+ spine plan pending
107
+ spine tasks validate pending
108
+ spine tasks analyze pending
109
+ rg 'GitHub: beettlle/pi-smart-router#|Closes:|Partial:' spine-tasks/*/PROMPT.md
110
+ ```
111
+
112
+ Read `spine-tasks/CONTEXT.md` for `Next Task ID`. Skim `docs/routing-roadmap.md` for enhancement priority.
113
+
114
+ **Output:** intake table (issue #, labels, mapped SP-* or gap, bucket, theme fit, profile fit).
115
+
116
+ ---
117
+
118
+ ## Phase 2 — Compose release manifest
119
+
120
+ Write:
121
+
122
+ ```
123
+ spine-tasks/_authoring/release-v{TARGET}/manifest.md
124
+ ```
125
+
126
+ Use [references/release-manifest-template.md](references/release-manifest-template.md).
127
+
128
+ ### Selection order (strict)
129
+
130
+ 1. State the **theme** (one sentence)
131
+ 2. **Documentation** fitting the theme
132
+ 3. **Bug fixes** (all high-impact that fit the cap; 0 OK)
133
+ 4. **Enhancements** — only if profile is minor/major; 1–3 related issues completing the theme
134
+ 5. **Defer** everything else with one-line rationale
135
+
136
+ Apply [release-profiles.md](references/release-profiles.md) budgets. **FAIL** if enhancements appear under patch — ask operator to bump to minor or drop features.
137
+
138
+ ### Operator gate
139
+
140
+ Present:
141
+
142
+ - Target version, profile, **theme**
143
+ - Selected SP-* / issues by bucket
144
+ - Deferred count + reasons
145
+ - Profile audit status
146
+
147
+ Require explicit **"approve release scope"** before Phase 3.
148
+
149
+ ---
150
+
151
+ ## Phase 3 — Author gaps and audit packets
152
+
153
+ ### 3.1 Author new tasks (gaps only)
154
+
155
+ For issues in manifest without SP-*:
156
+
157
+ - Follow `create-spine-tasks` (lean) + [packet-from-issue.md](../router-backlog-orchestrator/references/packet-from-issue.md)
158
+ - Link GitHub in `## Source`; Mission `Closes: #NNN` or `Partial:`
159
+ - Size S/M; ≤4 impl steps; Contract + Testing step
160
+ - Update `dependencies.json`, `CONTEXT.md`, `Next Task ID`
161
+ - Serialize hot files: `.pi/extensions/smart-router/index.ts`, `src/domain/pipeline/router-pipeline.ts`, `src/api/middleware/pi-router-middleware.ts`
162
+
163
+ ### 3.2 Audit release-scoped packets
164
+
165
+ | Size | Action |
166
+ |------|--------|
167
+ | **S** | Keep if ≤4 impl steps |
168
+ | **M** | OK if disjoint; in patch only for bug-fix decomposition |
169
+ | **L/XL** | **Split** before inclusion |
170
+
171
+ ```bash
172
+ spine tasks validate <release-scope>
173
+ spine tasks analyze <release-scope>
174
+ spine plan <release-scope>
175
+ ```
176
+
177
+ ### 3.3 Commit packet changes
178
+
179
+ ```bash
180
+ git add spine-tasks/
181
+ git commit -m "chore(spine): release v{TARGET} task packets"
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Phase 4 — Execute release scope
187
+
188
+ Delegate wave start / monitor / land / recovery to pi-spine **spine-release-operator** Phase 4 (or spine-autonomous-operator) with these **repo-specific** gates:
189
+
190
+ **Scope:** manifest tasks only — comma-separated release scope ID list.
191
+
192
+ ```bash
193
+ spine preflight
194
+ spine run sequence <release-scope> --dry-run
195
+ ```
196
+
197
+ For each wave until release-scoped tasks are `.DONE`:
198
+
199
+ 1. Detached `spine batch start <release-scope> --wave N` (omit `--attached` unless persistent interactive terminal)
200
+ 2. `spine status --diagnose` / `spine wait`
201
+ 3. Land: `spine gate approve` → `spine integrate` → `npm install` → `spine batch complete`
202
+ 4. **Post-integrate regression gate (blocking):**
203
+
204
+ ```bash
205
+ npm run release:check 2>&1 | tee /tmp/pi-smart-router-post-integrate-wave-${N}.log
206
+ test "${PIPESTATUS[0]}" -eq 0
207
+ ```
208
+
209
+ Do **not** start wave N+1, push, or publish until exit 0. Fix on `main` and re-run if failed.
210
+
211
+ Wave sizing: ≤4 M-sized tasks per wave; serialize hot shared files.
212
+
213
+ ---
214
+
215
+ ## Phase 5 — Pre-publish verification (STOP)
216
+
217
+ ```bash
218
+ spine plan <release-scope> # 0 pending for scope
219
+ spine preflight
220
+ npm run release:check 2>&1 | tee /tmp/pi-smart-router-release-check.log
221
+ test "${PIPESTATUS[0]}" -eq 0
222
+ ```
223
+
224
+ **If non-zero:** STOP. Fix on `main`, re-run Phase 5. Do not ask for publish approval.
225
+
226
+ Present checklist (only after exit 0):
227
+
228
+ - [ ] All release-scoped tasks done
229
+ - [ ] Theme + profile audit still accurate
230
+ - [ ] `npm run release:check` exit 0
231
+ - [ ] CI green on `HEAD` (`gh run list --workflow ci.yml --commit "$(git rev-parse HEAD)"`)
232
+ - [ ] Clean git tree
233
+ - [ ] Bump type matches Phase 2 profile
234
+
235
+ **Human gate:** do not bump or push until operator approves publish **and** Phase 5 passed.
236
+
237
+ ---
238
+
239
+ ## Phase 6 — Publish (after approval only)
240
+
241
+ **Prerequisites:** Phase 5 `release:check` exit 0; CI green on `HEAD`; operator said approve publish + confirmed bump type.
242
+
243
+ ```bash
244
+ COMMIT=$(git rev-parse HEAD)
245
+ gh run list --workflow ci.yml --commit "$COMMIT" --json databaseId,conclusion,status --limit 5
246
+ # Fail closed unless conclusion: success
247
+
248
+ npm version patch # or minor / major — must match Phase 2
249
+ git push && git push --tags
250
+ gh run list --workflow release.yml --limit 3
251
+ ```
252
+
253
+ Post-publish:
254
+
255
+ ```bash
256
+ npm view pi-smart-router version
257
+ # optional: pi install npm:pi-smart-router@<version>
258
+ ```
259
+
260
+ Update `spine-tasks/CONTEXT.md` release note. Close GitHub issues where acceptance was met (`Closes:`).
261
+
262
+ ---
263
+
264
+ ## Final report (required)
265
+
266
+ 1. Manifest path, target version, profile, **theme**, composition table
267
+ 2. Tasks completed — SP-IDs, waves, issues closed
268
+ 3. Deferred backlog — count and top items
269
+ 4. Profile audit result (no feature-in-patch OVERRIDE)
270
+ 5. Verification — `release:check` log path / exit code; CI run URL
271
+ 6. Publish — version bumped (Y/N), tag, workflow URL, or awaiting approval
272
+
273
+ ## Repo-specific notes
274
+
275
+ | Item | Value |
276
+ |------|-------|
277
+ | Tasks root | `spine-tasks/` |
278
+ | Issues repo | `beettlle/pi-smart-router` |
279
+ | Profiles | `skills/router-release-operator/references/release-profiles.md` |
280
+ | Pre-publish gate | `npm run release:check` |
281
+ | Publish | Tag-triggered `.github/workflows/release.yml` |
282
+
283
+ ## Short prompt (resume mid-release)
284
+
285
+ ```text
286
+ Resume router release v{TARGET}: check manifest at
287
+ spine-tasks/_authoring/release-v{TARGET}/manifest.md (theme + profile audit) →
288
+ spine status --diagnose → preflight → for each wave: batch start → diagnose →
289
+ gate approve → integrate → npm install → batch complete →
290
+ post-integrate release:check (exit 0) → final release:check → CI green on HEAD →
291
+ STOP for publish approval. Post final report with theme and composition table.
292
+ ```
@@ -0,0 +1,113 @@
1
+ # Issue intake checklist (pi-smart-router)
2
+
3
+ Run during **Phase 1** before composing the release manifest.
4
+
5
+ ## GitHub queries
6
+
7
+ Repo: `beettlle/pi-smart-router`
8
+
9
+ ```bash
10
+ gh issue list --repo beettlle/pi-smart-router --state open --limit 100 \
11
+ --json number,title,labels,body
12
+
13
+ gh issue list --repo beettlle/pi-smart-router --state open --label documentation \
14
+ --json number,title,labels
15
+
16
+ gh issue list --repo beettlle/pi-smart-router --state open --label bug \
17
+ --json number,title,labels
18
+
19
+ gh issue list --repo beettlle/pi-smart-router --state open --label enhancement \
20
+ --json number,title,labels
21
+ ```
22
+
23
+ ## Label taxonomy
24
+
25
+ | Label | Release bucket | Priority notes |
26
+ |-------|----------------|----------------|
27
+ | `documentation` | Documentation | Highest — address before enhancements when theme allows |
28
+ | `bug` | Bug fix | Prefer user-impact, reproducible, already-tasked |
29
+ | `enhancement` | Enhancement | Minor/major only; zero per patch |
30
+ | Priority in title/body (P0–P3) | Any | Prefer P0/P1 dogfood over P3 eval when choosing among enhancements |
31
+
32
+ ## Roadmap and theme fit
33
+
34
+ Read [`docs/routing-roadmap.md`](../../../docs/routing-roadmap.md) before selecting enhancements.
35
+
36
+ | Kind | Examples | Theme wording |
37
+ |------|----------|---------------|
38
+ | User-facing routing | Pinning, triage, local_zero, dogfood fixes | Name the user-visible behavior |
39
+ | Eval / infra | Corpora, benches, release gates soft-feed | Name the eval/tooling track; do not mix with unrelated dogfood unless one theme |
40
+
41
+ When multiple enhancements compete, prefer P0/P1 dogfood / routing quality over P3 bench/community work unless the operator sets an eval theme.
42
+
43
+ ## Issue → task mapping
44
+
45
+ 1. Grep pending and done tasks for issue links:
46
+
47
+ ```bash
48
+ rg 'GitHub: beettlle/pi-smart-router#|Closes:|Partial:' spine-tasks/*/PROMPT.md
49
+ ```
50
+
51
+ 2. Classify each open issue:
52
+
53
+ | State | Action |
54
+ |-------|--------|
55
+ | Mapped to pending SP-* | Candidate for manifest if fits profile + theme |
56
+ | Mapped to `.DONE` SP-* | Closed by shipped work — exclude |
57
+ | No SP-* yet | **Gap** — author with `create-spine-tasks` in Phase 3 |
58
+ | Epic / `[Epic]` in title | Defer unless major profile with operator approval |
59
+ | Hardware (#1/#25/#26) | Defer — physical access |
60
+
61
+ ## Documentation issue heuristics
62
+
63
+ Prefer for release inclusion when:
64
+
65
+ - `label:documentation` or title/body is README, quickstart, operator guide, env vars
66
+ - Pending SP-* with docs-only File Scope
67
+ - Docs required to ship the release theme (minor)
68
+
69
+ ## Bug issue heuristics
70
+
71
+ Prefer when:
72
+
73
+ - Repro steps in issue body or linked diagnosis
74
+ - Already has pending SP-* linked to the GitHub issue
75
+ - S/M size, disjoint file scope from parallel neighbors
76
+ - User-visible failure (routing, failover, pin, install)
77
+
78
+ Exclude when:
79
+
80
+ - Fixed on `main` but issue not closed
81
+ - Blocked by epic infrastructure not in this release
82
+
83
+ If **no open bugs**, record that for audit — do not invent OVERRIDE.
84
+
85
+ ## Enhancement issue heuristics
86
+
87
+ **Patch profile:** exclude all. If operator wants them, **reclassify release as minor**.
88
+
89
+ **Minor profile:** pick 1–3 **related** issues that complete the theme:
90
+
91
+ - User-visible or operator-visible improvement
92
+ - S/M size; split L/XL first
93
+ - Disjoint `fileScopeMustChange` from bug tasks in same wave
94
+ - Prefer roadmap P0/P1 over P3 when both fit
95
+
96
+ ## Pending task inventory
97
+
98
+ ```bash
99
+ spine plan pending
100
+ spine tasks validate pending
101
+ spine tasks analyze pending
102
+ ```
103
+
104
+ Read `spine-tasks/CONTEXT.md` for `Next Task ID` and phase notes.
105
+
106
+ Cross-reference pending SP-* with open issues. The release executes **manifest scope only**, not all pending tasks.
107
+
108
+ ## Intake output table
109
+
110
+ | Issue # | Labels | Mapped SP-* | Bucket | Theme fit | Profile fit | Notes |
111
+ |---------|--------|-------------|--------|-----------|-------------|-------|
112
+ | #97 | bug | SP-176 | bug | dogfood ✓ | minor ✓ | triage fix |
113
+ | #101 | enhancement | — | enh | eval corpus | patch ✗ → use minor | TwinRouterBench |
@@ -0,0 +1,117 @@
1
+ # Release manifest — v{TARGET_VERSION}
2
+
3
+ **Created:** {YYYY-MM-DD}
4
+ **Current version:** {from package.json}
5
+ **Target version:** v{TARGET_VERSION}
6
+ **Bump type:** patch | minor | major
7
+ **Profile:** patch | minor | major
8
+ **Theme:** {one sentence — required}
9
+ **Operator approved scope:** no | yes ({date})
10
+
11
+ ---
12
+
13
+ ## Composition audit
14
+
15
+ | Bucket | Selected | Profile limit | Status |
16
+ |--------|----------|---------------|--------|
17
+ | Theme | {sentence} | required | PASS / FAIL |
18
+ | Documentation | {n} | patch 0–2 / minor theme docs | PASS / WARN |
19
+ | Bug fixes | {n} | soft; 0 OK if none open | PASS / PASS (no open bugs) / WARN |
20
+ | Enhancements | {n} | patch **0** / minor 1–3 related | PASS / FAIL |
21
+ | **Total tasks** | {n} | patch ≤8 / minor ≤15 | PASS / WARN |
22
+
23
+ **Profile audit:** PASS | PASS with operator override (caps only) | FAIL (do not proceed)
24
+
25
+ **Hygiene (patch only, if any):** {one-line justification or "none"}
26
+
27
+ ---
28
+
29
+ ## Selected tasks
30
+
31
+ | SP-ID | Issue | Bucket | Size | Title | Notes |
32
+ |-------|-------|--------|------|-------|-------|
33
+ | SP-### | #NNN | doc / bug / enh | S/M | … | Closes / Partial |
34
+
35
+ **Release scope ID:** comma-separated SP-IDs for `spine plan`, `spine batch start`, and `spine run sequence` (e.g. `SP-196,SP-197,SP-199`). No spaces.
36
+
37
+ ---
38
+
39
+ ## Sequence runner (Phase 4)
40
+
41
+ The manifest is the operator contract; the CLI takes the **scope ID string**, not the manifest file path.
42
+
43
+ ```bash
44
+ spine tasks validate <SP-IDs...>
45
+ spine plan <release-scope-id>
46
+ spine run sequence <release-scope-id> --dry-run
47
+ spine run sequence <release-scope-id> # detached — omit --attached
48
+ ```
49
+
50
+ Per-wave manual loop (alternative to full sequence):
51
+
52
+ ```bash
53
+ spine batch start <release-scope-id> --wave N
54
+ spine status --diagnose
55
+ spine gate approve && spine integrate && npm install && spine batch complete
56
+ ```
57
+
58
+ **Regression gate** (after each integrate, before next wave):
59
+
60
+ ```bash
61
+ npm run release:check 2>&1 | tee /tmp/pi-smart-router-post-integrate-wave-${WAVE:-main}.log
62
+ test "${PIPESTATUS[0]}" -eq 0
63
+ ```
64
+
65
+ Do **not** use `| tail` alone for pass/fail — verify exit code.
66
+
67
+ **Operator gates** (human only):
68
+
69
+ 1. Approve this manifest (operator sign-off on scope + theme)
70
+ 2. `spine gate approve` per integrate wave
71
+ 3. Publish approval before `npm version <bump>`
72
+
73
+ ---
74
+
75
+ ## Gaps requiring new packets
76
+
77
+ | Issue | Bucket | Proposed SP-ID | Author with |
78
+ |-------|--------|----------------|-------------|
79
+ | #90 | doc | SP-### | create-spine-tasks (lean) |
80
+
81
+ ---
82
+
83
+ ## Wave plan snapshot
84
+
85
+ ```text
86
+ (paste output of: spine plan <release-scope>)
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Deferred backlog
92
+
93
+ | Item | Type | Rationale |
94
+ |------|------|-----------|
95
+ | SP-### / #NNN | enh | Outside theme; defer to next minor |
96
+ | #1 / #25 / #26 | epic | Hardware — blocked on physical access |
97
+
98
+ ---
99
+
100
+ ## Risks and blockers
101
+
102
+ - {e.g. hot-file serialization on router-pipeline.ts}
103
+ - {e.g. release:check flaky assert — fix before tag}
104
+
105
+ ---
106
+
107
+ ## Publish checklist (Phase 5–6)
108
+
109
+ - [ ] All release-scoped tasks `.DONE` on `main`
110
+ - [ ] Post-integrate `release:check` green after **each wave** (log paths recorded)
111
+ - [ ] `spine preflight` green
112
+ - [ ] `npm run release:check` green on final `HEAD` (exit 0 verified)
113
+ - [ ] CI workflow green on `HEAD` (`gh run list` / `gh run watch`)
114
+ - [ ] `git status` clean
115
+ - [ ] Operator approved publish bump type: patch | minor | major (matches Phase 2)
116
+ - [ ] `npm version <bump>` + `git push && git push --tags`
117
+ - [ ] `release.yml` succeeded; `npm view pi-smart-router version` matches target
@@ -0,0 +1,127 @@
1
+ # Release profiles (pi-smart-router)
2
+
3
+ Use at **Phase 2** after parsing the operator's target version. Compare `package.json` version to the target to derive bump type.
4
+
5
+ These budgets **replace** pi-spine `spine-release-operator` profile math for this repo. Batch land / publish mechanics still follow spine-release-operator or spine-autonomous-operator.
6
+
7
+ ## Derive bump type
8
+
9
+ | Current → Target | Bump type | Profile |
10
+ |------------------|-----------|---------|
11
+ | `0.9.3` → `0.9.4` | **patch** | `patch` |
12
+ | `0.9.3` → `0.10.0` | **minor** | `minor` |
13
+ | `0.10.0` → `1.0.0` | **major** | `major` |
14
+
15
+ If the operator says only `patch` / `minor` / `major` without a version, compute the next version from `package.json` and record both in the manifest.
16
+
17
+ ## Invocation parsing
18
+
19
+ | Operator says | Profile |
20
+ |---------------|---------|
21
+ | "release for v0.9.4", "patch release", "hotfix release" | `patch` |
22
+ | "release for v0.10.0", "minor release", "feature release" | `minor` |
23
+ | "release for v1.0.0", "major release", "breaking release" | `major` |
24
+ | "run a router release cycle" (no version) | **Ask** operator for target version or bump type |
25
+
26
+ ## Theme (all profiles)
27
+
28
+ Every release **requires** a one-sentence **theme** in the manifest (e.g. "Dogfood routing fixes", "Eval corpora & community bench", "Stability hotfix").
29
+
30
+ - Selected issues/tasks must **complete or clearly serve** that theme.
31
+ - Prefer **sibling clusters** that finish the theme over thin single-issue versions.
32
+ - Theme missing or selected work contradicts the theme → **FAIL** (do not proceed).
33
+
34
+ ## Profile budgets
35
+
36
+ ### Patch (`patch`)
37
+
38
+ Stability and correctness only. No new capability.
39
+
40
+ | Bucket | Target | Hard limits |
41
+ |--------|--------|-------------|
42
+ | Theme | Required (stability / hotfix) | Must match selected work |
43
+ | Documentation | 0–2 clarifications | No new feature docs; defer large doc epics |
44
+ | Bug fixes | Soft target 1–5 high-impact | Include open high-impact bugs that fit the cap; **0 OK** when none open |
45
+ | Enhancements | **0** | **Hard fail** if any enhancement included — reclassify as minor or drop |
46
+ | Total tasks | **≤8** | WARN if >8; proceed only with operator override that keeps bump type honest |
47
+ | Max waves | 1–2 | Prefer single wave when possible |
48
+ | Task sizes | S preferred; M OK | M allowed only for bug-fix decomposition with disjoint scope; split L/XL |
49
+
50
+ **Hygiene exception (patch only):** non-user-facing fixes (typo, flake clock, lint-only) allowed with a **one-line justification** in the manifest. Still **no** new capability.
51
+
52
+ **Defer by default:** all enhancements, roadmap items, eval/infra features, epics, hardware.
53
+
54
+ ### Minor (`minor`)
55
+
56
+ One capability theme plus related stability work.
57
+
58
+ | Bucket | Target | Hard limits |
59
+ |--------|--------|-------------|
60
+ | Theme | Required (capability name) | Sibling issues that complete the theme preferred |
61
+ | Documentation | Docs for the theme | Include operator-facing docs for shipped capability |
62
+ | Bug fixes | Open high-impact that fit | Soft; **0 OK** when no open bugs (`PASS (no open bugs)`) |
63
+ | Enhancements | **1–3 related** issues | Must serve the theme; defer unrelated P2/P3 |
64
+ | Total tasks | **≤15** | WARN if >15 without override |
65
+ | Max waves | 2–4 | ≤4 M-sized tasks per wave |
66
+ | Task sizes | S/M | Split L/XL before inclusion |
67
+
68
+ **Defer by default:** unrelated roadmap slices, hardware epics, work needing >4 waves.
69
+
70
+ **Priority among enhancements:** prefer [`docs/routing-roadmap.md`](../../../docs/routing-roadmap.md) P0/P1 dogfood over P3 eval when choosing what completes the theme.
71
+
72
+ ### Major (`major`)
73
+
74
+ Breaking changes and large migrations (e.g. 1.0 readiness). Operator-defined epic scope.
75
+
76
+ | Bucket | Target | Hard limits |
77
+ |--------|--------|-------------|
78
+ | Theme | Required (breaking / 1.0) | Explicit epic boundaries in manifest |
79
+ | Documentation | Migration guides + comprehensive pass | Required for breaking changes |
80
+ | Bug fixes | Critical blockers | Prioritize regressions blocking migration |
81
+ | Enhancements | Multiple allowed | Breaking API changes OK with migration path |
82
+ | Total tasks | Operator-defined | Manifest must list epic boundaries |
83
+ | Max waves | Planned in manifest | Expect multi-cycle execution |
84
+
85
+ **Require:** explicit operator approval of epic scope before Phase 3. Do not auto-select major scope from backlog alone.
86
+
87
+ ## Selection order (all profiles)
88
+
89
+ Apply in this order; stop when profile budget is full:
90
+
91
+ 1. **Documentation** — `label:documentation`, README/operator-guide clarifications fitting the theme
92
+ 2. **Bug fixes** — open `label:bug` with user impact; prefer already-tasked or quick S/M
93
+ 3. **Enhancements** — **minor/major only**; only theme-completing related issues
94
+ 4. **Defer** everything else with one-line rationale
95
+
96
+ ## Profile audit (must pass before Phase 3)
97
+
98
+ | Check | Patch | Minor | Major |
99
+ |-------|-------|-------|-------|
100
+ | Theme present and coherent | Required | Required | Required |
101
+ | Enhancement count | **>0 → FAIL** (reclassify or drop) | >3 without override → WARN | — |
102
+ | Bug count | 0 + no open bugs → **PASS (no open bugs)**; open bugs skipped without deferral → WARN | Same | Critical blockers skipped → WARN |
103
+ | Total tasks | >8 → WARN | >15 → WARN | — |
104
+ | M/L in patch | L/XL → split; M only for bug-fix decomposition | — | — |
105
+ | Bump type vs content | Features in scope → must be **minor**, not patch OVERRIDE | — | — |
106
+
107
+ **Do not** use OVERRIDE to ship enhancements as patch. Change bump type to minor or drop the enhancement.
108
+
109
+ Record `Profile audit: PASS` or `PASS with operator override` (caps/waves only; never for feature-in-patch) before proceeding.
110
+
111
+ ## Version ↔ publish alignment
112
+
113
+ The bump type chosen in Phase 2 must match `npm version` in Phase 6:
114
+
115
+ - `patch` profile → `npm version patch`
116
+ - `minor` profile → `npm version minor`
117
+ - `major` profile → `npm version major`
118
+
119
+ If the operator changes bump type at publish gate, update the manifest and confirm scope still fits the new profile.
120
+
121
+ ## Sanity checks (read-through)
122
+
123
+ | Proposal | Result |
124
+ |----------|--------|
125
+ | Ship #106 + #107 as **patch** | **FAIL** — enhancements; recommend **minor** with theme e.g. "TwinRouterBench fit & CI track" |
126
+ | Hotfix only open bugs as **patch**, theme "Stability hotfix" | **PASS** |
127
+ | Feature-only minor, 0 open bugs, theme "Live leaderboard ingest" | **PASS (no open bugs)** |