Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Claude finished @alukach's task in 14s —— View job ❌ Changes requested — see findings below. Blocking
const PROSE = ["description", "summary", "example", "examples"];
const shape = (value: unknown, inProperties = false): unknown =>
Array.isArray(value)
? value.map((v) => shape(v))
: value && typeof value === "object"
? Object.fromEntries(
Object.entries(value)
.filter(([key]) => inProperties || !PROSE.includes(key))
.map(([key, v]) => [key, shape(v, key === "properties" && !inProperties)])
)
: value;After the fix, regenerate the snapshot ( Simplify (ponytail)
DocsThe description names the docs, 💰 Estimated review cost: $0.10 · 0m13s · 4 turns |
Base automatically changed from
feat/api-accounts-and-remaining-routes
to
main
October 16, 2026 02:29
The data proxy is the one consumer the API has to stay compatible with. The operations it calls (data.source.coop's src/source_api/cache.rs) are marked with forDataProxy, which adds `x-consumers: ["data-proxy"]` and opens their description with a warning, and data-proxy-contract.test.ts snapshots each one's parameters, request body, statuses and 200 schema, references resolved and prose stripped. A change that reshapes what the proxy reads fails CI until the snapshot is updated on purpose, and the test also fails if the marked set stops matching the list of calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The x-consumers marker and the forDataProxy description it came with duplicated PROXY_CALLS: no renderer or tool reads an x- extension, and the test only used the marker to find the operations its own list already names. The test now looks those operations up directly and fails if one leaves the document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alukach
force-pushed
the
feat/api-data-proxy-contract
branch
from
October 16, 2026 02:31
37565e7 to
41fcf39
Compare
alukach
added a commit
that referenced
this pull request
Oct 16, 2026
Follows #667, now merged. Writes down the API conventions this round of PRs settled on, so the next endpoint follows them without anyone reconstructing them from the code. ## What - **`API.md`** at the repository root, beside `CONTRIBUTING.md`: - **One operation, thin adapters:** what an operation decides, what a route and a server action may do, and the exceptions for routes no session can call. - **Documented where it's defined:** `registerPath` beside the handler, the coverage test and its `UNREGISTERED` allowlist, published prose, explicit `HEAD`, `bearer` and `optionalBearer`, `internal`, and `deprecated`. - **Resources and methods:** URL and field naming, and a table of what each method means and answers. Deactivating is `PATCH { "disabled": true }`, never `DELETE`, and one resource has one edit endpoint. - **Lists:** `{items, next_cursor}`, never a bare array. - **Errors:** the shared shape and when each status applies, the 500 `internal` error and the trust exchange's `{trusted: false}` 403, authorizing before validating where the permission doesn't depend on the input, and answering 404 for things the caller may not know of. - **Writes:** carry only the fields that changed, and what `accountsTable.update` always writes. - **Compatibility:** the data proxy is pinned by a test, the CLI follows the reference, and anyone else gets a traffic check, then deprecation rather than removal. - **`CLAUDE.md`** (and `AGENTS.md`, which links to it) gets a short **API** section telling an agent to read `API.md` before touching `/api/v1`. - **`CONTRIBUTING.md`**'s "Server Actions & API Routes" paragraph said both call `isAuthorized()` themselves. It now describes them as adapters over one operation and points at `API.md`. ## Where it lives A root `API.md` rather than more of `CLAUDE.md`: these are conventions for whoever writes an endpoint, person or agent, and much of it is visible in the code once you know where to look, which is what `CLAUDE.md` says it isn't for. `CLAUDE.md` carries the pointer, so agents still load it at the right moment. `CONTRIBUTING.md` links to it. ## Merge order The guide describes the API as it stands once the open PRs from this round merge, and names things they add: - `optionalBearer`, `internal` and `deprecated` endpoints (#667) - `data-proxy-contract.test.ts` (#671) - explicit `HEAD` (#672) - `pageSchema` and `onePage` (#673) - one `PATCH` per account (#674) - `DELETE` that only deletes (#675) Merge it after them, or trim the line that names whichever of them doesn't land. ## Where the code doesn't follow the guide yet The guide states the conventions, not the code's progress toward them. Known gaps, tracked outside the docs: - The `/data-connections` routes and the data-connection actions still read tables and call `isAuthorized()` directly: #593. - The credentials, profile-image and `createAccount` actions still call `isAuthorized()` directly: #592 and #594. - `updateProduct`, `deleteProduct` and `updateMembership` validate the body before authorizing, so a caller who may not act sees field errors instead of a 403. - `accountsTable.update` always writes `name`, `type` and whole metadata maps, so `updateAccount` can undo a concurrent edit. ## Docs, ADRs and `llms.txt` Repository-internal guidance only: no user-facing flow changes, so docs.source.coop and `llms.txt` are unaffected, and it records no decision shared with the data proxy beyond the existing contract test, so no data.source.coop ADR changes. ## Testing Documentation only; no code changed. Each claim in `API.md` was checked against the code after a review pass found several the code didn't hold to (`route-coverage.test.ts`, `accountsTable.update`, `withApiSession`'s error handling, the revocations and trust-exchange routes). Checked that `AGENTS.md` still resolves to `CLAUDE.md` and that the prose in `API.md` wraps at 80, as the repository's Markdown does. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Not sure this should be done in this codebase, rather the data proxy should have these tests |
This branch was successfully deployed
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.
Follows #667, now merged, and the discussion there about keeping the data proxy's endpoints from drifting.
What
The data proxy is the one consumer this API has to stay compatible with. The CLI is being built against the API now, so it follows the spec rather than pinning it. This PR adds one test, which fails CI when a change reshapes an endpoint the proxy calls. It changes no route and nothing in the published spec.
data-proxy-contract.test.tskeepsPROXY_CALLS, the list of calls the proxy makes, taken from data.source.coop'ssrc/source_api/cache.rs. It fails if one of them leaves the generated document.$refs resolved and descriptions stripped. Rewording an endpoint's docs doesn't trip it, but renamingtrusted, removing a status, or changinglimit's bounds does. The snapshot pins the 200 body and the status list, because those are all the proxy reads. It treats 200 as the only success, 404 as a missing bucket and 401/403 as a refusal, and never reads an error body.Pinned here:
GET /products/{account_id}GET /products/{account_id}/{product_id}GET /products/{account_id}/{product_id}/permissionsPOST /accounts/{account_id}/trusts/exchangesPOST /service-account-keys/exchangesThe proxy's sixth call,
GET /data-connections/{data_connection_id}, isn't in the generated document until #657 lands. That PR, or a follow-up to it, adds one line toPROXY_CALLS.PROXY_CALLSis kept by hand, so it can't notice the proxy starting to call something new. That half belongs on the proxy's side: source-cooperative/data.source.coop#256 checks its stub routes against the published spec.When the test fails
An added optional field is safe, because the proxy's serde types ignore unknown fields, and
jest -uaccepts it. A removed or retyped field, a changed status, or a new required parameter needs the data.source.coop change first. The comment above the snapshot test says so.What it doesn't catch
Behavior the spec doesn't express. Two examples are answering an unknown key with
200 {"active": false}rather than a 404, and saying no to a trust with a 403. Those stay with the route and operation tests that already assert them.Snapshot size
The snapshot is 1,452 lines, almost all of it the
Productschema with its embeddedAccountunion, once for the product and once per item in the account's listing. Any change toProductorAccountwill show up here as a snapshot diff, which is the point: the proxy deserializes those bodies.Docs, ADRs and
llms.txtNo user-facing behavior changes, so docs.source.coop and
llms.txtare unaffected. This is a guard in this repo's tests rather than a decision shared with the proxy, so no data.source.coop ADR changes; ADRs 005, 007, 013 and 014 still describe these endpoints.Testing
npm run type-checkpasses.npx jest --ci src/app/api/openapi: 36 tests, 5 snapshots pass; the snapshots are unchanged from the first commit.trustedtotrustin the trust exchange's answer schema fails it with a diff naming the field.🤖 Generated with Claude Code