~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

knotless-serve: The delegation funnel follows the owner the gateway writes for

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:gateway-served-funnel

What changes

New event, gateway.served. Told by the repository's owner (remote.did()) whenever the gateway pushes for them and at least one ref moves, or lands a commit for them. A push whose every ref was refused serves no one. gateway.push and gateway.commit still record the caller, so their account counts keep meaning who wrote.

The funnel follows gateway.delegated -> gateway.served instead of -> gateway.push. Docs, the getUsage lexicon's known values and the tests follow.

Why

gateway.delegated is told by the owner who approved delegation, gateway.push by whoever pushed through the gateway: a collaborator or a runner. The funnel joins the two on one DID, so it only counted an owner who later pushed through their own gateway, which owners rarely do since they can write past it. Prod showed 1 of 3 reached, which said nothing about whether delegation led to use.

Recording the owner on the existing push event was the other option, but it would lose who actually pushed.

How it was checked

usage.rs's cohort test and tests/usage.rs tell gateway.served and assert the new funnel. The gateway tests now count usage, and protected_branches_hold_collaborators checks through the handler that a collaborator's refused push tells no gateway.served for the owner, and that the next push, which lands, does. Left to CI.

Shortcomings

No backfill: until this deploys and a delegated owner's gateway writes again, the funnel reads 0 reached for the days already counted. Runner pushes (merge queue landings) count as served too, which seems right since they need delegation, but it means an owner whose only gateway use is the queue still reaches.

Review

A quick look; the guarded events in gateway.rs are the change.

Changeset: none

🤖 Generated with Claude Code

Asked for changes

This adds a gateway.served event, told by the repository owner, and moves the delegated funnel from gateway.push to gateway.served. Docs, the lexicon's known values and the tests follow. The idea is sound, and the commit path correctly fires only on ok.

The push path has a problem. gateway.served is emitted whenever push returns, including when every ref was refused or failed. report.extend(refused) shows that a push can return Ok with only per-ref errors. The funnel is meant to show the gateway writing for the owner, so a delegated owner whose only pushes were all refused would count as reached. Emit it only when at least one ref in report succeeded, which is res.is_ok().

The tests don't cover this. The new tests/usage.rs case calls app.event directly and never goes through the handler, so it can't catch the problem above. A handler-level test with a refused push would.

Minor: one line in deploy/README.md runs long ("written for then or since, by anyone's push or commit; of those that signed in to MCP so, how many have").

crates/knotless-serve/src/gateway.rsline 665Outdated
report.extend(refused);
app.event("gateway.push", "", true, started.elapsed(), Some(&caller));
// By the owner it wrote for, whoever asked: what delegating led to.
app.event("gateway.served", "", true, started.elapsed(), Some(remote.did()));
review.knotless.dev

This fires even if every ref was refused or failed, since report can hold only Err entries. Guard it with report.iter().any(|(_, r)| r.is_ok()), as the commit path does with ok.

chadtmiller.com

Guarded with report.iter().any(|(_, res)| res.is_ok()) in c284fbf5, and protected_branches_hold_collaborators now checks through the handler that a refused push tells nothing and one that lands does. The README line is rewrapped.

Approved

Both points from my earlier review are addressed. In push, gateway.served now fires only when at least one ref in report succeeded (res.is_ok()). commit still fires it only on ok. The new handler-level assertions in tests/gateway.rs cover this: after the refused push, served is false for the owner. After a push that moves a ref, it is true, even though a collaborator pushed. The README funnel text is also reflowed, so the long line is gone. I didn't run the checks, so I haven't seen the tests pass.

Merged as 2eb4822