Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
177 commits
Select commit Hold shift + click to select a range
d5c3126
refactor(organization): require administrator evidence for create com…
claude Sep 28, 2026
55877c8
test(organization): record evidence pilot results and mutation findings
claude Sep 28, 2026
6ee807d
refactor(authz): require department reach evidence for unguarded comm…
claude Sep 28, 2026
3a128cc
refactor(authz): run authorized commands from their evidence
claude Sep 28, 2026
b8c0629
refactor(organization): require a team interest read scope
claude Sep 28, 2026
c2bb975
refactor(social-events): require creation evidence for a new event
claude Sep 28, 2026
416850c
docs(authz): record the evidence rollout and what stays
claude Sep 28, 2026
3a55e3a
fix(e2e): end a timed-out readiness probe under Bun
claude Sep 28, 2026
6979637
docs(authz): record the journey results of the evidence rollout
claude Sep 28, 2026
0861506
refactor(rpc): delete the HTTP API and serve native operations as Eff…
claude Sep 28, 2026
33fff20
feat(homepage): call the native backend over RPC
claude Sep 28, 2026
79a666d
feat(rpc): port the session, profile, and contact contracts, the dash…
claude Sep 28, 2026
6d836a6
feat(rpc): serve admissions and admission outcomes as RPC
claude Sep 28, 2026
ee4aa9c
feat(rpc): serve organization and directory operations as RPC
claude Sep 28, 2026
b558626
feat(backend): serve the session, profile, and contact RPCs
claude Sep 28, 2026
fc9b30c
feat(rpc): call admissions over RPC from the dashboard and homepage
claude Sep 28, 2026
2480450
feat(dashboard,homepage): call the session, profile, and contact RPCs
claude Sep 28, 2026
cb53065
test(rpc): drive the admission journeys and probes over RPC
claude Sep 28, 2026
10a6f05
test(rpc): drive the returning-assistant journey over RPC
claude Sep 28, 2026
fd89885
test(e2e): drive the identity and profile journeys over RPC
claude Sep 28, 2026
47d6cb5
test(rpc): call admission operations over RPC from other journeys
claude Sep 28, 2026
4bb6dc4
docs(rpc): record the admissions port and its lost HTTP capabilities
claude Sep 28, 2026
21716ac
test(e2e): drive the contact journey and the recovery probe over RPC
claude Sep 28, 2026
679df16
feat(rpc): migrate organization and directory clients to RPC
claude Sep 28, 2026
b8e3f03
test(e2e): read sessions and profiles over RPC in the other journeys
claude Sep 28, 2026
f914823
feat(dashboard): read the own profile over RPC in the dashboard loaders
claude Sep 28, 2026
6dffa5e
docs(rpc): record the session, profile, and contact port
claude Sep 28, 2026
c9264b7
chore(lint): make every Effect language-service rule an error
claude Sep 28, 2026
2252fbd
fix(rpc): keep ingress facts out of reach of RPC message headers
claude Sep 28, 2026
6bc2788
chore(lint): leave Effect.provide to the declared entry points
claude Sep 28, 2026
79872c3
merge: rpc/platform into the RPC migration
claude Sep 28, 2026
15acd02
merge: rpc/organization into the RPC migration
claude Sep 28, 2026
ede4b47
merge: rpc/admissions into the RPC migration
claude Sep 28, 2026
1038f7d
chore(rpc): one options object for the test harness, and the lint policy
claude Sep 28, 2026
286e330
feat(rpc): serve placements and certificates as RPCs
claude Sep 28, 2026
d0d65a2
feat(rpc): recruitment and onboarding contracts and handlers
claude Sep 28, 2026
e017441
refactor(rpc): clean the foundation and first wave under every Effect…
claude Sep 28, 2026
3607bab
feat(rpc): serve the receipt operations as RPCs
claude Sep 28, 2026
aacb811
feat(rpc): move placement callers and journeys to the placement RPCs
claude Sep 28, 2026
2e61647
test(rpc): recruitment and onboarding over RPC and PostgreSQL
claude Sep 28, 2026
512a4ed
feat(dashboard): call the receipt RPCs from the receipt routes
claude Sep 28, 2026
b4f5c6a
feat(dashboard): recruitment and onboarding callers over RPC
claude Sep 28, 2026
0980ab9
test(receipts): port the receipt journeys and verification tools to t…
claude Sep 28, 2026
ecb1d96
test(receipts): port the receipt journey drivers and record the RPC m…
claude Sep 28, 2026
a132cce
chore(journeys): recruitment and onboarding drivers and probes over RPC
claude Sep 28, 2026
285484c
docs(rpc): record the recruitment and onboarding port and its lost HT…
claude Sep 28, 2026
5224cc9
merge: rpc/lint-foundation into the RPC migration
claude Sep 28, 2026
289d238
merge: rpc/placements into the RPC migration
claude Sep 28, 2026
87793f4
merge: rpc/receipts into the RPC migration
claude Sep 28, 2026
ea293d9
merge: rpc/recruitment into the RPC migration
claude Sep 28, 2026
100a865
feat(rpc): serve team applications over RPC
claude Sep 28, 2026
fdba786
feat(content): serve the content operations as RPCs
claude Sep 28, 2026
f36cd93
feat(rpc): call team applications over RPC from the dashboard and hom…
claude Sep 28, 2026
964951e
feat(content): call the content RPCs from the dashboard and homepage
claude Sep 28, 2026
75d046f
feat(rpc): move the golden team-application journey to the RPCs
claude Sep 28, 2026
216274c
feat(content): port the content publication journey to RPC and record…
claude Sep 28, 2026
5073420
merge: rpc/content into the RPC migration
claude Sep 28, 2026
b4fff98
merge: rpc/team-applications into the RPC migration
claude Sep 28, 2026
eea5744
chore(rpc): integrate the migration: retire the HttpApi patch and SDK…
claude Sep 28, 2026
9678028
test(rpc): assert the RPC contract and pin React to the catalog
claude Sep 28, 2026
4118048
fix(backend): bound and strictly parse RPC bodies, and keep answers o…
claude Sep 28, 2026
e6908e9
fix(backend): admit only the headers an RPC reads in a browser preflight
claude Sep 28, 2026
2de9812
docs: describe the RPC contract, its ingress, and what RPC does not c…
claude Sep 28, 2026
b343fcc
style(rpc): bring packages/rpc under Oxfmt in place of the deleted ht…
claude Sep 28, 2026
8b5930c
build: remove the generate, OpenAPI, and SDK entries of the deleted H…
claude Sep 28, 2026
b405144
docs: describe the RPC contract where documents and comments named th…
claude Sep 28, 2026
ac606bc
docs(specs): point active specs at the RPC files that replaced http-a…
claude Sep 28, 2026
0c52d63
fix(backend): answer each health probe with its own response body
claude Sep 28, 2026
1021575
test(dashboard): export the RPC endpoint path predicate of the native…
claude Sep 28, 2026
e629371
test(e2e): export isNativeRpcPath for recorders that match the RPC en…
claude Sep 28, 2026
76999e4
chore(journeys): export the RPC endpoint path predicate for recorders
claude Sep 28, 2026
ab040bc
test(receipts): decode approval RPC values with the contract's JSON c…
claude Sep 28, 2026
2a5cde0
fix(e2e): answer an RPC defect as 500 in the replaced-route ledger
claude Sep 28, 2026
e45667e
fix(acceptance): read recommendation refusals and report denials over…
claude Sep 28, 2026
ac5ae88
test(e2e): record the RPC endpoint with its trailing slash in the sch…
claude Sep 28, 2026
c2d4376
test(e2e): post the schools empty-department probe from the browser w…
claude Sep 28, 2026
b278fe8
test(receipts): record the dashboard server's RPCs at the endpoint pa…
claude Sep 28, 2026
062251f
test(dashboard): run the Profile journey runner with Bun
claude Sep 28, 2026
6c0688b
test(dashboard): record admission RPCs at the endpoint path with its …
claude Sep 28, 2026
4a7523c
test(dashboard): classify Organization RPCs at the endpoint path with…
claude Sep 28, 2026
e4dfce0
test(homepage): redirect only the contact command RPC in the contact …
claude Sep 28, 2026
19eee93
fix(journeys): record dashboard RPCs at /api/rpc/ in the recruitment …
claude Sep 28, 2026
2a8917d
fix(acceptance): expect the ingress request.malformed for a non-JSON …
claude Sep 28, 2026
7f60828
feat(rpc): add a native client layer that follows no redirect
claude Sep 28, 2026
7a05b0e
fix(homepage): never follow a backend redirect with the contact secret
claude Sep 28, 2026
3a95f1f
test(e2e): read the social-events credential facts from the RPC messa…
claude Sep 28, 2026
9f210cb
test(receipts): read the settled receipt's fresh tag from the owner's…
claude Sep 28, 2026
8d322c6
docs(specs): record what social-events RPCs dropped from the HTTP con…
claude Sep 28, 2026
be8002f
test(dashboard): read Organization credential facts from the RPC mess…
claude Sep 28, 2026
29c5729
Merge branch 'fix/jr-directory' into fix/rpc-journeys
claude Sep 28, 2026
474161f
Merge branch 'fix/jr-admin' into fix/rpc-journeys
claude Sep 28, 2026
7127eaa
Merge branch 'fix/jr-recommend' into fix/rpc-journeys
claude Sep 28, 2026
3b8b931
Merge branch 'fix/jr-receipts' into fix/rpc-journeys
claude Sep 28, 2026
19d2ac7
fix(rpc): one endpoint predicate, a rule against path comparisons, an…
claude Sep 28, 2026
241d951
test(verification): name the problem or defect of a failed owner list…
claude Sep 28, 2026
1d8f7b7
fix(verification): keep the receipt rehearsal's script client until i…
claude Sep 28, 2026
0a200cb
fix(verification): pass the named Chromium to the Organization import…
claude Sep 28, 2026
351878e
refactor(database): construct Schema errors with make in recruitment,…
claude Sep 28, 2026
77ad35a
test(database): inline nested Effect.gen in recruitment Postgres suites
claude Sep 28, 2026
9fc826d
refactor(database): construct Schema errors and classes with make in …
claude Sep 28, 2026
703e258
refactor(database): compare explicitly in context folder conditions
claude Sep 28, 2026
9cea8e6
refactor(database): use concise arrow bodies in context folders
claude Sep 28, 2026
abd29f3
refactor(database): write explicit condition tests in recruitment, or…
claude Sep 28, 2026
b7f0931
refactor(database): use deterministic service keys in team-application
claude Sep 28, 2026
e1b8b00
fix(database): compare explicitly in conditions of the root database …
claude Sep 28, 2026
4aaf465
fix(domain): name each service by its deterministic key
claude Sep 28, 2026
2d088b7
test(database): inline nested Effect generators in context folder tests
claude Sep 28, 2026
828e5b2
fix(domain): construct schema errors with make, use concise arrows, a…
claude Sep 28, 2026
69fdf56
fix(database): construct Schema classes with make in the root databas…
claude Sep 28, 2026
93ea307
refactor(database): give exported recruitment, organization, placemen…
claude Sep 28, 2026
7a28323
test(database): inline nested Effect generators in the root database …
claude Sep 28, 2026
89f9faa
style(database): keep readable spacing after the rewritten statements
claude Sep 28, 2026
b55550d
fix(database): derive the service keys of the root database modules f…
claude Sep 28, 2026
326af72
test(database): keep one binding per name after inlining nested gener…
claude Sep 28, 2026
38151b0
fix(backend): satisfy the Effect rules in the receipt adapters
claude Sep 28, 2026
ac10443
fix(backend): satisfy the Effect rules in the onboarding and recruitm…
claude Sep 28, 2026
58a209c
fix(backend): satisfy the Effect rules in placements and the PostgreS…
claude Sep 28, 2026
75436d5
fix(dashboard): name schema class types instead of typeof queries
claude Sep 28, 2026
fa2a135
fix(docs): compare explicitly instead of relying on truthiness
claude Sep 28, 2026
f27b127
fix(database): give the exported functions of the root database modul…
claude Sep 28, 2026
c1a5137
refactor(database): give exported context folder functions a pipeable…
claude Sep 28, 2026
3a22072
fix(domain): give each exported multi-argument function a pipeable form
claude Sep 28, 2026
0779d10
Merge branch 'lint/db-context' into refactor/rpc-only
claude Sep 28, 2026
ac02a2d
Merge branch 'lint/db-root' into refactor/rpc-only
claude Sep 28, 2026
b1feba7
Merge branch 'lint/domain' into refactor/rpc-only
claude Sep 28, 2026
571812a
Merge branch 'lint/apps' into refactor/rpc-only
claude Sep 28, 2026
553bd6e
docs(constructs): regenerate the pages after the merged lint cleanup
claude Sep 28, 2026
8efb675
chore(lint): declare the proof, rehearsal, and example programs of do…
claude Sep 28, 2026
d54377d
fix(conventions): describe a dual construct by its data-first overload
claude Sep 28, 2026
9e10d7e
fix(e2e): audit the settled owner page in the golden reimbursement jo…
claude Sep 28, 2026
1bfd2fc
Merge branches 'fix/lint-followups' and 'fix/construct-dual' into ref…
claude Sep 28, 2026
7fc1201
build(tools): give every tool package Effect and the Bun platform, an…
claude Sep 28, 2026
9e2dc34
refactor(conventions): give the checks pipeable signatures and reposi…
claude Sep 28, 2026
fe90914
refactor(e2e): make the golden harness and its self-test lint clean u…
claude Sep 28, 2026
940b2e4
refactor(acceptance): run the substitutes probe as an Effect program …
claude Sep 28, 2026
b20b8d2
refactor(e2e): make the recording drivers, outbox driver, and receipt…
claude Sep 28, 2026
6e9e3df
refactor(domain): give the Schema decoders one JSON parameter and dro…
claude Sep 28, 2026
8ae141a
refactor(database): take one named input in the receipt persistence f…
claude Sep 28, 2026
83bdc6a
refactor(docs): run the page mirror as an Effect program, and registe…
claude Sep 28, 2026
f568567
refactor(scripts): run changelog, land, and the legacy profile check …
claude Sep 28, 2026
c2d0493
refactor(e2e): compare explicitly in the golden school-service driver…
claude Sep 28, 2026
f4c7b3e
refactor(acceptance): run the password recovery probe as an Effect pr…
claude Sep 28, 2026
798fc47
refactor(source-safety): scan the index as an Effect program
claude Sep 28, 2026
12b1bf2
refactor(acceptance): run the recommendation journey helpers as Effec…
claude Sep 28, 2026
5e90849
refactor(verification): make the delivery tests and the current assig…
claude Sep 28, 2026
eec2c6a
refactor(acceptance): run the onboarding probe as an Effect program
claude Sep 28, 2026
ff4f736
refactor(verification): give the organization import SQL observer and…
claude Sep 28, 2026
df366b3
docs(acceptance): render the guide of the new acceptance manifest
claude Sep 28, 2026
eb5c75b
refactor(verification): make the recommendation pre-upgrade fixture a…
claude Sep 28, 2026
43c11ab
Merge branch 'tools/t-acc' into refactor/rpc-only
claude Sep 28, 2026
6ee3ba9
Merge branch 'tools/t-rec' into refactor/rpc-only
claude Sep 28, 2026
96cfbff
Merge branch 'tools/t-golden' into refactor/rpc-only
claude Sep 28, 2026
664547e
Merge branch 'tools/t-e2e' into refactor/rpc-only
claude Sep 28, 2026
c1b3c7b
Merge branch 'tools/t-ver' into refactor/rpc-only
claude Sep 28, 2026
658a982
Merge branch 'tools/t-infra' into refactor/rpc-only
claude Sep 28, 2026
7ee5421
refactor(verification): make the current assignment rehearsal an Effe…
claude Sep 28, 2026
7462a62
refactor(conventions): read the repository and the justfile through E…
claude Sep 28, 2026
bbfddd8
refactor(verification): make the completion receipt proof an Effect p…
claude Sep 28, 2026
f18fc11
refactor(e2e): make the golden reimbursement journey an Effect program
claude Sep 28, 2026
a937287
refactor(scripts): run the heavy lock, measure-job, hook slots, and V…
claude Sep 28, 2026
3ae2dfc
fix(e2e): audit accessibility only on a settled page
claude Sep 28, 2026
30bd698
feat(oxlint): reject axe audits outside auditSettledPage
claude Sep 28, 2026
c77efcd
refactor(verification): make the receipt import rehearsal and its obs…
claude Sep 28, 2026
d00e284
refactor(e2e): make the native recruitment assignment journey an Effe…
claude Sep 28, 2026
cb9ec06
fix(verification): release withheld delivery sink requests before the…
claude Sep 28, 2026
a08f352
refactor(scripts): run the dev launcher, the model checks, and the pr…
claude Sep 28, 2026
7589d46
refactor(placements-docs): generate, check, and accept the reference …
claude Sep 28, 2026
0fd9440
refactor(acceptance): run the recommendation probe as one Effect program
claude Sep 28, 2026
88c5477
refactor(verification): make the unattended delivery recovery proof a…
claude Sep 28, 2026
1bd8752
Merge branch 'tools/w-ver' into refactor/rpc-only
claude Sep 28, 2026
13a523a
Merge branch 'tools/w-e2e' into refactor/rpc-only
claude Sep 28, 2026
2886dd9
Merge branch 'tools/w-infra' into refactor/rpc-only
claude Sep 28, 2026
7034b88
Merge branch 'tools/w-rec' into refactor/rpc-only
claude Sep 28, 2026
89f7e56
refactor(tools/postgres): run the disposable cluster construct as Eff…
claude Sep 28, 2026
5a2a920
docs(constructs): render the test-harness contracts of tools/postgres
claude Sep 28, 2026
af38c27
refactor(e2e): run the placement journeys and their golden observers …
claude Sep 28, 2026
7de87a5
Merge branch 'tools/x-postgres' into refactor/rpc-only
claude Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 9 additions & 9 deletions .agents/skills/effect-house/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: effect-house
description: House conventions for Effect v4 TypeScript in the vektorprogrammet mono-web repository. It names the shared constructs, the composition roots that select platform layers, the test platform and @effect/vitest conventions, the runtime bridges, typed HTTP problems, Effect-returning services, the lint configuration and the project rules with their FX ids, the module guides, and the Effect exception registry and its check, and it links to the file that owns each fact. Use when you write, review, or test TypeScript in mono-web, and before you choose a construct, a platform or test layer, a Promise bridge, or a lint suppression. It adds to the portable effect-* skills and the installed Effect guidance and does not restate them.
description: House conventions for Effect v4 TypeScript in the vektorprogrammet mono-web repository. It names the shared constructs, the composition roots that select platform layers, the test platform and @effect/vitest conventions, the runtime bridges, typed RPC problems, Effect-returning services, the lint configuration and the project rules with their FX ids, the module guides, and the Effect exception registry and its check, and it links to the file that owns each fact. Use when you write, review, or test TypeScript in mono-web, and before you choose a construct, a platform or test layer, a Promise bridge, or a lint suppression. It adds to the portable effect-* skills and the installed Effect guidance and does not restate them.
---

# effect-house: mono-web
Expand All @@ -17,7 +17,7 @@ The links are relative to this file, so the file is a complete entry point also
1. Read the `AGENTS.md` guide of the folder. Every app, package, and bounded-context folder has one. `just guides write` renders its first part from [docs/model/contexts.cml](../../../docs/model/contexts.cml), the `@construct` tags, and the package exports. Local invariants go below that part.
2. Search the one-line index [docs/constructs.md](../../../docs/constructs.md) for a construct that already owns the logic, read its contract on the page of its category, and use it.
3. Find the platform and test layers of the file's role: [references/composition-and-tests.md](references/composition-and-tests.md).
4. At an HTTP boundary, a service interface, or a Promise callback, read [references/boundaries.md](references/boundaries.md).
4. At an RPC boundary, a service interface, or a Promise callback, read [references/boundaries.md](references/boundaries.md).
5. If a rule cannot be followed, register an exception: [references/exceptions.md](references/exceptions.md).

## Constructs (FX002)
Expand All @@ -30,14 +30,14 @@ Reading about a construct discloses in three steps, each only when you need it:
| Ports for the servers of a journey | `reserveLoopbackPorts`, `loopbackPortFree` ([test-harness][test-harness]) | `anti-slop/no-port-probe` |
| Instants in journey fixtures | `journeyClock`, `admissionJourneyClock` ([test-harness][test-harness]) | `anti-slop/no-literal-window-instant` |
| Canonical JSON, digests, SQL JSON values | `canonicalJson`, `canonicalJsonBytes`, `sha256Hex`, `canonicalJsonValue` ([digest]) | `anti-slop/no-json-text-parameter` |
| The JSON text of an HTTP representation | `jsonText` ([http-problem]) | `effecttsgo/prefer-schema-over-json` |
| The JSON text of a representation | `jsonText` ([rpc-problem]) | `effecttsgo/prefer-schema-over-json` |
| An advisory lock | `lockAdvisory` with a registered `AdvisoryLockKey` ([sql-lock]) | `anti-slop/no-raw-advisory-lock-sql` |
| The Promise callbacks of a library | The pattern of `makeBetterAuthCallbackRunner`, until a second runner makes it a construct ([runtime bridges][runtime-bridges]) | review-only |
| The class of a request that a journey saw | `isNativeRequest`, `addressesAnyRoute` ([request-ledger]) | review-only |

[test-harness]: ../../../docs/constructs/test-harness.md
[digest]: ../../../docs/constructs/digest.md
[http-problem]: ../../../docs/constructs/http-problem.md
[rpc-problem]: ../../../docs/constructs/rpc-problem.md
[sql-lock]: ../../../docs/constructs/sql-lock.md
[runtime-bridges]: references/boundaries.md#runtime-bridges-fx003-fx006
[request-ledger]: ../../../docs/constructs/request-ledger.md
Expand All @@ -47,7 +47,7 @@ Reading about a construct discloses in three steps, each only when you need it:
- **Composition roots select the platform (FX003).** Only a composition root provides `BunServices.layer` or another platform layer; packages and adapters require platform services and stay portable. Enforcement: `effect/no-cross-runtime` against the roles and platforms that [oxlint.config.ts](../../../oxlint.config.ts) declares. Details: [references/composition-and-tests.md](references/composition-and-tests.md).
- **Tests are Effect programs (FX015).** `@effect/vitest`, one Effect per test, suite resources as `layer(L, { excludeTestServices: true, timeout })`, and the test platform of the package (`TestPlatform`, and `DatabaseTestLive` in database suites). Enforcement: `effecttsgo/async-function` in core code, `anti-slop/no-module-mocking`. Details: [references/composition-and-tests.md](references/composition-and-tests.md).
- **Services return Effects (FX003).** No Promise interface between Effect layers. A program runs only at a composition root or a runtime bridge. Enforcement: `effecttsgo/async-function` and `effecttsgo/new-promise` in core code, `effect/no-premature-execution`. Details: [references/boundaries.md](references/boundaries.md).
- **HTTP failures are typed problems (FX004, FX005).** A handler decodes with the contract schemas and answers with a problem that the endpoint declares; `ProblemBoundaryLive` is the only consumer of a Cause. Enforcement: `just check-types`, which checks the endpoint unions and asserts the HTTP contract. Details: [references/boundaries.md](references/boundaries.md).
- **RPC failures are typed problems (FX004, FX005).** The RPC server decodes each payload with the contract schema, and a handler answers with a problem that its RPC declares; `ProblemBoundaryLive` is the only consumer of a Cause. Enforcement: `just check-types`, which checks the declared unions, and [packages/rpc/test/contract.test.ts](../../../packages/rpc/test/contract.test.ts), which checks that every RPC runs inside the defect boundary. Details: [references/boundaries.md](references/boundaries.md).
- **Every exception is registered (FX012).** A suppression of an Effect rule names its entry in [docs/effect-exceptions.json](../../../docs/effect-exceptions.json). Enforcement: `just exceptions`. Details: [references/exceptions.md](references/exceptions.md).

## Lint configuration
Expand All @@ -58,7 +58,7 @@ Reading about a construct discloses in three steps, each only when you need it:
- The last group that matches a file decides every `effect/*` rule for it, so a test file does not inherit the rules of its source group. Groups use plain globs, because Oxlint has no extglob, and run from broad sources to narrow exceptions. [tools/conventions/tests/oxlint-groups.test.ts](../../../tools/conventions/tests/oxlint-groups.test.ts) guards that shape; keep it when you change a group.
- A new composition root or adapter joins the group of its role and platform, such as the Bun composition-root group; it gets no suppression and no `off` override. The Bun groups admit the Node modules that Bun implements (`bunNodeModules`), and their files import `process` from `node:process` and `Buffer` from `node:buffer`, because the rule admits no Node globals on `bun`.
- The `effecttsgo/*` rules of the Effect language service come from the `recommended` and `correctness` presets of `@effect/tsgo`, and they make `just lint` type-aware. Every rule is an error, and so is every rule of Oxlint's correctness category, the type-aware ones included. The `effectNative` rules replace platform APIs with Effect services, so they run only in the core Effect packages that `coreEffectFiles` lists; the other apps, packages, and tools are not Effect programs. `oxlint-groups.test.ts` guards these severities and that scope too. The language-service plugin in `tsconfig.json` keeps refactors and quick info in the editor and emits no diagnostics, so `tsc` reports none. Count sites with `just lint`, never with grep or `tsc`.
- Fix a finding with the rule's own fix, in the house form where one exists: `EffectSdkFailure<Group, Operation>` of `@vektorprogrammet/sdk/effect` is the failure channel of a generated SDK operation, `formText` ([apps/dashboard/app/lib/form-text.ts](../../../apps/dashboard/app/lib/form-text.ts)) reads a form field, and `DateTime` with `normalizeRfc3339Instant` ([packages/domain/src/time.ts](../../../packages/domain/src/time.ts)) handles instants. JSON goes through the constructs above.
- Fix a finding with the rule's own fix, in the house form where one exists: the declared `Problem` union of an RPC is the failure channel of its client call, and `callBrowserNative` ([apps/dashboard/app/lib/browser-native.ts](../../../apps/dashboard/app/lib/browser-native.ts)) adds `NativeAnswerInvalid` for an answer outside the contract, `formText` ([apps/dashboard/app/lib/form-text.ts](../../../apps/dashboard/app/lib/form-text.ts)) reads a form field, and `DateTime` with `normalizeRfc3339Instant` ([packages/domain/src/time.ts](../../../packages/domain/src/time.ts)) handles instants. JSON goes through the constructs above.

## Project rules and checks

Expand All @@ -81,7 +81,7 @@ The portable skills cite the `effecttsgo/*` rules. The rules and checks of this
| The rules of the constructs table | FX002 | Logic that a listed construct owns |
| `just exceptions` | FX012 | A suppression without a registered exception, and an entry that no longer matches its sites or versions |
| `just constructs` | FX002 | A construct page that differs from the `@construct` tags and their JSDoc, a construct without its contract tags or annotations, and a construct that fewer than two modules share |
| `just check-types` | FX004 | A type error, and an HTTP contract that differs from the one that it regenerates |
| `just check-types` | FX004 | A type error, such as a failure that an RPC does not declare |
| `packages/database/src/migration-registry.test.ts`, `just migration-hashes` | FX010 | An applied migration whose checksum changed, and a migration id, position, or file that the registry lacks |

`effect/no-native-promise-control-flow` and `effect/no-untyped-throw` are strict rules, so they run in every group whose role they cover. `effect/no-raw-json-parse` runs where a group declares the `external-data` boundary: the runtime adapters of `apps/backend` and `packages/database`.
Expand All @@ -97,8 +97,8 @@ The portable skills leave these facts to the overlay:
- **Composition roots, test platform, and runtime bridges:** [references/composition-and-tests.md](references/composition-and-tests.md) and [references/boundaries.md](references/boundaries.md).
- **Layer names:** `<Service>Live` for a live layer, such as `DatabaseLive`, `ContentManagementLive`, and `ReceiptFileStoreLive`, and `DatabaseTest()` for the PGlite database of a test. Services have no `layer` or `layerTest` statics.
- **Migrations and the test database:** `packages/database/migrations/NNNN-<name>.sql`, frozen by `packages/database/migrations/checksums.json`; `just migration-hashes write` records a new one. A test takes `DatabaseTest()` or a disposable cluster (`withDisposablePostgres`).
- **Drift check of generated artifacts:** `just check-types` runs the `generate` scripts of `packages/http-api` and `packages/sdk` before the type checks, and asserts the HTTP contract.
- **Test command and type-test tool:** `bun run --cwd <package> vitest run <file> --no-file-parallelism --maxWorkers=1`. Type tests use `expectTypeOf` of Vitest, as [`packages/sdk/src/__tests__/generated-native-client.test.ts`](../../../packages/sdk/src/__tests__/generated-native-client.test.ts) does.
- **Drift check of generated artifacts:** none. Nothing is generated from the RPC contract: handlers and clients derive from its groups, and [packages/rpc/test/contract.test.ts](../../../packages/rpc/test/contract.test.ts) checks the operation IDs, AccessSpecs, and defect boundary of every RPC.
- **Test command and type-test tool:** `bun run --cwd <package> vitest run <file> --no-file-parallelism --maxWorkers=1`. Type tests use `expectTypeOf` of Vitest, as [`packages/domain/src/organization/authority-evidence.test.ts`](../../../packages/domain/src/organization/authority-evidence.test.ts) does.
- **Foldkit house form:** one folder per bounded context in `apps/dashboard/app/foldkit`, each with its guide, and one Model per stateful workflow. Tests are `update.test.ts`, `view.test.ts` with `Scene` of `foldkit/test`, and `update.property.test.ts`. `anti-slop/no-unkeyed-command-row` runs there. `foldkit/prefer-command-mapmessage` does not, because `oxlint.config.ts` configures no Foldkit plugin.

## Done means
Expand Down
10 changes: 5 additions & 5 deletions .agents/skills/effect-house/references/boundaries.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Services, HTTP boundaries, and runtime bridges
# Services, RPC boundaries, and runtime bridges

## Services return Effects (FX003)

Expand All @@ -22,12 +22,12 @@ The pattern to copy is `makeBetterAuthCallbackRunner` in [packages/database/src/
A new library of this kind gets its own runner, built the same way in the layer that owns the library. Do not run a program with `Effect.runPromise` inside a callback.
The runner is no tagged construct while it is the only one, because a construct needs two consumers outside its own module. The second runner makes it one: move the logic that both share into one runner, tag it `@construct runtime-bridge`, and declare that category again in [tools/conventions/src/constructs.ts](../../../../tools/conventions/src/constructs.ts).

## HTTP boundaries (FX004, FX005)
## RPC boundaries (FX004, FX005)

[packages/http-api](../../../../packages/http-api) owns the contracts; the backend derives its transport from them, and `just check-types` asserts the generated HTTP contract.
[packages/rpc](../../../../packages/rpc) owns the contract ([docs/architecture.md](../../../../docs/architecture.md#rpc-contract-and-ingress)); the backend implements each context's group, and every client derives from the same group. Nothing is generated.

- A handler decodes its input with the contract schemas: `readJsonBody`, `decodeRequest`, and `strictOutput` ([docs/constructs/http-problem.md](../../../../docs/constructs/http-problem.md)).
- A failure is a `Problem`. `Problem.make(code)` takes only the code; `NativeProblemRegistry` in [packages/http-api/src/http-semantics.ts](../../../../packages/http-api/src/http-semantics.ts) owns its status and body. An endpoint declares its closed union with `problemUnion`.
- The RPC server decodes a payload with the contract schema before the handler runs. A handler decodes its success value with `strictOutput` ([docs/constructs/rpc-problem.md](../../../../docs/constructs/rpc-problem.md)).
- A failure is a `Problem`. `Problem.make(code)` takes only the code; `NativeProblemRegistry` in [packages/rpc/src/problem.ts](../../../../packages/rpc/src/problem.ts) owns its status and body. An RPC declares its closed union with `problemUnion` and takes it as `error: rpcProblems(...)`.
- Each context maps its domain failures once with `problemMapper`, as `contentProblems` and `receiptProblems` do, and declares the mapper's type as `ProblemMapper<Failure, Cases>`, where `Cases` is the type of its cases. A failure that an operation cannot produce is marked with `unreachable`.
- `ProblemBoundaryLive` is the only consumer of a Cause. A handler does not catch defects or render causes itself.
- A JSON representation is written with `jsonText`, which encodes through Schema and writes the bytes that `JSON.stringify` wrote.
Expand Down
18 changes: 9 additions & 9 deletions .claude/rules/constitution.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Monoweb Project Conventions

## SDK Conventions
## RPC Contract Conventions

When working on `packages/sdk/`:
When working on `packages/rpc/`:

- Domain methods speak the ubiquitous language: `approve()` not `updateStatus("refunded")`
- Types are Schema.Class — inferred via `Schema.Schema.Type`, never hand-written interfaces
- Effect is an internal detail — consumers see plain promises via `createClient()`
- Every new domain type needs a Schema round-trip test (`encode → decode === original`)
- Adapter transforms (Hydra unwrap, status mapping, date parsing) live in `src/adapter/`
- `src/domains/` contain the domain method factories — one file per domain
- Dual export: `@vektorprogrammet/sdk` (promises) + `@vektorprogrammet/sdk/effect`
- The RPC tag is the operation ID (`social-events.create`). Command receipts store it
- Payload and success are Schemas; the error is `rpcProblems(<Operation>Problem)`, a closed `problemUnion` of registry codes
- Types are inferred from the Schemas, never hand-written interfaces
- Each RPC takes at most one credential middleware (none for anonymous access) and exactly one `withAccessSpec(...)`; `packages/rpc/test/contract.test.ts` checks the AccessSpec, the tag grammar, and the defect boundary
- A contract re-exports only the schemas its own RPCs use; clients import other domain values from `@vektorprogrammet/domain`
- Every client derives from the group: `RpcClient` in Effect code, `callNative`, `callBrowserNative`, and `callHomepageNative` in the apps, and `nativeScriptClient` from `@vektorprogrammet/rpc/script` in journeys and probes. No client is generated or written by hand
- `packages/rpc/src/social-events.ts` is the precedent to copy
4 changes: 2 additions & 2 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
},
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read -r f; if [[ \"$f\" == *.ts && \"$f\" == */packages/sdk/* ]]; then cd packages/sdk && bunx tsc --noEmit 2>/dev/null | tail -3; fi; }",
"command": "jq -r '.tool_input.file_path' | { read -r f; if [[ \"$f\" == *.ts && \"$f\" == */packages/rpc/* ]]; then cd packages/rpc && bunx tsc --noEmit 2>/dev/null | tail -3; fi; }",
"asyncRewake": true,
"statusMessage": "Checking SDK types..."
"statusMessage": "Checking RPC contract types..."
}
]
}
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ jobs:
just constructs
just guides
just exceptions
# Type checks run the Turbo `generate` tasks, which derive and assert the HTTP contract
# artifacts. `just check` repeats the fast checks above, as the pre-push hook runs it.
- name: Check layout, constructs, guides, Effect exceptions, source safety, format, lint, types, and HTTP contract
# `just check` repeats the fast checks above, as the pre-push hook runs it.
- name: Check layout, constructs, guides, Effect exceptions, source safety, format, lint, and types
timeout-minutes: 12
run: just check
Loading
Loading