Public: anyone can read this; the crew can change it.
A studio page spawns one git process per row to decide the word "shipped" #319
Check · Review · Land · Live done — Landed and live in production.
Studio pages now ask git about production once per repository per page, not once per merged row. Before, `caughtUp` ran `git merge-base` for every merged change it worded; now it reads one `git rev-list <production commit>` and every row checks against that list.
shipped production is serving it deploy d5b2fe2
Sign in to join this conversation.
new above
offline
Studio pages now ask git about production once per repository per page, not once per merged row. Before,
caughtUprangit merge-basefor every merged change it worded; now it reads onegit rev-list <production commit>and every row checks against that list.What moved where
src/git/merge.tshas a newancestorsOf(dir, oid): the full ancestry of one commit in a single spawn, with the same safe-oid guard asmergeBase.src/web/studio/words.ts:WordCtxgains a requiredhistoryfield, created byservingHistory(). It stores the pending lookup, keyed by git directory and production commit.caughtUpnow takes theWordCtxand checks set membership. So shipped still means production is at or past the merge's commit (ancestry, not equality), and the equality shortcut stays. Because the pending lookup is stored before it finishes, rows worded at the same time throughPromise.allshare one spawn.WordCtx:app.ts,change.ts,lists.ts(×3),run.tsandtell.ts. It is dropped when the render ends, so a deploy that lands shows on the next page. The home makes one memo and passes it intoshelfRowsthrough a new optionalShelfReads.history, so the shelf and the home's list of open pulls share it. Keying by directory keeps separate repositories separate.docs/STUDIO.mdnow says how the ancestry check is bounded.Tests
test/studio.test.ts("words come from facts") merges five pulls and words all five with production at the second merge. It expectsshipped, shipped, waiting, waiting, waitingand exactly one git spawn, counted withspyOn(Bun, "spawn"). It then moves production to the last merge on a fresh page and again expects one spawn. With the old per-rowmergeBaseput back, it fails with 4 spawns instead of 1.history: servingHistory(), because the field is required:test/apps.test.ts:1932and the word fixture intest/studio.test.ts. No assertion changed, andtest/studio-words.test.tswas not touched.bun x tsc --noEmitis clean, and theforge.jsoncheck list passes: 462 tests across 23 files.Chose not to
--first-parentor--max-countlimit onrev-list: either could misjudge a commit that reachedmainas a second parent, or an old merge. The cost is that the output grows with the repository's history (about 41 bytes per commit), from one process per page.To try it: open
/changesor the home on an app with several merged pulls. The words match what they said before, and each repository costs one git process per page load.🤖 Generated with Claude Code
Closes #285