Skip to content

Add wire-contract CI gate and agent review workflow skills - #1326

Merged
ebma merged 7 commits into
stagingfrom
claude/review-workflow-tooling
Aug 10, 2026
Merged

Add wire-contract CI gate and agent review workflow skills#1326
ebma merged 7 commits into
stagingfrom
claude/review-workflow-tooling

Conversation

@ebma

@ebma ebma commented Aug 8, 2026

Copy link
Copy Markdown
Member

Motivation

An analysis of our recent development sessions showed two systematic weaknesses:

  1. Regression safety for live integrators rested on reviews alone. Reviews are probabilistic — each pass (Claude, Codex, Copilot) samples the finding space differently, which is why repeated reviews kept finding new issues. Breaking changes to the partner-facing surface need a deterministic gate, not a hopeful one.
  2. The review loop was manual toil. Every feedback round meant ferrying review URLs between sessions, re-explaining the same review approach, and re-triaging by hand.

This PR adds a deterministic wire-contract gate plus four repo-level agent skills that encode the review/feedback workflow we kept reinventing per session.

Wire-contract gate (deterministic)

  • scripts/wire-contract/generate-report.ts renders the typed partner-facing surface — the shared endpoint request/response types (packages/shared/src/endpoints) and the public SDK API (packages/sdk/src/index.ts) — into docs/api/wire-contract.snapshot.md (checked in, ~5.8k lines).
  • Types declared in-repo are expanded structurally (enums with values, unions sorted, Record<FiatToken, …> resolved), so a change to a transitively referenced type surfaces in the snapshot even when no endpoint file was edited. External types (viem, polkadot, lib) are kept by name.
  • bun run wire-contract:check fails when the snapshot is stale; bun run wire-contract:update regenerates it. CI runs the check in the build job, so every partner-facing change becomes an explicit, reviewable diff in the PR that made it.
  • Tests cover exact fixture output (enums/optionals/cycles/tuples/Record), determinism across program instances, and a no-filesystem-path-leak guard. Sorting is code-unit based so macOS and Linux produce identical snapshots.

Note: the SDK entry resolves @vortexfi/shared through its built declarations — run bun run build:shared before regenerating when shared changed (CI's build job already does).

Agent skills (.claude/skills/)

  • /vortex-review — multi-lens deep review: parallel finder agents with Vortex-specific lenses (financial integrity, phase-recovery/idempotency, presigned-tx identity, silent failures, partner surface, migrations vs deployed schema, corridor-matrix consistency, test adequacy), looped until two consecutive rounds find nothing new, every finding adversarially verified before it is reported. Review-only; never edits code.
  • /address-feedback <review-url> — one feedback round in one command: fetch the review via gh, verify each finding against the code, fix agreed items with regression tests, run the repo gates, push, and report a full disposition table. Business decisions are surfaced, never guessed.
  • /babysit-pr <PR#> — watches an open PR: reacts to new reviews and CI failures, pushes mechanical fixes, re-requests Copilot review after addressing a round, and notifies on business decisions or mergeability. Never merges.
  • /ship — the pipeline: plan (with explicit decision questions, human gate 1) → implement with tests → /vortex-review until dry → PR + Copilot review + /babysit-pr. Merge remains human gate 2.

.gitignore gets a !.claude/skills/ exception so the skills are version-controlled and available in worktree sessions once this lands on staging.

Verification

  • cd scripts/wire-contract && bun test — 3 pass.
  • bun run wire-contract:check — snapshot up to date.
  • bun run verify — clean.

ebma added 3 commits August 8, 2026 10:21
Reviews are probabilistic; live integrator breakage should be caught
deterministically. The gate renders the shared endpoint types and the
public SDK API into a structurally expanded snapshot, so any change to
what partners consume - including transitive type/enum drift - fails CI
until the snapshot is regenerated and the diff is reviewed on purpose.
vortex-review encodes the multi-lens finder fleet with loop-until-dry
and adversarial verification; address-feedback turns one PR review
round into a single verify-fix-gate-push command.
ship chains plan approval, implementation with tests, vortex-review
until dry, and PR creation; babysit-pr watches an open PR and reacts
to new reviews and CI failures so feedback rounds need no ferrying.
@ebma
ebma requested a balanced review from Copilot August 8, 2026 08:26

Copilot AI left a comment

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.

Pull request overview

Adds a CI-enforced partner API snapshot generator and reusable agent workflows for reviewing and shipping changes.

Changes:

  • Generates and verifies shared/SDK wire-contract snapshots.
  • Adds serializer fixtures and CI coverage.
  • Adds four PR review and delivery skills.

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
.gitignore Tracks shared Claude skills.
.github/workflows/ci.yml Runs wire-contract tests and checks.
.claude/skills/address-feedback/SKILL.md Defines feedback handling.
.claude/skills/babysit-pr/SKILL.md Defines PR monitoring.
.claude/skills/ship/SKILL.md Defines end-to-end delivery.
.claude/skills/vortex-review/SKILL.md Defines deep review workflow.
docs/api/README.md Documents the snapshot.
docs/api/wire-contract.snapshot.md Captures the generated public contract.
package.json Adds snapshot commands.
scripts/wire-contract/generate-report.ts Implements contract serialization.
scripts/wire-contract/generate-report.test.ts Tests serializer output.
scripts/wire-contract/fixtures/fixture-surface.ts Provides serializer fixtures.
scripts/wire-contract/fixtures/tsconfig.json Configures fixture compilation.
Suppressed comments (1)

.claude/skills/address-feedback/SKILL.md:17

  • gh pr view --json reviews,commits returns review summaries but not their inline review comments, so the bare-PR flow silently drops inline findings. Fetch the paginated review-comments endpoint too and retain comments whose pull_request_review_id belongs to reviews submitted since the last push.
- Bare PR number → fetch all reviews and review comments submitted since the last push
  (`gh pr view <n> --json reviews,commits`).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/wire-contract/generate-report.ts Outdated
Comment thread .claude/skills/address-feedback/SKILL.md Outdated
Comment thread .claude/skills/babysit-pr/SKILL.md Outdated
Comment thread scripts/wire-contract/generate-report.ts Outdated
Comment thread scripts/wire-contract/generate-report.ts Outdated
@netlify

netlify Bot commented Aug 8, 2026

Copy link
Copy Markdown

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit 7adc12d
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6a79848dc4d35600081cdc64
😎 Deploy Preview https://deploy-preview-1326--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 8, 2026

Copy link
Copy Markdown

Deploy Preview for vrtx-dashboard canceled.

Name Link
🔨 Latest commit 7adc12d
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6a79848df5452d0008146fed

@netlify

netlify Bot commented Aug 8, 2026

Copy link
Copy Markdown

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 7adc12d
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6a79848d2f60db0008ec214c
😎 Deploy Preview https://deploy-preview-1326--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

ebma added 2 commits August 10, 2026 09:39
Copilot review on #1326 found three blind spots: generic conditional
aliases rendered as self-references, signature type parameters and
their constraints were dropped, and readonly was erased. All three
let partner-facing drift pass the gate; the serializer now expands
conditional bodies, emits type-parameter constraints and defaults,
and preserves readonly, with fixture coverage for each.
Inline review comments are not returned by gh pr view and live on a
paginated endpoint; the address-feedback and babysit-pr instructions
now fetch them explicitly so findings cannot be silently dropped.
@ebma
ebma requested a balanced review from Copilot August 10, 2026 07:45

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated no new comments.

Suppressed comments (6)

scripts/wire-contract/generate-report.ts:136

  • Readonly index signatures are serialized identically to writable ones because info.isReadonly is ignored. The current endpoint surface already contains direct index signatures, so changing one to readonly [key: string] would leave the snapshot unchanged and bypass the gate. Preserve the modifier and add a readonly-index fixture assertion.
    lines.push(`[key: ${keyType}]: ${valueType};`);

scripts/wire-contract/generate-report.ts:235

  • Tuple mutability is lost here: [string, number] and readonly [string, number] have the same type arguments and therefore produce the same snapshot, despite being different public contracts. Include the tuple target's readonly metadata in the rendering and cover this in the tuple fixture.
  if (checker.isTupleType(type)) {
    const elements = checker.getTypeArguments(type as ts.TypeReference).map(element => serializeType(ctx, element, depth + 1));
    return `[${elements.join(", ")}]`;

scripts/wire-contract/generate-report.ts:159

  • Dropping every undefined constituent also erases explicitly declared undefined. With exactOptionalPropertyTypes disabled in both target configs, field?: string and field?: string | undefined serialize identically, although consumers enabling that option observe different contracts. Distinguish compiler-added optionality from an explicit union using the declaration node, and add a regression fixture.
    const optional = (property.flags & ts.SymbolFlags.Optional) !== 0;
    const isReadonly = modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ReadonlyKeyword);
    const propertyType = serializeType(ctx, typeOfSymbol(ctx, property), depth + 1, { dropUndefined: optional });
    lines.push(`${isReadonly ? "readonly " : ""}${property.name}${optional ? "?" : ""}: ${propertyType};`);

.claude/skills/vortex-review/SKILL.md:19

  • This executes code from the checked-out PR branch (package.json and the generator are both PR-controlled) under the reviewer's local credentials. An untrusted PR can therefore run arbitrary code even though this skill is described as review-only. Require an explicit trusted-head check, or run branch-controlled commands only in a credential-free sandbox; otherwise inspect untrusted PRs without execution.
- Run `bun run wire-contract:check` (after `bun run build:shared` if shared changed).

.claude/skills/address-feedback/SKILL.md:49

  • After checking out an arbitrary PR, these gates execute branch-controlled scripts and tests with the agent's local credentials. A malicious fork can exfiltrate GitHub or provider credentials before any feedback is addressed. Add a trusted-head/author gate or require a credential-free sandbox before running commands from the PR; untrusted feedback can still be inspected without execution.
## 4. Gates before pushing

Run what the change touches:

- `bun lint:fix` (Biome — except `packages/sdk`, which uses `bun lint` / ESLint inside

.claude/skills/babysit-pr/SKILL.md:31

  • The CI-failure path runs repository gates on whichever PR branch was checked out, without establishing that the branch is trusted. For an external PR this lets branch-controlled scripts execute repeatedly under the babysitter's credentials. Apply the same trusted-head or credential-free sandbox requirement before any local gate execution.
1. Fetch current PR state and diff against the baseline.
2. New CI failure on the current head → read the failing logs
   (`gh run view <run-id> --log-failed`), fix, run the repo gates, push.
3. New review or new inline review comments → run the `/address-feedback` flow on them:

ebma added 2 commits August 10, 2026 09:57
Second Copilot round on #1326: readonly index signatures and readonly
tuples serialized identically to their mutable forms, so mutability
changes to those constructs would pass the gate unseen.
Review, feedback, and babysit skills execute branch-local commands;
on a public repo with forks that would let an untrusted PR run code
under local credentials. Fork or external-author PRs are now
inspect-only in all three skills.
@ebma
ebma merged commit a732fec into staging Aug 10, 2026
6 checks passed
@ebma
ebma deleted the claude/review-workflow-tooling branch August 10, 2026 08:13
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.

2 participants