Public: anyone can read this; the crew can change it.

Iterations is Jay's actual page, with his name on it: the landed version is a smaller rewrite #9138

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull replaces the smaller Iterations rewrite with Jay Moran's page, and it fixes the squash that dropped his credit. Tests and the type check pass. The before-and-after screenshots are not on the pull yet.

shipped production is serving it deploy b070674

opened this

This pull replaces the smaller Iterations rewrite with Jay Moran's page, and it fixes the squash that dropped his credit. Tests and the type check pass. The before-and-after screenshots are not on the pull yet.

I couldn't take them: a preview of this branch only exists after the forge's check runs, and Jay's own page isn't reachable from my sandbox. Please add them from the preview, beside his page.

What changed

  • His page: iterations.ts and build_info.ts come from incoming/jay-main, with only the wiring changed. The Columns and Tree layouts, drag, Align and Reset all stay, as do zoom with Fit, Collapse and Expand forks, folds per browser, and Notes. So does the info panel with its link, clone, fork and delete dialogs.
  • Wiring to main:

- build_lineage.ts holds his buildLineage and familyRepos. - git/builds.ts gains the helpers his code calls (wholeNotes, splitPinNote, readBuildPin, isCopiedPin, pinsMergedInto, refsContaining, isAncestor). - POST /:owner/:name/builds/:label/note is now on the router.

  • Removed: iterations_family.ts and iterations_script.ts, the 5-second pin cache, and the old design doc. The terminal Iterations screen and its test now read from his module.
  • Why the credit was lost: a landing writes only its own trailers (Requested-by and the lander's Co-authored-by). The squash built a new message and dropped the Co-authored-by lines on the commits it folded.
  • The fix: git/coauthors.ts collects those lines from the commits being folded in, once per address and capped at 20. actions/pulls.ts adds them to a squash message. test/coauthors.test.ts covers it. Jay is credited in this pull's commit.

What I left out

  • Displays and the arcade: the Showcased and display picker, Edit display selections, Build and play, Download, and screenshots are absent.
  • build_play.ts: left out, because it only serves captures.
  • Build player: a build plays as a build preview, or nothing for a repository that is no app.
  • Old graph link: graphMoved and the old branches/graph redirect are not here.
  • Default layout: the default is Columns, as on his page, with Tree at ?layout=tree. The landed rewrite defaulted to Tree.
  • Design-lint changes to his CSS: four off-scale font sizes moved to 11.5px, and the drag shadow became an accent ring.
  • Pin reads: with the cache gone, each page load reads pins from git for every repository in the family.
  • Plan on the issue: I had no keep_plan tool, so there is no plan on the issue.

How to try it

  • Open /<owner>/<name>/iterations?layout=tree on a repository that holds pins.
  • Drag a run, then use Align, Reset, Fit and the fold buttons.
  • Click a build to open its panel and player.
  • The test files are test/iterations.test.ts, test/tui-iterations.test.ts and test/coauthors.test.ts. I also ran bun scripts/gate.ts, bun scripts/design-lint.ts and the related pull, merge and build-pin tests. The forge's own check has not run yet.

Closes #9133

commented

This pull replaces the smaller Iterations rewrite with Jay Moran's page, and it fixes the squash that dropped his credit. Tests and the type check pass. The before-and-after screenshots are not on the pull yet.

I couldn't take them: a preview of this branch only exists after the forge's check runs, and Jay's own page isn't reachable from my sandbox. Please add them from the preview, beside his page.

What changed

  • His page: iterations.ts and build_info.ts come from incoming/jay-main, with only the wiring changed. The Columns and Tree layouts, drag, Align and Reset all stay, as do zoom with Fit, Collapse and Expand forks, folds per browser, and Notes. So does the info panel with its link, clone, fork and delete dialogs.
  • Wiring to main:

- build_lineage.ts holds his buildLineage and familyRepos. - git/builds.ts gains the helpers his code calls (wholeNotes, splitPinNote, readBuildPin, isCopiedPin, pinsMergedInto, refsContaining, isAncestor). - POST /:owner/:name/builds/:label/note is now on the router.

  • Removed: iterations_family.ts and iterations_script.ts, the 5-second pin cache, and the old design doc. The terminal Iterations screen and its test now read from his module.
  • Why the credit was lost: a landing writes only its own trailers (Requested-by and the lander's Co-authored-by). The squash built a new message and dropped the Co-authored-by lines on the commits it folded.
  • The fix: git/coauthors.ts collects those lines from the commits being folded in, once per address and capped at 20. actions/pulls.ts adds them to a squash message. test/coauthors.test.ts covers it. Jay is credited in this pull's commit.

What I left out

  • Displays and the arcade: the Showcased and display picker, Edit display selections, Build and play, Download, and screenshots are absent.
  • build_play.ts: left out, because it only serves captures.
  • Build player: a build plays as a build preview, or nothing for a repository that is no app.
  • Old graph link: graphMoved and the old branches/graph redirect are not here.
  • Default layout: the default is Columns, as on his page, with Tree at ?layout=tree. The landed rewrite defaulted to Tree.
  • Design-lint changes to his CSS: four off-scale font sizes moved to 11.5px, and the drag shadow became an accent ring.
  • Pin reads: with the cache gone, each page load reads pins from git for every repository in the family.
  • Plan on the issue: I had no keep_plan tool, so there is no plan on the issue.

How to try it

  • Open /<owner>/<name>/iterations?layout=tree on a repository that holds pins.
  • Drag a run, then use Align, Reset, Fit and the fold buttons.
  • Click a build to open its panel and player.
  • The test files are test/iterations.test.ts, test/tui-iterations.test.ts and test/coauthors.test.ts. I also ran bun scripts/gate.ts, bun scripts/design-lint.ts and the related pull, merge and build-pin tests. The forge's own check has not run yet.
commented

I found nothing to fix, so I changed nothing and pushed nothing.

The deploy log you pasted shows the preview came up. It reads ready, serving and done, with no error or stack trace. Starting the process took 0.7s and it answered 0.9s after that. I also checked the live preview: /healthz and / both return 200.

The only failure-sounding line is "no tests declared, none run". That is the deploy step saying forge.json has no test command for the preview. It is not an error from the app. forge.json is unchanged by this pull, and its check entries are the ones that run the gate, tsc and the tests. A preview deploy was never meant to run them.

Locally the gate, tsc, design-lint and the Iterations, TUI, co-authors, told-by, build-pin and merge tests all passed (124 tests). The branch is level with origin at a77c3eb7.

If something specific is red on #9138, such as the forge's check run, send me its log. That log would show a failure the deploy log doesn't.

commented

This pull now makes Iterations and Builds both Jay Moran's pages, and a squash keeps Co-authored-by. The new tests, the gate, the type check and design-lint pass. The before-and-after screenshots are still not on the pull. Jay's page isn't reachable from my sandbox, so please add them from the preview next to his.

Iterations

  • It is Jay's iterations.ts and build_info.ts from incoming/jay-main. I changed only the wiring: his lineage and git helpers, plus a new note route (POST /:owner/:name/builds/:label/note).
  • It has the Columns and Tree layouts. In Tree you can drag runs and use Align and Reset. Zoom has Fit, Collapse and Expand forks work, folds are kept per browser, and the info panel is there.
  • The smaller rewrite (iterations_family.ts and iterations_script.ts) is deleted. The terminal Iterations screen now reads from his module.

Builds

  • builds.ts is his lineage. Each pin is indented under its parent, and a pin from another repository gets a dotted concept edge.
  • The Pin a build form suggests a label (iter-N for an iteration branch or a fork's first pin) and offers every pin of the family as Parent. A new pin lands on Iterations with it picked.
  • I brought build_lineage.ts back into builds.ts, where he keeps it.
  • src/git/builds.ts already has everything the page needs, so I added only the helpers (wholeNotes, splitPinNote, readBuildPin, isCopiedPin, pinsMergedInto, refsContaining, isAncestor).
  • I did not copy the rest of his 847 lines (demos, covers, screenshots). Nothing on the page reads them.
  • I did not diff actions/builds.ts or core/intent_notes.ts against his, since you said they are close.

Co-authored-by

  • A landing wrote only its own trailers (Requested-by and the lander's Co-authored-by), so a squash dropped the trailers on the commits it folded.
  • git/coauthors.ts now carries those lines into a squash message, once per address and capped at 20. test/coauthors.test.ts covers it.
  • Jay is credited in this pull's commits.

What I left out

  • The Showcased and display picker, Edit display selections, Build and play, Download and screenshots wait for the displays and arcade ports. So does the demo option on the pin form.
  • build_play.ts isn't included because it only serves captures.
  • The old branches/graph redirect is gone.
  • Iterations still defaults to Columns, as on his page. Tree is ?layout=tree.
  • Four off-scale font sizes and the drag shadow in his CSS were changed to satisfy design-lint.
  • With the 5-second pin cache gone, each page load reads pins from git for every repository in the family.

Two things to know

  • The gate wants Why now: and Try: lines in a commit message, and my first commit had neither. The new commit has them, and the gate now passes. The first commit stays in the history without them.
  • Two existing test expectations changed, because Jay's behaviour differs. Pinning now redirects to Iterations instead of Builds, and the Builds page links to /iterations?layout=tree.

To try it

  • Open /<owner>/<name>/builds and /<owner>/<name>/iterations?layout=tree on a repository with pins.
  • To check the squash, merge a pull whose commit message has a Co-authored-by: line and look at the landed commit.
commented

I merged main into the branch and pushed it. The Iterations page is still Jay Moran's version, and main's new JSON API now reads from it.

The gate script and tsc ran clean. The 39 tests in iterations, tui-iterations, build-pins and coauthors pass. I did not run the full suite; the forge runs it on the push.

What the conflicts were: main had moved the old iterations_family.ts to src/core/iterations.ts and added GET /api/v1/repos/:owner/:name/iterations on top of it (#9145). This branch had deleted that file, because Jay's page carries its own iterationsOf and lanesOf in src/web/pages/iterations.ts and build_info.ts.

How I resolved it:

  • Code: I dropped src/core/iterations.ts and kept this branch's page, TUI screen and tests as they were.
  • API: src/http/api/iterations.ts now calls Jay's iterationsOf(ctx, repo) and keeps the same response shape, { forks, lanes }. A private repository you can't read is a 404, and an empty family answers 200 with empty lists.
  • API tests: I added main's two API tests to test/iterations.test.ts. They check that a reader, a stranger and a guest get the same pins from the API as from the page.
  • Docs: docs/design/areas/iterations.md and docs/features/iterations.md keep this branch's text. The features doc also gains main's "Over the API" section, without the parts that no longer apply (the 40-repository cap and the 5-second pins cache).

The API now imports from src/web/pages/, which is the wrong direction for layering. I did that rather than move Jay's data code into core/, which would be a larger change to his files. The alternative is to extract the data layer into core/ in a follow-up.

To try it, open /:owner/:name/iterations on the preview and /api/v1/repos/:owner/:name/iterations for the JSON.

🤖 Generated with Claude Code

commented

The failing check was a stale generated file. The merge left src/contract/openapi/routes/index.ts out of date, with the iterations export in the wrong place. I regenerated it with bun scripts/openapi-routes.ts, and the only change is that one export line moving into sorted order.

The 421 OpenAPI tests pass locally, and the fix is pushed. I did not rerun the full suite, so the forge's check on this push is the confirmation.

Changes requested — before the latest push

Changes needed in one round:

  1. (high, DoS) The 5-second pin cache is gone, and the page and the JSON API now do much more git work per request, with no cache. Per request: listBuildPins for every repo in the family (up to 40), pinsMergedInto for every pin, and refsContaining and listBranches for every build. A signed-out or any viewer can hit /iterations and /api/v1/repos/:o/:n/iterations in a loop and fan out hundreds of git processes. Restore a per-repo TTL cache (the old pinsOf) and bound the per-pin git calls, or compute refsContaining only for the selected build.
  2. Layering: src/http/api/iterations.ts and src/tui/screens/iterations.ts now import data code from web/pages/iterations.ts, and src/core/iterations.ts is deleted. The data (iterationsOf, lanesOf, familyRepos) belongs in core/; keep the page as the drawer only. The pull's own description admits this is the wrong direction.
  3. familyRepos/FAMILY_LIMIT are now duplicated between builds.ts and the iterations module; keep one.
  4. Clean: builds.ts has an orphaned doc comment ("The whole family's pins as one forest...") sitting above familyRepos' own comment, plus a malformed \n/ header close. git/builds.ts has no blank line before wholeNotes and a stray trailing blank line. The delete dialog text reads "from X, Its commit".
  5. Issue box 3: before/after screenshots are not on the pull. Add them.
  6. The squash now copies Co-authored-by lines from any commit's text onto the landed commit, so any pull author can credit any email. Say in the pull that this is accepted, or limit it to addresses of known users.

I could not read noteSubmit in the cut diff; confirm it checks identity, write access, same-origin and the body size cap, and that back goes through isLocalPath.

commented

I addressed items 1–4 and pushed. I did not add screenshots (item 5) or limit the squash Co-authored-by lines (item 6). tsc, scripts/gate.ts and scripts/design-lint.ts pass. The route index is current, and the iterations, builds, pins, co-authors and new cache tests pass. Three looks.test.ts chromium captures fail in this sandbox with and without my changes; I did not check them against main.

  1. Git fan-out. A new src/core/ttl_cache.ts keeps each slow read for 5 seconds, per app and key. Each repository's pins and per-pin merge sets (member:), its branch list (branches:) and each build's refsContaining (refs:) are cached. A loop of requests now costs at most one fan-out per repository every 5 seconds. A write calls forget(app), so pinBuild, deletePin and notePin show up at once. Pins written by other routes, such as git pushes, can lag up to 5 seconds. I kept refsContaining per build rather than computing it only for the picked build, because forkHas is part of every build's data. test/ttl-cache.test.ts covers the cache.
  2. Layering. src/core/iterations.ts holds the types, iterationsOf, lanesOf, buildOf and repoFactsOf. src/core/lineage.ts holds Viewing, buildLineage and familyRepos. The API, the TUI screen and the tests import from core/. web/pages/iterations.ts and build_info.ts only draw.
  3. Duplication. There is one familyRepos and one FAMILY_LIMIT, in core/lineage.ts.
  4. Clean-up.

- Removed the orphaned doc comment and the malformed header close in builds.ts, and restored buildLineage's own comment. - Added the blank line before wholeNotes and removed the trailing blank line in git/builds.ts. - The delete dialog now reads "from X. Its commit".

  1. Screenshots. Not added. This sandbox cannot run a browser against the preview, so before/after images for issue box 3 need someone with one.
  2. Squash Co-authored-by. I left it as it is. The squash exists to keep credit for people who are not forge users, such as Jay's [email protected], so limiting it to known users would defeat that. The lander is a person who merges after seeing the commit messages, and the existing parser already rejects malformed lines and caps the count at 20. If you want it limited, say so.

noteSubmit. It does all of these checks:

  • It refuses a signed-out user.
  • readForm(ctx, "rw") enforces the same-origin check and the body size cap.
  • notePin requires a person with write access and refuses mirrors and agents. A caller without access gets a 404.
  • backTo goes through isLocalPath.
  • NOTES_MAX is enforced in git (notePinBuild), which returns invalid_note.

I did not re-read readForm's body to confirm the same-origin and size-cap checks beyond its "rw" call site.

commented

Merged main into the branch and pushed. The type check is clean. I ran the iterations, MCP and terminal-view tests (195 pass, 0 fail) and did not run the whole suite. scripts/fast.ts estimated 131 minutes for the full set it named, so I ran only those four files. The forge's check runs the rest on this push.

  • Conflict: the only conflict was docs/features/iterations.md, in "Over the API". I kept main's wording, which adds the 40-repository cap and the 5-second pins cache. I also kept main's new "Over MCP" section.
  • Type fix: the merge left src/http/mcp/tools/iterations.ts on the old iterationsOf(app, user, repo) signature. It now passes { app: ctx.app, auth: { user } }, as the route does, and reads .forks from the result. That is a second commit, separate from the merge commit.
  • Left out: nothing new; the pull's scope is unchanged.
Approved

Round check: the change since my last review is a merge of main plus the MCP iterations tool moved to the new iterationsOf({app, auth:{user}}) signature and reading .forks. That matches the API route and TUI screen and introduces no new security surface. Earlier asks: layering (core/iterations.ts, core/lineage.ts), the single familyRepos, the TTL cache with forget() on writes, and clean-up are met. Non-blocking: before/after screenshots (box 3) are still not on the pull; add them from the preview. Non-blocking: squash Co-authored-by lines are copied from any commit message, strictly parsed and capped at 20; acceptable since a person lands it. I could not diff against a4e6cdf23e49 as the clone lacks it, so I read the change as given.

commented

Left #9133 open: 1 unticked item remain (Before and after screenshots beside his page, on the pull.).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs