pi-smart-router 0.10.0 → 0.12.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
@@ -473,7 +473,7 @@ See [routing-roadmap.md](docs/routing-roadmap.md) §2 P2 and GitHub [#78](https:
473
473
 
474
474
  ### P(success) training export (baseline classifier)
475
475
 
476
- When `SMART_ROUTER_DATASET=1`, the router records privacy-safe dataset rows and behavioral outcome labels (model override, compaction pin break, `/smart-router feedback good|bad`). Export labeled training data from pi:
476
+ When `SMART_ROUTER_DATASET=1`, the router records privacy-safe dataset rows and behavioral outcome labels. Export labeled training data from pi:
477
477
 
478
478
  ```bash
479
479
  /smart-router export dataset [--limit N]
@@ -481,23 +481,62 @@ When `SMART_ROUTER_DATASET=1`, the router records privacy-safe dataset rows and
481
481
 
482
482
  Each JSONL row joins dataset features with `success_label` and `outcome_signals`. Success means no negative outcome signals were recorded for that `request_id` (for example `model_override` or `feedback_bad` mark failure). Prompt plaintext is never included.
483
483
 
484
- **Dogfood artifact (SP-175):** the repo ships a non-example `config/p-success-weights.json` trained on the synthetic fixture at `scripts/fixtures/p-success-synthetic-train.jsonl` (**provenance: synthetic/fixture**, not community contrib — 40 labeled feature-vector rows, no prompt text). With `trained_sample_count ≥ 30`, the low-intensity gate uses trained logistic scores instead of neutral `0.5`. Missing or invalid artifacts still fall back safely to neutral defaults.
484
+ #### Behavioral-first bootstrap (zero manual labels)
485
485
 
486
- **Operator train / reload (no prompt text):**
486
+ Primary path for [#110](https://github.com/beettlle/pi-smart-router/issues/110) (docs slice).
487
+
488
+ Manual `/smart-router feedback good|bad` is **optional**. Passive dogfood signals already captured under `SMART_ROUTER_DATASET=1` (and privacy-safe telemetry-contrib export) are sufficient to train when you have enough rows:
489
+
490
+ | Passive field / signal | Role |
491
+ |------------------------|------|
492
+ | `model_override` | Failure — operator overrode the routed model |
493
+ | `compaction_pin_break` | Neutral/positive context — pin broke at compaction (not a cheap-tier failure by itself) |
494
+ | Loop-escalation proxies (`tool_failure_chain`, pin reason `loop_escalation`) | Failure proxies for stuck tool loops |
495
+ | `stop_reason` / `stop_reason_invalid` / `stop_reason_length` | Execution outcome — invalid or truncated stops mark failure |
496
+
497
+ Optional `feedback_good` / `feedback_bad` only refine labels when the operator chooses to annotate; they are not required for a valid train path. **Do not invent labels** — incomplete exports skip or stay unlabeled rather than fabricating outcomes.
498
+
499
+ **Sample floor:** collect at least **≥30** labeled **economical-tier** rows (`minimum_training_samples.p_success_weights` / `isotonic_calibrator` in [`config/routing-calibration.json.example`](config/routing-calibration.json.example)) before relying on non-neutral `P(success)` or isotonic. Below that floor the classifier returns neutral `P_success_cheap = 0.5`.
500
+
501
+ **Provenance today vs behavioral adoption:** the checked-in `config/p-success-weights.json` remains **synthetic/fixture** (SP-175 — trained on `scripts/fixtures/p-success-synthetic-train.jsonl`, not community dogfood). Treat those weights as an interim dogfood enablement until real passive-signal floors are met and artifacts are retrained/shipped ([#110](https://github.com/beettlle/pi-smart-router/issues/110) train/ship slice — SP-206). Do not claim synthetic rows are behavioral.
502
+
503
+ **SP-206 status (v0.12.0):** **deferred / Partial (B).** Operator had no #95 dogfood exports in this window (labeled economical-tier rows = **0**, floor ≥30). No behavioral `config/p-success-weights.json` or `config/routing-calibration.json` was shipped. See [`spine-tasks/_authoring/release-v0.12.0/behavioral-calibration-partial.md`](spine-tasks/_authoring/release-v0.12.0/behavioral-calibration-partial.md). Leave [#110](https://github.com/beettlle/pi-smart-router/issues/110) open until floors are met; never invent labels.
504
+
505
+ **Zero-manual-label path (aggregate → train → verify):**
487
506
 
488
507
  ```bash
489
- # 1) Opt in + dogfood, then export privacy-safe labeled JSONL (features + labels only)
508
+ # 1) Opt in + dogfood (no /feedback required) see docs/qa/shadow-dogfood-protocol.md
490
509
  SMART_ROUTER_DATASET=1
491
- # …run sessions with /model smart-router/auto and /smart-router feedback
510
+ # …sessions with /model smart-router/auto; prefer passive outcomes
492
511
  /smart-router export dataset --limit 200
512
+ /smart-router export telemetry-contrib
513
+
514
+ # 2) Aggregate privacy-safe contrib / exports (reject tainted payloads)
515
+ npm run routing:calibration-aggregate -- --contrib-dir data/contrib
493
516
 
494
- # 2) Train standalone weights (≥30 labeled rows required)
517
+ # 3) Train when ≥30 economical-tier labeled rows exist
495
518
  npm run routing:train-p-success -- --input path/to/export.jsonl --output config/p-success-weights.json
519
+ npm run routing:train-calibration -- --input path/to/aggregated.jsonl
520
+
521
+ # 4) Verify artifact shapes / gates
522
+ npm run routing:verify-calibration -- config/routing-calibration.json
523
+ ```
524
+
525
+ #### Operator train / reload (no prompt text)
496
526
 
497
- # Or regenerate the checked-in dogfood weights from the synthetic fixture:
527
+ ```bash
528
+ # Opt in + dogfood, then export privacy-safe labeled JSONL (features + labels only)
529
+ SMART_ROUTER_DATASET=1
530
+ # …run sessions with /model smart-router/auto (optional: /smart-router feedback)…
531
+ /smart-router export dataset --limit 200
532
+
533
+ # Train standalone weights (≥30 labeled rows required)
534
+ npm run routing:train-p-success -- --input path/to/export.jsonl --output config/p-success-weights.json
535
+
536
+ # Or regenerate the checked-in dogfood weights from the synthetic fixture (interim only):
498
537
  npm run routing:train-p-success
499
538
 
500
- # 3) Optional: merge isotonic into an existing calibration bundle (does not rewrite hydra/centroids)
539
+ # Optional: merge isotonic into an existing calibration bundle (does not rewrite hydra/centroids)
501
540
  npm run routing:train-p-success -- --input path/to/export.jsonl \
502
541
  --calibration-output config/routing-calibration.json
503
542
 
@@ -628,7 +667,7 @@ Dry-run behavior:
628
667
  | `--include-excluded-in-fit` | Weak rows may warm-start the fit pool; `ece_eligible` / holdout ECE stay verifier-grade |
629
668
  | Soft threshold | Advisory `0.25` calibrated ECE — **does not** change `config/release-gates.json` |
630
669
 
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.
670
+ **#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).
632
671
 
633
672
  ### Operator tuning (frugality slider)
634
673
 
@@ -864,6 +903,7 @@ Contributors must run `npm run build` before publishing or consuming the library
864
903
  | `npm run routing:eval-harness:smoke` | Harness summary JSON only (CI smoke; no network) |
865
904
  | `npm run routing:eval-harness:corpus-smoke` | Harness summary on TwinRouterBench CI corpus subset (`tests/eval/corpus/twinrouterbench`) |
866
905
  | `npm run routing:assert-release-gates:corpus-report` | Soft-feed: assert corpus vs absolute gates with `--report-only` (exit 0; does not gate releases) |
906
+ | `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`) |
867
907
  | `npm run routing:twinrouterbench:full-track` | Local/nightly: pin fetch → full convert (no `--limit`) → harness + gates `--report-only` (gitignored cache) |
868
908
  | `npm run routing:twinrouterbench:full-ingest` | Convert cached `question_bank.jsonl` → full static-track JSON (no `--limit`) |
869
909
  | `npm run routing:twinrouterbench:full-report` | Harness summary + gates `--report-only` on cached full track |
@@ -915,6 +955,7 @@ npm run routing:twinrouterbench:full-track
915
955
  | **Regenerate** | `npm run routing:ingest-twinrouterbench -- --input <question_bank.jsonl> --output tests/eval/corpus/twinrouterbench/ci-subset.json --limit 150 --prefer-code-tool` |
916
956
  | **Harness smoke** | `npm run routing:eval-harness:corpus-smoke` |
917
957
  | **Gate soft-feed** | `npm run routing:assert-release-gates:corpus-report` |
958
+ | **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) |
918
959
  | **Human QA protocol** | [`docs/qa/shadow-dogfood-protocol.md`](docs/qa/shadow-dogfood-protocol.md) · `npm run qa:shadow-dogfood` |
919
960
 
920
961
  **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).
@@ -966,6 +1007,12 @@ npm run routing:community-bench -- \
966
1007
  --output /tmp/community-bench-report.json \
967
1008
  --email-file /tmp/community-bench-report.txt
968
1009
 
1010
+ # Optional Track B: labeled dogfood export → harness gates (skips if incomplete — never invents labels)
1011
+ npm run routing:community-bench -- \
1012
+ --dogfood-export tests/eval/dogfood-track-b/synthetic-labeled-export.json \
1013
+ --output /tmp/community-bench-report.json \
1014
+ --email-file /tmp/community-bench-report.txt
1015
+
969
1016
  # Optional Track C: offline LLMRouterBench regret/CS on the vendored subset (no full HF download)
970
1017
  npm run routing:community-bench -- \
971
1018
  --llmrouterbench \
@@ -975,7 +1022,7 @@ npm run routing:community-bench -- \
975
1022
 
976
1023
  **How to send:**
977
1024
 
978
- 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.
1025
+ 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.
979
1026
  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
980
1027
 
981
1028
  **Tracks:**
@@ -983,7 +1030,7 @@ npm run routing:community-bench -- \
983
1030
  | Track | Corpus | When |
984
1031
  |-------|--------|------|
985
1032
  | **A (required)** | [TwinRouterBench CI corpus](#twinrouterbench-ci-corpus-sp-186--sp-187--sp-188) (`tests/eval/corpus/twinrouterbench`) | Always |
986
- | **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 |
1033
+ | **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)) |
987
1034
  | **C (optional)** | [LLMRouterBench offline subset](#llmrouterbench-offline-regret-sp-192--sp-193) (`tests/eval/corpus/llmrouterbench`) | `--llmrouterbench` or `--full`; offline only |
988
1035
 
989
1036
  PR CI does **not** download full TwinRouterBench / LLMRouterBench corpora. Absolute gate thresholds in `config/release-gates.json` are unchanged by this CLI.
@@ -1064,6 +1111,8 @@ npm run routing:verify-benchmark-profiles
1064
1111
 
1065
1112
  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.
1066
1113
 
1114
+ **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).
1115
+
1067
1116
  **Tier 0 functional smoke** (`release:functional-smoke`) runs before tag publish and chains:
1068
1117
 
1069
1118
  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.10.0",
3
+ "version": "0.12.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,7 @@
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",
76
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\"'",
77
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'",
78
79
  "routing:twinrouterbench:full-track": "bash scripts/eval/twinrouterbench-full-track.sh",
@@ -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)** |