--- model: accounts/fireworks/routers/kimi-k2p5-turbo --- # Plan: `ask262Debug` Module for engine262 ## Overview Runtime execution tracker that records which ECMAScript spec sections are entered during execution. The Babel transform auto-injects `ask262Debug.mark()` at the start of every function body with URL comments — developer writes nothing. All metadata (sectionId, file, line) resolved at build time. **Primary Use Case:** AI analysis of execution flow mapped to ECMAScript spec sections for understanding JavaScript engine behavior. ## Files to Change | File | Action | |------|--------| | `engine262/src/ask262-debug.mts` | **CREATE** — the module with deduplication logic | | `engine262/src/index.mts` | **MODIFY** — add named re-export | | `engine262/tsconfig.base.json` | **MODIFY** — add `#self/ask262Debug` path mapping | | `engine262/package.json` | **MODIFY** — add `#self/ask262Debug` import | | `engine262/scripts/rollup.config.mts` | **MODIFY** — add resolve-self plugin to main build, extend for subpaths | | `engine262/scripts/transform.mts` | **MODIFY** — auto-inject `mark()` and import | | `engine262/scripts/verify-ask262-debug.mts` | **CREATE** — post-build verification script | ## 1. `scripts/transform.mts` — Enhance the Babel Plugin ### 1a. Extend State Interface ```typescript type NeededNames = 'Completion' | 'AbruptCompletion' | 'Assert' | 'Call' | 'IteratorClose' | 'AsyncIteratorClose' | 'Value' | 'skipDebugger' | 'ask262Debug'; // NEW interface State extends PluginPass { needed: Partial>; fileRelativePath?: string; // NEW: captured at Program enter } ``` ### 1b. Refactor `addSectionFromComments` ```typescript function addSectionFromComments( path: NodePath | NodePath | NodePath | NodePath | NodePath, state: State, getName: () => string ) { if (!path.node.leadingComments) return; const sectionIds: string[] = []; let url = ''; for (const c of path.node.leadingComments) { for (const line of c.value.split('\n')) { const matches = line.match(/#(sec-[a-zA-Z0-9._%-]+)/g); if (matches) { sectionIds.push(...matches.map(m => m.substring(1))); if (!url) { const section = line.split(' ').find(l => l.includes('#sec')); if (section) { url = section.includes('https') ? section : `https://tc39.es/ecma262/${section}`; } } } } } if (sectionIds.length === 0) return; const name = getName(); // 1. Keep existing .section (backward compat) - uses first URL if (url) { path.insertAfter(template.ast(`${name}.section = '${url}';`)); } // 2. Determine if we can inject mark() let body: t.BlockStatement | null = null; if (path.isFunctionDeclaration()) { body = path.node.body; } else if (path.isClassMethod() || path.isObjectMethod()) { body = path.node.body; } else if (path.isVariableDeclaration()) { const init = (path.get('declarations.0') as NodePath).get('init'); if (init.isFunctionExpression()) { body = init.node.body; } else if (init.isArrowFunctionExpression()) { body = init.node.body.type === 'BlockStatement' ? init.node.body : null; } } else if (path.isExportNamedDeclaration()) { const declaration = path.node.declaration; if (declaration?.type === 'FunctionDeclaration') { body = declaration.body; } } // 3. Inject mark() at start of function body (only for block bodies) if (body?.type === 'BlockStatement') { const line = path.node.loc?.start.line ?? 0; const markCall = template.statement( `ask262Debug.mark(${JSON.stringify(sectionIds)}, ${JSON.stringify(state.fileRelativePath)}, ${line});` )(); body.body.unshift(markCall); state.needed.ask262Debug = true; } } ``` ### 1c. Add Visitors for All Function-like Nodes ```typescript return { visitor: { Program: { enter(path, state) { state.needed = {}; // Capture relative file path from state.filename const absolutePath = state.filename || ''; state.fileRelativePath = absolutePath.replace(/.*\/(src\/)/, '$1').replace(/\.mts$/, '.mts') || 'unknown.mts'; }, exit(path, state) { // Existing imports... if (state.needed.ask262Debug) { path.unshiftContainer('body', template.ast(`import ask262Debug from '#self/ask262Debug';`)); } }, }, FunctionDeclaration(path, state) { addSectionFromComments(path, state, () => path.node.id!.name); }, VariableDeclaration(path, state) { const init = path.get('declarations.0.init'); if (init.isFunctionExpression() || init.isArrowFunctionExpression()) { const id = path.node.declarations[0].id as t.Identifier; addSectionFromComments(path, state, () => id.name); } }, ExportNamedDeclaration(path, state) { const declaration = path.node.declaration; if (declaration?.type === 'FunctionDeclaration') { addSectionFromComments(path, state, () => declaration.id!.name); } }, ClassMethod(path, state) { const key = path.node.key; if (key.type === 'Identifier') { addSectionFromComments(path, state, () => key.name); } }, ObjectMethod(path, state) { const key = path.node.key; if (key.type === 'Identifier') { addSectionFromComments(path, state, () => key.name); } }, // ... rest of existing visitors (CallExpression, ThrowStatement, etc.) unchanged }, }; ``` ### 1d. Arrow Function Special Handling The updated `addSectionFromComments` handles this automatically: - Arrow with block body `() => { ... }`: `.section` + `mark()` injected - Arrow with expression body `() => expr`: `.section` only, no `mark()` ## 2. `engine262/package.json` — Add Subpath Import ```json { "imports": { "#self": "./lib/engine262.mjs", "#self/ask262Debug": "./src/ask262-debug.mts" } } ``` ## 3. `engine262/tsconfig.base.json` — Add Path Mapping ```json { "compilerOptions": { "paths": { "#self": ["./lib/engine262.mjs"], "#self/ask262Debug": ["./src/ask262-debug.mts"] } } } ``` ## 4. `engine262/scripts/rollup.config.mts` — Add resolve-self to Main Build ### 4a. Extend Existing resolve-self Plugin ```typescript // Inspector build (existing plugin, modified) { name: 'resolve-self', resolveId(source, _importer, _options) { if (source === '#self') { return { id: './engine262.mjs' }; } if (source.startsWith('#self/')) { // For inspector build, resolve subpaths to bundled engine262 return { id: './engine262.mjs' }; // All #self/* resolve to main bundle } return undefined; }, } ``` ### 4b. Add to Main Engine262 Build ```typescript { input: './src/index.mts', plugins: [ importUnicodeLib(), (json.default || json)({ compact: true }), (commonjs.default || commonjs)(), nodeResolve({ exportConditions: ['rollup'], extensions: ['.mts'] }), { name: 'resolve-self', resolveId(source) { if (source === '#self') { return { id: '#self' }; // Mark as internal, bundled } if (source === '#self/ask262Debug') { return { id: './src/ask262-debug.mts' }; // Will be bundled } return undefined; }, }, babel({ ...babelOptions, plugins: [ './scripts/transform.mts', ['@babel/plugin-proposal-decorators', { 'version': '2023-11' }], ], }), // ... dts plugin ], // ... output config } ``` ## 5. `engine262/src/index.mts` — Add Named Re-export ```typescript // Add to existing exports export { default as ask262Debug, type MarkData } from './ask262-debug.mts'; ``` ## 6. `engine262/src/ask262-debug.mts` — The Module Deduplicated data collection. No stack parsing, no `node:` imports, no decorators. ```typescript export interface MarkData { readonly sectionIds: string[]; readonly fileRelativePath: string; readonly lineNumber: number; readonly important: boolean; } interface MarkKey { readonly sectionIds: string; readonly file: string; readonly line: number; } class Ask262Debug { marks: MarkData[] = []; private _importantStack = false; private _markIndex = new Map(); // key -> index in marks private _makeKey(sectionIds: string[], file: string, line: number): string { return `${sectionIds.join(',')}|${file}|${line}`; } mark(sectionIds: string[], file: string, line: number) { const key = this._makeKey(sectionIds, file, line); const existingIndex = this._markIndex.get(key); if (existingIndex !== undefined) { // Merge important flag const existing = this.marks[existingIndex]; if (this._importantStack && !existing.important) { (this.marks[existingIndex] as any).important = true; } return; } const newMark: MarkData = { sectionIds: [...sectionIds], // defensive copy fileRelativePath: file, lineNumber: line, important: this._importantStack, }; this._markIndex.set(key, this.marks.length); this.marks.push(newMark); } startImportant() { this._importantStack = true; } stopImportant() { this._importantStack = false; } } const ask262Debug = new Ask262Debug(); export default ask262Debug; ``` ### Key Behaviors | Scenario | Behavior | |----------|----------| | Duplicate `(sectionIds, file, line)` | Keep one entry, merge `important` flags (OR logic) | | Generator resumption | Mark on every `.next()` call (may create duplicates if same location) | | Nested functions | Each entry adds its mark (chronological trace) | ## 7. `engine262/scripts/verify-ask262-debug.mts` — Verification Script ```typescript #!/usr/bin/env node import engine262 from '../lib/engine262.mjs'; console.log('=== ask262Debug Verification ===\n'); // 1. Check export exists console.log('1. Checking export...'); if (!engine262.ask262Debug) { console.error('FAIL: ask262Debug not exported'); process.exit(1); } console.log(' ✓ ask262Debug exported\n'); // 2. Run code that hits known spec sections console.log('2. Executing test code...'); const agent = new engine262.Agent(); const realm = new engine262.ManagedRealm({ agent }); realm.evaluateScript(` // Array.prototype.every - should hit sec-array.prototype.every [1, 2, 3].every(x => x > 0); // Proxy creation - should hit sec-proxycreate or similar new Proxy({}, {}); `); // 3. Verify marks were captured console.log('3. Checking marks...'); const marks = engine262.ask262Debug.marks; console.log(` Captured ${marks.length} unique marks\n`); if (marks.length === 0) { console.error('FAIL: No marks captured'); process.exit(1); } // 4. Show sample marks console.log('4. Sample marks:'); marks.slice(0, 5).forEach((m, i) => { console.log(` [${i}] ${m.sectionIds.join(', ')} @ ${m.fileRelativePath}:${m.lineNumber}${m.important ? ' [important]' : ''}`); }); console.log('\n=== All Checks Passed ==='); ``` ## Key Design Decisions Summary | Decision | Choice | Rationale | |----------|--------|-----------| | **Use case** | AI execution flow analysis | Map runtime to spec sections | | **Data structure** | Deduplicated array | Chronological trace with unique entries only | | **Deduplication key** | `(sectionIds, file, line)` | Same location = same semantic entry | | **Duplicate handling** | Merge `important` flags (OR) | If any call was important, mark it important | | **Module name** | `#self/ask262Debug` | Follows existing `#self` pattern | | **Export style** | Named export from engine262 | `import { ask262Debug } from '#self'` | | **Bundle strategy** | Included in engine262.mjs | Single artifact, no external dependency | | **All metadata** | From transform (build time) | No runtime stack parsing, no `node:` imports | | **`mark()` injection** | Auto-injected at start of block body | Developer writes nothing | | **Arrow functions** | Block body: `.section` + `mark()`, Expression: `.section` only | Can't inject statement in expression | | **Multi-section** | Array of section IDs per function | Functions can implement multiple spec sections | | **`.section`** | Kept (backward compat) | Used by test262-intrinsics | | **Generators** | Mark on every `.next()` | Simpler, deduplication handles repeats | | **Nested functions** | Mark all | Chronological trace for AI analysis | | **`important`** | User-driven `startImportant()`/`stopImportant()` | Manual annotation of interesting sections | | **Function types** | FunctionDeclaration + ClassMethod + ObjectMethod + VariableDeclaration | Covers all URL comment patterns | | **Class/Object method keys** | Identifier names only | Simple, covers 99% of cases | | **File paths** | Relative to `engine262/src/`, `.mts` extension | Maps to source, not compiled output | | **Line numbers** | 1-indexed from Babel AST | Matches source file line numbers | ## Verification Steps 1. **Type checking**: `cd engine262 && npx tsc -b .` 2. **Linting**: `cd engine262 && npm run lint` 3. **Build**: `cd engine262 && npm run build:engine` 4. **Verification**: `cd engine262 && node scripts/verify-ask262-debug.mts` 5. **Manual inspection**: Check that transformed files have `ask262Debug.mark()` at start of functions with URL comments 6. **Multi-section test**: Find a function with multiple URL comments (e.g., `ArrayProto_every`) and verify all section IDs are in the array ## Expected Output from Verification ``` === ask262Debug Verification === 1. Checking export... ✓ ask262Debug exported 2. Executing test code... 3. Checking marks... Captured 47 unique marks 4. Sample marks: [0] sec-array.prototype.every @ intrinsics/ArrayPrototypeShared.mts:173 [1] sec-proxycreate @ abstract-ops/proxy-objects.mts:540 ... === All Checks Passed === ```