22.0.0
22.0.0 in progress: plan 101, the framework deep sweep
(docs/plans/2026/09/23/101-framework-deep-sweep/).
Every breaking entry below has a manual edit in the
Upgrading 21.x → 22.0.0 section.
Changed
- BREAKING —
t.daterefuses any string that is not ISO-8601 in shape ('March 14, 2026',
'3/14/2026','12').new Dateread these at the host's local midnight, so the answer depended
onTZ.coerceQueryleaves them untouched and validation refuses them. Numbers (epoch ms) and
Dateobjects are unchanged. - BREAKING —
timestamp()refuses a string that is not ISO-8601 withZor an offset
('2026-03-14T09:00','March 14, 2026'); such a string used to be parsed in the host's zone. - BREAKING —
x deploy --method helmnames the release afterapp.config.ts'sname(it was
the literalapp), waits for the rollout (--wait,--timeout, default 15m) and reports
data.rollout. New--release,--namespaceand--timeout, refused on--method compose.
planDeploy(image, 'helm', root)needs a fourthHelmTargetargument. - BREAKING —
invokeAdminActionno longer takesexpectedConfirmation. The gate derives the
token from the action's entity andsubject.id. Before, with both fields omitted, a destructive
action ran unconfirmed. - Admin: direct
adminCreate,adminUpdateandadminDestroycalls refuse an operation the
resource does not offer. An admin action called over MCP with anidloads the row, so row-level
policies apply. - Testing:
toDenyPolicy,toMatchOpenApiandtoBeWithinBudgetthrow on a receiver of the
wrong type (X_TEST_POLICY_EXPECTED,X_TEST_OPENAPI_EXPECTED,X_TEST_NUMBER_EXPECTED) instead
of passing under.not. The island test DOM treats all 14 void elements as leaves, and an observer
that re-observes afterdisconnect()gets resizes again. - BREAKING —
@ultimat3/uiDateTime/toDaterefuses non-ISO strings ('August 14, 2026 09:00','8/14/2026'). Pass an ISO-8601 date, a date-time withZor an offset, or aDate. - A draining process serves in-flight and kept-alive requests with
connection: closeinstead of
answeringX_DRAINING503; it still answers 503 once stopped. Ahelm upgradeon kind failed 598
of 7,690 requests before this, and none after. render'scontentHashis xxHash32 (Bun.hash): 134 µs → 21 µs on a 96 kB document. Every
static ETag and every scoped CSS class name changes once — a one-time cache bust.- Mail idempotency keys are
mail:<id>:<digest>, a digest over the canonical recipients and
payload, so a 50-recipient send stays header-safe. Keys change once, so a retry spanning the deploy
can send twice. - A gateway
budgetapplies with no scope open.StopReasongains
model_context_window_exceeded, and an unknown stop reason counts as a truncation (isTruncated()). - Query routes send errors through the pipeline, as action routes now do.
- BREAKING —
channel()requirespolicy. A declaration without one is a type error and throws
X_CHANNEL_DECLARATION_INVALID; a public channel says so with an explicit policy.
ChannelDescription.policyisstring, no longerstring | null. - BREAKING — the offline outbox is stored one record per mutation.
QueueStore.save(state)→
write(change: QueueChange), andLocalStore.saveQueue(scope, state)→writeQueue(scope, change).
Two tabs saving whole queues erased each other's writes. Whole-queue records written by 21.x are
converted on first read, so queued writes survive the upgrade. - BREAKING —
workerName(scope)→workerName(scope, buildId): one SharedWorker per build. - BREAKING —
ChangeOpgains'truncate'(rowless). ATRUNCATEempties affected live windows and
starts a new epoch on every open channel topic. AswitchoverChangeOpneeds the new case. startLiveReplicatorlives in@ultimat3/realtime/server.@ultimat3/testingre-exports it for
now.x grefuses a path, a reserved word or a leading digit in a name (X_CLI_BAD_FLAG) and always
writes kebab-case slice directories:x g entity BlogPostwritesapp/blog-post/.- Surface boundaries are derived from
SURFACE_SPECS: anapi/→site/,site/→app/or
app/→api/runtime import isX_BOUNDARY_SURFACE_IMPORT.api/may importapp/. x cifindings are fenced assource: 'ci-log', never read as the framework's own.- BREAKING —
@ultimat3/coredropsResult:Result,Ok,Err,ok,err,map,mapErr,
isOk,isErr,tryCatch,unwrap,unwrapOr(result.ts, no consumer anywhere, and a second
error path besidethrow UltimateError). Usethrow/try. - BREAKING — boot owns the auth tables.
X_USERS_TABLE,X_SESSIONS_TABLE,X_ACCOUNTS_TABLE,
X_VERIFICATIONS_TABLE,X_API_KEYS_TABLEandX_USERS_MIGRATION_1_3are gone from
@ultimat3/auth;AUTH_TABLEScarries the 1.3 upgrade (add column if not exists) and boot applies
it. Delete any hand-pasted auth migration. - BREAKING — unreferenced internals leave the package barrels. Runtime values no code outside
their own package used, none of them an error class, code table or documented API:- auth:
API_KEY_PREFIX_SEGMENTS,DEFAULT_JWKS_TTL_MS,DEFAULT_KDF_LIMITS,
IDLE_SLIDE_DIVISOR,OAUTH_HANDSHAKE_COOKIE_PREFIX,ORG_ATTEMPT_FACTOR,SQL_AUTH_*(7),
apiKeyPrefix,base64Url,base64UrlBytes,matchesHash,parseHashParams,
parseSessionToken,pkceChallenge,resetKdfGate. - ui:
BAR_CHART,CHANNELS_PATTERN,COMBOBOX_LIMIT,DELTA_ARROW_PATH,EMPTY_TOAST_QUEUE,
GRID_STEPS,SPARKLINE,VISIBLE_EDGE,acceptMatches,accordionOpenIds,adoptDroppedFiles,
ariaSortFor,clearSolidRuntime,collapsedToasts,distributeIssues,gridY,isIconTag,
linkTarget,loadMoreState,loadingHints,maxOf,messagesOf,meterShare,meterWidth,
nextRovingIndex,nextSortState,parseChannels,progressPercent,ratioFor,
relativeTimeText,sameFieldValue,shellLandmarks,sparkPoints,visibleToasts. - core:
OTEL_SAMPLER_ARG_KEY,OTEL_SAMPLER_KEY,OTLP_ENDPOINT_KEY,OTLP_HEADERS_KEY,
OTLP_PROTOCOL_KEY,OTLP_SCOPE,OVERFLOW_ATTRIBUTE,SECRETS_ALG,SECRETS_IV_BYTES,
SECRETS_KEY_BYTES,SECRETS_KEY_HEX_LENGTH,SECRETS_KEY_ID_LENGTH,SECRETS_TAG_BYTES,
SECRETS_VERSION,SECRET_BRAND,SECRET_NAME,VERSION_MANIFEST,assertPixelBudget,fitBox,
otlpAttributes,otlpResource,parseSecretsEnvelope,rasterFrom,resetDefaultSampler,
scaledToFit,unixNano. - http:
DEFAULT_CSRF,DEFAULT_TZ_CONFIG,FORWARDED_CLIENT_CERT,FORWARDED_FOR,
FORWARDED_PROTO,SQL_RATE_LIMIT_*(3),TENANT_SCOPE,acceptsHtml,clientUsedHttps,
forwardedValue,normalizePath,readCorrelation,renderOverlay,resetProblemMeta,
selfOrigin,stripBasePath. - entity:
SEARCH_PROPERTY,describePlan,emptyPlan,hasOrgPredicate,isOrgScoped,
searchExpression,sqlTypeOf,tenantColumnOf. - query:
PAGE_AFTER_KEY,PAGE_FIRST_KEY,advanceCursor,liveEpoch,matchesFilters,
nameQuery,toKebabCase. - mcp:
DEFAULT_QUERY_ROWS,MCP_RATE_LIMIT_WINDOW_MS,NO_ARGS,PARSE_GUARD,QUERY_LIMITS,
STYLE_NAME,UI_DIFF_DEFAULT_THRESHOLD,UI_INTERACT_STEP_SCHEMA,UI_VIEWPORTS,
URI_ARG_SCHEMA,appToolPrimitive,appToolPrimitives,bearerToken,isAgentActor,
viewportOf. - ai:
OVERALL,ZERO_USAGE,hybridSql,narrowScope,parseStopDetails,reasoningBody,
resetAiRuntime,scopeAdmits,textSql,upsertSql,vectorLiteral. - mail:
DARK_RULES,FOOTER_KEYS,MAIL_CATALOG_SOURCE,MAIL_ENV_KEYS,MAIL_FONT_STACK,
MAIL_WIDTH_PX,RESEND_BASE_URL,UNCONFIGURED_DRIVER_NAME,UNSUBSCRIBE_KEY,darkModeCss,
envelopeRecipients. - notify:
DEFAULT_DELIVERY_WINDOW_MS,DEFAULT_MAX_DELIVERY_RECORDS,SQL_NOTIFY_*(7),
requireDigest. - pwa:
CAPABILITY_MANIFEST_KEYS,MIN_ENGAGEMENT_MS,SPLASH_MATRIX,STRATEGY_FNS,
STRATEGY_FN_NAMES,STRATEGY_SOURCE,serializePrecacheManifest,serializePushMessage. - render:
DEFAULT_REPLAY_EVENTS,DEFAULT_ROUTE_STATUS,ISLAND_NODE,THEME_SCRIPT_MAX_BYTES,
checkIslandProps,headTagKey,isEmittableSpecifier,isErrorStatus,requiredStrategies,
routeCount,toHeadTag. - scraping: 38 internals (
DEFAULT_*tunables, cookie matchers, snapshot/recording helpers). - manifest:
parseGuideSections,parseReExports.
- auth:
- BREAKING — the e2e driver lives in
@ultimat3/testing.@ultimat3/clino longer exports
installE2eDriver,e2eFixtures,startE2eApp,e2eApp,e2eBaseUrl,e2eBrowser,
openE2eBrowser,openE2eBrowserIfAvailable,cdpConnect,cdpE2eTab,cdpE2eSession,
findChrome,launchChrome,launchFoundChrome,CHROME_CANDIDATES,CHROME_PATH_ENV,e2ePage,
e2eLocatorand the selection/evaluate helpers, theCdp*Error/E2e*Errorclasses or their types.
Import them from@ultimat3/testing; the preload is@ultimat3/testing/e2e-preload. The
X_E2E_*/X_CDP_*codes are unchanged and now registered by testing (E2E_ERROR_CODES). The driver
spawns the app's ownx, resolved from the app root. - BREAKING —
entityRow(relation, physical, image)decodes a WAL image through the registered
entity (decodeRow, money included) instead of guessing from column names; a relation with no
registered entity is refused, andcamelis no longer exported from@ultimat3/realtime/server. - BREAKING — a
syncrole with no reachable change feed refuses to boot (X_REALTIME_TOPOLOGY):
on a real database it needsNATS_URL(shared withweband one replicator) or an in-process
replicator. It used to come up healthy and deliver nothing. Both charts (roles.sync.enabled: false,
the/_x/syncIngress rule gated on it) and both Compose files (replicas: 0) shipsyncoff, with
the enable recipe beside the switch. - A production boot refuses the development cursor secret (
X_CURSOR_SECRET_DEV): set
ULTIMATE_CURSOR_SECRET. @ultimat3/cli/serveexportsrunRolealone; the scaffold'sserver.tsimports it, and a bundle
of it carries no testing, template, e2e or CDP module (serve-graph.test.ts). Onlywebbuilds
islands at boot, and the metrics listener opens before boot work.- BREAKING —
x shot,x shot --islandand theui.*MCP tools drive Chrome over raw CDP, on the
e2e step's launcher. An app no longer installspuppeteer-core, andX_SHOT_BROWSER_MISSINGnow
means "no Chrome to launch": setCHROME_PATHwhere Chrome is not on the probed paths, or pass
--cdp-url. Requests to hosts off the allow list are refused inside the browser and recorded as
refused: "host", and each response's status is recorded. - BREAKING —
ui.interactstep failures carryX_SHOT_ELEMENT_MISSING,X_SHOT_ELEMENT_UNREADYor
X_SHOT_KEY_INVALIDinmeta.code, notX_SCRAPE_*. - BREAKING —
@ultimat3/realtimeno longer exportsbackoffDelay. Its 0-based copy counted one
step differently from@ultimat3/core's under the same name. Use core's withattempt: n + 1. A
failed channel catch-up now retries after the base wait, not twice it. - BREAKING —
realtime.transportdecides the fanout bus, not the presence ofNATS_URL.
'nats'dials the variablerealtime.urlEnvnames and refuses the boot (X_CONFIG_INVALID) when it
is unset — it used to fall back to in-process in silence.'memory'withNATS_URLset refuses too.
realtime.enabled(defaulttrue) is obeyed:falsestarts nosyncnode and no replicator, and
ROLE=syncalone on such an app refuses.'redis', never built, is removed
fromRealtimeTransport.selectTransport(env)→selectTransport(env, { transport, urlEnv }). x g resourcewrites a real create action: its input is the entity's$view, its org comes
from the actor, and the form posts that shape.x ggrants the permissions it declares (<f>:read
tomember,<f>:writetoadmin), registers the jobs and tasks it writes inapi/index.ts, and
refreshesopenapi.jsonbeside the manifest. The dev actor, the seed and the dashboard share one
demo org. A freshx new+x g resource customeranswersPOST /api/customers/createwith 2xx
underx dev.- New gate findings:
X_PERMISSION_UNGRANTED(a single-permission rule no role grants),
X_JOB_UNREGISTERED(an anonymous job or task),X_ROUTE_ASYNC_PAGE(an asyncPagewith no
load).x g --featurerefuses a slice that does not exist (X_FEATURE_UNKNOWN), and job, task and
action generators no longer invent an entity. A module that will not load is reported once, under
manifest. A boundary finding'sfix:names the exact edit. x build --target dockerstampsBUILD_IDand writes a verified island store (.x/islands/)
the container loads instead of rebuilding; an island that will not parse isX_BUILD_FAILED.- BREAKING —
@ultimat3/testingno longer exportsstartLiveReplicator,LiveReplicatoror
LiveReplicatorOptions. Import them from@ultimat3/realtime/server. x shot's verdict records each response's status and counts responses ≥ 400 as
network.failed— recorded, never gating. The "HTTP response status is not observed" blind spot is
retired.X_CSRF_BLOCKEDfrom a loopback caller names the header that proves same-origin
(-H 'sec-fetch-site: same-origin').- The
AGENTS.mdtabulation warning reads only table headers, so a conventions table no longer
trips it. - BREAKING —
@ultimat3/clino longer exports 236 internals nothing outside the package used:
command objects other thannewCommand,dbCommandandverifyCommand, scan internals, report
helpers and option types.maskLiterals/stripCommentscome from@ultimat3/core. The CLI no
longer depends on@ultimat3/scraping. - BREAKING —
x db gen's schema hash uses core'scanonicalJson. Ifx verify --only drift
reports drift after upgrading, runx db genonce. Neither tracked app needed it. xloads a command's code only when that command runs:x --help1.2 s → 0.24 s. Sass and
Babel load on first use.- The CLI's modules say where they run:
role-*/runtime-*run in production,dev-*only under
x dev(module-naming.test.tsderives it from the import graph). x build --target staticweighs authed routes inside a request, as the app's measurement actor,
with the app's own API answered in-process, and runsloads against a throwaway embedded database
carrying the app's migrations anddevseeds. A dynamic route is weighed at its ownprerender()
paths; one with a budget and noprerender()isX_BUDGET_PARAMS_UNDECLARED, and arender: 'ssr'
route with params is printed as not weighed.- BREAKING — a
from()read that filters or sorts on a column its rows do not carry is
X_QUERY_COLUMN_UNSELECTED(QueryColumnUnselectedError); it used to answer[]. Add the column
to the loader'sselect({ … }), or drop the filter if the loader already applies it. - The database pool runs unnamed statements (
prepare: false). A warmselect *or
returning *no longer fails with0A000 cached plan must not change result typeon every running
pod after a column is added or dropped, and the pool is safe behind PgBouncer's transaction mode.
Measured cost: about 90 µs p50 per statement.Dateparameters are encoded as ISO strings.
Known limitation: on the Postgres pool atimestamptzwith a year before 1000 reads back wrong,
becauseBun.SQLexposes no parser hook for unnamed statements; embedded PGlite reads it right. canonicalJson/fingerprinttag bigints and bytes (BigInt(5),Bytes(<hex>)), so5n
and'5n', andUint8Array([1])and{0:1}, no longer share a key. Idempotency and cache keys for
payloads carrying a bigint change once.- Logger: a caller field named
level,msgortsno longer overwrites the line's own; it is
emitted asfield.<key>. - 4xx failures log at
warn(401/403/429) orinfo; only 5xx logs aterror. - Production 5xx problem bodies no longer carry the server's cause (for example the Postgres
message and SQL ofX_DB_STATEMENT_FAILED).registerProblemMeta({ CODE: { publicCause: true } })
opts a code in. - An action's error takes the pipeline's error path —
onError/reportErroron a 5xx, the HTML
error page,requestId,Retry-After— and deprecation headers ride every response. - A patch property set to
undefinedwrites nothing in either driver; passnullto clear a column. - Tagged shared responses carry
Surrogate-KeyandCache-Tag, so CDN purges reach Fastly and
Cloudflare.x-cache-tags, which no CDN reads, is no longer written. - Compose is hardened and rotates logs (
read_only, tmpfs,cap_drop: [ALL],
no-new-privileges,mem_limit),stop_grace_period40 s. The scaffold Dockerfile installs from
manifests only; the demo image is--production(842 → 594 MB). - Release path:
release.ymlis split into acheckjob (no environment, noid-token: the ref
check,release.ts --check, andci.yml'sverifyon the tagged commit) and apublishjob
(needs: check,environment: npm-publish). The in-workflowverifyre-run, which had no
Postgres, NATS or Redis, is gone.publishskips a package npm already holds, so
gh run rerun <id> --failedresumes a partial release. Every printed tag command is annotated.
deploy-social-demo.ymlruns onworkflow_runofciand builds the exact commit CI passed. - The gate:
bun run verify --only <step>runs one step, and an unknown flag or step is refused
(X_CLI_BAD_FLAG). Thetypecheckstep runstsc -p .in a root withoutreferences, so an
upgrade to a version Bun already had cached no longer passes locally while CI fails (#450). The
manifeststep runs besidelive;noFloatingPromisesis scoped to shipped package source.
Whole-tree guards read one shared corpus and refuse an unreadable tree (X_CORPUS_UNSCANNED).
Added
drain.readinessGraceMs,configureLifecycle({ readinessGraceMs })andServerOptions.drain:
/readyzanswers 503 for 5 s (0 locally) before the listener closes, added to the drain deadline.assertNoDevSecretsOutsideLocal()throwsX_CURSOR_SECRET_DEVat boot outside
development/test; a process that names no environment counts as production.classifyAddress()andisPublicAddress()in@ultimat3/core.hostDecision,hostMatches,ANY_HOSTin@ultimat3/core, moved from@ultimat3/scraping
(which re-exports them).@ultimat3/testingexportscdpConnectOver,CdpTransport,
E2E_ERROR_CODES, and a CDP event listener receives the event'ssessionId.@ultimat3/clino
longer depends on@ultimat3/scraping.withInProcessFetch(fetchImpl, fn)in@ultimat3/core: every typed-client call insidefnis
answered in-process, for a build's measurement render; it wrapsfetchserver-side, inside the
scope only, and costs a browser bundle nothing.defineMeasurementActor(factory)/
measurementActor()declare, fromapp.config.ts, the actor authed pages are weighed as.DbTx.onCommitand entityTx.onCommit;entityForTableanddecodeRowin
@ultimat3/entity;stagedMasterKeyPathin@ultimat3/core;ColumnFact.hasDefaultin the
manifest.?locale=is read as a locale source, aswiki/I18n.mddocuments.x db genemits in-place column changes:set/drop default,drop not null(or the
backfill note for NOT NULL), and a generated column's retype when it becomes plain.- Webhook delivery refuses non-public targets: the host is resolved and loopback, private,
link-local, ULA, CGNAT and unspecified addresses are refused (allowPrivate: trueopts out); the
connection goes to the approved address;http:is refused outside a local environment. - Helm charts: a hook ServiceAccount for the migrate Job,
startupProbeon every role, a 5 s
preStopsleep on Kubernetes 1.30+, the worker HPA on anExternalqueue_depthmetric,
scheduler memory 512Mi. Adeploy-proofCI job installs and upgrades the chart on kind under load. - Gate rules:
pin-raises(X_PIN_RAISE_UNSTATED), stale "unreleased" claims in
changelog-check(X_DOC_UNRELEASED_STALE), a generatedllms.txt(X_LLMS_TXT_DRIFT,
bun run llms-txt --write);budget-raisesfetchesorigin/mainor refuses
X_BUDGET_BASE_MISSING.scripts/release.tsrefuses a dirty tree (X_RELEASE_TREE_DIRTY) and a
--versionat or below the current one or combined with--bump(X_RELEASE_VERSION_INVALID). X_STORAGE_NOT_PENDING(409),X_JOB_NOT_REQUEUEABLE(409),X_JOB_DECLARATION_INVALID.
Fixed
- core:
writeMasterKeyFilereplaces the key atomically at 0600. Prometheus HELP lines no longer
escape". A same-key read issued right afterbump()no longer joins the aborted flight. OTLP
exporters hold at most one batch in flight while a collector stalls.probeImageapplies JPEG EXIF
orientation. Config overlays merge key by key, and an overlay'sundefinedchanges nothing.
jobs.concurrency,jobs.maxAttempts,jobs.visibilityTimeoutMsandcache.defaultTtlMsare
refused at boot unless whole numbers in range. - http: a
publiccache hint on a signed-in request isprivate. The error page's retry link can
no longer point to another host.x-forwarded-client-certvalues are unescaped once. Security
headers are built once per config (30 µs → 0.03 µs per response). - auth: OAuth userinfo/emails fetch failures and the token leg no longer put provider text (which
could carryclient_secret) in the public body.issueApiKeyrefuses anenvparseApiKey
cannot read back.MemoryAdapter.linkAccountkeeps the owner on re-link;linkAccountreturns the
stored row;listApiKeyshas one order in both adapters. - db: a
BEGIN ATOMICbody is one statement. The replica breaker ignores errors in the caller's
own statement. Two PGlite clients no longer write into each other's transactions.reapBranches
refuses a non-integermaxAgeMs. The ledger id inrollback()'s fix line is encoded. Generated
expressions are screened on every path. Embedded Postgres reads every timestamp in any session zone. - entity / query: the memory driver refuses duplicate keys (
X_DB_UNIQUE_VIOLATION).
.transition()works on entities not keyed byid.decimal()/bigint()store Postgres's
canonical spelling in both drivers. A seedupsertreportsskippedon re-run.min/maxover
timestamptzis right in any session zone. Keyset pagination keeps numeric id tiebreaks. The live
matcher treats equalbigintandnumberas equal.text({ max })counts code points and
integer()enforces int4. - storage:
promoteAttachmentaccepts only a pending key.sweepOrphansrefuses a non-integer
olderThanMs. The local disk treats a process that names no environment as production. - money renders every digit up to
MAX_SAFE_INTEGER. time:fromIsorefuses non-ISO text.
i18n: a registeredpt-BRresolves regardless of case. seo: offsetless feed dates are
treated as absent; a title may contain$$; anullrequired JSON-LD field raisesX_LD_INVALID. - action: an idempotent replay is re-validated against the output schema. A mutator carries
row,rateLimitanddeprecated. - jobs: a bad cron is refused at
task(), and one failing task no longer stops the round. Step
replays have one shape on every driver. A claim round that fails partway returns the rest of its
batch without using attempts. A due delayed job counts as ready. A SIGTERM during a manual
scheduler stop respects the budget.x jobs retryrefuses a live job (X_JOB_NOT_REQUEUEABLE) and
--from-stepdrops the steps after the target too. - mcp:
readonly-sqlrefuses dollar tags with digits or non-ASCII characters, and a$tag$
glued to an identifier can no longer hide a call.pingandprompts/getare answered. - ai: Bun's connection errors are retried; the redactor runs over
agent()tool results;
re-indexing a shorter document prunes its old chunks; the Postgres vector upsert dedupes repeated
ids; a non-2xx embedder body is bounded. - mail: bytes pipelined after the STARTTLS
220refuse the session (RFC 3207 §4.2). - notify: a digest window closed but not yet drained is no longer lost.
- pwa: stale-while-revalidate keeps its fetch event alive while it refreshes.
- render: ISR route lookup is compiled once per registry change; stream reveals are one constant,
CSP-hashable script (STREAM_REVEAL_BODIES); prerender params that escape the output directory are
refused and URLs are percent-encoded; an emptied stylesheet stops serving underx dev. - ui:
Dialog/Drawerno longer close on a drag that ends on the backdrop;InfiniteScrollno
longer stalls;CopyButtonsays "Copied" only after the write succeeds. - realtime, server: a live patch's
indexis counted against the subscriber's own rows; a cold
window no longer loses rows written during its first read, and its lsn is read before the rows;
Bun's-1send result is a delivered frame and the drop ceiling is per 10 s window; a frame is
encoded once per delivery (16.9 ms → 0.6 ms to 10,000 sockets); fan-out is indexed (80.7 ms →
6.1 ms at 1,000 × 500); channel loaders run as the subscribing actor; NATS KV presence pages (it
answered an empty set past 1,024 members); the replication reader copies a message once (32 MB:
5.6 s → 69 ms); publication andwal_levelpreflight fixes work on managed Postgres. - realtime, client: a write left
inflightby a reload is resent; a write made while the outbox is
non-empty queues behind it; replay holdsnavigator.locks; a tab's realtime recovers from a worker
reap and a bfcache restore; a gap during catch-up earns another read and a failed catch-up shows
failedwhile it retries; an IndexedDB quota abort rejects writes instead of hanging them; a
supersededmore()no longer overwrites the page cursor. - cli:
x gandx newconflict fixes reproduce every flag.x newrefuses a name with no
letters or digits (X_APP_NAME_EMPTY) and never commits into a directory that already existed. An
app that loads no module isX_APP_EMPTY, not a vacuous green. Commands run from a subdirectory
load the root's.env*.x devreadsPORTand releases what it acquired when boot fails.
x build --target staticempties its export directory; a relative--outresolves against the cwd.
x db resetrefuses whilex devruns.x manifest --checkchecksopenapi.json.x secrets rotatesurvives a crash between its writes, and Ctrl-C inx secrets editterminates. The i18n
index is rewritten only if it still matches the template. A throwingapplies()fails one gate step,
not the gate.ui.*tools refuse origin-escaping routes. The island settle waits for the mount
(#474), and an old capture can no longer hide a failed one.package-shapescans imports with the
transpiler (#493). - The dev row observer reports changes at
COMMIT; a rollback reports nothing.
installSecretsrecovers from a key rotation interrupted before its rename. Adding a NOT NULL
column with a default is additive in the manifest diff. Scraping's request interception leaves no
unhandled rejections. - core:
maskLiterals/stripCommentshandle a template literal nested inside another
template's${}; they used to close the outer template early and hide every literal after it from
the gate's scanners. - deploy: a first
helm installno longer hangs on the pre-install migrate Job.
Commits
- docs: 22.0.0 leaves flight in Upgrading; milestone 11 closed on main's deploy-proof (0/9,028 failed)
- feat!: plan 101 — framework deep sweep (22.0.0) (#512)
- docs(plans): 101 — third sweep and the demo's infrastructure stack (#511)
- docs(plans): 101 — framework deep sweep, 18 tier-ordered slices (#510)