Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .claude/skills/address-feedback/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: address-feedback
description: Fetch a GitHub PR review (Copilot, human, or another agent), verify each finding against the code, fix what is real with regression tests, run the repo gates, and push. Use when the user shares PR review feedback, a pullrequestreview URL, or asks to address review comments.
---

# Address PR review feedback

Turns one review round into one command: fetch → verify → fix → gate → push → report.

## 1. Fetch the feedback

- `.../pull/<n>#pullrequestreview-<id>` URL →
`gh api repos/{owner}/{repo}/pulls/<n>/reviews/<id>` for the body and
`gh api repos/{owner}/{repo}/pulls/<n>/reviews/<id>/comments --paginate` for the
inline comments (always paginate — large reviews span pages).
- Bare PR number → `gh pr view <n> --json reviews,commits` for the review summaries,
plus `gh api repos/{owner}/{repo}/pulls/<n>/comments --paginate` for the inline
comments (`gh pr view` does not return them); keep the ones whose
`pull_request_review_id` belongs to a review submitted since the last push.
- Pasted findings text → use as-is.
- Make sure the PR branch is checked out and current (`gh pr checkout <n>` — never mix
with uncommitted local work; stop and say so if the tree is dirty with unrelated
changes).

## 2. Verify before trusting — triage every finding

Reviews (Copilot especially) contain false positives. For each finding, read the actual
code — whole functions and their callers, not diff hunks — then classify:

- **Agree**: real defect, fix it.
- **Disagree**: false positive or intended behavior. Keep the code evidence; it goes in
the report verbatim.
- **Business decision**: a behavior/product choice (defaults, risk acceptance, who gets
notified, what partners may see). Never guess these — collect them and ask the user,
with a recommendation each (use AskUserQuestion when interactive).

## 3. Fix agreed findings

- Surgical changes only; match surrounding style; no drive-by refactors.
- Per repo rules: every bug that slipped past existing tests gets a regression test that
fails without the fix, in the same commit.
- If the fix changes behavior documented in `docs/security-spec`, sync the owning spec
file in the same change (grep `docs/security-spec/README.md` for the owner).

## 4. Gates before pushing

Trust guard: gates execute branch-local code. Only run them when the PR head lives in
`pendulum-chain/vortex` itself and the author is a known collaborator or team agent;
for fork or external-author PRs, stop after triage and report instead of executing.

Run what the change touches:

- `bun lint:fix` (Biome — except `packages/sdk`, which uses `bun lint` / ESLint inside
the package).
- `bun typecheck`.
- Affected package/app test suites (commands in each subdirectory's CLAUDE.md).
- `bun run build:shared` when `packages/shared` changed, then re-run dependent suites.
- `bun run wire-contract:check` when shared endpoint types or the SDK surface changed;
if the change is intentional, `bun run wire-contract:update` and commit the snapshot
diff with an explicit note on backward compatibility.

## 5. Push and report

- Commit in logical groups using Conventional Commits (`<type>(<scope>): <summary>`).
- Push to the PR branch; watch CI in a background task and fix failures it surfaces.
- Final message: a disposition table — every finding → **Fixed** (commit), **Disagreed**
(evidence), or **Needs your decision** (options + recommendation). Nothing silently
dropped.
- Reply on the PR threads only if the user asks.
52 changes: 52 additions & 0 deletions .claude/skills/babysit-pr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: babysit-pr
description: Watch an open PR and keep it moving without manual ferrying — react to new reviews (Copilot, human, agent) and CI failures, push mechanical fixes, and surface business decisions. Use after opening a PR, e.g. "babysit PR 1234" or "watch this PR until it's mergeable".
---

# Babysit a PR

Long-running watch loop for one PR. Autonomous for mechanical work; it never merges the
PR and never resolves business decisions on its own.

## Setup

- Resolve the PR: argument, or the current branch's PR via `gh pr view`.
- Trust guard: this loop runs branch-local code (gates, fixes). Only babysit PRs whose
head lives in `pendulum-chain/vortex` itself with a known collaborator or team agent
as author; for fork or external-author PRs, watch and report only — never execute
branch code.
- Make sure the PR branch is checked out and the tree is clean; stop and report if there
is unrelated uncommitted work.
- Record a baseline to diff against on every wake-up (persist it in a scratch state
file): head SHA, review ids, issue-comment ids, and CI runs from
`gh pr view <n> --json headRefOid,reviews,comments,statusCheckRollup` (its `comments`
field is issue comments only), plus the inline review-comment ids from
`gh api repos/{owner}/{repo}/pulls/<n>/comments --paginate`.
- If no Copilot review exists yet, request one:
`gh api repos/{owner}/{repo}/pulls/<n>/requested_reviewers -f "reviewers[]=copilot-pull-request-reviewer[bot]"`.
If the API rejects the bot reviewer, note it in the report and continue — the user can
request it in the GitHub UI.

## Each iteration

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:
verify each finding against the code, fix agreed items with regression tests, run
gates, push. Keep the disagree evidence and any business decisions for the report.
4. New human questions or discussion → draft replies but do not post them unless the
user explicitly enabled posting; include the drafts in the report instead.
5. After pushing fixes prompted by a Copilot review, re-request the Copilot review so
the next round starts without the user ferrying anything.
6. Update the state file.

## Pacing, notifying, stopping

- Pace with the harness loop mechanism (dynamic `/loop` / scheduled wake-ups): check
every 5–15 minutes; after pushing, watch CI to completion in a background task and act
on the result instead of waiting for the next tick.
- Actively notify the user (not just a log line) when: a business decision is pending, a
reviewer pushes back on a disagree disposition, or all feedback is addressed and CI is
green (mergeable — the user's call).
- Stop when the PR is merged or closed, or when the user says stop. Never merge.
50 changes: 50 additions & 0 deletions .claude/skills/ship/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
name: ship
description: End-to-end Vortex feature pipeline — plan with decision gates, implement with tests, self-review until dry, open the PR, and hand off to babysit-pr. Use for "ship this feature", "one-shot this", or when starting substantial feature work from a problem statement or handoff document.
---

# Ship a feature

Pipeline with exactly two human gates: plan approval and merge. Everything in between
runs autonomously.

## Phase 0 — Understand and plan (human gate 1)

- Ingest the problem statement, handoff doc, linked PRs/proposals/ADRs.
- Fan out parallel read-only mapping subagents over the affected subsystems (quote
pipeline, phases/blocks, providers, dashboard, SDK — whatever the change touches).
- Draft the implementation plan: approach and alternatives considered, files to touch,
DB/migration impact (including what is already deployed on staging/prod),
`docs/security-spec` impact, wire-contract impact (is a partner-facing change
intended?), and the test plan (which suites, which new tests).
- Collect every open product/behavior decision — defaults, who is notified, what
partners may see, risk acceptances — and ask the user concretely with a
recommendation per question (AskUserQuestion). Never resolve these silently.
- Present the plan and wait for approval before writing any code.

## Phase 1 — Implement

- Work in a fresh worktree branched off the latest `origin/staging`.
- Implement in logical Conventional Commits; ship tests alongside per the repo rules
(features get tests; bug fixes get regression tests that fail without the fix).
- Gates before every push: `bun lint:fix` (ESLint inside `packages/sdk`),
`bun typecheck`, affected test suites, `bun run build:shared` when shared changed,
`bun run wire-contract:check` (update + compatibility note only when the surface
change is intentional), security-spec sync when documented behavior changed.

## Phase 2 — Self-review until dry

- Run `/vortex-review` on the branch.
- Fix the confirmed findings here (this session has implementer context), rerun the
gates, then rerun `/vortex-review`. Repeat until a run reports no new confirmed
findings.
- Findings deliberately not addressed go into the PR description with the reasoning —
never silently dropped.

## Phase 3 — PR and handoff (human gate 2)

- Push and open the PR against `staging`: human-friendly sentence-case title, and a
description covering what/why, the decisions taken in phase 0, test evidence, and the
wire-contract note when the snapshot changed.
- Request a Copilot review and start `/babysit-pr` for the follow-through.
- Merging is always the user's decision.
84 changes: 84 additions & 0 deletions .claude/skills/vortex-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
name: vortex-review
description: Deep multi-lens review of a Vortex PR or branch. Runs parallel Vortex-specific finder lenses, loops until no new findings, adversarially verifies every finding, and reports severity-ranked results. Use when asked for an in-depth code review, a pre-merge confidence check, or to review a PR/branch/diff.
---

# Vortex deep review

Review-only skill: it produces a findings report and NEVER modifies code. Fixes happen in
the implementing session or via `/address-feedback`.

## 1. Resolve scope

- Argument is a PR number/URL → `gh pr view` for title/description/discussion, `gh pr diff`
for the diff. If the branch isn't checked out locally, check it out in a worktree.
- No argument → diff the current branch against `$(git merge-base HEAD origin/staging)`.
- Build a change inventory: files by workspace, plus flags that route lens emphasis:
migrations touched, `packages/shared` touched, SDK public surface touched,
`docs/security-spec` relevant paths touched, frontend machines/widget touched.
- Trust guard: before running ANY branch-local command (installs, builds, tests,
`wire-contract:check`), confirm the PR head lives in `pendulum-chain/vortex` itself
and the author is a known collaborator or team agent. For fork or external-author
PRs, review by inspection only — read the diff and files, execute nothing from the
branch — and say so in the report.
- Run `bun run wire-contract:check` (after `bun run build:shared` if shared changed).
A stale snapshot on the branch = automatic P1 finding.
- Read the PR description and any linked proposal/ADR: findings include "the change
doesn't achieve its stated intent", not just "the code is wrong".

## 2. Round 1 — finder fleet

Spawn parallel read-only subagents, one per lens (use the Workflow tool if available,
otherwise parallel Agent tasks). Every finder gets: the diff, the change inventory, its
lens brief below, and these standing rules:

- Verify every claim against the actual code — read whole functions/files, never judge
from diff hunks alone. Check whether a suspected issue is already guarded elsewhere.
- Report findings as: severity (P0 blocker / P1 must-fix / P2 should-fix / P3 nit),
`file:line`, one-sentence claim, concrete failure scenario (inputs/state → wrong
outcome), suggested fix, suggested regression test.
- Also report what you checked and found clean.

Lens briefs (these encode the classes that historically slipped through review):

| Lens | Hunt for |
|---|---|
| correctness | Logic errors, wrong conditionals, off-by-one, unhandled branches, race conditions, dead code introduced by the change |
| financial-integrity | Fee math and rounding (Big.js modes), raw (18-dp) vs decimal confusion, subsidy caps, net-rate promise, the same amount derived differently at quote vs settlement vs distribution time |
| phase-recovery | Phase handlers/blocks: idempotency under retry and crash-between-steps; preconditions that can never pass after partial success (e.g. balance checks for funds that already moved); presigned-tx identity must include nonce (phase+network+signer alone collides); retries vs lock expiry; `unknown`-status operations conflated with "not started" |
| silent-failures | Swallowed errors, catch-and-continue, fallbacks that mask wrong data, logs asserting success on unverified paths, error branches that can never fire |
| partner-surface | Anything a live integrator depends on: shared endpoint types, SDK public API and `parseAPIError` message matching vs actual backend error strings, webhook payloads/signing, auth semantics, `docs/api/openapi/vortex.openapi.json` sync, wire-contract snapshot diff review |
| db-migrations | Migrations vs the already-deployed staging/prod schema (edits to already-run migrations never re-run; backfills must handle existing rows); irreversible steps without a runbook; enum exhaustiveness (`FiatToken` has 6 values: EURC, ARS, BRL, USD, MXN, COP — check every `Record<FiatToken, X>`; `SubsidyToken`); Sequelize model ↔ schema drift |
| consistency | Corridor/capability matrix agreement across widget (frontend), API, dashboard, SDK (`tokenAvailability`, `mapFiatToDestination`, `ARRIVAL_TEXT_BY_TOKEN`); i18n in both en and pt-BR; `docs/security-spec` staleness per the CLAUDE.md sync rule |
| test-adequacy | Would the new tests fail without the fix; edge cases vs happy path only; `mock.module` leak rules (snapshot values before mocking, restore in `afterAll`); no production data/PII in fixtures; coverage gates still passing |

For small diffs (< ~150 changed lines) merge to 4 finders: correctness+silent-failures,
financial+phase-recovery, partner-surface+db-migrations, consistency+test-adequacy.

## 3. Loop until dry

- Deduplicate new candidates against everything already seen (file + line + claim), not
only against confirmed findings — otherwise refuted findings resurface forever.
- After any round that produces new candidates, run another fleet round where finders get
the list of everything found so far and the brief "hunt for what these reviewers
missed — different files, different failure classes".
- Stop after two consecutive rounds with zero new candidates (typically 2–3 rounds).

## 4. Adversarial verification

Every candidate goes to a verifier subagent prompted to REFUTE it with code evidence: is
the path reachable, is the behavior actually wrong, is it guarded elsewhere, does the
failure scenario hold? P0/P1 candidates get two independent verifiers; the finding
survives only if the refutation fails. Refuted candidates go to a one-line appendix so
the same false positive isn't re-litigated next run.

## 5. Report

Deliver in the final message (and post via `gh pr review --comment` only if asked):

1. One-paragraph verdict: mergeable or not, and the dominant risk.
2. Findings ranked by severity: `file:line`, claim, failure scenario, fix, regression
test to add.
3. "Verified clean" — per lens, what was checked and held up. Absence of findings must
be evidence of checking, not of not looking.
4. Appendix: refuted candidates (one line each).
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ jobs:
- name: ✏️ Typecheck
run: bun run typecheck

- name: 🔒 Wire-contract gate
run: |
cd scripts/wire-contract && bun test && cd ../..
bun run wire-contract:check

test:
name: Running tests
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ storybook-static


CLAUDE.local.md
# Ignore everything under .claude except the team-shared settings.json
# Ignore everything under .claude except the team-shared settings.json and skills
.claude/*
!.claude/settings.json
!.claude/skills/
/.roo/*

# hardhat generated files in workspace contract projects
Expand Down
1 change: 1 addition & 0 deletions docs/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This directory is the repository source of truth for the partner-facing Vortex A
## Structure

- `openapi/vortex.openapi.json` is the OpenAPI reference used for the Apidog endpoint catalog.
- `wire-contract.snapshot.md` is the generated snapshot of the typed partner-facing surface (shared endpoint types + public SDK API). CI fails when it is stale; regenerate with `bun run wire-contract:update` and review the diff for backward compatibility.
- `pages/*.md` contains the pure Markdown guide pages that sit around the endpoint reference.
- `apidog/page-manifest.json` records the intended page order, source files, current Apidog project ID, and endpoint grouping decisions.
- `scripts/*.ts` contains the local export, validation, and type-generation helpers for this docs source.
Expand Down
Loading
Loading