Skip to content

Scope SDK batch generation + add spec-changes manifest#35

Merged
gjtorikian merged 7 commits into
mainfrom
filter-resolved-ir
Jun 23, 2026
Merged

Scope SDK batch generation + add spec-changes manifest#35
gjtorikian merged 7 commits into
mainfrom
filter-resolved-ir

Conversation

@gjtorikian

Copy link
Copy Markdown
Collaborator

Summary

  • Make generate-prs.yml workflow_dispatch-only with batch_id (required) + services (CSV, optional) inputs, so SDK regeneration targets changed services instead of fanning out over everything on push-to-main.
  • Extract branch/commit/push/PR logic into scripts/open-batch-pr.mjs: deterministic oagen/batch-<id> branch, force-push idempotence, empty-diff skip, per-entry + catch-all commits, create-or-reuse PR with --dry-run gating the gh mutations.
  • Forward --services through scripts/sdk-generate.sh to oagen generate (full generation when the flag is absent).
  • Add scripts/build-spec-changes.mjs + .github/workflows/spec-changes.yml: on a spec merge, record .spec-changes/<sha>.json of changed post-mount services (+ hasBreaking) at the repo root, so the manifest commit re-triggers neither spec-changes.yml nor release.yml.
  • Publish a dedicated sdk-compat commit status on PRs so the automation bot reads a clean breaking/non-breaking signal instead of scraping the PR comment.
  • Add node:test suites (28 tests) + a captured oagen-diff fixture and a test npm script.

Test plan

  • npm test passes (28 node:test cases)
  • Dispatch generate-prs.yml with batch_id + services CSV; confirm only listed services regenerate into oagen/batch-<id>
  • Re-run the same dispatch; confirm force-push idempotence + empty-diff skip
  • Merge a spec change; confirm .spec-changes/<sha>.json is written and does not re-trigger spec-changes.yml or release.yml
  • Open a PR with a breaking change; confirm the sdk-compat status reports failure (success when non-breaking)

gjtorikian and others added 2 commits June 20, 2026 19:51
Phase 2 of scoped SDK generation. LOCAL scope only — the oagen/oagen-emitters
version bump and real workflow_dispatch/push verification are deferred CI steps
the maintainer runs after publish.

- Sever the push-to-main fan-out from generate-prs.yml; it is now
  workflow_dispatch-only, with new `services` (CSV, optional) and `batch_id`
  (required) inputs.
- Forward `--services` through scripts/sdk-generate.sh to `oagen generate`
  (full generation when absent); CSV spaces are stripped before threading.
- Extract the branch/commit/push/PR logic into scripts/open-batch-pr.mjs:
  deterministic oagen/batch-<id> branch, force-push idempotence (NFR-2.2),
  no-op/empty-diff skip (FR-2.7), per-entry + catch-all commits, and
  create-or-reuse PR with `--dry-run` gating only the gh mutations.
- Add scripts/build-spec-changes.mjs + .github/workflows/spec-changes.yml:
  on a spec merge, record a per-commit .spec-changes/<sha>.json of changed
  post-mount services (mapped via the imported policy mountRules, with
  IR-based model/enum ownership) and hasBreaking. The manifest lives at the
  repo root so its commit re-triggers neither spec-changes.yml nor release.yml.
- Add node:test suites (28 tests) + a captured oagen-diff fixture, and a `test`
  npm script (node --test scripts/__tests__/*.spec.mjs).

Review: 1 cycle, PASS (0 critical/high). 3 medium + 2 low findings addressed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SDK automation bot needs a clean breaking/non-breaking
signal to act on, and the only machine-readable source today is
the PR comment body, which is fragile to scrape. A dedicated
sdk-compat commit status encodes compatibility directly, kept
separate from the build/test job conclusion so the two signals
don't get conflated.
@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR scopes SDK batch generation to changed services (instead of fanning out over everything on push-to-main), extracts branch/commit/push/PR logic into a tested Node script (open-batch-pr.mjs), and adds a new spec-changes.yml workflow that computes a changed-services manifest on every spec merge and POSTs it HMAC-signed to the SDK automation bot.

  • generate-prs.yml: Converted from push-triggered to workflow_dispatch-only with required batch_id + optional services CSV; per-entry commit/PR creation delegated to open-batch-pr.mjs; sdk-compat commit status published from validate-sdks.yml so the bot reads a clean breaking/non-breaking signal without scraping PR comments.
  • spec-changes.yml: New workflow runs oagen diff + oagen parse on spec merges, builds a per-service manifest via build-spec-changes.mjs (including transitive model/enum attribution), and POSTs it to the SDK bot — nothing is committed back to this repo.
  • Tests: 28 node:test cases with a local bare-repo integration harness for open-batch-pr.mjs and unit coverage for build-spec-changes.mjs including a real captured diff-report.json smoke test.

Confidence Score: 5/5

Safe to merge; the changes are well-scoped workflow orchestration with no irreversible side-effects and a solid test suite covering the critical paths.

The core logic lives in two well-tested Node scripts (28 tests, local bare-repo integration). The workflows use standard GitHub Actions patterns, the HMAC signing is correct, and the fork-PR guard in validate-sdks.yml properly addresses the statuses:write limitation. The only two findings are minor style/hygiene items — direct input interpolation in one run step and a missing --base flag — neither of which affects correctness in the current deployment context.

.github/workflows/generate-prs.yml — the Create batch PR step interpolates inputs.batch_id and inputs.services directly into the shell script, unlike the guarded env-var pattern used in the adjacent Generate SDK step.

Important Files Changed

Filename Overview
.github/workflows/generate-prs.yml Workflow migrated from push-triggered full-fan-out to workflow_dispatch-only with required batch_id and optional services inputs; PR creation logic delegated to open-batch-pr.mjs; direct interpolation of inputs in the batch-PR step is inconsistent with the guarded env-var pattern used in the Generate SDK step.
.github/workflows/spec-changes.yml New workflow that diffs the spec on push-to-main, builds a changed-services manifest, and POSTs it HMAC-signed to the SDK bot; correctly uses -euo pipefail with the
.github/workflows/validate-sdks.yml Adds sdk-compat commit status step with statuses: write permission; fork PR case is correctly gated with github.event.pull_request.head.repo.full_name == github.repository to avoid the 403 from read-only tokens on fork events.
scripts/open-batch-pr.mjs Well-structured extraction of branch/commit/push/PR logic with dry-run gating on all gh mutations; NOOP_ONLY_FILES guard, force-push idempotence, per-entry ordered commits, and create-or-reuse PR all look correct; gh pr create lacks --base but defaults safely to repo's default branch.
scripts/build-spec-changes.mjs Correctly transforms oagen diff report into a sorted, deduped per-service manifest; transitive model/enum attribution via buildSymbolOwners handles shared schemas and removed models; unattributed symbol changes are counted and reported on stderr without failing the build.
scripts/sdk-generate.sh Clean addition of --services forwarding; absent/empty flag correctly skips appending to EXTRA_ARGS, preserving existing full-generation behaviour for callers that don't pass the flag.
scripts/tests/open-batch-pr.spec.mjs Good integration tests using a real local bare-repo origin; covers empty-diff, manifest-only, force-push idempotence, per-entry commit ordering, dry-run output, and scoped-diff confinement.
scripts/tests/build-spec-changes.spec.mjs Comprehensive unit tests covering mount-rule remapping, breaking-flag rollup, shared-model transitive attribution, behavior changes, and a real-fixture smoke test against the captured diff-report.json.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Spec as openapi-spec repo
    participant SCW as spec-changes.yml
    participant Bot as SDK Automation Bot
    participant GPW as generate-prs.yml
    participant OBP as open-batch-pr.mjs
    participant SDK as SDK Repo

    Spec->>SCW: "push to main on spec/**"
    SCW->>SCW: oagen diff + oagen parse
    SCW->>SCW: build-spec-changes.mjs builds manifest
    SCW->>Bot: POST /internal/spec-changes HMAC-signed
    Bot->>Bot: store manifest, compute batch_id
    Bot->>GPW: workflow_dispatch with batch_id and services
    GPW->>GPW: npm run sdk:generate with services scope
    GPW->>OBP: batch-id, lang, services, sdk-dir
    OBP->>SDK: checkout branch oagen/batch-ID
    OBP->>SDK: per-entry commits and force-push
    OBP->>SDK: gh pr create or reuse existing PR
    OBP-->>GPW: pr_number, pr_url, branch
    GPW->>SDK: add changelog fragment if bullets present
    GPW->>Spec: gh api statuses for sdk-compat signal
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"}}}%%
sequenceDiagram
    participant Spec as openapi-spec repo
    participant SCW as spec-changes.yml
    participant Bot as SDK Automation Bot
    participant GPW as generate-prs.yml
    participant OBP as open-batch-pr.mjs
    participant SDK as SDK Repo

    Spec->>SCW: "push to main on spec/**"
    SCW->>SCW: oagen diff + oagen parse
    SCW->>SCW: build-spec-changes.mjs builds manifest
    SCW->>Bot: POST /internal/spec-changes HMAC-signed
    Bot->>Bot: store manifest, compute batch_id
    Bot->>GPW: workflow_dispatch with batch_id and services
    GPW->>GPW: npm run sdk:generate with services scope
    GPW->>OBP: batch-id, lang, services, sdk-dir
    OBP->>SDK: checkout branch oagen/batch-ID
    OBP->>SDK: per-entry commits and force-push
    OBP->>SDK: gh pr create or reuse existing PR
    OBP-->>GPW: pr_number, pr_url, branch
    GPW->>SDK: add changelog fragment if bullets present
    GPW->>Spec: gh api statuses for sdk-compat signal
Loading

Reviews (3): Last reviewed commit: "refactor(spec-changes): push the manifes..." | Re-trigger Greptile

gjtorikian and others added 5 commits June 22, 2026 21:42
Address two Greptile findings on PR #35:

- spec-changes.yml: enable `-e` in the diff/parse step so a failing
  `oagen parse` aborts with a clear error instead of silently writing an
  empty IR file (which surfaced downstream as a cryptic JSON parse error).
  The `oagen diff` line stays exit-code-2 tolerant via its errexit-safe
  `|| DIFF_EXIT=$?` suffix.
- validate-sdks.yml: skip the `sdk-compat` commit-status step for fork
  PRs, whose read-only `github.token` would 403 on the statuses write and
  fail an otherwise-green job.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ommitting it

Don't accumulate .spec-changes/<sha>.json artifacts in this repo. The
spec-changes workflow now POSTs the computed manifest to the SDK bot
(HMAC-signed with SPEC_CHANGES_SECRET), which stores it in D1 and owns
retention. build-spec-changes.mjs already writes to stdout when --output
is omitted, so the script is unchanged; only the workflow rewires.

- spec-changes.yml: run build-spec-changes.mjs → stdout → HMAC-sign →
  curl POST $SDK_BOT_URL/internal/spec-changes (3 retries, skip when no
  services changed). Drops contents:write + the App token (no commit).
- Remove the .spec-changes/ directory + README (no committed artifacts).

Requires a SPEC_CHANGES_SECRET Actions secret (shared with the bot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gjtorikian gjtorikian merged commit 2adaa35 into main Jun 23, 2026
6 checks passed
@gjtorikian gjtorikian deleted the filter-resolved-ir branch June 23, 2026 02:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant