ADR-024: SYN-185: batch approval over syn pending, not a syn agent runner
Date: 2026-06-08 Status: Accepted (owner, 2026-06-08) Author: Rômulo Febasi
Context
SYN-185 was filed as “syn agent: autonomous loop with batch approval”,
with the acceptance line: “BR-12.3 is a hard criterion: nothing applies
without human sign-off; batch approval means the human approves N proposals
at once, never the agent auto-applying.”
Two things changed between filing and implementation, making the literal “autonomous loop” framing the wrong thing to build:
-
The autonomous loop already exists, and it is the external agent. Synapse is local-first: it ships no LLM, holds no API keys, and (since SYN-219) no longer uses MCP server-initiated sampling. A loop in which “the AI works a task across multiple steps and queues writes” is exactly what an MCP client (Claude Code, etc.) does today over
syn mcp. Asyn agentcommand that ran a model itself would contradict the product’s foundations and duplicate the MCP session. The genuinely missing piece is the human side: sanctioning many queued proposals in one action instead of onesyn pending accept <id>at a time. -
ADR-022 superseded the “never auto-apply” line. When SYN-185 was filed, BR-12.3 was an absolute gate. ADR-022 (accepted 2026-06-07, implemented in SYN-218) evolved it into a confidence-tiered policy: the opt-in
safetier auto-applies low-risk, reversible writes (alink_entitybetween two existing non-selfentities), stampedauto-accepted. So “never the agent auto-applying” is no longer the rule, the rule is “the human sanctions everything the policy does not auto-apply.”
Decision
Deliver SYN-185 as batch approval on the existing syn pending queue, not
as a new syn agent command and not as an LLM orchestrator:
syn pending accept <id>...accepts one or more ids;syn pending accept --allsanctions every pending proposal in one action.syn pending reject <id>... | --all [--prune]mirrors it.- Each proposal applies independently and atomically (SYN-216): the batch
is best-effort: a failure on one is reported, it never half-applies and
never blocks the others. Cross-proposal all-or-nothing remains the job of a
single
propose_batchrow (SYN-202), which is the unit when atomicity across several writes is wanted. - There is no
syn agentcommand. The autonomous loop is the external MCP agent, unchanged.
Consequences
- Scope change (recorded): SYN-185’s
syn agentnoun and any “Synapse-runs-the-agent” reading are dropped. The issue’s deliverable, “human approves N at once”: is met bysyn pendingbatch flags. The milestone item is satisfied; the name is not. - Business-rule implications (recorded):
- BR-12.3 is intact and unchanged. A human still sanctions every
non-auto-applied write;
--allis one human action over the queue, not a bypass. The provenance + audit trail is unchanged. - The issue’s original “never the agent auto-applying” clause is
superseded by ADR-022 / SYN-218: the
safetier (opt-in, defaultmanual) auto-applies the low-risk, reversible class. Batch approval covers exactly what the policy leaves queued.
- BR-12.3 is intact and unchanged. A human still sanctions every
non-auto-applied write;
- Improves: the high-friction part of an agent-driven session (reviewing many queued writes one id at a time) collapses to one command, without weakening the gate.
- Open: if a richer “review the agent’s run” UX (showing auto-applied + pending together, interactive select) is ever wanted, it layers on top of these flags: revisit on demand.
Alternatives considered
- A
syn agent runorchestrator that shells out to an external agent CLI and drives a task loop. Rejected: depends on an external LLM/CLI, breaks local-first / no-API-key, and the loop already runs viasyn mcp. - A dedicated
syn agent reviewcommand with run transparency (auto-applied + pending, interactive). Reasonable, but more product than the deliverable needs; deferred (owner chose the minimal form). - Cross-proposal all-or-nothing for
accept --all. Rejected: one bad proposal would block every good one in a review-many flow; per-proposal atomicity + a clear failure report is the better UX.propose_batchalready provides all-or-nothing when that is the intent.