pi-crew 0.9.59 → 0.9.61

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/CHANGELOG.md CHANGED
@@ -3,6 +3,54 @@
3
3
  > **Note:** `atomic-write-v2.ts` / `AtomicWriter` mentioned in historical entries below was consolidated into `atomic-write.ts` as of v0.9.42. This changelog is preserved as historical record — the migration was completed (the v2 class was never adopted; v1 won on simplicity + symlink-safety + link+unlink atomicity). See `docs/migration/atomic-write-v2-migration.md` for the decision rationale.
4
4
 
5
5
 
6
+ ## [0.9.61] — bundle republish: bug-44 fix shipped in dist (2026-08-05)
7
+
8
+ ### Bug fixes
9
+
10
+ - **Bug-44 fix was missing from the v0.9.60 npm bundle (hot-fix republish).** The source-level fix for GitHub #44 (chain run fails fast when `workflow:"chain"` is forwarded to steps) landed in commit `5b43d556`, but the published `dist/index.mjs` was built from a stale source tree *before* the fix, so users installing `pi-crew@0.9.60` got the old buggy bundle (the chain runner still forwarded `workflow` to steps). v0.9.61 rebuilds the bundle with the fix included and verified (`grep` for the reject message + fallback logic now matches in `dist/index.mjs`). No source changes — purely a corrected bundle republish.
11
+
12
+ ## [0.9.60] — subagent model routing: live-session model tracking, fallback policy, quota-aware ordering + iterative-audit hardening (2026-08-05)
13
+
14
+ ### Bug fixes
15
+
16
+ - **Chain run fails fast (~58 ms) with no error when `workflow:"chain"` is forwarded to steps (GitHub #44).** `chain-dispatch.ts` forwarded `params.workflow` (="chain") into every step's executor overrides; `chain-executor.ts` passed it through to each step's `handleRun`, which then executed the dispatcher-only `chain` workflow via the normal `executeTeamRun` path. Since `chain.workflow.md` is a documentation file (not a runnable workflow — it parses to 10 doc-heading steps with unknown roles), validation failed fast with a confusing empty error. Fix: (1) `chain-dispatch.ts` no longer forwards `workflow` (a chain has no per-step workflow; steps use the team's defaultWorkflow); (2) `chain-executor.ts` defensively drops a `"chain"` workflow override; (3) `run.ts` falls back to the team's default workflow when `workflow="chain"` is requested without a `chain` param; (4) `handleChainRun` rejects `workflow:"chain"` with a clear message. Regression tests added in `chain-executor.test.ts`.
17
+ - **Subagent model "jumped" to whatever a previous session had saved.** `ctx.model` is the session's *saved* model, not the live one. A session that restored stale state could report `anthropic/claude-sonnet-4-5` while actually running `minimax/MiniMax-M3`. Subagents inheriting the parent model (`model: false`, which every builtin agent uses) therefore landed on the wrong model. Fix: track the live model via pi's `model_select` event (`src/runtime/model/session-model.ts`) and use it as the parent model for all spawn paths.
18
+ - **Live-session path silently discarded `ctx.model`.** `resolveParentModelFromRegistry` only accepted strings; `ctx.model` is a pi `Model` object. Every live-session subagent that inherited the parent model fell through to `getAvailable()[0]` instead. Fix: accept both objects and strings via `modelRefToString`.
19
+ - **Background/async runs lost the caller's model context.** A detached background run has no `ExtensionContext`, so it lost the `model=` override, the inherited session model, and the auth-filtered model catalogue — silently routing to whatever `models.json` listed first. Fix: persist `modelContext` (override / parent model / available models) on the manifest at dispatch time and re-hydrate it in `background-runner`.
20
+ - **Dead re-resolve branch in child-executor.** When the precomputed fallback chain was exhausted, the one-shot re-resolve found an alternative model but never appended it to `attemptModels` — the loop logged "retrying with X" but never actually retried. Fix: append the discovered model, exclude all previously-tried models, bump the spawn budget, and guard against re-entry.
21
+
22
+ ### Features
23
+
24
+ - **Model fallback policy** (`runtime.modelFallback` in config, or env vars). Controls the auto tail (models appended from the registry/pi-config that nobody explicitly declared):
25
+ - `maxAutoFallbacks` — cap the auto tail (each extra candidate multiplies the worst-case spawn budget by `maxAttempts + 1`)
26
+ - `order: "parentFirst" | "asIs"` — keep the tail on the same provider as the running model before crossing providers
27
+ - `requireCredentials` — drop pi-config models whose provider has no discoverable credential
28
+ - `quotaAwareOrdering` — deprioritize providers near their rate-limit/quota (default: true, reads `after_provider_response` headers)
29
+ - `defaultSubagentModel` — default model for subagents when neither the caller nor the agent specifies one (sits between agent model and parent inheritance)
30
+ - Env overrides: `PI_CREW_MAX_AUTO_FALLBACKS`, `PI_CREW_MODEL_FALLBACK_ORDER`, `PI_CREW_MODEL_REQUIRE_CREDENTIALS`, `PI_CREW_MODEL`
31
+ - **TeamRole `fallbackModels` + `thinking`**. Role lines now accept `fallbackModels=a,b` (comma-separated) and `thinking=high|medium|low|off`. Previously `fallbackModels=a,b` was silently swallowed into the role description.
32
+ - **Quota-aware ordering** (`src/runtime/model/provider-quota.ts`). Tracks `x-ratelimit-remaining-*` and `retry-after` headers from `after_provider_response` events. Providers that are 429'd or near-zero remaining are pushed to the back of the auto tail. Process-local, 5-minute TTL, never blocks spawn.
33
+ - **`task.model_dropped` warning event**. When the caller's requested model is not resolvable against the available catalogue, the chain silently runs something else. Now surfaced as an event + persisted to `task.modelRouting.droppedRequested` so users can see what happened.
34
+ - **Doctor: "Model Routing" section**. Shows the live session model (from `model_select`), the active fallback policy, a sample chain for a generic agent, and the auto tail size.
35
+
36
+ ### Bug fixes
37
+
38
+ - **Iterative-audit hardening (3 rounds, source-verified; 1 false positive rejected).** Round 1: provider-quota `headerResetMs` parsed `x-ratelimit-reset-requests` as epoch-seconds, but OpenAI sends Go-duration strings (`"6m0s"` → `parseInt`=6 → reset in 1970) so the low-remaining deprioritization heuristic never fired — now parses Go-duration / Anthropic RFC3339 / `retry-after` seconds. Scope-gate source attribution now tracks real precedence (override/step/teamRole → hard error; frontmatter/defaultSubagent/parent → soft warn). `quotaCache` cleared on `session_before_switch` (cross-session leak) + evicted past `2×QUOTA_TTL`. `PI_CREW_MAX_AUTO_FALLBACKS` NaN/negative now guarded with a warn (was silently unbounded / clamped to 0). Round 2 (re-audit caught regressions IN round 1): scope warnings were **silent** — the `logInternalError` calls forgot the `"warn"` severity, so they were debug-gated and the entire Sec-M1 fix was ineffective; now centralised in `warnOutOfScopeSoft()` (all 3 call sites) with a non-vacuous test. `parseResetValue` pure-seconds check moved before RFC3339 (`Date.parse("0")` returns Y2K, not NaN). Removed 2 vacuous re-resolve tests. `isFrontmatterOverride` source corrected to `"frontmatter"` so the soft warning surfaces. Round 3: verified Round-2 fixes; no new bugs (diminishing returns → stop).
39
+ - **CI flake fixed — `[RT-NEW-2] budget abort drains in-flight tasks` (failed 3×: v0.9.59, `cfd68d06`, `12386af2`).** `terminaliseRunWithDrain` built `inflightTaskIds` as a SNAPSHOT of `ctx.pendingUnits`; a task whose dispatch unit settled + left `pendingUnits` before the abort — but whose task status wasn't terminal yet — was absent from the snapshot, fell through to `markBlocked`, and got clobbered to `"skipped"`. Now `SchedulerContext.dispatchedTaskIds` (monotonic Set populated at dispatch, never removed) drives the cancel-not-skip guard; `markBlocked` only catches genuinely never-dispatched queued tasks (semantics preserved). Verified 20/20 runs of the previously-flaky test + test:critical 101/101.
40
+
41
+ ### Docs / tooling
42
+ - `skills/real-test-pi-crew/REPORT-TEMPLATE.md` + SKILL.md: per-run dated report artifact (evidence per tier) required for every real-test — fixes "all 9 tiers pass" overclaim where past runs were unverifiable memory. First report: `docs/real-test/reports/real-test-2026-08-05-model-routing.md`.
43
+ - `docs/bugs/chain-workflow-forward-quirk.md` + GitHub issue #44: chain run via team tool fails ~58ms silent when `workflow:"chain"` is forwarded to steps (chain-dispatch passes it into each step's `handleRun`, which runs the "chain" workflow via `executeTeamRun`). Workaround: omit `workflow` (chain then runs 2/2 success).
44
+
45
+ ### Technical details
46
+
47
+ - `ConfiguredModelRouting` gains `droppedRequested` and `autoFallbackCount` fields.
48
+ - `ModelRoutingState` (persisted to task state) gains `droppedRequested` and `autoFallbackCount`.
49
+ - `TeamRunManifest` gains `modelContext?: RunModelContext` for background/async model routing restoration.
50
+ - `buildConfiguredModelRouting` input gains `defaultSubagentModel`, `teamRoleFallbackModels`, and `policy` fields.
51
+ - New modules: `src/runtime/model/session-model.ts`, `src/runtime/model/provider-quota.ts`.
52
+ - 42 new unit tests covering session-model tracker, provider-quota tracker, policy resolution, defaultSubagentModel precedence, teamRoleFallbackModels chain position, and droppedRequested detection.
53
+
6
54
  ## [0.9.59] — cross-session isolation: stop leak of runs/subagents between concurrent pi sessions + stop false-reap of live sessions (2026-08-05)
7
55
 
8
56
  ### Bug fixes