Skip to content
quarry Artifact [bbad8c47a4]
Login

Artifact [bbad8c47a4]

Artifact bbad8c47a4f51dce832e827239f052ca1196e9b8333347ae7516c0a332b62dbe:

Wiki page [Audit after change] by dmestas on 2026-08-21 19:53:05.
D 2026-08-21T19:53:05.688
L Audit\safter\schange
N text/x-markdown
U dmestas
W 8009
# Audit after change

Features that are rarely reached in ordinary use, so a regression goes unnoticed until someone lands on the one page that exercises them. After any change touching the areas named, walk the relevant checklist by hand — the automated coverage is listed where it exists, and its gaps are the point of this page.

Add an entry when you build something that (a) only shows up on unusual data, (b) has a no-script or progressive-enhancement path, or (c) depends on a browser behaviour a unit test cannot see.

---

## 1. Large-diff windowing (check-in page, `/diff`, `/diff.frag`)

**Why rare:** only a check-in with more than ~3,000 diff lines triggers it. Most check-ins render in one window and the whole mechanism is invisible.

**Canonical case:** fossil `62b38332f7e0d122dd5d6b19b6a89033ea7612a3d38876972015db876cb34b44` — a 600-file, 216K-line merge.
- Check-in page: `/r/fossil/checkin/62b38332…`
- Single file, 54K lines: `/r/fossil/checkin/62b38332…/diff?file=extsrc%2Fsqlite3.c`

**Touch points:** `internal/diff.Window` / `LastWindow`, `checkin.diff` op (`offset`, `maxLines`, `file`, `nextOffset`, `lastOffset`, `totalLines`), `diffWindow()` and the `diff-body` / `diff-more` / `diff-pager` templates in `internal/web/web.go`, the `#diff-more` sentinel, `diffBudget`.

**Checklist**
- [ ] With JS: first window renders; scrolling the `⋯` sentinel into view appends the next window in place (row count grows, a `(continued)` section appears when a window opens mid-file); repeat to the end; no pager visible; no "continue" link visible.
- [ ] Without JS (DevTools → "Disable JavaScript", reload): no "the rest loads as you scroll" note; pager shown at top and bottom of page 1; `Next ›` goes to `?after=N&prev=M`; `‹ Previous` returns; `« Start` and `Last »` land on the first and final windows.
- [ ] Line readout `Lines a–b of T`: `T` is identical on every page of the chain, and on the `Last »` page `b == T`.
- [ ] A hand-typed mid-hunk `?after=` snaps back to a hunk boundary (readout still sums to `T`).
- [ ] `?file=` with a slash in the path renders that file, not the file list (watch for double-encoding, `%252F`).
- [ ] `?view=split` survives Next/Previous/fragment URLs.
- [ ] Response time: warm page < 300 ms; cold first hit is bounded by `zit diff` itself (zit#110 tracks path-filtered diffs).

**Automated:** `internal/diff/window_test.go` (contiguous chain, snapping, `LastWindow` agreement). **Not automated:** the intersect fetch, the `<noscript>` swap, the attribute name `data-on-intersect` (the `data-on:intersect` spelling silently does nothing in Datastar RC.7).

---

## 2. Changed-file list on very large check-ins

**Why rare:** same data as §1; lists under ~30 files look fine as a flat list, so a broken grouping only shows at scale.

**Planned shape:** directory tree with `<details>` groups collapsed past a threshold, A/M/D summary strip with status filters, multi-column rows inside open groups. When built, add its checklist here: groups collapsed/open by threshold, single-child directory compression, anchors still reach the diff sections (including not-yet-loaded windows), `<details>` works with scripting off.

---

## 3. Fleet fragment parity (`/fleet.frag`, `/fleet.rev`)

**Why rare:** the live fragment replaces the server-rendered listing moments after load; a field the fragment omits flashes and vanishes, which is easy to miss and looks like flicker.

**Checklist**
- [ ] Signed-in admin: "New repository" link, "N of M repositories" count, filter and sort all persist after the first live refresh.
- [ ] Anonymous: no admin-only controls appear at any point.
- [ ] Filter typed with JS on updates the list without a page load; with JS off, Enter submits a GET that lands on the explore view.

**Automated:** `TestFleetFragmentCarriesEverythingThePageDoes`.

---

## 4. Explore vs. personal dashboard routing

**Why rare:** `/` is the explore listing for anonymous readers and the personal dashboard for signed-in ones, so links that say `/` behave differently depending on who clicks them.

**Checklist**
- [ ] Signed in: explore tabs (repositories ↔ people) and the filter's `×` clear link stay on `?view=explore`, never drop to the dashboard.
- [ ] Anonymous: the same links land on the explore listing.

---

## 5. Repository posture: mirrors, detached stores, refused writes

**Why rare:** the mirror/native distinction only shows on a forge that mirrors other projects, and the failure and detach states need an upstream to go away or an operator to act. Most pages are native repos where none of this renders.

**Canonical case:** any mirrored repo (`/r/fossil`, `/r/wapp`); a failing one is made by pointing a test mirror at `https://dead.invalid/home` and pulling once. Branch `mirror-posture`.

**Touch points:** `oltp.SetMirror/DetachMirror/SetMirrorWrites`, `api.posture/mirrorState/Writable/refuseUnlessWritable`, `ops.ErrForbidden`, `xfer.SetWriteGate`, the `posture` type and `repobar` template in `internal/web/web.go`, `/fleet` mirror table and `#mirror-form`, `/new` kind radios.

**Checklist**
- [ ] Repo header on a mirror: `⟲ mirror of <host>` chip linking to the upstream; `· accepts writes` only when allowed. Detached store: `forked from <host>`. Native store: no chip.
- [ ] `failing` state: a one-line notice under the bar ("upstream X unreachable (N attempts); showing content as of …"); `lagging` stays silent; `current` shows nothing.
- [ ] Read-only mirror: "new ticket", "new thread", "edit" (wiki), "reply" become "… on <host> →" links to the upstream's `tktnew` / `forumnew` / `wikiedit?name=` / `forum`. After "allow writes" they revert to local links.
- [ ] API/xfer: `POST /api/v1/r/<mirror>/ticket` returns 403 `forbidden: <repo> mirrors <url> …`; a `zit push` to a mirror gets the xfer error reply, whoever signed it.
- [ ] Explore: `⟲` glyph after mirrored names; `kind=mirror|native` select filters and the count reads "n of served".
- [ ] `/fleet`: State column shows current/lagging/failing/detached from one derivation; Writes column; pull / edit / allow·refuse writes / detach per row; a detached row shows "detached from <url>" and a re-attach link; `?edit=<repo>` prefills the form and the button reads "Save mirror".
- [ ] Posture changes: changing the URL clears failures; same URL keeps them; detach keeps the URL as `detachedFrom`; re-attach clears it and returns writes to refused.
- [ ] `/new`: Start empty / Import and own (clone, `noMirror`) / Mirror (clone + interval) produce the expected posture on `repo.get`.
- [ ] Write *pages* on a read-only mirror (`/ticket/new`, `/ticket/<id>/edit`, `/wiki-new`, `/wiki/<name>/edit`, `/forum-new`, `/technote-new`, `/technote/<ev>/edit`) answer 403; "edit ticket", the wiki "Create" box and technote "edit" become "… on <host> →" links.
- [ ] Detach goes through `/fleet?detach=<repo>`: the POST without `ack=fork` redirects back to the confirmation; with it the row reads `fork <host> · detached`. Re-attach is one click on `/fleet?reattach=<repo>` and returns writes to refused.
- [ ] Header chip at phone width (≤48rem) is the icon alone with the title intact; the page does not scroll sideways.
- [ ] `/fleet` on a phone: one row per store, problems first with the healthy rows folded, summary strip, no horizontal scroll (document width == viewport). The row's `⋯` is a native popover: closes on outside click and Esc; its items match the account menu's size.

**Automated:** `internal/oltp/mirror_test.go`, `internal/api/mirror_posture_test.go`. **Not automated:** the header/notice rendering, the link swaps, the fleet actions.

---

## Conventions

- Keep the canonical repro URL for every entry; a feature that is hard to reach needs a shortcut to reach it.
- Prefer adding an automated test and then noting it here; leave the manual checks for what tests cannot see (scroll, no-script, timing).
- When a change makes an entry obsolete, delete it rather than leaving stale steps.
Z 20fd4350a99bd4286502a27cb7045feb