Skip to content

fix(effect-bun-test): restore the v3 log-level labels and cover command/prop - #2

Merged
jfspencer merged 1 commit into
mainfrom
fix/log-capture-v3-labels-and-harness-coverage
Aug 18, 2026
Merged

jfspencer merged 1 commit into
mainfrom
fix/log-capture-v3-labels-and-harness-coverage

Conversation

@ToxicBakery

Copy link
Copy Markdown
Contributor

main already carries the Effect v4 flip (catalog effect@4.0.0-rc.109) and it is green. This closes the gaps found while validating that flip against its downstream consumer, so the tree is ready to tag as the first v4 release.

1. logLevelLabel was dropped, and it is load-bearing

v4 models a log level as a bare string union member — 'Warn', 'None' — where v3 exposed an object whose label was upper case: 'WARN', 'OFF'. Every level differs in case, and the off sentinel differs in spelling.

That makes it a silent break rather than a loud one. A caller that kept the v3 comparison does not fail:

const errors = captured.filter((l) => l.level === 'ERROR'); // always []
expect(errors).toHaveLength(0);                             // vacuously true

logLevelLabel is restored as an export from ./log-capture and applied inside makeLogCapture, so the package agrees with itself: the helper a caller uses to label its own Logger.make sink produces the same strings the built-in capture records.

Consumer impact — this is the reason it matters. In the monorepo that consumes these tarballs, logLevelLabel is imported by 23 files across apps/xavier, apps/sofa, apps/cerebro and tools/ultravisor. Without this export they do not resolve. makeLogCapture itself has exactly one importer, and it discards entries, so restoring the upper-case labels breaks nothing and un-breaks the 23.

2. src/command.ts and prop had no tests, and both were rewritten wholesale

command.ts moved onto effect/unstable/process (CommandExecutor.ProcessChildProcessSpawner.ChildProcessHandle) and prop moved onto Schema.toArbitrary. Neither rewrite is observable to tsc: a schema-to-arbitrary bridge that produced nothing, or a property body that never ran, would still typecheck and still report as passing.

Both are now covered (__tests__/command.test.ts, __tests__/prop.test.ts), including a case that counts property-body invocations so a silently inert prop fails instead of passing.

Everything below was checked against the running v4 runtime rather than inferred:

  • prop derives values for the array, record, it.effect.prop and it.live.prop forms, for scalar and composite schemas, and for raw FastCheck arbitraries.
  • The scripted-subprocess doubles serve exit codes, stdout, stderr and the new all stream, and all concatenates as a stream rather than string-joining.
  • An unmatched spawn is a typed PlatformError (so Effect.catch sees it), and the violation is also replayed when the layer scope closes — so a test that swallowed the error still fails.
  • The it.effect environment installs no logger, so a passing test stays quiet.

No behaviour was changed in command.ts or the prop machinery; both were already correct.

Deliberately not changed

testConfigLayer resolves nested paths with _ (via ConfigProvider.fromEnvRecord) rather than v3's ., and rejects empty-string values. That divergence is documented and pinned by a test, and it has zero consumers — the only import from ./env anywhere downstream is scopedEnv. Left alone.

Verification

bun run dod      tsc + effect diagnostics + 292 tests + biome   green
bun run test:e2e 16 pass, against freshly packed tarballs       green

Per-package: root 91, effect-bun-test 103 (was 72), bun-svelte-test 45, fixture-residue 33, effect-test-kit 12, uuid-effect 8. Zero failures.

Note for whoever cuts the release

@packages/uuid-effect is not a test-only package — it has ~110 importers downstream and 62 of them are src/, i.e. production code. Its v4 change is one line in src/tag.ts (Context.TagContext.Service) and the service key string is unchanged, so the DI identity is preserved, but the release should be treated as a production dependency rather than a test-harness bump.

The published v0.2.1 tarballs cannot load under v4 at all: they ship TypeScript source against a ^3.22.1 peer, and 8 of the 11 Effect modules they import no longer resolve. So this release is the unblock, not an optimisation.

No version bump is included here — that belongs to the release commit.

…nd/prop

The v4 migration is otherwise complete and green, but it dropped one public
export and left the two largest v4 rewrites untested.

`logLevelLabel` is gone from `log-capture`, and `CapturedLog.level` now carries
the raw v4 level. v4 models a log level as a bare string union member ('Warn',
'None') where v3 exposed an object whose `label` was upper case ('WARN', 'OFF').
Every level differs in case and the off sentinel differs in spelling, so a
caller that kept `level === 'WARN'` does not fail — it matches nothing and
quietly asserts nothing. A `filter(l => l.level === 'ERROR')` guarding a
`toHaveLength(0)` becomes vacuously true.

`logLevelLabel` is restored as an export and applied inside `makeLogCapture`, so
the package agrees with itself: the helper a caller uses to label its own
`Logger.make` sink produces the same strings the built-in capture records.

`src/command.ts` and the `prop` family had no tests at all, and both were
rewritten wholesale for v4 — `command.ts` onto `effect/unstable/process` and
`prop` onto `Schema.toArbitrary`. Neither rewrite is observable to `tsc`: a
schema-to-arbitrary bridge that produced nothing, or a property body that never
ran, would still typecheck and still report as passing. Both are now covered,
including a case that counts property-body invocations so a silently inert
`prop` fails instead of passing.

Verified against the real v4 runtime rather than inferred: `prop` derives values
for the array, record and Effect forms; the scripted-subprocess doubles serve
exit codes, stdout, stderr and the new `all` stream; an unmatched spawn is a
typed `PlatformError` and is replayed when the layer scope closes; and the
`it.effect` environment installs no logger.

  bun run dod   tsc, effect diagnostics, 292 tests, biome — all green
  test:e2e      16 pass, against freshly packed tarballs
@jfspencer
jfspencer merged commit 235f758 into main Aug 18, 2026
2 checks passed
jfspencer added a commit that referenced this pull request Aug 18, 2026
Ships PR #2 (`fix(effect-bun-test): restore the v3 log-level labels and cover
command/prop`), which merged to main after v0.4.0 was tagged and so missed that
release.

That change keeps `CapturedLog.level` on v3's upper-case labels and exports
`logLevelLabel` so a caller building its own capture logger can label a raw v4
level the same way. v4 models a log level as a bare string union member ('Warn',
'Info', 'None') where v3 used an object whose `label` was upper case ('WARN',
'INFO', 'OFF'), so a caller that kept a `level === 'WARN'` comparison would not
have failed — it would have matched nothing and quietly asserted nothing.

No contract change: `logLevelLabel` is a new export on the existing
`./log-capture` subpath, and it reaches the packed dist and its declaration.
Dependency shape is untouched — `effect` stays a peer at `>=4.0.0-rc.109 <5`.
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.

2 participants