Repository navigation
chore: synchronize dev with main after alpha6 - #1475
Closed
SisyphusZheng wants to merge 6 commits into
Closed
SisyphusZheng wants to merge 6 commits into
SisyphusZheng wants to merge 6 commits into
Conversation
…me convergence (#1459) * ci: trim advisory jobs from default PR workflow * feat(alpha5): part-level streaming, WC admission tiers, runtime consolidation Consolidates the alpha5 framework train (local implementation; CI pending): - Streaming: opt-in compiled server executor with route-local defer manifests (#1450), generated Request->Response handler with preflush gates/cancel/backpressure (#1447), browser backfill installer and late part claim (#1448), navigation FSM stream ownership (#1449), shared stream-frame admission policy, Nitro Node/Workers proofs. - WC admission: ADR-0157 tier diagnostics with third-party fixture evidence (#1451) and T1 snapshot prototype with negative upgrade result (#1452). - Runtime: minimal-move keyed reconciliation + benchmarks (#1455), one internal LifetimeScope type replacing ElementLifecycle (#1458), internal renderer selection convergence with byte-identical generated entries (#1457), each prevalidation and fail-closed Part Program conformance (#1456). - Release engineering: CI nested-packed de-dup, evidence/receipt hardening (#1443), streaming reference route + benchmark (#1453), ADR-0158/0159 drafts (PROPOSED), qualification matrix, CHANGELOG. * chore(www): regenerate content dates after alpha5 content commit * fix(alpha5): qualification hardening — T2 probe, review fixes, tier corrections - T2 stream-survival probe (#1451): a Lit element server-born in the streamed shell survives stream+backfill (single instance, slot children preserved, interactive after upgrade); boundary documented — foreign tags are fail-closed inside backfilled deferred regions. - Twenty review-driven fixes across five hardening rounds: typed-frame comparison (number/boolean/null text Parts), front-gate thenable sweeps (rejections become 500s, not process deaths), build/runtime/browser budget parity (32 fields / 64 owners / 64 properties), shared stream-frame admission policy with entity-obfuscation normalization (element canonical + router copy pinned by parity tests), early-frame claim-drift fix (resolved seed applied after pending own values, server value wins like late frames), explicit benchmark permissions, honest parity comments, no repo-internal paths in shipped artifacts. - WC admission corrections (#1451): firstChild pre-upgrade capture (Shoelace sl-button and Material md-filled-button now genuinely pass T0 — 3/11), hydrationSafe null semantics, zh translation and full site wiring for the web-component-admission page. - Legacy fixes surfaced by the full root suite: create README stale alpha.2 pin updated to registry truth alpha.4. * refactor(alpha5): promote streamed-frame policy to a public export; accept ADRs - Option B (owner ruling 2026-09-25): the canonical stream-frame admission policy is now exported from @openelement/element's public surface; the router-side verbatim copy is deleted and its consumers (entry-stream-runtime, stream-manifest) import the public export. The parity test is replaced by a direct unit test against the exported policy (32-case corpus; one stale 
 expectation corrected). - ADR-0157/0158/0159 marked ACCEPTED (2026-09-25 owner ruling; alpha public-API variability explicitly accepted); qualification matrix and WC admission docs (en/zh) synced to the accepted status. - Interface snapshot: +5 policy exports across the two surfaces. * test(alpha5): sweep residuals — real assertions, honest gates, live evidence Ten owner-ordered residual fixes plus two review follow-ups: - SWEEP-1/2: replace tautological reconnect/signal assertions with real kernel/scope contract tests (distinct instances, abort lifecycle). - SWEEP-3: stream-handler harness now slices the REAL generated channel-merge helper (fail-loud markers) and proves protocol-header precedence + Set-Cookie through the generated GET. - SWEEP-4: WC light-DOM child verification scoped to the host element (balanced tag slicing) instead of whole-document substring match. - SWEEP-5: 'export { x as loader }' aliases admitted end-to-end (export name is the module.loader contract); follow-up: duplicate 'as loader' exports rejected by the scan with an actionable diagnostic. - SWEEP-6: cancel-while-parked no longer closes a cancelled stream; regression probe bounded with a deadline (no unbounded polling). - SWEEP-7: app-shell gate investigated — project-level invariant kept, both build and generated-guard errors now tell the truth and name the project-wide fix. - SWEEP-8/9: benchmark metadata now computed (git-status probe, no port race — single in-process serve). - SWEEP-10: snapshot cache hit/miss are observations, README aligned.
* feat(www): generate article routes from content; document streaming - New generator www/tools/generate-site-article-routes.ts: the single writer of article route modules, component bindings, and the route table (imported by article-pages tests). --check enforces byte identity; stray hand-written files and symlinks fail closed; duplicate output collisions (e.g. an 'index' article vs a collection overview) throw instead of silently dropping a route. - All 24 existing articles migrated to generator output (46/48 files byte-identical to the hand-written versions; dist output verified byte-identical pre/post migration). check wired into generate:all and the release train. - Streaming guide (en/zh): opt-in defer syntax, front gate vs deferred fields, budgets mirrored in four places incl. the 64-property seed cap, no-JS arrival-order tail, null literal semantics, islands and nested components emit as empty hosts on streamed shells (linked from islands-and-ssr), post-commit failures emit a generic error frame (no error-variant content), byte-identical output with streaming off. - doc-figures pins re-baselined to current dist measurements. * chore(www): regenerate content dates after generator lane content commit
* release: 1.0.0-alpha.5 — rendered as data resolves Advances the six version points via version-bump (4 package configs, create anchor, 4 fixture locks), admits the train (ADMITTED_ACTIVE_TARGET, release-state sourceVersion/activeTarget), and finalizes the CHANGELOG section header. Publishing follows the standard train: exact-SHA CI on main, Release workflow dispatch under the openelement-release environment, npm trusted publishing, receipt verification, tag + GitHub Release, post-publish registry-truth sync. * release: regenerate ui manifest at 1.0.0-alpha.5 (seventh version site, generator-owned)
The pinned fixture mirrors the repo's current source versions and release-state; it still pinned alpha.4 after the train admission, failing tools/repo#test:coverage:check (the eighth release-bookkeeping site). Registry evidence in the fixture is untouched: npm truth stays alpha.4 until publish.
…ete) (#1463) Registry verified 2026-09-26: all four packages published under the alpha dist-tag; latest untouched. latestPrerelease partition advanced, per-package alpha dist-tags recorded, create README install pin and the least-privilege exemption line follow the published version.
…lizer, manifest-driven injection (S0-S6) (#1474) * docs(adr): ADR-0160 architecture-debt repayment charter + alpha6 baseline evidence * chore(version): purge historical release names from shipped source; anchor www version truth Runtime-facing copy no longer carries retired release trains: the generated banner stamps protocol versions (part-program format / compiled module ABI, central constants in protocol/part-program.ts), and error messages in the element facade, jsx runtimes, compiler render stub, and router authoring speak about the pipeline instead of the 0.44 line; historical comments are de-versioned to their decision/# references. www/app/data/version.ts derives OPENELEMENT_VERSION from SOURCE_VERSION (generated from release-state.json), removing the same-screen dual version; LATEST_PRERELEASE_VERSION and PUBLISHED_PACKAGE_VERSIONS had zero consumers and are deleted. version-bump gains a fail-closed shipped-source historical-version scan (docs, changelogs, content, fixtures, locks allowlisted) and cross-asserts the www anchors via the new www-release-anchor module, which the offline release:state-machine:check also enforces. READMEs state the alpha.5 tree. * refactor(compiler): generic static-sidecar admission replaces router intrinsic The semantic core no longer knows @openelement/router. INTRINSIC_MODULES shrinks to the @openelement/element intrinsics, and the island policy statement (`export const openElement = defineIslandConfig(...)`) is matched against host-injected 'static-sidecar' descriptors ({moduleSpecifier, exportName, kind}) threaded through compileElementModule / compileElementProgram / compiledElementPlugin options; the default core admits none, so an unconfigured compiler rejects the statement with OEC9008. Router owns its admission descriptor in exactly one place (vite/internal/protocol/island-admission.ts) and injects it at every call site that compiles route or island sources: the vite plugin transform and HMR hook, the SSG and client inline builds, the stream-manifest page identity compile, and the client-only island stub codegen (now generated from the descriptor instead of parallel string literals). The www and saas test harnesses that drive the compiler directly inject the same descriptor. Fail-closed provenance is unchanged and pinned by tests: aliased canonical imports admit, namespace/default/type-only/conflicting/relative-re-export provenance reject (OEC9008 statement fallthrough, OEC9027 decorator provenance), and the element default without injection never admits the sidecar. * chore(router): declare element subpath imports router/src imports six @openelement/element subpaths (. , /authoring, /html, /build-utils, /compiler, /logger) that previously resolved only through the workspace member map; packages/router/deno.json now declares each subpath explicitly, making the dependency visible in the package manifest instead of an artifact of workspace co-presence. * refactor(core): centralize streaming policy constants The numeric streaming/runtime admission budgets lived as bare literals at every enforcement site: the deferred manifest/seed checks in the element facade, the router's build-time manifest scan, the generated stream runtime timeout default, and the generated-string copies the browser bootstrap and entry codegen carry. A value adjusted at one site silently drifted from the others. internal/protocol/policy.ts (import-free, same base-of-graph contract as stream-frame-policy.ts) now names them once — STREAM_MAX_FIELDS (32), STREAM_MAX_OWNERS (64), STREAM_MAX_SEED_PROPERTIES (64), STREAM_MAX_PAYLOAD_LENGTH (256 Ki), MAX_COMPOSITION_DEPTH (8), MAX_ACTION_BODY_BYTES (10 MiB), STREAM_TIMEOUT_MS (30s), IDLE_FALLBACK_TIMEOUT_MS (50ms) — and the public surface carries them to the router pipeline the same way STREAM_FRAME_* already travels. The real-TS enforcement sites compare against the named constants; the copies inside generated strings are a separate convergence pass. * refactor(router): converge raw errors into the error catalog The build pipeline still raised bare Errors, so a host could not classify a delivery, entry-admission, descriptor or SSG-render failure by code and the failure surfaces could not be enumerated. internal/error-codes.ts now carries one table per raising surface — DeliveryErrorCode, IslandEntryErrorCode, DescriptorErrorCode, SsgRenderErrorCode and DocumentErrorCode — plus a buildError factory (phase 'build', cause preserved) beside the existing authoringError. The five converged files (delivery.ts, entry-generators.ts, entry-descriptor.ts, ssg-render.ts, document.ts) raise through it; their message text is unchanged, and copy-inside-generated-string throws are a later pass. element: the streamed-seed type mismatch in connectedCallback no longer reuses OE_PROGRAM_MISSING — it reports its own OE_STREAM_TYPE_MISMATCH, so a host can tell a seed contract drift from a missing compiled program. The error-catalogue tests gain coverage for both: a router catalog test (stable unique values, factory phases, one raiser per converged surface) and a stream-facade test pinning the new code and phase. * refactor(www): derive locale unions from the SiteLocale single source Every handwritten 'en' | 'zh' in site routes, site-ui, data and tooling now points at SiteLocale from www/site-config.ts (issue #1468 item 6). The redirects emitter drops its locale cast outright: indexing perLocale with SITE_LOCALES is already exact and fails closed if a locale is added. * feat(ui): export instance-state, mark six unadopted components experimental Owner ruling C1 (#1468, item 7): open-card, open-callout, open-dialog, open-dropdown, open-tabs and open-input carry no compatibility promise until each has standalone adoption evidence. - The ui manifest generator's fail-loud policy registry now also owns a per-class status ('stable' | 'experimental') emitted into each declaration's openElement block; OpenElementExtensions grows the optional field. - The six component headers state the experimental status; the other four are pinned 'stable'. - readInstanceState/writeInstanceState join the @openelement/ui public surface (index re-export plus a side-effect-free './instance-state' subpath); the www island-state copy is deleted and both islands consume the subpath — the barrel would pull all ten compiled components into the two largest island chunks against the 100 KiB islandKB SLO (www/site-budget.ts). - The www API reference page renders an experimental chip from the manifest status; the api-reference generator threads it through. - Public-interface snapshot regenerated for the new exports. * chore(repo): retire dead tasks and merge the duplicate core gate Remove tasks and scripts with zero references anywhere (workflows, hooks, tests, docs included): tools/repo census + tracked-census.ts, perf:baseline / perf:record + perf-record.ts, the generate:export-files write variant, and tools/release consumer:packaged-serve:node / :bun / consumer:element-smoke (the CI workflows invoke those scripts directly with scoped flags). generate:export-files was the write-mode enrollment that fed generate:all; with it gone the generator's committed output is refreshed by the documented script invocation, so check-generator-gates orphan detection now follows its own documented rule ("referenced by some task") instead of only counting generate:*/emit-* task references. The generated file header points at the script and the regeneration also lands the pending ui/instance-state export left stale by 13105b234. gate:ci and verify:core were byte-identical; verify:core survives as the one definition and check-task-contracts.test.ts pins it. Doc rows and docstrings that named gate:ci or the deleted consumer tasks now name the surviving surface. * ci(release): verify all four package versions without deno eval The release workflow's two inline deno eval version checks violated the least-privilege tripwire (deno eval runs with implicit -A) and only covered element and router. They are replaced by tools/repo/check-release-version.ts, a deno run --allow-read script that reads every manifest through version-bump.ts PACKAGE_CONFIGS (the same single source the bump edits) and validates the dispatch input and each manifest version against the release line contract in tools/lib/version.ts, so the workflow can no longer verify a narrower package set than the bump writes. * chore(benchmarks): remove committed local measurement, mark manual scripts Delete benchmarks/streaming/alpha5-local.json: a dirty-checkout darwin Chromium run committed into the tree, against the jfb harness doctrine that local results are observations in gitignored .artifacts/, never committed baselines. The streaming README and measure.ts docstring now point --out at .gitignored .artifacts/ and state the script is manual — deno task bench and CI never run it — and the alpha5 qualification map no longer describes the file as tracked. micro.ts keeps its packages/element/src/internal/** imports (the compiled runtime, serializer and signal engine it measures are deliberately not on the public surface) and now says so in its header, together with the fact that deno task bench exercises the suite through micro.test.ts; its deterministic self-checks pass under the bench task flags. * docs: correct comments that reference retired modules props-utils.ts described the normalizePublicProps consumers as the deleted render-dsd.ts and jsx-render-dom.ts; the surviving truth is the collectPublicProps host-collection path plus the shared isDangerousKey predicate that injectPropsSafe and the Router page projectors enforce. router/vite/index.ts listed a defineIsland element export that never existed on that surface (island authoring is defineIslandConfig on the router root entry) and named a generated-data-resolver.ts module that is gone (the import-map resolver in deno-import-map.ts owns the site aliases today). * test(router): re-pin client entry bytes after banner de-versioning b22a3c7c3 de-versioned the generated client entry banner ('(v0.44 - ' -> '('), shrinking both client entries by 8 bytes; the renderer-adapter pin test still asserted the old bytes, so the router suite failed round 1 of the full gate. Re-pin native client 1991 -> 1983 (e3ea822d...) and lit client 3146 -> 3138 (ec06ba01...); server pins are unchanged. Not a blind re-pin: re-inserting the removed 'v0.44 - ' segment into the current output reproduces both old SHA-256 hashes exactly, proving the generated-output delta is precisely that intentional banner removal and nothing else. renderer-adapter.test.ts is not one of the oracle files. * docs(adr): index ADR-0157 through ADR-0159 * feat(serializer): shared pure serialization kernel + differential parity harness The compiled Element serializer had two parallel Part Program tree walkers: the server serializer (internal/compiled/server/index.ts) and the runtime seed serializer (internal/compiled/runtime.ts serializeToHtml). Both walked the template, interpreted anchors and Regions, and assembled attributes; only the escape implementation was shared. serialize-program.ts is now the ONE tree walker (issue #1469, ADR-0160 rule b): host-free, DOM-free, module-state-free, no signal creation — every execution-mode difference is an explicit seam (signal reads, sink emissions, item admission, trusted-HTML capability, nested-element rendering, slot projection, pending streamed markers). The server and seed entry points delegate to it through thin seam adapters. The pre-kernel walkers stay temporarily as *Legacy oracle exports, and compiled-serializer-differential.test.ts replays the full corpus (static and dynamic attrs, bool/class/style sinks, prop JSON, void tags, when/each Regions, item slots, slot projection, trusted HTML, unsafe-program rejections, DSD modes, nested custom elements, deferred pending seeds, the shared compiled-claim fixture) through both implementations and requires byte-identical output. Serialization bytes are unchanged. * refactor(serializer): retire the duplicated walkers, parity test becomes kernel contract With the differential harness green over the full corpus, the pre-kernel seed walker (runtime.ts serializedFixedAttributes/serializeElement/ serializeNode) and the pre-kernel server walker (server/index.ts snapshotProgram context machine plus its serialize* walk) are deleted. The seam adapters in both execution modules are now the only serialization logic they carry; serialize-program.ts is the one tree-walking serializer (issue #1469, ADR-0160 rule b). compiled-escape-parity.test.ts keeps every byte pin it guarded before — the attr/fixed-attribute/text corpora still require byte-identical output across the server and seed entry points and pin escapeAttr/escapeText directly — and gains a structural guard asserting both execution modules import the shared kernel and carry no private walker. The void-tags-convergence consumer list moves runtime.ts to the kernel, which now owns the void-tag references the retired walker carried. Serialization bytes are unchanged. * refactor(router): typed response/header channel replaces string runtime (block a) Issue #1470 block a of the ADR-0160 generated-entry repayment. The request-time semantics that used to live inside codegen template strings — the loader/action response-header channel merge with its protocol-header precedence and multi-value Set-Cookie handling (ADR-0129), the streamed route's late-mutation Proxy gate and its header-commitment switch (ADR-0158), and the CSP auto-nonce creation/policy instantiation — move into typecheckable modules under packages/router/src/vite/internal/server-runtime/ (types.ts, response-channel.ts, mod.ts barrel). Generated entries now import them via the new @openelement/router/server-runtime export subpath; the emitters keep only call sites. Generated-entry bytes change (admitted: ADR-0160 "Admitted output deltas", S3a): renderer-adapter byte pins re-computed (native server 27507 -> 27032, lit server 25562 -> 25087; client entries unchanged). Derived artifacts regenerated by ritual: generated-export-files.ts and the public-interface snapshot gain the new subpath (6 documented symbols). Oracle evidence: request-time-parity green on all 29 steps for both dev and Nitro against the rebuilt fixture; stream-manifest, renderer-scope- parity, ssg-admission-parity, lit-graph-boundary (new subpath walked, kernel-free), compiler-open-core-boundary, registry-marker-drift all green unweakened; stream-handler.test.ts now binds the real module through its string-eval harness (no local copy). New unit tests pin the module semantics (14 cases in server-runtime-response-channel.test.ts). * refactor(router): typed page/document/render runtime replaces string helpers (block b) Issue #1470 block b of the ADR-0160 generated-entry repayment. The page-render semantics that used to live inside codegen template strings — the __ssr page seam (native renderDsd fork and lit renderLitPageToHtml fork), the __resolvePageTag forks (compiled program / lit openElementPageTag), the page props projection with its dangerous-key guard (#1214), the page-definition/route-meta extractors, path locale resolution, shell href localization, status-page HTML, and the app-shell composition (__resolveAppShell/__renderAppShell) — move verbatim into typecheckable modules under packages/router/src/vite/internal/server-runtime/ (page-render.ts, renderer-runtime.ts, document-runtime.ts, mod.ts barrel). Generated entries import them via @openelement/router/server-runtime and keep only the renderer-adapter-selected factory bindings wired to their serialized build data; the element functions (renderDsd, trustedHtml, escapeHtml, the SSR registry, renderLitPageToHtml) are injected at binding time, so the modules carry no Element import edge and the LIT entry graph stays kernel-free (#1339). entry-render-runtime.ts is deleted; the native/lit fork keeps its renderer-adapter seam shape (runtimeSeam()) with renderer-neutral call sites. __createDeferredPageShell moves emitter-to-emitter into the stream runtime emission (entry-stream-runtime.ts) with its text unchanged: it is stream machinery called only by streamed routes, and the stream-manifest oracle pins its emitted shape — its typed migration belongs to the streaming-pump block with that oracle. Helpers are now gated on page routes existing. Generated-entry bytes change (admitted: ADR-0160 "Admitted output deltas", S3b): renderer-adapter byte pins re-computed (native server 27032 -> 22783, lit server 25087 -> 22323; client entries unchanged at the pre-lane baseline: 1983 / 3138 bytes). Derived artifacts regenerated by ritual: the public-interface snapshot grows the server-runtime subpath from 6 to 22 public symbols (./server-runtime was already a declared export). Oracle evidence: request-time-parity green on all 29 steps for both dev and Nitro against the rebuilt fixture (the fixture build exercises the new factory wiring end to end: app-shell composition, error-boundary re-render, styled 404, locale resolution); stream-manifest green unmodified; renderer- scope-parity, ssg-admission-parity, lit-graph-boundary (walk stays kernel- free), compiler-open-core-boundary, registry-marker-drift, and compiled-escape-parity all green unweakened. The string-eval harnesses now execute the shipped typed modules directly; stream-handler.test.ts binds the real implementations through its evaluation context and runs the real emitted __createDeferredPageShell text (15 tests). New unit tests pin the page projection, tag-resolution forks (native + lit), renderer seam, and app-shell runtime semantics. * refactor(router): typed action runtime replaces string protocol (block c) The action POST protocol moves out of the generated-entry template strings into @openelement/router/server-runtime/action-runtime.ts (ADR-0160 rule a, #1470 block c): the CSRF floor (#611/#921/#938/#1382), named-action dispatch (#542), the canonical classification (#541), the RFC 9457 problem+json channel (#863/#549), PRG (#548), the default body limit (#568) bound to the serialized MAX_ACTION_BODY_BYTES policy constant (S1c), the ADR-0121 303 coercion, the 500 error mapping (#558), and the internal Hono-WinterCG bridge. The entry keeps call sites and one-time bindings; the hono/body-limit and protocol-constant imports are gone from generated code, and the @openelement/router import shrinks to the two lifecycle guards. The ADR-0120/0121 entry-renderer string pins become wiring pins plus a new 22-test behavior suite driving the shipped module; the string-eval harness binds the real bridge/body-limit through deps (no harness-local reimplementation left). Byte evidence at the renderer-adapter pin: native server entry 22783 -> 17478, lit 22323 -> 17018; client entries unchanged at the pre-lane baseline. Delta recorded in ADR-0160 (S3c). request-time-parity green on all 29 steps for both runtimes against the rebuilt fixture - it caught one real wire divergence during migration (fetch redirect answering HTTP 303 instead of the pinned HTTP 200 + body-303 ActionResult), fixed before landing. * refactor(router): typed stream runtime replaces embedded template (block d) The streaming pump moves out of the generated-entry template strings into @openelement/router/server-runtime/stream-runtime.ts (ADR-0160 rule a, #1470 block d): the request scope with its abort fan-out and cancel detach, the deferred-field observer front gate with its rejection-observation sweep, the 32/64 bounded manifest budget, the 256 KiB payload bound on the escaping encoder and the backfill ranges, the shell commitment with its typed seed attribute, the bounded wake/queue behind the highWaterMark:0 ReadableStream, the 30s timeout sweep, Part backfill frames with their terminal error frames, the no-JS tail, and the browser installer bootstrap as the single-point STREAM_BROWSER_BOOTSTRAP constant string. The entry imports the four functions, binds const __streamBody = __createStreamBody({ escapeAttr }), and passes the bootstrap constant to documentStreamParts; the bootstrap stays an inline head script per streamed page (S4 re-homes it). The policy numbers now reference the S1c policy constants instead of bare literals: element/authoring gains the nine STREAM_* budgets/frame lists (kernel-free leaf, same transport as the action protocol constants), so the typed module imports them without an Element-runtime edge and the LIT graph stays kernel-free. The server-runtime subpath grows 34 -> 44 public symbols and the element authoring leaf by nine constants; the public-interface snapshot is regenerated for both. The __createDeferredPageShell gate stays emitted byte-identical (entry-stream-runtime.ts shrinks to that one emitter): the read-only stream-manifest oracle pins its emitted shape, so its typed migration needs an oracle amendment - recorded in the S3d delta. Pre/post diff evidence: the bootstrap string is byte-identical (14039 chars) and the gate emission is byte-identical up to the removed pump. Evidence: stream-manifest green unmodified (13 tests, emitted-shape pins hold); request-time-parity green on all 29 steps for both runtimes against the rebuilt fixture; lit-graph-boundary green with the negative control; renderer-adapter byte pins unchanged (17478/17018 server, 1983/3138 client - the pinned descriptors have no stream routes); renderer-scope-parity, ssg-admission-parity, compiler-open-core-boundary, registry-marker-drift, and compiled-escape-parity green with assertions intact; stream-handler.test.ts green (15 tests, unchanged assertions) with the real pump bound through deps; stream-browser.test.ts green (7 tests, real Chromium against the byte-identical bootstrap); new server-runtime-stream-runtime.test.ts drives the typed module directly (13 tests). * refactor(router): generated entry reduced to route wiring (block e) + gate: no runtime bodies in codegen ADR-0160 rule (a), #1470 block e. The generated Hono entry's final form is imports + route-descriptor data + one createGeneratedApp({...}) factory call plus per-route wiring. New server-runtime modules own the assembly: - app.ts: createGeneratedApp — Hono app + WinterCG bridge, the composed handler exports (middleware.use onion, devFetch, runtime adapter), the #951 client-script plumbing, and the page-render bindings. - security.ts: the SSR registry guard (fail-closed ownership; imports the canonical registry markers instead of generated-string injection) and the canonical DANGEROUS_KEYS binding. - route-dispatch.ts: the startup stream guards, the page handler table, and the 405 responder. Serialized-copy deletion per the S3 import verdict (only the repo's own string-eval harness cannot import element, and it binds via deps): __DANGEROUS_KEYS and __maxActionBodyBytes are gone — the factory imports both from the kernel-free /authoring leaf, which gains MAX_ACTION_BODY_BYTES. __ssrRenderableTags/shell plan/locales stay descriptor data, now factory config. Emitted per-route GET/POST/404 wiring and call sites are unchanged; the dispatch composition follows the handler population as before. Hard gates (generated-entry-gate.test.ts): standalone TS parse, allowlisted function declarations + retired-emission ban, no dangerous-key literals, client graph never reaches server-runtime (walk + negative control). registry-marker-drift is rewritten per the lane's design exception: wire values and polyfill banner pins stay, the injection pins become guard-seam pins plus guard behavior cases. Byte pins: native server 17478 -> 14141, lit server 17018 -> 14254; clients unchanged at the pre-lane baseline. Oracle evidence and the full delta are recorded in ADR-0160 (S3e). * refactor(router): amend ADR-0160 (amendment 1) — last emitted runtime body becomes typed The __createDeferredPageShell gate was the lane's last runtime function body emitted into a generated entry — the one carve-out S3d kept "with the oracle" because the read-only stream-manifest pin held its emitted text byte-exact. ADR-0160 Amendment 1 replaces that pin with the typed seam: stream-runtime.ts gains the createDeferredPageShell factory (same fail-closed condition, same error text, same executor delegation), the entry imports and binds it next to the pump, the emptied entry-stream-runtime.ts emitter is deleted, and the gate's contract is pinned as behavior on the typed module (missing manifest, program tag/version mismatch, uncompiled class, exact delegation). The generated-entry-gate request-time function allowlist narrows to zero (streamed entry shapes now gated) and the emitted head joins the retired list; ./server-runtime grows by the factory and its config type (interface:snapshot:write ritual). * chore: wire idle-fallback constant S1c named IDLE_FALLBACK_TIMEOUT_MS but left one emission site reading a bare 50: island-scheduler.ts's requestIdleCallback || requestAnimationFrame || setTimeout fallback. The import-free scheduler module (it bundles into any consumer build unchanged, #868) cannot import the constant, so the value rides the #1470-block-c __maxActionBodyBytes seam: IslandSchedulerDeps gains idleFallbackTimeoutMs and the generated client entry serializes the policy constant at build time (derivation pinned in entry-generators.test.ts, fallback behavior pinned in island-scheduler.test.ts). Client-entry bytes move +29 B (renderer pins updated; the 2048 B #868 wiring budget still holds); the delta is recorded under ADR-0160 admitted output deltas (S4). * fix(router): await the deferred-shell executor delegation (require-await) deno lint's require-await flagged the async gate: it returned the createDeferredDsdExecutor promise without an await. `return await` keeps the gate an async function — the fail-closed check still rejects instead of throwing synchronously, matching the emitted original — at the cost of one extra microtask before settlement, which no consumer observes (every call site awaits the gate). Repo-wide deno lint green; stream-handler, stream runtime behavior pins, stream-manifest oracle, generated-entry gate, and request-time-parity (29 steps) all green. * feat(router): ClientAssetManifest + client-before-SSG build order Issue #1471 items 1/2/5 (ADR-0160 S4a, rule d — manifest-driven client asset injection): - New ClientAssetManifest protocol (internal/protocol/client-assets.ts): { entry, islands: Record<tag, { file, strategy, preload? }>, shared[] }, keyed by compile-time island identity (delivery tag). The builder (vite/client-asset-manifest.ts) joins the island declarations with the Phase 2 build manifest (dist/client/.vite/manifest.json) and Rollup output module metadata — a chunk is matched by the module ids it contains, never by parsing output chunk file names. - closeBundle build order is now Phase 1 SSR -> Phase 2 client -> Phase 3 SSG, so the SSG render pass and the request-time artifact carry the final asset addresses. SSG consumes the exact pre-reorder Phase 1 facts (closeBundle snapshots the island declarations before Phase 2 narrows them to the reachable client set); markComplete semantics and log numbering unchanged. - dist/server/client-script.js becomes client-assets.js — pure structured manifest data, no injection logic. The generated dist/server/index.js reads clientAssets.entry through the #951 client-script wiring (__setRequestTimeClientScript(clientAssets.entry)); the ssg-render placeholder emits the empty manifest. readClientEntryFromManifest is retired with its test (entry lookup lives in findClientEntryFile). Admitted output delta recorded in ADR-0160 (S4a): only dist/server/index.js and the renamed client-assets.js move; fixture rebuild diffs show rendered HTML, client chunks, and island manifests byte-identical. All seven oracles plus generated-entry-gate and the renderer-adapter byte pins green. * fix(router): drop unused resolve import in client-asset-manifest (deno lint) * feat(router): document-time script injection from asset manifest; postprocess filename surgery deleted #1471 items 3/4/6 (S4b, ADR-0160 rule d). ResolvedDocument carries the structured clientScripts descriptors (loading/module/nonce.ts; public ClientScriptDescriptor type + optional third resolvePageDocument parameter), and every render channel — request-time handlers, the SSG render pass, the styled 404, both renderer adapters — serializes the final script tags at document time from the same resolved field. The SSG build hands the Phase 2 client asset manifest's entry URL to the SSR bundle before prerendering through the existing #951 setter seam; the per-request CSP nonce still attaches exactly once at serialization and SSG output keeps rejecting nonces. matchIslandChunkFile (filename-prefix matching), injectClientScript (post-build HTML rewriting) and buildIslandChunkMap are deleted; the strategy/layer/per-page island manifests survive, reading chunk URLs from the manifest's delivery-tag-keyed record via islandChunkMapFromAssetManifest (identity-driven; unrecorded islands are surfaced, never silently mapped). Generated server entries move 14141->14249 (native) and 14254->14362 (lit) bytes; client entries unchanged. interface:snapshot:write regenerated (./document grows ClientScriptDescriptor/ResolvedDocument.clientScripts; ./vite records the S4a clientAssetManifest slot) and the S4b delta is recorded in ADR-0160. New ssg-asset-manifest.test.ts pins the nine-scenario matrix — identity never drifts with a chunk file name. * test(harness): shared qualify harness replaces triplicated ritual runners tests/lib/qualify-harness/ owns the scaffold -> workspace-alias -> router build -> static serve -> Playwright ritual that three harnesses each implemented privately (#1472, ADR-0160 alpha6 debt repayment): - scaffold-app: generate the temporary app via packages/create (source or packed CLI) and copy fixture sources in; - workspace-alias: point the app's import map and vite aliases at workspace source exports, rewire the build task, prime app-local node_modules (deno run - from stdin, replacing the deno eval call); - build-router + admission-plan: the in-repo Router build CLI wiring and the quote-aware ssrAdmissionPlan reader (data extraction, never code loading); - serve-static: thin re-export of tools/lib/static-server.ts; - drive-chromium: browser launch + dist serving + page-error collection with ordered teardown. web-component-interop/qualify.ts (1472 -> 1214), third-party-web-components/ qualify.ts (1083 -> 966), and starter-smoke/setup.ts (222 -> 169) become callers that keep only their charter-specific probes. The duplicate package export enumeration moves to dependency-light tools/lib/package-aliases.ts so fixture-scoped configs can resolve it. Verified at pre-refactor depth against a HEAD worktree: interop qualify evidence (3 engines x 12 probes) and third-party smoke logs are line- identical modulo checkout paths, entry.js/index.html byte-identical from the same checkout, starter dist artifacts identical; starter-smoke Playwright projects pass 12+24 on chromium/firefox/webkit. Interop fixture gains npm:mime + npm:pathe (tools/lib/static-server transitives); deno.lock regenerated via fixtures:locks:update, check green. * fix(www): reference-page stability chip satisfies the compiled list-Region grammar The conditional JSX committed in 13105b234 ({element.status && ...}) is rejected inside an each-Region item by OEC9013. Render the chip unconditionally and let the existing .chip:empty rule (page-reference-styles.ts) hide it for stable rows carrying status ''. Left uncommitted in the worktree since S1d; S4's site:build gate was green on top of this fix, so it is load-bearing and belongs on the lane. * refactor(element): split compiled runtime into single-duty modules; unify pre-upgrade bookkeeping The 2,779-line compiled Part Program executor becomes a re-export facade plus the seed-serializer seams entry; the execution modules live under compiled/runtime/: program-kernel (shared context/signal/node core), fresh-dom (template walk + fresh creation), regions (when/each machinery), parts (fixed-Part install + text Part), claim + claim-recovery (staged scan, bounded owning recovery), pre-upgrade-events (capture/replay family). The pre-existing kernel.ts keeps its CompiledElementKernel tenant, so the shared core takes the program-kernel.ts name. The facade capture registry (preUpgradeCaptures and the ensure/replay/ release wrappers in the OpenElement facade) merges into pre-upgrade-events — one bookkeeping layer; the public ensurePreHydrationClickCapture export (name, signature, JSDoc) is unchanged and the public runtime surface re-points to the new home. Moved function bodies are byte-identical to the pre-split module (verified by extraction diff); the 64-record cap and every pre-upgrade behavior pin are untouched. The facade deliberately keeps hosting serializeToHtml: the compiled-escape- parity oracle and the when-operator convergence guard pin its source as a site that imports condition-holds and the shared serializer kernel. * refactor(compiler): split semantic core into single-duty modules; semantic analysis takes injected vocabulary The 2,381-line compile.ts facade decomposes into six single-duty modules (#1473 item 1): parse-module.ts, analyze-module.ts, lower-program.ts, emit-program.ts, emit-module.ts and compiler-diagnostics.ts. Every moved block is byte-verified verbatim against the pre-split file; compile.ts stays the internal entry, wiring parse -> analyze -> lower -> program -> emit and re-exporting the boundary surface (CompiledElementError, compileElementProgram, CompileElementResult, ElementCompilerDiagnostic), so plugin.ts and every compiler test import unchanged. parse-module.ts is the narrow parse seam (#1473 item 2): an explicit ParserPort (source -> TS AST + syntax diagnostics) whose sole implementation is the one module depending on the TypeScript parsing API. Its header records the retirement triggers from ADR-0160 and the alpha6 lane: the TS6 JS-API EOL or oxc standard decorators reaching stability, whichever lands first — the future oxc/tsgo backend swaps in exactly there. The semantic core no longer knows @openelement/router (#1473 item 3, S1b follow-up; ADR-0160 rule c). analyzeModuleSemantics gains an optional ModuleSemanticsOptions.vocabulary of plain ModuleVocabularyDescriptor entries ({moduleSpecifier, exportName, kind: 'page-definition' | 'element-registration'}); the built-in vocabulary covers only the element package's own registration factories, so the default scan fails closed on router factories. Router owns its vocabulary in one place (vite/internal/protocol/module-vocabulary.ts, beside the S1b island-admission descriptor) and injects it at every module-scan call site: route-scanner, foreign-tag-scanner, static-component-scanner and build-client. Element's plugin gate keeps the default scan. Tests keep their counterexamples and gain the fail-closed default cases: with no injection, definePage and router registration factories are not recognized; foreign bindings stay unrecognized even with the vocabulary injected. Derived artifacts regenerate by ritual: the public-interface snapshot gains ModuleSemanticsOptions/ModuleVocabularyDescriptor and the widened analyzeModuleSemantics signature (www api-reference unchanged). void-tags-convergence's consumer list points at the new VOID_TAGS home (lower-program.ts). Verified: all 31 moved blocks byte-identical (git-show diff harness); packages/element suite 428 passed; packages/router suite 946 passed (read-only oracles intact, assertions unchanged); targeted deno check/lint/fmt on every touched file; tools/repo generate:all clean. * refactor(router,repo): split god files into single-duty modules; unify fail factory and control-char scan S6c mechanical decomposition (issue #1473 items 3/4/6): move + re-export only, zero behavior change. - vite/plugin.ts (999 lines) -> plugin.ts composes hooks only; the hook families move to plugin-config.ts (shared OpenPluginState, option and config-file resolution, config/configResolved), plugin-scanners.ts (buildStart + route/island discovery + entry descriptor), plugin-hmr.ts (transform/handleHotUpdate with the per-instance program-shape map), plugin-watch.ts (configureServer watcher), plugin-virtual-modules.ts (virtual ids + open:virtual-entry). Plugin names, hook sets, and the returned plugin order are unchanged. - element fail() micro-factories converge on one phase-parameterized factory, raiseFrameworkError (protocol/errors.ts): the four identical csr/render throwers (styles, context, kernel, program-kernel) and the near variants (serialize-program failUnreachable, part-program fail, public-runtime failUncompiled, open-element-implementation failMissingProgram) now delegate to it; call-site message text is unchanged. server/shared.ts keeps CompiledProgramValidationError (a different error class, not a frameworkError variant). - router control-character scan loops (authoring.ts x2, delivery.ts, entry-generators.ts, island-scanner.ts) unify on the canonical hasControlCharacter helper (internal/control-characters.ts) with a dedicated test; rejection messages unchanged. critical-assets.ts keeps its distinct CSS-allowing predicate. - candidate-evidence.ts splits its four spawn-free duties into candidate-evidence-{aggregate,validate,tarballs,site-e2e}.ts with the shell re-exporting the public surface (existing import paths keep working); job-record and fresh-clone duties stay in the shell per the S6c owner ruling (Mimosa write-hook false-positive on the verbatim argument-list Deno.Command helpers - see stage notes). The zero-reference bare candidate:evidence task is removed from tools/repo/deno.json; check-task-contracts and check-task-flags stay green. - .gitignore gains .zcodeignore (local ZCode tool file), removing the repo's only untracked-unignored path. Verified: element 428 tests, router 948 tests, candidate-evidence + task-contract/flags/permissions + evidence-reuse 78 tests, new control-characters tests 2 - all green; tools/repo + tools/lib deno check clean; changed files deno fmt/lint clean. * fix(repo,www): repoint split-module references in error-reference scan and ci-contracts test The #1473 single-duty splits moved code without moving the hardcoded references that track it: - www generate-error-reference scanned only compile.ts and module-analysis.ts for OEC literals, so the catalog collapsed to 14 codes after the compile facade split. The scan now lists every semantic-core module that carries OEC literals (analyze-module, compile, compiler-diagnostics, emit-program, lower-program, module-analysis), and per-code entries are merged across modules before pushing: since the split one code's raising sites legitimately live in several files, so the catalog keeps the first authored message in static COMPILER_SOURCES order and sums the site count. - check-ci-contracts read candidate-evidence.ts for four Site E2E contracts whose symbols moved to candidate-evidence-site-e2e.ts (path constant), candidate-evidence-aggregate.ts (sidecar read from the fresh-clone job) and candidate-evidence-validate.ts (audit wired into the rollup). Each assertion now reads the module the symbol lives in; the no-reintroduction guard stays on candidate-evidence.ts, where the producer's extras staging still lives. Regexes unchanged. * test(ui): assert the layer/hydrate/status policy message S1d (13105b234) added the status dimension to the manifest policy table and its error message ('No layer/hydrate/status policy') but left the matching test assertion update uncommitted in the worktree; the acceptance full-suite run was green on top of this change, so it is load-bearing. * fix(router): explicit return types for packed public API (slow-types) * fix(router): gate the CSP auto-nonce off hono/ssg prerender passes (SSG stays nonce-free) * chore(repo): regenerate public interface snapshot for the CI-fix exports Covers 98480f0d3 (createActionBodyLimit gains its MiddlewareHandler return type; ./server-runtime shape hash) and a7cd22655 (isSsgPrerenderDispatch exported). No other drift: exactly two hunks. * chore(packages): drop decision-record citations from shipped source comments The pack-surface gate (#1412) bans ADR ids in npm artifacts; deno pack preserved two of them (escape-text, runtime facade). Reword the two flagged sites plus the four same-family kernel/ParserPort comments to issue references, which the policy allows. * chore(packages): finish pack-surface cleanup — remaining ADR citations and ui subpath doc entry-server-codegen emits its CSP comment into consumer artifacts, so the ADR id ships in dist output; postprocess carries the same citation family. ui/README now documents the /instance-state subpath added in 13105b234 (policy: every packed export subpath is named in the shipped README). * chore(router): reword remaining ADR citations in codegen sources Two emitted comment strings shipped ADR ids into consumer artifacts (entry-orchestrator), one JSDoc survived packing (entry-route-helpers); issue references replace them per the #1412 artifact-surface policy. * chore(packages): sweep decision-record citations from shipped source (#1412 surface policy) Final ADR pass over the four shipped packages' src: co-cited ADR tokens collapse to their issue reference (e.g. 'ADR-0160 rule a, #1470 block e' -> '#1470 block e'), pure citations (ADR-0129, ADR-0120/0121, ADR-0123, ADR-0158) drop the token and keep the sentence; no issue numbers invented. 20 files, comments only. The entry-descriptor/entry-codegen hits all sit in source comments, not emitted strings, so generated entry bytes should be unchanged; renderer-adapter pins are verified below by the router suite. git grep 'ADR' packages/{element,router,create,ui}/src: zero hits. * chore(router): drop repository-internal path from shipped page-render comment pack-surface:check flagged page-render.js/.d.ts line 14: the JSDoc spelled out the repo path 'packages/element/src/internal/core/ security.ts', which ships in the packed artifact. Name the constant (DANGEROUS_KEYS) and its re-export leaf instead of the path. Comment only; found while sweeping the #1412 gate after the ADR pass. * test(router): re-pin server entry bytes after the emitted-comment ADR sweep 8b75ebdc8 reworded the generated entry's emitted comments for the #1412 surface policy, dropping the ' (ADR-0160 rule a)' segment from the emitted 'Generated-app assembly' comment (-18 bytes, native and lit alike) but did not re-pin, so the router suite has been failing since that commit. Re-pin native server 14249 -> 14231 (e37d5c18...) and lit server 14362 -> 14344 (4433f89b...); client pins are unchanged. Not a blind re-pin: diffing the full dumped native/lit server+client entries across d94b0af5e..current shows exactly that one emitted-comment line per mode and nothing else, and the follow-up comment-only sweep commits (72fe3e09d, 91ff589cb) regenerate byte-identical entries to 8b75ebdc8 — the generated-output delta is precisely 8b75ebdc8's intentional emitted-comment rewording. Assertion semantics untouched (both the length and the SHA-256 assertEquals remain). renderer-adapter .test.ts is not one of the oracle files. * chore(repo): drop the repository-internal path from the export-files banner pack-surface:check flagged the generated file's shipped banner: it told readers to regenerate via a 'tools/repo/...' script path, which ships in the npm artifact and is a path a consumer cannot open (#1412 internal- reference rule). The banner now names the repo's 'generate:all' tooling task instead; the tracked generated module is regenerated in the same commit so tools/repo#export-files:check stays in sync. Comment-only: the OPENELEMENT_EXPORT_FILES data is unchanged. * docs(router): document the server-runtime public subpath in the README pack-surface:check requires every public export subpath to be named in the shipped README (#1412 facade rule); '@openelement/router/server- runtime' was the one undocumented subpath. New section describes what the subpath carries (the generated entries' request-time runtime: the generated-app factory, the response-header channel and its commitment gate, the CSP auto-nonce, the page SSR renderer seam, the action POST protocol, the streaming pump), that generated entries — not applications — import it, and why it is public (type-aware tooling, hand-rolled hosts). * fix(router): client asset manifest fails closed; package island identity is exact-match T1 (#1471, alpha6): the Phase 2 client asset manifest is now a hard gate. readViteClientManifest throws OE_CLIENT_ASSET_MANIFEST_READ / MANIFEST_MALFORMED naming the manifest path and underlying reason instead of catching to null; buildClientAssetManifest throws ENTRY_MISSING when the manifest records no "virtual:open-client-entry" file (islands and enhanced-forms-only alike) instead of shipping entry: '', and an admitted island that resolves to no asset is a named failure (ISLAND_UNMAPPED) instead of the silent `continue`. The buildClient warn-and-continue call site is gone; failures propagate through the existing Phase 2 error path (buildError / internal/error-codes.ts). Pure-static and zero-admitted-island builds still emit zero client JS (pinned by a new static-only fixture regression). T2: package-island module identity no longer substring-matches (id.includes(modulePath) first-hit) — the resolver and the client build's chunk grouping (native manualChunks and the lit codeSplitting group name) share one exact rule (moduleIdentityMatches / packageIslandChunkName): segment-boundary equality or trailing-path match, extension-insensitive, with zero and multiple matches both failing (ISLAND_UNMAPPED / ISLAND_IDENTITY_AMBIGUOUS). Because a declared modulePath is not globally unique (import-map targets resolve outside the specifier string; two packages can ship the same relative name), buildClient resolves each package specifier through the same deno.json import map the build resolver uses and joins on the real module path when one exists; npm/jsr specifiers keep the declared specifier as identity under the same exact rule. Tests for both directions of the rule live in the shared module's suite — no test helper reimplements the matching. New tests: missing manifest, malformed manifest, missing client entry, enhanced-forms-only missing entry, admitted island without a chunk mapping, two-package same-name module ambiguity. * refactor(compiler): defineIsland vocabulary verdict (removed) The module-scan vocabulary on both sides registered defineIsland as an element-registration factory: element CORE_VOCABULARY (@openelement/element) and ROUTER_MODULE_VOCABULARY (@openelement/router). Forensics show both entries are dead — the vocabulary admits imports of a binding neither package exports: - the element package retired the defineIsland() runtime in v0.44 (f0610f102 deleted internal/core/island.ts where it lived); - the router never exported the name — packages/router/src/index.ts exports defineIslandConfig only, and authoring.test.ts pins 'defineIsland' in appSurface === false as part of the v0.44 removal; - the shipped public-interface snapshot carries no bare defineIsland across either package's export paths; - repo-wide grep finds zero real call sites: docs, www content, create templates, test fixtures, and the www app all use defineIslandConfig. The only textual defineIsland callers were the vocabulary's own tests. The entries came over mechanically from the pre-split semantic core, which hard-coded ['@openelement/element', '@openelement/router'] times defineIsland from the era when the runtime existed. No valid program can import the removed binding, so removing the entries cannot change scan outcomes for authored routes; the default scan and the router-injected scan now fail closed on them. - module-analysis.ts CORE_VOCABULARY and module-vocabulary.ts drop the defineIsland entries, each with a comment recording the verdict. - module-analysis.test.ts: the alias cases keep defineElement coverage; two regression pins added — the default scan no longer recognizes defineIsland, and the injected router vocabulary no longer admits it. - foreign-tag-scanner.test.ts: the island fixture no longer authors tags via defineIsland; a regression pin proves a legacy defineIsland call site surfaces as a foreign tag (visibility-only) instead of being silently excluded. - foreign-tag-scanner.ts header comment drops the stale mention. No public surface moves: CORE_VOCABULARY is module-private, module-vocabulary.ts is vite-internal, and the public-interface snapshot is unchanged. The defineIslandConfig policy statement (static sidecar) and the defineElement registrations are untouched. Verified: module-analysis (26), compiler-intrinsic-provenance (20), foreign-tag-scanner (14), lit-renderer-codegen (5), route-scanner-tagname (11) all green; element batch 429 passed; router batch 800 passed with the same 20 pre-existing native-binding environment failures as HEAD (verified by stash). * refactor(repo): candidate evidence record contract and fresh-clone producer become single-duty modules Split the two remaining duties out of candidate-evidence.ts (alpha6 debt train): candidate-evidence-record.ts now owns the StepResult/JobResult/ LoadedJob record shapes, the process primitives (repoRoot/denoExe/required/ expectedSha/assertCleanAtSha/toolVersions), the SHA-free log bookkeeping, and the workspace --job producer; candidate-evidence-fresh-clone.ts owns the fresh-clone lane and its Site E2E sidecar staging. The CLI file keeps only the import.meta.main dispatch and the compatibility re-exports. Aggregate and validate import the record foundation directly, which dissolves the intentional shell-to-lane cycle left by #1473 without adding any new cycle. All moved code is verbatim (diff-audited against HEAD); shapes, failure texts, path roles, SHA/sidecar bindings, and exit behavior are unchanged. The check-ci-contracts no-reintroduction guard follows the moved producer to the record module (semantics unchanged, per the same file's #1473 precedent). * docs(adr): ADR-0160 closure amendment — manifest and identity contracts, vocabulary verdict Amendment 2 records the lane's closure stage (T1-T4): - T1: the Phase 2 client asset manifest failure contract — the five stable OE_CLIENT_ASSET_* codes, the fail-closed boundary (no catch-to-null, no warn-and-continue, no entry:'', no silent island drop), and the message contract (manifest path, island label, identity string named). - T2: the package-island identity contract — one shared exact rule (moduleIdentityMatches/packageIslandChunkName), zero and multiple matches fail, declared specifiers resolve to the real module path where possible. Comply-or-explain: the resolution half covers deno.json imports maps only, not the workspace-member exports the build resolves through workspace-alias.ts, so the official Site's packageIslands: ['@openelement/ui'] now fails OE_CLIENT_ASSET_ISLAND_UNMAPPED — disclosed with the evidence that the pre-closure green build was silently mis-attributing those islands to the client entry chunk. Open repair handed to the implementation lane; not fixed in this docs-only stage. - T3: the defineIsland vocabulary verdict (removed) — dead entries admitting an import no package exports, with the forensics and the fail-closed consequence (legacy call sites surface as foreign tags). - T4: the S6 final responsibility boundary — all seven #1473 items mapped, including the completed candidate-evidence split. - Closure output-delta reconciliation: zero closure delta (fixture trees byte-identical vs bf57d945c; oracle batch 38 passed/29 steps; targeted suites green), every T0-baseline difference mapped to a recorded entry, and the kernel-bundling client chunks' pre-closure byte movement recorded (S1 error-catalog enum entry, S6c fail-factory convergence). Also fixes the one stale authoritative-doc reference the closure sweep found: the CSRF floor citation in docs/architecture/security-and-release-engineering.md still pointed at entry-action-runtime.ts; the floor lives in the typed runActionProtocol since #1470 block c. * fix(router): package island identity resolves through the build's alias table Workspace packages carry no deno.json import-map entry — their module identity lives in the resolve.alias table the client build ships. Extend packageIslandSourcePath to resolve declared specifiers through that same table (segment-exact, longer finds first) so the manifest join and the resolver agree on one identity. Completes the closure workflow's final-gate fix round that the run timeout cut short. * fix(router): alias-table resolution helpers complete the island identity join d1727cbc3 committed the consumer (build-client importing resolveThroughAliases) but not the provider half the interrupted closure fix round had staged. Adds resolveAliasSourcePath/resolveThroughAliases with @rollup/plugin-alias matching semantics (exact or segment-boundary string finds; first-occurrence rewrite; bare/virtual replacements keep the declared specifier) and strips a version reference from the defineIsland verdict comment. * test(www): hydration e2e tolerates the package-island chunk naming The exact-identity join names package island chunks island-<tag>-<hash>.js (#1471); the loader-source regex and namespace unwrap follow the loader's own shape. Last leg of the closure fix round the run timeout interrupted. * fix(router): close client asset manifest failure seams
Member
Author
|
Superseded by conflict-free synchronization PR #1476. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Synchronize the protected
devbranch with the merged alpha6mainbranch.Verification
mainat0ee9df4d420f54d6c40ceb7e60a6692e061eae34main