Skip to content

chore(examples): use built-in framework surface over hand-rolled setup - #473

Merged
ScriptedAlchemy merged 3 commits into
mainfrom
chore/examples-use-builtins
Sep 3, 2026
Merged

chore(examples): use built-in framework surface over hand-rolled setup#473
ScriptedAlchemy merged 3 commits into
mainfrom
chore/examples-use-builtins

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Fixes #51, #52 and #54 (daemon side; the client-side MAKEFLAGS transport item in #54 is handled separately).

#51 — kill honoured while parked; batch, ETA and settlement hardening

  • processJob now races the job's kill signal against the load gate + admission.withPermits(1). A kill on a job parked at the gate or on the permit settles it killed (killed while queued) immediately via the existing finishKilledBeforeRun path, releases any heavy claim, and no longer blocks the rest of its lane. A kill that lands after claimStart is left to the executor (the race arm parks instead of interrupting an admitted run).
  • foldBatch skips candidates whose state is not queued; processLaneJob re-checks state before the batch window sleep and before folding, so a kill-requested head neither waits for nor leads a batch.
  • Queue ETA uses remainingEstimateMs (clamped at 0) and counts a head parked at the gate (new Lane.head, set from take to settlement). The existing assertion in daemon-broker.test.ts that encoded the negative-cancel bug (waitEtaMs === 0) now expects the queued job's estimate.
  • settleJob isolates every step after claimSettlement (markFinished, metrics, notifyWaiters, completeExit, settleAttachments) with settlementStep (log + continue on defect). settleAttachments and finishAttachment apply the same per-step isolation.

#52 — attachment registration races

  • replayThenGoLive takes the replay snapshot and clears pendingLive in one Effect.sync, so a chunk emitted between registration and replay is delivered once.
  • completeAttachRegistration re-checks leader.attachments.get(ticket) === attachment in a sync frame before any ledger write and returns early if the leader settled / the attachment was killed or released in the window. updateRunning / updateAttached carry AND status NOT IN (<terminal>) and record a transition only when a row changed.
  • Early follower release from the stdout pump (releaseSatisfiedAttachments) is guarded: a ledger/metric defect is logged instead of surfacing as pump-failed and terminating cargo.
  • mergeStderr is part of identity/coverage attach compatibility for raw-output leaders (channelsCompatible); demux runs never merge so the flag is irrelevant there. Batch folding is documented as unchanged (folded followers receive the composite's channels as produced).

#54 — jobserver vs CARGO_BUILD_JOBS

  • New isSharedJobserverArmed(); cargoExecEnv injects CARGO_BUILD_JOBS only when the FIFO is not armed, so an armed daemon lets sharedJobserverDelta inject MAKEFLAGS and cargo joins the shared budget. Caller -j / CARGO_BUILD_JOBS still win.
  • README: parallelism paragraph, capability row and CARGO_HAULER_JOBS_GRANT env row state the precedence; DaemonConfigShape.jobsGrant doc updated.

Tests (each written failing first, then fixed)

  • tests/daemon-races.test.ts (new, in-process broker over the fake cargo via the shared tests/broker-fixture.ts, extracted from daemon-async.test.ts):
    • kill of a job parked on the permit settles killed within the await budget while the holder keeps running
    • kill-requested pending job is not folded into a batch (leader chosen via a rider so the doomed job is the fold candidate)
    • settlement completes (exit callback fires, directory entry cleared, successor runs alone) when markFinished dies
    • late attacher receives each of 40 replayed ticks exactly once with markAttached delayed 400 ms
    • follower whose markAttached is held until after the leader settled stays done
    • early follower release with a dying markFinished leaves the leader done (not pump failed) and still delivers the follower's exit
    • identity attach on cargo test requires equal mergeStderr
  • tests/daemon-ledger.test.ts: late markAttached/markRunning never reopen a done row or add transitions.
  • tests/daemon-jobs-grant.test.ts (new): cargoExecEnv matrix + a daemon spawn asserting CARGO_BUILD_JOBS unset and MAKEFLAGS carrying --jobserver-auth=fifo:<stateDir>/jobserver.fifo.

Gate

pnpm check green locally: validate, build, typecheck, Effect diagnostics (pre-existing suggestions only), rstest 637 passed / 0 failed, route-unit 32 passed / 0 failed.

Review status

(filled in per AGENTS.md once the automated review runs)

…lineage and useAgent()

- src/api.ts: add useWorktree() over the runtime's useAgent(); the README
  no longer claims a hook contract is missing.
- event routes: session/start, agent/start, tool/before, tool/after and
  stop take actor identity from (await agent()).lineage first, then the
  native agent_id/session_id pair, then the worktree binding, then the
  derived worktree:<root> fallback. Provenance now records the runtime
  lineage resolution (native | registry | inferred) alongside derived.
- providers/agent-topology.ts: state the actual reason the snapshot is
  unavailable (providers receive no identity/lineage/state, #459).
- README: fix the stale useWorktree()/lineage sentences; point at #457,
  #458, #459, #460 for what is still missing.
- route-unit tests: cover lineage-carried agent/start and tool/before.
…col/server dependency

The generated MCP server ships its own transport; no module in the example
imports the SDK. Lockfile refreshed for the removed importer entry.
…types from public exports

JsonObject/JsonValue come from the agent-bundle root export and
DevRuntimeProvider from agent-bundle/api; both were reached through
../../../../packages/agent-bundle/src/dev before. The remaining deep
imports (runtime-protocol, runtime-generation-store, runtime-mcp-registry,
the rest of runtime-provider) have no public counterpart yet.
@ScriptedAlchemy ScriptedAlchemy added the skip-changeset PR changes a publishable package but ships no observable change; changeset not required label Sep 3, 2026
@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 7811fcb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@473
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@473
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@473

commit: 7811fcb

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

The two framework gaps listed under "Proposed framework issues" are now filed:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR changes a publishable package but ships no observable change; changeset not required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant