feat(contract): @forgegraph/contract — Effect HttpApi → operation IR compiler #564

Merged
gmackie merged 1 commit from feat/contract-package into main 2026-09-12 02:08:40 +00:00
Owner

What

New workspace package packages/contract (@forgegraph/contract 0.1.0): compile an Effect HttpApi into ForgeGraph's operation contract IR with no hand-authored endpoint, schema, error or auth catalogs.

Phase 1, tasks 1.1–1.7 of the plan: https://7n04n7hhuesf.postplan.dev

Surface

entry needs effect contents
@forgegraph/contract / ./ir no Zod IR schema, validateContract, fingerprints
./sla no leaf-merged SLA resolver with provenance
./effect peer ≥ 4.0.0-rc.112 compileHttpApi, Sla / IsPublic / Authentication annotations, forgeGraph({...}) helper

Design points

  • Identity is semantic: <serviceId>.<group>.<endpoint>; matches the group.endpoint span name the create-gmacko-app template already emits. A route move does not change identity (tested).
  • Only public Effect APIs: HttpApi.reflect (identity, middleware, statuses, merged annotations) and OpenApi.fromApi (JSON Schema + components). No AST walking.
  • SLA merges per leaf across global → service → api → group → endpoint → environment; every leaf records the level that set it; invalid values fail the build.
  • Private by default; Authentication is derived from the security middleware (cookie/basic → user, bearer/header key → service, both → mixed, none → anonymous). An explicit annotation overrides and sets mismatch: true for ForgeGraph to flag.
  • Fingerprints are sha256 over canonical JSON; a schema fingerprint covers the transitive closure of referenced components, so it changes exactly when the client-visible shape changes.
  • The hub stays Effect-free: it will validate ingested contracts with the ./ir Zod schema (Phase 2).

Verification

  • 37 unit tests (pnpm -F @forgegraph/contract test), typecheck and tsc -p tsconfig.build.json clean, oxlint clean of errors.
  • Lockfile change is additive only (new importer + effect rc.112 and its deps).

Not in this PR

Ingest endpoint, tables, UI tab (Phase 2) and the template-side annotations + contract.json generation (tasks 1.8–1.10, separate PR in create-gmacko-app).

🤖 Generated with Claude Code

## What New workspace package `packages/contract` (`@forgegraph/contract` 0.1.0): compile an Effect `HttpApi` into ForgeGraph's operation contract IR with no hand-authored endpoint, schema, error or auth catalogs. Phase 1, tasks 1.1–1.7 of the plan: https://7n04n7hhuesf.postplan.dev ## Surface | entry | needs `effect` | contents | |---|---|---| | `@forgegraph/contract` / `./ir` | no | Zod IR schema, `validateContract`, fingerprints | | `./sla` | no | leaf-merged SLA resolver with provenance | | `./effect` | peer ≥ 4.0.0-rc.112 | `compileHttpApi`, `Sla` / `IsPublic` / `Authentication` annotations, `forgeGraph({...})` helper | ## Design points - **Identity is semantic**: `<serviceId>.<group>.<endpoint>`; matches the `group.endpoint` span name the create-gmacko-app template already emits. A route move does not change identity (tested). - **Only public Effect APIs**: `HttpApi.reflect` (identity, middleware, statuses, merged annotations) and `OpenApi.fromApi` (JSON Schema + components). No AST walking. - **SLA** merges per leaf across global → service → api → group → endpoint → environment; every leaf records the level that set it; invalid values fail the build. - **Private by default**; `Authentication` is derived from the security middleware (cookie/basic → user, bearer/header key → service, both → mixed, none → anonymous). An explicit annotation overrides and sets `mismatch: true` for ForgeGraph to flag. - **Fingerprints** are sha256 over canonical JSON; a schema fingerprint covers the transitive closure of referenced components, so it changes exactly when the client-visible shape changes. - The hub stays Effect-free: it will validate ingested contracts with the `./ir` Zod schema (Phase 2). ## Verification - 37 unit tests (`pnpm -F @forgegraph/contract test`), typecheck and `tsc -p tsconfig.build.json` clean, oxlint clean of errors. - Lockfile change is additive only (new importer + `effect` rc.112 and its deps). ## Not in this PR Ingest endpoint, tables, UI tab (Phase 2) and the template-side annotations + `contract.json` generation (tasks 1.8–1.10, separate PR in create-gmacko-app). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(contract): add @forgegraph/contract, the Effect HttpApi → operation IR compiler
Some checks failed
CI / gitleaks (pull_request) Successful in 17s
CI / storybook (pull_request) Successful in 1m51s
CI / ci (pull_request) Has been cancelled
b916218360
New workspace package that turns an Effect `HttpApi` into ForgeGraph's operation
contract IR without any hand-authored endpoint, schema, error or auth catalog.

- `./effect`: `compileHttpApi(api, { serviceId, globalSla?, serviceSla?, environmentSla? })`
  built on `HttpApi.reflect` for identity, middleware, success/error statuses and
  merged annotations, and on `OpenApi.fromApi` for JSON Schema. No private Effect
  internals are read.
- Annotation vocabulary as `Context.Reference`s with defaults: `Sla` ({}),
  `IsPublic` (false), `Authentication` (derived from security middleware unless
  overridden; an override sets `mismatch: true`).
- `./sla`: leaf-merged resolution global → service → api → group → endpoint →
  environment with per-leaf provenance and value validation.
- `./ir`: Effect-free Zod schema + `validateContract` (shape, unique ids,
  id/parts agreement, per-operation and contract fingerprints, dangling $refs)
  so the ForgeGraph server can validate ingested contracts without Effect.
- Stable semantic ids `<serviceId>.<group>.<endpoint>` match the `group.endpoint`
  span names the create-gmacko-app template already emits.

`effect` is an optional peer (≥ 4.0.0-rc.112, pinned to the template catalog).
37 unit tests. Plan: https://7n04n7hhuesf.postplan.dev (Phase 1, tasks 1.1–1.7).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gmackie force-pushed feat/contract-package from b916218360
Some checks failed
CI / gitleaks (pull_request) Successful in 17s
CI / storybook (pull_request) Successful in 1m51s
CI / ci (pull_request) Has been cancelled
to 47a91edcff
Some checks failed
CI / gitleaks (pull_request) Successful in 6s
CI / ci (pull_request) Failing after 8s
CI / storybook (pull_request) Successful in 1m37s
2026-09-09 22:36:47 +00:00
Compare
Author
Owner

Preview environment is live: https://pr-564-forgegraph.forgegraf.com

Deployed b9162183 with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.

Preview environment is live: https://pr-564-forgegraph.forgegraf.com Deployed `b9162183` with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.
gmackie force-pushed feat/contract-package from 47a91edcff
Some checks failed
CI / gitleaks (pull_request) Successful in 6s
CI / ci (pull_request) Failing after 8s
CI / storybook (pull_request) Successful in 1m37s
to c2f1c4ef6e
All checks were successful
CI / gitleaks (pull_request) Successful in 8s
CI / storybook (pull_request) Successful in 1m16s
forgegraph/ci CI passed
CI / ci (pull_request) Successful in 10m35s
2026-09-09 22:47:52 +00:00
Compare
Author
Owner

Preview environment is live: https://pr-564-forgegraph.forgegraf.com

Deployed c2f1c4ef with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.

Preview environment is live: https://pr-564-forgegraph.forgegraf.com Deployed `c2f1c4ef` with the beta stage's environment. It redeploys on every push and is destroyed when this PR closes.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gmackie/ForgeGraph!564
No description provided.