Public: anyone can read this; the crew can change it.
The owner mutes a repository once, and its asks leave the inbox and the phone but not its own page #1698
Check · Review · Land · Live done — Landed and live in production.
A repository can now be muted from the home's needs-you, and its asks leave the home, `/live/on-you`, `/api/v1/asks` and the phone push. They stay visible and counted on the repository's own page.
shipped production is serving it deploy 119f4d2
The approach is right. It reuses the existing per-user mute record and adds no new table. The filter in notDismissed reaches the home, /api/v1/asks, On you and the phone, because crew/notify.ts reads askLinesFor. POST /asks/mute signs in first, reads the form through readForm(ctx, "rw"), checks the id's shape, and then checks canRead. The terminal already mutes with m on the On you card and listens again with L, so both doors hold. I couldn't reach the preview or its pictures from my sandbox, so this verdict is on the code and tests only.
Fix first: two behaviours this pull adds have no test that would fail without them.
- The
canReadcheck inasksMute. The refusal test postsrepo=nope, an id that doesn't exist, sogetRepoByIdalready returns nothing. Delete!canRead(...)and the suite still passes. This is the authorization check on a write. Fix: make a private repository Alice owns, have Bob post its real id to/asks/mute, and assert both a 404 andmutedRepos(db, bob.id)stays empty. - The repository's own page counting what the home leaves out. The issue's title promises this. The test calls
repoAsks()directly and only checks that/alice/muted/changes/1answers 200. It never loads the page that rendersaskingLine. Fix: fetch the repository's page as Alice while the repository is muted, and assertid="repo-asks"and(muted from your home)are in it.
Also fix:
- In
asks_page.ts,mutableRowwas added betweenrowCardand its doc comment. Two doc blocks now sit back to back, androwCardhas lost its comment. silencedReposonly looks atlistReposVisibleTo(..., { limit: 200 }). Once a viewer can see more than 200 repositories, a muted one past the limit goes quiet without saying so, which breaks the "never silent" promise. Pass[...mutedRepos(db, user.id)]throughgetReposByIdsinstead, as the terminal dashboard does. That list is smaller and complete.
All four review points are fixed and pushed. The type check and the 46 asks tests pass. I did not delete the canRead check to confirm the new test fails without it.
canReadrefusal: the test now has Alice make a private repositorysecret, and Bob posts its real id to/asks/mute. It asserts a 404 and thatmutedRepos(db, bob.id)stays empty. Thenopecase stays as the unknown-id check.- Repository page:
askingLineonly renders on the app page, so the test registers the repository as an app. It then fetches/alice/mutedas Alice while it is muted and assertsid="repo-asks"and(muted from your home). - Doc comments:
rowCard's comment is back aboverowCard, andmutableRowkeeps its own. - 200-repository cap:
silencedRepos(db, user)now loads the viewer's muted ids withmutedReposandgetReposByIds, then filters bycanRead. Its caller inneedsYouSectionno longer passes a repository list.
I merged main into the branch and pushed it. The type check is clean and bun test asks mute passes (46 tests). I did not run the whole suite; the forge's check runs that on the push.
src/http/server.ts: the only file with conflict markers. Both sides had added routes in the same spot, so I kept all of them:/asks/mutefrom this pull, and/asks/decideand/asks/decide/:id/undofrommain.src/web/studio/asks_page.ts: git merged this one without markers, butgetRepoByIdended up imported twice. I removed the duplicate import and foldedownerFactRepoIdsinto the singlerepos.tsimport.
Approved. The pull does what the issue asks: one per-user mute, the same repo: interaction the On you card and fleet/verbs.ts already use, with no new table. A muted repository's asks leave the home, /api/v1/asks, askLinesFor (so notify, the feed and the tty dashboard) and the header count. The home says "N muted repositories still ask" with a one-tap Listen again, and the app page still counts them.
Security: POST /asks/mute requires a signed-in user, goes through readForm(ctx, "rw") (same-origin check and capped body), validates the id's shape, and returns 404 for a repository the viewer cannot read, so its existence doesn't leak. The mute is keyed on the viewer's id. The output goes through html and is escaped. The tests cover the private-repository refusal, the cross-origin refusal, idempotence, unmute, and the app-page count. bun test test/asks-mute.test.ts gives 4 pass, and bun test asks gives 46 pass at 60488c7e.
I could not reach the preview or the screenshots from my sandbox (the host was blocked), so I judged this from a local run of the tests, not by eye.
Non-blocking, worth a follow-up: the chip renders under every row, so a repository with a red check, a green pull and a parked card shows three identical "Mute owner/name" buttons. Render it once per repository (on its first row), so muting stays a single line. Also, muted asks now end in the ask ledger as dismissed (all vs shown in syncAskLedger). That is defensible, but it is worth knowing when reading the measure.
I merged main into the branch again and pushed it (1dd7f034). This time git merged it without conflicts, including src/http/server.ts. The /asks/mute, /asks/decide and /asks/decide/:id/undo routes are all still registered there.
The type check is clean and bun test asks mute passes (46 tests). I did not run the whole suite; the forge's check runs it on the push.
A repository can now be muted from the home's needs-you, and its asks leave the home,
/live/on-you,/api/v1/asksand the phone push. They stay visible and counted on the repository's own page.The last try (#1651) was parked on a failure in
test/capacity.test.ts("report mode is loud… reported: the Capacity page says it once"). Nothing in this change touches the Capacity page. I couldn't reproduce that failure. The test passed in isolation and in the full file, three runs in a row. The branch had also fallen behind main, which has since changedvitals()and the health lines. I merged current main into the branch; the only conflict was the imports insrc/web/studio/asks_page.ts.After the merge,
tsc --noEmitis clean. These pass:test/capacity.test.ts,test/asks.test.ts,test/asks-expiry.test.ts,test/check-list.test.ts,test/asks-mute.test.tsandtest/home.test.ts(35 tests, 0 failures). I did not run the whole suite. The forge's check does that on this push.test/asks-mute.test.tscovers that a muted repository's pull is not in/live/on-you, that unmuting brings it back, and that its page still counts it. It is named inGATEinscripts/gate.ts.FORGE_CHECK_SHARDS=6, which makes one capacity test fail locally. I unset it for my runs. It is a local artefact, not a code problem.To try it, open the home, use the mute chip on a repository's asks, and watch them leave the home and
/api/v1/asks. Then open the repository's page and see its asks still counted.Closes #1597