# DISMISSED — AMG-3 — the fenced-real-gate / plain-decoy self-approval in the records auto-merge guard

status: dismissed by TRIAGE 2026-08-24 · **premise FALSIFIED by the queue-as-directory migration (47e8e73)** · raised panel run 12 (2026-08-21) · body verbatim below · **the exploit still ALLOWs — what died is its consequence**

---

## Resolution — the exploit survives, its authority does not

**Stated bluntly first, because this is a dismissal of a live exploit:** the
fence-decoy probe still returns ALLOW against the guard at HEAD. This row is
dismissed because **the thing it could poison no longer decides anything**, not
because the code was fixed.

**The item's premise, in its own words, had two conjuncts.** Both are now
false:

1. *"an implementer LLM reading the raw file may honour the fenced
   self-approval"* — **FALSIFIED.** `ops/RESEARCH_IMPLEMENTER.md:49` now reads
   `research/queue/approved/` — one file per approved item, a directory. The
   implementer does not read `research/RESEARCH_QUEUE.md`'s `## Approved`
   section at all.
2. *"the poisoned file MERGES TO MAIN, making the decoy the canonical rendered
   gate for every future reader"* — **FALSIFIED.** The canonical gate is now
   the directory, enforced by PATH rather than by parsing:
   `scripts/automerge_guard.py:51` and `:191` deny any agent write into
   `research/queue/approved/` with no parsing involved.
   `research/RESEARCH_QUEUE.md` is a **frozen archive** whose own header says
   so, and whose `## Approved` section reads `_(none yet …)_`. A decoy planted
   there is a defaced museum label, not a gate.

**This is exactly the finding panel run 13 recorded, independently.** See
`research/queue/open/amg-5-sanctioned-move-fail-open.md`, cross-reference
section: *"AMG-3 (archive item 16) → PARTIALLY CLOSED / defanged … build
authority moved to the directory, so the merged poison no longer drives the
implementer."*

**What is left, and where it goes.** The guard still carries
`QUEUE_FILE = "research/RESEARCH_QUEUE.md"` and its `## Approved`
section-parsing machinery (`automerge_guard.py:74, 111-142, 228-238`) — dead
weight that can still be tricked but no longer gates anything. Panel run 13
already recorded the cheapest full close **inside the AMG-5 row**, which
touches the same file: add `^research/RESEARCH_QUEUE\.md$` to the guard's deny
patterns (a frozen archive needs no auto-mergeable edits) and delete the
vestigial section parser. That is where the residual belongs — one fix, one
PR, one row. Duplicating it here is how one defect becomes two queue rows.

**Explicitly NOT dismissed with it: AMG-4** (`queue/open/`), which panel run 13
re-verified as still live and aggravated, and which AMG-5 states plainly it
does **not** subsume.

**Reopens if:** (a) the guard's `## Approved` section parsing, or
`research/RESEARCH_QUEUE.md` itself, ever regains authority over any consumer
(the implementer, the digest, the go-live gate, a future routine); or (b) the
frozen archive is un-frozen and returns to being a live queue surface; or
(c) the AMG-5 fix lands **without** the deny-pattern/parser-deletion fold-in
recorded above, leaving trickable gate-parsing code in a guard whose docstring
still claims it fails closed everywhere.

---

## Body as raised (verbatim from the frozen archive)

**16. AMG-3 — the records auto-merge guard still ALLOWs a self-approval when
the real `## Approved` gate is wrapped in a Markdown code-fence and a plain
decoy `## Approved` is planted outside it; AMG-2's fix (955db93) did not touch
this, and the 2026-08-18 reopen valve fired with both its conjuncts true.** ·
judgement: **YES** · effort 0.25 pd · horizon: live now (any routine with
contents-write can mount it)

*Mechanism, reproduced this run.* `scripts/automerge_guard.py:106`
`_strip_fences()` runs BEFORE the `## Approved` header-uniqueness count at
`:115` and before section extraction. So a records-only EDIT to
`research/RESEARCH_QUEUE.md` that (a) wraps the genuine `## Approved` section —
carrying an inserted self-approval — inside a ```-fence, and (b) plants a
second, plain `## Approved` header outside the fence with the verbatim
`_(none yet…)_` text, presents exactly **one** un-fenced header to the count,
so `AMBIGUOUS` (`:117-118`) does not fire and the decoy's empty content is
returned. Executed against the file at 10e4ce9: `ALLOW: records-only (1
file(s)); no gate touched`, with the self-approval present in the merged file.
The prior AMG-1/AMG-2 defences are structurally blind to this inversion — the
original attack hid the *decoy* in a fence; this hides the *real gate* in a
fence, and stripping deletes the evidence before counting. `ops/RESEARCH_
IMPLEMENTER.md` (`:33`, `:49`) instructs "Build ONLY what is in `## Approved`"
and mentions fences zero times, so an implementer LLM reading the raw file may
honour the fenced self-approval; and regardless of the implementer, the
poisoned file MERGES TO MAIN, making the decoy the canonical rendered gate for
every future reader.

*Valve provenance.* The `## Dismissed` entry dated 2026-08-18 pre-registered:
"REOPENS as its own row if AMG-2's fix lands with **neither** the
pre/post-fence-strip `## Approved` header-count-differ guard leg **nor** the
`RESEARCH_IMPLEMENTER.md` §1 fence-quotation pin." 955db93 landed with
neither (grep-verified: no fence logic added; `RESEARCH_IMPLEMENTER.md` still
has no fence text). Both conjuncts hold; this is the valve firing, not a fresh
discretionary find.

*Data plan.* None — static code + this run's probe fixture. Owned.

*Test design + kill criterion — pre-registered, negative-controlled both
ways.* Add the probe fixture (fenced-real-gate + plain-decoy) as a permanent
**deny-asserted** test, plus a clean-file **allow** control. The fix is an
**unscoped** raw-vs-fence-stripped `^## Approved` header-count compare: if the
counts differ, DENY. (Do NOT scope it to a gate-sentinel line — verified: the
live queue file has exactly 1 approved header both raw and stripped and 4
fenced blocks with zero headers, so an unscoped compare is false-positive-free
today, simpler, and strictly stronger; scoping reintroduces the parsing
subtlety that has now beaten this function three times. A future legitimate PR
that *quotes* the gate inside a fence costs only a DENY→human-merge, which is
the correct handling for a PR reproducing the gate verbatim.) **Kill
criterion:** probe fixture DENYs and both controls ALLOW post-fix; revert the
guard change → the deny test reds. **Owner escape:** if the owner rules the
`RESEARCH_IMPLEMENTER.md` fence-quotation pin sufficient on its own, the
guard-side gap closes as *accepted-and-recorded* — but the acceptance record
must state that **merge-poisoning of the queue's rendered gate remains
possible** (the pin defends only the implementer's read, not the merged file),
not merely that a known-ALLOW fixture is kept.

*Cross-reference row 17 (F2, the self-widening flank) — same file, different
mechanism, possibly different fix-owner; deliberately a separate row per the
2026-08-11 valve's own "as its own row" clause.*
