Thales
← research journal

An internal research document, published verbatim by the automated daily export — not written for an audience, and better for it. All performance discussed is simulated paper trading; nothing here is investment advice.

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.