Skip to content

feat(harness): expose writable delegation [Agent Map 14/15] - #833

Open
ynadge wants to merge 1 commit into
review/agent-map-13-child-sessionsfrom
review/agent-map-14-delegation-tool
Open

feat(harness): expose writable delegation [Agent Map 14/15]#833
ynadge wants to merge 1 commit into
review/agent-map-13-child-sessionsfrom
review/agent-map-14-delegation-tool

Conversation

@ynadge

@ynadge ynadge commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Primary change type

  • Feature

Problem and motivation

Project agents need a usable delegation tool that connects durable claims to real writable child sessions without duplicate kickoff turns or interference with manual sessions.

Summary and scope

Wire the complete coordinator, optional focused briefs, acknowledgement/recovery events, nested delegation, scoped release, and universal MCP registration.

Share one 30-second readiness/identity budget across a batch, returning partial results with durable child identities for explicit retry. Recover unfinished dormant cleanup without emitting a second release event.

How this increment fits

The writable tool activates only after its store, child lifecycle, and focused context are complete. It supports nested delegation from ordinary project sessions.

Stack and review boundary

  • Part 14 of 15 in the Agent Map review stack; review this increment against its predecessor.
  • Base: review/agent-map-13-child-sessions.
  • Current head: 4af416a289eec6c545f4624988af3321cbf8eb51; 3,249 changed lines across 13 files, counting additions and deletions including tests.
  • Repackages the corresponding final behavior from #808. Original code and review history remain preserved.
  • Complete coworker testing branch: fix/studio-onboarding-followups.
  • The stack remains unmerged. Dependent PRs target their predecessor, so their diffs do not repeat earlier increments.

Related work

Agent Map checkpoint SAP-3147; relevant work SAP-3151. This packaging follows the maintainer-approved 15-PR split.

Validation

Root checks ran against ef760767dfcccff85e95b79d7c1ad4eadb696395. The final head changes only README terminology or commit ancestry; a complete tracked-file comparison confirms identical executable source and build inputs. The terminology gate was rerun on 4af416a289eec6c545f4624988af3321cbf8eb51.

pnpm build — passed (exit 0)
pnpm typecheck — passed (exit 0)
pnpm lint — passed (exit 0)
pnpm test — passed (exit 0)

Tests and documentation

Regression coverage: Realistic child reuse and kickoff acknowledgement, scoped release, nested delegation, batch deadlines, partial timeout results, and cleanup recovery after receipt expiry.

See part 15 for integrated browser, native CLI, and Mac journey validation. The checks above were run independently on this PR’s own commit.

Linux tests run with ordinary user filesystem permissions; the sandbox's extra ambient capabilities are dropped. Hosted CI and automated review are separate from these recorded local results.

Compatibility and release impact

  • Compatibility: Adds project_subsession_delegate with delegate, refresh, release, and dormant-release operations. AnalyticsEventType gains subsession events; exhaustive consumers must handle them.
  • Changeset: Included: .changeset/writable-project-subsessions.md

Security

  • No secrets, credentials, private user data, or unsanitized logs are included.
  • This PR does not publicly disclose a suspected vulnerability.

AI assistance

  • Codex assembled the implementation, addressed reproduced defects, supplied tests and documentation, inspected the diff, and ran the checks above. Reviews are handled by hosted PR automation.

Checklist

  • Read CONTRIBUTING.md; implementation follows the requested 15-PR split.
  • Description reflects this PR's actual predecessor-relative diff.
  • Relevant tests accompany the changed behavior.
  • Root build, typecheck, lint, and test evidence matches the final implementation; any documentation-only update is identified above.
  • Release/documentation treatment is explained above.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Review — PR #833 (round 1)

1. Published copy: the changeset ships internal mechanics into an un-retractable CHANGELOG

.changeset/writable-project-subsessions.md is 45 body lines. The next-longest changeset in
.changeset/ is 21 lines and the median is 5–6. It compiles verbatim into
packages/harness/CHANGELOG.md and ships inside the npm tarball, where it cannot be edited.

What it currently documents to an anonymous npm consumer: tombstone compaction, request receipts,
canonical request digests, spawn claims, incarnation counters, "private SessionManager ownership
proof is pruned so release churn remains bounded across restart", and the eviction/cleanup retry
protocol. None of that is actionable by a consumer of @sapiom/harness; it is the design note for
this stack.

Separately, the "Breaking for embedders" paragraph names SubsessionCoordinator and "internal
session hosts that construct the Agent Map MCP router". Neither createAgentMapMcpRouter,
createAgentMapToolServer, nor SubsessionCoordinator is exported from
packages/harness/src/index.ts — so the changelog asserts a break that no published consumer can
hit, and readers will go looking for a migration that does not apply to them.

Fix: cut the body to what a consumer can observe and act on — a new project_subsession_delegate
MCP tool on /mcp/agent-map; its bounds (16 per batch, 4 nesting levels, 64 coordinator-owned
sessions per project); the delegate / refresh-focused-context / release / release-dormant
operations; and the one behavioral rule they must honor (uncertain kickoff is terminal, use a new
request key when canonical content changes). Move the state-machine narrative to
packages/harness/docs/shared-build-plan.md, which this PR already extends and which does not
ship (files is dist, LICENSE, CHANGELOG.md, README.md). Drop or rescope the breaking note to the
actual public surface (the widened AnalyticsEventType union from shared/types.js).

2. One tool call can block for ~16 minutes with no aggregate deadline

delegate() (packages/harness/src/core/subsession-coordinator.ts:252) awaits reconcileBinding
sequentially for every item, and the schema allows 16 per request
(packages/harness/src/server/agent-map-mcp-tools.ts:97). Each item can burn the full readiness
budget twice: waitForReady (subsession-coordinator.ts:1084) and then waitForAdapterIdentity
(subsession-coordinator.ts:1041), both bounded by readinessTimeoutMs, which defaults to 30 s and
is not overridden at the only construction site (packages/harness/src/server/index.ts:3204).

Failure scenario: an agent delegates 16 children on a loaded machine and each takes ~35 s to reach
adapter identity. The MCP request runs ~9–16 minutes and the client request timeout fires first. The
coordinator has by then already spawned real Harness sessions and written durable bindings, but the
calling model receives no result and cannot tell what landed. The retry does converge on the same
bindings, so this is recoverable rather than corrupting — but the first call is unusable and the
model is left guessing.

Suggest a wall-clock budget spanning the batch: once it is spent, stop waiting and return the
remaining items with the existing readiness_timeout / retry error so the caller gets a
well-formed partial result inside one request.

3. README still advertises three MCP tools; the endpoint now serves eight

packages/harness/README.md:144 reads "Every trusted project session receives the same three
project-wide tools" and lists only agent_map_read / agent_map_validate / agent_map_propose.
The tool list asserted in packages/harness/src/server/agent-map-mcp.test.ts:117 is now eight,
including project_subsession_delegate. The README ships in the tarball, so this is a published
inaccuracy about the package's primary integration surface.

The drift started in earlier increments of this stack, and the PR body defers "final expanded
tool/schema/prompt guidance" to PR 15 — but this PR widens the gap, and the one-line count fix
belongs with it rather than three PRs later.


Verdict: Request changes — finding 1 must land before publish (the changelog is permanent);
findings 2 and 3 are fixable in this PR without touching the coordinator's design.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Review — PR #833 (round 2, follow-up)

Delta reviewed: 193a0168ef760767. The feature commit is byte-identical after rebase; all
movement is in fix(harness): bound delegation batch readiness waits.

Round 1 findings

  1. Changeset — fixed. Body cut 49 → 9 lines, state-machine narrative moved to the non-shipping
    docs/shared-build-plan.md, and the false "Breaking for embedders / SubsessionCoordinator"
    claim replaced with the real public break (AnalyticsEventType gains 16 subsession.* members,
    and src/index.ts:6 does re-export shared/types.js, so that one is accurate).
  2. Unbounded batch wait — fixed. batchWaitTimeoutMs (default 30 s) now spans the whole batch
    and both wait phases (subsession-coordinator.ts:248,527,1059,1102); exhaustion returns
    readiness_timeout / retry per item with durable IDs. Two tests cover partial results and the
    converging retry.
  3. README tool count — fixed and now matches the nine names asserted in
    agent-map-mcp.test.ts:112, with the batch bounds documented.

New finding

Abandoned reserved bindings hold live capacity with no reclaim path.
When the budget expires mid-batch, the remaining items stay in sessionState: "reserved"
(subsession-coordinator.ts:263). reserved counts toward the 64-session live cap
(subsession-coordinator-store.ts:1553-1561), but release-dormant only sweeps exited/failed
(subsession-coordinator.ts:327), and plain release requires the same parentSessionId
(subsession-coordinator-store.ts:1141). Failure: a parent times out on a 16-item batch, leaves 15
reserved, then ends without retrying or releasing — those slots are unreclaimable by any operation,
and repeated occurrences dead-end the project at live_session_limit_reached. Previously this state
was only reachable via crash mid-batch; the new partial path makes it a routine outcome. Either
include reserved-with-no-runtime in the dormant sweep, or release unreached reservations before
returning the partial result.

Correction to round 1

Round 1 said the endpoint serves "eight" tools; it is nine. The README fix used the right number.

Verdict: Approve with one comment — the reclaim gap is worth closing here, but it is recoverable
while the parent session lives and does not block publish.

@ynadge
ynadge force-pushed the review/agent-map-13-child-sessions branch from cabf531 to 4aa4784 Compare September 5, 2026 12:17
@ynadge
ynadge force-pushed the review/agent-map-14-delegation-tool branch from ef76076 to 4af416a Compare September 5, 2026 12:17
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