Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ All build tiers and v1 gates are `tested` (37 of 39 requirements): `model` → `
- **`nvm use default` puts a Node 24 on PATH** for `bun run mutate` / focused `stryker run` invocations.
- **`bun test <single-file>` may exit 1 with zero failures** — the per-file coverage floor (bunfig.toml) judges partially-imported files. Exit 1 with 0 fails = coverage floor, not a test failure; gate on full `bun test` runs.
- **Internal imports**: upward reaches (anything needing `../`) use `#src/…`/`#scripts/…` (package.json `imports`); same-directory and downward stay relative, explicit `.ts` extensions. Enforced by `test/import-style.test.ts` (D-013).
- **Never run `biome migrate` unattended** (D-021). On this repo's v1 config it rewrites `"rules": { "recommended": true }` as `"rules": { "preset": "none" }`, which deletes the rule set instead of preserving it: `biome check .` then exits 0 on code containing `any`, `==` and unused vars, so the lint gate dies silently and CI stays green. The correct v2 spelling is `"preset": "recommended"`. After any biome config change, re-verify with a planted violation and check the **exit code**, not the printed summary.
- **Dependency bumps: refresh ≠ range change.** Taking a newer build of an already-declared range is routine; requiring a version you previously did not is a decision. `bun update` conflates them — it rewrites `package.json` floors even for packages whose version did not move — so refresh with `bun update`, then `git checkout package.json && bun install` to keep the change lockfile-only. Range changes get their own entry in `DECISIONS.md`, their own PR, and a measurement (D-020, D-021).
- **CI (GitHub Actions)**: `.github/workflows/ci.yml` runs the gate set (`check-docs` → `lint` → `typecheck` → `demo-app:build` → full `bun test`) on PRs and main pushes; main pushes also upload `demo-app/dist/` + `coverage/` artifacts. Bun is pinned there (1.3.14) so the bunfig coverage-gate semantics stay as verified; bump the pin deliberately, in its own PR. A `main` ruleset requires the `gates` check (repo-admin bypass keeps direct pushes possible). Mutation testing stays out of CI (D-017).
17 changes: 17 additions & 0 deletions DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,20 @@ Append-only. Each decision has a stable never-reused `D-###` id, what was decide
**Obligations**: none deferred. The L1 tuple fork remains open exactly as D-018 left it, now with a third option on the table.
**From**: release review of json-schema-faker v0.6.3 (2026-08-01); every claim above measured against the installed toolchain, none taken from the changelog.
**Folds into**: package.json, docs/specs/build-plan.md §1, docs/specs/design.md §4, docs/specs/contracts.md §3, REQUIREMENTS.md (R-027), src/engine/faker.ts, src/registry/index.test.ts, test/spikes/jsf-fidelity.test.ts, DECISIONS.md (D-003 premise note)

### D-021: Take the five in-range dependency refreshes; decline mqtt-pattern 2.x, defer aedes 1.x, biome 2.x and TypeScript 7 as their own decisions
**Date**: 2026-08-01
**What**: Refresh the five dependencies whose newest release already satisfies the declared range — `@asyncapi/parser` 3.6.0→3.6.1, `hono` 4.12.27→4.12.33, `mqtt` 5.15.1→5.15.2, `@types/react` 19.2.17→19.2.18, `@types/react-dom` 19.2.3→19.2.4 — as a **lockfile-only** change, with `package.json` untouched. The four remaining outdated packages each need a range change, and each is decided separately rather than swept in: **`mqtt-pattern` 2.1.1 is declined outright**; **`aedes` 1.1.1 is deferred behind R-006/R-007**; **`@biomejs/biome` 2.5.6 and `typescript` 7.0.2 are both viable and both deferred to their own PRs**.
**Why**: A version bump and a range change are different acts. The first says "take the newest build of what we already declared"; the second says "we now require something we previously did not". Only the first is routine, so only the first is bundled. `bun update` does not respect that line — it rewrote seven `package.json` floors as a side effect, including for `ajv`, `yaml`, `react`, `react-dom`, `typescript` and `biome`, none of which changed version at all. Those floors are declared intent, so they were restored and the lockfile refresh kept on its own.
**Measured (2026-08-01, installed toolchain, Bun 1.3.14)**:
- **The refresh is gate-clean**: `check-docs`, `lint`, `typecheck`, `demo-app:build` and full `bun test` each exit 0, against a same-command baseline taken on `main` before any change. `@asyncapi/parser` 3.6.1 adds a v3 channel-parameter-vs-address-placeholder validation rule, which is the one item here that could have rejected a previously-accepted fixture; it does not.
- **`mqtt-pattern` 1.2.0 → 2.1.1 ships a byte-identical runtime**: `index.js` in the two tarballs has the same sha256 (`63fbbfd2…`) once CRLF/LF is normalized, and the whole major is the addition of `.d.ts` files plus a `ts-toolbelt` **production** dependency.
- **v2's types are strictly worse for offbook's call shape**: `exec` becomes `exec<P extends string>(p: P, t: string): MqttParameters<P> | null`, and offbook's patterns are computed at runtime (`toPattern(c.topic)`), so `P` infers as the general `string` and `MqttParameters<string>` resolves to a type with no properties. Reading a captured parameter off it fails with `TS7053: Property 'deviceId' does not exist on type 'MqttParameters<string>'`. The repo typechecks under v2 only because the 9-line ambient shim in `src/registry/mqtt-pattern.d.ts` shadows the shipped types, or because the existing `as Record<string, string>` cast absorbs them — both verified. Deleting that shim is the only thing the bump could buy, and the shim is the more accurate declaration.
- **`aedes` 0.51.3 → 1.1.1 breaks offbook's exact construction call, by design**: 1.x is `"type": "module"`, `engines.node >= 20`, exports `class Aedes` as a **named** export, and sets its **default** export to a function whose entire body throws ``Aedes default export has been removed. Use 'const aedes = await Aedes.createBroker()' instead.`` `src/broker/index.ts` does `import Aedes from "aedes"` and `new Aedes({...})`, so it hits that throw. The constructor also becomes `static async createBroker(opts)`, and `drainTimeout` changes default from `0` to `60000`.
- **`@biomejs/biome` 2.5.6 is viable, but its own `migrate` command silently disables the lint gate** — see below. With the config corrected by hand it is clean-ish: 17 `assist/source/organizeImports` (named-import sorting, auto-fixable churn from v2's import-organizer overhaul), 14 `lint/correctness/noUnsafeOptionalChaining`, and 4 assorted. The transport-isolation rule survives the move out of `nursery` into `style` and was re-verified to still error outside `src/broker/` and stay exempt inside it.
- **`typescript` 7.0.2 typechecks the repo cleanly and about 10x faster**: `tsc --noEmit` exits 0 and takes 0.11s wall against 5.9.3's 1.12s. Gate liveness was confirmed separately (a planted `const n: number = "…"` still exits 1), so the pass is a real pass and not a silently-skipped check.
**Mitigations / notes**: **`biome migrate` is not safe to run unattended on this repo.** Pointed at the v1 config it rewrites `"rules": { "recommended": true }` as `"rules": { "preset": "none" }`, which does not preserve the rule set — it removes it. Verified by measurement, not by reading: a file containing `any`, `==` and an unused `var` draws **zero** diagnostics under the migrated config and four (`noExplicitAny` ×2, `noDoubleEquals`, `noUnusedVariables`) once `preset` is corrected to `"recommended"`. The failure mode is the dangerous kind — `biome check .` exits 0, CI stays green, and the lint gate is gone. Whoever takes the biome 2 PR must correct that line by hand and re-verify with a planted violation. The 14 `noUnsafeOptionalChaining` findings are real but low-severity and confined to test files, all the same `(x[0]?.payload as T).prop` shape: a `?.` guard immediately dereferenced, so a genuine failure surfaces as a confusing `TypeError` instead of a clean assertion diff. They are worth fixing on their own merits and are not a reason to hold the bump.
**Consequences for earlier entries**: none. D-020's measured-bump rule ("a bump is taken only when it is measured not to move the R-027 corpus") is unaffected — none of the five refreshed packages is the faker, and `json-schema-faker` stays exactly pinned at `0.6.3`.
**Obligations**: three deferred, none blocking. **(1)** `aedes` 1.x stays deferred until R-006 (WS fidelity) and R-007 (capture the browser application's `connect()`) have run, because both spikes measure `broker/`'s **current** Aedes defaults and the ws stack underneath them; moving that floor first would invalidate the thing being measured, and `aedes-server-factory` — last published 2021-06-28, four years before this entry and nearly three years before aedes 1.0 — is not a maintained path to 1.x either. **(2)** `@biomejs/biome` 2.5.6 as its own PR, carrying the hand-corrected config and the ~34 code changes. **(3)** `typescript` 7.0.2 as its own PR: it is a three-week-old major of the compiler that gates CI, so it earns a deliberate decision rather than a quiet range change, and the ~10x speedup is a real reason to take it soon.
**From**: a dependency review on 2026-08-01 covering all nine outdated packages; every behavioral claim above measured against the installed toolchain or the published tarballs, none taken from release notes.
**Folds into**: bun.lock, AGENTS.md (working notes)
10 changes: 5 additions & 5 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.