SynapCores v1.14.2 — Your agent worked on run 1 and quietly stopped by run 10

Published on August 10, 2026

SynapCores v1.14.2 — Your agent worked on run 1 and quietly stopped by run 10

The worst kind of bug isn't the one that crashes. It's the one that keeps reporting success.

We found this one the honest way: by building a real three-agent compliance pipeline against the shipped image and running it ten times in a row. Run 1 did exactly what it was told — read the deal, check the watchlist, write a ruling into an append-only ledger. By run 10 the agent was answering in prose and writing nothing. Every run still reported status = success.

Agents were being poisoned by their own history

A durable agent replayed a shared, per-tenant conversation transcript into every run. When the engine saved that transcript, it stripped the tool evidence — the calls, the arguments, the results.

So what each new run actually read was a doctored record of its own past: a conversation where the assistant answered questions without ever calling a tool. Small models are excellent few-shot learners. They copied it.

Nothing in the product made this visible. The audit table said success, because the run had completed and produced text.

Durable agents are now stateless by default. Run N is no longer primed by run N-1's phrasing. Working memory is a per-run scratchpad. If you want continuity you opt into memory = 'persistent' — and then tool evidence round-trips faithfully and stays isolated per (agent, subject), so two agents sharing a persona can't teach each other bad habits.

Failure is loud now

The deeper problem was that a broken agent looked identical to a working one. _system_agent_runs now distinguishes them:

SELECT agent_name, exit_reason, tool_calls_made, iterations_used
FROM   _system_agent_runs
ORDER  BY started_at DESC;

A run that finished without calling a single tool reports completed_no_tools, not success. A model stuck re-issuing the same call reports stalled instead of grinding to the iteration ceiling. _system_agent_transcripts keeps tool_name, tool_args and tool_result per turn, so you can read what actually happened rather than what the summary claims.

Unknown personas are rejected at CREATE AGENT instead of being silently downgraded to a generic prompt. Models that can't call tools are refused at creation rather than failing mysteriously at 3am.

A five-word prompt beat a carefully written one

Personas are first-class objects now — CREATE, ALTER, DROP, SHOW, DESCRIBE PERSONA — and building the pipeline taught us something we didn't expect.

Two personas, identical task, identical model, identical engine. The only variable was the prompt.

persona executed the instructed statement
'You are a compliance reviewer.' 3 / 3
the conversational default 0 / 3

The conversational one greeted the agent, asked what its name was, offered to help further, and ended the run having done nothing at all. It's a good chat prompt. Attached to an unattended agent it's a liability, because there is no human on the other end to answer "could you let me know your name?"

If you're driving an unattended agent, keep the prompt task-shaped. Tell it to do the work and report the value. That's the whole trick.

Three ways your queries were quietly wrong

Not agent-related, and not new — these were sitting under normal SQL.

DELETE left index entries behind on TEXT primary keys. Delete a row, and the key stayed in the index:

CREATE TABLE t (id TEXT PRIMARY KEY, v TEXT);
INSERT INTO t VALUES ('A','a');
DELETE FROM t;                  -- 1 row deleted, COUNT(*) = 0
INSERT INTO t VALUES ('A','a'); -- ERROR: Duplicate key

Row ids were only removed from the index when they parsed as an integer. An INTEGER primary key worked fine; a TEXT primary key leaked on every single delete. That's why it looked random for so long — it depended entirely on your key type.

UPDATE never touched explicit secondary indexes. Index maintenance was gated on the constraint list rather than the index catalog, and CREATE INDEX doesn't create a constraint. So after an update, queries filtering on that column returned the old value and found nothing under the new one. No error — just wrong rows.

A lookup matching zero rows raised an error instead of returning an empty result.

What we checked before shipping

  • feature_validator: 88/88
  • Recipe certification: 160/162 from a pristine data dir, zero regressions
  • Non-AVX-512 hardware: model loads, EMBED returns 384 dims, 0 SIGILL
  • The pipeline that started this, run 10× in a row: 10/10 produced a hash-chained ledger, 117/117 agent runs called their tools, 0 ended completed_no_tools, and 19 rulings across 3 subjects came out identical every time — no contradictions

That last number is the one that matters. Consistency is the whole product claim for an agent that writes to a compliance ledger.

Known issues, stated plainly

COUNT(<column>) counts the NULLs an outer join produces, so a LEFT JOIN with no match returns 1 where SQL requires 0. Verifying an immutable table reports success on an empty chain, so read the record count next to it. And a single run of a multi-subject agent queue may not drain every pending item — the rulings it does produce are correct and consistent.

Upgrading

Drop-in from v1.14.1.1, with one behaviour change worth knowing: CREATE AGENT now rejects a persona that doesn't exist. If you have agent SQL naming a persona you never created, create it, switch to a built-in, or opt out per statement with WITH (allow_unknown_persona = true).

docker pull synapcores/community:v1.14.2-ce
curl -fsSL https://get.synapcores.com | sh

Full notes: docs.synapcores.com/releases/v1.14.2-ce