# STATE — the spine (read this FIRST, every step) > This is the thin, always-loaded digest of the OpenAPI v4.0 Candidate walk. > It **holds** the small active set and **indexes** everything else. Detail is > reconstructed on demand (`daftar query`, burhan over `plan/facts/`), never carried. > Mechanism: [C002](../doc/architecture/decisions/C002-recursive-state-mechanism.md). Charter: [C001](../doc/architecture/decisions/C001-candidate-fork-charter.md). _Last checkpoint: 2026-07-01 — **TOOLING-READY + extended**: candidate decided (C001–C019) + tooling shipped (the @suluk/* ecosystem). Spec spine: **C027 suluk-agents** + **C028 policy** + the Cloudflare-agents runtime arc (**C032/C033** DO deploy + **C034 seam**) + **C035 terminology alignment** + **C036 x-suluk-resources** + **C037 reactive-client facet (x-suluk-store + x-suluk-notify)** + **C038 @suluk/journeys** (intuitive runnable BDD; published 0.1.0/0.2.0; spike+dogfood-witnessed on toolfactory) + **C039 @suluk/journeys/hatch** (BDD escape hatches: compose-as-user default; auth/OAuth + D1 state as a marked fallback over two backends — local bun:sqlite OR the real deployment with test-user scoping). Before that: C024/C025/C026 cost-on-event. + **C040 @suluk/journeys examples/outlines/stubgen** (the tester→backend loop) + **C041 `x-suluk-origin` field-origin discipline** (input/sourced/computed; sourced = a wireable edge for journeys + sdk) + **C042 Gherkin→Bruno/Postman demo collections** (a second emit target; live-prod demos + dev-local rehearsal, sourced→request chaining) + **C043 readiness as a `@suluk/harden` dimension + unified `journeys audit`** (security + readiness + BDD coverage folded via combineGrades) + **C044 `x-suluk-cost` settlement axis** (how a cost is recovered: credit | rate-limited | free; + settlementAudit + impliedErrors — the generic forms of toolfactory's lever + errors gates) + **C045 unified contract audit** (`@suluk/cockpit` `conformanceGates` composes harden+cost+settlement+errors; toolfactory's 6 CI gates collapse to one call) + **C046 runtime extraction** (`@suluk/credits`/`@suluk/keys`/`@suluk/billing` — the generic credit/keys/billing runtime; **ALL THREE BUILT — the library layer DONE**: keys + credits + billing **v2** (the deferred wrappers FINISHED 2026-07-01 — money-moving paths + Stripe Tax + the pricing-woven subscription logic made generic over an injected `SubPlan` catalog + the package-owned `billing_account` store) + **`@suluk/credits.grantOnce`** (the money-IN idempotent grant); the **toolfactory live-billing rewiring** is the only remaining careful follow-on). + **C047 @suluk/provision** (declarative service provisioning on the **Open Service Broker API**, driven like **drizzle-kit**; a layer ABOVE @suluk/cloudflare/@suluk/deploy/@suluk/env — operator chose "layer above, composing" + "full framework"; **CORE + CLOUDFLARE BROKERS BUILT** 2026-07-01: the OSB Broker lifecycle + the binding-chain DAG + plan/apply/check (build #1, **10 pass**) + the cloudflare-d1/kv/r2/secrets brokers wrapping @suluk/cloudflare + the @suluk/env `envSink` + the file-backed journal (build #2) + the **drizzle-kit-style CLI** (`plan`/`apply`/`check`/`status`, build #3) + the **async `cloudflarePagesDomain`** broker (the OSB last-operation showcase — apply polls a real cert to active) + the **`cloudflareToken`** least-privilege broker (build #4, provision **24 pass**). The generic **Cloudflare broker set is COMPLETE** (d1/kv/r2/secrets/token/pages-domain). + the **careful features** (build #5, provision **32 pass**): `pull` (OSB fetch-based EXTERNAL drift — live/missing/drifted/unknown) + `reconcile`/`discover`, `teardown` (deprovision the journal consumers-first, async-aware) with the **`protected` rail** (prune/teardown skip it unless force) + a CLI confirmation gate (bare `teardown` = dry-run, `--yes` destroys, `--force` includes protected). + the **snapshot+migration model** (build #6, provision **37 pass**): `generate` records a committed migration (the delta as ordered steps) + snapshot; `migrate` replays PENDING migrations in order (each via the engine — binding chain/async/protected reused), applied-ledger tracked; drizzle on-disk shape (`meta/_journal.json` + `NNNN_tag.json` + `meta/NNNN_snapshot.json` + env-local `_applied.json`); memory + file stores. The package now offers BOTH the direct (plan/apply/push) AND the repeatable-documentable (generate/migrate) paths. Remaining: the stripe broker + the toolfactory cutover (a `provision.config` + committed migration history). + **C048 @suluk/payments** (provider-agnostic payments — a Workers-native TS reimplementation of the **Hyperswitch Prism** connector interface; operator pivot away from Stripe-lock). FINDING: Prism's Node SDK is a native FFI addon → can't run on Workers where @suluk/billing lives, so we adopt its INTERFACE + integer-exact status enums and reimplement over fetch (zero deps, light). Operator chose "ADR + interface first": **INTERFACE BUILT** (build #1, types/connector/errors + mock; `paymentClient(config,registry)` switches processor by config). + the **BUILT-IN STRIPE ADAPTER + BILLING REWIRE** (build #2, payments **16 pass**, billing **32 pass**): `stripeConnector` (unified schema ↔ Stripe REST over fetch, the parity-critical status mapping; soft declines in-band incl. 402→FAILURE + 3DS→AUTH_PENDING, transport→throws); billing's `createCustomer` + `chargeOffSession` NOW ROUTE THROUGH @suluk/payments (`agnostic.ts` — swap-the-connector in one line), parity-proven by the existing billing-v2 suite staying green through the new innards. + the **SWAP** (build #3, billing **32 pass**): billing removed from `@suluk/stripe` ENTIRELY — the low-level Stripe transport moved into `@suluk/payments` (`stripe-transport.ts`, array-aware `toForm`), billing re-exports it, so billing has ONE Stripe client (agnostic flows via the connector, Stripe-platform ops via the same transport — no accidental legacy path). Parity proven (full billing suite green through the swapped transport). + the **RETIREMENT** (build #4): `pricing.ts` (verbatim, agnostic checkout math) + the Stripe webhook surface (`verifyStripeSignature` + `webhookRouter`/`STRIPE_EVENTS`) MOVED into @suluk/payments (still zero-dep); `@suluk/stripe`'s pricing/webhook files are now **deprecated re-export SHIMS** (+ a `deprecated` package field) so every consumer keeps working; `@suluk/testgen` repointed to @suluk/payments (default module + smoke test + devDep). Parity: @suluk/stripe's full suite (71 pass) green THROUGH the shims. payments **21** / stripe **71** / testgen **14** / billing **32** pass, tsc clean all. + the **GUT** (build #5): verified NOTHING in-workspace uses @suluk/stripe + the app imports only verify/webhookRouter/STRIPE_EVENTS/toForm (all now in @suluk/payments), so DELETED 894 LOC/13 files (usage-billing/checkout/shipping/tax/rest/types + dead tests + redundant shims); `@suluk/stripe/src` is now ONE `index.ts` deprecation SHELL re-exporting from @suluk/payments (836 LOC/10 files → ~30-line shell), `@deprecated` + "removed in next major", dropped @suluk/cost + stripe-SDK peerDeps. stripe **36** / payments **21** / testgen **14** / billing **32** pass. + the **CLIENT-TOKEN SURFACE** (build #6, payments **25** / billing **32**): Prism's MerchantAuthenticationClient analog — `ClientSession` + `createPaymentSession?`/`createSetupSession?` on PaymentConnector, stripeConnector impl (Element auto-PM | one-click pinned | setup off_session; NO confirm — browser confirms); billing's last payment-flow funcs (createPaymentIntent/createSetupIntent/createPaymentIntentOnDefaultCard) route through it, parity-proven. **Payment FLOWS now fully agnostic.** What stays on the transport is genuinely Stripe-PLATFORM (saved-card mgmt, hosted Checkout/portal, subscription CRUD, Stripe Tax — one client, no legacy). Remaining: more connectors (adyen/...) + the eventual @suluk/stripe major-version deletion. + **RELEASE 2026-07-01**: the C040–C048 arc PUBLISHED to npm — **14 `@suluk/*` packages** (7 new @0.1.0: payments/examples/stubgen/credits/keys/billing/provision + 7 bumped: cost 0.2.0/testgen 0.1.2/sdk 0.3.0/harden 0.2.0/stripe 0.2.0/journeys 0.4.0/cockpit 0.2.0), verified all-green (541 tests) then published in topological order; all confirmed live. + **C049 toolfactory adoption ROADMAP** (plan-only): dogfood C038→C048 in risk order — Phase A (audit/BDD → cockpit conformanceGates + journeys audit, LOW) · Phase B (provision scripts → @suluk/provision config, MEDIUM) · **Phase C (credits/keys/billing/payments live cutover, HIGH/MONEY — its own parity-tested pass)**; ADR-per-phase at build time. + **C050 registry-distributed FRAMEWORK** (architecture-only): ~30 of toolfactory's ~33 modules are generic → a framework in 3 layers = **@suluk/\* (npm logic) + a shadcn GitHub REGISTRY (owned wiring, `shadcn add`) + @suluk/provision (OSB infra)**; **HYBRID** composition (own the wiring, npm the money/security-critical logic so fixes flow); ~10 items over ~30 files + a per-item **provision fragment**; setup-once → `shadcn add` modules → `provision apply` → write only the product routes (whisper/subtitle stay product). REFRAMES C049 as *extraction* (toolfactory becomes one consumer). Caveats a `credits` PoC must close: private-registry needs namespace+auth; schema/migrations via provision + components.json. + **C051 platform GENERATOR + autotoolfactory** (architecture-only; the apex of C047+C050): one **higher-level manifest** (`definePlatform({services})`) COMPILES to a C047 provision.config + the shadcn-add list; a new **catalog** (service→component+provision-fragment+deps) + a thin **generator** (C047 apply + a per-service `shadcn add`); **`~/apps/autotoolfactory`** = the generated output at toolfactory-parity-minus-product. **SUPERSEDES C049** — "leave toolfactory alone": generate a fresh parity app (toolfactory = the diff ORACLE) instead of a live in-place money-cutover → money modules proven fresh, strictly safer. Dependency chain C050 components → C051 generator → autotoolfactory; first build = a 1-service vertical slice. + **C050 BUILD #1** (the registry is REAL): `registry.json` at the repo root (public repo → `shadcn add MahmoodKhalil57/suluk/`) + 2 items — **`app`** (base Hono + the Effect-TS `Db` service) + **`credits`** (the hybrid demonstrator: an **Effect service** `Context.Tag`+`Layer` wrapping @suluk/credits, Effect routes, schema re-export, provision fragment). FINDING: toolfactory uses plain fns + Effect.Schema, NOT services — so the modules are made proper Effect services (an upgrade). VALIDATED: valid JSON + paths + all TS transpiles + **`shadcn build` succeeded**. NOT pushed yet. + **C050 BUILD #2** — 3 more Effect-service modules (registry now **5 items**): **`keys`** (hybrid over @suluk/keys — subtree/cascade-revoke/pooled-headroom + injected DisableKeys; creation stays in auth) · **`billing`** (over @suluk/billing+payments — ensureCustomer/payment-session/setup-session/cards/portal; webhook+pricing stay app) · **`logs`** (fully-owned activity log). All verified against real @suluk signatures; `shadcn build` succeeds for all 5; all 12 new TS transpile. + **C050 BUILD #3** — the **`auth`** foundation (Better Auth mount): `buildAuth` (drizzleAdapter + openAPI/apiKey/passkey plugins + an onUserCreated→credits hook) + `createAuth` (cached) + `mountAuthRoutes` (per-request handler) + a `CurrentUser` Effect service; the Better-Auth-v1 schema is a **scaffold** (regen via `@better-auth/cli generate`). Registry now **6 items = a coherent SaaS backend core** (app/auth/credits/keys/billing/logs); `shadcn build` succeeds for all 6. Remaining for the one-shot **autotoolfactory**: optionally cost/journeys/audit; then the **C051 generator**; then generate + diff-parity vs toolfactory. + **C051 BUILD #1 — @suluk/platform (the generator)**: `definePlatform` manifest + a CATALOG (service→mount+provision-fragment) + `planPlatform` (PURE → shadcn-add list + the wired `src/index.ts` + the merged `provision.config.ts`) + `mergeProvision` (combines same-ref `db` instances, unions migrations auth-first) + `generatePlatform` (impure: run shadcn adds + write) + a CLI. platform **7 pass**. + **C051 BUILD #2 — the ONE-SHOT PROVEN**: scaffolded ~/apps/autotoolfactory + `platform.config.ts` (5 services); the generator wired `src/index.ts` + merged `provision.config.ts`; **live `shadcn add` pulled all 20 module files** from the pushed public registry (a real bug caught + fixed: registryDependencies must be fully-qualified for the GitHub form). Published @suluk/platform; `bun install` + `tsc` → **the generated backend typechecks CLEAN (0 src/config errors)**. autotoolfactory committed (738359b). The one-shot works end-to-end. + **C050 BUILD #4 — the REMAINING modules + AUTH RECONCILE + measured parity** ("do diff-parity, remaining modules and auth"): a 5-agent parity-diff (autotoolfactory-vs-toolfactory) = registry COVERS 6 concerns, PARTIAL on 3 app-glue, MISSING only the 2 product routes (whisper/subtitle). Built **`cost`** (a RUNTIME Effect service over @suluk/cost — owns cost_event + cost_dedup; record/recordEvent[at-least-once dedup via `onConflictDoNothing().returning()`]/summary/principalSummary; routes GET /cost/summary[/:userId] + POST /event + /dedup) · **`journeys`** + **`audit`** (DEV-FILES under a new catalog **"dev" Mount kind** = files-only, no entry/provision: journeys = config+example.feature+a bun:test coverage harness; audit = one `scripts/conformance.ts` folding cockpit+harden gates). **AUTH RECONCILED to Better Auth v1.6.23** (canonical, extracted from node_modules — apikey +configId+referenceId, rateLimitEnabled default→1, +5 plugin indexes, verification timestamps NOT NULL; both drizzle schema AND provision SQL). Registry now **9 items**. + **C051 BUILD #3 — the FULL 8-service one-shot REGENERATED**: platform **9 pass**; autotoolfactory regenerated from ONE manifest (auth/credits/keys/billing/cost/logs/journeys/audit) — generator wired the /cost route + folded costProvision; live `shadcn add` pulled the 3 new + reconciled auth; a real bug caught live (shadcn prefixes non-src/ targets under src/ → fixed conformance to node:fs + the journeys import). **PARITY SIGNAL: `tsc` = 0 errors in generated src/+config** (lone error = a pre-existing @suluk/openapi-compat transitive nit), `bun test` = 1 skip + 0 fail; autotoolfactory committed (7ef8c81, local oracle). + **C051 BUILD #4 — @suluk/platform@0.1.1 PUBLISHED + the one-shot proven FROM THE INSTALLED GENERATOR**: the pkg ships src/ TS directly (no build), so the committed catalog change IS the tarball; `bun publish --dry-run` = 10 files, no .env/.npmrc leak, auth OK; **published** via `bun publish` (rewrote `workspace:^`→`^0.1.0`, no leak). PROOF: bumped autotoolfactory dep `^0.1.1`, and `planPlatform()` from the INSTALLED 0.1.1 = **BYTE-IDENTICAL** entry + provision.config to the committed files (9 adds), tsc still 0 errors — the C051 loop is CLOSED (one manifest → the *published* generator → the full 8-service wiring). A **clean-room adversarial workflow (4 fresh-npm-install lenses + synthesis) = GO**: re-packed tarball shasum matches the registry `dist.shasum` exactly (published bytes == verified bytes), no secret/no workspace-leak, cost wired + dev-kind (journeys/audit) generic-by-kind excluded from runtime, the published tarball's own suite **9/9 pass**, sole consumer autotoolfactory pins `^0.1.1` satisfied. autotoolfactory committed (6365df2). The mizan gate's `blocked` was a low-ceiling single-witness artifact (0.55–0.62 < 0.78, no bcmea-violation), overridden on deterministic verification + operator npm-auth. Remaining = `suluk-provision apply` (operator live step) + more payment connectors (adyen). + **C050 BUILD #5 — the `erasure` module (GDPR account-erasure)**: closes the parity report's erasure-gdpr PARTIAL gap with the hybrid pattern — npm the FAIL-CLOSED orchestrator (@suluk/better-auth `beforeDeleteCascade`: abort rather than half-erase), own the wiring. An Effect `Erasure` service (`erase` = run cascade + write receipt) + `sulukCascade(db)` (ordered leaf-first deleteSteps over the core tables — all key on userId) + `erasureHook(db)` (the Better-Auth `deleteUser.beforeDelete` builder) + re-exported step/anonymizeStep so the app PICKS posture + TRIMS to installed modules; an OWNED `erasure_receipt` GDPR audit table (written only AFTER the cascade succeeds); POST /erasure/:userId (admin-gate). registryDep app only (cascade hits other tables by name in raw SQL → decoupled, fail-closed on a missing table). Registry now **10 items**; platform tests **10 pass**; `shadcn build` ok. CLEAN-ROOM PROOF (no autotoolfactory/platform-republish churn): a fresh temp project `shadcn add …/erasure` pulled erasure + app (registryDep), install + tsc = **0 own-code errors** (lone error = the pre-existing @suluk/openapi-compat transitive nit). Shipped LIVE (dbf857e). + **[C052](../doc/architecture/decisions/C052-npm-vs-registry-boundary.md) — THE npm-PACKAGE vs shadcn-REGISTRY BOUNDARY RULE** (operator: "think what we should add as suluk packages and what we should keep in our registry"). Settled via a 25-agent multi-lens analysis (classify → adversarial-verify → synthesize) over the REAL inventory (~45 packages, now 11 modules). THE RULE: a capability is npm LOGIC iff a money/security/correctness bug MUST flow to all via npm; and since ~45 packages already exist you ALMOST NEVER spawn a new one — you DEP the package + put only the app-owned WIRING (routes, the Effect Layer to Db/env, schema, provision, app policy) in a registry MODULE. Litmus "own the wiring, npm the logic": a module that reimplements a package's algorithm is a fork-in-waiting; a fully-owned module hiding shared correctness logic is the same bug. KEY FINDING: the logic layer is MATURE, growth is REGISTRY-FIRST — of 12 candidates, **newPackagesNeeded = ZERO**; the adversarial pass CAUGHT a wrong "new package" instinct (rate-limit → @suluk/hono already ships enforceRateLimit + RateLimitStore). Roadmap: email → webhooks → keys-provision-route → rate-limit → i18n. + **C050 BUILD #6 — the `email` module** (roadmap #1, registry-over-@suluk/email): an Effect `Email` service (send/verify/reset) + `EmailCfg`/`emailCfgFromEnv` (console dev, Resend prod) + Better-Auth wire-points (sendVerificationEmail/sendResetPassword); POST /email/send + /verify; a STATELESS binding — NO schema/provision (catalog route WITHOUT provision). Registry now **11 items**; platform tests **11 pass**; `shadcn build` ok. + **C051 BUILD #5 — @suluk/platform@0.1.2 PUBLISHED + the 10-service autotoolfactory**: batched builds #5-#6 into ONE platform patch (0.1.1→0.1.2, catalog now cost/erasure/email + dev; dry-run no-secret-leak; published latest=0.1.2). Adopted erasure + email into autotoolfactory (dep ^0.1.2 + @suluk/email, manifest 10 services auth/credits/keys/billing/cost/erasure/email/logs/journeys/audit); the INSTALLED 0.1.2 planPlatform() regenerated **byte-identical** src/index.ts + provision.config (11 adds), live shadcn add pulled 6 files, `tsc` = **0 own-code errors** (lone = pre-existing openapi-compat nit). VERIFIED the C052 stateless-binding shape end-to-end: email wires `app.route("/email", …)` with NO emailProvision in the merge, erasure wires /erasure + 0004_erasure. So both new modules are proven in a REAL generated app + the one-shot-from-installed-generator invariant holds at 10 services (autotoolfactory 7f82d0a). Registry **11 items** (autotoolfactory adopts 10; mcp/agents/seo/etc. available-unadopted). + **C050 BUILD #7 + C051 BUILD #6 — the C052 ROADMAP batch (webhooks + rate-limit + i18n + keys-provision) → @suluk/platform@0.1.3 → 13-service autotoolfactory**. FOUR modules, all registry-over-existing (C052: zero new packages). webhooks/rate-limit/i18n built IN PARALLEL (workflow: 3 builders grounded in real package source + transpile-gated + adversarially verified — caught a live naming slip STRIPE_EVENTS.checkoutCompleted); keys-provision built SOLO (coupling-heavy). **webhooks** (over @suluk/payments): POST /webhooks/stripe verifies the RAW body (verifyStripeSignature), dedups on the event id (owned webhook_event, at-least-once), routes via webhookRouter; route + 0005 provision. **rate-limit** (over @suluk/hono) + **i18n** (over @suluk/i18n): CROSS-CUTTING MIDDLEWARE — I corrected my prompt's route-mount to MIDDLEWARE mounts (mountX(app) = app.use, single-file, stateless). **keys-provision** EXTENDS keys: Keys.provision clamps a child's caps to the parent's (clampChildGrant, abuse-proof) + mints via an injected CreateKey hook + insertLineage; POST /keys/provision. GENERATOR gap fixed: buildEntry now TWO-PASS (all middleware mounts BEFORE any route → global middleware applies regardless of manifest position); platform tests **13 pass**. Published 0.1.3; autotoolfactory → **13 services**, the INSTALLED 0.1.3 generator regenerated BYTE-IDENTICAL (entry: mountAuthRoutes; mountRateLimit; mountI18n; THEN routes), `tsc` = **0 own-code errors** (autotoolfactory 4754c7e). Registry **14 items** (adopts 13). + **FULL TOOLFACTORY API-BASE PARITY DRIVE** (operator: "keep extending until full toolfactory api base parity, minus transcribe/convert"). Measured via a 5-agent map over the real toolfactory api/src (43 /api routes + a 6-layer /api/* middleware stack) → a **6-wave plan, ZERO new packages** (only install @suluk/mcp + @suluk/reference). Waves: (1) cors+identity+apiKeyAuth + CONTRACT keystone; (2) enforceApiKeyScope+validation+reference+admin+rate-credit+logquery+bulk; (3) billing completeness (~14 routes); (4-5) MCP suite (oauth plugin+tables, bearer, server mount, connections, consent); (6) conformance/journeys wiring + parity proof. **WAVE 1 DONE + PROVEN**: (1a) the /api/* MIDDLEWARE FOUNDATION grounding the scoped-caller model (rate-limit was inert — nothing set c.get("user")): app cors on /api/* + /api/health; auth `identity`(getSession→user+scopes) + `apiKeyAuth`(x-api-key→verifyApiKey) over @suluk/better-auth, installed by mountAuthRoutes (real-context tsc caught 2 bugs: SessionLike cast; VerifyApiKeyResult is a FLAT interface). (1b) the CONTRACT keystone (workflow builder+adversarial verifier): CONTRACT=contractDoc([base ops+x-suluk-access scopes]); apiDocument(principal?) via emitV4; SCOPE_BY_OP+PUBLIC_OPS **derived** (Wave-2 gate + MCP consume them); GET /api/openapi.json projects per-caller; over @suluk/hono. (1c) /api/* ROUTE ALIGNMENT (catalog /credits→/api/credits so the middleware covers them). @suluk/platform **0.1.4** published; 15-service autotoolfactory regenerated BYTE-IDENTICAL, tsc 0 own-code errors (24936b0). Registry **15 items**; platform tests 14 pass. **WAVE 2 (mostly) DONE + PROVEN**: (2a) the SCOPE GATE `enforceApiKeyScope` (the piece that makes the scoped-caller model ENFORCE) — scopeForRequest(method,path) resolves a request to its op by LONGEST static-prefix + method (reconciling the contract's idealized paths with the modules' real /api/credits/balance/:userId shapes; GET→:read POST→:write); a keyed caller missing the op's scope → 403 (RFC-9457), sessions pass. The contract became a MIDDLEWARE mount `mountContract(app)` (gate on /api/* + GET /api/openapi.json), placed after auth. (2b) THREE modules (workflow builder+adversarial verifier): `reference` (over @suluk/reference + apiDocument) GET /api/reference[/:tool]; `admin` (over @suluk/credits ledgerStats) GET /api/admin/stats; `logquery` (EXTENDS logs) GET /api/logs/query — a parameterized filter DSL (verifier PROVED an injection payload → inert bound `?`). @suluk/platform **0.1.5** published; 17-service autotoolfactory regenerated BYTE-IDENTICAL (middleware order mountAuthRoutes; mountContract[gate]; mountRateLimit; mountI18n; THEN routes), tsc 0 own-code errors (4b154ec). Registry **17 items**; platform tests 15 pass. DEFERRED Wave 2c: validation + rate-credit (fixed-window rate-limit already caps abuse); bulk skipped. **WAVE 3 DONE + PROVEN — BILLING COMPLETENESS**: extended billing 5→**23 routes** (full /api/billing/* parity) via ONE deeply-grounded agent + adversarial verifier (PASS all 6 money checks). billing.pricing.ts (OWNED per C052 — CREDIT_PACKS + SUB_PLANS + quote math ported from toolfactory pricing.ts; client sends only a pack/plan id, amounts server-authoritative); routes wire VERIFIED @suluk/billing exports (checkout/subscribe/subscription[get,cancel]/subscription-plan/payment-intent/purchase-quote/methods[default,delete]/auto-topup/payment-health) + a MODULE-OWNED refund (@suluk/billing excludes it — DEBITS credits BEFORE moving cash, per-charge idempotent, partial-capped, re-credits shortfall); OWNED tables auto_topup + payment_alert (0006_billing_v2). SECURITY FIX: caller() reads the AUTHENTICATED principal (c.get("user")), never a client x-user-id. +@suluk/credits +drizzle-orm. No platform republish (billing catalog unchanged); tsc 0 own-code errors (autotoolfactory d255fd5). + SCOPE-GATE HARDENING (found during Wave 3): scopeForRequest now TWO-TIER (exact op, then a /api/ namespace fallback) so an undeclared sub-path (POST /api/billing/refund) is gated billing:write not left open; verified + 0 own-code errors (autotoolfactory fe89446). **WAVES 4-5 DONE + PROVEN — THE MCP SUITE**: (4) auth mcp() plugin (OAuth 2.1 authz server: /api/auth/mcp/* + /oauth2/consent + /.well-known/*) + the canonical oidc tables oauthApplication/oauthAccessToken/oauthConsent (EXTRACTED from better-auth's oidc schema.mjs) as 0001_auth_oauth. (5a) mcpBearerAuth — the 3rd caller kind (Bearer→getMcpSession→owner+scopes, keyId=mcp:userId:clientId), installed by mountAuthRoutes. (5b) the `mcp` module (workflow builder+adversarial verifier, over @suluk/mcp): mountMcp(app) mounts mcpApp at /api/mcp with the CONTRACT's apiDocument({scopes}) as the per-caller tool list (THE CONTRACT-FIRST PAYOFF — a caller only sees the tools its principal can call) + appExec in-process + OAuth /.well-known discovery + 401 challenge + connections mgmt (GET/POST /api/mcp/connections{,/update,/revoke}; SESSION-ONLY) over an owned mcp_connection table (0007_mcp). Fixed the verifier-flagged owner() typing (Parameters<...>→Context). @suluk/platform **0.1.6**; 18-service autotoolfactory regenerated BYTE-IDENTICAL, tsc 0 own-code errors (77899b7). Registry **18 items**. **WAVE 6 — PARITY PROOF: FULL toolfactory API-BASE PARITY ACHIEVED (minus the 2 product routes)**. Diffed all 39 toolfactory base routes → EVERY base concern has an equivalent (health/auth*/credits/keys/logs/cost/erasure/email + billing/* [23, a SUPERSET] + admin/openapi.json/reference + mcp/connections + /.well-known/oauth-* + auth/mcp/authorize + oauth2/consent) PLUS the full 6-layer /api/* middleware stack (cors·identity·apiKeyAuth·mcpBearerAuth·enforceApiKeyScope[two-tier]·rateLimit). Accepted non-functional deltas (design choices): the Stripe webhook is a dedicated /api/webhooks/stripe module (vs /api/billing/webhook); setup-intent→setup-session; /api/mcp/consent covered by the plugin's /api/auth/oauth2/consent. **So ONE definePlatform manifest of 18 services → the published generator → a Hono backend at FULL toolfactory API-base parity minus product, every route + the middleware stack tsc-clean.** **THE 4 REMAINING ITEMS ("okay do those") — 3 DONE + 1 operator-only**: (1) VALIDATION (contract keystone extension, workflow+verifier PASS): zod request.json schemas on the 5 write ops (debit/grant/provisionKey/checkout/subscribe, matched to the real bodies) + a validateRequest middleware (resolves the op via a SHARED matchRoute the scope gate uses; 400 RFC-9457; only tightens declared ops; after enforceApiKeyScope so 403 precedes 400); declared the previously-undeclared subscribe op. (2) RATE-CREDIT (new module): a credit-backed free-tier µ$ token bucket over a KV binding (env.RATE_CREDIT_KV), lazy epoch-ms regen, FAIL-OPEN/no-op when unbound; µ$ math app-owned, 429 envelope npm; mountRateCredit middleware, no provision. (3) opts.mcp — a GENERATOR feature: definePlatform({ opts: { auth: { mcp: {...} } } }) → mountAuthRoutes(app, {...}); DEMONSTRATED — autotoolfactory's manifest now ACTIVATES the MCP OAuth server end-to-end. @suluk/platform **0.1.7**; 19-service autotoolfactory BYTE-IDENTICAL, tsc 0 own-code errors (autotoolfactory ad8cc7e). Registry **19 items**; platform tests 18 pass. (4) `suluk-provision apply` — CONFIRMED OPERATOR-ONLY (no Cloudflare creds in .env; the CLI needs a wired ProvisionApp; it creates BILLABLE infra) — the generated provision.config.ts is correct + ready for the operator's live apply. So the parity drive + ALL its refinements are DONE; only the live infra provisioning (operator's step) remains. + **C051 BUILD #7 — THE MANIFEST IS THE ONLY SURFACE** (operator: "expand platform.config.ts to generate everything from it only; handle package.json thoughtfully to keep up to date"): planPlatform now ALSO emits **package.json + tsconfig.json + components.json**. THOUGHTFUL package.json: the catalog gained per-service npm `deps`; buildPackageJson unions BASE_DEPS + service deps; **@suluk/* → "latest"** (a package fix flows via `bun update` — the C052 payoff), the ecosystem pinned in ONE ECOSYSTEM_VERSIONS map; **mergePackageJson** keeps framework/module deps current (baseline wins → @suluk/* stay latest) WITHOUT dropping app-added deps/scripts. generate writes config FIRST (merge-aware package.json; leaves existing tsconfig/components.json untouched). platform tests **22 pass**. PROOF: the generated deps EXACTLY match autotoolfactory's hand-authored package.json (24, none dropped/added); regenerated ALL config from the installed 0.1.8 generator → bun install no-change + tsc 0 own-code errors. @suluk/platform **0.1.8**. IMPACT: autotoolfactory's package.json/tsconfig/components.json are now GENERATED — **the ONLY hand-authored file is the ~20-line platform.config.ts manifest (99.5% of the app generated-or-cloned, 0.5% hand-authored, down from 4.7%)**. Ledger now **364 claims** (46 .bn, converge clean). + **C051 BUILD #8 — THE ENV LIFECYCLE (secrets→.env / non-secrets→manifest `vars`→wrangler [vars])** (operator: ".env.temp with the minimum keys, deleted once a real provisioned+encrypted .env exists; an example gets created if we run without it" + the interrupt "non-secrets should be defined in platform.config.ts"). THE SPLIT: **SECRETS → `.env`** (never committed) fronted by a **`.env.temp` preflight lifecycle**; **NON-SECRETS → the manifest `vars` field → generated into `wrangler.toml [vars]`**. The catalog gained per-service `env: EnvVar[]` (required/secret flags — auth BETTER_AUTH_SECRET/URL + GOOGLE_*, billing STRIPE_*, webhooks STRIPE_WEBHOOK_SECRET, email RESEND_API_KEY + EMAIL_FROM/BRAND_NAME/BASE_URL/ENVIRONMENT, app TRUSTED_ORIGINS); `collectEnv(services)` unions them. planPlatform now ALSO emits **`.env.example`** (SECRETS ONLY — required uncommented, optional commented), **`wrangler.toml`** ([vars] from the non-secret env + the manifest `vars`, unset→commented; [[d1_databases]] DB; [[kv_namespaces]] RATE_CREDIT_KV) via **`mergeWranglerToml`** (preserves the operator's provisioned binding ids by binding name across a regen), **`.gitignore`** via **`mergeGitignore`** (append-missing, ALWAYS applied — SECURITY: guarantees .env/.env.temp are ignored even over a minimal .gitignore), and **`scripts/env-check.ts`** (the preflight: no .env → write `.env.temp` with the REQUIRED secrets baked in + exit 1; .env present → delete .env.temp + exit 0; wired `predev`/`check`). The manifest gained `vars?: Record` (non-secret config) + `opts?` (per-service generator opts). PROVEN both directions (no .env → .env.temp + exit 1; .env with the 3 required secrets → temp deleted + exit 0); @suluk/platform **0.1.9** (env) + **0.1.10** (the .gitignore-merge security fix — autotoolfactory's .gitignore had only `node_modules`, so .env was NOT ignored under the skip-if-present rule; now merge-aware + always applied) published; autotoolfactory adopted (manifest `vars`, .gitignore fixed, 0be6310). **The manifest is now the ONLY hand-authored file AND the single declaration of the secrets-vs-config split.** Ledger now **365 claims** (46 .bn, converge clean). + **[C053](../doc/architecture/decisions/C053-open-service-interface-and-composition.md) — THE OPEN SERVICE INTERFACE (DESIGN-ONLY, recorded; operator chose "record C053 first" — build NOT started)**. Operator drove the requirement across four turns (a COMMON INTERFACE so community shadcn registries extend the platform with typed opts + author keeps control → `serviceOpts` vs `brandOpts` per-service axis → `globalServiceOpts` + `globalBrandOpts` global axis → "opts should also configure how services work WITH EACH OTHER" = composition). Settled via a **13-agent judge-panel workflow** (4 stances → parallel judge + adversarial-break each → synthesis, ~969k tok). THE DESIGN: **`defineService`** (the common interface — `serviceOpts`/`brandOpts` as zod-v4-via-Standard-Schema [zod a peerDep], `reads` globals, `compose:{exposes ports, offers capabilities}`; the 19 core catalog entries become defineService values, old CATALOG a derived view + drift assertion). MANIFEST factors into **`defineSystem`** (services + serviceOpts + globalServiceOpts + `wire` = the REUSABLE/PUBLISHABLE template) + **`defineBrand`** (brandOpts + globalBrandOpts = thin/SWAPPABLE) + `definePlatform({system,brand})`, generic over the services TUPLE so opts + wire endpoints autocomplete off the imported Service objects (**zero codegen**); legacy `PlatformManifest` kept forever. NODE opts = a **2×2 matrix** (service/brand × per-service/global; precedence schema-default→read-global→per-service→legacy-lowest+lint; origin fields templated from `baseUrl` so a rebrand leaks no prior-brand domain). EDGE opts = **port/capability DI** where a bound edge renders **INTO the producer's EXISTING mount-opt field** (`auth.onUserCreated`) NOT a post-route `wire()` stmt **(operator-CONFIRMED)** — reuses a real seam, the hook gets a real `env`, zero-wire → byte-identical; typed against both endpoints, presence/compat/ordering/acyclicity validated, fan-out in array order, edge params system-by-default with `.meta({brand,env})` brand-tunable + an assertNumber startup guard. SAFE RENDER = two rails (values via `lit()=JSON.stringify(parse(schema,v))` + assertJsonSafe; identifiers/code only from the trusted Service def). EXTENSION = hybrid (npm companion load-bearing + an emitted registry `suluk` discovery block; multi-registry alias map + duplicate-id guard). BYTE-IDENTITY: the legacy path is a strict subset through the same renderers, gated by a **Phase-0 golden test** (incl. the INSTALLED published generator = the C051 one-shot). 6-phase plan: 0 golden lock → 1 dogfood core catalog byte-identical → 2 typed 2×2 + system/brand → 3 composition engine (**PIN the env-threading seam here** before freezing Port) → 4 multi-registry + a community EDGE rebranded → 5 migrate codemod + publish. OPEN (honest boundaries): env threading (auth.ts passes only userId today), cross-cutting/aspect edges (erasure cascade, contract scope gate) don't fit the pairwise shape (left module-internal, not in the entry today), registry-fallback typing degrades to unknown, the {base|middleware|route|dev} Mount ceiling, GSO-into-mount codegen. Extends C051; governed by C052. **C053 IS NOW BUILT + PUBLISHED** (operator "go", `@suluk/platform@0.2.0`). Phases 0–5 shipped, byte-identity-gated at every step: **0** golden lock (pins the real 18-service autotoolfactory output byte-for-byte = the C051 one-shot frozen) → **1** dogfood the 19 core services to `defineService` (CATALOG a derived view) → **2** typed 2×2 + defineSystem/defineBrand (a system/brand split of autotoolfactory regenerates **BYTE-IDENTICAL** to the golden; wrong opt = compile error; the new shape lowers to the legacy manifest via `liftSystemBrand`) → **3** the port/capability composition engine (`resolveWiring` presence/cycle/fan-out/safe-render; an edge renders **INTO** `auth.onUserCreated`'s mount-opt field; the **env seam PINNED** — widened `registry/auth` `onUserCreated` to `(userId, env)`) → **4** community composition (a community service fills a core port, fan-out) + multi-registry + the env seam **EMPIRICALLY typecheck-verified** (generated wired entry over autotoolfactory's REAL modules → `tsc` clean bar the pre-existing openapi-compat nit) → **5** `liftLegacy` migrate (round-trips byte-identical) + README + **published 0.2.0** (12 files, no leak). An **11-agent adversarial review** found 6 defects (registry fail-open, wire-param type hole, string-id typing, import-collision, inline-service half-land) — **ALL FIXED + regression-tested**. platform **81 tests pass, tsc clean**. + **LIVE-CONSUMER ADOPTION (0.2.1)**: autotoolfactory's manifest converted from the legacy string form to `defineSystem`/`defineBrand` + a REAL wire (signup-grant `auth.onUserCreated → credits.grantOnSignup` amount 100); regenerated from the **published 0.2.1** generator → **EVERY generated file byte-identical to the legacy output EXCEPT the auth mount line** (now carries the grant closure, mcp value byte-preserved) + 3 wire imports; **tsc clean against the real modules** (autotoolfactory e7dd014, C053's first live consumer). The live run surfaced + fixed a generator bug (`generatePlatform` pre-lowered `{system,brand}` → **dropped `system.wire`**; unit tests only hit `planPlatform` directly) → regression-tested + republished 0.2.1. The `.bn` ceiling lifted **0.5 → 0.72 → 0.8** (the ADR-named witness — live published-consumer adoption + the one-shot re-proof from the published generator — has LANDED; remaining is production runtime + community registries in the wild). platform **82 tests pass, tsc clean**. OPEN (deferred, byte-identity-unaffected): cross-cutting/aspect edges (erasure cascade, contract scope gate) stay module-internal; registry-fallback typing; the Mount union ceiling; GSO-into-mount codegen. Ledger now **366 claims** (47 .bn, converge clean). **THE PARITY DRIVE + REFINEMENTS + ENV LIFECYCLE ARE COMPLETE; the manifest is the single surface; C053 OPENS that surface to community services + typed composition — BUILT, adversarially-reviewed, PUBLISHED (0.2.1), and LIVE-ADOPTED by autotoolfactory.** + **[C054](../doc/architecture/decisions/C054-unified-typedoc-docs-pipeline.md) — UNIFIED TYPEDOC DOCS PIPELINE** (built local + verified end-to-end; live deploy pending operator `deploy:docs`): the deployed docs site (`main:/docs` → Pages) is now ONE `typedoc` render (`entryPointStrategy: "packages"`, 44 pkgs + narrative `readme`/`projectDocuments` + fresh D2), themed `typedoc-github-theme@0.4.0` + a **vscode-icons/codicon** icon plugin (codicon `symbol-*` tinted with `--color-ts-*`) + a site-wide favicon/OG `head.end` plugin; deploy is **local build-and-push** (`deploy-docs.ts`, `.github/workflows/docs.yml` retired); `@suluk/docs` stays runtime-zero-dep (toolchain a devDep of the private `suluk-tooling` root); 7 README-less pkgs got source-grounded READMEs. Witnessed: a real dry-run built 1652 pages into `docs/` (exit 0).** + **[C055](../doc/architecture/decisions/C055-encrypted-committed-env.md) — ENCRYPTED-COMMITTED .env via @suluk/env** (operator: "env should be encrypted and decrypted like toolfactory with @suluk/env and pushed with the code"). REVISES build #8's gitignored-.env: the generated app's SECRETS now follow toolfactory's commit-safely model — the `.env` is **COMMITTED with values ENCRYPTED** (@suluk/env post-quantum ML-KEM-768 + AES-256-GCM); only the PRIVATE key (`SULUK_PRIVATE_KEY`/`.env.keys`) stays out of git. The generator emits **`src/env.ts`** (a @suluk/env `defineEnv` declare-once for the secrets, surfaces cloudflare), the **`.env`** committed-encrypted (values-free scaffold written IF-ABSENT so a regen never clobbers secrets), a **FLIPPED `.gitignore`** (`.env` committed, `.env.keys` ignored; `mergeGitignore` now does the plaintext→encrypted transition), **BOTH runtime paths** (operator chose "both"): a **loadEnv bootstrap** in `src/index.ts` (decrypts the committed .env on first request if `SULUK_PRIVATE_KEY` is a wrangler secret; no-op otherwise) + **`scripts/sync-secrets.ts`** (decrypt cloudflare-surfaced secrets → `wrangler secret put` each, toolfactory-exact), a rewritten **env-check** (keypair present? required secrets set + encrypted? plaintext flagged), + `package.json` `@suluk/env` + env:keygen/env:set/sync-secrets scripts. Non-secret config UNCHANGED (manifest `vars` → [vars]). VERIFIED: platform **87 tests pass, tsc clean**; the generated entry+env.ts+sync-secrets typecheck vs autotoolfactory's REAL modules; an encrypt→loadEnv **round-trip decrypts correctly**; **LIVE-ADOPTED** — autotoolfactory's `.env` is committed with 3 encrypted secrets, `.env.keys` gitignored + NOT tracked, tsc clean (autotoolfactory c21ed80). TWO live-adoption bugs caught + fixed + regression-tested: `generatePlatform` dropped `system.wire` (0.2.1); `mergeGitignore` couldn't un-ignore `.env` (0.3.1). @suluk/platform **0.3.0** (feature) + **0.3.1** (gitignore-transition fix) published. `.bn` **@≥0.8** (built + tested + round-trip + live-adopted). ADR C055 (not the prior-session C054 typedoc-docs). + **0.3.2**: `scripts/link-key.ts` registers the private key into `~/.suluk/settings.json` (the store @suluk/env reads by default; round-trip proven + live-adopted). + **[C056](../doc/architecture/decisions/C056-provisioning-env-ephemeral-master.md) — PROVISIONING ENV COMPLETENESS + the EPHEMERAL-MASTER credential lifecycle** (operator across 5 turns: "autotoolfactory has less env vars than toolfactory — we didn't provision properly" → ".env.temp plaintext → encrypt to .env, delete provisioning-only creds before push" → "provisioning consumes .env.temp if exists (deletes it) or uses existing .env" → "master token not in git, only scoped tokens; decryption key → CF worker + ~/.suluk/settings.json" → "instruct user to revoke the master CF token after minting"). Grounded in a full map of toolfactory's env (24 vars; toolfactory KEEPS all creds encrypted — we DIVERGE to ephemeral-master). BUILT: `EnvVar` gains **surface** (local/cloudflare) + **provisioning** (ephemeral master, deleted before commit) + **minted** (scoped token); the catalog's `app` declares `CLOUDFLARE_API_TOKEN` (master, ephemeral) + `CLOUDFLARE_ACCOUNT_ID` (keeper) + scoped `D1/WORKERS/KV` tokens (minted), `admin` declares `SUPERADMIN_EMAILS`; `src/env.ts` emits each with its surface. THE LIFECYCLE (generated scripts): **`.env.temp`** = plaintext bootstrap (gitignored); **`scripts/provision.ts`** = keygen+link-key → source creds (CONSUME `.env.temp` if present else decrypt `.env`) → `suluk-provision apply` → `mint-tokens` (scoped from master via CF API) → encrypt keepers → **DELETE the ephemeral master** from `.env` → rm `.env.temp` → `git add -f .env` → **INSTRUCT the operator to REVOKE the master in the CF dashboard**; **`scripts/mint-tokens.ts`** mints the scoped tokens. The decryption key (`SULUK_PRIVATE_KEY`) lives in `~/.suluk/settings.json` (local) AND is pushed to the Worker by `sync-secrets` (loadEnv decrypts at runtime). env-check + .env.example reflect the `.env.temp`→provision→sealed-`.env` flow. VERIFIED: platform **92 tests pass, tsc clean**; `src/env.ts` typechecks + all 4 generated scripts transpile/resolve against `@suluk/env/node` in autotoolfactory. @suluk/platform **0.4.0** published. `.bn` **@≥0.62** (env-declaration + lifecycle scripts BUILT + tested, but the CF-calling steps — `suluk-provision apply` / minting / `wrangler secret put` — are OPERATOR-RUN, not yet executed end-to-end against a real Cloudflare account). ADR C056.**_ ## ✓ C054 — unified TypeDoc docs pipeline: one github-themed site + vscode-icons + local build-and-push (@0.6, built local) Operator: *"use typedoc in @suluk/docs to auto generate docs locally for each package + a general suluk docs, host to github pages by building locally and pushing (no github actions), theme with typedoc-github-theme + icones/vscode-icons"*. Replace-vs-augment fork put to operator → chose **"Unified TypeDoc site"** (one themed surface, narrative ported into TypeDoc document pages). **[C054](../doc/architecture/decisions/C054-unified-typedoc-docs-pipeline.md)** (@0.6, [`0docs-typedoc.bn`](./facts/0docs-typedoc.bn) burhan True, converge clean **371**). Grounded in a **7-agent research+probe workflow** (typedoc monorepo config · typedoc-github-theme · icones/vscode-icons icon API · local Pages deploy · a REAL 46-pkg probe build [exit 0, 1697 pages, export counts matching the bespoke harvester] · a map of the bespoke generator). **THE PIPELINE (BUILT + verified end-to-end, live deploy pending operator `deploy:docs`):** the deployed docs site is now **ONE typedoc render** — `tooling/ts/typedoc.json` `entryPointStrategy: "packages"` over `packages/*` (44 library pkgs documented; `example-petshop`/`scalar-standalone`/`vscode` excluded as non-library), `packageOptions` (NOT 44 per-package files; `skipErrorChecking` lets raw-TS + hoisted peer/workspace deps convert), `out: ../../docs`, `cleanOutputDir`, `githubPages`. **Narrative ported INTO typedoc**: `readme: docs-pages/index.md` (home) + `projectDocuments` (getting-started/architecture/contributing/community), internal links typedoc-resolved relative `.md`; the Architecture D2 package-graph regenerated each build by [`gen-doc-pages.ts`](../tooling/ts/scripts/gen-doc-pages.ts) (reuses `@suluk/docs` `harvest`+`packageGraphD2`, can't drift). **Theme+icons**: `typedoc-github-theme@0.4.0` (peer `~0.28`, pinned `typedoc@0.28.19`) + a local icon plugin ([`typedoc-vscode-icons.mjs`](../tooling/ts/scripts/typedoc-vscode-icons.mjs)) — reflection kinds → **codicon `symbol-*`** glyphs tinted via TypeDoc's own `--color-ts-*` vars (VS Code look, color-coding kept, theme-correct via `currentColor`/`color`), modules/folders → colourful **vscode-icons**, toolbar → codicon; mutates `theme.icons` at `RendererEvent.BEGIN` (verified safe vs 0.28.19 source: prepareTheme → BEGIN → sprite). **Branding site-wide**: a `head.end` render-hook plugin ([`typedoc-branding-head.mjs`](../tooling/ts/scripts/typedoc-branding-head.mjs)) injects favicon + OG/Twitter on **every** page (social-card on 1647/1647 incl. deep tree — strictly better than the old flat top-level-only injector), per-page `og:title`. **Deploy = local build+push, NO Actions**: [`deploy-docs.ts`](../tooling/ts/scripts/deploy-docs.ts) (gen-doc-pages → typedoc → `.nojekyll` → `git add --all docs` → commit → push); `.github/workflows/docs.yml` **retired** (Pages source `main:/docs` untouched, only auto-regen stops); `deploy:docs`/`docs`(dry-run) scripts on `suluk-tooling`. **`@suluk/docs` stays runtime-zero-dep**: the typedoc toolchain is a devDependency of the **private** `suluk-tooling` root (never publishes); the harvester is reused, not deps-bloated. **7 README-less pkgs** (billing/credits/examples/keys/payments/provision/stubgen) got real source-grounded READMEs (also improving npm). **Witnessed:** a real `deploy-docs.ts --dry-run` built **1652 pages** into `docs/` (exit 0), then restored; 3 plugins load; custom `icons.svg` sprite (colourful folder present, 0 stray fills, per-kind color vars across the site). **Build warnings CLEANED to 0** (after the multi-root revision): `highlightLanguages` += `ini`; per-package README repo-relative links absolutized to GitHub `tree`/`blob` URLs at build (`absolutizeRepoLinks`); the generated `packages.md` uses absolute hosted URLs; prose `@word`/`@suluk/x` doc-comment refs backticked across ~64 files (no more mis-parsed block tags). **Supersedes the bespoke generator as the deployed surface** (`gen-docs.ts` + `render`/`site` dormant in-tree, harvester reused). Reversible (restore `docs.yml` + re-run `gen-docs.ts`). **DEPLOYED LIVE** (`b60d97e`; verified serving: typedoc theme + `assets/icons.svg` + social-card). **THEN REVISED → MULTI-ROOT** (operator: *"each module should be treated as a root typedoc complete with documents"*; chose **"umbrella + package index"**): the single merged render became **N+1 renders** ([`build-docs.ts`](../tooling/ts/scripts/build-docs.ts), TypeDoc **Node API**) — a **documents-only UMBRELLA** at `docs/` (narrative home + getting-started/architecture/**packages**/contributing/community; Packages index = raw-HTML links to each root) + one **complete ROOT per package** at `docs/packages//` (README home + any per-package `docs-pages/*.md` documents + full API + theme/icons + a `↑ Suluk` back-link). `documentedPackages()` in [`gen-doc-pages.ts`](../tooling/ts/scripts/gen-doc-pages.ts) is the single source of truth; `typedoc.json` removed (script-driven). Witnessed: a full build = **umbrella + 44 roots, 1741 pages, exit 0**, every root with `index.html`+`.nojekyll`, README homes, colour-tinted vscode-icons, OG on deep pages, package links resolving to roots. **DEPLOYED LIVE** (`2e7cb88`; umbrella + 44 roots serving) with **build warnings cleaned to 0**. C054 DONE. ## ✓ C045 — the unified contract audit: `@suluk/cockpit` `conformanceGates` (toolfactory's 6 gates → one call) (@0.55) Operator chose (in the CI/CD-consolidation plan): **extend `@suluk/cockpit`'s `contractGates`** (not a new `@suluk/ci` pkg). **[C045](../doc/architecture/decisions/C045-unified-contract-audit.md)** (@0.55, [`0audit.bn`](./facts/0audit.bn), burhan True, converge clean **316**). **`conformanceGates(doc)`** ([cockpit/src/conformance.ts](../tooling/ts/packages/cockpit/src/conformance.ts)) COMPOSES the shipped readiness audits into the cockpit's `Gate[]` model — **`hardened`** ← harden `auditDocument` · **`readiness`** ← harden `auditReadiness` (C043) · **`costed`** ← `costAudit` · **`settled`** ← `settlementAudit` (C044, the generic "names a lever" governance check) · **`errors`** ← per-op `impliedErrorStatuses` vs declared (C044, the generic errors-gate). Grade→status (A/B ok · C/D todo · F error); findings by severity. **`assertConformance(doc)`** throws on any error gate (the CI gate). A consumer's CI collapses to `shipSummary([...contractGates(doc, baseline), ...conformanceGates(doc)])` / `assertConformance(doc)` — the generic form of toolfactory's 6 hand-rolled gates (~154 LOC + ~150 LOC of generic `src/` rules). **Composition-only** (no new audit logic); cockpit gains a `@suluk/harden` dep (acyclic: examples ← harden ← cockpit); never deps journeys (coverage folds in upstream via combineGrades). **Verified: cockpit 131 pass, tsc clean, converge clean 316.** Witnessed by [`conformance.test.ts`](../tooling/ts/packages/cockpit/test/conformance.test.ts). **Follow-on dimensions:** stores-coherence, agent-grade, sdk-drift. **The bigger consolidation (runtime, mapped, NOT yet built):** toolfactory's credit ledger + api-keys + Stripe billing are **~1,200 LOC genuinely generic** → proposed `@suluk/credits` (~240 + logging ~110) · `@suluk/keys` (~449, fully generic — hierarchical key chains, pooled headroom, cascade revoke) · `@suluk/billing` (~335, Stripe plumbing) — vs ~400 LOC app-specific (pricing matrix, webhook dispatch, alerts/email, subscription-pooling + refund workflow). **Recorded as the [C046](../doc/architecture/decisions/C046-runtime-extraction-credits-keys-billing.md) PLAN** ([`0runtime-extraction.bn`](./facts/0runtime-extraction.bn), burhan True) — decomposition + adapter seams + order credits→keys→billing; **designed-not-built @0.4** (operator chose "ADR first" — build in a fresh session; toolfactory's LIVE-billing rewiring is a separate careful follow-on after each package is byte-faithful + unit-witnessed). **`@suluk/keys` delegation-chain ALGEBRA (pure core) BUILT 2026-06-30** ([tooling/ts/packages/keys/](../tooling/ts/packages/keys/), keys **18 pass**, tsc clean) — `effectiveCaps`/`pooledHeadroom` (the abuse-proof pooling, witnessed)/`clampChildGrant`/expired+disabledAncestor/path-utils/`parseScopes`+`parseKeyMeta`, extracted VERBATIM; the app builds `ChainNode[]`+`SpendRow[]` from its DB (the query is the deferred seam) and calls these so the money/abuse logic can't drift. **`@suluk/credits` BUILT 2026-06-30** (the dependency root — [tooling/ts/packages/credits/](../tooling/ts/packages/credits/), credits **10 pass**): the package OWNS the schema (`credit_transaction` + sidecars) and the app injects a Drizzle handle; the **atomic `debitIfCovers`** (conditional INSERT, can't go negative) + the **idempotent `debitOnceIfCovers`** (partial-refund double-spend guard) + `keySpend`/`listTransactions`/`ledgerStats` — extracted VERBATIM and **witnessed against a real bun:sqlite**. Excluded (app): payment-alert kinds, the user-count. **`@suluk/keys` generic surface COMPLETE 2026-06-30** (keys **22 pass**): + the lineage DB ops (`subtreeOf`/`parentPathOf`/`insertLineage`/`revokeKeyTree` with the strict-descendant guard + injected apikey-disable) + **`chainHeadroom`** — the keys×credits integration (joins the credit ledger → `pooledHeadroom` real end-to-end: the abuse-proof cap bounds parent+child TOTAL spend, witnessed `{50, spent 40, remaining 10}`). The app-specific grant-fetch (apikey vs MCP) stays in the app and calls these. **`@suluk/billing` v1 BUILT 2026-06-30** ([tooling/ts/packages/billing/](../tooling/ts/packages/billing/), billing **7 pass**): the Stripe transport over an injected `StripeConfig {secretKey, fetch?}` + customer/SetupIntent/PaymentIntent creation + the saved-card surface (list/default/owns/set-default/detach + subscription-card + payOpenInvoice + setSubscriptionCancel), `res.ok`/field semantics VERBATIM, the Effect-Schema decode dropped (no `effect` dep), mock-fetch witnessed. **`@suluk/billing` v2 — the deferred wrappers FINISHED 2026-07-01** (billing **29 pass**, tsc clean): **`payments.ts`** (money-moving — Checkout / subscription-Checkout / portal / on-default-card top-up / `chargeOffSession`, the app's product-name + success/cancel/return URLs injected as PARAMS, the off-session decline taxonomy verbatim: `authentication_required`→flag, hard 402 returned, transient throws) + **`tax.ts`** (`calculateTax`/`recordTaxTransaction`, graceful — any failure → `taxCents 0`) + **`subscriptions.ts`** (the PRICING-WOVEN logic made GENERIC over an injected `SubPlan` catalog — `planById`/`planByPrice` + a `SubscriptionBranding` seam + the **pure `ceilingFor`** paid-ceiling math + `ensurePlanPrice`/`createSubscriptionOnDefaultCard`/`getSubscriptionStatus`/`changeSubscriptionPlan`, the up→down→up never-recharge invariant intact) + **`account.ts`** (the package-OWNED `billing_account` store; userId PK plain col, app injects a Drizzle handle, `linkBillingCustomer` never clears a subscriber's sub). The deferred **`creditOnce` landed as `@suluk/credits.grantOnce`** — its right home — the money-IN idempotent grant (legacy-key honoured + non-finite/fraction/negative rejected; the money-IN twin of `debitOnceIfCovers`; credits **14 pass**). **STAYS APP (policy, not library — honest):** the webhook DISPATCH (composes `@suluk/stripe` webhookRouter/verifyStripeSignature + these primitives + `grantOnce` + the app's pricing/alerts), the branded email templates, payment-alert kinds, refund + subscription-pooling. deps += `@suluk/drizzle` + `drizzle-orm`. **The C046 library layer is DONE; only the toolfactory rewiring (the live-billing cutover) remains** — the separate careful step, after each package proves byte-faithful + witnessed. (Consolidation notes: `@suluk/better-auth` exports `parseApiKeyMetadata`; `@suluk/stripe` exports `restStripe`/`stripeGet`.) ## ✓ C044 — `x-suluk-cost` settlement axis: how a cost is recovered (credit | rate-limited | free) (@0.55) Operator: "allow the user to define how the cost will be paid — by rate limiting or by credit." Also a real **cowpath** — toolfactory's CI/CD governance gate already checks "every cost names a lever (`credit | rate-limit | free`)" in its app-specific `src/openapi-governance`; this promotes it into a first-class facet (C027/C036 cowpath pattern). Surfaced during the toolfactory CI/CD-consolidation investigation (operator chose: **C044 first**, then grow `@suluk/cockpit`'s `contractGates` into the unified audit that composes it). **[C044](../doc/architecture/decisions/C044-cost-settlement-axis.md)** (@0.55, [`0settlement.bn`](./facts/0settlement.bn), burhan True, converge clean **315**). The FIFTH orthogonal cost axis (basis=how-meters · trigger=when-fires · attribution=who-pays · reconciliation=declared-vs-actual · **settlement=how-recovered**). **NO core change** — `CostModel` lives in `@suluk/cost`; the matcher has ignored `x-suluk-cost` since C024, so settlement (an enum+int+enum, purely static) is trivially D1-safe. **`settlement?: CostSettlement`** on `CostModel`: `method "credit"|"rate-limited"|"free"` + `credits?` (the credit debit; else derive from estimateMicroUsd × the operator's rate) + `overflow?` (when a rate-limited free cap is hit). **`rate-limited`** = free to the user, the op's `x-suluk-ratelimit` IS the settlement; **`credit`** = a balance is debited; **`free`** = truly free. **`settlementAudit(doc)`** = the generic "names a lever" check (`cost-without-settlement` · `rate-limited-without-cap` HIGH · `credit-without-amount` · `free-but-priced`); **`impliedErrorStatuses(req)`** = the generic errors-gate (credit→402 · auth→401 · scope→403 · ratelimit→429 · upstream `per-request`→502); **`settlementRollup(doc)`** = a monetization tally. **Verified: cost 43 pass, tsc clean, converge clean 315.** Witnessed by [`cost/test/settlement.test.ts`](../tooling/ts/packages/cost/test/settlement.test.ts) (incl. a type-linked D1-wall check — every field enum/scalar, never a value selector). **NEXT (the chosen plan):** grow `@suluk/cockpit`'s `contractGates` into the **unified contract audit** that composes validateDocument + harden(security+readiness) + costAudit + **settlementAudit + impliedErrors** + stores + agents → one graded report + a gate runner; toolfactory's 6 CI gates (~154 LOC + ~150 LOC of generic `src/` audit rules) collapse to thin calls. **HONEST:** the audits are built; the ENFORCEMENT is the consumer's runtime (rate-limit middleware ships in `@suluk/hono`; the credit debit is a thin adapter over the app's balance store — an adapter seam); the µ$→credits rate is a runtime concern, not declared. ## ✓ C043 — readiness as a `@suluk/harden` dimension + the unified `journeys audit` (security + readiness + coverage @0.55) Operator: "shouldn't the gaps/outlines be surfaced by `@suluk/harden` and then we use it in the packages we are working on today?" — yes: `@suluk/harden` already IS the unified contract-grade surface (it ships `combineGrades`/`assertCombinedGrade`, designed to fold its security grade together with `@suluk/agents`' `gradeAgent`). **[C043](../doc/architecture/decisions/C043-harden-readiness-and-unified-audit.md)** (@0.55, [`0audit.bn`](./facts/0audit.bn), burhan True, converge clean **311**). **THE HARD CONSTRAINT:** harden deps only `@suluk/core`; journeys deps harden ⇒ harden CANNOT import journeys (cycle) and has no `.feature` files, so BDD coverage is computed in journeys and combined by **LETTER** (exactly as the agent grade is — `combineGrades` takes letters, not deps). **THREE PIECES:** (1) **harden `auditReadiness(doc)`** ([readiness.ts](../tooling/ts/packages/harden/src/readiness.ts)) — a SECOND, SEPARATE grade (kept apart from the security `auditDocument` grade): `computed-required` (HIGH — a required `computed`/`readOnly` field a client can't send: a real bug) + `request-without-example` (LOW); reuses harden's `Finding`/`grade`, reads origin via `@suluk/examples` `fieldOrigin` (single source of the C041 convention; harden gains a zero-dep `@suluk/examples` dep). (2) **journeys `coverageGrade(report)`** ([coverage.ts](../tooling/ts/packages/journeys/src/coverage.ts)) — the binder's covered/total → a letter (via harden's `grade`) + the uncovered op names (the gaps → generate an outline for each); journeys gains a `@suluk/harden` dep. (3) **`journeys audit` + pure `buildAudit`** — folds security + readiness + coverage via harden's `combineGrades` → worst+average; `--min A|B|C|D|F` gates CI on the **worst**; coverage included only with `--features`. The outline GENERATOR stays in journeys; the audit surfaces WHICH ops need one. **Acyclic:** `@suluk/examples` (zero-dep) ← `@suluk/harden` ← `@suluk/journeys`; harden never imports journeys. **NO new facet.** **Verified: harden 21 / journeys 98 pass, tsc clean, converge clean 311.** Witnessed by [`harden/test/readiness.test.ts`](../tooling/ts/packages/harden/test/readiness.test.ts) + [`journeys/test/audit.test.ts`](../tooling/ts/packages/journeys/test/audit.test.ts) (a REAL `journeys audit` spawn + the `--min` gate) + a manual run (security C / readiness C / coverage F → worst F; uncovered: health, refund). **DEFERRED:** wiring the gate into toolfactory CI; an `outlines` subcommand emitting stubs for exactly the uncovered ops; an "unmarked-but-likely-sourced" heuristic finding (too fuzzy for now). ## ✓ C042 — Gherkin → Bruno/Postman demo collections: a second emit target (live-prod demos + dev-local rehearsal @0.5) Operator: "allow testers to write demos using Gherkin that compile to bruno or postman so they can showcase features start-to-end on production in a live call" + follow-up: "also used by developers to generate bruno/postman to test locally before others run the demo live on production." **[C042](../doc/architecture/decisions/C042-gherkin-demo-collections.md)** (@0.5, [`0demos.bn`](./facts/0demos.bn), burhan True, converge clean **306**). A SECOND emit target in `@suluk/journeys` ([`demos.ts`](../tooling/ts/packages/journeys/src/demos.ts)) — same C038/C040 binding, a different lowering (raw-HTTP collection, not a typed `client.()` call). **`compileDemos(doc,vocab,features)` → a target-agnostic IR** (`DemoScenario[]`): each bound `When` → a `DemoRequest` (method+path+auth+JSON body); the body is built from the scenario's **first Examples row** when present, else **synthesized** from the schema (C041 origin-aware, `computed` dropped). A **`sourced` field becomes request CHAINING** — it renders as `{{var}}` and the SOURCE request CAPTURES the field (Postman `pm.collectionVariables.set` / Bruno `script:post-response` `bru.setVar`) — the live-call `resolveSourced`. **`renderPostman`** (Collection v2.1.0 string) + **`renderBruno`** (a file map: `bruno.json` + per-request `.bru` + environments). **ENVIRONMENT-AGNOSTIC IR = the dual use:** the IR holds no URL, only `{{baseUrl}}`; both renderers emit a **local** (default `wrangler dev` port — dev rehearses first) and a **prod** environment; the presenter switches `baseUrl` for the live call. **NO new facet** — a downstream consumer like `emit.ts`; the C038 wall holds. **Verified: journeys 81 pass, tsc clean, converge clean 306.** Witnessed by [`demos.test.ts`](../tooling/ts/packages/journeys/test/demos.test.ts) + the visual Bruno collection (createSubscription captures `createSubscription_id`; charge body `"subscriptionId": "{{createSubscription_id}}"`). **HONEST:** format fidelity = "good enough to import+run" (not full schema completeness); path/query is `{{param}}`-stubbed where not a body field; the 2xx assert is a smoke check (OpInfo lacks the declared status set). **CLI SHIPPED (2026-06-30):** a `journeys` bin ([`bin/journeys.ts`](../tooling/ts/packages/journeys/bin/journeys.ts)) with a `demos` command over the pure, filesystem-free core [`buildDemoFiles`](../tooling/ts/packages/journeys/src/cli.ts) — `journeys demos --doc --features … --out [--format bruno|postman|both] [--name] [--base-url] [--local-base-url]` loads a contract + `.feature` files and writes the collection(s) to disk (witnessed by [`cli.test.ts`](../tooling/ts/packages/journeys/test/cli.test.ts) incl. a REAL bin spawn; journeys **87** pass). **DEFERRED:** the op's real declared statuses; per-row demo variants; `Then`-derived assertions; the P4 promote bin (+ its `mizan_check_action_safety` gate). ## ✓ C041 — `x-suluk-origin` field-origin discipline: which fields a client may faker, which are sourced (wired), which are computed (SHIPPED @0.5) Operator sharpened C040's faker: "mark fields that are genuinely defined by the validation and are faker-able … or if it is retrieved from somewhere else or calculated somehow" + a follow-up: "wire [sourced fields] so both the Gherkin DSL generator AND `@suluk/sdk` can use it." **[C041](../doc/architecture/decisions/C041-field-origin-discipline.md)** (@0.5, [`0field-origin.bn`](./facts/0field-origin.bn), burhan True, converge clean **300**). A **per-property Zod `.meta()` convention** — `x-suluk-origin: input|sourced|computed` (+ optional `x-suluk-from`) — authored where the single source of truth lives (Zod) and read ONLY downstream. **NO core facet, NO meta-schema change, NO new D1 surface.** **WITNESSED up front (the load-bearing assumption):** `z.toJSONSchema` (which `zodToV4` wraps) carries arbitrary `.meta()` keys **verbatim** onto the property (incl. a STRUCTURED `x-suluk-from`), `.readonly()` → `readOnly:true`, zero warnings — so `@suluk/journeys`/`@suluk/sdk` read the marker with no change to `@suluk/core`. **SHIPPED in [`journeys/src/examples.ts`](../tooling/ts/packages/journeys/src/examples.ts):** `fieldOrigin` (explicit > `readOnly`⇒computed > default `input`), `describeInputs` (per-field `{origin, from, source?, fakerable, required}` — the client/SDK-facing surface), and **origin-aware `synthesize({direction})`** — a REQUEST example **omits `computed`** (the faker stops inventing ids/totals; `readOnly` treated as computed), a RESPONSE omits `writeOnly`; **`sourced` is synthesized type-valid but tagged**, never laundered as free input. **SOURCED = A WIREABLE EDGE (the follow-up), DUAL CONSUMER:** `x-suluk-from` is EITHER a free note OR a structured **`SourceRef {op, select?}`** (`op` = C009 by-name handle, `select` = dotted response path, default `id`); the pure primitive **`resolveSourced(captured, ref)`** is BUILT + witnessed, consumed by (1) the journeys emitter (capture each bound `When ` response → resolve the cell — realizes C038's deferred carried-data) and (2) `@suluk/sdk` (surface as a sourced edge for sampleInput/chaining/docs). **C037 claim-2 RECONCILED (recorded, not laundered):** this declares a response→request edge C037 kept out of the *store facet*, but it is (a) NOT matcher-read (codegen-only), (b) fits C037's POLICY/PLUMBING/BEHAVIOR split (declares the graph; generator emits plumbing; extraction is generated behavior), (c) an operator-directed lift of a C037 reserve at a lowered ceiling. **D1 GATE PASSED:** [`core/test/origin-d1-invariance.test.ts`](../tooling/ts/packages/core/test/origin-d1-invariance.test.ts) (a petstore PROVABLY stamped with the markers incl. a structured `x-suluk-from` → byte-identical ADA + identical `matchRequest`); round-trip witnessed by [`zod/test/meta-passthrough.test.ts`](../tooling/ts/packages/zod/test/meta-passthrough.test.ts). **Verified (C041 core): journeys 76 / zod 38 / core 53 pass, tsc clean.** **SDK WIRING + EXTRACTION SHIPPED (2026-06-30):** wiring `@suluk/sdk` forced the reader BELOW both sdk and journeys (journeys deps sdk ⇒ cycle), so the self-contained `examples.ts` was lifted verbatim into a NEW **zero-dep leaf [`@suluk/examples`](../tooling/ts/packages/examples/)** (journeys keeps a re-export shim; public API + projector wall unchanged) — supersedes C040's "all inside journeys" fork FOR THE SHARED READER ONLY; journeys stays the façade. `@suluk/sdk` now emits per-method **`.fields`** = the full `describeInputs` (origin + the wireable `source` edge), so a caller knows which inputs to faker / chain / skip; `$manifest` stays lean. **Verified: examples 33 / journeys 44 (unit tests moved to the leaf) / sdk 23 pass, tsc clean, converge clean 302.** **DESIGNED, follow-on:** the journeys EMITTER capture loop (the runtime half of the wiring) + an sdk `sampleInput` (fill only `input` fields); a `computed+required` lint (a schema smell); `@suluk/hono` authoring sugar (`input`/`sourced`/`computed` helpers) so a runtime contract needn't write raw `.meta()`. **The keyword tokens are a one-line rename while adoption is still zero.** ## ✓ C040 — `@suluk/journeys` examples + outlines + `@suluk/stubgen`: closing the tester→backend loop (P2 SHIPPED @0.45; P1/P3/P4 designed) Operator asked to extend the journeys arc into a **bidirectional loop**: a tester expands generated **Scenario Outlines**, runs them immediately (C038 runnable + C039 hatches), curates which **examples** are public, and — where a scenario needs an op the contract lacks — **shapes the backend** via a generated contract + handler stub the maintainer fills. **[C040](../doc/architecture/decisions/C040-suluk-journeys-examples-and-stubgen.md)** (@0.45, [`0journeys-examples.bn`](./facts/0journeys-examples.bn), burhan True, converge clean **295**). The three architecture forks were decided **by the operator** (no council — the contested part was the forks): **(1) promote examples into Zod** (Zod is the literal home for every example), **(2) all inside `@suluk/journeys`**, **(3) a generic `@suluk/stubgen` now**. FOUR pieces: **P1** Scenario-Outline generator + outline-aware parse/emit · **P2** example-precedence resolver · **P3** generic `@suluk/stubgen` (contract stub + handler via an adapter seam mirroring `@suluk/deploy`/C034) · **P4** promote-into-Zod (a tester `@public` row → `.meta({examples})` in the Zod source → flows into the rendered docs). **NO new contract facet, NO new D1 surface** — examples are VALUES, so they stay as `.example` annotations (never the static matcher) and the value-synthesis layer is walled off from the pure projector core. **P2 SHIPPED + WITNESSED (the cheapest-first slice):** [`journeys/src/examples.ts`](../tooling/ts/packages/journeys/src/examples.ts) — `resolveExample(schema, {public?, maintainer?}, hint)` resolving **public > maintainer (explicit, or the schema's own examples/example/const) > synthetic**, tier-1 a **deterministic** schema synthesizer honoring const/enum/default/format/length/bounds. **DEVIATION (recorded):** v1 uses NO external faker dep (a deterministic synthesizer) against the operator's "take the faker dep" framing — for determinism (BDD tests don't flap) + never-launder (synthetic is always lowest + marked `synthetic:true`); swappable behind the seam later. **VALUE WALL witnessed** by [`test/examples-wall.test.ts`](../tooling/ts/packages/journeys/test/examples-wall.test.ts) (projector core never imports `./examples`; `examples.ts` self-contained → one-file extractable). **Verified: journeys 60 pass, tsc clean, converge clean 295.** **P1 GENERATOR + PARSER-CAPTURE SHIPPED (2026-06-30):** [`journeys/src/outline.ts`](../tooling/ts/packages/journeys/src/outline.ts) `buildScenarioOutlines`/`renderScenarioOutlines` emit a `Scenario Outline` per op (Examples columns = client-facing inputs, `computed` dropped via C041; an `input` cell = a synthesized value, a `sourced` cell = the wiring token ``); `gherkin.ts` now CAPTURES the `Examples:` table into `Scenario.examples` (+ fixed a LATENT bug: the KW alternation mis-parsed `Scenario Outline:` names). Witnessed by [`journeys/test/outline.test.ts`](../tooling/ts/packages/journeys/test/outline.test.ts). **P1 RUNNABLE HALF SHIPPED (2026-06-30):** [`emit.ts`](../tooling/ts/packages/journeys/src/emit.ts) unrolls ONE bun:test per Examples row — the outline's `When` is the contract's **bindable** vocabulary phrase (so it binds) and the Examples columns carry the bound When op's body by NAME; an `input` cell → a coerced literal, a `sourced` cell `` → `pick(captured, op, select)` resolving from a prior step's CAPTURED result (end-to-end **chaining** across a multi-step journey; each bound When captured under its `op.name`). Ops with path/query args fall back to the provide-input placeholder. Witnessed by [`journeys/test/emit-outline.test.ts`](../tooling/ts/packages/journeys/test/emit-outline.test.ts) (journeys **60** pass, tsc clean). **P4 PROMOTE-INTO-ZOD — PURE CORE SHIPPED (2026-06-30):** [`promote.ts`](../tooling/ts/packages/journeys/src/promote.ts) — the parser now captures `@`-tags; `extractPublicRows` + `buildExampleObject` (typed coercion, wiring-token skipped) + `promoteExampleIntoZod` lift a `@public` Examples row into the Zod schema's SOURCE as `.meta({ examples })`, **marked + idempotent (re-promote replaces, via a string-aware paren scan) + never-clobber (refuses a hand-authored top-level `.meta({examples})`; a property-level `.meta` isn't confused)** + `promoteFeatureExamples` (orchestrator, target injected). Witnessed by [`promote.test.ts`](../tooling/ts/packages/journeys/test/promote.test.ts) (journeys 71 pass). **P4 BIN SHIPPED (2026-06-30):** `journeys promote --features … --target "=#"… [--write] [--because]` over the pure core `planPromotions` ([cli.ts](../tooling/ts/packages/journeys/src/cli.ts)) — **DRY-RUN by default** (prints a `miniDiff`, writes nothing), `--write` applies; a substrate operator runs `mizan_check_action_safety` AROUND the `--write` (the bin can't call mizan — a published `@suluk` pkg must stay free of the adam substrate). Never-clobber refusals surface as skipped rows. Witnessed by [`promote-cli.test.ts`](../tooling/ts/packages/journeys/test/promote-cli.test.ts) (units + a REAL spawn: dry-run leaves the file unchanged, `--write` applies; + a manual multiline-`z.object` run). **P4 remaining:** toolfactory wiring. **P3 `@suluk/stubgen` — SHIPPED (2026-06-30):** a NEW zero-dep package [`@suluk/stubgen`](../tooling/ts/packages/stubgen/) turns a NEEDS-CONTRACT gap → a generic `@suluk/hono` `RouteContract` literal (name/method/path inferred from the intent; request Zod inferred from the Examples columns, every inference `// TODO: tighten`) + the HANDLER half via a `HandlerTarget` adapter seam (`honoEffectTarget` = toolfactory's Effect+run()+RouteError idiom, the first adapter; `honoTarget` = framework-generic). `@suluk/core` never imports it (test-enforced). Witnessed by [`stubgen.test.ts`](../tooling/ts/packages/stubgen/test/stubgen.test.ts) + the visual stub. **ALL FOUR C040 PIECES NOW HAVE SHIPPED CORES** (P2 resolver · P1 outlines+runnable+chaining · P4 promote-into-Zod · P3 stubgen) + C041 field-origin + SDK `.fields`. **REMAINING = consumer wiring (the "live" glue, app-specific):** the P4 promote BIN (file IO + `mizan_check_action_safety` gate before write + git-diff review); a journeys helper deriving `StubGap`s from a `GapReport`'s NEEDS-CONTRACT + the outline columns; toolfactory integration on the `convert` op (the end-to-end pilot); an sdk `sampleInput` + a `computed+required` lint; `@suluk/hono` authoring sugar. **Khazīna candidate flagged** (tester-shapes-backend loop + promote-into-Zod-with-precedence), gated on an author-in-the-loop witness. ## ✓ C039 — `@suluk/journeys/hatch`: BDD escape hatches (compose-as-user DEFAULT; auth/OAuth + D1/KV state a marked, prod-safe FALLBACK @0.42) Operator directed: "allow easy connection to these [CF state] services but only as a FALLBACK; preferably compose all BDD as an actual user, but sometimes we need hatches like OAuth." **[C039](../doc/architecture/decisions/C039-suluk-journeys-hatches.md)** (@0.42 verify-adjusted, [`0hatches.bn`](./facts/0hatches.bn), burhan True, converge clean **289**) decided by a **security-led council** (`wf_d65d8c26-0eb`, **5/6 → Candidate 1**: a thin in-package subpath `@suluk/journeys/hatch`, reusing @suluk/cloudflare REST + @suluk/env — not a new package). **USER-DEFAULT by surface asymmetry:** a plain bound `When` lowers to `client.(...)` with zero ceremony; a hatch additionally requires importing `@suluk/journeys/hatch` + CF creds + a resolved target — a user-composed scenario imports NONE of the hatch subtree (opt-in by absence). **AUTH HATCH `signInAs`** (the motivating case — toolfactory is Google-OAuth-only, sessions in D1): mints via the app's OWN Better Auth (NEVER hand-forges a row) and **self-verifies** the cookie against a live authenticated endpoint, **throwing if rejected** (fails closed, never a false green). **SAFETY-MODEL PIVOT (operator-directed — no test infra provisioned):** two backends — `resolveBackend({mode:"local",d1Path})` = **bun:sqlite over the miniflare local D1** (completely local, recommended for CI), or `{mode:"remote",cf,d1DatabaseId,acknowledgeRealDeployment:true}` = the **REAL deployment** (the seeded rows ARE test users — BDD-as-living-documentation). The write-safety guard is **TEST-USER SCOPING** (not prod-refusal — the real risk was *unscoped* destructive ops): `seed(table,ownerColumn,rows)` **forces** the owner column to the test-user id; `cleanupScope` deletes only that user's rows; raw `exec` is **refused on the real deployment** (local-only). **STATE HATCH `stateHatch`:** capability-by-type (READ-ONLY default; scoped writes only when `{write:true}`), all values **params-bound**, identifiers validated, `seed` requires a `because`. **SERVICES v1: D1** (both backends; the auth substrate); KV data-plane verbs landed in @suluk/cloudflare but the hatch KV surface is deferred; Vectorize/Queues/R2/Analytics designed-in-seam; Workers AI + Browser **excluded** (stateless). **AUTH HATCH `signInAs`** mints via the app's OWN Better Auth + **self-verifies** the cookie against the live API (fails closed, never a false green); **WITNESSED end-to-end completely locally** — package test [`test/hatch-auth.test.ts`](../tooling/ts/packages/journeys/test/hatch-auth.test.ts) pins the fail-closed contract, and toolfactory's `scripts/journeys-hatch-selftest.ts` mints a real Better Auth session (signed via better-call) over in-memory bun:sqlite + verifies via Better Auth's own getSession → **PASS** (no throwaway CF account, no wrangler dev). **CONTRACT WALL** witnessed by [`test/hatch-wall.test.ts`](../tooling/ts/packages/journeys/test/hatch-wall.test.ts); **test-user scoping witnessed** (real bun:sqlite round-trip) by [`test/hatch.test.ts`](../tooling/ts/packages/journeys/test/hatch.test.ts). **Security fix:** scrubbed the `CloudflareError` body leak. **BUILT + GREEN (workspace-only, not published):** journeys 34 pass, cloudflare 23 pass, tsc clean. Receipt `seg-04a8ba8493`. **HONEST/OPEN:** the consumer still wires `ensureUser`/`mintSession`/`verify` against toolfactory's Better Auth (then run the local self-test); teardown best-effort (the `journeys reap` sweep unbuilt); the binder-side `HatchUse` visibility marker + minimize-hatch lint deferred; a least-privilege CF token is still recommended defense-in-depth for remote runs. ## ✓ C038 — `@suluk/journeys`: intuitive runnable BDD over a v4 contract (operator-surfaced; spike-witnessed on toolfactory @0.45) Operator asked (three turns) for a package that lets NON-technical PM/BA/QA write **intuitive, runnable Gherkin** stories/journeys, generate the DSL **from a v4 contract**, detect **gaps** a dev fills, bind through **`@suluk/sdk`** (so the suite partly tests the frontend), and **semantically search** the corpus to reuse flows — proven on **toolfactory**. **[C038](../doc/architecture/decisions/C038-suluk-journeys-bdd.md)** (@0.45, [`0journeys.bn`](./facts/0journeys.bn), burhan True, converge clean **282**) decided by **3 council sessions** (`wf_2b935f6e-ed3` journeys-v1 · `wf_45bff8f5-5a3` sdk-runnable · `wf_ae8159e8-af1` discovery) + a **spike on toolfactory's live contract** (`apiDocument()`, 31 ops). **v1 = SIDECAR, NO contract facet** (6/9 voices co-first): `generateVocabulary(doc)` projects a step palette (**Given**←`x-suluk-access` · **When**←method+op-name · **Then**←statuses+`x-suluk-store`+per-unit`x-suluk-cost`); authored `.feature` stories are sidecars (a C036 provenance pointer). **Binding = EXACT-or-UNBOUND**, with **outcome (`Then`) steps bound RELATIVE to the scenario's `When`-subject** — the spike-forced fix to a real defect (a global phrase→handle map mis-bound the generic `Then it succeeds` to an arbitrary op; the council's predicted ambiguity failure, caught + corrected on a live contract). **Stable identity = `op.name`+path-uri** (NOT the sdk `clientAccessor`; `resolveOps` mutates `op.member`) — witnessed on toolfactory's REAL shared path `api/billing/subscription` (`getSubscription`+`cancelSubscription` distinct). **Bidirectional TRI-STATE gaps** (PARAPHRASE→author-aliases-no-dev / NEEDS-DEV-GLUE / NEEDS-CONTRACT) + contract→authored **coverage holes** (the "complete" guarantee). **Runnable through `@suluk/sdk` client + nano-stores** → frontend **DATA-PATH** coverage (honest literal label: NOT rendered-UI). **D1: downstream consumer, no facet ⇒ matcher invariant**; a pre-commit `core/test/journeys-d1-invariance.test.ts` pre-walls a hypothetical future `x-suluk-journeys` facet. **Spike result:** 7 toolfactory scenarios → **16 BOUND / 3 NEEDS-DEV-GLUE / 3 NEEDS-CONTRACT**, coverage 4/31 + 27 stubs; surfaced honest source-gaps (`x-suluk-access` too coarse for *admin* scope; non-`get`/`list` phrasing needs `op.summary`). **DISCOVERY (semantic reuse-search) — DESIGNED + GATED @0.4:** deterministic faceted handle-index INSIDE journeys (`generateJourneyIndex`), reuse/modify/rebuild verdict = **set algebra over contract-handle overlap** (never prose vibes); embedding overlay = **walled-off gated sibling** `@suluk/journeys-recall` (CF Vectorize + Workers AI, cosine never decides); search panel in `@suluk/editor`; **gated until a real corpus exists**. Receipt `seg-1acd9f25f5`. **NEXT (in flight):** build the `@suluk/journeys` package (the spike is the skeleton) + the d1-invariance test; dogfood the full BDD suite on toolfactory. **RESIDUAL OPEN:** the constrained-vocabulary-plus-alias UX as *intuitive vs rigid* for a real PM (needs an author-in-the-loop witness); carried-data + teardown across a live journey (v2 journey-as-unit). ## ✓ C037 — reactive-client facet `x-suluk-store` + `x-suluk-notify` (operator-surfaced; spec-first, generator deferred @0.5) Operator (toolfactory session 2026-06-26) directed: "in the backend we define how we expect frontend to setup their states and events and callbacks so @suluk/sdk just generates a ready to use frontend package." **[C037](../doc/architecture/decisions/C037-suluk-reactive-store-facet.md)** (@0.5, [`0reactive.bn`](./facts/0reactive.bn), burhan True, converge clean **270**) defines **two paired OPTIONAL vendor facets**: per-op **`x-suluk-store`** (on a Request, beside the shipped `x-suluk-ratelimit`/`x-suluk-approval`) + doc-level **`x-suluk-notify`**. A SulukStore plays ONE role — a **QUERY** (`key` present) backs a `$` store (+ `ttl`/`revalidateOnFocus`/`params` *names*); a **MUTATION** (`invalidates` present) invalidates named stores on a 2xx (+ `onSuccess` text). `x-suluk-notify` is a status→severity map (status / `2xx`/`4xx`/`5xx` / `network` → `silent|info|success|warn|error`). The operator's three words map exactly: **states**=`key`, **events**=`invalidates`, **callbacks**=`onSuccess` + `x-suluk-notify`. **The wall (STRONGEST D1 of any facet):** this is the FIRST facet whose ONLY consumer is the `@suluk/sdk` FRONTEND codegen — it touches NO server path (not `buildAda`/`matchRequest`, not runtime-advisory agent/job/policy selection), and every field names a store name / param NAME / scalar / status — NEVER a request VALUE (the C018/C024 selector wall). **Target-agnostic = the C034 seam one layer up:** declares a dependency GRAPH + cache hints + a policy, default-projected to nanostores + @nanostores/query (peer deps) but adapter-swappable (TanStack Query/SWR/Pinia); the notify policy projects to an INJECTED `notify(severity, problem)` renderer (policy declared, rendering injected). Discriminator mirrors C027's presence-of-`model`. **D1 GATE PASSED:** `d1_store_selector_safe` + `store_no_request_value_selector` witnessed by core [`test/store-d1-invariance.test.ts`](../tooling/ts/packages/core/test/store-d1-invariance.test.ts) (buildAda byte-identical with vs without a per-op store + doc notify; **2 pass**). Types added to `core/src/types.ts` (`SulukStore`/`SulukNotifyPolicy`/`SulukNotifySeverity`, structural-only) + re-exported. **Verified: core 44 pass (42 + 2 new), tsc clean, converge clean 270.** Honest ceiling 0.5 — **generator-not-yet-built** (spec-first per operator): grounded in real boilerplate a consumer (toolfactory) hand-writes today (`stores/session.ts` + `lib/api-toast.ts` + per-panel `load()`+refetch), but unwitnessed by a real projection. **PARITY BOUNDARY (council-verified 2026-06-26, 8-agent adversarial panel — D1-safety/overreach/composability all hold-with-caveat, converged; ADR §"Parity boundary"):** the reactive layer splits POLICY (data the spec holds) / PLUMBING (generator-emitted) / BEHAVIOR (function bodies → a typed `hookable` hook-bus seam). **Declare LESS, not more:** multi-call AND zero-call actions are recovered by COMPOSITION (or a server aggregate endpoint), NOT declared — **do NOT build x-suluk-action**; retry/cache-tuning + per-op notify overrides are target-specific adapter config, not contract. Claims `store_parity_policy_plumbing_behavior_split` + `store_no_action_facet_compose_instead` + `store_no_request_value_selector_witnessed` (273). **Claim-2 now WITNESSED** (the panel's one real defect-find): `test/store-d1-invariance.test.ts` structurally rejects any value-extracting facet field (pagination `nextCursorPtr`, optimistic `idFrom`, entity `keyFields`-extractor) — 5 pass. **NEXT (in flight):** build `generateStores(doc)` in `@suluk/sdk` (owned-source, self-contained, hookable seam) + wire toolfactory. (`@suluk/nano-stores` runtime overlaps but doesn't read the facet — consolidation deferred.) ## ✓ C034 — agent-runtime adapter seam (Cloudflare is the FIRST adapter, not the only target @0.85) The runtime-adapter **seam** that lets one `x-suluk-agents` declaration project to an *executing* runtime, target-agnostic. **[C034](../doc/architecture/decisions/C034-agent-runtime-adapter-seam.md)** (@0.85, [`0run-seam.bn`](./facts/0run-seam.bn) added 2026-06-23, burhan True, converge clean 261, witnessed by [`test/runtime.test.ts`](../tooling/ts/packages/agents/test/runtime.test.ts)): `AgentRuntimeProvider` + a `runtimeProviders` registry in `@suluk/agents/src/runtime.ts`, mirroring `@suluk/deploy`'s proven `DeployProvider`/`providers` pattern one layer up. L3 holds at the seam — a provider RENDERS owned source + a **typed** `RuntimeDeployHint` (`{kind:"cloudflare";durableObjects} | {kind:"node"}`); it never hosts/sockets/holds-a-credential. **TWO adapters shipped** — `cloudflareRuntime` (wraps `projectCloudflareAgent`) + `nodeRuntime` (`projectNodeAgent`, a Bun-served process, no DO = a materially-different deploy shape), resolving the N=1 caveat (ceiling 0.8→0.85); the contract→tool derivation was extracted to `runtime-shared.ts` and REUSED (cloudflare output byte-identical), not forked. The direct `project*Agent` exports stay first-class; a future `vercelRuntime` is a new adapter + a `kind`, not a rewrite. **NOTE (merge-review honesty):** the seam + both deploy consumers (`@suluk/deploy` migrations + `@suluk/cloudflare` REST) are built and unit-wired, but NO production host yet *joins* projection→deploy — that connector is the consumer's step (a per-unit library increment, not a wired end-to-end flow). ## ✓ C036 — x-suluk-resources loadable catalog (CF "Agent Skills", contract-first; DEVIATION from C035 reserve @0.5) Operator directed "pick up all of the deferred follow-ups." **[C036](../doc/architecture/decisions/C036-suluk-resources-loadable-catalog.md)** (@0.5, [`0resources.bn`](./facts/0resources.bn), burhan True, converge clean **258**) defines **`x-suluk-resources`** — a top-level vendor map of `SulukResource` + a by-name `resources` field on `SulukAgent` — Suluk's contract-first form of **Cloudflare Agent Skills**: an on-demand catalog of instructions/references/scripts an agent ACTIVATES when a task matches. **CONTENT-ONLY (no model)** is the wall that separates it from a model-bearing always-on `skill` — **resolving the C035 collision in code** (`presence-of-model` discriminates skill-vs-route; `content-only-loadable` discriminates resource-vs-skill). **DEVIATION (recorded):** C035 RESERVED this name as build-by-nobody-until-memory-descriptors; lifted here by operator direction (same operator-surfaced-cowpath as C027). Honest mitigation: low ceiling 0.5, structural-only, CF anchor is EXPERIMENTAL (`agents/skills` + Session loadable-context) so `kind:"script"` is lint-flagged. Rides C025/C027 EXACTLY (additive, no normative kind, no meta-schema change). **D1 GATE PASSED:** `d1_resources_selector_safe` witnessed by core [`test/resources-d1-invariance.test.ts`](../tooling/ts/packages/core/test/resources-d1-invariance.test.ts) (buildAda byte-identical, 2 pass). Static surface in `@suluk/agents`: `resourceCatalog` (CF `get()` listing) + `lintResources`/`resourcesOk` (well-formed + dangling + experimental-script flag). Types added to `core/src/types.ts` (`SulukResource`/`SulukResourceRef`, structural-only) + re-exported. **Verified: core 42 / agents 173 pass, tsc clean.** Receipt `burhan.segment` C036 (deviate-by-receipt). **DEFERRED:** fold `lintResources` into `gradeAgent`; a `SKILL.md`-set / script-runner projection (CF script exec experimental); a runtime loader. ## ✓ C035 — Cloudflare terminology alignment (Rosetta layer over C027; doc-grade @0.7) Operator asked to align Suluk on **Cloudflare Agents SDK** terminology + standardize the agent-**pyramid**. Read the vendored CF docs snapshot (`cloudflare-agents-llms-full.md`, 2026-06: what-are-agents / agentic-patterns / HITL / long-running / calling-llms / conversation-state-and-memory / concepts-tools / Agent-Skills / Agents-as-tools / mcp / ai-search / payments) against `core/src/types.ts` + the C027 glossary. **[C035](../doc/architecture/decisions/C035-cloudflare-terminology-alignment.md)** (@0.7, [`0cf-align.bn`](./facts/0cf-align.bn), burhan True, converge clean **253**): a **Rosetta mapping** (each Suluk noun → CF noun → projected artifact), **NOT a rename** — honors C027's deliberate `_Avoid_: tool` choice. **One genuine collision (Skill)** resolved **KEEP + RESERVE** (operator-chosen): Suluk Skill = model+instruction tier (→ CF agent model-config + the generated SKILL.md, itself a valid CF Agent-Skill artifact); CF Skill = loadable on-demand content. Keep `skills` (honors shipped C027); **reserve `x-suluk-resources`** for CF's loadable-catalog meaning (built-by-nobody until memory descriptors land). **Pyramid = the existing route(no-model)/skill(model) determinism gradient made vertical** (Layer 0 = routes→MCP tools; Layer k = skills + lower routes/sub-agents; edges = MCP connections); an agent's **level** is a pure static derivation, **never read by the D1 matcher**. Per-layer observability **reuses shipped infra** (gradeAgent A–F + contextBudget + tier). **No type / schema / normative change.** Honest caveat: two CF anchors (`agents/skills`, Session memory) are EXPERIMENTAL → those rows flagged provisional, ceiling bounded ≤0.7. Receipt `burhan.segment` C035. CONTEXT.md gains a "Cloudflare alignment" subsection (+ Pyramid term). **FOLLOW-UP DONE (2026-06-23):** the pyramid now has running code — `agentLevel()` (pure static composition-height; routes=0, leaf agent=1; cycle-safe via `subtreeDepth`) + `layerReport()` (folds level + grade + token-budget + context-waste into one per-layer surface; a COMPOSITION of shipped analyzers, never read by D1) in `@suluk/agents/src/pyramid.ts`, exported + README'd; agents **147** tests pass (10 new), tsc clean. **ALL DEFERRED FOLLOW-UPS DONE (2026-06-23):** agentic-pattern affordances (`agenticPatterns`/`affordedPatterns`, advisory-only per C029) + `x-suluk-cost → paidTool(price)` wiring (`paidToolPrice` + scaffold annotation) + the `snapshots` key-convention unification (dual-accept, mirrors `instructions`); `x-suluk-resources` defined as its own Step → **C036** above. ## ✓ C028 — x-suluk-policy operator governance overlay (resolves C027 open-Q #6; sibling-build, static subset @0.52) Resolved C027's deferred governance question via council panel `wf_b2f1fd82-7a7` (11 voices: **8 sibling-build / 3 defer / 0 core / 0 decline**; both Class-A static voices + security-reviewer → sibling-build; deferrers objected only to building *enforcement* for zero fleets). Adversarial verify: all 3 load-bearing claims **hold-with-caveat** (@0.5/0.58/0.52). **[C028](../doc/architecture/decisions/C028-suluk-policy-governance-overlay.md)** (@0.52, [`0policy-d1.bn`](./facts/0policy-d1.bn) + [`0policy-d1-witness.bn`](./facts/0policy-d1-witness.bn), converge clean 230): an OPTIONAL top-level **`x-suluk-policy`** map keyed by **OPERATOR/fleet name** of `SulukPolicy` — operator-owned governance that NARROWS agent self-declaration. **effective = INTERSECT(operatorPolicy, agentSelfDeclaration)** — a monotone MEET (never exceeds either; widening = lint hard-fail), reusing the shipped `intersectScope`. **BUILT (static subset, real author-time teeth):** `policyConstrain` + `lintPolicy` (D1 request-value-selector rejection, dangling/malformed appliesTo, unsatisfiable, widening guard, + novel cross-facet **cap-below-estimate**), the effective fold into the signable `agentManifest` (signature covers operator caps), the policy-aware over-serve auditor (`policy-denied-served`), and a read-only cockpit OBSERVE diff (declared vs effective + the cost three-number cap/estimate/actual). **DECLARED-not-enforced + RESERVED:** `costCeiling{amount,unit,basis,enforcedBy REQUIRED}` — the schema declares the cap, only a runtime adapter enforces it; the terminate-at-spend kill-switch is built-by-nobody until the reopen-trigger (a real fleet operator running ≥2 third-party-authored agents). **D1 GATE PASSED:** `d1_policy_selector_safe` (mizan no-bcmea, cap 0.55 = declared, above 0.139), witnessed by [`test/policy-d1-invariance.test.ts`](../tooling/ts/packages/core/test/policy-d1-invariance.test.ts) (matcher byte-identical with vs without a deny-all policy). **Verified: core 36 / @suluk/agents 40 / cockpit 122 tests pass, tsc clean.** Originated honesty: zero second user today (Conin is author==operator); the verdict survives only because reserving a security FLOOR is a one-way door + the static subset reuses shipped infra at near-zero cost. ## ✓ C027 — suluk-agent composition standard (operator-surfaced; build-scoped-pilot @0.52) Operator surfaced a real cowpath: **Conin** (Construction Intelligence) is already a *suluk agent* (skills + deterministic routes + an intelligent tier) shipped as one Claude plugin + servable by OpenRouter — but with NO standard describing the composition. Council panel (`wf_9e8712c7-871`, 14 voices: **11 support-with-conditions, 3 reframe, 0 oppose**; 3 SDKs — Strands / Claude Agent SDK / OpenAI Agents — corroborate the shape). **[C027](../doc/architecture/decisions/C027-suluk-agents-composition-map.md)** (@0.52, [`0agents-d1.bn`](./facts/0agents-d1.bn) + [`0agents-d1-witness.bn`](./facts/0agents-d1-witness.bn), converge clean 226): an OPTIONAL top-level **`x-suluk-agents`** name-keyed map of **`SulukAgent`**, riding the **C025 `x-suluk-jobs` precedent EXACTLY** (no new normative kind, no meta-schema change). A SulukAgent = **skills** (model-bearing; provenance pointer `source`+`contentHash`+`version`, SKILL.md GENERATED not inlined) + **routes** (by-name `operationRef` `$ref`s into EXISTING ops, **no `model`** — that absence is the hard route-vs-skill discriminator) + optional **agents** (by-name sub-refs; cycle-linted + REQUIRED `maxDepth`; built-by-nobody until a 2nd real nested agent). Selection/tiering **runtime-advisory only**; determinism **DECLARED not enforced**. Types added to `core/src/types.ts` (`SulukAgent`/`SulukSkillRef`/`SulukRouteRef`/`SulukAgentRef`, structural-only, mirrors SulukJob). **D1 GATE PASSED** (the council's hard pre-landing gate): claim `d1_agent_selector_safe` — `mizan_verify_claim` no-bcmea, cap 0.55 = declared and **above the 0.139 D1 floor**; independent maintained witness [`test/agents-d1-invariance.test.ts`](../tooling/ts/packages/core/test/agents-d1-invariance.test.ts) (3 pass) proves `buildAda`/`matchRequest` are **invariant** to an `x-suluk-agents` block, even a cyclic one. **Honesty (council-forced):** the operator's "tiering SOLVES the context problem" was adversarially **REFUTED** (tiering relocates+duplicates context; Conin's public MCP `tools/list` ships the FULL catalog → 0 context saved in the served path today) and **reframed** to "makes allocation EXPLICIT + per-tier cost AUDITABLE — a CONDITIONAL reduction a conforming adapter must deliver"; Conin is non-conformant day-one (named conformance-failure fixtures). Receipt `burhan.segment` C027. **DEFERRED:** the `@suluk/agents` projector (flat-first → Claude plugin + OpenRouter manifest), recursion machinery, tier-trim-serving mandate, runtime determinism gate, enterprise `x-suluk-policy` overlay, expansionist static axes (streaming/loop/human-gate/memory). ## ✓ C024/C025/C026 — background-event cost (operator-surfaced; topic COMPLETE) Operator surfaced a real gap: cost is often incurred when a BACKGROUND EVENT fires (a Stripe webhook charges you; cron; queue; a callback completes), not when a route runs — and `x-suluk-cost` was request-relative only. Council panel (`wf_026469fd-1f3`, C006/C007 classes + C010 pattern): A = hudlow .78 / handrews .70 / rafalkrupinski .70 + B/C lenses; 8/10 voices → candidate-b (split form). **[C024](../doc/architecture/decisions/C024-cost-trigger-and-attribution.md)** (@0.58, [`0cost-trigger.bn`](./facts/0cost-trigger.bn), converge clean 213): three ORTHOGONAL axes on `x-suluk-cost` — **basis** (HOW it meters; UNCHANGED — no `per-event`, rejecting the double-duty) · **trigger** (WHEN it fires; NEW static closed enum `synchronous`|`webhook-received`|`scheduled`|`queue-consumed`|`callback-completed`, default `synchronous` zero-migration, + `triggerRef`; locally decidable — passes hudlow) · **attribution** (WHO pays; NEW runtime-only strategy modeled on `SulukRateLimit.key`, the `event-expression` kept OUT of the static matcher exactly as C018 walls callback keys; no-session gated on Open-Dec #5). Fail-loud `@unattributed` + `unattributed-background-cost`/`unverified-attribution` audit findings; `costAudit`/`annotateCosts`/`costTable` now walk webhooks. **Does NOT reopen C018's async scope** (a vendor-ext dimension, orthogonal — same move as x-suluk-ratelimit vs C012/#43). Reference UI: `costRollup` walks webhooks + a `.deferred` count + a `↯ charged on: ` badge. Receipt `seg-3dc4e01757`. **C025 follow-on** ([ADR](../doc/architecture/decisions/C025-jobs-vendor-map.md), convergent — C024-pre-blessed, [`0cost-jobs.bn`](./facts/0cost-jobs.bn), converge 216): a top-level `x-suluk-jobs` name-keyed map of `SulukJob` (non-HTTP cron/queue work, no Request) so cron/queue cost has a first-class home; `@suluk/cost` `eachJob`/`costLoci` walk it, reference rolls it in. **C026** ([ADR](../doc/architecture/decisions/C026-cost-reconciliation.md), convergent — C024-council-proposed, [`0cost-reconciliation.bn`](./facts/0cost-reconciliation.bn), converge 218): a 4th orthogonal axis `reconciliationBasis: declared-estimate|payload-reconciled` — a payload-reconciled cost reads the ACTUAL charge from the event (amountExpression+amountUnit, runtime-only) so the recorded total is the real invoice line. **Topic COMPLETE** (webhooks+cron/queue · trigger+attribution+reconciliation · facet+runtime+docs UI). ## ✓ C010 Wave-2B1 → C013 (referencing cluster, 4 facets, one panel) Council-integrated panel `wf_b4344a37-dcd` resolved #73/#72/#49/#26 as one: **adopt JSON Schema 2020-12 + defer-the-grammar.** Dialect EXPLICITLY DECLARED + statically/locally decidable at DOM→ADA (@0.85); **typed-component-name is the primary identity** (map key = canonical, by-name-never-index per C009; @0.62); OpenAPI Reference Object INDEPENDENT of JSON-Schema `$ref` (#49, near-unanimous @0.62); **Imports Object** = namespace+href pairs, absolute-IRI no-fragment (#72 @0.6); resolve by-stable-name default (#26 @0.7). 2 deviations (identity-mechanism, json-pointer policy). **2nd live council hit:** handrews persona predicted the holistic frame + the #49 divorce + that he'd *defer the grammar* — matched his real comment verbatim; its pre-registered valence-inversion risk caught the over-normative ADOPT candidate. Deferred: exact fragment byte-grammar, version pin, relational value-equality vocab (#24/#100). ## ✓ C010 Wave-2A → C012 (8 contested items, compact panels) Workflow `wf_806e7b7b-df3`: 8 of 9 contested items resolved via compact per-item panels (read-poles → resolve-with-council → adversarial-refute-and-finalize), post-refutation ceilings 0.5–0.74 → [`batch2-waveA.bn`](./facts/batch2-waveA.bn) + [C012](../doc/architecture/decisions/C012-contested-batch-waveA.md): **#116** inheritance (optional `shared` map + override/accumulate algo @0.55) · **#57** discriminator (retain as codegen hint + propertyDependencies @0.6) · **#45** HTTP-versions (version-agnostic @0.74) · **#43** rate-limits (out-of-scope @0.74) · **#82** versioning (permit-don't-mandate @0.74) · **#76** tiers (decline @0.6) · **#17b** precedence (most-specific-wins + allOf-compose @0.62) · **#58** links (scoped baseline @0.5). converge clean (149). #60/61 resolved directly post-limit (permit-desugar @0.6) — **Wave A 9/9**. ## ✓ C010 Wave-1 batch → C011 (17 convergent items, one wave) Triage (`wf_550dd30c-fa6`, 42 isolated agents) → 17 convergent / 24 contested / 0 originated; operator-approved. The **17 convergent** resolved directly (inherit / out-of-scope / thin) in one batched ledger [`batch1-convergent.bn`](./facts/batch1-convergent.bn) + [C011](../doc/architecture/decisions/C011-convergent-batch-1.md): #119 #224 #172 #79 #209 #54 #124 #141 #128 #63 #42/202 #130 #19 #120 #102 #75/84/50 #18. **converge backstop clean** (141 claims). 3 items (#209→#108, #63→#72, #18→#76) resolved self-contained part only, dep flagged. First C010 batch — 17 in one wave vs 17 sequential Steps. **24 contested still need panels** (dependency waves below). ## ✓ #83/#32 resolved → C009 (+ first live council hit) **Identification-first** (handrews c10): user-keyed collections stay **map/struct** for the *identity* reason — references resolve **by stable name, never by array index** — not for ergonomics. paths/requests/responses/#20-slots/components stay maps; **root tags flip array→map** (the single container change); optional non-negative order field; names via keys. 4 deviations; verdict @0.5–0.7. **Council scorecard:** the handrews persona predicted his identification-first reframe **blind** and matched his real #32 c10 near-verbatim (valence over-firm, but pre-registered) — **first in-the-wild persona confirmation**. codegen-author's "index-identity is poison" became the committed rule; tech-writer was the sole array voice, so the map default is *not* hardened. Evidence: [`0083-array-vs-map.synthesis.md`](./facts/0083-array-vs-map.synthesis.md). ## ✓ Resolved log (detail in each ADR + `plan/facts/*.synthesis.md`) - **#16 → [C003](../doc/architecture/decisions/C003-signature-mechanism.md)** — signature = uniform DOM→ADA multi-aspect matcher; detect-and-tolerate; matching-only. (24 agents) - **#20 → [C004](../doc/architecture/decisions/C004-parameter-schema.md)** — per-location slots + opt-in cross-cutting; D1-safe. *Panel overturned the unified-wrapper prediction.* (17) - **#127 → [C005](../doc/architecture/decisions/C005-templating-system.md)** — RFC6570 parseable profile + normative grammar/reverse-algorithm; D1-safe. (21) - **#17 → [C008](../doc/architecture/decisions/C008-merge-out-of-scope.md)** — document-merge out-of-scope → Overlay Spec. *Right-sized, no workflow; conflation split → #17b.* - **#59 → `0002`** — IRI support inherited from SIG ADR 0002. - **Council** — A backtested (hudlow .78 / handrews .70 / rafalkrupinski .70), B/C replay-validated (13 useful / 3 marginal / 0 drop), + first wild hit on #83. [plan/council/](./council/) - **Meta** — C002 recursive-state · C006/C007 council · **C010 batched execution** (scaling model). ## ⏳ Pending (optional · one workflow at a time) - **Council resume** — 4 rate-limited Class-A voices (earth2marsh, darrelmiller, karenetheridge, arno-di-loreto). - **C027 follow-on (agent track) — ✓ projector + marketplace-signing + scope-intersection SHIPPED.** [`@suluk/agents`](../tooling/ts/packages/agents/) (separate pkg; `core`-never-imports invariant test-enforced): `lintAgents` (cycle/maxDepth/dangling-ref/**D1 selector-rejection**/route-has-model/**scope-escalation**), the **twin projection** `projectClaudePlugin` (`plugin.json`+`.mcp.json` host-side-OAuth-no-creds+`SKILL.md` w/ sha256 `contentHash`+`version` stamp) + `projectOpenRouter` — both PURE/deterministic/fail-loud; `reachableSurface`/`assertServedSubset` (over-serve auditor) + `verifySkillFreshness`; **scope-intersection** (`analyzeScopes` — child effective = INTERSECTION(child, caller), escalation = error); and the **signable `agentManifest`** (carries every skill `contentHash` + effective scope) signed via @suluk/builder's existing ECDSA-P256 `signRegistry` so the C021 signature **covers preprompt drift** (council open-Q #8: `verifyAgentFreshness` catches a served preprompt that drifts after mint; structural tamper breaks the signature). Conin + its day-one gaps (dangling `run_core_primitive`, over-serve, scope-escalation) are NAMED failure fixtures. **31 tests pass (7 files), tsc clean; core 34 pass.** Plus the **cockpit OBSERVE surface** ([`@suluk/cockpit` `agentsView`/`agentsSummary`](../tooling/ts/packages/cockpit/src/agents.ts)): the tier tree + effective scope + gate findings + reachable surface + a names-only projection preview — strictly read-only (no execution/creds, C020 seam); 6 tests, full cockpit suite 121 pass. **All shipped to the fork** (commits `4b372c2`/`7e60f3b`/`5be6861`; npm publish needs the release token, not present in-env). STILL DEFERRED behind contested-decision reopen-triggers: recursion machinery beyond one hop, the runtime determinism gate, and the expansionist static axes (streaming/loop/human-gate/memory). (The `x-suluk-policy` overlay → resolved as **C028**, static subset built; its costCeiling *enforcement* runtime stays reserved.) **✓ Tier-trim adapter capability BUILT** (the first half of the tier-trim reopen-trigger): `SulukRouteRef.tier` (resident|cold-tail); `projectOpenRouter` now puts resident routes in the default `tools[]` + cold-tail behind a `discover_tools` meta-tool (`discoverable[]`); `residentSurface`/`assertDefaultServedResident` audit it (`cold-tail-in-default` finding); cockpit projection preview splits resident vs discoverable. So the headline context reduction is now ACTUALLY DELIVERABLE on the served path — only the *mandate* + Conin's server-side over-serve fix remain open. (core 36 / agents 43 / cockpit 123 tests pass, tsc clean.) ## Frontier head — question-frontier RESOLVED (all 57 → C001–C031); work is now PROJECTION - **All waves DONE.** Wave A→C012; Wave B (B1 referencing→C013, B2 dependents→C014); Wave C1→C015; Wave C2 (#163→C016, #upgrade→C017). Agent layer: C027 composition / C028 governance / C029 thinking / C030 router+ZDR. - **Both the question-frontier AND the `specification/` projection are now current** — C024–C026 + C027–C030 projected into SPEC.md §15–§17 (2026-06-13). The only remaining work is the gated reopen-triggers. See Cheapest-next-move. ## Decisions so far - Frontier resolved: **51** — all ~56 seeded questions resolved or accounted-for · Deviations: **27+** · ADRs: **C001–C031** spec-frontier (+ `0002`) **+ C032–C036 Cloudflare-agents tooling arc** (DO deploy + the C034 runtime seam + C035 terminology alignment + C036 x-suluk-resources). callbacks/webhooks closed (C018); cost-on-event closed (C024/C025/C026); **agent layer: C027 composition + C028 operator governance + C029 thinking-bound + C030 router-delegation (D1-gated, scoped, @0.52–0.76)**; serving surfaces **@suluk/{models,agents,chat,mcp}** shipped+published. - Last (2026-06-13): **conin MIGRATED + DEPLOYED to production + agent diagrams + tier-trim MANDATE resolved (C031).** Deployed conin's /mcp over-serve fix LIVE (construction-intelligence.saastemly.com, Version 72805730; serves 8 resident + discover_tools, not 35). **C031** (council `wf_4badc65e-14b`, unanimous 4/4 CONDITIONAL @0.52): the standard MANDATES the tier-trim IFF tiers are declared — `cold-tail-in-default` is now a gate-failing conformance FAILURE (`ConformanceFinding.severity` + `conformanceOk`, agents@0.1.5). **vscode 0.1.16 PUBLISHED to the VS Code Marketplace** (MahmoodKhalil.suluk-vscode, with the Agent diagram command). (1) Tier-trim serving built — `@suluk/mcp` (0.1.2) `mcpApp({ resident })` + `@suluk/agents` (0.1.3) `residentToolNames` (the cold-tail is withheld + revealed by `discover_tools`, lossless). (2) conin's full 39-tool `x-suluk-agents` contract authored + verified (lints clean, resident set == conin's `RESIDENT_TOOLS`). (3) **conin-plugin** is now a contract projection (`projectClaudePlugin` reproduces its published plugin byte-for-byte + `contentHash` provenance). (4) **conin's `/mcp` over-serve FIXED** (serves the 8 resident + discover_tools, not 35; conin `94abc00`, 421 tests) — the tier-trim reopen-trigger is FULLY MET. (5) **D3 agent-diagram generator** (`@suluk/agents` 0.1.4 `agentDiagram`/`agentDiagramHtml` — zoomable composition map) + a vscode `Suluk: Agent diagram` command (0.1.16). Commits `f40eb6b`/`4c989cb`/`5d6ff06`/`4674351`/`4fa8b4f` + conin-plugin `723dfb8` + conin `94abc00`. Before that: the SPEC.md deliverable pass (projected C024–C030 §15–§17; all 75 examples conformed to valid v4; D1 `bodyId` fix core@0.1.11; punch-list a/b/c closed). And: **C030 ZDR-router** — a LIVE OpenRouter probe (saasuluk key) confirmed `provider:{zdr:true}`+`openrouter/auto` combine (200), so `modelRequire.zdr` resolves to the router; region/license still pin; core@0.1.10 / agents@0.1.2; commit `364c274`. **@suluk/chat + @suluk/mcp** packages committed+published (in-page agent SSE loop + MCP server); **saasuluk** dogfoods chat/mcp + panel-projected `/dashboard` on latest deps (34 tests, full build green). Before that: **C029** thinking-bound, **C028** x-suluk-policy (D1-gated @0.52, costCeiling RESERVED), **C027** suluk-agents. ## Per-Concern confidence map | Concern | Prior richness | Sections drafted | Aggregate ceiling | |---|---|---|---| | API shapes | HIGH (richest discussion energy) | 4 (signature, parameter schema, templating, collections) | 0.85 directional / **0.5–0.62** on contested shapes (declared-indicator, #20 slots, #127 profile, tags-flip, deviations) | | Content schema formats | MEDIUM (SHACL/XSD/JSON-Schema threads) | 0 | — | | Deployment configuration | LOW → mostly Originated | 0 | — | | Foundational interfaces | LOW → mostly Originated | 0 | — | | Mechanical upgrade (3.x→4.0) | LOWEST → fully Originated | 0 | — | ## Active contradictions - **D1 ↔ #20: resolved (not fired).** #20 landed D1-safe — its per-location slots + opt-in construct are all runtime validation, orthogonal to D1's static-vs-runtime axis. No contradiction. - **D1 is weakly witnessed (watch).** `mizan_verify_claim(d1_jsonschema_out_of_static_contract)` → recommended cap **0.139** vs declared 0.55 (2 co-located L1 witnesses). "Stay out of the static matcher" is a *soft* guardrail, not a hard fact — recorded as `d1_is_soft_guardrail_cap_0139`. An independent witness would lift it. - **#20 static-matcher tripwire (live, not fired).** README L63/L170 + rpc.yaml share-method requests frame `parameterSchema` as request-*selection*, pressuring toward compiling the schema into the static matcher — which *would* contest D1. We decline; any future promotion is a deviation-on-a-deviation needing its own receipt. - **Spec-review punch-list (2026-06-13) — three PRE-EXISTING spec↔code contradictions surfaced by the §15–§17 integration review** (each predates the projection; each is hard-to-reverse → wants a deliberate decision + receipt, NOT a rushed edit). **(a) `operations:` container** — ✅ **RESOLVED 2026-06-13.** §1.9's *canonical example* used 3.x `operations:`/`requestBody:`/`body:` blocks (and `/pets/{petId}` had no `requests:` → invalid v4); §6.5.2 + §14.2 likewise. Rewrote all three to canonical v4 (`requests:` + required `method:` + `contentSchema:` + `parameterSchema` slots); the full §1.9 example now passes `validateDocument`. **(b) path-key leading-slash** — ✅ **RESOLVED 2026-06-13 (via doc note).** §2 doesn't mandate a leading slash; `compileTemplate` strips one, so `/pets` ≡ `pet`. Rather than churn 33+ examples to one arbitrary convention (and §16's no-leading-slash correctly mirrors the real conin code it documents), added a §2 note stating the leading slash is optional+normalized — the inconsistency is now intentional + documented. (Also confirmed the meta-schema is clean: top-level `additionalProperties:true` permits the `x-suluk-*` vendor layers, and it is synced with `types.ts` + the AOT `validateDocument`.) **(c) D1 `bodyId`** — ✅ **RESOLVED 2026-06-13 (core@0.1.11).** `core/src/signature.ts` had returned `inline:`, folding body SHAPE into the static signature key (a D1 breach). Fixed to the Appendix-A.2 design: `bodyId` inline → `"#inline"` sentinel + `collide()` special-cases it → `not-statically-determinable` (A.2's `a or b == '#inline' -> UNDECIDED`); 2 witness tests; core 38/agents 73/cockpit 125 green. **All three (a)/(b)/(c) RESOLVED.** *(The 6 review findings INSIDE §15–§17 were fixed in `d235ff1`; the 21 spec-wide 3.x-leftover example bugs in `98b00ef`.)* (General hunt: `burhan-converge` / `burhan-perturb` over `plan/facts/`.) ## Cheapest-next-move **The question-frontier is RESOLVED** (all 57 seeded questions → C001–C031; [frontier.md](./frontier.md): 57 RESOLVED, 0 OPEN; converge clean, now **261 claims** — grew with the C032–C036 Cloudflare-agents tooling ledgers — load-bearing all witnessed). The spec-frontier remaining work is **projection + gated reopens**, not new spec decisions; the C032–C036 arc is the separate tooling/runtime track: 1. **SPEC.md projection — ✅ CAUGHT UP (2026-06-13).** Projected the resolved clusters into new sections, each adversarially fidelity-verified against its ADR + `core/src/types.ts` (no deferred-as-normative laundering): **§15 Cost & Deferred Jobs** (C024–C026, @0.58), **§16 Agents** (C027, @0.52), **§17 Agent Governance, Thinking & Model Resolution** (C028–C030, @0.52, incl. the verified ZDR-router). Header/ToC/front-matter refreshed to C001–C031. SPEC.md now **4928 lines, 17 sections + Appendix A**. 2. **Only open work = gated reopens** (do NOT build ahead — see [AGENT-TRACK.md](./AGENT-TRACK.md)): operator-governed-ZDR (needs a policy retention vocabulary), recursion-beyond-one-hop (2nd nested agent), tier-trim MANDATE, `endpoints[]` (a real fleet), vsce Marketplace publish (separate token). `burhan-converge` backstop after any ledger edit. One workflow at a time. ## Index (pointers — load on demand) - Open questions → [plan/frontier.md](./frontier.md) - Horizon plan → [plan/HORIZONS.md](./HORIZONS.md) - **Agent track** (the `x-suluk-agents` layer: C027 composition · C028 governance · C029 thinking · `@suluk/{agents,models}` · cockpit · context-intelligence) → **[plan/AGENT-TRACK.md](./AGENT-TRACK.md)** — complete checkbox roadmap (✅ shipped + ☐ remaining w/ reopen-triggers), the resumable plan for this layer. - **Product track** (the extension as cockpit + modules + marketplace) → [plan/EXTENSION-ROADMAP.md](./EXTENSION-ROADMAP.md) — decided 2026-06-10 by a 6-lens council ([C020](../doc/architecture/decisions/C020-extension-cockpit-charter.md) charter, [C021](../doc/architecture/decisions/C021-modules-contract-merge-marketplace.md) modules). **COMPLETE — nothing left.** S1·S2·M2·M1·M3·L1 + signed-registries·L2·converge·D2(ext/app/docs)·component-confidence·L3 ship-readiness·**live role-preview** all built, adversarially reviewed (72 findings fixed), and shipped (npm + Marketplace; vscode `0.1.14`). The originated L3 AND the last optional item (role-preview) are both done. - Burhan ledger → [plan/facts/](./facts/) · spine claims → [plan/MAIN.bn](./MAIN.bn) - Narrative receipts → `daftar query "" --project=/home/mk/apps/suluk` - SIG record (priors) → [github-export/](../github-export/) · official ADRs → [doc/architecture/decisions/](../doc/architecture/decisions/) - Our ADRs → `doc/architecture/decisions/Cxxx-*.md` (frontier: [C003](../doc/architecture/decisions/C003-signature-mechanism.md) [C004](../doc/architecture/decisions/C004-parameter-schema.md) [C005](../doc/architecture/decisions/C005-templating-system.md) [C008](../doc/architecture/decisions/C008-merge-out-of-scope.md) [C009](../doc/architecture/decisions/C009-array-vs-map.md) **[C011 batch×17](../doc/architecture/decisions/C011-convergent-batch-1.md) [C012 waveA×8](../doc/architecture/decisions/C012-contested-batch-waveA.md) [C013 referencing×4](../doc/architecture/decisions/C013-referencing-cluster.md) [C014 waveB2×5](../doc/architecture/decisions/C014-contested-batch-waveB2.md) [C015 waveC1×6](../doc/architecture/decisions/C015-contested-batch-waveC1.md)**; meta C001/C002/C006/C007/C010) · glossary → [CONTEXT.md](../CONTEXT.md) - **Tooling substrate** → [v4-meta-schema.json](../specification/candidate-v4/v4-meta-schema.json) (validates docs) · [v4-types.ts](../specification/candidate-v4/v4-types.ts) (TS model) · [conformance/](../specification/candidate-v4/conformance/) (corpus + ADA contract) · [CONFIDENCE.md](../specification/candidate-v4/CONFIDENCE.md) (soft points) · SPEC Appendix A (grammars) - Worked example → [examples/petstore.suluk.yaml](../specification/candidate-v4/examples/petstore.suluk.yaml) (validates the candidate) - **Candidate spec document → [specification/candidate-v4/SPEC.md](../specification/candidate-v4/SPEC.md)** (Completion v1, ~27k words, 91 flagged-provisional points) · section stubs in the same dir - Council (guides, not prophets) → [plan/council/](./council/) ([calibration](./council/CALIBRATION.md))