S264 Aot Final Validation Handoff

Documentation for Sessions

S264: AOT Final Validation Handoff

For: Co-work agent (final validation + AOT switch) From: S264.1-264.5 (architecture, implementation, bug fixes) Supersedes: S264-aot-testing-handoff.md (original handoff — S267 completed Phases A-D from that doc) Branch: session-264-268 Date: 2026-03-24


Status: What's Already Done

Completed by S264.1-264.2

Completed by S267 (first test round)

Completed by S264.4-264.5 (this round — fixes the S267 blockers)


What You Need To Do

Task 1: Browser Integration Test (THE critical validation)

This is the test that S267 attempted but couldn't pass due to Bugs 5-7 (now fixed).

Step 1: Confirm JIT baseline works

# Make sure dev server is running
yarn serve:space
# Open browser: http://localhost:6200
# Navigate to any space → universe → Studio → Live Preview
# Verify: preview renders, data loads, no red errors
# Console should show: "Angular is running in development mode"
# Console should show: "[useCrudList] Loaded N items"

Step 2: Switch to AOT

File: libs/libs-structural/platform-preview/src/lib/services/bundler.service.ts
Line ~15: Change the factory:

FROM: { factory: () => new JitCompilationStrategy() }
  TO: { factory: () => new AotCompilationStrategy() }

Save the file. Wait for dev server to recompile (~3-5 seconds).

Step 3: Test AOT rendering

Reload the Live Preview tab (or navigate away and back).
Open browser DevTools → Console.

CHECK FOR:
  ✅ "[DecoratorTransformer] Transformed N component(s)" — AOT transform ran
  ✅ "Compiled (2 assets, Xms)" — rspack compilation succeeded
  ✅ "Angular is running in development mode" — Angular bootstrapped
  ✅ The preview renders UI (not blank)
  ✅ Data loads: "[useCrudList] Loaded N items"
  ✅ Click handlers work (click items in list, buttons)
  ✅ Navigation works (if multiple modules, click nav links)

CHECK AGAINST:
  ❌ "Preview Load Error" — AOT transform or rspack failed
  ❌ Blank white iframe with no errors — likely Bug 5 regression (missing dependencies)
  ❌ "ɵɵ... is not a function" — Ivy instruction mismatch
  ❌ "needs to be compiled using the JIT compiler" — decorator not transformed

Step 4: Compare JIT vs AOT

Step 5: Revert to JIT

Change bundler.service.ts back to JitCompilationStrategy.
Save. This is important — don't leave AOT as default until validated.

Task 2: Edge Case Testing (if Task 1 passes)

Test these specific template patterns in AOT mode. Create a test component or find generated code that uses each:

Pattern What to check Why it matters
@for (item of items(); track item.id) Loop renders, scoping correct Bug 6+7 fix validation
[routerLink]="['/some-path']" No ctx. on array literal Bug 3 fix validation
[(ngModel)]="value" Two-way binding works Bug 2 fix validation
{{title()}} signal interpolation Renders signal value Core AOT functionality
[class.active]="item.id === selectedId()" Mixed local+component scoping Bug 7 fix validation
(click)="select(item.id)" inside @for Handler uses loop var correctly Scoping in handlers
Nested @if inside @for Both control flow blocks render Nested scope handling
@switch with multiple @case Correct case renders Switch codegen
Component with provideHttpClient() HTTP calls work Hybrid AOT+JIT for libraries

Task 3: Performance Comparison (if Tasks 1-2 pass)

Measure in browser DevTools → Performance tab:

Metric How to measure Target
Compilation time Console: "Compiled (2 assets, Xms)" AOT should be similar or faster
Bootstrap time Time from "Compiled" to "Angular is running" AOT should be faster (no template compilation)
Bundle size DevTools → Network → look at main.js size AOT should be smaller (no compiler import in main.js)

Task 4: Flip the Switch (if ALL above pass)

If Tasks 1-3 validate successfully:

  1. Change default strategy to AOT in bundler.service.ts:
    { factory: () => new AotCompilationStrategy() }
    
  2. Commit with message: [S264.X] feat: switch default compilation strategy to AOT
  3. Test one more time after commit to confirm

Architecture Reference (Quick)

Generated .ts files
  → BundlerFilesystemService.enrichForWorker() [enriches, injects schemas]
  → AotCompilationStrategy.transformSources() [decorator → Ivy instructions]
    → DecoratorTransformer.transformComponentFile()
      → TemplateParser.parse(template) → AST
      → IvyCodegen.generate(ast) → Ivy instructions
      → Replace @Component with static ɵcmp + ɵfac fields
      → Add dependencies, changeDetection, schemas
  → rspack Worker [bundles to main.js + styles.css]
  → PreviewServerService [wraps in HTML with prerequisites]
    → zone.js loaded first
    → @angular/compiler loaded (hybrid mode — library code needs JIT)
    → main.js parsed → Ivy instructions already present → bootstrap

Key files

File Role
bundler.service.ts:15 THE SWITCH — JitCompilationStrategy vs AotCompilationStrategy
decorator-transformer.ts @Component → Ivy static fields (dependencies, template fn, styles)
template-parser.ts Angular template HTML → AST nodes
ivy-codegen.ts AST → Ivy instruction code (CREATE + UPDATE blocks)
aot-compilation.strategy.ts AOT strategy: transforms sources, loads compiler for library code
jit-compilation.strategy.ts JIT strategy: no transforms, loads compiler for everything
compilation-strategy.ts Interface both strategies implement

All under: libs/libs-structural/platform-preview/src/lib/


Bug History (Complete)

# Bug Severity Found by Fixed by Status
1 }} infinite loop in parseText() CRITICAL S267 S267 Fixed (1f1c8e6f6)
2 [(ngModel)] parse order HIGH S267 S267 Fixed (1f1c8e6f6)
3 Array literal ['/route'] got ctx. prefix HIGH S267 S267 Fixed (1f1c8e6f6)
4 ɵɵdefineComponent was a comment, not a call HIGH S267 S267 Fixed (1f1c8e6f6)
5 Missing dependencies → blank render BLOCKING S267 S264.4 Fixed (d30bd8d33)
6 @for parser: items() broke on ) HIGH S264.4 S264.4 Fixed (d30bd8d33)
7 item.name → ctx.item.name in @for HIGH S264.4 S264.5 Fixed (005765588)

Known Limitations (Acceptable for Ship)

  1. Angular compiler still loaded in AOT mode — library packages (HttpClient, Router, Forms) ship as partially-compiled and need JIT. Our AOT only pre-compiles USER component templates. Benefit: faster bootstrap, not smaller bundle.

  2. Pipe codegen is simplified — uses ɵɵpipeBind(name, expr) pattern instead of proper slot-allocated ɵɵpipe() + ɵɵpipeBind1(). Low risk: generated code rarely uses pipes directly.

  3. Single @Component per file — transformer finds only the first @Component. Low risk: LLM generates one component per file.

  4. No @Directive/@Pipe transformation — these pass through to JIT. The hybrid strategy handles this correctly (compiler is loaded).

  5. String-based metadata extraction — works for predictable LLM output. Would break on creative formatting. Acceptable tradeoff vs. adding ts-morph dependency.


Success Criteria (Copy-Paste Checklist)

[ ] JIT baseline renders correctly (control)
[ ] AOT compilation succeeds (console: "Transformed N component(s)")
[ ] AOT preview renders (not blank, UI visible)
[ ] Data loads in AOT mode (console: "[useCrudList] Loaded N items")
[ ] Click handlers work in AOT mode
[ ] No new console errors vs JIT
[ ] @for loops render correctly with signal accessors
[ ] Mixed local/component expressions scope correctly
[ ] Performance: AOT bootstrap time ≤ JIT bootstrap time
[ ] Reverted to JIT works (no regression)

When ALL boxes are checked → flip the default to AOT and commit.