Skip to content

DO NOT MERGE — merge train: 3238,3230,3231,3240 - #3251

Closed
vybe wants to merge 14 commits into
devfrom
train/20261005-1731
Closed

vybe wants to merge 14 commits into
devfrom
train/20261005-1731

Conversation

@vybe

@vybe vybe commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Integration surface for #3238, #3230, #3231, #3240. Never merged; members merge individually once green.

Carries one train-only commit: the chat_with_agent entry is removed from PENDING in tool-description-budget.test.ts, because #3240 brings that description under the cap and #3238's test fails an entry that fits. The same removal goes onto #3240's branch after #3238 lands.

dolho and others added 14 commits October 5, 2026 15:22
…inding fills (#3186)

A metric/status/progress widget bound to a declared metric gets its value
(and a status widget its color) from the recorded points on every read
(ent#479), and the agent server's validate_widget already exempts them.
D-003 still demanded value/color, so an agent following the documented
binding contract was reported HARD-incompatible.

D-003 now applies the agent server's predicate (a truthy `metric`) and
skips exactly the filled fields (_BOUND_FILLED); `label` stays required
and unbound widgets keep today's rule. Decided: a binding to an
undeclared name is exempt too — the backend renders "not declared" and
drops any written value, so requiring one demands a number nobody sees.
D-009 checks the metrics block's shape only; no check flags undeclared
bindings yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#3214)

Docker volumes are daemon-global while the sweep's ownership check reads
one stack's DB, so a second stack on a shared daemon reclaimed every other
stack's unattached agent volumes — force-removed, logged at INFO.

- Every agent data volume is created through docker_utils.
  agent_volume_labels, which stamps trinity.instance=<installation_id>
  (instance_identity.get_instance_id — the durable id the alert label
  already abbreviates; one source). All six creation sites use it, pinned
  by a guard test.
- The sweep lists candidates on the instance label's key AND value and
  skips the cycle when the id is unresolvable.
- is_reclaimable_agent_volume refuses a volume labelled for another
  instance, closing the same hole on the retention-purge path (two stacks
  can both have an agent `alpha`).
- Legacy (unlabelled) volumes fail closed: labels are immutable, so the
  sweep never reclaims them; unowned+unattached ones are named in one
  WARNING per change of that set for a human. Own agents' volumes are
  still removed at retention purge, which is ownership-row driven.
- Reclaims and removals log at WARNING as unrecoverable, naming volumes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… — never re-send on silence (Abilityai/trinity-enterprise#568)

The receipts already existed on every dispatch route (#914, #2661, #2670);
what was missing was the caller knowing what they mean. In the 2026-09-08
cascade every duplicate dispatch was an agent re-sending after "could not
confirm delivery". The contract is now ONE text, taught wherever a caller
reads:

- the platform prompt, §Agent Collaboration (DELEGATION_CONTRACT spliced into
  PLATFORM_INSTRUCTIONS) — every agent, every turn, no image rebuild;
- verbatim in the chat_with_agent and every dynamic chat_with_<agent>
  description (src/mcp-server/src/delegation_contract.ts) — the copy an
  external MCP client, or an agent at PromptTier.MINIMAL, reads; fan_out and
  send_message repeat its rule sentence and point at it;
- the receipt message itself: every MCP-authored receipt ends with "Do not
  re-send: read the outcome with get_execution_result(agent_name=…,
  execution_id=…)", chat() reuses queuedTimeoutReceipt, and runAgentChat
  rewrites the backend's REST-only "Poll GET …" line on accepted/queued.

Claude Code cuts every MCP tool description at 2,048 characters
(CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH). The old chat_with_agent description
was 2,424, so its async and list_recent_executions advice never reached a
model. It is now lead + modes + contract (~1.9 KB); per-mode detail moved into
parameter descriptions, which are not cut.

The text names only what the platform produces today: no `replayed` (ent#566
has not shipped it), the agent.task.* wake scoped to parallel runs (a
sequential /chat turn emits none), `retryable: false` → "do what its message
says" (gate refusals say "try again shortly"). The unverified
"concurrent-duplicate guard will kill mid-execution" claim is gone from the
description, the receipts and requirements §37.1 — no such guard exists.

Tests: tests/unit/test_ent568_delegation_contract.py (byte parity with the TS
copy via a strict JSON parse + guard-the-guard cases; every tool, argument,
status and event it names proven real; budget; AC4) and
src/mcp-server/src/delegation-contract.test.ts (the descriptions a real
tools/list publishes, under the cap; receipt messages on chat/task timeout,
409 replay, async accepted/queued and the pull-routed path). 15 wiring
mutations each go red. CI boot smoke also imports dist/tools/dynamic-agents.js.

Docs: requirements §37.5, architecture/mcp-server.md, six feature flows, the
agent guides' stale "will fail after 60 seconds" sections, user-docs.
Follow-ups filed: #3232, #3233, #3234.

Implements Abilityai/trinity-enterprise#568.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mport

- test_2669: get_instance_id() mints installation_id on purpose. A volume
  created before the id exists would carry no owner and never be
  reclaimed. It gets an _ALLOWED_USES entry with that reason, like the
  label tier's existing entry.
- test_agent_readiness_probe: the hand-written services.docker_utils stub
  lacked agent_volume_labels, which lifecycle.py now imports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e's 2,048-char description cap (#3234)

Claude Code shows a model only the first 2,048 characters of an MCP tool
description. The server publishes the full text, so the cut tails were
invisible from Trinity's side.

- deploy_local_agent (2,698 -> 1,477): the four packaging steps,
  including the manifest script, move into the `archive` parameter,
  whose description is not cut. Steps 1-2 are byte-identical to before.
  The description keeps the rules up front.
- get_objectives (2,349 -> 2,034): this tool has no parameter to carry
  detail, so the wording is tightened instead with no instruction
  dropped. "stale: DO NOT ACT" now comes right after the purpose.
- tool-description-budget.test.ts: a real createServer, a user-scoped
  key and tools/list over streamable HTTP. It fails naming every
  published tool over the cap with its length. chat_with_agent (2,424)
  is a shrink-only PENDING entry owned by Abilityai/trinity-enterprise#568,
  which is rewriting it; the entry fails once that tool fits.

Fixes #3234

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… out (Abilityai/trinity-enterprise#568)

AC1 lists `replayed` among the receipts. No dispatch route emits it until
ent#566 ships intent-scoped dedupe (only ask_operator answers `replayed`),
and the guard that checks every named status against a dispatch-route
producer would refuse it. A replay is still covered by "whatever its status"
and "an exact repeat is normally answered with the original" — observed live
on localhost: an identical repeat answered in 28 ms with the first call's
execution_id, and one task ran.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rding, history corrected (Abilityai/trinity-enterprise#568)

The PR #3240 review found three places where the change said more than
the code does.

- Contract, bullet 4: `agent_busy` is not proof that nothing ran. The
  SUB-003 usage-limit 429 is raised after the turn ran, and the MCP
  client labels it `agent_busy` (#3244). The bullet now sends that case
  through the same `list_recent_executions` check as every other error
  without an `execution_id`, then a word-for-word re-send after
  `retry_after_seconds`.
- Receipt leads: the backend stores the async receipt as the
  idempotency snapshot at dispatch time and replays it for 24 h (#3245),
  so "Accepted: the task is running" can be false on a replay. The leads
  now claim nothing about liveness. A replay of the backend's own
  sync-/task `queued_timeout` snapshot, which tells a REST caller to
  poll GET, is rewritten too; the MCP server's own `queued_timeout`,
  which already carries the read line, is left as it is.
- History: Claude Code's 2,048-character description cap has cut the
  `chat_with_agent` description since #2958 (2026-09-24), which took it
  from 2,035 to 2,424 characters. The receipt advice was delivered
  before that. Requirements, the learnings fragment and the CSO report
  now say so.

Tests: every `chat_with_*` tool must take `parallel` and `async`; the
dynamic-tool factory keeps the backend's line and falls back to the
exact default; each lead is pinned per status for agent, user and
self-task sessions; the backend `queued_timeout` replay is rewritten
and the MCP server's own is not. Ten mutations each turn a test red: a
dropped `async`, swapped or optimistic leads, a skipped rewrite per
session kind, a factory that ignores the backend line, both
`queued_timeout` branches, and TS-only contract drift.

Docs: execution.md names the sync `/chat` exception (it emits no
`agent.task.*` event), requirements §37.5 says why `replayed` is left
out, and follow-ups #3244 and #3245 are linked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Abilityai/trinity-enterprise#568)

The history now says Claude Code cut the `chat_with_agent` tail before
the model read it, instead of "any model" or "every agent": the 2,048
cap was read out of the Claude Code binary, and agents on the Codex or
Gemini runtimes reach the same tools through MCP clients that were not
measured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vybe

vybe commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Train gated green; #3238, #3230 and #3231 merged, #3240 merging on its own checks. Closing the integration surface.

@vybe vybe closed this Oct 5, 2026
@vybe
vybe deleted the train/20261005-1731 branch October 5, 2026 17:50
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.

3 participants