fix(api): correct baseline-snapshot sample + tech-events omitted-paging default (#4599 adversarial follow-ups A+B)#4666
Conversation
…ng default (adversarial follow-ups #4599) Two defects surfaced by an adversarial re-audit of the merged OpenAPI docs (#4657): A — RecordBaselineSnapshot request sample used `type: "all"`, which the handler rejects (VALID_BASELINE_TYPES has no 'all' → record-baseline-snapshot.ts:43 silently `continue`s), so a copy-paste yields `updated: 0` while the 200 example claims `updated: 1`. The examples injector's `endsWith('type')` heuristic emitted the literal 'all' with no curated override. Add a drift-anchored BASELINE_TYPE_EXAMPLE_ID (= infrastructureTemporalBaselineTypes[0], 'military_flights', matching the sibling GetTemporalBaseline enum example) + an overrideStringExample case scoped to baseline ops. Re-ran only the examples injector (version-independent). B — list-tech-events documented `limit`/`days` "defaults to 50/90 when omitted", but the REST decoder maps an omitted query param to 0, and clampInt treats a finite 0 as a value (→ min 1), not the fallback — so a no-params call returned 1 event within 1 day, not 50/90. Extract a pure, tested resolveTechEventsPaging() that guards with `|| default` (mirrors seismology `|| 500` and BLS `>0 ? : 60`); wire both handler call sites (fetchTechEvents + filterEvents) to it. The primary documented claim is now true. (The residual "explicit 0 clamps to 1" wording is a proto-comment change and rides the follow-up regen PR with #4599 items C/D.) Guard tests: baseline sample type ∈ VALID_BASELINE_TYPES; resolveTechEventsPaging omitted/0 → 50/90 (reproduced failing first, then fixed). 384 contract tests pass; tsc clean; examples injector --check idempotent. Claude-Session: https://claude.ai/code/session_01EsjtheWqt8GxEZfd3DyTMu
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Greptile SummaryThis PR fixes two doc-to-handler drift defects caught by an adversarial re-audit of the OpenAPI specs. Both fixes are narrowly scoped, version-independent, and accompanied by drift-anchored tests.
Confidence Score: 5/5Safe to merge — both changes are narrowly scoped bug fixes with targeted tests and no observable side-effects on other endpoints. The handler fix correctly mirrors the established sibling pattern (|| default) and is exercised by five unit tests covering the critical 0/undefined case. The OpenAPI sample correction is regenerated output guarded by a new drift-anchored contract test. The only rough edge is a test description that says 'below the minimum' while its input is at the minimum, which is a labelling issue with no impact on correctness. tests/tech-events-paging.test.mts — the 'below minimum' test case exercises the boundary value (1), not a sub-minimum value; worth a one-line fix before the follow-up PR adds more paging tests. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[REST decoder\nparams.get limit ?? 0] -->|decoded value| B{resolveTechEventsPaging}
B -->|req.limit = 0 or undefined| C["req.limit || 50 → 50\nclampInt(50, 50, 1, 200) → 50"]
B -->|req.limit = 25| D["req.limit || 50 → 25\nclampInt(25, 50, 1, 200) → 25"]
B -->|req.limit = -5| E["req.limit || 50 → -5\nclampInt(-5, 50, 1, 200) → 1"]
C --> F[fetchTechEvents / filterEvents]
D --> F
E --> F
G[examples injector\noverrideStringExample] -->|key='type', path includes 'baseline'| H[BASELINE_TYPE_EXAMPLE_ID\n= military_flights]
H --> I[record-baseline-snapshot\nrequest sample]
I -->|handler reads type| J{VALID_BASELINE_TYPES\nincludes?}
J -->|yes| K[updated += 1]
J -->|no — old: 'all'| L[silently continue\nupdated = 0]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[REST decoder\nparams.get limit ?? 0] -->|decoded value| B{resolveTechEventsPaging}
B -->|req.limit = 0 or undefined| C["req.limit || 50 → 50\nclampInt(50, 50, 1, 200) → 50"]
B -->|req.limit = 25| D["req.limit || 50 → 25\nclampInt(25, 50, 1, 200) → 25"]
B -->|req.limit = -5| E["req.limit || 50 → -5\nclampInt(-5, 50, 1, 200) → 1"]
C --> F[fetchTechEvents / filterEvents]
D --> F
E --> F
G[examples injector\noverrideStringExample] -->|key='type', path includes 'baseline'| H[BASELINE_TYPE_EXAMPLE_ID\n= military_flights]
H --> I[record-baseline-snapshot\nrequest sample]
I -->|handler reads type| J{VALID_BASELINE_TYPES\nincludes?}
J -->|yes| K[updated += 1]
J -->|no — old: 'all'| L[silently continue\nupdated = 0]
Reviews (1): Last reviewed commit: "fix(api): correct baseline-snapshot samp..." | Re-trigger Greptile |
| it('clamps explicit values below the minimum to 1', () => { | ||
| assert.deepEqual(resolveTechEventsPaging({ limit: 1, days: 1 }), { limit: 1, days: 1 }); | ||
| }); |
There was a problem hiding this comment.
The test description says "clamps explicit values below the minimum to 1", but the input values
{ limit: 1, days: 1 } are AT the minimum, not below it. The output { limit: 1, days: 1 } confirms this — no clamping actually occurs. As-is the test verifies that the lower bound is inclusive (fine), but the name implies a negative/sub-minimum value (-5 etc.) would be tested. This could mislead a future reader who changes clampInt's lower boundary and wonders why this test still passes.
| it('clamps explicit values below the minimum to 1', () => { | |
| assert.deepEqual(resolveTechEventsPaging({ limit: 1, days: 1 }), { limit: 1, days: 1 }); | |
| }); | |
| it('floor-clamps the minimum-boundary values (limit=1, days=1 are the minimums)', () => { | |
| assert.deepEqual(resolveTechEventsPaging({ limit: 1, days: 1 }), { limit: 1, days: 1 }); | |
| }); | |
| it('clamps explicit values below the minimum to 1', () => { | |
| assert.deepEqual(resolveTechEventsPaging({ limit: -5, days: -3 }), { limit: 1, days: 1 }); | |
| }); |
… fixed default (review #B) Follow-on to the resolveTechEventsPaging fix in this PR: with the handler now treating omitted/0 as the 50/90 default, the proto field comment's residual "0 is not unlimited (it clamps up to 1)" clause was stale (0 now → 50, since an omitted query param and an explicit 0 are the same value on the wire). Reword to "defaults to 50/90 when omitted or 0" and regenerate the ResearchService specs + bundle with the pinned sebuf v0.11.1 plugin (scoped diff: 3 artifacts, param descriptions only). make generate idempotent; contract + description-guard tests pass.
What & why
An adversarial re-audit of the merged OpenAPI docs (#4657, umbrella #4599) — 5 lenses (samples, auth, completeness, contract-validity, doc-truth) each verified against the real gateway/handlers — surfaced two defects the guards missed. This PR fixes both (the version-independent pair; the plugin-gated items C/D follow in a second PR).
A —
RecordBaselineSnapshotsample rejected by the handlerThe request sample used
type: "all", butVALID_BASELINE_TYPES=[military_flights, vessels, protests, news, ais_gaps, satellite_fires]—record-baseline-snapshot.ts:43silentlycontinues on a non-member, so a copy-paste yieldsupdated: 0while the200example claimsupdated: 1. Root cause: the examples injector'sendsWith('type')heuristic emitted the literal'all'with no curated override (the siblingGetTemporalBaselinequery enum correctly showsmilitary_flights).Fix: drift-anchored
BASELINE_TYPE_EXAMPLE_ID(=infrastructureTemporalBaselineTypes[0]) + anoverrideStringExamplecase scoped to baseline ops. Re-ran only the examples injector — version-independent, 3-artifact diff.B — tech-events "defaults to 50/90 when omitted" was false
The REST decoder maps an omitted query param to
0(Number(params.get("limit") ?? "0")), andclampInttreats a finite0as a value (→ min1), not the fallback — so a no-params call returned 1 event within 1 day, not the documented 50/90. Siblings guard correctly (seismology|| 500, BLS> 0 ? : 60); tech-events didn't.Fix: extract a pure, tested
resolveTechEventsPaging()that guards with|| default, and wire both handler call sites (fetchTechEvents+filterEvents) to it — de-duplicating the two identical resolutions. The primary documented claim is now true.Tests (Bug Fix Protocol — reproduced first)
resolveTechEventsPagingomitted/0→ 50/90 (added the failing test, confirmed it returned{1,1}, then fixed).record-baseline-snapshotsampletype∈VALID_BASELINE_TYPES(drift-anchored guard).tscclean; examples injector--checkidempotent; biome clean.Follow-up: #4658 tracks the handler-behavior notes.