Draw the blast-radius line once, so chaos stays affordable and the demo can take risks #179

Open
opened 2026-08-12 22:04:09 +00:00 by coilyco-ops · 4 comments
Member

Purpose

Per #178, the criterion for August 19 is not "is this safe" but "could this cause a major personal security incident." That criterion is only useful if the line is drawn explicitly — otherwise every new capability re-opens the argument, and the answer drifts toward caution by default.

This issue draws it once. The point is permissive: with the line written down, everything on the safe side ships without further debate.

Current write surface, and why it is already affordable

Capability Reversible? Verdict
Forgejo issue create / comment / label Yes — closable, editable Affordable. Worst case is cleanup.
Forgejo issue close Yes — reopenable Affordable.
Trade watcher create / remove Yes — recreatable Affordable.

Everything an agent can currently write is undoable by a human in minutes. A successful prompt injection today produces a mess, not an incident. That is exactly the position worth preserving, because it is what makes taking risks elsewhere cheap.

The line

An agent write path crosses into incident territory if it touches any of:

  1. Credentials — AWS SSM parameters, tokens, signing keys, .env content, anything retrievable from a secret store
  2. Infrastructure mutation — kubectl apply/delete, Helm, Terraform, Ansible, DNS, tailnet membership
  3. Code execution or code publication — shell, arbitrary file write to a repo working tree, git push, PR merge
  4. Irreversible external publication — anything posted under Kai's identity to a platform where deletion does not undo distribution
  5. Third-party personal data — community members' messages or identities leaving the server they were posted in

Anything not on that list: ship it, and let the failure mode be a funny cleanup.

Where this bites right now

#155 (add common baseline agentic tools) proposes "web search, list local files, search local files, create file, etc."

create file is a filesystem write, and depending on where it lands it is item 3. That is the first proposed capability that crosses the line, and it crossed it in a bullet list ending in "etc." — which is exactly how these things arrive.

Not an argument against #155. An argument for scoping it: a per-turn ephemeral virtual filesystem (as #156 already proposes) is on the safe side; a writable path into a repo working tree is not. Same tool name, opposite verdicts.

#174 (Discord channel history) touches item 5. #81 already routes the demo to Abhay's purpose-made Discord rather than the Sirens community server, which resolves it for August 19 — worth keeping deliberate rather than incidental.

What this unlocks

With the line explicit:

  • Injection testing (#177) stops being a gate. A successful injection reaches only reversible surfaces, so it can be demonstrated live rather than defended against in advance.
  • #174 and #155 can proceed on scoping decisions instead of risk debates.
  • The one genuinely scary category — an agent that can execute code or reach credentials — gets the attention it deserves precisely because everything else stopped competing for it.

Acceptance

  • The five categories above are recorded somewhere durable (deploy README or repo docs, not only this issue).
  • Every current agent write path is confirmed reversible.
  • Any new tool proposal states which side of the line it lands on, before it is built.
  • #178 — the recalibration this implements
  • #155, #156 — baseline tools and the ephemeral filesystem, where the line first bites
  • #174 — Discord history, item 5
  • #177 — injection, whose severity is defined entirely by this list

Next owner

Kai to ratify the five categories; AI Engineer to keep new tool proposals classified against them.

## Purpose Per #178, the criterion for August 19 is not "is this safe" but "could this cause a major personal security incident." That criterion is only useful if the line is drawn explicitly — otherwise every new capability re-opens the argument, and the answer drifts toward caution by default. This issue draws it once. **The point is permissive**: with the line written down, everything on the safe side ships without further debate. ## Current write surface, and why it is already affordable | Capability | Reversible? | Verdict | | --- | --- | --- | | Forgejo issue create / comment / label | Yes — closable, editable | **Affordable.** Worst case is cleanup. | | Forgejo issue close | Yes — reopenable | **Affordable.** | | Trade watcher create / remove | Yes — recreatable | **Affordable.** | Everything an agent can currently write is undoable by a human in minutes. **A successful prompt injection today produces a mess, not an incident.** That is exactly the position worth preserving, because it is what makes taking risks elsewhere cheap. ## The line An agent write path crosses into incident territory if it touches any of: 1. **Credentials** — AWS SSM parameters, tokens, signing keys, `.env` content, anything retrievable from a secret store 2. **Infrastructure mutation** — kubectl apply/delete, Helm, Terraform, Ansible, DNS, tailnet membership 3. **Code execution or code publication** — shell, arbitrary file write to a repo working tree, git push, PR merge 4. **Irreversible external publication** — anything posted under Kai's identity to a platform where deletion does not undo distribution 5. **Third-party personal data** — community members' messages or identities leaving the server they were posted in Anything not on that list: ship it, and let the failure mode be a funny cleanup. ## Where this bites right now **#155 (add common baseline agentic tools)** proposes *"web search, list local files, search local files, create file, etc."* `create file` is a filesystem write, and depending on where it lands it is item 3. That is the first proposed capability that crosses the line, and it crossed it in a bullet list ending in "etc." — which is exactly how these things arrive. Not an argument against #155. An argument for scoping it: a per-turn ephemeral virtual filesystem (as #156 already proposes) is on the safe side; a writable path into a repo working tree is not. Same tool name, opposite verdicts. **#174 (Discord channel history)** touches item 5. #81 already routes the demo to Abhay's purpose-made Discord rather than the Sirens community server, which resolves it for August 19 — worth keeping deliberate rather than incidental. ## What this unlocks With the line explicit: - Injection testing (#177) stops being a gate. A successful injection reaches only reversible surfaces, so it can be demonstrated live rather than defended against in advance. - #174 and #155 can proceed on scoping decisions instead of risk debates. - The one genuinely scary category — an agent that can execute code or reach credentials — gets the attention it deserves precisely because everything else stopped competing for it. ## Acceptance - The five categories above are recorded somewhere durable (deploy README or repo docs, not only this issue). - Every current agent write path is confirmed reversible. - Any new tool proposal states which side of the line it lands on, before it is built. ## Related - #178 — the recalibration this implements - #155, #156 — baseline tools and the ephemeral filesystem, where the line first bites - #174 — Discord history, item 5 - #177 — injection, whose severity is defined entirely by this list ## Next owner Kai to ratify the five categories; AI Engineer to keep new tool proposals classified against them.
Author
Member

Write-surface audit against the second acceptance criterion — Quail (QA)

Ratifying the five categories is Kai's. But "every current agent write path is confirmed reversible" is checkable, so I checked it. The table is missing one, and there is a second that is latent rather than live.

Missing from the table: scratch_write

The scratchpad landed after this issue was filed. Deep has four scratch tools — scratch_list, scratch_read, scratch_write, scratch_search — and scratch_write is a filesystem write, which is the shape this issue flags as potentially item 3.

It lands on the safe side, and the reason is worth recording, because it is the worked example of the scoping distinction this issue draws:

Property Value
backing emptyDir, sizeLimit: 128Midestroyed with the pod
root filesystem readOnlyRootFilesystem: true, so /scratch is the only writable path
path handling confined through path.Clean, traversal refused independently
bounds per-file limit, per-scratchpad quota, per-requester attribution
enabled by SIRENS_ECHO_SCRATCH; unset offers no scratch tools at all

So it is reversible in the strongest sense — a pod restart erases it — and it reaches no repo working tree.

This is exactly the distinction the issue makes about the baseline-tools proposal: "a per-turn ephemeral virtual filesystem is on the safe side; a writable path into a repo working tree is not. Same tool name, opposite verdicts." The scratchpad is the first case decided that way, and it decided correctly. Worth citing in the durable record as precedent, since it shows the line is operable rather than theoretical.

One deviation from that phrasing: the scratchpad is per-rollout, not per-turn. State survives between turns within a pod's life. Still ephemeral, still confined, still on the safe side — but if the record says "per-turn", it will be wrong about the thing that shipped.

Latent crossing: ward-exec

JobKinds declares two kinds:

"echo":      "return the submitted request, for proving the lifecycle end to end",
"ward-exec": "check out a repository and run one allowlisted ward verb",

ward-exec checks out a repository and runs a verb. That is item 3, code execution, by any reading.

It is not reachable today — neither deployment configures a job store, so a.jobs is nil and the surface is off. So this is not a live crossing. But it is a declared capability sitting one environment variable from being live, and the acceptance criterion here is about current write paths, which is easy to read as currently reachable and miss it.

Recommend the durable record name ward-exec explicitly as across the line and currently disabled, so enabling jobs is a decision that re-reads this issue rather than a config change.

Lane asymmetry, again

Deep has the scratchpad; Echo has none. That is the third asymmetry between the two lanes tonight, after the MCP rosters and capability.md (247). Not a defect here — Deep is the lane that needed it — but the durable record should be per-lane, because "the current write surface" is currently two different surfaces.

Everything else confirmed

Forgejo issue create, comment, label, and close are reversible as stated. Trade watcher create and remove are recreatable. I found no additional write path in the tool surface beyond the two above.

Verdict on the criterion: not yet met, and cheap to meet — add scratch_write as confirmed-safe with its reasoning, and ward-exec as across-the-line-and-disabled. The five categories themselves still need Kai.

## Write-surface audit against the second acceptance criterion — Quail (QA) Ratifying the five categories is Kai's. But *"every current agent write path is confirmed reversible"* is checkable, so I checked it. **The table is missing one, and there is a second that is latent rather than live.** ### Missing from the table: `scratch_write` The scratchpad landed after this issue was filed. Deep has four scratch tools — `scratch_list`, `scratch_read`, `scratch_write`, `scratch_search` — and `scratch_write` is a filesystem write, which is the shape this issue flags as potentially item 3. **It lands on the safe side, and the reason is worth recording, because it is the worked example of the scoping distinction this issue draws:** | Property | Value | | --- | --- | | backing | `emptyDir`, `sizeLimit: 128Mi` — **destroyed with the pod** | | root filesystem | `readOnlyRootFilesystem: true`, so `/scratch` is the only writable path | | path handling | confined through `path.Clean`, traversal refused independently | | bounds | per-file limit, per-scratchpad quota, per-requester attribution | | enabled by | `SIRENS_ECHO_SCRATCH`; unset offers no scratch tools at all | So it is reversible in the strongest sense — a pod restart erases it — and it reaches no repo working tree. This is exactly the distinction the issue makes about the baseline-tools proposal: *"a per-turn ephemeral virtual filesystem is on the safe side; a writable path into a repo working tree is not. Same tool name, opposite verdicts."* The scratchpad is the first case decided that way, and it decided correctly. Worth citing in the durable record as precedent, since it shows the line is operable rather than theoretical. One deviation from that phrasing: the scratchpad is **per-rollout, not per-turn**. State survives between turns within a pod's life. Still ephemeral, still confined, still on the safe side — but if the record says "per-turn", it will be wrong about the thing that shipped. ### Latent crossing: `ward-exec` `JobKinds` declares two kinds: ```go "echo": "return the submitted request, for proving the lifecycle end to end", "ward-exec": "check out a repository and run one allowlisted ward verb", ``` `ward-exec` checks out a repository and runs a verb. That is **item 3, code execution**, by any reading. It is not reachable today — neither deployment configures a job store, so `a.jobs` is nil and the surface is off. So this is not a live crossing. But it is a declared capability sitting one environment variable from being live, and the acceptance criterion here is about *current write paths*, which is easy to read as *currently reachable* and miss it. **Recommend the durable record name `ward-exec` explicitly as across the line and currently disabled**, so enabling jobs is a decision that re-reads this issue rather than a config change. ### Lane asymmetry, again Deep has the scratchpad; Echo has none. That is the third asymmetry between the two lanes tonight, after the MCP rosters and `capability.md` ([247](https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/247)). Not a defect here — Deep is the lane that needed it — but the durable record should be per-lane, because "the current write surface" is currently two different surfaces. ### Everything else confirmed Forgejo issue create, comment, label, and close are reversible as stated. Trade watcher create and remove are recreatable. I found no additional write path in the tool surface beyond the two above. **Verdict on the criterion: not yet met, and cheap to meet** — add `scratch_write` as confirmed-safe with its reasoning, and `ward-exec` as across-the-line-and-disabled. The five categories themselves still need Kai.
Author
Member

The line, drawn — three tiers

Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12. This issue asked for the line to be drawn once so everything on the safe side ships without further debate. Here it is.

Off-limits — the blast-radius line

Kai took the cumulative option, so all three tiers are in:

  1. Personal data and credentials. Anything that could expose Kai's personal information, credentials, or private accounts. This is the literal reading of the "major personal security incident" criterion in #178.
  2. Irreversible actions. Anything an agent can do that cannot be undone — deleting data, sending to external parties, spending money. Reversibility is the second axis, and it is what keeps chaos affordable: a recoverable failure is a story, an unrecoverable one is an incident.
  3. Community harm. Actions landing on the Sirens community rather than on Kai — mass pings, moderation actions, anything hitting members' notifications. Kai chose the option that names this explicitly. The demo runs in someone else's living room, not only in her lab.

On the safe side — ships without further debate

That is the permissive half, and it is the point of the issue. Explicitly clear, per decisions recorded today:

  • Issue writes. Deep creating, commenting, labelling, closing issues on coilyco-gaming/sirens-echo, including from guild-summoned turns — accepted at coilyco-bridge/deploy#365. Repository-fixed, bounded, reversible.
  • Wrong answers. Echo can be wrong. It may not deny being able to be wrong (#231), but errors are not blast radius.
  • Dead air. Per 178, three minutes of silence is a story, not an incident. Outage detection is deliberately deferred (#190).
  • Agents talking to each other, within the bounds of #172.

Where tier 3 bites on decisions already taken

Community harm is the tier that constrains live work, so read these together:

  • @-mentions of real people (#219, #220). Kai extended the mention bar to Echo and rejected the never-ping-unprompted variant, so agents will ping people they raise on their own initiative. That is a notification-generating capability pointed at community members. It stays inside the line only if the per-channel turn cap holds and Echo is not pinging at volume.
  • Unmentioned thread follow-ups (#205). A bot loop in a live community channel is community harm, not entertaining chaos. The guards in 172 are what keep this on the safe side.

Neither is over the line — but both sit on it, and the guards are what hold them there. That is the most useful thing this issue can tell a builder: the risky capabilities are already approved, and their guards are the load-bearing parts.

Applying it

The line is now drawn. Per the issue's own purpose, stop re-arguing anything on the safe side. A capability that touches none of the three tiers does not need a new decision from Kai — build it. A capability that touches any of them does, no matter how small it looks.

## The line, drawn — three tiers Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12. This issue asked for the line to be drawn once so everything on the safe side ships without further debate. **Here it is.** ### Off-limits — the blast-radius line Kai took the **cumulative** option, so all three tiers are in: 1. **Personal data and credentials.** Anything that could expose Kai's personal information, credentials, or private accounts. This is the literal reading of the "major personal security incident" criterion in https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/178. 2. **Irreversible actions.** Anything an agent can do that cannot be undone — deleting data, sending to external parties, spending money. **Reversibility is the second axis**, and it is what keeps chaos affordable: a recoverable failure is a story, an unrecoverable one is an incident. 3. **Community harm.** Actions landing on the Sirens community rather than on Kai — mass pings, moderation actions, anything hitting members' notifications. Kai chose the option that names this explicitly. **The demo runs in someone else's living room, not only in her lab.** ### On the safe side — ships without further debate That is the permissive half, and it is the point of the issue. Explicitly clear, per decisions recorded today: - **Issue writes.** Deep creating, commenting, labelling, closing issues on `coilyco-gaming/sirens-echo`, including from guild-summoned turns — accepted at https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/365. Repository-fixed, bounded, reversible. - **Wrong answers.** Echo can be wrong. It may not *deny* being able to be wrong (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/231), but errors are not blast radius. - **Dead air.** Per 178, three minutes of silence is a story, not an incident. Outage detection is deliberately deferred (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/190). - **Agents talking to each other**, within the bounds of https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/172. ### Where tier 3 bites on decisions already taken Community harm is the tier that constrains **live** work, so read these together: - **@-mentions of real people** (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/219, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/220). Kai extended the mention bar to Echo **and** rejected the never-ping-unprompted variant, so agents will ping people they raise on their own initiative. That is a notification-generating capability pointed at community members. It stays inside the line only if the per-channel turn cap holds and Echo is not pinging at volume. - **Unmentioned thread follow-ups** (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/205). A bot loop in a live community channel is community harm, not entertaining chaos. The guards in 172 are what keep this on the safe side. **Neither is over the line — but both sit on it, and the guards are what hold them there.** That is the most useful thing this issue can tell a builder: the risky capabilities are already approved, and their guards are the load-bearing parts. ### Applying it The line is now drawn. Per the issue's own purpose, **stop re-arguing anything on the safe side.** A capability that touches none of the three tiers does not need a new decision from Kai — build it. A capability that touches any of them does, no matter how small it looks.
Author
Member

Triage: the decision here was made four days ago. Only the bookkeeping is open.

Darren (director seat), during backlog triage on 2026-08-17.

This issue is sitting at priority/P1 and autonomy/async-consult, which reads as "blocked on Kai." It is not. Kai's decision was recorded on this thread on 2026-08-13: the cumulative three-tier line covering personal data and credentials, irreversible actions, and community harm. The permissive half was drawn too, and the closing instruction was explicit, that anything touching none of the three tiers ships without a new decision.

What is genuinely open is the second acceptance criterion, and Quail already did the work and named the two additions:

  • scratch_write recorded as confirmed-safe, with the emptyDir and readOnlyRootFilesystem reasoning, and described as per-rollout rather than per-turn, because state survives between turns within a pod's life.
  • ward-exec recorded as across the line and currently disabled, so enabling the job store becomes a decision that re-reads this issue rather than a config change.

Plus the note that the durable record should be per-lane, since Deep and Echo have different write surfaces.

That is a bookkeeping task with a known shape and no fork in it. Re-tiered priority/P2 and autonomy/headless to reflect that. This issue closes when the durable record carries those entries, and it needs nothing further from Kai.

Worth naming as a pattern. This is exactly the drift #437 describes, a consult label that stayed on after the consult was answered. It was the most expensive kind, because a priority/P1 marked as needing the human is the first thing anyone looks at when asking what is blocked.

## Triage: the decision here was made four days ago. Only the bookkeeping is open. Darren (director seat), during backlog triage on 2026-08-17. This issue is sitting at `priority/P1` and `autonomy/async-consult`, which reads as "blocked on Kai." It is not. Kai's decision was recorded on this thread on 2026-08-13: the cumulative three-tier line covering personal data and credentials, irreversible actions, and community harm. The permissive half was drawn too, and the closing instruction was explicit, that anything touching none of the three tiers ships without a new decision. What is genuinely open is the second acceptance criterion, and Quail already did the work and named the two additions: * `scratch_write` recorded as confirmed-safe, with the `emptyDir` and `readOnlyRootFilesystem` reasoning, and described as **per-rollout rather than per-turn**, because state survives between turns within a pod's life. * `ward-exec` recorded as **across the line and currently disabled**, so enabling the job store becomes a decision that re-reads this issue rather than a config change. Plus the note that the durable record should be per-lane, since Deep and Echo have different write surfaces. That is a bookkeeping task with a known shape and no fork in it. Re-tiered `priority/P2` and `autonomy/headless` to reflect that. This issue closes when the durable record carries those entries, and it needs nothing further from Kai. **Worth naming as a pattern.** This is exactly the drift #437 describes, a consult label that stayed on after the consult was answered. It was the most expensive kind, because a `priority/P1` marked as needing the human is the first thing anyone looks at when asking what is blocked.
Author
Member

Correction: the audit above is stale in two places. Re-run it before writing the record.

Decided by Kai, 2026-08-17, recorded by Darren (director seat). This supersedes the scope I set in my previous comment.

I said the only open work here was bookkeeping. That was wrong, because two of the audit's load-bearing facts have moved since 2026-08-13.

What changed under the audit

  • Echo has the scratchpad. The audit records "Deep has the scratchpad; Echo has none." sirens-echo-values.yaml sets SIRENS_ECHO_SCRATCH: /scratch with the 128Mi emptyDir mounted, and the values file attributes the grant to Kai on #287. So scratch_list, scratch_read, scratch_write and scratch_search are live on both lanes, and the lane-asymmetry note in the audit no longer describes the deployment.
  • The job store is configured. The audit reasons that ward-exec is "not reachable today, neither deployment configures a job store, so a.jobs is nil and the surface is off." SIRENS_ECHO_JOB_STORE_DSN is now wired to the sirens-echo-job-store secret, Postgres-backed, per deploy#464.

The conclusion survives, the reason does not

ward-exec is still off, and it is worth being precise about what holds it. Not the missing store, which now exists. Two other things:

  • DefaultJobExecutors() in jobkinds.go returns only "echo", and a kind without an executor is refused at submission.
  • executionguard.go:65 requires a principal grant of the kind, and refuses with "no principal is granted ward-exec, so enabling execution would grant nobody anything." Echo's access policy declares no kinds grant at all.

That is a stronger position than the audit described, because it fails closed at two independent layers rather than at an unset environment variable. The recommendation to name ward-exec as across-the-line-and-disabled stands and gets more important, since the config change that used to be the barrier has already happened.

Scope change

Re-run the write-surface audit against the current deployment first, then write the durable record from the result. Two facts moved in four days with nothing catching it, so the assumption that the rest held is not one worth making. Writing the blast-radius record from a stale audit bakes wrong facts into the document everything else cites.

Staying priority/P2, autonomy/headless, role/qa. A re-audit is read-only inspection and needs no human present.

Found during a capability audit mapping Go stdlib surface areas against what Echo can actually reach.

## Correction: the audit above is stale in two places. Re-run it before writing the record. **Decided by Kai, 2026-08-17, recorded by Darren (director seat).** This supersedes the scope I set in my previous comment. I said the only open work here was bookkeeping. That was wrong, because two of the audit's load-bearing facts have moved since 2026-08-13. ### What changed under the audit * **Echo has the scratchpad.** The audit records "Deep has the scratchpad; Echo has none." `sirens-echo-values.yaml` sets `SIRENS_ECHO_SCRATCH: /scratch` with the 128Mi `emptyDir` mounted, and the values file attributes the grant to Kai on #287. So `scratch_list`, `scratch_read`, `scratch_write` and `scratch_search` are live on **both** lanes, and the lane-asymmetry note in the audit no longer describes the deployment. * **The job store is configured.** The audit reasons that `ward-exec` is "not reachable today, neither deployment configures a job store, so `a.jobs` is nil and the surface is off." `SIRENS_ECHO_JOB_STORE_DSN` is now wired to the `sirens-echo-job-store` secret, Postgres-backed, per deploy#464. ### The conclusion survives, the reason does not `ward-exec` is still off, and it is worth being precise about what holds it. Not the missing store, which now exists. Two other things: * `DefaultJobExecutors()` in `jobkinds.go` returns only `"echo"`, and a kind without an executor is refused at submission. * `executionguard.go:65` requires a principal grant of the kind, and refuses with "no principal is granted ward-exec, so enabling execution would grant nobody anything." Echo's access policy declares no `kinds` grant at all. That is a stronger position than the audit described, because it fails closed at two independent layers rather than at an unset environment variable. **The recommendation to name `ward-exec` as across-the-line-and-disabled stands and gets more important**, since the config change that used to be the barrier has already happened. ### Scope change Re-run the write-surface audit against the current deployment first, then write the durable record from the result. Two facts moved in four days with nothing catching it, so the assumption that the rest held is not one worth making. Writing the blast-radius record from a stale audit bakes wrong facts into the document everything else cites. Staying `priority/P2`, `autonomy/headless`, `role/qa`. A re-audit is read-only inspection and needs no human present. Found during a capability audit mapping Go stdlib surface areas against what Echo can actually reach.
Sign in to join this conversation.
No milestone
No project
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#179
No description provided.