Skip to content

fix(docs): derive closed-value OpenAPI examples#4844

Merged
koala73 merged 4 commits into
mainfrom
codex/docs-openapi-curated-examples-4827
Jul 5, 2026
Merged

fix(docs): derive closed-value OpenAPI examples#4844
koala73 merged 4 commits into
mainfrom
codex/docs-openapi-curated-examples-4827

Conversation

@koala73

@koala73 koala73 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

OpenAPI examples now use real documented values for closed-value API fields instead of placeholder strings that clients could not copy successfully. The examples injector now derives curated values at generation time for the confirmed clusters in #4827, including GDELT topics, regional intelligence IDs, consumer-price ranges and baskets, Google Flights filters, summarize-article mode, scenario polling, and request/response echo fields that must agree.

This is a generator-level fix in scripts/openapi-inject-examples.mjs, so regenerated per-service specs and the unified OpenAPI bundle stay consistent instead of patching YAML/JSON by hand. The async scenario status poll example now represents a plausible completed job using the worker template key and lifecycle-compatible result shape.

Closes #4827.

Validation

  • node scripts/openapi-inject-examples.mjs
  • npm run build:openapi
  • node --test tests/openapi-examples-contract.test.mjs
  • node --test tests/openapi-async-jobs-contract.test.mjs
  • node scripts/openapi-inject-examples.mjs --check
  • git diff --check
  • npm run typecheck:api
  • Pre-push hook: frontend typecheck, API typecheck:api, Convex type check, CJS syntax, Unicode safety, boundary/safe-html/rate-limit/premium-fetch guards, edge bundle check, changed OpenAPI examples test, proto freshness, version sync

Post-Deploy Monitoring & Validation

No additional operational monitoring required. This changes generated API documentation examples and the docs injector/test coverage only; no runtime handler behavior changes.


Compound Engineering
GPT--5

@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Jul 5, 2026 11:58am

Request Review

@mintlify

mintlify Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
WorldMonitor 🟢 Ready View Preview Jul 5, 2026, 11:17 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes OpenAPI documentation by replacing placeholder example strings with real, validated values for closed-value API fields across IntelligenceService, ConsumerPricesService, AviationService, NewsService, and ScenarioService. The fix is generator-level: scripts/openapi-inject-examples.mjs now derives curated examples at generation time by reading the same server-side source files the handlers use, keeping examples drift-anchored rather than hand-patched.

  • New constant derivations cover GDELT topic IDs, regional intelligence IDs, consumer-price basket slugs and ranges, Google Flights filters (cabin class, max stops, departure window, airlines, sort order), summarize-article mode, and a lifecycle-correct scenario-status poll response (status: "done" with template key and chokepoint IDs).
  • A new descriptionClosedValueExample helper parses prose field descriptions for closed-value enumerations and selects a plausible example automatically, removing the need for per-field overrides on most parameters.
  • The contract test suite gains seven new assertions covering all of the above and a new general-purpose assertClosedValueParamExamples sweep that enforces prose-enumerated values across all service specs.

Confidence Score: 4/5

Safe to merge for documentation purposes; no runtime handler behavior changes. The generator logic has a few edge-case gaps but the test suite acts as a meaningful safety net at generation time.

The change is entirely documentation-layer: generated OpenAPI spec files and the injector script that produces them. The three issues found are all in the generator logic — a latent firstClosedValue bug that could emit "default" as an example literal, a permanently unreachable tariff_shock fallback, and a basket-ID source-file mismatch between injector and test. None affect runtime behavior, but they represent logic gaps that could surface as confusing test failures during a future refactor.

scripts/openapi-inject-examples.mjs — the firstClosedValue first-pass guard and the basket-ID source-file discrepancy warrant a second look before the next round of example coverage expansion.

Important Files Changed

Filename Overview
scripts/openapi-inject-examples.mjs Core generator that derives curated OpenAPI examples; adds ~180 lines for GDELT, region, consumer-price, Google Flights, and scenario-status derivation. Contains a latent firstClosedValue bug (first pass can emit the literal "default"), a permanently unreachable 'tariff_shock' fallback, and a basket-ID source-file mismatch vs. the test.
tests/openapi-examples-contract.test.mjs Extends the contract test suite with GDELT topic, region ID, consumer-price range/basket, Google Flights, ComputeEnergyShockScenario echo, and scenario-status poll assertions. Comprehensive guard coverage; the 'tariff_shock' branch in assertScenarioStatusPollExample mirrors the dead-code branch in the injector.
docs/api/IntelligenceService.openapi.json Regenerated artifact; examples updated with curated GDELT topic, region ID, and chokepoint IDs replacing generic placeholders.
docs/api/ScenarioService.openapi.json Regenerated artifact; scenario-status poll response example updated with lifecycle-compatible done shape including template key and affected chokepoint IDs.
docs/api/ConsumerPricesService.openapi.json Regenerated artifact; basket slug and range parameter examples now use real documented values.
docs/api/AviationService.openapi.json Regenerated artifact; Google Flights filter examples (cabin class, max stops, departure window, airlines, sort by) updated with documented closed-set values.
docs/api/NewsService.openapi.json Regenerated artifact; summarize-article mode example now uses a valid documented value instead of a placeholder.
docs/api/worldmonitor.openapi.yaml Regenerated unified bundle; reflects all per-service example improvements consistently.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[openapi-inject-examples.mjs] --> B{overrideStringExample}
    B -->|matched key| C[Curated override\ne.g. GDELT topic, region, basket, range]
    B -->|no match| D{shouldUseDescriptionClosedValue?\nexampleSurface = parameter or request}
    D -->|yes| E[descriptionClosedValueExample\nparse prose description]
    E --> F{closed-value match?}
    F -->|yes| G[firstClosedValue\nprefer default-annotated candidate]
    F -->|no| H[heuristic fallback\nformat / key pattern / generic]
    G --> I[constrainedString → example value]
    H --> I
    D -->|no| H
    C --> I
    I --> J[Per-service openapi.json / .yaml\nupdated examples]
    J --> K[worldmonitor.openapi.yaml bundle]
    K --> L[openapi-examples-contract.test.mjs\nvalidates all examples]
Loading
%%{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[openapi-inject-examples.mjs] --> B{overrideStringExample}
    B -->|matched key| C[Curated override\ne.g. GDELT topic, region, basket, range]
    B -->|no match| D{shouldUseDescriptionClosedValue?\nexampleSurface = parameter or request}
    D -->|yes| E[descriptionClosedValueExample\nparse prose description]
    E --> F{closed-value match?}
    F -->|yes| G[firstClosedValue\nprefer default-annotated candidate]
    F -->|no| H[heuristic fallback\nformat / key pattern / generic]
    G --> I[constrainedString → example value]
    H --> I
    D -->|no| H
    C --> I
    I --> J[Per-service openapi.json / .yaml\nupdated examples]
    J --> K[worldmonitor.openapi.yaml bundle]
    K --> L[openapi-examples-contract.test.mjs\nvalidates all examples]
Loading

Reviews (1): Last reviewed commit: "fix(docs): derive closed-value OpenAPI e..." | Re-trigger Greptile

Comment on lines +233 to +244
function firstClosedValue(candidates) {
for (const raw of candidates) {
const value = normalizeDescriptionValue(raw);
if (/\bdefault\b/i.test(String(raw)) && candidateLooksLikeClosedValue(value)) return value;
}
for (const raw of candidates) {
const value = normalizeDescriptionValue(raw);
if (!value || value.toLowerCase() === 'default') continue;
if (candidateLooksLikeClosedValue(value)) return value;
}
return undefined;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 firstClosedValue first pass may return the literal "default" as an example

The first loop checks \bdefault\b in the raw candidate and returns the normalized value. When raw === "default", normalizing it gives "default" and candidateLooksLikeClosedValue("default") is true, so the function returns "default" as the example string — a value that no API handler accepts. The second pass correctly guards against this with value.toLowerCase() === 'default', but it only runs when the first pass doesn't short-circuit. Any description parsed as ["economy", "default"] would produce "default" as the chosen example instead of "economy".

The fix is to add the same guard in the first pass: if (/\bdefault\b/i.test(String(raw)) && value.toLowerCase() !== 'default' && candidateLooksLikeClosedValue(value)) return value;. The assertClosedValueParamExamples test would catch this at generation time, but the root cause is still worth addressing.

Comment on lines +96 to +99
const SCENARIO_RESULT_TEMPLATE_NAME =
SCENARIO_RESULT_AFFECTED_CHOKEPOINT_IDS.length > 0
? SCENARIO_RESULT_AFFECTED_CHOKEPOINT_IDS.join('+')
: 'tariff_shock';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 'tariff_shock' fallback is permanently unreachable dead code

SCENARIO_RESULT_AFFECTED_CHOKEPOINT_IDS is guaranteed to be non-empty: its own IIFE returns ids.length > 0 ? ids : [CHOKEPOINT_EXAMPLE_ID] (line 93), so it always contains at least one element. Therefore the condition SCENARIO_RESULT_AFFECTED_CHOKEPOINT_IDS.length > 0 is always true, and SCENARIO_RESULT_TEMPLATE_NAME is never 'tariff_shock'. The mirror in the test (assertScenarioStatusPollExample, line 444) has the identical dead branch. If the chosen scenario template ever has no affectedChokepointIds in source, the fallback would silently produce the chokepoint example ID (e.g., 'suez') as the template name rather than the intended 'tariff_shock'.

Comment on lines +128 to +132
const CONSUMER_PRICE_BASKET_EXAMPLE_ID = (() => {
const src = readRepoText('src/services/consumer-prices/index.ts') || readRepoText('scripts/seed-consumer-prices.mjs');
const match = src.match(/\b(?:DEFAULT_BASKET|BASKET)\s*=\s*['"`]([^'"`]+)['"`]/);
return match?.[1] ?? 'essentials-ae';
})();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Injector and test read basket ID from different source files with different regex patterns

The injector reads src/services/consumer-prices/index.ts (fallback: scripts/seed-consumer-prices.mjs) using the pattern (?:DEFAULT_BASKET|BASKET)\s*=, while the test builds CURATED.consumerBaskets from server/worldmonitor/consumer-prices/v1/get-consumer-price-basket-series.ts with the narrower DEFAULT_BASKET\s*= pattern. If the constant in the injector's primary source file is named BASKET (not DEFAULT_BASKET) or is set to a different value than the handler constant, the injector will emit a basket slug that the test's accepted-set doesn't contain — the test would fail without revealing the source-of-truth mismatch. Both lookups should use the same source file and same pattern.

@koala73
koala73 force-pushed the codex/docs-openapi-curated-examples-4827 branch from 4dc497d to 3db2580 Compare July 5, 2026 11:54
@koala73
koala73 merged commit 74a0bab into main Jul 5, 2026
25 checks passed
@koala73
koala73 deleted the codex/docs-openapi-curated-examples-4827 branch July 5, 2026 12:05
koala73 added a commit that referenced this pull request Jul 5, 2026
…son — back under the ~1MB scanner cap (#4852) (#4853)

Today's per-op doc injections (#4843 429 blocks, #4841 idempotency, #4844
examples) grew the minified public/openapi.json 752KB -> 1.04MB, crossing
the ~1MB body cap orank's function-calling validator imposes: the Access
check function-calling-compat flipped PASS -> 'API spec found but couldn't
validate function calling compatibility' (score 91 -> 90). elevenlabs
(1.8MB) and openrouter (1.5MB) hit the identical error path; sub-800KB
specs get computed verdicts.

Hoist the byte-identical non-2xx response objects (429 x193, default x193,
401 x186, 400, 403, 409, 422) into components.responses $refs when
emitting the JSON artifact only - semantically identical OpenAPI 3.1,
validated with @seriousme/openapi-schema-validator. 2xx responses stay
inline (orank credits only the inline responses['200'] schema). YAML
sources keep their inline copies for Mintlify and the contract tests.

Result: 812,276 bytes (10 shared components, 975 refs), deterministic
rebuild, lossless roundtrip proven by test. A 950KB budget guard test
stops the next injector from silently re-crossing the cap.

Claude-Session: https://claude.ai/code/session_013AWjvnpnJTE6G2PaYk9iT1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(api): examples injector ships placeholder/invalid samples for closed-value params — 7 confirmed clusters incl. the async-contract poll op

1 participant