Skip to content

Fix/effect v4 phase 1 service shape#55

Merged
Makisuo merged 9 commits into
mainfrom
fix/effect-v4-phase-1-service-shape
May 20, 2026
Merged

Fix/effect v4 phase 1 service shape#55
Makisuo merged 9 commits into
mainfrom
fix/effect-v4-phase-1-service-shape

Conversation

@Makisuo
Copy link
Copy Markdown
Owner

@Makisuo Makisuo commented May 20, 2026

No description provided.

Makisuo and others added 6 commits May 21, 2026 00:31
Continues the v3→v4 service-shape sweep started in earlier "fix" commits:

* `lib/effect-cloudflare`
  - `WorkerEnvironmentLive` (standalone export) → `WorkerEnvironment.layer`
    (static on the class), per the v4 reference's "primary layer is `layer`"
    rule. `layerFromEnvRecord` factory stays as an external helper since it's
    parameterised by an env record, not a singleton.
  - `WorkerConfigProviderLive` → `WorkerConfigProviderLayer` (drop the v3
    `Live` suffix; the symbol is still a free-standing Layer because there's
    no Service class to hang it off of).

* `apps/api`
  - `AuthorizationLive` binding → `ApiAuthorizationLayer` (file renamed
    accordingly). It's a `Layer.effect(CurrentTenant.Authorization, …)`, not a
    service class, so it stays a top-level const but drops the v3 suffix.

* Consumers updated:
  - `apps/api/src/worker.ts`
  - `apps/alerting/src/worker.ts`
  - `apps/api/src/app.ts`

Verification:
- `bun typecheck` — 19/19 packages clean.
- Service tests still pass (48/48 across AlertsService, AuthService,
  OrgIngestKeysService, DashboardPersistenceService).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pullfrog
Copy link
Copy Markdown

pullfrog Bot commented May 20, 2026

This run croaked 😵

The workflow encountered an error before any progress could be reported. Please check the link below for details.

Pullfrog  | Rerun failed job ➔View workflow run | via Pullfrog𝕏

…tIntBetween

`computeRetryDelayMs` in `AlertsService` used `Math.random()` for the 0–999 ms
jitter added to the exponential backoff. That's two problems at once:

  1. Non-deterministic in tests — there's no way to pin the jitter when
     asserting retry timestamps.
  2. Not seeded from Effect's fiber-local Random service, so the value can't
     be driven by `Effect.withRandom` or replaced by a test seed.

Switching to `yield* Random.nextIntBetween(0, 1_000)` fixes both. Required
converting the helper to an `Effect.fn` and adjusting the single call site
(`processQueuedDeliveries`, currentTime + delay) to `yield*` the result.

Verification:
- `bun typecheck` clean
- 19/19 AlertsService tests pass

Deferred to a later commit:
- `AlertRuntime.now`/`makeUuid`/`fetch`/`deliveryTimeoutMs` still indirect
  through the runtime service. Migrating `now` to `Clock.currentTimeMillis`
  is blocked on tests adopting `TestClock` (Phase 8 of the v4 sweep).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Makisuo and others added 2 commits May 21, 2026 00:59
…th/BucketCache

Replaces direct wall-clock reads in three services with
`yield* Clock.currentTimeMillis`, threading time through Effect's Clock so
tests can pin it via `TestClock`. No behaviour change; same semantics with
testable substitution available later when test layer is migrated.

* `ApiKeysService`
  - `create.now` (insert createdAt + computed expiresAt)
  - `revoke.now` (revokedAt)
  - `resolveByKey` expiration check (only reads clock when an expiresAt is set)
  - `touchLastUsed` lastUsedAt

* `AuthService`
  - JWT `nbf`/`exp` validation in `verifyHs256Jwt`
  - Self-hosted login `iat` stamp
    Both still divide by 1000 because RFC 7519 uses epoch-seconds.

* `BucketCacheService`
  - Flux-window boundary (`fluxBoundaryMs`) in `getOrComputeBuckets`

Verification:
- `bun --filter=@maple/api typecheck` clean
- 32/32 AuthService + BucketCacheService tests pass

Deferred (still pending in Phase 3c):
- AlertRuntime.now (blocked on TestClock test migration)
- CloudflareLogpushService, ScrapeTargetsService, ServiceMapRollupService,
  DigestService, NotificationDispatcher, ErrorsService, HazelOAuthService,
  DashboardPersistenceService, EdgeCacheService memory backend,
  QueryEngineService latency, WarehouseQueryService TTL — same Clock
  migration, ~40 remaining sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Makisuo Makisuo merged commit 7680f2a into main May 20, 2026
1 of 2 checks passed
Makisuo added a commit that referenced this pull request May 21, 2026
`SERVICE_INSTANCE_ID = crypto.randomUUID()` ran at module top-level, which
Cloudflare Workers reject during upload validation (error 10021: "generating
random values are not allowed within global scope"). This broke prd deploys
once PR #55 forced the api worker to re-upload.

Lazily memoize via getServiceInstanceId() so the randomUUID() call happens on
first use inside a request handler. Same per-isolate-stable semantics; the ID
is still generated once per process and reused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant