The Rust tests run against the reference PDS, under a coverage gate
MergedThis adds a reference-PDS harness, integration tests for the core, a coverage gate, lexicon answer checks and the CI workflow. The full diff is about 11,000 lines, and I could only read the files around it: the workflows, harness/cov.mjs, AGENTS.md and cov.json. I did not read the Rust tests or the other harness scripts line by line. The harness and check runs were still in progress when I looked, and rust and test were queued, so I have not seen any check result.
The coverage gate is set to zero. harness/cov.json is { "lines": 0, "functions": 0 }. cov.mjs reads it as the threshold, so nothing can fail the gate. The body and AGENTS.md both say the gate "is where the workspace stands" and must never be lowered. Set it to the percentages the first successful harness run reports, rounded down, so the gate holds from this pull on. If 0 is deliberate until the first run, say so and fix it in this pull once the numbers exist.
The description and the workflow disagree about when the check runs. The body says the check runs on "pulls into main and feature/* and pushes to main". harness.yml matches this for pulls, with base: [main, feature/*], and for pushes, which cover only main. This is fine if intended. If you meant pushes to feature/* as well, add them.
Please also confirm the harness and rust checks pass on this head before it merges.
harness/cov.jsonline 1Outdated
{ "lines": 0, "functions": 0 } |
Both thresholds are 0, so the gate can never fail. Set them to what the first green run reports (rounded down); AGENTS.md says they only go up.
The zero gate was there only until the first run reported a figure. That run gave 99.15% of lines and 98.43% of functions, and b4cce33 sets the gate to 99.1 and 98.4. The trigger is deliberate: harness.yml runs on pushes to main and on pulls into main and feature/*, the same as rust, check and test. The parts of a feature branch arrive as pulls, so a run on each push to it would only repeat the run of the pull that landed. All four checks passed at 6a43047, and they are running again at b4cce33.
Both points from my first review are fixed. harness/cov.json is now { "lines": 99.1, "functions": 98.4 }, so the gate can fail. The workflow now matches the description: pulls into main and feature/*, pushes to main. I only re-read cov.json and harness.yml this round, not the rest of the diff.
On this head (b4cce33) harness and check were still running, and rust and test were queued. I have no result for any of them. Before merging, make sure harness passes, since it is the first run to enforce those thresholds. If it fails on coverage, set cov.json to what it reports, rounded down.
- The Rust tests run against the reference PDS, under a coverage gate
- main

What changes
A reference PDS for the tests.
harness/runs@atproto/pds(from@atproto/dev-env0.6.26, as knotless pins it) and a PLC directory on free ports, as knotless's harness does:pds.mjsstarts them and prints where,authorize.mjsapproves (or rejects, or signs up at) the PDS's OAuth page as the browser, andtls-proxy.mjsputs a confidential client athttps://client.grain.internal, which the harness resolves to 127.0.0.1 and trusts.crates/grain/tests/commonstarts one per test binary, or uses the oneGRAIN_TEST_NETnames (just pds), and makes an account per test.Integration tests of the core against it.
tests/pds.rs: a handle and a DID resolved through the PDS and PLC, the DID document's service and key, verified handles; app-password sessions; service tokens fromgetServiceAuthverified against the account's PLC key,lxm/aud/expheld; password sessions kept, refreshed withrefreshSession, and refused once the PDS ends them;uploadBlobandgetBlob.tests/oauth.rs: the command line's loopback login end to end (PAR, PKCE, the redirect to 127.0.0.1, DPoP proofs under the PDS's nonces, refresh in place, a spent refresh token refused, logout revoking), a refused login, a confidential client's login withprivate_key_jwtassertions, refresh and revoke, and an account made at sign-up (prompt=create). Both check the scope: a post goes through, a like and a text blob are refused asout_of_scope.tests/cli.rsand grain-serve'stests/main.rsrun the two binaries.The coverage gate.
harness/cov.mjs, ported from knotless's, builds the tests instrumented once and runs each binary against shared harnesses, retrying a failure once (loggedFLAKY), and fails underharness/cov.json's lines and functions. The gate is where the workspace stands, not knotless's 100%: 99.1% of lines and 98.4% of functions, from the first run's 99.15% and 98.43%, rounded down. What falls short is 27 lines of the core: defensive branches its unit tests never reach (an issuer that names itself wrongly, a token for another DID,Env::from_process), and a few lines of the in-crate test servers.Lexicon answer checks.
harness/answers.mjs, from knotless's: every XRPC answer grain-serve's tests received, throughcrates/grain-serve/tests/common, which records them underGRAIN_ANSWERS, must be valid output for its lexicon inlexicons/, ask only declared parameters, fail as{error, message}, and be a method some lexicon names._health, which no lexicon names, is held to{version}.harness/answers-test.shchecks the check against a lexicon and answers of its own, right and wrong. grain-serve now answers a method it does not serve as XRPC servers do,501 MethodNotImplemented, so failures have something to be held to.CI and docs.
.knotless/workflows/harness.ymlruns the gate and the answer checks on pulls into main andfeature/*and on pushes to main, as every other workflow here does;rust.ymlkeeps fmt and clippy, its plaincargo testfolded into the harness run.just setup,pds,t,cov,answers; AGENTS.md says how it works.Why
The core pulls left untested what only a real PDS shows: PLC resolution, service tokens, the authorization server's PAR, token, refresh and revoke endpoints and DPoP nonces, blobs, app passwords. Every grain-serve method from here on is held to its lexicon as it is added, which knotless found to be what keeps a server and its pages' generated types agreeing.
How it was checked
On the runner:
harnessran all 9 test binaries (61 tests) against two harnesses in about 100s, and the answer checks passed;rust,checkandtestpassed too.answers-test.shwas also run here.Shortcomings
plans.mjs(until there is a database) and the screenshot tooling (until there are pages).app.bsky.feed.post, notsocial.grain.*, so the test PDS never resolves grain's published lexicons over the network.🤖 Generated with Claude Code