p4-web is developed in Perforce — every entry below is a
real submitted changelist, newest first. The source is mirrored to
GitHub.
2026-08-02
day 12
Where the work is going
69156A Stats page: submits by day, week, month or year, by depot path with drill-down, and by account (all three charts read one filter set, so narrowing the time range or stepping into a directory narrows the others too, and clicking any bar opens the changelists behind it. The path chart starts one level below wherever you are rather than at a fixed depth, and says how many submits touched nothing that deep — without that line the totals quietly shrink the further in you go. Charts are plain SVG: the only shapes needed are a bar and an axis, and a chart library would have meant unpinning the content-security and supply-chain rules for it)
69155The aggregates behind it, served from the local changelist index (so a year of history is a millisecond query rather than a walk through every changelist on the server, and because the index is built with your own Perforce ticket the numbers only ever count what you may see. Buckets are cut in your timezone — folded raw, a morning submit in Seoul lands on the previous day — and weeks start Monday, keyed by the date rather than an ISO week number that older SQLite builds can’t format)
69151Per-change directory rollup in the index, so path stats are instant (folding nine million file rows on every query measured 28 seconds; expanding each change’s directories once, up front, is 7% more rows and turns the same question into single-digit milliseconds. An index built before this fills in on a background pass while the page stays usable — the time and account charts are already exact, and the page says so)
2026-07-26
day 11
The list keeps going, and pictures open as pictures
67389Clicking an image in a changelist opens it in the file viewer instead of starting a download (a .jpg is binary+F to Perforce, so it went to the download endpoint along with everything else binary — on a phone that meant dismissing a save-or-open sheet before you could see the picture. The viewer already previewed images inline; its Raw and Download links are still there when you want the original, and other binaries download as before)
67388The Changes list keeps loading as you scroll instead of stopping at a Load more button (the next page starts arriving about a screen before you reach the bottom, and the fast index can page now too, so a filtered search continues past its first 200 rows as well. A button still appears for the two cases that shouldn’t drive themselves: a page that failed, and a filter so sparse that whole pages come back empty)
2026-07-25
day 10
Turn features on and off
66854A Settings page behind the gear in the top bar — switch reviews, comments, mentions, write operations, favorites and fast changelist search off for yourself, and set theme, diff layout and markdown view in the same place (the feature switches are stored per account and follow you to any browser; appearance stays per device, because dark on the phone and light on the desktop is reasonable while comments hidden here but not there is only confusing)
66852The app hides what is switched off rather than offering buttons that can only fail — menu entries, comment panels and diff comment buttons, review bars, the mention badge, the favorites star and the Edit/Delete links all follow the switches (a link or bookmark into a switched-off feature still opens, and says whether the server or your own settings turned it off; a tab left open from before a change asks you to reload rather than failing silently)
66849Whoever runs the server can turn any of the six features off for everyone, from a features.json or P4WEB_FEATURE_* environment variables (a switched-off feature also stops answering on its endpoints, so this is a real boundary rather than a hidden button; nothing is deleted either — reviews and comments written while a feature was on come straight back when it returns. Deployments differ: some want a read-only browser, some already have their reviews elsewhere)
2026-07-24
day 9
Large files download again
66839A file over 100 MB downloads again — the Download link no longer refuses it with File too large(the size cap was only ever meant for the inline preview, which would pull the whole file into the page; a download streams straight from Perforce to your disk without ever buffering on the server, so its size no longer matters — the inline preview keeps the 100 MB limit)
2026-07-22
day 7
Reviews, mentions, and comments where the code is
66478The guided tour catches up to the app — a step for commenting inside a diff, and a step for reviews and @mentions(two new steps with screenshots staged from the fictional depot; the landing page's architecture note was refreshed to match)
66477A diff's ---/+++ header pair reads as a header again, instead of a red-and-green pair of edits numbered line 0
66476On a phone, the background now covers the whole screen when you overscroll, and a diff scrolled sideways keeps its green and red across the full line (the page background moved to the document root, and unified diff rows are as wide as the widest line rather than as wide as the window)
66472A diff expanded inside a changelist no longer stretches the file list past the screen on a phone (the cell takes the table's width and the code scrolls inside the diff, where it was always meant to; the comment panel stays put while you scroll)
66471Say @name in a comment and that person gets a badge in the top bar linking to everything they were named in (names are checked against real Perforce users, with autocomplete while you type; the Changes list and the depot browser also show how many comment threads a change or file has, and how many are still open)
66470Comment on a line from inside a diff — every diff line now carries its own anchor, and unified diffs finally show line numbers (a thread opened in a changelist's diff also reads on the file's page, and vice versa; lines that already have threads show the count)
66468Light reviews: mark a changelist in review, approved, or needs work, with a history of who moved it and why (a new Reviews page under More lists them; nothing about the changelist itself changes — the state lives beside the comments)
66465The guide gains a folder-diff step — comparing a whole directory against another path, or against its own state at an older changelist or date (screenshot staged from the fictional depot, like every other image in the guide)
66463This site fits a phone again — the deploy cards no longer stretch the page sideways (a card was sized by the long launchctl line inside it; the command scrolls within its own box instead, and the section markers now name the newest changelist in each area)
66462On a phone, diffs stay unified — “Side by side” is offered again as soon as the window is wide enough (two code columns get about 130 px each on a 393 px screen, which wraps every other line; your choice is remembered rather than overwritten, so rotating a tablet or widening a window brings the two panes straight back)
66458A diff opened inside a changelist no longer inherits the file listing’s row styling — the last case where the two panes ran their text together (the listing rules now match only their own rows, so a table nested in a changelist row is left alone)
66451Side-by-side diffs line up on a phone — the two panes now get equal width instead of one side collapsing and pushing blank space between the lines of the other (the table is laid out from an explicit column set, so long file headers no longer stretch it past the screen; leading is tighter and the line-number gutters give their width to the code on narrow screens)
66448A markdown file that starts with a YAML front-matter block now shows it as a tidy metadata table instead of a run-together paragraph (the block used to render as a rule plus prose, with keys like first_seen_build losing their underscores to italics; it is now a collapsible table, and a file opening with a genuine horizontal rule is left alone)
66380Navigating away from a page of image previews no longer strands file readers on the Perforce server — a cancelled download now closes its p4 print instead of leaving it connected (the streamed reader is reaped on client disconnect, not only on normal completion; stray readers had been piling up as IDLE connections that held a server slot until the app was restarted)
2026-07-20
day 5
Long pages keep their pictures
66121A markdown file with a hundred screenshots now loads every one of them — the later images used to fail silently (the server was running out of file descriptors: HTTP/2 lets the browser open all those image requests at once, and each one spawns two p4 processes. It now raises its own limit, starts streams a few at a time, and the page retries an image that still fails.)
2026-07-19
day 4
Staying logged in
65727Guide gains three steps — reading a changelist (inline diffs + comment threads), depot search, and the More menu (screenshots staged from a fictional depot by the new tools/mock_shots.py)
65723Site accuracy pass: the launchd command, ssl fingerprint trust, P4WEB_P4PORT in the quickstart, favorites and changelist description edit/delete in the feature lists
65718The Changes page paints before it queries — filters are usable immediately and the listing fills in underneath (the index status no longer counts 9.5 M file rows on every load: cold open 4.3 s → 0.04 s)
65715Your session now lasts exactly as long as your Perforce ticket — no more fixed 12-hour logout (the ticket is re-checked every 15 minutes, so it follows a renewal and drops you the moment the ticket is revoked elsewhere)
2026-07-17
day 2
Search index, hardening, and this site
65340Cache-bust the app’s CSS/JS so a deploy reaches already-open browsers (no-store HTML shell, ?v= tags on app.js/style.css)
65339“Index older” backfills continuously — one click keeps extending the index backward until you press Stop or leave the Changes page
65225Changes view picks its engine automatically — the user-facing “Fast” toggle is gone (index for description/filename/date browsing, live p4 for pending and path prefixes)
65221Date filters accept YYYY-MM-DD as plain text inputs (native date pickers rendered browser-locale formats)
65220Per-user changelist search index — instant description and filename search that respects protections