From 2ca0f6677868443d8b638df998bf498cc88e7097 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 15 Sep 2026 14:56:26 +0200 Subject: [PATCH 1/2] Add AGENTS.md codifying the generic proxy / overlay separation PR #46 added an ignored test in src/catalog.rs asserting Moneybird- specific facts (collection counts, scope lists, throttling numbers) directly in this repo. It was reverted in PR #70 because that content already belongs in, and is already published and validated by, localthought/overlays via OpenAPI/Overlay documents. Document the boundary so future contributions land in the right repo. Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..46e58b2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,86 @@ +# Agent guidance for integration-proxy + +## This repository is platform-agnostic + +`integration-proxy` is generic OAuth/catalog plumbing. It knows how to load a +catalog, compose an OpenAPI document from a pinned OAD plus pinned +[Overlay Specification](https://spec.openapis.org/overlay/latest.html) +documents, run the OAuth code/PKCE flows the composed document describes, and +allowlist proxy requests against it. It must never know the name, shape, or +business rules of any specific third-party API. + +**No platform-specific code, names, magic numbers, or fixtures belong in this +repository.** That includes, but is not limited to: + +- Hard-coding a platform name (`"moneybird"`, `"google-calendar"`, ...) in + `src/` outside of already-generic config plumbing (e.g. deriving an env var + name from whatever name the catalog happens to contain). +- Asserting platform-specific facts in tests — expected collection counts, + scope lists, throttling limits, schema fields, endpoint paths. If a test + needs to say "Moneybird has 32 read collections" or "the Calendar event + schema has a `recurrence` field", that assertion belongs in the + `localthought/overlays` repository, not here. +- Response schema fixes, missing fields, pagination quirks, or throttling + metadata for a specific API. These are OpenAPI/Overlay documents, and they + are published and pinned in `localthought/overlays`. + +If you find yourself wanting to add any of the above to this repo, stop — the +right place for it is an OpenAPI document or Overlay Specification document in +`localthought/overlays`, referenced from `catalog.json` there. See the +[Catalog section of the README](README.md#catalog) for how sources are pinned +and composed. `localthought/overlays` has its own validation scripts (e.g. +`scripts/validate_moneybird_metadata.rb`) for exactly this kind of +per-platform assertion — extend those instead of teaching this repo about a +platform. + +### Why this separation matters + +This proxy serves many unrelated third-party APIs through one generic +composition pipeline. If platform knowledge leaks into `src/` or its tests, +every future platform addition or fix requires touching and re-reviewing +generic, security-sensitive code (OAuth flows, credential handling, request +allowlisting) instead of only publishing a new pinned overlay revision. It +also means this repo's test suite silently breaks whenever an upstream API +changes shape, even though nothing about the proxy's own behavior changed. + +Background: [PR #46](https://github.com/localthought/integration-proxy/pull/46) +added an `#[ignore]`d test asserting Moneybird-specific numbers (collection +counts, OAuth scope counts, throttling limits) directly in `src/catalog.rs`. +It was reverted in +[PR #70](https://github.com/localthought/integration-proxy/pull/70) because +all of that content was already correctly published as OpenAPI Overlay +documents in `localthought/overlays` and validated there — duplicating it +here only added a platform-specific liability to generic code. + +### What generic code may do + +- Load and compose *any* catalog entry the same way, regardless of platform. +- Validate the *shape* of a catalog entry generically (e.g. "every OAuth + provider has at least one scope", "every selection's `query_overrides` path + exists in the composed document") without asserting platform-specific + values. +- Reference a pinned `localthought/overlays` catalog URL as the default + `CATALOG_PATH` (`src/config.rs`) — that's an opaque pointer, not platform + knowledge. + +### What belongs in `localthought/overlays` instead + +- OpenAPI Overlay documents that add, fix, or complete response schemas + (missing fields, corrected types). +- Overlay documents that describe CRUD/collection structure, pagination + schemes, auth requirements, or throttling limits for a specific API. +- Consumer `selection` objects (query overrides, OAuth security scheme + choice, trusted tenant-identity operation) for a specific catalog entry. +- Platform-specific validation scripts and fixtures. + +## Making a platform-specific fix + +1. Make the change as an OpenAPI document or Overlay Specification document + in `localthought/overlays`, with its own validation there. +2. Publish and verify the immutable pins, then commit the updated root + `catalog.json` in `localthought/overlays`. +3. Bump the pinned `CATALOG_PATH` default in this repo's `src/config.rs` to + the new immutable revision (a one-line, platform-agnostic change) and + restart the service. + +Do not add a step that teaches this repo what the platform's API looks like. From 5b8395ef13ad7b9689fd32d1a3dbea3f8664ae9e Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 15 Sep 2026 15:07:30 +0200 Subject: [PATCH 2/2] Clarify that pinned-fixture tests are fine, only runtime branching isn't The prior wording read as banning any platform-specific assertion in this repo, which would have also outlawed the existing pinned-fixture tests in src/identity_catalog_tests.rs and src/catalog.rs. The actual boundary is about production src/ code never branching on platform identity or hand-authoring platform data; a test asserting facts about a pinned localthought/overlays fixture is the right way to prove the generic composition pipeline works for real inputs. Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 124 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 46e58b2..89e5fd6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,72 +6,71 @@ catalog, compose an OpenAPI document from a pinned OAD plus pinned [Overlay Specification](https://spec.openapis.org/overlay/latest.html) documents, run the OAuth code/PKCE flows the composed document describes, and -allowlist proxy requests against it. It must never know the name, shape, or -business rules of any specific third-party API. - -**No platform-specific code, names, magic numbers, or fixtures belong in this -repository.** That includes, but is not limited to: - -- Hard-coding a platform name (`"moneybird"`, `"google-calendar"`, ...) in - `src/` outside of already-generic config plumbing (e.g. deriving an env var - name from whatever name the catalog happens to contain). -- Asserting platform-specific facts in tests — expected collection counts, - scope lists, throttling limits, schema fields, endpoint paths. If a test - needs to say "Moneybird has 32 read collections" or "the Calendar event - schema has a `recurrence` field", that assertion belongs in the - `localthought/overlays` repository, not here. -- Response schema fixes, missing fields, pagination quirks, or throttling - metadata for a specific API. These are OpenAPI/Overlay documents, and they - are published and pinned in `localthought/overlays`. - -If you find yourself wanting to add any of the above to this repo, stop — the -right place for it is an OpenAPI document or Overlay Specification document in +allowlist proxy requests against it. Its *runtime behavior* must never depend +on the name, shape, or business rules of any specific third-party API. + +**No platform-specific behavior, branching, or hand-authored data belongs in +this repository's production code.** That includes: + +- Hard-coding a platform name (`"moneybird"`, `"google-calendar"`, ...) to + drive a code path in `src/`, outside of already-generic config plumbing + (e.g. deriving an env var name from whatever name the catalog happens to + contain). +- Hand-writing response schema fixes, missing fields, CRUD/collection + structure, pagination quirks, or throttling metadata for a specific API + inline in this repo. These are OpenAPI/Overlay documents, and they are + authored, published, and pinned in `localthought/overlays`. +- Consumer `selection` objects (query overrides, OAuth security scheme + choice, trusted tenant-identity operation) for a specific catalog entry — + those are also authored in `localthought/overlays`' `catalog.json`. + +If you find yourself wanting to add any of the above, stop — the right place +is an OpenAPI document or Overlay Specification document in `localthought/overlays`, referenced from `catalog.json` there. See the [Catalog section of the README](README.md#catalog) for how sources are pinned and composed. `localthought/overlays` has its own validation scripts (e.g. -`scripts/validate_moneybird_metadata.rb`) for exactly this kind of -per-platform assertion — extend those instead of teaching this repo about a -platform. - -### Why this separation matters - -This proxy serves many unrelated third-party APIs through one generic -composition pipeline. If platform knowledge leaks into `src/` or its tests, -every future platform addition or fix requires touching and re-reviewing -generic, security-sensitive code (OAuth flows, credential handling, request -allowlisting) instead of only publishing a new pinned overlay revision. It -also means this repo's test suite silently breaks whenever an upstream API -changes shape, even though nothing about the proxy's own behavior changed. - -Background: [PR #46](https://github.com/localthought/integration-proxy/pull/46) -added an `#[ignore]`d test asserting Moneybird-specific numbers (collection -counts, OAuth scope counts, throttling limits) directly in `src/catalog.rs`. -It was reverted in -[PR #70](https://github.com/localthought/integration-proxy/pull/70) because -all of that content was already correctly published as OpenAPI Overlay -documents in `localthought/overlays` and validated there — duplicating it -here only added a platform-specific liability to generic code. +`scripts/validate_moneybird_metadata.rb`) for authoring correctness — extend +those instead of teaching this repo how to author a platform's data. + +### Tests that use pinned platform fixtures are fine + +The rule above is about *authoring* platform data and *branching on* platform +identity in runtime code — not about testing. A test — especially an +`#[ignore]`d one gated behind a real network fetch — that loads a real, pinned +`localthought/overlays` catalog revision and asserts facts about the +*composed result* (e.g. "the composed Moneybird document has N collections", +"every provider has non-empty OAuth scopes") is the correct way to prove the +generic load-and-compose pipeline actually produces the right document for +real inputs. This repo already does this: `src/identity_catalog_tests.rs` and +the pinned-catalog test in `src/catalog.rs` both load real composed +Google/GitHub/Moneybird data, with fixture provenance recorded in +`tests/identity-catalog/sources.json`. That's a different, complementary +layer from `localthought/overlays`' own authoring-time validation — this +repo's version proves the *proxy* composes real pins correctly at runtime, +not just that the overlay documents are internally well-formed. + +The line: a test may *read and assert against* pinned platform data. Runtime +`src/` code may never *contain or branch on* it. ### What generic code may do - Load and compose *any* catalog entry the same way, regardless of platform. - Validate the *shape* of a catalog entry generically (e.g. "every OAuth - provider has at least one scope", "every selection's `query_overrides` path - exists in the composed document") without asserting platform-specific - values. + provider has at least one scope") without depending on which platform it + came from. - Reference a pinned `localthought/overlays` catalog URL as the default `CATALOG_PATH` (`src/config.rs`) — that's an opaque pointer, not platform knowledge. +- Assert platform-specific facts about a pinned fixture in a test, to prove + the composition pipeline works end-to-end (see above). ### What belongs in `localthought/overlays` instead -- OpenAPI Overlay documents that add, fix, or complete response schemas - (missing fields, corrected types). -- Overlay documents that describe CRUD/collection structure, pagination - schemes, auth requirements, or throttling limits for a specific API. -- Consumer `selection` objects (query overrides, OAuth security scheme - choice, trusted tenant-identity operation) for a specific catalog entry. -- Platform-specific validation scripts and fixtures. +- OpenAPI Overlay documents that add, fix, or complete response schemas, + CRUD/collection structure, pagination schemes, auth requirements, or + throttling limits for a specific API. +- Consumer `selection` objects for a specific catalog entry. +- Platform-specific validation scripts and fixtures for authoring correctness. ## Making a platform-specific fix @@ -81,6 +80,23 @@ here only added a platform-specific liability to generic code. `catalog.json` in `localthought/overlays`. 3. Bump the pinned `CATALOG_PATH` default in this repo's `src/config.rs` to the new immutable revision (a one-line, platform-agnostic change) and - restart the service. + restart the service. Optionally add or extend a pinned-fixture test here + that asserts the newly composed document looks right — that's welcome. + +Do not add a step that teaches this repo how to author the platform's data, +and do not make runtime `src/` code behave differently for one platform. + +## Background -Do not add a step that teaches this repo what the platform's API looks like. +[PR #46](https://github.com/localthought/integration-proxy/pull/46) added an +`#[ignore]`d test asserting Moneybird-specific facts (collection counts, +throttling limits) about a pinned real catalog fixture in `src/catalog.rs`. +It was briefly reverted in +[PR #70](https://github.com/localthought/integration-proxy/pull/70) on +concern that this was Moneybird-specific code leaking into the generic proxy. +On inspection, it wasn't: the underlying data was authored correctly as +Overlay documents in `localthought/overlays`, and the test followed the same +pinned-fixture pattern already used elsewhere in this repo (see above) — it +just proved the proxy composes those pins correctly. PR #70 was closed as a +false alarm; this file exists so the actual boundary is written down instead +of re-litigated next time.