Development record
RecordGrounds is an unlocked read-modify-write so a concurrent second grounds write silently discards the first
RecordGrounds is an unlocked read-modify-write so a concurrent second grounds write silently discards the first
Found by the round-2 adversarial security review of build/itd-179.
Two sessions each running abcd intent ready itd-N --grounds "..." both read
the same record, each appends onto its own snapshot, and the later write wins.
Both processes print the "recorded grounds" receipt and exit clean, so nothing
reports the loss: the groundsWriteIsReadable count check compares each
writer's own before/after pair, which stays consistent. Reproduced in 40 trials
of two concurrent RecordGrounds calls on one record; 39 lost an entry.
This falsifies the append-only guarantee the same file documents at
internal/core/intent/grounds.go:50-55 ("Recording is APPEND-ONLY: a second
gate decision adds an entry beside the first rather than replacing it").
It also reopens a defect already resolved one day earlier in this same package:
iss-2608300235388164, whose body records that stampPlanned was a
read-modify-write with no lock, and whose fix put the sequence under
withIntentMintLock at internal/core/intent/lifecycle.go:319 with the
comment naming exactly this failure. The branch adds a second writer to the
record and does not take the lock.
Remedy: wrap the readRepoFile -> appendGroundsBullet -> writeIntentFile
sequence in withIntentMintLock, as stampPlanned does.
CORROBORATED independently by the round-2 ruthless review, which graded it
FIX-FIRST, reproduced it 20/20 with two goroutines (zero errors returned), and
verified the remedy: applying withIntentMintLock around read -> append ->
groundsWriteIsReadable -> writeIntentFile in a scratch copy takes the
reproduction to 20/20 green with go test and go test -race ./internal/core/intent/ both staying green.
Two adversarial reviewers, in fresh contexts and by different routes, landed on the same defect and the same one-line remedy. That is the strongest signal this cycle has produced for a single finding.
Grounds
- pursued: we expect an append-only contract to hold only where one advisory lock spans the whole read-modify-write, and a concurrent-loss reproduction that stays green after the lock is what would show it wrong
Frontmatter
| id | iss-2608301206036067 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-2608301206036067-recordgrounds-is-an-unlocked-read-modify.md
open on GitHub ↗ · commit history ↗
mentions2
- iss-2608300235388164The claim parser and stamper are fence-blind and comment-blind: a Scope Conditions heading inside a fenced code block shadows the real section (first match wins) so intent plan writes a marker into the fence and intent ready reports READY on the example while the real conditions go unchecked; a fenced example bullet under the real heading is stamped and counted; a commented-out block is read as live and the stamp's closing sequence ends the outer comment early; a hand-typed marker of the wrong shape is silent prose, gets a real marker glued beside it, and the bogus comment leaks into the JSON text; a second Scope Conditions heading is ignored without report; stampPlanned is a read-modify-write with no lock. Track fence state in sectionLineRange, refuse to stamp a section containing a fence or a duplicate heading, fault a malformed marker by name with a delete-it remedy.
- itd-179The reasoning behind what was pursued no longer evaporates at the gate — readiness and triage record grounds for the conjecture, not only the decision