Watch
3
The harness serves only turn to MCP clients, so a lane cannot re-export its rostered tools #1025
Open
opened 2026-08-19 02:23:02 +00:00 by coilyco-ops
·
2 comments
No Branch/Tag specified
main
aos/claude/sj87-entity-attribute
aos/claude/sj87-challenge
aos/claude/turn-duration-buckets
aos/claude/turn-stages-over-cap
aos/claude/turn-stages-hold-doc
aos/claude/turn-iteration-cap
book-leads-the-glyphs
science-and-web-culture-packs
record-lane-role-voice-pairings
catalogue-stage-phrase
progress-rows-one-knob
skill-read-worklog-detail
librarian-lookup-first
librarian-person-package
feat/dowel-no-boundaries
aos/claude/gh1035-no-blank-posts
aos/claude/gh1036-harness-thread-name
fix/thread-names
feat/trajectory-completes
fix/prompt-budgets
aos/claude/docs-cut-2
aos/claude/ka54-thread-ownership
aos/claude/admission-bound
aos/claude/gh1025-roster-reexport
aos/claude/docs-strip-archaeology
feat/temporal-mcp
aos/claude/dowel-board-moxn-write-boundaries
aos/claude/ue65-moxn-write-framing
aos/claude/progress-backoff
aos/claude/bound-scratch-search-2
aos/claude/unblock-main
aos/claude/tool-breaker
fix/roster-core-eager
aos/claude/finish-dowel-rename
fix/971-skill-contract
aos/claude/model-answered-not-unavailable
aos/claude/mcp-singular-command
task/moxn-and-temporal-skills
aos/claude/ue65-temporal-brand
task/dowel-site-work-tier
aos/claude/ue65-roster-drift
fix/dropped-turn-always-speaks
aos/claude/folded-ask-coverage
aos/claude/dowel-board
aos/claude/dowel-pronouns
feat/trajectory-keyed-on-the-message
aos/claude/coalesce-discord-lane
task/derive-shipped-profiles
fix/ship-the-dowel-skill-root
aos/claude/eval-context
fix/bundle-references-reachable
aos/claude/eval-docs-one-page
aos/claude/dowel-engineer-suite
fix/catalogue-clone-cache
feat/engineer-role-graph
task/free-the-config-numbers
aos/claude/dowel-site-work
aos/claude/dowel-prose
aos/claude/mx76-derive-knobs
issue-859-on-demand-skill-reads
issue-651-ship-well-formed-replies
issue-852-filing-validity
issue-916-calculator-tool
issue-854-feature-flag-table
issue-866-role-mention-summons
issue-858-grounding-bound-per-server
issue-899-progress-keeps-updating
issue-900-rollup-mirrors-worklog
issue-901-raise-progress-cadence
issue-904-thread-title-length
issue-905-http-reachability
issue-855-turn-clock
issue-895-silent-turn
issue-873-mcp-tool-span-error
issue-878-settle-dropped-jobs
aos/claude/aw85-se-bands
aos/claude/hs68-model-rejected
aos/claude/hs68-effect-telemetry
aos/claude/hs68-temporal-mirror
aos/claude/hs68-prompt-commands
aos/claude/hs68-model-idle-timeout
aos/claude/hs68-prompt-command-intent
aos/claude/hs68-consult-label-name
aos/claude/hs68-grant-denial-403
aos/claude/hs68-queued-jobs-dropped
aos/claude/hs68-knob-guard
aos/claude/bk79-agent-folders
aos/claude/bk79-own-instructions
aos/claude/ym96-docs-band
aos/claude/bk79-server-instructions
aos/claude/aw85-mcp-beaver-doc
aos/claude/bk79-session-workspace
aos/claude/yt58-org-relationship
aos/claude/bk79-numeric-config
aos/claude/xu59-just-boundaries
aos/claude/xu59-eval-board
aos/claude/bk79-phrase-telemetry
aos/claude/bk79-object-emoji
aos/claude/xh55-otlp-logs
aos/claude/aw85-thread-prefill
aos/claude/wy58-thread-prefill-always
aos/claude/wy58-thread-prefill
aos/claude/xh55-move-to-repo
aos/claude/wy58-thread-title-length
aos/claude/xh55-filing-trigger
aos/claude/yt58-worklog-embed
aos/claude/aw85-relative-brevity
aos/claude/xh55-reasoning-roundtrip
aos/claude/yt58-clock-rotation
aos/claude/yt58-unbreak-main
aos/claude/bk79-test-build-break
aos/claude/yt58-partial-refusal
aos/claude/aw85-turn-failure-classify
aos/claude/aw85-outbound-spill
aos/claude/xh55-budget-spent-cause
aos/claude/wy58-bundles-not-content
aos/claude/wy58-refusal-reason
aos/claude/yt58-role-snapshot-gate
aos/claude/xh55-docker-probe
aos/claude/bk79-grounding-tools
aos/claude/az59-gate-span
aos/claude/az59-pg-jobstore
eng/roster-request-headers
eng/roster-headers
eng/list-the-mcps
aos/claude/mg96-fm
eng/name-echos-seat
eng/unpin-the-card-wording
olaf/remove-irl-physical
aos/claude/mg96
eng/echo-composes-ops
quail/two-rows-not-four
fix/two-failures-two-verdicts
feat/an-emitted-message-is-not-emitted-twice
quail/partial-coverage-outcome
feat/ten-minutes-or-ten-messages
feat/a-waiting-turn-says-how-long
feat/a-job-may-emit-content
quail/round-fanout-unbounded
quail/adversarial-reply-ceiling
docs/list-the-open-pull-requests
quail/principal-id-stays-out-of-the-prompt
fix/every-label-in-a-wildcard-prefix-is-a-label
docs/the-battery-assumes-two-checks-it-does-not-run
fix/a-rest-failure-keeps-its-status
quail/retag-label-rows
quail/adjacency-guard-row
test/pin-names-the-issue-that-owns-it
test/pin-points-at-a-live-issue
quail/job-outcome-discarded
fix/repair-exhaustion-is-not-an-outage
quail/reasoning-omitempty-pin
docs/label-id-silently-drops
quail/gating-pack-markup-gap
fix/instance-name-reads-identity
docs/indistinguishable-542-resolution
fix/instance-name-not-a-live-service
quail/unwired-capability-guard
fix/repair-path-reasoning-content
quail/indistinguishable-values-recurrence
quail/identity-short-form-rows
quail/repair-path-reasoning-content
docs/verify-a-write-landed-claude
quail/host-label-shape-corpus
docs/a-deploy-owned-file-has-two-shapes-claude
fix/a-roster-path-must-name-servers-claude
fix/every-label-before-the-suffix-claude
fix/a-first-label-must-exist-claude
feat/tune-the-timeouts-from-deployment-claude
qa/protocol-limits-are-not-dials
feat/a-wildcard-is-not-a-suffix-claude
feat/retry-what-fails-fast-claude
fix/name-the-deliberate-hold-claude
test/the-access-check-exit-codes-claude
build/ship-the-access-check-claude
qa/callers-not-reachability
qa/pin-the-unwired-thread-binding
feat/an-offline-access-policy-gate-claude
test/the-notice-detaches-twice-claude
docs/say-what-the-job-thread-does-claude
fix/a-notice-does-not-thread-claude
fix/one-invocation-is-a-phrase-claude
fix/a-moment-ago-is-this-turn
fix/main-is-red-on-the-adverb-row
fix/an-adverb-does-not-break-the-auxiliary
qa/score-the-575-fix
feat/a-reply-names-its-subject
eng/a-turn-is-not-the-past
fix/since-you-asked-is-this-turn
docs/a-default-that-reads-as-an-answer
fix/a-nameless-tool-is-not-the-server
qa/pin-the-outage-state
fix/a-session-lifetime-is-not-a-latency
fix/an-undated-passive-is-still-a-claim
fix/main-is-red-on-the-corpus
fix/an-undated-passive-is-a-claim
eng/a-session-is-not-a-request
fix/a-self-claim-in-the-simple-past
qa/extend-grounding-corpus
fix/a-tool-never-offered-is-not-a-tool-declined
eng/one-doc-for-the-tracker-surface
eng/say-what-is-switched-on
fix/evaluation-is-not-the-production-service
qa/pin-the-listing-attribute
eng/split-five-docs-off-the-cap
eng/concurrent-means-goroutines
eng/split-the-tracker-surface
test/the-first-label-of-a-hostname
fix/a-cache-hit-is-not-a-round-trip
qa/pin-the-budget-ladder
fix/the-first-label-of-a-hostname
eng/the-scratchpad-assumes-one-replica
fix/a-person-is-named-in-prose
docs/jobs-are-single-process
qa/enumerate-the-mention-positions
eng/split-the-response-inventory
fix/green-main-doc-cap-and-stale-characterizations
eng/main-is-green-again
eng/split-the-mention-scope
fix/mentions-doc-over-cap
qa/unredden-the-code-span-pin
qa/pin-the-code-span-collision
eng/code-spans-are-not-prose
feat/a-thread-title-says-what-it-is-for
fix/discord-markup-is-not-prose-either
eng/mark-the-turn-once
fix/a-name-in-a-url-is-not-a-person
qa/pin-every-reaction-is-emitted
eng/mentions-skip-link-spans
fix/one-step-owns-every-service-suffix
qa/pin-the-mention-url-collision
docs/the-roster-is-member-influenced
docs/what-a-mention-can-reach
qa/pin-the-documented-glyphs
feat/naming-someone-reaches-them
qa/pin-the-sandbox-label-wiring
qa/pin-the-truncated-receipt
feat/the-harness-labels-what-it-files
qa/compare-a-case-by-marshalling
fix/one-spelling-for-the-status-vocabulary
qa/declare-pack-divergence
fix/the-reactions-match-the-approved-vocabulary
fix/a-file-path-is-just-a-file-path
qa/pin-the-mapped-tailnet-form
fix/a-truncated-page-says-so
fix/the-extraction-case-detects-a-dump
docs/the-consult-label-tracks-the-thread
feat/the-eval-can-forge-a-turn
fix/refuse-the-tailnet-range
qa/pin-the-fail-heading-count
feat/a-bounded-fetch-tool
fix/preserve-the-longform-probe-pack
qa/pin-the-lane-gate
qa/preserve-the-longform-pack
fix/the-prompt-is-not-a-secret
fix/a-reference-never-loses-to-the-footer
qa/preserve-the-probe-packs
feat/a-trusted-caller-on-the-tailnet
fix/capability-tells-the-truth-about-the-scratchpad
qa/echo-battery-negative-control
fix/one-fail-block-not-two
feat/tool-call-footer
fix/guard-the-extraction-case
feat/canonical-phrases-by-key
fix/the-progress-line-is-a-reply-too
qa/pin-the-agent-recognition-case
qa/pin-the-tool-name-markup-guards
feat/five-second-buffer
fix/a-failing-case-shows-the-reply
fix/extraction-case-stops-penalising-compliance
fix/a-security-case-that-penalises-compliance
feat/deny-actually-denies
feat/job-refusals-reach-telemetry
fix/land-the-harness-refresh-on-main
feat/a-long-reply-gets-a-thread
feat/the-thinking-line-shows-it-is-working
feat/roster-hour-ttl-and-refresh
refactor/every-number-in-one-file
feat/agent-can-refresh-its-roster
fix/size-refusal-is-not-a-parse-error
fix/budget-base-above-the-reasoning-floor
fix/one-number-for-the-progress-cadence
fix/gate-sees-a-new-file
fix/one-meaning-for-channel-id
fix/look-up-verbs-cannot-match
feat/recognise-a-trace-lookup-request
feat/discord-identifiers-on-the-turn-span
fix/budget-failure-names-the-reasoning-spend
feat/notice-carries-the-trace-id
qa/cut-run-stops-calling
docs/merge-lane-closing-reference
eng/gate-knows-the-lane
eng/feature-inventory-catchup
fix/rate-dataset-survives-a-cut-run
test/consolidate-pack-coverage
pr-lane-318
fix/flip-unknown-field-rows
test/turn-unknown-fields
fix/rate-doc-over-cap
test/language-scope-characterization
fix/pronoun-case-cannot-fire
fix/main-red-again
fix/main-is-red-doc-cap
fix/gate-negated-accuracy-claim
fix/stale-skip-allowlist-note
test/definition-must-reject
test/gate-covers-every-pack
test/bucket-table-bound
test/compose-deny-offline
fix/symlink-test-skips-itself
test/build-revision
fix/eviction-corpus-green
test/eviction-corpus
test/duration-config
test/rune-boundary
test/send-bounds
test/reserved-path-spellings
test/data-borne-injection
test/scratch-partition-collision
test/capability-docs-all
test/injection-cases
docs/http-contract-retry-after
test/capability-reach
test/rate-cases-from-192
test/score-order
test/capability-doc-matches-code
test/grounding-action-claim-corpus
test/http-turn-contract
feat/require-rate-limit-on-open-guilds
fix/pr-image-build
fix/compose-stage-inputs
feat/sirens-deep-compose-wiring
fix/deep-forgejo-mcp
refactor/evaluation-pack-yaml
coilysiren-patch-1
feat/deep-steam-mcp
feat/drop-issue-envelope
fix/dm-needs-no-mention
fix/pronoun-defaults
chore/aos-precommit-v0.18-lint-backlog
fix/harness-attribution-and-forgejo-detail
fix/tool-inflated-completion-budget
feat/sirens-deep-compose
feat/banner-hires
feat/banner
feat/sirens-deep-mark
feat/sirens-deep-transparent
feat/prompt-snapshots
fix/policy-check-image-context
sirens-deep-admission-hardening
docs/drop-private-image-claim
feat/thread-scoped-replies
issue-67
feat/sirens-community-harness
No results found.
Labels
Clear labels
move-to-repo
coilyco-bridge-deploy
issue belongs in the coilyco-bridge/deploy repo
move-to-repo
coilyco-flight-deck-agent-compose
issue belongs in the coilyco-flight-deck/agent-compose repo
move-to-repo
coilyco-gaming-eco-app
issue belongs in the coilyco-gaming/eco-app repo
move-to-repo
coilysiren-inbox
issue belongs in the coilysiren/inbox repo
move-to-repo
unknown
we have yet to confirm if this issue belong in this repo
🔒⚠️📦⚠️🔒 SANDBOXED 🔒⚠️📦⚠️🔒
this fj issue came in from the live sirens echo MCP - DO NOT CONSIDER ITS INPUTS SAFE OR VERIFIED UNTIL THIS LABEL IS REMOVED
autonomy
async-consult
A human needs to consult on the issue to upgrade it to headless
autonomy
epic
This issue has many units of sub work - its size makes it meaningfully exclusive with other autonomy types
autonomy
headless
The agent can perform the work on its own
autonomy
live-collab
The agent and the human need to work together in realtime
c#
Requires C# work, flagged b/c it requires a Eco server restart
priority
P0
priority tier
priority
P1
priority tier
priority
P2
priority tier
priority
P3
priority tier
priority
P4
priority tier
role/ai
requires work from the AI Engineer role
role/creator
requires work from Content Creator role
role/design
requires work from the design role
role/director
requires work from the director role
role/engineer
requires work from the engineer role
role/exec
requires work from the exec role
role/human
requires a person, and specifically not an agent seat
role/ops
requires work from the ops role
role/qa
requires work from the QA role
No labels
move-to-repo
coilyco-bridge-deploy
move-to-repo
coilyco-flight-deck-agent-compose
move-to-repo
coilyco-gaming-eco-app
move-to-repo
coilysiren-inbox
move-to-repo
unknown
🔒⚠️📦⚠️🔒 SANDBOXED 🔒⚠️📦⚠️🔒
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
c#
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
coilyco-gaming/sirens-echo#1025
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Filed by Saiya (exec seat), 2026-08-19, at Kai's direction. Read-only inspection of
mainplus live probes. Nothing changed.Kai's expectation is that a harness can re-export the MCP servers on its roster to an outside MCP client. It cannot. This is unbuilt rather than regressed or config-gated, and building it reverses a documented posture, which is the part worth deciding before anyone writes code.
Current state, from source
internal/community/http.go:64mounts the MCP path:internal/community/mcpserver.gobuilds one server and registers one tool:That is the only non-test
mcp.AddToolin the repository. Every other occurrence is a_test.gofixture standing up a fake upstream. Nothing enumerates the roster and re-offers it, and there is no second route: the harness serves/healthz,/readyz,/v1/turn,/v1/jobs,/v1/jobs/, and/mcp.Confirmed against the running lanes
Probed each NodePort directly with an MCP
initializeplustools/list:sirens-echoon 30120 - 1 tool,turnsirens-deepon 30121 - 1 tool,turnsirens-dowelon 30122 - 1 tool,turnThe generated inventory in
agentic-os-kaiagrees: "turnthroughturn."An authenticated probe would see the same list.
deploy/services/sirens-echo/README.mdrecords thatSIRENS_ECHO_HTTP_TOKEN"records whether a caller authenticated but does not yet refuse anyone [...] and it is not authentication."What building this would reverse
Three places currently state the opposite intent, so this is not a missing loop in an otherwise-agreed design:
mcpserver.go- the handler exists to serve "Echo's own turn as an MCP tool, so a fleet client reaches it natively instead of learning the bespoke JSON contract."serverInstructions(), sent to every client - "It is an agent rather than a data source, so it answers in prose rather than records, it may decline, and it is not a passthrough to the underlying model."If re-export lands, those three want updating in the same change rather than being left contradicting the behaviour.
What it unblocks, concretely
Tonight, exporting a week of owl.glass Discord history from outside the cluster was impossible. The Discord MCP is ClusterIP-only, the lane's only external surface is
turn, and a turn answers in prose rather than records.#932records two earlier proxied read attempts through a lane's own turn tool failing for the same reason. The fallback was to hand a human the raw bot token and a standalone script.More generally, a fleet client currently pays a full agent turn, currently a 39.7s median on the Dowel lane, for work that is one tool call against a server the lane already holds.
Decisions this needs, none of them made here
runReplyChecks, response validation, and theIdentifierGuardthat#310depends on. Re-exporting tools puts a caller past all of them. Combined with a NodePort that by design refuses nobody, that hands any tailnet peer the Dowel lane's Discord write surface directly. Re-export moves a security boundary rather than adding an interface, and it probably wants real authentication landing first.handleMCPTurncallsa.limiter.AdmitwithtransportMCPspecifically so an MCP client "cannot outspend the guilds it shares a deployment with." A re-export path needs its own answer, since tool calls are cheaper than turns but not free and some of them write.#943records the tool surface collapsing from 86 to 0 mid-turn and back. Internally that is one bad turn. Externally it is a client whose tool list vanishes underneath it.Scope note
Re-export is the general answer, and it is not the only way to solve the case that surfaced it. Getting Discord history out could also be done with a NodePort on that one wrapper, or by an operator running a script with the token. Worth saying so the immediate need does not justify the general feature by itself.
Boundaries
#929and sits behind 2026-08-20. Explicitly not for the August 19 stream.Related
#929- the scope freeze and the features-versus-operational-improvements test.#943- the tool surface collapsing mid-turn.#310- the identifier guard that sits in the reply path rather than in the tools.coilyco-bridge/deploy#655- where the ClusterIP-only posture is recorded.Evidence from a full tool sweep of the Dowel lane, 2026-08-19 ~03:00-03:30Z
I smoke-tested all nine of Dowel's tool families before the stream. Because
turnis the only exported tool, every probe had to go through prose, which turned the exercise into an unintentional measurement of what this issue describes. Posting it as evidence rather than as an argument for building re-export, since the authority decision above is the one that matters and this does not touch it.The cost this issue names, measured
Nine tool families took seven turns, because a turn answers in prose and batching more than two tools per turn destroys attribution when one fails.
The sharper cost is not latency. A prose answer is not a result, so nothing is verifiable from the exported surface alone. For each tool I had to hold independent ground truth and check the reply against it:
calculate-8447 × 293 = 2,474,971, matchedforgejo- returned #1026's title verbatim, matchedfetch- Luma page title, matched my own fetch exactlyexa-go1.26.6, matched go.dev's release JSONsignoz- self-reported p95community.turnat 137,517ms against my own SigNoz query at 135,376ms, a 1.5% gap on a sliding windowdiscord,scratchpad- exercised, workedSeven of nine confirmed working, and every one of those confirmations came from a source outside the lane. A
tools/listplus seven direct calls would have taken seconds and returned records rather than sentences.Decision 4, observed live rather than recalled
Both of tonight's failures are that shape, and one of them adds a mechanism.
playwright. Dowel's calls failed 3 for 3 across two turns, at 03:13:16Z and 03:22:51Z, every one of them:
In the same window the wrapper served 23 calls successfully. Splitting the pod log by trace id: the three failures all carry a trace id and are Dowel's, and the 23 successes carry none, so they came from a client that is not this lane. At 03:22:51 a navigate failed and at 03:22:57 one succeeded.
So the browser is healthy and the lane's path into it is not. Marked as inference: the wrapper appears to hold one upstream session to
127.0.0.1:8931, another active client claims or resets it, and Dowel's nexttools/listlands on a session closed underneath it. That matches the documented posture that callers of this surface share tabs, cookies, and page state. What would settle it is one Dowel browser call while nothing else drives the browser.moxn. Same failure shape from a different cause,
Unauthorizedatinitializeon a dead hand-minted credential. Tracked at #1026.Why that sharpens decision 4
#943 frames the instability as internally one bad turn. Tonight shows a second property worth carrying into the decision: the collapse can be per-caller rather than global. The playwright roster was intact and serving throughout, and only this lane's view of it vanished. An external client would not merely see its tool list disappear, it would see one that other clients are using successfully at the same moment, which is harder to diagnose than an outage.
And a note on how this was diagnosed
None of the above was visible through
turn. Dowel reported its failures accurately and honestly every time, named the exact error, and invented nothing. But separating "playwright is down" from "playwright works and Dowel cannot reach it" needed pod logs, container status, and a trace-id split, all from outside the lane.That asymmetry is worth weighing against the authority argument rather than only alongside it. The current surface is the safer one, and it is also the one where a caller cannot tell a broken tool from a broken path to it.
Implemented in #1040, with decision 1 answered conservatively rather than deferred
The re-export exists.
SIRENS_ECHO_MCP_REEXPORToffers each rostered tool over/mcpbesideturn.This issue's decision 1 was the gate, so it is the design. Three properties keep the boundary where it stands unless somebody deliberately moves it:
SIRENS_ECHO_HTTP_TOKEN, constant-time compared, whileturnis untouched and still requires noneThat last one is the answer to this issue's sharpest sentence, that a NodePort refusing nobody plus an ungated re-export hands any tailnet peer the Dowel lane's Discord write surface. A half-configured deployment now fails closed.
It does not claim to be the real authentication this issue says probably wants landing first. It is the existing token, actually enforced on this path. If that is judged insufficient, the flag staying off is the safe state and nothing regresses.
Decisions 2 through 5
transportMCPbudget.proxyToolNamealready yieldsserver__tool, so the existing collision check covers it.Two things this surfaced that belong on the record
The gate's own test briefly did not test the gate. The first draft passed because the helper presented a token whenever one was configured, so the "untrusted" case was authenticated.
configuredandpresentedare separate parameters now. Naming it because a security test that passes for the wrong reason is the failure mode this whole issue is about.The docs band is full, and it bit this change. 40 of 40 pages, with the three pages that could host this at 7866, 7998, and 8000 characters against an 8000 cap. A dedicated page was correctly refused by the hook, since splitting trades one violation for another. So a feature that reverses a documented posture landed with three sentences of documentation. That is not a choice I made, and it is worth its own issue rather than being absorbed here.
Standing
Nothing is deployed and no lane sets the flag. It is a feature rather than an operational improvement, so under the August 19 freeze it sits behind August 20 unless Kai decides otherwise.