Skip to content

Commit ec5fa66

Browse files
authored
Document that PolicyBlock field names are not the wire format (#117)
## Summary Documentation only. No behavior change. `PolicyBlock` uses camelCase and the AgentScore API expects snake_case. This SDK already translates the five compliance fields correctly at the request boundary (`buildGateFromPolicy`, `src/core.ts:779-783`), so anyone using the SDK is unaffected and always has been. The gap is that the type is exported, so a caller who hand-rolls the HTTP request takes the field names from it and sends camelCase. The API used to ignore a key it did not recognise, which meant such a policy matched no rule, ran no check, and returned `decision: "allow"`: a compliance gate passing without evaluating anything. The API now rejects it with a `400 invalid_policy` naming the correct spelling, so the failure is loud instead of silent. That leaves this type as the last place still suggesting a shape the API refuses, which is what this fixes. It also records which fields actually cross the wire: `enforcement`, `allowedShippingCountries` and `allowedShippingStates` are merchant-side concerns the SDK acts on locally and never sends, which is not obvious from a type whose other members all do. Worked with Varun, going through the Q3 2026 penetration test findings. ## Type of change - [ ] Bug fix (no breaking change) - [ ] New feature (no breaking change) - [ ] Breaking change (existing callers must update) - [x] Docs, tests, or internal maintenance only ## Public API None. No exported type, signature, wire format or response shape changes. `PolicyBlock`'s members are untouched; only its doc comment is added to. Deliberately NOT renamed: aligning the field names to snake_case would be a breaking change to a published package, and the SDK's translation is already correct, so the camelCase names are a genuine convenience rather than a defect. If we ever want them aligned it belongs in a major. ## Test plan Nothing here is executable, so the suite is a regression check rather than evidence for the change itself: `bun run lint`, `bun run typecheck` (including the examples project) and `bun run test` all clean, 119 files and 1817 tests passing with 4 skipped. The claims in the doc comment were checked against the source rather than assumed. `src/core.ts:779-783` maps exactly the five compliance fields to snake_case, and the three merchant-side fields (`enforcement`, `allowedShippingCountries`, `allowedShippingStates`) appear nowhere in the outbound request. Two things deliberately left out. The commerce-side half of the same finding is not here: the report separately flags `const allow = decision === 'allow' || decision == null` in `src/core.ts`, which treats a missing decision as allow, and that is a behavior change with its own tests and release. The finding stays open until it lands. And the 14 pre-existing em-dashes in this file are left alone, since our convention is that a gate judges the lines a change publishes and sweeping the prose would balloon a documentation diff. ## Checklist - [ ] Tests cover the new behavior, and the suite passes locally Not ticked deliberately: this is a doc comment, so there is no behavior to cover. The suite passes and is included above as a regression check. - [x] Lint, format, and type checks pass - [x] Docs and README examples updated if the public surface changed - [x] No secrets, credentials, or personal data in the diff or the tests
1 parent 0c9f0fc commit ec5fa66

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

src/identity/policy.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,27 @@ export type EnforcementMode = 'hard' | 'soft';
3737
/** Per-order trust level captured at settle time. */
3838
export type IdentityStatus = 'verified' | 'unverified' | 'anonymous' | 'denied';
3939

40-
/** Compliance fields a merchant attaches per product / per tier. All optional. */
40+
/**
41+
* Compliance fields a merchant attaches per product / per tier. All optional.
42+
*
43+
* THESE ARE SDK FIELD NAMES, NOT THE WIRE FORMAT. The AgentScore API expects
44+
* snake_case, and this SDK translates the five compliance fields at the request
45+
* boundary (`buildGateFromPolicy` in `../core.ts`). Sending these names to
46+
* `POST /v1/assess` directly is rejected with a 400 `invalid_policy`.
47+
*
48+
* That rejection is deliberate and recent. The API previously ignored a key it
49+
* did not recognise, which meant a camelCase policy matched no rule, ran no
50+
* check, and came back `decision: "allow"`, a silent pass from a compliance
51+
* gate. It now fails loudly instead, and the 400 names the correct spelling.
52+
*
53+
* So if you are hand-rolling the HTTP request rather than using this SDK, use
54+
* the snake_case names: `require_kyc`, `require_sanctions_clear`, `min_age`,
55+
* `blocked_jurisdictions`, `allowed_jurisdictions`.
56+
*
57+
* Note also that only those five cross the wire. `enforcement`,
58+
* `allowedShippingCountries` and `allowedShippingStates` are merchant-side
59+
* concerns this SDK acts on locally and never sends.
60+
*/
4161
export interface PolicyBlock {
4262
enforcement?: EnforcementMode;
4363
requireKyc?: boolean;

0 commit comments

Comments
 (0)