Skip to content

DO NOT MERGE — merge train: 3261,3181,3227,3252 - #3266

Closed
trinity-ability wants to merge 22 commits into
devfrom
train/20261006-0833
Closed

trinity-ability wants to merge 22 commits into
devfrom
train/20261006-0833

Conversation

@trinity-ability

Copy link
Copy Markdown
Contributor

Integration surface for #3261, #3181, #3227, #3252. Never merged; members merge individually once green.

dolho and others added 22 commits October 2, 2026 10:57
Dismiss (Abilityai/trinity-enterprise#748): one click ends a pending
question or approval as disposition=dismissed (status stays cancelled)
through the ask ending sink — audit, thin broadcast, and the filer's
wake with its own framing. 5s client-side Undo window; nothing is sent
until it lapses. Addressee only (person gate, uniform 404); a dismiss
that loses a race, or lands past the deadline, is a no-op.

Discuss (Abilityai/trinity-enterprise#747): opens one chat per ask with
the asking agent (CAS link in a new platform-only context key), titled
after the ask, with the ask as its tile; a turn-context provider puts
the ask (id, kind, live status, options) in every turn there. The ask
stays one pending row; a question can be answered from the composer
with "Send as answer" (written as response).

Also renders agent markdown in the ask context's "Your recent answers"
list, the surface #3115 missed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Inbox turned Discuss's open-thread into a bare /workspace/c/<id>
push, and the #3140 guard read the just-created chat (not yet in the
thread list) as not the viewer's. Route it through the shell's
openThread, which adopts the id, and refresh the list. The chat tile
now forwards open-thread too — its Discuss did nothing before.

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

An answer that woke an opted-in agent left the woken run's output in the
execution history only — the person saw the agent start and never saw
what it did. The resume run now carries the Workspace destination (the
ask's discussion chat, else its attached chat; only when the answerer is
the addressee), so the ent#457 completion report posts the result there
as an agent message. The open chat watches for it for up to 5 minutes,
since it has no history poll.

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

# Conflicts:
#	src/frontend/src/components/portal/PortalConversation.vue
…rite errors

F1: an answered ask's resume run reports into the ask's DISCUSSION chat
only. The attached-chat fallback (Main for a background ask) widened every
answered ask's audience to the client — verbatim final reply, shared files,
inherited by delegated children. The run is now told its reply goes to
the person. Store watch narrowed to match. Tests pin turn_audience and
delegation inheritance for the stamped run.

F2: the discussion-link write tolerates only SQLite's busy snapshot
(OperationalError). Any other failure, or a busy write with no racing
link while the ask is still pending, is a retryable 503 instead of
"409 This ask is already pending".

F3: the discussion's system notice no longer quotes the agent-written title.
F4: options are truncated before JSON encoding, keeping the closing quote.
F5: Dismiss refuses alerts (422), like Discuss and the card.
F7: real TestClient tests through get_portal_principal (agent key 403)
and the live in-process limiter (429).
Send as answer stands down while a reply chip or attachment is in the
composer (#3168 collision). tables.py disposition comment lists dismissed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
operating-room.md: an answered ask's result returns to its discussion
chat only; the attached chat is not a destination (F1), so an
undiscussed answer's run stays owner-only.
backend.md: turn_context now has one OSS provider, the discussed-ask line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A queued /task row carries delivery settings in backlog_metadata. The push
drain applied them in run_async_task; the pull sink wrote the terminal and
stopped. On a pull pilot a Chat-tab /task (save_to_session, trigger manual)
succeeded and never reached the chat session, and the collaboration activity
stayed started.

- run_post_turn_delivery: the three post-turn steps (chat-session save and
  broadcast, collaboration activity, self-task finalisation), moved out of
  run_async_task. The push drain and the pull sink both call it.
- request_from_metadata: the queued-request rebuild, shared by _spawn_drain
  and the pull sink.
- Pull sink: on the CAS-won branch, spawns delivery when the metadata asks for
  it, then signals the sync waiter with the chat session id; signals at once
  when there is nothing to deliver. Delivery failure never blocks the signal.
- A token-gated SUCCESS write refuses a row already SUCCESS or SKIPPED. The
  claim token survives the terminal write, so a worker's retried result POST
  won the CAS twice and would have saved the chat turn twice. A late SUCCESS
  still corrects a FAILED row.
- close_execution_activity and the bulk close also close the collaboration /
  self-task activity a queued row names, so a terminal written outside
  run_async_task (pull sink, lease-reaper park, expire, watchdog) does not
  leave it started.
- Sync /task keeps the chat_session_id the sink signals.

Fixes #2329

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pplied terminal (#2329)

- The lease reaper closes the dead attempt as CANCELLED on a row it has just
  re-queued. The queued-activity close now runs only for a row that is
  terminal, so the collaboration / self-task activity stays open for the
  re-delivered attempt (a CANCELLED close is never upgraded).
- Sink delivery runs only when the row still holds the status its own CAS
  wrote, so FAILED then a late SUCCESS under one token saves the turn once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…patch.dict re-import

test_channel_image_vision re-imports adapters.message_router inside a
patch.dict(sys.modules, ...) that mocks adapters.base. patch.dict puts the
original module back in sys.modules on exit, but not the `adapters` package
attribute the re-import rebound, and `import adapters.message_router as mr`
resolves through that attribute. A later test then received the module built on
the mocked ChannelResponse: test_ent751_gate_callers::
test_a_channel_message_held_by_the_gate_is_answered_in_the_conversation failed
after test_1533 + test_channel_image_vision, reproduced on the base commit
09f9d08 (pre-existing, order-dependent; surfaced by an -n auto run).

An autouse fixture in the polluting file puts the binding back after every
test. The three-file reproduction goes from 1 failed to 88 passed. Learnings
fragment added (the 2026-08-10 package-attribute / sys.modules class).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n was approved for it (Abilityai/trinity-enterprise#752)

The dispatch-time gate (#751) reads what a requester typed, so a request
that names a gated skill only in prose ("please pay the invoice") reached
the executor, and the agent's own Skill call loaded the skill. On Claude Code
agents a PreToolUse hook now asks the platform before a skill loads into a
run, and refuses it unless that run was cleared for it.

- Hook: docker/base-image/hooks/skill-gate.py (bootstrap) + _skill_gate.py,
  registered by its own managed-settings drop-in
  (/etc/claude-code/managed-settings.d/50-skill-gate.json, root 0444, exec
  form under `env -i` + `-I -S`, LD_* pinned empty) on Skill and on
  Agent/Task subagent `skills:` preloads. Identity from /proc (the claude
  process's launch env, the container's), never its own env. Every outcome
  is exit 0 or 2 under a 10 s deadline — for this CLI exit 1, a crash or a
  hook timeout lets the tool run. No verdict → a root-owned marker decides:
  an agent with gates fails closed, every other agent keeps its skills.
- Check: POST /api/skill-gate/check (routers/skill_gate.py), the agent from
  its key (get_self_agent), every verdict a 200; refusals hand the request
  back ("…with a message that includes /pay-invoice…"), name no person or
  role, and are audited skill_gate_refused (throttled).
- Clearance is execution + skill (D3), not an input hash: #751's approved-run
  record, or a new `self_approved` record that record_self_approval writes at
  /task, /chat (moved from admission to the row's setup — the agent receives
  the row's id, not the capacity slot's) and the execute_task backstop. No
  migration: a new value in skill_gate_requests.state, outside the lattice.
- A self-approved /chat turn runs in its own session (isolated_session), so
  the next caller never resumes a context with the skill loaded.
- Marker synced at start/recreate (gated agents only), self-healed from
  the check (rate-limited) and serialised per agent; /health reports
  skill_gate_hook.
- Review hardening: a skill or subagent definition whose name the hook
  cannot read (or an unterminated front matter) is "could not tell", never
  "not gated"; block-scalar names are read; no subagent_type means
  general-purpose (a definition may override it); CLAUDE_CONFIG_DIR from
  the claude env adds its dirs; refusal audits are capped per agent (the
  run id is the caller's); a logger that cannot start never changes the
  verdict. Every wired call site and each review fix was mutation-checked.

Inert until ent#753 supplies the gate map. Stated limits in
requirements/security.md §26.13 (Claude Code only; not a boundary against an
adversarial executor — credential confinement is, R23 / ent#558).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ading slash never reaches it (Abilityai/trinity-enterprise#752)

The localhost eyeball showed that Claude Code expands an approved or
self-approved request that starts with /pay-invoice without any Skill call,
so the hook is never asked about it; the dispatch-time check decides those.
The hook's allow path is a Skill call inside the cleared run (a slash
mid-sentence, or the model choosing the skill).

- skill-gate.md Testing step 7 now uses the mid-sentence form for the approved
  and self-approved cases, adds the isolated /chat probe and the no-run case,
  replaces "stop the backend" (the chat itself goes through it) with a check
  route that answers 503, and saves the running base image before the build so
  the restore never downgrades the agents.
- §26.13 and the flow's limits say what a clearance lets through.
- "the session tab" is the Chat tab.
- Status records the 2026-10-05 eyeball.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st-runner classifies its skip (Abilityai/trinity-enterprise#752)

The skip matched no rule in test-runner's skip-patterns.txt and showed up as an unclassified warning in /verify-local's unit stage. Its skipif is exactly 'not Linux', so the reason now says so and the existing GATED:Linux only rule classifies it.

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

On a browser-claimed install (every one-click / marketplace path) the
only system-agent deploy runs at boot, before /setup has created the
admin, and fails with "Admin user 'admin' not found". Nothing retried
it, so trinity-system stayed absent until a backend restart.

/setup now schedules ensure_deployed() as a background task after the
admin row is written, ahead of first-run seeding (the boot order; the
seeder hosts its alerts on trinity-system). The task never raises, since
Starlette runs background tasks in sequence, and skips without Docker.

Fixes #3237

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
merge-train: resolve pull_coordination_service.py — keep dev's #2514
_spawn_breaker_verdict and follow it with #2329's _spawn_post_turn_delivery,
which replaces the inline signal_sync_waiter. Mechanical, per the merge-train
note on the PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#2329 close-owner docstrings

merge-train: expire_stale_queued writes FAILED and calls no closer, so the
docstrings and the test docstring overstated coverage. Mechanical, per the
merge-train note on the PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
merge-train: resolve docs/memory/feature-flows.md — keep both 2026-10-05 rows
(ent#752 from this branch, ent#568 from dev). Mechanical, per the merge-train
note on the PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ui PR touches the frontend UI — triggers Playwright e2e tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants