You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(pm): post-stamped's unread-knock check never narrows on a stamp that names no instant
The `--body` refresh derives "the body's last write" from the newest protocol
stamp in the stored body, and the file's header promises that derivation is a
LOWER bound: more comments count as newer, never fewer. It was not. The newest
stamp went through `Date.parse` alone, which rolls an impossible date FORWARD
and returns an ordinary number — a stored `2026-04-31T00:00Z` read back as
1 May, so a knock at `2026-04-30T12:00:00Z` fell outside the window, the check
answered `none-newer`, and the refresh voided the knock.
`lastWriteStamp` now judges every stamp with `stampRealInstant`, the same round
trip the write side refuses a quoted stamp with — one predicate, never two. A
stamp that names no instant (NaN or rolled over) is not read as the last write
at all; the derivation falls back to the newest REAL stamp, which is earlier, so
the window only widens, and a body whose stamps are all unreal lands on the
existing no-stamp rule and counts every comment. Nothing else moves: a card with
nothing newer is still written, so the acceptance control the header states
("no unread knock ⇒ the refresh is not affected") holds unchanged.
The derivation always answers an object now, carrying the stamps it refused to
read, so the refusal, the transcript line and the `--json` transcript can name a
window that is wider than the body looks instead of claiming the body carries no
stamp at all.
Self-test: 186 → 204 cases; the unread-knock battery floor 23 → 41.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
'the substitution: one clock, read once, written everywhere': 9,
1113
1196
'the read-back: what the transcript can actually prove': 11,
1114
1197
'the CLI: the one decision a typo must never make': 16,
1115
-
'the unread-knock check: a refresh cannot void what nobody read': 23,
1198
+
'the unread-knock check: a refresh cannot void what nobody read': 41,
1116
1199
'the shared rule: this tool and H56 cannot come to disagree': 6,
1117
1200
});
1118
1201
constSELF_TEST_BATTERY_FLOOR=10;
@@ -1386,6 +1469,37 @@ export function selfTest() {
1386
1469
t('…and one at the last second of the minute before does not',unreadComments({storedBody: SEAT_BODY,comments: [{id: 1,created_at: '2026-09-12T09:59:59Z'}]}).ok===true);
1387
1470
t('the newest is by created_at, not by input order',unreadComments({storedBody: SEAT_BODY,comments: [LATER,KNOCK]}).newest.id===5648793698);
1388
1471
t('a comment with an unreadable created_at is newer, never silently old',unreadComments({storedBody: SEAT_BODY,comments: [{id: 7,created_at: 'n/a'}]}).ok===false);
1472
+
// The post-stamped reading: a STORED body whose newest stamp names no instant
1473
+
// the calendar has. `Date.parse` rolls 31 April FORWARD to 1 May, so reading
1474
+
// it as the last write moved the window LATER and a knock inside the gap read
1475
+
// as "none-newer" — the derivation shrank, which the header forbids. The
1476
+
// write side refuses such a stamp; a stored body can still carry one by hand,
1477
+
// through the platform's own editor, or from before this tool existed.
t('⭐ THE FILED READING: a knock inside a rolled-over stamp\'s gap is NOT "none-newer"',rolled.kind!=='none-newer',`kind=${rolled.kind}`);
1484
+
t('…it is refused as unacknowledged — the window may only widen',rolled.ok===false&&rolled.kind==='unacknowledged');
1485
+
t('…because the rolled-over stamp is not read as the last write at all',rolled.since.stamp===null&&rolled.since.from===null);
1486
+
t('…and the stamp it would not read is named, with the date it actually rolls to',rolled.since.unreal.length===1&&rolled.since.unreal[0].stamp==='2026-04-31T00:00Z'&&rolled.since.unreal[0].rolledTo==='2026-05-01T00:00Z');
1487
+
t('…the refusal says THAT, rather than claiming the body carries no stamp',unreadRefusalText(rolled,18293).includes('2026-04-31T00:00Z')&&unreadRefusalText(rolled,18293).includes('names an instant the calendar HAS'));
1488
+
t('…and still points at the newest comment as the flag to pass',unreadRefusalText(rolled,18293).includes('--ack-through=5678039238'));
t('⭐ a stamp that does not parse AT ALL reaches the same outcome — one rule, not two accidents',noParse.kind==='unacknowledged'&&noParse.since.stamp===null);
1491
+
t('…and reports no rollover it did not have',noParse.since.unreal.length===1&&noParse.since.unreal[0].rolledTo===null);
t('⭐ with an older REAL stamp beside it the window measures from THAT one — earlier, so wider',fellBack.since.stamp==='2026-04-29T09:00Z');
1494
+
t('…so the same knock still counts as newer',fellBack.ok===false&&fellBack.after.length===1&&fellBack.after[0].id===5678039238);
1495
+
t('…and the refusal says the window is WIDER here, never narrower',unreadRefusalText(fellBack,18293).includes('WIDER here, never')&&unreadRefusalText(fellBack,18293).includes('2026-04-31T00:00Z'));
1496
+
t('⭐ --ack-through naming the newest comment still clears a body with no readable stamp',unreadComments({storedBody: ROLLED_BODY,comments: [GAP_KNOCK],ackThrough: 5678039238}).kind==='acknowledged');
1497
+
t('⭐ THE ACCEPTANCE CONTROL: nothing newer ⇒ the refresh is still written, unreal stamp or not',unreadComments({storedBody: ROLLED_BODY,comments: []}).ok===true);
1498
+
t('…and the pass line names the stamp the derivation did not read',unreadPassText(unreadComments({storedBody: ROLLED_BODY,comments: []})).includes('2026-04-31T00:00Z'));
1499
+
t('⭐ THE CONTROL, UNCHANGED: a body whose stamps are all real is judged exactly as before',control.ok===true&&control.kind==='none-newer'&&control.since.stamp==='2026-09-12T10:00Z'&&control.since.unreal.length===0);
1500
+
t('…and its pass line carries no skipped-stamp clause at all',unreadPassText(control).includes('NOT read as the last write')===false);
1501
+
t('a body with NO stamp stays distinguishable from one with only unreal stamps',lastWriteStamp('nothing stamped').unreal.length===0&&lastWriteStamp(ROLLED_BODY).unreal.length===1);
1502
+
t('lastWriteStamp always answers an object, so no caller can read a null as "no stamp problem"',lastWriteStamp('nothing stamped').stamp===null&&Array.isArray(lastWriteStamp('nothing stamped').unreal));
1389
1503
t('the pass line names what was measured against',unreadPassText(control).includes('2026-09-12T10:00Z'));
1390
1504
1391
1505
battery('the shared rule: this tool and H56 cannot come to disagree');
0 commit comments