bench(lab): admit a repository with one command - #298
Merged
Conversation
Admission was three manual acts that nothing checked against each other: a clone, a hand-written repository file with a sha copied out of it, and a scan. A sha in the json that is not the sha the clone sits at gives every later run a worktree at the wrong tree, and nothing about a result says so. The resolver is pure and its order is first match wins: an admitted id, a path on disk, `owner/name`, then a url. The ambiguous case resolves as the path, because a directory that is there is evidence and a handle is a guess. Everything that decides runs before anything is written, and the decision is announced in between: a caller whose announce returns an error stops with the directory as it found it. The pin is then read back out of the tree rather than carried over from the request. Ownership decides what may be moved. A clone the lab made and that drifted goes back to its pin; a clone somebody handed in is read and never written to, and a mismatch there is refused with its reason. The index phase runs the product binary the way a user would and reads its counts through the MCP server, in the checkout, because that is the channel a benched agent actually has. A scan that indexed nothing writes an artifact that says so.
`sense-lab repo <handle|url|path>` is the whole admission: it prints what it resolved, clones under the lab's own root, records the revision the clone is actually at, indexes it and writes the index artifact. The repository file is written last and only when there is an index to read its languages off, so a failed clone, an unreachable url or a scan that indexed nothing leaves nothing behind that a later phase would read as ready. Re-running on an admitted repository admits nothing and prints where it stands. The crank calls this on every invocation, so admission has to be idempotent for that to be safe. The repository record gains `checkout`, and its absence is the ownership rule: a repository the lab cloned has none, and is one the lab may move back to its pin.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This was referenced Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Admitting a repository to the bench is three manual acts today and nothing checks that they agree with each other: a human clones it, hand-writes
lab/repos/<id>.jsonwith a commit copied out of the clone, and runssense scanover it.Two things go wrong and only one of them is loud. A sha typed into the json that is not the sha the clone sits at produces a worktree at the wrong tree for every run afterwards, and nothing says so. A scan that indexed half the tree produces a repository that reads as dark when the tool simply did not finish.
Summary
sense-lab repo <handle|url|path>does the whole thing: resolve, clone, pin, index, record.The resolver is pure and its order is first match wins — an admitted id, a path on disk,
owner/name, then a url. A local directory namedowner/nameresolves as the path, because a directory that is there is evidence and a handle is a guess.Nothing is written before the resolution is printed. Everything that decides runs first and touches nothing; the decision is announced; only then does anything reach a disk. The recorded pin is read back out of the clone rather than carried over from the request.
Ownership decides what may be moved: a clone the lab made and that drifted goes back to its pin, and a clone somebody handed in is read and never written to, with a mismatch refused and its reason given.
Re-running on an admitted repository admits nothing and prints where it stands, because the crank will call this on every invocation.
Changes
lab/internal/repo: the pure resolver, the checkout (clone, adopt, correct or refuse) and the index phase, which runssense scanand reads its counts through the MCP server in the checkoutlab/internal/cli/repocmd.go: the command, its announcement, and the two records it writes — the index artifact and the repository file, the latter written last and only when there is an index to read its languages offcatalog.Repogainscheckout, whose absence is the ownership recordlab/README.mdandlab/repos/README.md: the first step of the shortest useful path is now this commandTest plan
make cigreen: coverage floor with no new exception, zero complexity suppressions, lint clean-embedfrom the scan, asking the server outside the checkout, deleting the MCP handshake, selecting the reply without its id, and reusing an earlier reply's document for a call that failedsensebinary, not only against the stand-in