Skip to content

Bound worker launch cost by tier and branch - #964

Merged
thomasluizon merged 6 commits into
redesign/mainfrom
chore/ticket-536-worker-budget
Sep 15, 2026
Merged

thomasluizon merged 6 commits into
redesign/mainfrom
chore/ticket-536-worker-budget

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 14, 2026 •

Copy link
Copy Markdown
Owner

Closes thomasluizon/orbit-tickets#536

Summary

  • Add a mechanical worker tier using medium reasoning while keeping default at high reasoning.
  • Cap ordinary launches at two per repository branch.
  • Claim ordinary launches through fixed branch slot names using exclusive creation.
  • Require and record --relaunch-reason after the cap, while keeping ledger writes fail-soft.
  • Make the exclusive slot creation the admission decision, with no directory count or ordering.
  • Stamp and validate every configured worker tier in calibration.
  • File follow-up ticket Astra prompt→behavior eval harness (on-demand pre-launch capability gate) #537 for the attended orchestrate skill update.

Test evidence

  • Before changes, node tools/test-tools.mjs passed with ORBIT TOOLS GATE OK while the original race remained present.

  • The unchanged tests included both sequential branch-cap paths, so they did not expose simultaneous reservations.

  • After strengthening the original regression, node --input-type=module -e "import { resolve } from 'node:path'; const h = await import('./tools/__tests__/_harness.mjs'); h.configure({ toolsDir: resolve('tools'), self: 'test-tools.mjs' }); const m = await import('./tools/__tests__/run-state.mjs'); await m.cases(); process.exit(h.failureCount() === 0 ? 0 : 1)" exited 1 before the first fix.

  • That failure reported both interleaved reservations as allowed and showed the last rename had discarded one record.

  • After the first fix, the same focused command exited 0 with PASS lib/run-state.mjs: simultaneous reservations admit exactly one launch and retain both admitted records.

  • Review round two started with the unchanged node tools/test-tools.mjs, which passed with ORBIT TOOLS GATE OK while the free-slot defect remained present.

  • After adding the free-slot case, node --input-type=module -e "const h=await import('./tools/__tests__/_harness.mjs');h.configure({toolsDir:new URL('./tools/',import.meta.url).pathname.replace(/^\/[A-Za-z]:/,p=>p.slice(1)),self:'test-tools.mjs'});h.beginToolScope('lib/run-state.mjs');await (await import('./tools/__tests__/run-state.mjs')).cases();h.endToolScope();process.exit(h.failureCount()===0?0:1)" exited 1 before the round-two fix.

  • The new failure reported both contenders refused and an admitted total of one instead of two.

  • After the round-two fix, the same focused command exited 0 with both simultaneous reservation cases passing.

  • node tools/test-tools.mjs passed after the round-two fix with ORBIT TOOLS GATE OK.

  • The tools gate observed PASS launch-worker.mjs: a third launch exits 2 and names both earlier launches.

  • The tools gate observed PASS launch-worker.mjs: a third launch with a recorded reason succeeds.

  • node .claude/hooks/test-hooks.mjs passed after the round-two fix with ORBIT HOOKS OK.

  • node tools/check-calibration.mjs passed for 31 files and both configured tiers in the original implementation round.

  • Review round three started with unchanged node tools/test-tools.mjs, which passed with ORBIT TOOLS GATE OK while the delayed-create defect remained present.

  • After adding the delayed-create case, node --input-type=module -e "const h=await import('./tools/__tests__/_harness.mjs');const {resolve}=await import('node:path');h.configure({toolsDir:resolve('tools'),self:'test-tools.mjs'});h.beginToolScope('lib/run-state.mjs');const {cases}=await import('./tools/__tests__/run-state.mjs');await cases();process.exit(h.failureCount()?1:0)" exited 1 before the round-three fix.

  • That failure reported both contenders allowed and two ledger records after the later contender had already returned.

  • After the round-three fix, the same focused command exited 0 with all three race cases passing.

  • node tools/test-tools.mjs passed after the round-three fix with ORBIT TOOLS GATE OK.

  • node .claude/hooks/test-hooks.mjs passed after the round-three fix with ORBIT HOOKS OK.

External interface evidence

The launcher reads Git's common-directory response to map a linked worktree to its configured repository key.

git -C "<linked worktree>" rev-parse --git-common-dir returned exit 0 and one stdout string: "<absolute Git common directory>\n".

git -C "<main checkout>" rev-parse --git-common-dir returned exit 0 and one stdout string: ".git\n".

These are the complete response shapes consumed by the implementation. No structured fields are read.

Assumptions

  • The checkout lifetime is the run boundary; grouping by head SHA was rejected because worker commits move the head during one run.
  • Repository identity uses Git's common directory; remote URL matching was rejected because equivalent remotes can use different URL syntax.

@vercel

vercel Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
orbit-ui-mobile-web Ignored Ignored Sep 14, 2026 9:37pm UTC

Request Review

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The launch cap can be bypassed by concurrent reservations, and the checked-in workflow is not yet wired to the newly enabled controls.

Reviewed changes the two commits that add worker tiers, branch-scoped launch accounting, and tier-aware calibration.

  • Worker profiles — Adds default high-reasoning and mechanical medium-reasoning launch vectors with config validation and dry-run reporting.
  • Branch launch budget — Maps worktrees to configured repositories, records non-dry launches in checkout-local Git state, refuses ordinary launches above the cap, and permits reasoned overrides.
  • Calibration coverage — Reworks calibration stamps and reseeding to bind every configured tier's model and complete argument vector.
  • Harness and catalog — Adds sequential tier, cap, override, config, run-state, and calibration cases and updates the tool catalog.

⚠️ The production workflow still exposes the old launcher contract

The authoritative orchestrator skill still defines the launcher command without either new flag and still says the launcher resolves one model tier. Because this PR enables the cap immediately while deferring workflow integration, normal orchestration cannot select mechanical and has no prescribed --relaunch-reason recovery when a legitimate branch reaches the cap.

Technical details
# Wire the enabled controls into the production workflow

## Affected sites
- `.claude/skills/orchestrate/SKILL.md:117-125` — the fixed interface omits `--tier` and `--relaunch-reason`.
- `.claude/skills/orchestrate/SKILL.md:643-656` — local execution always uses the default tier and documents no cap recovery.
- `.claude/skills/orchestrate/SKILL.md:1071-1080` — model routing still states that the launcher resolves one tier.
- `tools/launch-worker.mjs:38-41` — the flags are enabled by this PR.

## Required outcome
- Merge the workflow contract and routing rules with this activation, or sequence activation after the stated follow-up so the checked-in production caller always describes every enabled control.
- Define which eligible orders select `mechanical` and when a branch-cap override is legitimate.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread tools/lib/run-state.mjs Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The new post-publication accounting can refuse every concurrent contender even when the branch still has capacity.

Reviewed changes since the prior Pullfrog review, the new commit replaced the shared launch ledger with per-launch records and added a concurrency regression.

  • Replaced shared ledger snapshots — Stored each reservation in an exclusively created JSON file, counted peer files after publication, and removed refused records.
  • Added race coverage — Exercised a nested reservation and updated the launcher assertions for directory-backed records.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread tools/lib/run-state.mjs Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The launch cap can still be exceeded by one publication ordering that the new race harness does not exercise.

Reviewed changes since the prior Pullfrog review, the new commits elected fully published contenders by reservation filename order, replaced the nested race with synchronized worker-thread coverage, and merged redesign/main without changing the net PR patch.

  • Elected fully published contenders — Assigned each reservation a sortable name and counted only matching records ordered before it so one contender owns a free slot.

  • Strengthened race coverage — Added worker-thread barriers for full-cap and free-slot scenarios, but those barriers force all writes to complete before admission reads.

  • Merged the latest base — Merged redesign/main into the branch without changing the PR's net 13-file patch.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread tools/lib/run-state.mjs Outdated
@sonarqubecloud

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The fixed-slot change introduces no new issues, but the previously reported production workflow mismatch remains unresolved and still blocks approval.

Reviewed changes since the prior Pullfrog review, I reviewed the fixed-slot reservation rewrite and its new delayed-publication regression.

  • Claimed bounded branch slots — Replaced publication-order election with exactly cap deterministic branch slot files, using exclusive creation as the ordinary-launch admission decision.
  • Covered delayed publication — Added a worker-thread interleaving where one caller finishes before an earlier caller attempts its slot claim, proving only one unreasoned launch is admitted at cap one.
  • Preserved fail-soft accounting — Kept ledger setup and record-content failures from aborting a launch while retaining claimed slots as the durable branch budget.

Pullfrog  | Fix it ➔ | View workflow run | Using GPT Sol | 𝕏

@thomasluizon

Copy link
Copy Markdown
Owner Author

The sequencing question is settled, and a gate settles it the other way round

The open finding on this pull request is that .claude/skills/orchestrate/SKILL.md still documents
launch-worker.mjs without --tier and --relaunch-reason while this change enables them, so the
checked-in production caller does not describe every enabled control. That is correct.

The review offered two outcomes: merge the contract change with the activation, or sequence the
activation after it. A gate in this repository forbids the second one.

.claude/hooks/test-hooks.mjs carries "every prescribed tool invocation names flags the tool accepts".
Pull request 890 now documents both flags, and on 890's branch that harness FAILS, five times, with:

FAIL skill commands: .claude\skills\orchestrate\SKILL.md prescribes launch-worker.mjs which does not accept --tier
FAIL skill commands: .claude\skills\orchestrate\SKILL.md prescribes launch-worker.mjs which does not accept --relaunch-reason

Reproduced locally at 890's head 7c7344a1. The gate is right: documentation that prescribes a flag
the checked-in tool refuses is worse than documentation that omits one. So the documentation cannot
land before the flags exist.

The order is therefore: this pull request merges first, then 890 merges redesign/main forward and its
harness goes green with the flags present. Between the two merges SKILL.md omits two flags that
launch-worker.mjs accepts, which no gate objects to and which no caller can be misled by, because an
undocumented flag is simply unused.

On this branch the same harness passes, because the gate checks prescribed against accepted and never
the reverse.

Nothing else on this pull request changed. Requesting a fresh review of the same head.

@thomasluizon

Copy link
Copy Markdown
Owner Author

@pullfrog review

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes I re-reviewed the complete same-head patch, prior concurrency findings, the body-only sequencing concern, and the linked follow-up evidence.

  • Worker profiles — Adds default high-reasoning and mechanical medium-reasoning launch vectors with validation and dry-run reporting.

  • Atomic branch budget — Maps linked worktrees to configured repositories and claims exactly cap checkout-local branch slots through exclusive creation before launching.

  • Reasoned overrides — Refuses ordinary launches after the cap, reports earlier attempts, and records deliberate --relaunch-reason overrides without making ledger failures fatal.

  • Calibration and regression coverage — Stamps every configured tier and covers sequential admission, free-slot contention, full-cap contention, and delayed-create interleavings; the focused launcher suite and calibration gate pass.

  • Sequenced workflow contract — Verified that open PR #890 carries both launcher signatures, tier-routing rules, and cap-override guidance, and that its invocation gate requires this PR's flags to land first.

Pullfrog  | View workflow run | Using GPT Sol | 𝕏

@thomasluizon
thomasluizon merged commit 1ef2f5e into redesign/main Sep 15, 2026
46 checks passed
@thomasluizon
thomasluizon deleted the chore/ticket-536-worker-budget branch September 15, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant