Skip to content

6.0.0: Solid reactivity that works, Bun.Image, and four defects that shipped green - #263

Merged
sebyx07 merged 8 commits into
mainfrom
feat/six-oh
Aug 20, 2026
Merged

6.0.0: Solid reactivity that works, Bun.Image, and four defects that shipped green#263
sebyx07 merged 8 commits into
mainfrom
feat/six-oh

Conversation

@sebyx07

@sebyx07 sebyx07 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Second of two. Stacked on #262 — base retargets to main when that merges.

101 files

1. A catalog that never registers now fails the gate — #249 · BREAKING

Observed in a real app on 5.0.1 — every user-facing string on every page:

curl /play  ->  <h1>⟦app.play.title⟧</h1>

The keys existed. The catalog module called defineCatalogs() and nothing imported it. Both guards said greenx verify passed and x i18n check answered "18 keys used — no gaps", because it audited the catalog file against source usage and never asked whether anything loaded it.

The loud-miss design worked exactly as intended and the guard still missed it, because it checked the wrong question.

The fix makes it impossible, not detectable. The framework catalog installs itself at module scope, so you cannot call t() without having imported the module that registers it. registerFrameworkCatalog() is deleted rather than kept as a no-op.

The same bug, one package over: registerMailCatalog() had zero production callers — every mail.* string in every running app was ⟦key⟧. Deleting it turned three existing mail tests red, because the tests that would have caught it were the ones calling it themselves. Identical trap.

Root cause, which is not what the issue said: the framework shipped two idioms and the generators shipped the broken one. examples/dummy used useT() in 100% of its pages; x new and x g route|resource|admin:page emitted t from @ultimat3/i18n at six sites.

2. i18n is the 19th gate step

A named step, not a rider on boundaries"did this import cross a line?" and "did this declaration reach the running app?" are different questions with different fixes. Skipped, never passed, on a repo that is not an app.

Without this, everything above is detection that never fires.

3. The reference app's first genuinely reactive island — #243

examples/dummy exercises every primitive once — and demonstrated no working island with reactivity. That absence is why the client bundle shipped broken through five majors.

/settings is now ssr chrome plus island({ src }). Proven in a real browser, driving the real served chunk:

change the timezone <select>
  before:  … August 20, 2026 at 9:00 PM     (UTC)
  after:   … August 20, 2026 at 11:00 PM    (Europe/Berlin)

A signal drove an effect that patched the DOM.

Measured, and the honest shape of #254: 19,368 bytes, of which 15,020 is the Solid runtime floor before rendering anything. The plain-DOM island is 875.

The island deliberately does not import @ultimat3/ui — measured, not preferred. The barrel does not tree-shake (51 kB for anything, 82 kB for one <Switch>), and a .module.scss inside an island resolves to a string, so every class renders empty while the build reports success. Both filed as #259. So setSolidRuntime still has no non-test caller and #246 is not closed in substance — stated rather than claimed.

4. A step count that cannot drift again

The gate had 17 steps in 20 markdown files, 18 in the code since the SEO step landed, and 19 by the end of this branch. Wrong across a whole major release, in the file every agent reads first.

scripts/gate-steps.ts compares every documented count and every documented list against VERIFY_STEP_NAMES, inside the manifest step. Two rules, because a list can be wrong while its count is right — which wiki/Getting-Started.md was.

DOC_GLOBS widens 99 → 166 pages. Every root file was already clean; the rot was entirely in package pages, ratcheted at 23 shrink-only pins.

5. A README for two audiences

A human skimming for ninety seconds sees one action and the six artifacts it projects, a real error with its runnable fix:, the eight primitives, the one-command gate. Demonstration, not adjectives. An agent gets ## Navigate, the 30-package table derived from list-workspaces.ts, and a second-person line telling it to read llms.txt first.

No number appears without the command that re-derives it.

wiki/Upgrading.md said "three majors to cross" with a table ending at 4.0.0 — while its own body documented 4.1.0 → 5.0.0. Now four, 70 entries, counted from CHANGELOG.md. docs/architecture/19-cutting-a-major.md records the convention, which existed only by imitation.

Gate

bun run verify14 of 19 passed, 5 skipped, 0 failed.

Also fixes a regression #253 shipped: --external @babel/preset-typescript on every --compile site, verified on Bun 1.3.14 (bundle 952 modules, ./app --version5.0.1). docker/Dockerfile carries the same flag and a test now fails if either site drifts — the Dockerfile had already been the one place a compile flag went missing once before, for --define.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

sebyx07 and others added 7 commits August 20, 2026 17:02
…d PNG codec

`packages/core/src/image/` was a from-scratch codec — Huffman tables, DCT,
scanline filters, a Lanczos resampler. 1,679 source lines and 1,292 test lines,
deleted. `pipeline.ts:20` gave the reason it existed:

    Bun ships no image API and the contract forbids `sharp`, so WebP and AVIF
    are probed and served, never synthesised here.

That stopped being true in Bun 1.3.14 — the version already pinned. `Bun.Image`
is statically-linked libjpeg-turbo / libspng / libwebp with SIMD resize kernels.
Still zero dependencies.

WebP encodes now, so `@ultimat3/storage`'s default variant format and its default
`.webp` key extension finally agree: a `srcset` entry can be served, not merely
named.

`Bun.Image.backend` is pinned to `'bun'` on every call. That forces the static
codecs and Highway geometry everywhere, which is what `variantKey`'s
content-addressed cache requires — a platform-dependent variant is a cache that
never hits. The cost is that AVIF and HEIC are refused on every platform rather
than working on two of them, which is one behaviour instead of two.

`blurDataUrl` is `Bun.Image.placeholder()` — a deterministic ThumbHash at most
32px on its long edge. `BLUR_PLACEHOLDER_WIDTH` is deleted; there is no width to
name. ThumbHash quantises the aspect ratio, and `responsiveImage()` paints the
LQIP as `background-size: cover` inside a box sized from the real dimensions, so
nothing shifts.

With no `format`, the SOURCE format is kept. The old rule guessed from the pixels
and turned an opaque PNG into a JPEG; a heuristic that can flatten a logo
eventually does.

`png-pixels.ts` (183 lines) survives as a raw-pixel seam, and writing its test
first found a real bug: unfiltering into a `Uint8ClampedArray` CLAMPS where PNG
filters are mod-256, so `255 + 1` gave 255 instead of 0. Invisible against our
own filter-0 writer, wrong against every adaptive one — it forced alpha to 255,
flattening every transparent PWA icon. `Bun.Image` has no compositor and no
raw-pixel terminal, and the PWA maskable safe zone needs both, which is why the
seam exists at all.

Bun agrees with Pillow byte-for-byte on five reference decodes (RGBA, greyscale,
grey+alpha, 16-bit, palette+tRNS). Determinism is asserted on both the fast and
composite paths, since the content-addressed cache depends on it.

Refs #252

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
BREAKING. Bun 1.4 ships ICU 78, where `new Intl.DateTimeFormat('en',
{timeZone:'CET'})` no longer throws. `resolve()` delegated the IANA-ness
judgement to `Intl`, so a runtime upgrade alone reopened the framework's
"no date without an explicit IANA timeZone" rule — silently, and in the
direction that fails dangerous:

    isValidTimeZone('CET')  -> true   (was false)   also EST, EST5EDT, GMT, MST

`Intl` answers "can I format this", never "is this IANA", and at ICU 78 the two
stopped agreeing. The judgement is now structural: `UTC`, or a name containing
`/`. It cannot move with the runtime again.

43 names change answer, enumerated with their replacements in CHANGELOG.md. The
24 geographic `backward` links and the three UTC aliases swap textually — each
verified against seven probe instants including both 2026 DST transitions. The
GMT family maps to `Etc/GMT`, not `UTC`, because `UTC` renders a different zone
label. The eleven abbreviations have no mechanical replacement, and that is the
defect: an abbreviation names no jurisdiction and carries no DST rule.

No denylist. A list of refused abbreviations grows with every tzdata release, and
there is no structural rule that keeps `CET` out and lets `Japan` in.

`X_TIMEZONE_INVALID`'s `cause:` was itself false — `Japan` IS an IANA name, a
`backward` link in shipped tzdata — so it now reads "not an IANA Area/Location
zone name", which is true for all four refused classes. The `fix:` instructs both
classes: the mechanical swap for a legacy link, and "name the city" for an
abbreviation, because only the author can choose one.

Three `format.test.ts` expectations move to anchored patterns rather than pinned
ICU-78 literals, so the suite is green on ICU 75 and 78 both and this does not
have to merge with the Bun upgrade.

Refs #251

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
… worked

BREAKING. Every `spa` route ever declared served an empty document — 200, correct
headers, blank page:

    <body><div id="x-root"></div></body>

`dev-render.ts:205` passed `chunks: []`, hardcoded; `prerender.ts` refused the
mode outright; the container mounted the same table. No document in the
framework's history ever carried a <script>. And `renderSpa` never read
`entry.component`, so a `spa` page's own component was dead code in every mode —
along with its `hydrate` and `budget.js`, which nothing could honour.

The mode's own header claimed the shell was "identical for every actor and
therefore cacheable" while it emitted `private, max-age=0, must-revalidate` and
required a `policy`. `MODE_SPECS.spa.prerenderable` was `true` while
`isPrerenderable` is `render === 'static'`.

The deployed demo had already rejected it in writing, one release earlier:

    `ssr`, not `spa`: the shell has data to render, and a `spa` shell would ship
    that decision to the browser to be asked again.

With `solid-loader.ts` landed, `island({ src })` is a working client model with a
bundler, a content-addressed URL, a boot runtime and a budget measured in real
bytes. `spa` was a second path to interactivity that delivered strictly less. Not
a different thing — a worse island.

`createRouter` goes with it: 236 lines exported from `@ultimat3/render`, 490
lines of tests, zero callers. Its header called it "load-bearing for every app
page"; nothing loaded it. It existed to drive a `spa` shell, and it was built on
a premise `solid-loader.ts` disproves — "inject reactive primitives, import no
solid-js" — because Solid's reactivity is a compile-time contract no injected
runtime can stand in for.

`SPA_ROOT_ID` was never a `spa` symbol: `routeBody` wraps EVERY mode's body in
it. It returns as `ROOT_ELEMENT_ID` in `render-html.ts`, same value.

The guard is a loop over `RENDER_MODES` itself — every mode puts the route
component inside the hydration root — so a fifth mode arriving without a renderer
is a build error, not a blank page.

`@ultimat3/admin`'s generated views join its custom pages at `ssr` +
`hydrate: 'never'`; admin views are pure functions of props with no local state,
so there was never page-level state to hydrate.

Four more hand-copied `RenderMode` unions still admitted 'spa' and typechecked
green after the deletion — `http`, `seo`, `manifest`, `pwa`. All corrected.
`pwa`'s mapped `spa -> cache-first`, the only mode that gave an `app/` route a
shared cache entry. Five copies of one closed set with nothing comparing them is
filed as #261.

Refs #245, #247, #261

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
BREAKING. Observed in a real app on 5.0.1 — every user-facing string on every
page rendered as a placeholder:

    curl /play -> <h1>⟦app.play.title⟧</h1>

The keys existed. The app's catalog module called `defineCatalogs()` and nothing
imported it, so registration never ran. Both guards said green: `x verify` passed
and `x i18n check` answered "18 keys used — no gaps", because it audited the
catalog file against source usage and never asked whether anything LOADED it.

The loud-miss design worked exactly as intended and the guard still missed it,
because it checked the wrong question.

The fix is a base layer, not a check. `framework.ts` installs the framework
catalog at MODULE SCOPE, so you cannot call `t()` without having imported the
module that registers `errors.*`, `auth.*` and `ui.*`. `registerFrameworkCatalog()`
is deleted rather than kept as a no-op — there is nothing to replace it with.
Base entries merge UNDER whatever an app registers, so it is order-independent
and an app override always wins.

`x i18n check` gained the runtime half: it calls the same `loadApp` the server
calls at boot, then asks the registry what actually arrived. And it is now the
19th step of `x verify` — a named step, not a rider on `boundaries`, because
"did this import cross a line?" and "did this declaration reach the running app?"
are different questions with different fixes. Skipped, never passed, on a repo
that is not an app.

The same bug, one package over: `registerMailCatalog()` had ZERO production
callers, so every `mail.*` string in every running app was `⟦key⟧`. Deleting it
turned three existing mail tests red — only the package entry reached
`catalog.ts`, so any deep import of `render.ts` rendered misses, and the tests
that would have noticed were the ones calling `registerMailCatalog()` themselves.
The renderer now depends on the strings it renders.

Root cause of both: the framework shipped two idioms and the generators shipped
the broken one. `examples/dummy` used `useT()` from the app's own module in 100%
of its pages; `x new` and `x g route|resource|admin:page` emitted `t` from
`@ultimat3/i18n` at six sites. Corrected.

The 14 `@ultimat3/ui` assertions that read `⟦ui.*⟧` were doing double duty —
proving which key a component asked for AND that it had not written its own
English. Replacing the marker with a literal would have kept the first and lost
the second, so they assert `uiString(UI_KEYS.x)`, a lookup by key. Mutation-proved
both ways.

Closes #249

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
…till compiles

Five changes to `@ultimat3/cli`, all consequences of the slices around them.

`x verify` gains `i18n` as its 19th step (`verify-step.ts`, `cmd-verify.ts`), so
a catalog that never reaches the runtime registry is a gate failure rather than a
green run shipping ⟦key⟧ to every user. `i18n-registration.ts` composes both
halves of one question — a key missing from a catalog, and a catalog no module
registered — and `x i18n check` renders the same call as a table, so the command
and the gate cannot disagree.

The generators emit `useT()` from the app's own catalog module instead of `t`
from `@ultimat3/i18n`. An app with no catalog package keeps the old import:
emitting one that cannot resolve trades a wrong idiom for a file that does not
compile.

`cmd-verify.ts` (511) and `cmd-generate.ts` (509) were over the 500 ceiling and
split by name rather than by length: which checks run / what running them means /
the command, and which files a generator emits / what happens to them on disk /
the command. Re-exports keep one import path per symbol.

`--external @babel/preset-typescript` on every `--compile` site, which repairs a
regression this branch shipped. Adding `@babel/core` put a runtime
`require("@babel/preset-typescript/package.json")` in the binary's static graph.
It sits inside a `catch`, in a path unreachable at runtime because the loader
passes `babelrc: false, configFile: false` — but the bundler walks it anyway, and
Bun 1.3.14 fails the build where 1.4.0 bundles it as a runtime throw. That is
also why the local gate was green while CI was red.

Measured on Bun 1.3.14, not inferred from 1.4: without the flag, CI's error
verbatim; with it, `bundle 952 modules` and `./app --version` answering `5.0.1`.
`--external @babel/core` was tried and rejected — the binary then dies at boot,
because `serve.ts:294` calls `buildIslands` unconditionally, so a compiled binary
genuinely does need to build islands. A lazy `await import` was tried and
rejected too: Bun follows a literal dynamic specifier into `--compile`.

`docker/Dockerfile` carries the same flag, and `compile-externals.test.ts` now
fails if either site drifts from the other. The Dockerfile had already been the
one place a compile flag went missing once before, for `--define`, one release
earlier. This time it is mechanised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
`examples/dummy` exercises every primitive once, idiomatically — and until now it
demonstrated NO working island with reactivity. That absence is why the client
bundle shipped broken through five majors: nothing in the repo compiled a `.tsx`
that reached a browser.

`/settings` was the worst case. It declared `render: 'spa'`, so it served a blank
page, and its `Page()` was a full Solid component that was dead code in every
mode — and uncompilable besides, against `SelectProps` that has no `label`, no
`hint` and no children.

It is now `ssr` chrome plus `island({ src: './settings.island.tsx' })`. The island
carries five signals, a `<For>`, a `createEffect` that writes and removes
`<html data-theme>`, and a fetch to a server-minted endpoint. `Page()` renders a
summary of the saved row as the island's shell, so the screen paints before a
byte of the module arrives and `mount` replaces it.

`offline: 'precache'` became `'runtime'`: precaching a per-request authed
document is a shared cache entry holding one member's HTML.

The test builds the real chunk through the same `buildIslands` `x build` uses and
drives `mount` against a micro-DOM. Hoisting the preview out of its accessor
fails two cases — that is the compile-time reactivity contract, asserted rather
than assumed.

Measured, and the honest shape of #254: the chunk is 19,368 bytes, of which
15,020 is the Solid runtime floor before rendering anything. The plain-DOM
`contact-sales` island is 875. An `app/` route fits one reactive island, which is
why the budget says 20kb rather than the fictional 45kb it declared before.

The island does NOT import `@ultimat3/ui`, and that was measured rather than
preferred: `@ultimat3/ui`'s barrel does not tree-shake, so importing anything at
all costs 51 kB and one `<Switch>` costs 82 kB — and worse, a `.module.scss`
inside an island resolves to a STRING, so every class renders empty and the build
reports success. Both filed as #259. Until that is fixed, `setSolidRuntime` still
has no non-test caller and #246 is not closed in substance.

Refs #243, #245, #254, #259

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
…rift again

The gate had 17 steps in 20 markdown files, 18 in the code since the SEO step
landed, and 19 by the end of this branch. A number wrong across a whole major
release, in the file every agent reads first.

`scripts/gate-steps.ts` compares every documented count AND every documented step
list against `VERIFY_STEP_NAMES`, and runs inside the `manifest` step — so it is
enforcement, not a script someone remembers. Two rules, because a page is stale
in two ways: a list can be wrong while its count is right, which is exactly what
`wiki/Getting-Started.md` was.

`DOC_GLOBS` widens from 99 to 166 pages — `*.md` and `packages/*/*.md` were never
scanned, which is how the `x g` kind list stayed four short. Every root file was
already clean; the rot was entirely in package pages, ratcheted at 23 pins that
may only shrink.

The README is rebuilt for two readers at once. A human skimming for ninety
seconds sees one `action` and the six artifacts it projects, a real error with its
runnable `fix:`, the eight primitives and the one-command gate — demonstration
rather than adjectives. An agent gets `## Navigate`, the 30-package table derived
from `list-workspaces.ts`, and a second-person line telling it to read `llms.txt`
first. No number appears without the command that re-derives it.

`llms.txt` is regenerated from the on-disk indexes: 210 links, 16 wiki pages and 4
architecture docs that were missing, and no version number at all — only the
commands that resolve one.

`wiki/Upgrading.md` said "three majors to cross" with a table ending at 4.0.0,
while its own body documented 4.1.0 -> 5.0.0. Now four, 70 entries, counted from
`CHANGELOG.md` rather than asserted — and a new `5.x -> 6.0.0` section, structured
so entries append without rewriting it. `docs/architecture/19-cutting-a-major.md`
records the convention itself, which existed only by imitation.

Also corrected: `x i18n check` does NOT silently answer ok on this repo
(`X_NOT_IN_APP` refuses it); the real vacuous green was an app with no catalogs at
all. The demo app is 16 of 18 with two pinned red, not 15 of 17. `examples/dummy`
is pinned on 4 steps, not 6. `packages/ui/CATALOG.md` says 52 components; four
pages said 46. Migration advice that named a codemod, in a repo that has never
shipped one, now names the manual edit.

Refs #251, #252, #245, #249

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 21 minutes

Limit details: You’ve used the included review currently available. Your 77 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

You’re in a promotional period — use the checkbox below to run this review for free:

  • Run review for free

On-demand reviews are free for the next 31 days. After that, they cost $0.25 per reviewed file.

How can I continue?

Run this review now using the option above, or comment @coderabbitai review --use-credits.

You can also wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 318f1f28-e0cf-4c0d-b716-5770747ec76a

📥 Commits

Reviewing files that changed from the base of the PR and between c0f6c4d and 6909dc8.

📒 Files selected for processing (163)
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • PUBLISHING.md
  • README.md
  • docker/Dockerfile
  • docs/README.md
  • docs/architecture/04-error-contract.md
  • docs/architecture/19-cutting-a-major.md
  • docs/architecture/README.md
  • docs/idea/10-testing.md
  • docs/idea/14-roadmap.md
  • docs/idea/20-large-app-readiness.md
  • dummy/social-media-clone/CLAUDE.md
  • dummy/social-media-clone/PLAN.md
  • dummy/social-media-clone/x.verify.json
  • examples/dummy/apps/web/app/settings/page.module.scss
  • examples/dummy/apps/web/app/settings/page.tsx
  • examples/dummy/apps/web/app/settings/settings.island.test.ts
  • examples/dummy/apps/web/app/settings/settings.island.tsx
  • examples/dummy/imports.test.ts
  • examples/dummy/x.manifest.json
  • examples/dummy/x.verify.json
  • framework.manifest.json
  • llms.txt
  • packages/admin/README.md
  • packages/admin/src/dev/facts.ts
  • packages/admin/src/dev/server.test.ts
  • packages/admin/src/routes.ts
  • packages/cli/CLAUDE.md
  • packages/cli/README.md
  • packages/cli/e2e/registry-boot.e2e.test.ts
  • packages/cli/src/cmd-build.ts
  • packages/cli/src/cmd-generate.ts
  • packages/cli/src/cmd-i18n.test.ts
  • packages/cli/src/cmd-i18n.ts
  • packages/cli/src/cmd-verify.test.ts
  • packages/cli/src/cmd-verify.ts
  • packages/cli/src/compile-externals.test.ts
  • packages/cli/src/compile-externals.ts
  • packages/cli/src/dev-hooks.test.ts
  • packages/cli/src/dev-render.test.ts
  • packages/cli/src/dev-render.ts
  • packages/cli/src/generate-files.ts
  • packages/cli/src/generate-write.ts
  • packages/cli/src/i18n-audit.test.ts
  • packages/cli/src/i18n-audit.ts
  • packages/cli/src/i18n-registration.test.ts
  • packages/cli/src/i18n-registration.ts
  • packages/cli/src/templates/admin-page.ts
  • packages/cli/src/templates/resource.ts
  • packages/cli/src/templates/route.test.ts
  • packages/cli/src/templates/route.ts
  • packages/cli/src/templates/scaffold-app.ts
  • packages/cli/src/templates/scaffold-i18n.ts
  • packages/cli/src/verify-checks.ts
  • packages/cli/src/verify-run.ts
  • packages/cli/src/verify-step.ts
  • packages/core/README.md
  • packages/core/src/image/canvas.test.ts
  • packages/core/src/image/canvas.ts
  • packages/core/src/image/errors.test.ts
  • packages/core/src/image/errors.ts
  • packages/core/src/image/jpeg-decode.test.ts
  • packages/core/src/image/jpeg-decode.ts
  • packages/core/src/image/jpeg-encode.test.ts
  • packages/core/src/image/jpeg-encode.ts
  • packages/core/src/image/jpeg-headers.ts
  • packages/core/src/image/jpeg-huffman.ts
  • packages/core/src/image/jpeg-tables.ts
  • packages/core/src/image/pipeline.test.ts
  • packages/core/src/image/pipeline.ts
  • packages/core/src/image/png-pixels.test.ts
  • packages/core/src/image/png-pixels.ts
  • packages/core/src/image/png.test.ts
  • packages/core/src/image/png.ts
  • packages/core/src/image/resize.test.ts
  • packages/core/src/image/resize.ts
  • packages/core/src/index.ts
  • packages/entity/CLAUDE.md
  • packages/http/src/router.ts
  • packages/i18n/CLAUDE.md
  • packages/i18n/src/context.ts
  • packages/i18n/src/define-catalogs.test.ts
  • packages/i18n/src/define-catalogs.ts
  • packages/i18n/src/errors.ts
  • packages/i18n/src/framework.test.ts
  • packages/i18n/src/framework.ts
  • packages/i18n/src/index.ts
  • packages/i18n/src/registration.test.ts
  • packages/i18n/src/registration.ts
  • packages/mail/src/catalog.test.ts
  • packages/mail/src/catalog.ts
  • packages/mail/src/driver-parity.test.ts
  • packages/mail/src/envelope-address.test.ts
  • packages/mail/src/index.ts
  • packages/mail/src/job.test.ts
  • packages/mail/src/layout-registry.test.ts
  • packages/mail/src/mail.test.ts
  • packages/mail/src/render.test.ts
  • packages/mail/src/render.ts
  • packages/mail/src/templates.test.ts
  • packages/manifest/src/schema.ts
  • packages/pwa/src/icons.ts
  • packages/pwa/src/service-worker.test.ts
  • packages/pwa/src/strategies.test.ts
  • packages/pwa/src/strategies.ts
  • packages/render/CLAUDE.md
  • packages/render/README.md
  • packages/render/src/index.test.ts
  • packages/render/src/index.ts
  • packages/render/src/modes.test.ts
  • packages/render/src/modes.ts
  • packages/render/src/registry.ts
  • packages/render/src/render-html.ts
  • packages/render/src/render-spa.test.ts
  • packages/render/src/render-spa.ts
  • packages/render/src/route.ts
  • packages/render/src/router-client.test.ts
  • packages/render/src/router-client.ts
  • packages/render/src/surfaces.ts
  • packages/seo/src/image-driver.test.ts
  • packages/seo/src/image-driver.ts
  • packages/seo/src/routes.ts
  • packages/storage/README.md
  • packages/storage/src/image.test.ts
  • packages/storage/src/image.ts
  • packages/storage/src/index.ts
  • packages/time/CLAUDE.md
  • packages/time/README.md
  • packages/time/src/errors.ts
  • packages/time/src/format.test.ts
  • packages/time/src/zone-canonical.ts
  • packages/time/src/zones.test.ts
  • packages/ui/src/components/DataTable.test.ts
  • packages/ui/src/components/ErrorState.test.ts
  • packages/ui/src/components/LocaleSwitcher.test.ts
  • packages/ui/src/components/chrome.test.ts
  • packages/ui/src/components/file-controls.test.ts
  • packages/ui/src/components/presentation.test.ts
  • packages/ui/src/errors.ts
  • packages/ui/src/theme/solid-adapter.ts
  • scripts/doc-commands.test.ts
  • scripts/doc-commands.ts
  • scripts/error-map-backlog.ts
  • scripts/gate-steps.test.ts
  • scripts/gate-steps.ts
  • scripts/help.test.ts
  • scripts/verify.ts
  • wiki/CLI-Reference.md
  • wiki/Contributing.md
  • wiki/Entities-And-Migrations.md
  • wiki/Error-Codes.md
  • wiki/FAQ.md
  • wiki/Getting-Started.md
  • wiki/Home.md
  • wiki/PWA-And-Offline.md
  • wiki/Troubleshooting.md
  • wiki/Tutorial-01-First-App.md
  • wiki/Tutorial-02-First-Feature.md
  • wiki/Tutorial-06-Growing-Up.md
  • wiki/UI-Components.md
  • wiki/Upgrading.md

Comment @coderabbitai help to get the list of available commands.

@sebyx07
sebyx07 changed the base branch from feat/six-oh-core to main August 20, 2026 22:09
@sebyx07 sebyx07 changed the title 6.0.0 (2/2): the i18n gate step, a reactive reference island, and docs that cannot drift 6.0.0: Solid reactivity that works, Bun.Image, and four defects that shipped green Aug 20, 2026
… sorts its imports

Two consequences of the `i18n` gate step, both caught by CI on #263.

`x.verify.json` is each app's committed floor — the steps it has proved it can
run — so a suite that vanishes reads as a skip rather than a regression. Both
apps ran `i18n` and neither named it: `X_REFERENCE_APP_NO_FLOOR`, with the exact
edit in its `fix:`.

`x g admin:page` emitted its two imports in a fixed order, and the correct order
DEPENDS on the app's scope: an app catalog (`@myapp/i18n`) sorts BEFORE
`@ultimat3/admin`, while the fallback `@ultimat3/i18n` sorts AFTER it. Either
hardcoded order is a lint error in exactly one of the two cases.

Each case is covered by a different job, which is why one order looked correct:
`templates`' own linter test generates without an app catalog module and pinned
the fallback ordering, while only `scaffold-smoke` reaches the app-scoped one —
because it runs every generator against a real scaffold rather than stopping at
`x new`. Moving the import unconditionally traded one red job for the other, and
both were needed to see the whole rule.

The imports are now sorted by specifier, so neither case can regress.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgsU1WBJMAjnLaazvfuJmD
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