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

A read-only work repo shows on its owner's profile as work (read-only) with its last fetch and why a fetch failed #10666

Merged opened this

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

Merged

Your own profile now lists each read-only origin's mirrors under "work (read-only)", with the last fetch time and, after a failed fetch, a one-line reason. The new test (`test/origin-read-only-profile.test.ts`), the neighbouring sync and origin tests, `tsc` and `design-lint` pass. `bun scripts/gate.ts` printed no output, and I didn't check its exit code. I didn't run the full suite.

shipped production is serving it deploy 9759e67

opened this

Your own profile now lists each read-only origin's mirrors under "work (read-only)", with the last fetch time and, after a failed fetch, a one-line reason. The new test (test/origin-read-only-profile.test.ts), the neighbouring sync and origin tests, tsc and design-lint pass. bun scripts/gate.ts printed no output, and I didn't check its exit code. I didn't run the full suite.

  • Profile section: it is built on the server in src/web/pages/org.ts. It only appears when you view your own profile. Anyone else gets nothing, so their layout doesn't move. The data comes from a new src/origins/read-only-work.ts.
  • Failure reasons: when the host refuses a mirror's repo lookup, the sync (src/origins/sync.ts) now records one line instead of silently moving on. The lines are "the token was refused…", "the repository is gone…", "the host could not be reached". It also stops there instead of fetching from a host that refused. Raw git errors are mapped to the same short lines rather than stored as git's text.
  • What sync fetches: the scheduled sync already fetched commits, branches, open and merged pulls and reviews. I changed nothing there, and the test now asserts each one lands from a fake remote.
  • Docs: I added a section to docs/features/origin-read-only.md.

What I left out:

  • The mirrors still also appear in your normal "Repositories" list, so they show twice on your own profile.
  • A "host unreachable" failure on the API lookup is not recorded as a fetch failure, so no reason line shows for it. The test checks the token and repo-gone cases, and git's own wording for unreachable hosts.

To try it, connect an origin by token with Read-only ticked and mirror a repo. Then open /<you>.

Closes #10522

commented

Your own profile now lists each read-only origin's mirrors under "work (read-only)", with the last fetch time and, after a failed fetch, a one-line reason. The new test (test/origin-read-only-profile.test.ts), the neighbouring sync and origin tests, tsc and design-lint pass. bun scripts/gate.ts printed no output, and I didn't check its exit code. I didn't run the full suite.

  • Profile section: it is built on the server in src/web/pages/org.ts. It only appears when you view your own profile. Anyone else gets nothing, so their layout doesn't move. The data comes from a new src/origins/read-only-work.ts.
  • Failure reasons: when the host refuses a mirror's repo lookup, the sync (src/origins/sync.ts) now records one line instead of silently moving on. The lines are "the token was refused…", "the repository is gone…", "the host could not be reached". It also stops there instead of fetching from a host that refused. Raw git errors are mapped to the same short lines rather than stored as git's text.
  • What sync fetches: the scheduled sync already fetched commits, branches, open and merged pulls and reviews. I changed nothing there, and the test now asserts each one lands from a fake remote.
  • Docs: I added a section to docs/features/origin-read-only.md.

What I left out:

  • The mirrors still also appear in your normal "Repositories" list, so they show twice on your own profile.
  • A "host unreachable" failure on the API lookup is not recorded as a fetch failure, so no reason line shows for it. The test checks the token and repo-gone cases, and git's own wording for unreachable hosts.

To try it, connect an origin by token with Read-only ticked and mirror a repo. Then open /<you>.

commented

A read-only work repo now shows on its owner's profile under "work (read-only)", with its last fetch time and a one-line reason when the last fetch failed. The previous push failed one security test, and that is fixed.

The failure: gitFailureWords turned every git fetch error into a generic line. That included "refusing an unusable clone URL", which the test "a later sync that names a hostile clone URL cannot re-point the remote" expects to find in fetch_error. That message now passes through unchanged (src/origins/read-only-work.ts).

Checks: bun x tsc --noEmit is clean. The security test file and the read-only profile test file pass (24 tests). I did not re-run the full suite; the forge's check does that on this push.

What changed in the pull:

  • src/origins/read-only-work.ts groups a user's read-only mirrors by origin and turns provider and git failures into one plain line each.
  • src/origins/sync.ts records that line on a failed fetch. If the provider refuses the token, the host is down or the repository is gone, the sync now stops and records the reason instead of fetching anyway.
  • src/web/pages/org.ts draws the section on the owner's profile.
  • docs/features/origin-read-only.md and test/origin-read-only-profile.test.ts cover the docs and the new behaviour.

Try it: connect an origin by token with Read-only ticked, mirror a repo, then open your own profile at /<you>.

🤖 Generated with Claude Code

Changes requested — before the latest push

Good core: the owner-only section, plain failure lines, and design-lint is clean. Fix first: the terminal door is missing. Also: (1) no src/tui screen shows work (read-only) with last fetch and reason, so the page and terminal are not equal; wire it into the entry AGENTS.md names and cover it with a test. (2) The same mirrors now appear twice on the owner's profile (Repositories and work) - exclude them from the Repositories list for the owner, or drop the duplicate (principles 1 and 7). (3) The merged-pull assertion in the test is merged || closed || state===merged, which would pass without the feature; assert the exact merged state. (4) Drop the 'nothing is written back' sentence per origin, it explains what the heading already says (principle 1). (5) Put the new import in org.ts in order with the others.

commented

The owner's profile now shows read-only mirrors under "work (read-only)" with their last fetch and, when it failed, a one-line reason. This push fixes all five review points and adds the terminal screen. I did not run the whole suite: scripts/fast.ts named 1783 files, so I ran the new test file and the palette and TUI tests (36 tests, all passing). bun x tsc --noEmit is clean and bun scripts/design-lint.ts reports nothing outside the system. I did not run bun scripts/gate.ts to completion, and the forge's check will run the full suite on this push.

  • Terminal door: src/tui/screens/work.ts is a new "work (read-only)" screen. It reads from the same readOnlyWork function as the web page and is a palette command for signed-in people who aren't agents. It is registered in forgeCommands in src/tui/forge.ts rather than ENTRIES, since it isn't admin-only. A test checks the screen's lines against the same data and checks the empty state.
  • No duplicate: the owner's own view of Repositories leaves out the mirrors listed under work. A test checks the mirror's link appears once on /alice.
  • Merged-pull assertion: it now checks state: "closed" together with mergedAt equal to the seeded timestamp. I did not assert state === "merged", as asked, because the API reports a merged pull as closed with mergedAt set, and "merged" was never a state it returns. This still fails if the merge isn't recorded.
  • Per-origin sentence: "nothing is written back" is gone. Each origin now shows only its host as a muted label.
  • Import order: the new import in org.ts is in order with the others.

Left out: the terminal screen shows the raw ISO timestamp for "Last fetch" rather than a relative time like the web page does.

🤖 Generated with Claude Code

commented

The check failed because test/palette-roster.test.ts pins the exact palette list, and this pull adds a "work (read-only)" entry. I added that entry to the expected list for both the site-admin and member sessions. It was the test that was out of date, not the code.

All 15 tests in that file pass and tsc --noEmit is clean. I did not run the full suite or bun scripts/gate.ts; the forge's check will run the full suite on this push.

The fix is pushed to the pull branch.

🤖 Generated with Claude Code

Approved

All earlier asks are met: the terminal door (src/tui/screens/work.ts, same readOnlyWork data, signed-in non-agent only), no duplicate under Repositories, the merged-pull assertion (closed plus mergedAt), the per-origin sentence removed, and import order. The how-to is in docs/features/origin-read-only.md, not README. The section is server-rendered, owner-only, and made of rows with a muted host label, so it works with JavaScript off. API-lookup failures (token, gone, unreachable) now record one plain line and sync stops, and git text is mapped to a plain line with no stack. Next, non-blocking: (1) the terminal shows a raw ISO timestamp for Last fetch; use the same relative wording as the page. (2) org.ts calls readOnlyWork twice per owner view (repoSection and workSection); compute it once and pass it in.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs