Skip to content

Commit 466bb45

Browse files
author
DevBot
committed
feat(v0.44): define compiler intrinsics by binding provenance, not spelling (#1209)
Alpha.10 truth closure: the compiler admitted intrinsics by identifier spelling (getText === 'element'), letting foreign/ambient same-name bindings into the OE grammar, with three disagreeing recognizers. - one canonical intrinsic-binding model in the semantic core (createModuleIntrinsicBindings / resolveIntrinsic): module specifier + imported name, aliases followed; bare/global/local spellings never admit; type-only/namespace/default/conflicting/relative-re-export provenance fails closed with OEC9027 - compile.ts: every recognition site uses the model; import injection deleted; generated modules strip compile-time-only element/property bindings; codegen follows aliases - plugin.ts prefilter documented as a non-recognizer; ambiguous provenance routes to the compiler boundary for fail-closed diagnostics - element gains runtime no-op element/property exports (@experimental dual-use contract) so ui/www modules evaluate uncompiled; the ui compile-decorators impostor shim is deleted - all declare-spelling fixtures/templates/www/examples/tools and the MDX generator + v0.44 codemod migrated to canonical imports - 19 hostile provenance tests (RED at baseline) + 3 no-op contract tests Implemented by fresh kimi-code/k3-256k HIGH session (.agents/v044-kimi-implementer.md), packet A10.1 with two orchestrator-reviewed repair rounds (scope expansion + ui dual-use resolution). No frozen ADR-0122 paths touched. No publish, no tag.
1 parent 42f9421 commit 466bb45

139 files changed

Lines changed: 1305 additions & 1051 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/current/PACKAGE_SURFACE.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,10 @@ unaffected: their `tagName` export remains the registration tag.
191191

192192
### v0.44 experimental additions (unfrozen)
193193

194-
| Export (element root) | Class | Purpose | Removal/move condition |
195-
| ----------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
196-
| `isDangerousKey`, `injectPropsSafe`, `DANGEROUS_KEYS` | experimental (#1214) | The one canonical prototype-pollution guard shared by page projection (SPA bootstrap, `projectPageProps`) and adapter codegen, which serializes `DANGEROUS_KEYS` into generated server runtimes at build time | May move to a dedicated security subpath at the B1.2 surface freeze |
194+
| Export (element root) | Class | Purpose | Removal/move condition |
195+
| ----------------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
196+
| `isDangerousKey`, `injectPropsSafe`, `DANGEROUS_KEYS` | experimental (#1214) | The one canonical prototype-pollution guard shared by page projection (SPA bootstrap, `projectPageProps`) and adapter codegen, which serializes `DANGEROUS_KEYS` into generated server runtimes at build time | May move to a dedicated security subpath at the B1.2 surface freeze |
197+
| `element`, `property` | experimental (#1209) | Compile-time-only decorator intrinsics: the compiler admits them by binding provenance (a runtime named import from `@openelement/element`) and erases them from generated code; evaluated without the compiler (unit tests, config evaluation) they are inert no-ops, carrying no runtime semantics and acting as no second recognizer | May move to a dedicated authoring subpath at the B1.2 surface freeze |
197198

198199
## Removed from current graph
199200

‎docs/current/v0.44.0-MIGRATION.md‎

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@ The canonical route module is a thin wrapper around the compiled page element
4444

4545
```tsx
4646
// app/components/page-form.tsx — compiled by the open:compiled-element transform
47-
import { OpenElement } from '@openelement/element';
48-
49-
declare function element(
50-
tag: string,
51-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
52-
): ClassDecorator;
53-
declare function property(options: { reflect: boolean; attribute?: false }): PropertyDecorator;
47+
import { element, OpenElement, property } from '@openelement/element';
5448

5549
@element('form-page', { root: 'shadow-open' })
5650
export default class FormPage extends OpenElement {
@@ -113,15 +107,9 @@ Islands are single-module compiled classes; the delivery policy stays in the
113107
statically scanned `defineIslandConfig` export:
114108

115109
```tsx
116-
import { OpenElement } from '@openelement/element';
110+
import { element, OpenElement, property } from '@openelement/element';
117111
import { defineIslandConfig } from '@openelement/app';
118112

119-
declare function element(
120-
tag: string,
121-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
122-
): ClassDecorator;
123-
declare function property(options: { reflect: boolean; attribute?: false }): PropertyDecorator;
124-
125113
export const openElement = defineIslandConfig({ hydrate: 'visible', ssr: true, dsd: true });
126114

127115
@element('live-counter', { root: 'shadow-open' })
@@ -205,12 +193,14 @@ The automatic subset is deliberately narrow:
205193
or a zero-argument render function.
206194

207195
The generated class uses the canonical `element` decorator and `OpenElement`
208-
import. If the source does not already declare the decorator, the codemod adds
209-
`declare function element(tag: string): ClassDecorator;`. This is compiler-only
210-
input and is erased with the decorator; it is not runtime registration
211-
machinery. Existing class method bodies are retained as source text; the
212-
compiler remains responsible for lowering supported render syntax to the Part
213-
Program.
196+
import. If the source does not already import the decorator, the codemod adds
197+
`element` to the canonical named import from `@openelement/element` (#1209:
198+
the compiler admits intrinsics by binding provenance, never by spelling). The
199+
binding is compile-time-only — the compiler erases the decorator application
200+
and strips the binding from generated imports; evaluated without the compiler
201+
it is an inert no-op, not runtime registration machinery. Existing class
202+
method bodies are retained as source text; the compiler remains responsible
203+
for lowering supported render syntax to the Part Program.
214204

215205
## Manual repair cases
216206

‎docs/release/public-interface-snapshot.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
},
1313
"declarations": {
1414
".": {
15-
"publicShapeSha256": "3334cfeb124b5ad4d7f22fc6647ed8170fd087fc65412a46852a1d26b670b1bb",
15+
"publicShapeSha256": "91ae10b67582b58198720342b1d5e7065af882d94215f04bac7f1adea002c671",
1616
"publicSymbols": [
1717
"ACTION_FETCH_HEADER=value:\"x-openelement-action\"",
1818
"Action=type:{call:(ctx:{env:Env;formData:FormData;params:Record<string, string>;platform:union(Platform|undefined);request:Request;responseHeaders:Headers;route:Route})=>union(Promise<T>|T)}",
@@ -72,6 +72,7 @@
7272
"createLogger=value:{call:(tag:string)=>{debug:{call:(msg:string,...args:array(unknown))=>void};error:{call:(msg:string,...args:array(unknown))=>void};info:{call:(msg:string,...args:array(unknown))=>void};warn:{call:(msg:string,...args:array(unknown))=>void}}}",
7373
"deepGetElementById=value:{call:(id:string,root:union(Document|ShadowRoot))=>union(HTMLElement|null)}",
7474
"effect=value:{call:(fn:{call:()=>union(void|{call:()=>void})})=>{call:()=>void}}",
75+
"element=value:{call:(_tag:string,_options:union(undefined|{delegatesFocus?:union(false|true|undefined);formAssociated?:union(false|true|undefined);root?:union(\"light\"|\"shadow-closed\"|\"shadow-open\"|undefined)}))=>{call:(target:unknown,context:unknown)=>void}}",
7576
"ensureDeepFragmentNavigation=value:{call:(options:{enabled?:union(false|true|undefined)})=>void}",
7677
"ensurePreHydrationClickCapture=value:{call:(root:union(EventTarget|undefined))=>void}",
7778
"escapeAttr=value:{call:(value:string)=>string}",
@@ -81,6 +82,7 @@
8182
"isDangerousKey=value:{call:(key:string)=>union(false|true)}",
8283
"isSafeAttributeName=value:{call:(name:string)=>union(false|true)}",
8384
"isValidTagName=value:{call:(tagName:string)=>union(false|true)}",
85+
"property=value:{call:(_options:{attribute?:union(false|string|undefined);converter?:unknown;reflect:union(false|true);type?:unknown})=>{call:(target:unknown,context:unknown)=>void}}",
8486
"provideContext=value:{call:<T>(host:HTMLElement,context:{readonly defaultValue:T;readonly key:symbol},value:T)=>{call:()=>void}}",
8587
"renderDsd=value:{call:(input:union(CustomElementConstructor|string),options:{componentClass?:union(CustomElementConstructor|undefined);projectedChildren?:union(ReadonlyMap<string, TrustedHtml>|undefined);props?:union(Record<string, unknown>|undefined);sourceInfo?:union(undefined|{route?:union(string|undefined);source?:union(string|undefined)});ssrRenderableTags?:union(array(string)|undefined)})=>{errors:array({code:string;message:string;phase:string;recoverable:union(false|true);severity:union(\"error\"|\"warning\");tagName:string});html:string;hydrationHints:array({hydrate?:union(\"idle\"|\"load\"|\"only\"|\"visible\"|undefined);layer:union(\"dsd-interactive\"|\"dsd-static\"|\"light-dom\"|\"pure-island\");tagName:string});metrics:{hasError:union(false|true);layer:union(\"dsd-interactive\"|\"dsd-static\"|\"light-dom\"|\"pure-island\");nestingDepth:number;renderTimeMs:number;tagName:string;templateSize:number}}}",
8688
"reportError=value:{call:(error:{readonly code:string;readonly phase:union(\"build\"|\"csr\"|\"navigation\"|\"render\"|\"ssr\"|\"unknown\"|\"validation\");readonly recoverable:union(false|true);readonly severity:union(\"error\"|\"warning\");readonly statusCode?:union(number|undefined);toJSON:{call:()=>Record<string, unknown>}})=>void}",

‎examples/supabase-cloudflare-starter/app/components/page-admin.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44
* shown in each row through the section-level forms (grammar v1 list Regions
55
* carry no per-row forms).
66
*/
7-
import { OpenElement } from '@openelement/element';
8-
9-
declare function element(
10-
tag: string,
11-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
12-
): ClassDecorator;
13-
declare function property(
14-
options: { reflect: boolean; attribute?: false },
15-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
7+
import { element, OpenElement, property } from '@openelement/element';
168

179
@element('admin-page', { root: 'shadow-open' })
1810
export default class AdminPage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-auth-callback.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
/** /auth/callback page element (v0.44 compiled). The PKCE exchange runs in the loader; the page renders the outcome. */
2-
import { OpenElement } from '@openelement/element';
3-
4-
declare function element(
5-
tag: string,
6-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
7-
): ClassDecorator;
8-
declare function property(
9-
options: { reflect: boolean; attribute?: false },
10-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
2+
import { element, OpenElement, property } from '@openelement/element';
113

124
@element('auth-callback', { root: 'shadow-open' })
135
export default class AuthCallbackPage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-checkout.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44
* fully static conditional Regions; the attempt id rides a property Part on
55
* the hidden input (the form stays no-JS capable).
66
*/
7-
import { OpenElement } from '@openelement/element';
8-
9-
declare function element(
10-
tag: string,
11-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
12-
): ClassDecorator;
13-
declare function property(
14-
options: { reflect: boolean; attribute?: false },
15-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
7+
import { element, OpenElement, property } from '@openelement/element';
168

179
@element('checkout-page', { root: 'shadow-open' })
1810
export default class CheckoutPage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-home.tsx‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
/** Home page element — public, prerendered at build time (default static intent). */
2-
import { OpenElement } from '@openelement/element';
3-
4-
declare function element(
5-
tag: string,
6-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
7-
): ClassDecorator;
2+
import { element, OpenElement } from '@openelement/element';
83

94
@element('index-page', { root: 'shadow-open' })
105
export default class HomePage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-login.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,7 @@
66
* placeholder keeps "no provider configured" an explicit page state that
77
* Tier-2 evidence can assert on.
88
*/
9-
import { OpenElement } from '@openelement/element';
10-
11-
declare function element(
12-
tag: string,
13-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
14-
): ClassDecorator;
15-
declare function property(
16-
options: { reflect: boolean; attribute?: false },
17-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
9+
import { element, OpenElement, property } from '@openelement/element';
1810

1911
@element('login-page', { root: 'shadow-open' })
2012
export default class LoginPage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-magic-link.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@
22
* /magic-link page element (v0.44 compiled). Request-time rendered; the props
33
* projector lives in app/route-logic/magic-link.ts.
44
*/
5-
import { OpenElement } from '@openelement/element';
6-
7-
declare function element(
8-
tag: string,
9-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
10-
): ClassDecorator;
11-
declare function property(
12-
options: { reflect: boolean; attribute?: false },
13-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
5+
import { element, OpenElement, property } from '@openelement/element';
146

157
@element('magic-link-page', { root: 'shadow-open' })
168
export default class MagicLinkPage extends OpenElement {

‎examples/supabase-cloudflare-starter/app/components/page-notes.tsx‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,7 @@
1616
* dashed dynamic host attributes); the island's attribute-backed @property
1717
* fields receive them through the SSR expansion and the client claim.
1818
*/
19-
import { OpenElement } from '@openelement/element';
20-
21-
declare function element(
22-
tag: string,
23-
options?: { root: 'light' | 'shadow-open' | 'shadow-closed' },
24-
): ClassDecorator;
25-
declare function property(
26-
options: { reflect: boolean; attribute?: false },
27-
): (target: undefined, context: ClassFieldDecoratorContext) => void;
19+
import { element, OpenElement, property } from '@openelement/element';
2820

2921
@element('notes-page', { root: 'shadow-open' })
3022
export default class NotesPage extends OpenElement {

0 commit comments

Comments
 (0)