Skip to content

Commit 2e6cf94

Browse files
jaysin586claude
andcommitted
docs(guard): close out typed-lint and stream-swap-follow plan batches
Both batches are fully landed on main — stream-swap-follow via PRs #54 (v0.1.17) and #55 (v0.1.18), typed-lint via PR #57 — with guard PASS close-out reports on every plan. Add a batch-level SIGNOFF.md to each recording verdicts, merge commits, gate history, and the residual follow-ups that survive closure, then move both folders from .agents/.plans/ to .agents/.plans-closed/ so the active-plans directory only holds executable work. Notably carried forward: the persistent-strand Firefox question remains open (stream-swap-follow fixed transients only), and the tail-deletion leak still lacks a committed regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a0bf83b commit 2e6cf94

15 files changed

Lines changed: 137 additions & 0 deletions

.agents/.plans/stream-swap-follow/001-stream-swap-follow-bottom.guard-report.md renamed to .agents/.plans-closed/stream-swap-follow/001-stream-swap-follow-bottom.guard-report.md

File renamed without changes.

.agents/.plans/stream-swap-follow/001-stream-swap-follow-bottom.guard.md renamed to .agents/.plans-closed/stream-swap-follow/001-stream-swap-follow-bottom.guard.md

File renamed without changes.

.agents/.plans/stream-swap-follow/001-stream-swap-follow-bottom.md renamed to .agents/.plans-closed/stream-swap-follow/001-stream-swap-follow-bottom.md

File renamed without changes.
File renamed without changes.

.agents/.plans/stream-swap-follow/002-overflow-anchor-follow-bottom.guard-report.md renamed to .agents/.plans-closed/stream-swap-follow/002-overflow-anchor-follow-bottom.guard-report.md

File renamed without changes.

.agents/.plans/stream-swap-follow/002-overflow-anchor-follow-bottom.guard.md renamed to .agents/.plans-closed/stream-swap-follow/002-overflow-anchor-follow-bottom.guard.md

File renamed without changes.

.agents/.plans/stream-swap-follow/002-overflow-anchor-follow-bottom.md renamed to .agents/.plans-closed/stream-swap-follow/002-overflow-anchor-follow-bottom.md

File renamed without changes.
File renamed without changes.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Batch signoff — stream-swap-follow
2+
3+
**Status: CLOSED** · Signed off 2026-07-09 · Both plans PASS, merged to `main`.
4+
5+
This batch is complete and moved to `.agents/.plans-closed/`. No plan in it
6+
remains executable; the documents are retained as the record of what was done,
7+
how it was verified, and — critically for this batch — which reported symptom
8+
is **not** closed by it (see "What this closure does not claim").
9+
10+
## Plans
11+
12+
| Plan | Title | Verdict | PR | Merged to main |
13+
| ---- | ------------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------- | ------------------------------- |
14+
| 001 | Keep follow-bottom locked when a streamed message is replaced | PASS (operator-approved, amended) | [#54](https://github.com/humanspeak/svelte-virtual-chat/pull/54) | `46ed850` (v0.1.17, 2026-07-09) |
15+
| 002 | CSS scroll anchoring as a pre-paint follow-bottom guarantee | PASS | [#55](https://github.com/humanspeak/svelte-virtual-chat/pull/55) | `23538db` (v0.1.18, 2026-07-09) |
16+
17+
## What the batch delivered
18+
19+
Consumer apps that stream an assistant reply into a placeholder and then swap
20+
in the final document (new id, sometimes remove-then-add) no longer lose
21+
follow-bottom:
22+
23+
- **001** fixed the message-identity symptoms: height carry-over, in-place
24+
identity invalidation (`messageShape`), shrink→grow smooth suppression.
25+
- **002** fixed the structural cause: no JS-timing hook (rAF, ResizeObserver,
26+
microtask) can guarantee a pre-paint `scrollTop` write, so the fix moved
27+
into layout — CSS scroll anchoring on the viewport with a bottom sentinel,
28+
content opt-out, a derived sentinel height (webkit border-top law), and a
29+
bounded tail-swap height reserve in `chatTailSwapCarry.ts`.
30+
- Verified as **fixes, not probability reductions**: guard measured the
31+
user-visible defect directly — 3/25 chromium regrow runs painted a real
32+
off-bottom frame (worst 408px) without 002's change, 0/25 with it; the
33+
previously 1-in-10-failing variants repeat-sampled 0-in-30 across webkit,
34+
mobile-safari, and mobile-chrome. Full browser matrix green at close-out.
35+
36+
## Gate history (full detail in the per-plan `.guard.md` / `.guard-report.md`)
37+
38+
This batch earned its PASS the hard way, and the record should not smooth
39+
that over:
40+
41+
- **001** initially NO-PASS at `final` (STOP line-budget exceeded, unplanned
42+
strategy). Operator reviewed and accepted; the plan was amended to authorize
43+
the work. A post-close-out `trunk check` gap surfaced 3 lint issues, fixed
44+
with operator authorization.
45+
- **The batch was reopened 2026-07-09**: 001's single-run-per-browser gate had
46+
let a ~1-in-20 chromium race through. Measured (`--repeat-each=25`), not
47+
inferred. That lesson — repeat-sample or a green run means little — is
48+
institutionalized in 002's done criteria.
49+
- **002** went through two NO-PASS checkpoints (a forbidden JS-timing hook; a
50+
scope violation that would have permanently leaked phantom height on tail
51+
deletion) before passing. Three operator-approved amendments, all
52+
strengthening; no criterion or STOP was ever weakened.
53+
54+
## What this closure does not claim
55+
56+
**The persistent-strand question stays open.** No failing run in either plan
57+
ever showed `following=false` or a settled `finalGap > 2` — everything this
58+
batch fixed was a _transient_. The originally reported real-world Firefox
59+
symptom (a viewport that stays stranded off-bottom) was never reproduced and
60+
remains unexplained. Do not close that report on the strength of this batch.
61+
The tracer for chasing it is committed at `tests/chat/regrow-trace.debug.ts`.
62+
63+
## Residual follow-ups carried forward (none block closure)
64+
65+
- **Highest value: commit a regression test for the tail-deletion leak.**
66+
Guard proved the fix with a throwaway fixture (permanent tail delete →
67+
reserve clears after 250ms) and deleted it; nothing in the repo would catch
68+
a reintroduction. The component's 250ms clear timer is untested.
69+
- **`TAIL_SWAP_RESERVE_MS = 250` is a magic number.** A store slower than
70+
250ms to deliver the replacement reopens the original race. Derive the
71+
window or document the assumption.
72+
- **Anchor selection is the load-bearing invariant.** Any new element inside
73+
the viewport without `overflow-anchor: none` can steal anchor selection and
74+
silently reintroduce the bug. Reviewers must check every new viewport child.
75+
- **webkit + `viewportClass` border-top hazard** deserves a line in the prop
76+
docs — a top border taller than the sentinel disables anchoring in Safari.
77+
- **`same-id` and `new-id` variants are still single-sampled** in the stress
78+
suite; twice on this batch a real bug hid behind a single green run.
79+
- Orphaned height-cache entry pruning (memory growth over long sessions) —
80+
deferred from 001, still real, still independent.

.agents/.plans/typed-lint/001-lint-unit-tests-and-typed-lint.guard-report.md renamed to .agents/.plans-closed/typed-lint/001-lint-unit-tests-and-typed-lint.guard-report.md

File renamed without changes.

0 commit comments

Comments
 (0)