Repository navigation
feat(repo): give the site worker one d1 database, emulated locally under pnpm dev - #63
Merged
Merged
Conversation
systemfsoftware-maker
added this pull request to stack #61
October 6, 2026 23:13
systemfsoftware-maker
force-pushed
the
lake1/http-api
branch
from
October 6, 2026 23:46
16525e5 to
4e8103c
Compare
systemfsoftware-maker
force-pushed
the
lake1/d1
branch
from
October 6, 2026 23:46
aeeacad to
531fe57
Compare
systemfsoftware-maker
force-pushed
the
lake1/d1
branch
2 times, most recently
from
October 7, 2026 00:35
a8124fa to
d2b088a
Compare
check:ci no longer runs stryker. The release gate on push to main plans one shard per workspace package that declares a mutation script, refuses an empty set, and runs each shard at break 100 on the fleet with its incremental report cached. The checker drops prioritizePerformanceOverAccuracy, which stryker-js 15 removes. Operator approval: Kiro, 2026-10-05 (GATE1)
The plan and per-package mutation jobs move from the self-hosted fleet, which admits only private repositories, to ubuntu-latest. Mutation stays one parallel job per package. Operator approval: Kiro, 2026-10-05 (GATE1)
A package with a mutation script whose mutate globs match nothing reports zero mutants and passes a break-100 threshold vacuously (review finding #9). Each package now declares its globs once, as stryker.mutate in package.json; its Stryker config reads them and the release gate's shard planner expands them. The planner fails red at plan time naming the package, its directory and its globs when they match no file, including a package with no declared globs. Its Deno tests are ordinary tests: a turbo root task, test:scripts, runs them through the dev shell's deno, and both pnpm test and check:ci run it, so a local check:ci covers the planner exactly as CI does
…ns to mutate A decision is a *.workflow.ts file. When no workspace package has one, the planner emits an empty shard list and a 'No decisions to mutate' notice, and the mutation job is skipped. When decisions exist and no package declares a mutation script, it still refuses the empty set, naming how many decisions went unmutated. Kiro ruling, 2026-10-06
Every catalog entry is an exact version: effect 4.0.1, the systemfsoftware toolchain on its Effect 4 stable majors (recommended preset 4.0.0, stryker-js 15.0.1, vitest 2.0.0, gherkin-spec 7.0.1) and current tooling. minimumReleaseAge 1440 is explicit, so the policy is strict; the exclude list holds the effect name patterns and one exact entry per resolved systemfsoftware package. oxlint-tsgolint stays 7.0.2001, the exact peer the presets require. turbo 2.11 writes an agent guidance block into AGENTS.md unless agentGuidance is false, so turbo.json opts out. Grader package majors move here because they require Effect 4 stable (CONST-W3 declared)
oxlint.shared.ts, vitest.shared.ts and stryker.shared.ts hold the house settings; each package config extends them and declares only its own mutate set and aliases. Both lint overrides are gone: preset 4.0.0 already accepts Gherkin step bodies and build-config imports. The root lint file is named oxlint.shared.ts so lint-staged's nearest-config walk never treats the repository root as a package. Turbo inputs track the shared files. Operator approval: Kiro, 2026-10-05 (GATE1)
…root Root tsconfig.base.json extends the bundler/dom preset and allows exactly effect/http through the effect language service. effect 4.0.1 ships HTTP only as unstable and global-fetch-in-effect bans the fetch alternative. Operator approval: Kiro, 2026-10-05 (GATE1)
One Cloudflare Worker serves the TanStack Start site, defined with Alchemy and run locally by pnpm dev through alchemy dev. The e2e journeys run against that local app
bin/journeys starts the app with pnpm dev, runs the journeys against it and stops it with one SIGINT to its process group, so alchemy's local sidecar is not orphaned. The dev port is strict, so a stale server fails the run instead of moving it to another port
… site worker
The site Worker routes /api/ to an Effect HttpApi: GET /api/health answers {"status":"ok"}, and /api/openapi.json serves the OpenAPI 3.1 document HttpApiBuilder generates. Every other path still goes to TanStack Start under the strict CSP. The root unstable-API opt-in gains exactly effect/http-api, where Effect 4.0.1 ships HttpApi (Kiro ruling, 2026-10-06). A journey reads the API description and calls the health check against pnpm dev
…der pnpm dev alchemy.run.ts declares a D1 database and binds it to the Worker as DB. alchemy dev creates and serves it locally with no cloud account, and each cloud stage gets its own. The Worker reads the binding from cloudflare:workers, typed through Alchemy's InferEnv of the Site, so a binding renamed on one side fails the typecheck. The Health procedure now answers ok only when the database answers SELECT 1, and the home page shows unreachable when it does not. Queries go through the D1 binding itself, with no effect/sql or @effect/sql-d1
…e release gate In an adopter's copy, never the template, a same-repo pull request deploys as its pr-<N> stage, gets its URL in one PR comment, runs the e2e journeys against it and is destroyed when it closes. Main deploys production once every mutation shard passes, to SITE_DOMAIN when that repository variable is set. The deployed journeys run through pnpm journeys:deployed, whose sandbox reaches only the site and gets no Cloudflare credentials
Ryan ruling via Kiro 2026-10-07: one RpcGroup served by RpcServer over HTTP at /api/rpc, a typed RpcClient in the page; a Health procedure replaces /api/health and the OpenAPI document goes. The home page shows the Worker's health and a browser journey reads it. The unstable-API opt-in lists effect/rpc instead of effect/http-api
packages/starter and every trace of it leave in one commit: the README sections that describe it, the trusted-publisher note in .changeset, and the catalog entries no remaining package uses (rimraf, tsdown). npm publishing goes with it. The release job keeps capture, release-note assertion, tagging and GitHub Releases and drops build, OIDC and pnpm publish. A version in a manifest with no matching <name>@v<version> tag is owed; no script queries registry.npmjs.org. Operator approval: Kiro, 2026-10-05 (release.yml)
The Worker draws a fresh nonce per request, hands it to TanStack Start for its scripts and sends a strict Content-Security-Policy with Trusted Types. A browser journey in Chromium loads the home page under that policy with no violations, and removing the Trusted Types directive fails it
…packages from nix Every script that runs dependency code (install, build, test, dev, the journeys and the git hooks) goes through prm's sandbox launcher, systemfsoftware packages come from the systemfsoftware flake as tarballs, and the pnpm store is built from per-tarball fetches. check:sfs-sources stays red on the two Stryker packages, which still resolve from npm until systemfsoftware/stryker-js-effect ships them as flake outputs
pnpm run deploy deploys the Worker with Alchemy to the adopter's own Cloudflare account through bin/cloud, the one place Cloudflare credentials enter the sandbox; cloud stages keep their state in Cloudflare. A production domain is adopter configuration: SITE_DOMAIN, read by alchemy.run.ts on the prod stage. The template holds no credentials
With no decisions to mutate the release gate skips the mutation job, which used to skip the deploy that needs it. Production now deploys when the plan passed and the mutation job passed or was skipped, and never when either failed or the run was cancelled
systemfsoftware-maker
force-pushed
the
lake1/http-api
branch
from
October 7, 2026 01:01
1f24957 to
907bdac
Compare
systemfsoftware-maker
force-pushed
the
lake1/d1
branch
from
October 7, 2026 01:01
6070a3d to
79fdb88
Compare
Conductor rulings, cycles 74 and 77: pnpm-release-management main 537d17c carries #14, #20 (the consumer store) and #24 (the linked-worktree change), so the starter's own copy of that change (nix/patches/sandbox-linked-worktree-git.patch) and its applyPatches wiring go. pnpm-release-management becomes a direct input on main, locked to 537d17c; systemfsoftware follows it, and its nixpkgs, comment-checker and importPnpmLock follow the starter's
starter-verify c73: withoutSandboxOnPath removed only the first directory that held sandbox, so with two launchers on PATH the hooks still found one and the refusal step failed falsely. It now drops every PATH entry that provides sandbox. Two launchers on PATH: the old helper fails the step, the new one passes; with the hooks' sandbox prefix stripped, the step fails
Conductor ruling, cycle 83: stryker-js-effect main f06f244 (#196) publishes its 17 members as tarballs with an index.json. The flake adds it as an input (locked to f06f244, following the starter's nixpkgs, comment-checker, importPnpmLock, pnpm-release-management and systemfsoftware), and .sfs-deps now holds both flakes' tarballs with one merged index.json. Every @systemfsoftware/stryker-* member is a file:.sfs-deps catalog entry with an override, the same mechanism as the systemfsoftware packages, plus one for the stryker-js-vm-runner npm alias that stryker-js 17.0.2 declares, so check:sfs-sources passes with no npm-sourced @systemfsoftware/* package
Contributor
There was a problem hiding this comment.
Verified: 9/9 green on 85438ee, diff = d1's 13 files, 0 threads, hunt clean.
systemfsoftware-maker
added a commit
that referenced
this pull request
Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lake 1, new layer 2 (Kiro ruling, 2026-10-06), stacked on #62. Restacked onto the RPC layer.
apps/site/alchemy.run.tsdeclaresCloudflare.D1.Database('Database')and binds it to the Worker asDB.alchemy devcreates and serves it locally (underapps/site/.alchemy/local) with no cloud account; each cloud stage gets its own database.apps/site/src/cloudflare-env.d.tstypescloudflare:workers'envfrom Alchemy'sInferEnvof the Site, so renaming the binding on one side fails the typecheck.healthprocedure runs one D1 probe (env.DB.prepare('SELECT 1')) and hands its outcome tosrc/api/check-health.workflow.ts, a pureWorkflow.makedecision: healthy when the probe answered, otherwise the tagged refusalDatabaseUnreachable, which is the procedure's typed error. The home page showsunreachableon any failure, defects included.effect/sql, no@effect/sql-d1.Gate after the cycle 52 restack (Linux only)
Gate at
7f70d04, clean worktree, Linux, sandboxed:CI run 37573598160 on
7f70d04: 6 of 7 jobs pass (format, lint, typecheck, test, dist, journeys);check (sfs-sources)fails, the same red as the local gate above.Sabotage: renaming the binding in
alchemy.run.tsfails the typecheck (Property 'DB' does not exist on type 'Env'). Breaking the query (SELECT FROM) fails the health journey withWorker health: unreachable.Cycle 35: the site's own test (Kiro rulings)
After F5 dropped
--passWithNoTests, the guestbook's property test was the site's only test, so removing the guestbook leftcheck:cired on@endgame/site#test(No test files found). Ruling: the site gets a test of its own that survives removal, as a pure decision with a property, on this layer.apps/site/src/api/check-health.workflow.ts: commandCheckHealth { probe: ProbeAnswered | ProbeUnanswered }, decisionHealthy(private to the file), refusalDatabaseUnreachable. The handler only runs the probe and calls it.apps/site/src/api/__tests__/check-health.workflow.property.test.ts:∀c_Healthy_=ProbeAnswered, drawing the command from its production schema: the workflow succeeds exactly when the probe answered, and otherwise refuses withDatabaseUnreachable.vitest,@systemfsoftware/vitest, the four@systemfsoftware/stryker-*packages,@systemfsoftware/effect-cell-types,vitest.config.ts,stryker.config.ts, thetest(vitest run) andmutationscripts, andstryker.mutate: ["src/**/*.workflow.ts"]. The release-gate planner now plans@endgame/site(packages=["@endgame/site"]), andcheck:sfs-sourcescounts 11 packages here, the F1 gap that closes with stryker-js-effect#196's flake.Gate after cycle 83 (every
@systemfsoftware/*package from our flakes, #52)Gate at
89b434f, clean worktree, Linux, sandboxed:CI run 37676551794 on
89b434f: all 7 jobs pass,check (sfs-sources)included. Theexit 1gates above are from before the stryker packages came from the stryker-js-effect flake.