[fix] Key the lifecycle capability table by the wire harness spellings - #6364
[fix] Key the lifecycle capability table by the wire harness spellings#6364mmabrouk wants to merge 1 commit into
Conversation
harnessKind matched only the bare literals 'pi', 'claude', 'codex', but the wire carries 'pi_core' / 'pi_agenta' (empty defaults to pi_core), so every playground Pi run resolved to 'unknown' and took the fail-closed capability row where every facet rebuilds the sandbox. Two consequences: - The one live route that already ships (a model-only switch applies live via setModel) never fired for Pi: every model switch in the playground tore down the warm sandbox, minted fresh Daytona Secrets, and re-entered the placeholder-propagation race (see #6362). - Every reconcile shadow log line for Pi read 'harness=unknown' with an all-rebuild plan, so the step-4/5 DISAGREE audit was noise for the main harness. Normalize exactly as buildRunPlan does before keying the capability table. Claude-Session: https://claude.ai/code/session_014s6jqKCsVKsNMmnrJVJkZt
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe runner now maps absent, ChangesPi harness routing
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🔵 Low · up to The change lets supported Pi requests reuse warm sandboxes for model-only switches, reducing unnecessary rebuilds. Malformed harness values can still select the live Pi path instead of failing closed, and equivalent omitted and explicit pi_core values may trigger unnecessary rebuilds; the PR is mergeable with explicit owner awareness and follow-up on validation and canonicalization. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: a0b663a4-0e97-482b-97ed-b38f8538c2d6
📒 Files selected for processing (2)
services/runner/src/lifecycle/reconciliation-router.tsservices/runner/tests/unit/lifecycle-reconcile-plan.test.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.
Found by a code audit of the cold/warm flows (follow-up to #6364). The coordinator computed the eviction reason with an else-if chain and the live model route then set mismatch = undefined wholesale, so a repair of the CONFIG question also cleared every question the chain never reached: - a model switch riding an EDITED transcript continued warm on a native conversation still holding the unedited turn; - riding a ROTATED credential with no delivery port, it ran on the old baked key (silently, if the old key still worked); - riding an EXPIRING mount lease, it let the turn die under the mount; - riding a stale tail, it ran a turn the tail check should have evicted. The claude live route has been exposed since step 6 shipped; #6364 makes the route fire for pi_core too, widening the surface, so this belongs in the same stack. Each repair door now marks ITS reason repaired and re-asks the ordered checks. A model switch with a deliverable rotation chains both repairs and stays warm (pinned); the four bad pairings rebuild (pinned). Claude-Session: https://claude.ai/code/session_014s6jqKCsVKsNMmnrJVJkZt
Found by a code audit of the cold/warm flows (follow-up to #6364). The coordinator computed the eviction reason with an else-if chain and the live model route then set mismatch = undefined wholesale, so a repair of the CONFIG question also cleared every question the chain never reached: - a model switch riding an EDITED transcript continued warm on a native conversation still holding the unedited turn; - riding a ROTATED credential with no delivery port, it ran on the old baked key (silently, if the old key still worked); - riding an EXPIRING mount lease, it let the turn die under the mount; - riding a stale tail, it ran a turn the tail check should have evicted. The claude live route has been exposed since step 6 shipped; #6364 makes the route fire for pi_core too, widening the surface, so this belongs in the same stack. Each repair door now marks ITS reason repaired and re-asks the ordered checks. A model switch with a deliverable rotation chains both repairs and stays warm (pinned); the four bad pairings rebuild (pinned). Claude-Session: https://claude.ai/code/session_014s6jqKCsVKsNMmnrJVJkZt
Cold/warm audit finding 2. modelCapabilities is the resolved model's input modalities: per-turn data the attachment chain reads from each incoming request, baked into nothing. But it rode the fingerprint and the harnessSession facet, and it changes WITH the model — so switching between a vision model and a text-only model moved two facets, the mixed plan refused the live setModel route, and the switch rebuilt the warm sandbox (fresh Daytona Secrets, the substitution race, ~15s) for nothing. The Pi catalog splits 249 text+image vs 163 text-only models, so this hit ordinary playground use even after #6364. Same treatment as workflowRevision/isDraft in step 1: out of the hash, documented in the volatile list, pinned in both directions (the per-turn-volatile test gains the field; the old changes-the-fingerprint test is reversed with the reason). Claude-Session: https://claude.ai/code/session_014s6jqKCsVKsNMmnrJVJkZt
Context
While tracing why a config change evicted a user's warm sandbox (the placeholder-401 investigation, #6362), the reconcile shadow log showed
harness=unknownon every playground run. The lifecycle router'sharnessKindmatched only the bare literalspi,claude,codex, but the wire carriespi_coreorpi_agenta, and an empty harness defaults topi_core. Every playground Pi run therefore resolved tounknownand took the fail-closed capability row, where every facet maps to a full sandbox rebuild.Two real costs:
setModel) never fired for Pi. Every model switch in the playground tore down the warm sandbox, created fresh Daytona Secrets, and re-entered the substitution-propagation race that produces the placeholder 401s.Changes
harnessKindnow normalizes exactly asbuildRunPlandoes before keying the capability table.Before:
harness: "pi_core"resolved tounknown(model switch plansrebuild-sandbox).After:
pi_core,pi_agenta, barepi, and the empty default all resolve topi(model switch plansapply-live; a harness-session change plansreopen-session).claudeandcodexwere already correct and are unchanged. A genuinely unknown harness still fails closed.Tests
lifecycle-reconcile-plan.test.tspin the wire spellings, the empty default, and the recoveredapply-livemodel route.pnpm run typecheckclean.What to QA
https://claude.ai/code/session_014s6jqKCsVKsNMmnrJVJkZt