type: product-backlog
source-path: language specification and compiler architecture
ingested-at: 2026-11-07
version: 0.1-draft
Nova128 Epics and Stories
All stories are planned until the user approves implementation. Story IDs are
stable. Splitting a story creates child IDs such as E02-S03a; do not renumber
existing work.
Status and Priority
- P0: required to prove feasibility or unblock most other work
- P1: required for version 1
- P2: valuable release hardening
A dependency is complete only when its claim is done with acceptance evidence.
Epic Summary
| Epic |
Outcome |
Exit gate |
| E00 |
Product contracts are frozen enough to implement |
User approves plan and provisional defaults |
| E01 |
C128 platform mechanisms are proven |
Stable compiler memory-map inputs and test mailbox |
| E02 |
Source can be read, tokenized, diagnosed, and represented |
Vim-created token fixture passes on x128 |
| E03 |
Programs parse and type-check |
Procedural semantic fixtures pass |
| E04 |
Procedural programs compile and run |
Control-flow and call examples pass end to end |
| E05 |
Classes and deterministic objects work |
Two independent objects construct, mutate, and delete |
| E06 |
Interfaces and dynamic dispatch work |
Multiple interface implementations dispatch correctly |
| E07 |
Editor-to-compiler workflow is safe and repeatable |
Vim-created source builds from a copied D81 |
| E08 |
Version 1 is hardened and packaged |
Regression, stress, docs, and release gates pass |
E00 — Product and Contract Freeze
Purpose: turn provisional assumptions into explicit user-approved contracts.
Primary files: docs/, README.md, AGENTS.md.
E00-S01 — Approve product defaults (P0)
Depends on: none
Story: As the product owner, I want the working name, source suffix, target,
editor strategy, interface scope, and ownership model confirmed so agents do
not implement mutually incompatible products.
Acceptance criteria:
- User approval or requested changes are recorded in
docs/decisions.md.
- The language name and source suffix have an explicit status.
- C128 native mode, on-machine compilation, and C64-mode Vim integration have
explicit status.
- Version 1 interface and memory-management scope is explicit.
E00-S02 — Freeze source grammar fixtures (P1)
Depends on: E00-S01
Story: As a parser implementer, I want accepted and rejected source fixtures
for every grammar production so parser behavior is testable without guessing.
Acceptance criteria:
- At least one accepted fixture covers every declaration and statement form.
- Rejected fixtures cover missing terminators, invalid line continuation,
duplicate declarations, and malformed interface/class headers.
- Fixtures remain within the editor source profile.
- Expected diagnostic IDs are named even if numeric assignments come later.
E00-S03 — Resolve specification open questions (P1)
Depends on: E00-S01
Story: As a language implementer, I want cast, char-literal, overflow, and
runtime-fault decisions resolved before their code paths are written.
Acceptance criteria:
- Each open language-spec question is accepted, deferred, or rejected.
- No version 1 grammar production references undefined behavior.
- Changes are reflected in fixtures and decisions.
E01 — C128 Platform Foundation
Purpose: prove the hardware/emulator facts on which every assembly module
depends. Primary files: src/common/, src/compiler/mmu.s, cfg/, tests/platform/,
monitor/, and story-specific probe targets.
E01-S01 — Minimal native C128 PRG (P0)
Depends on: E00-S01
Story: As a compiler developer, I want a minimal ca65/ld65 C128-native PRG
that starts, writes a deterministic signature, and exits predictably.
Acceptance criteria:
ca65/ld65 builds from a clean workspace.
x128 autostarts the PRG in C128 native mode.
- The PRG writes an expected screen/message and machine-readable result.
- A monitor script reaches the documented entry point.
E01-S02 — MMU and common-RAM probe (P0)
Depends on: E01-S01
Story: As a memory architect, I want verified bank configurations and a
common-memory trampoline so bank switching cannot be based on C64 assumptions.
Acceptance criteria:
- Both 64K banks are written/read with distinct patterns.
- The chosen common region remains visible across configurations.
- Code safely switches banks and returns with interrupts handled explicitly.
- Page-zero/page-one behavior is recorded.
- VICE watchpoints show only the intended MMU writes.
E01-S03 — KERNAL mapping wrapper probe (P0)
Depends on: E01-S02
Story: As an I/O implementer, I want a wrapper that enters KERNAL routines
from compiler mappings and restores state afterward.
Acceptance criteria:
- Character output and a disk-status call work from both compiler bank states.
- MMU state before and after each wrapper is identical.
- Carry/status and error values survive the wrapper contract.
- Open channels are closed on success and failure.
E01-S04 — Clock and display-mode probe (P1)
Depends on: E01-S01
Story: As a user, I want compiler output to work on either C128 display
without unsafe 2 MHz assumptions.
Acceptance criteria:
- Text is legible in tested 40- and 80-column modes.
- Safe clock switching conditions are documented from observed behavior.
- No semantic compiler data is placed in VDC RAM.
- The fallback clock/display behavior is deterministic.
E01-S05 — Freeze memory-map inputs and test mailbox (P0)
Depends on: E01-S02, E01-S03, E01-S04
Story: As downstream agents, we need agreed linker regions, reserved zero
page, and a test mailbox so independent modules share one platform contract.
Acceptance criteria:
docs/architecture.md lists verified regions and reservations.
cfg/compiler.cfg can link a capacity-checking skeleton.
src/common/c128.inc defines observed hardware/KERNAL constants.
- The test mailbox address and protocol are documented and exercised.
E02 — Source, Lexing, Names, and Diagnostics
Purpose: consume the exact files produced by Vim and establish bounded compiler
tables. Primary files: src/compiler/source.s, lexer.s, names.s,
diagnostics.s, src/common/tokens.inc, errors.inc, tests/lexer/.
E02-S01 — Buffered PETSCII source reader (P0)
Depends on: E01-S03, E01-S05
Story: As the compiler, I want a rewindable SEQ source stream with exact
line/column tracking.
Acceptance criteria:
- Reads Vim-created SEQ source without host conversion.
- Accepts
$0D lines and a missing final $0D.
- Enforces line/file limits with stable errors.
- Rewinds identically for all compiler passes.
- Disk failure closes channels and leaves no partial output.
E02-S02 — PETSCII lexer (P0)
Depends on: E02-S01, E00-S02
Story: As a parser, I want normalized, positioned tokens for the complete
version 1 lexical grammar.
Acceptance criteria:
- Both supported PETSCII letter ranges compare case-insensitively.
- Keywords, identifiers, numbers, strings, operators, comments, EOL, and EOF
match the specification.
- Invalid bytes and overlong identifiers report exact positions.
- Token dump of a Vim-created fixture matches a golden expected file.
E02-S03 — Name interning and bounded tables (P1)
Depends on: E01-S05, E02-S02
Story: As semantic passes, I want compact interned names with deterministic
capacity errors.
Acceptance criteria:
- Equal normalized identifiers share an ID.
- First-declaration spelling is preserved for diagnostics/MAP output.
- Hash collisions are tested.
- Full tables report a resource error without memory corruption.
E02-S04 — Stable diagnostic catalog and ERR writer (P1)
Depends on: E01-S03, E00-S02
Story: As a user and test author, I want stable diagnostic IDs, compact
screen messages, and complete ERR output.
Acceptance criteria:
- Lexical, syntax, type, access, interface, disk, and resource categories have
stable IDs.
- Screen form fits 40 columns for representative diagnostics.
- ERR output contains source, line, column, code, and message.
- Error limiting defaults to 20 and terminates cleanly.
E03 — Parser and Semantic Model
Purpose: recognize complete version 1 source and reject invalid programs before
code emission. Primary files: parser.s, expr.s, symbols.s, types.s,
classes.s, interfaces.s, tests/parser/, tests/semantic/.
E03-S01 — Top-level declaration parser (P0)
Depends on: E02-S02, E02-S03, E02-S04
Acceptance criteria:
- Parses interfaces, classes, implements lists, and exactly one program.
- Supports forward top-level type references.
- Rejects duplicate names and invalid ordering with recovery to later lines.
- Accepted/rejected fixtures from E00-S02 pass.
E03-S02 — Method, field, and local parser (P1)
Depends on: E03-S01
Acceptance criteria:
- Parses access, signatures, parameters, fields, and leading local declarations.
- Enforces unique method names and valid
init/destroy shapes.
- Assigns lexical scopes without leaking names across methods/classes.
- Reports private-member violations with source positions.
E03-S03 — Expression and statement parser (P1)
Depends on: E03-S02
Acceptance criteria:
- Implements documented precedence and left/right associativity.
- Parses every version 1 statement form.
- Rejects multiple statements per line and cross-line expressions.
- Recovers sufficiently to report a later independent error.
E03-S04 — Type representation and checking (P1)
Depends on: E03-S03
Acceptance criteria:
- Represents primitives, arrays, class references, interface references, and
null.
- Implements exactly the specified implicit conversions.
- Checks calls, assignments, returns, conditions, indexing, and operators.
- Reports incompatible interface assignments and missing returns.
E03-S05 — Class layout and access model (P1)
Depends on: E03-S02, E03-S04
Acceptance criteria:
- Field offsets begin after the class-descriptor pointer and are deterministic.
- Instance size overflow/capacity is diagnosed.
- Field default privacy and method default publicity match the specification.
- MAP fixture lists sizes and offsets in declaration order.
E03-S06 — Interface conformance model (P1)
Depends on: E03-S02, E03-S04
Acceptance criteria:
- Interface method slots follow interface source order.
- A public exact-signature method satisfies a requirement.
- One method may satisfy identical requirements from multiple interfaces.
- Same-name incompatible requirements are rejected.
- Missing, private, parameter-mismatched, and return-mismatched methods each
have fixture coverage.
E04 — Procedural Code Generation
Purpose: produce runnable native code before adding heap/object complexity.
Primary files: sizing.s, codegen.s, output.s, src/runtime/startup.s,
frames.s, arithmetic.s, print.s, faults.s, tests/codegen/.
E04-S01 — PRG and MAP writer (P0)
Depends on: E01-S05, E02-S04
Acceptance criteria:
- Writes a valid load-address header and deterministic sections.
- Emits a runnable startup path and clean termination.
- Refuses/handles output-name collision according to the approved policy.
- Removes or marks partial output after any failure.
- MAP records section start, size, and entry point.
E04-S02 — Software frames and calling convention (P0)
Depends on: E01-S05, E03-S04
Acceptance criteria:
- Arguments and locals use the documented software frame.
- Nested calls preserve required registers and frame state.
- One- and two-byte returns follow the ABI.
- Stack overflow follows a stable runtime-fault path.
- ABI tests include recursion to a bounded successful depth and overflow.
E04-S03 — Scalar expressions and assignments (P1)
Depends on: E04-S02
Acceptance criteria:
- Emits correct byte, word, integer, boolean, comparison, and assignment code.
- Short-circuit
and/or avoids evaluating the unused operand.
- Division by zero faults predictably.
- Golden disassembly covers representative expression shapes.
E04-S04 — Control flow and functions (P1)
Depends on: E04-S03, E03-S03
Acceptance criteria:
- Emits
if, else, while, for, calls, and returns.
- Pass 2 sizes/addresses exactly match Pass 3 output.
- Relative branches that cannot reach use a correct long-branch expansion.
- Nested-control fixtures execute expected mailbox signatures.
E04-S05 — Print and runtime faults (P1)
Depends on: E04-S03, E01-S04
Acceptance criteria:
- Prints literals and every supported scalar on tested displays.
- Null, bounds, divide, stack, and heap faults have stable codes.
- Runtime messages do not corrupt the program's memory mapping.
hello.n8 compiles and runs end to end in x128.
E04-S06 — Parser-to-codegen integration (P1)
Depends on: E04-S04, E04-S05, E05-S04, E03-S04
Acceptance criteria:
- Statements and expressions emit code through
codegen.s/flow.s instead of
being type-checked only: assignment, calls, if/else, while, for,
return, and print.
- Evaluation order and temporaries follow the D129 frame ABI; results arrive in
A (byte) or A/X (word), and arguments are pushed right-to-left and discarded
by the caller.
self.field and concrete method calls emit through members.s (D136), and a
method body stores its incoming self before any other statement.
- Emitter failures (buffer full, label or fixup exhaustion) become diagnostics;
a failed emit leaves no partial output.
- A source program using statements, expressions, and one concrete call
generates a routine that runs in x128 and produces the expected mailbox
signature.
E04-S07 — Sizing pass and pass-3 address assignment (P1)
Depends on: E04-S06
Acceptance criteria:
sizing.s measures each routine in count mode so pass 2 and pass 3 produce
identical lengths and identical label offsets, with a mismatch counter of 0.
- Pass 3 patches every label, branch,
JSR, and section address; the MAP
ENTRY and SECTION records carry the final addresses, including class
descriptors and method entries.
- Forward references to methods and classes declared later resolve; an
unresolved reference is a single diagnostic rather than a bad operand.
- Recompiling the same source produces a byte-identical PRG, and the existing
overwrite refusal (E202) still holds.
counter.n8 compiles from source and runs in x128 with the expected result,
closing the end-to-end criteria deferred by E05-S04 and E04-S05.
E04-S08 — Calling-convention emission (P0)
Depends on: E04-S07
Acceptance criteria:
- A call's byte and word arguments are staged while the argument list is
parsed and pushed in reverse, so arg0 lands at
FP+2 in the callee and the
declared parameter slots read the passed values.
- Every body gets a frame prologue whose local byte count is patched after the
body is parsed; a refused frame returns without running
frame_leave, and
the sizing pass measures the same prologue bytes.
return leaves the frame and preserves a 0-, 1- or 2-byte result; the caller
keeps that result across the argument discard.
- Frames are opt-in, so a fixture that does not request them emits no prologue
and keeps its previous code shape.
- A test drives source with a parameter and a result in
x128 and checks the
returned value.
E05 — Classes, Heap, and Concrete Methods
Purpose: implement object identity, encapsulated state, construction, and
deterministic lifetime before interface dispatch. Primary files:
src/runtime/heap.s, objects.s, compiler class/codegen modules, object tests.
E05-S01 — Free-list heap (P0)
Depends on: E01-S05, E04-S05
Acceptance criteria:
- Allocates, zeroes, frees, splits, and coalesces blocks deterministically.
- Heap exhaustion faults without corrupting allocated blocks.
- Debug mode detects representative double-free/corrupt-header cases.
- Stress test returns the heap to its initial free capacity.
E05-S02 — Class descriptor format (P1)
Depends on: E03-S05, E05-S01
Acceptance criteria:
- Descriptor identifies instance size and optional destructor.
- Every object begins with a valid descriptor pointer.
- Descriptor/MAP output is deterministic.
- Format reserves a documented path to interface-directory data without
introducing class inheritance.
E05-S03 — Construction and deletion (P1)
Depends on: E05-S02, E04-S02
Acceptance criteria:
new allocates, initializes the header, then calls init once.
- Failed allocation does not call
init.
delete null is a no-op.
delete calls destroy once and frees the complete object.
- Constructor arguments and destructor side effects have end-to-end tests.
E05-S04 — Fields, self, and concrete calls (P1)
Depends on: E05-S03, E03-S05
Acceptance criteria:
self.field loads/stores correct offsets.
- Concrete calls use direct
JSR and preserve the caller ABI.
- Private access is rejected at compile time.
- Two objects of one class retain independent state.
counter.n8 compiles and runs with the expected result.
E05-S05 — Fixed arrays and debug bounds (P2)
Depends on: E04-S03, E05-S04
Acceptance criteria:
- Local and field arrays use specified element sizes.
- Constant and computed indices address correct elements.
- Debug bounds checks fault on low/high invalid indices.
- Release behavior matches the approved bounds-check policy.
E06 — Interfaces and Dynamic Dispatch
Purpose: deliver the user-requested interface polymorphism. Primary files:
compiler/runtime interfaces.s, class descriptors, code generation, ABI tests.
E06-S01 — Freeze interface ABI (P0)
Depends on: E01-S05, E03-S06, E05-S02
Acceptance criteria:
- Four-byte interface value layout is documented and tested little-endian.
- Interface slot and per-class table layouts are frozen.
- Conversion, parameter, return, local, field, and array storage rules are
specified.
- Register clobbers and the four-byte return convention are finalized.
E06-S02 — Indirect-call trampoline (P0)
Depends on: E06-S01, E04-S02
Acceptance criteria:
- Calls at least three target methods selected at runtime.
- Returns correctly through nested and recursive calls.
- Preserves documented registers, software frame, and interrupt state.
- Null/invalid targets use a fault path rather than executing address zero.
- Hardware-stack boundary tests pass.
E06-S03 — Emit interface implementation tables (P1)
Depends on: E06-S01, E05-S04
Acceptance criteria:
- Each class emits one method table per implemented interface.
- Table addresses and slots appear in MAP output.
- One method can populate slots for multiple compatible interfaces.
- Different classes implementing one interface emit distinct correct tables.
E06-S04 — Concrete-to-interface conversion (P1)
Depends on: E06-S03
Acceptance criteria:
- Assignment creates the correct object/table pair.
null conversion produces a canonical null interface value.
- Passing, returning, storing, and array-copying interface values preserve all
four bytes.
- Invalid class-to-interface conversion is a compile-time error.
E06-S05 — Interface method calls (P1)
Depends on: E06-S02, E06-S04
Acceptance criteria:
- Call uses the compile-time interface slot and runtime table pointer.
self is the underlying object, not the fat-reference address.
- Two classes dispatch the same interface call to different methods.
- One class implements and dispatches at least two interfaces.
- Arguments and one-/two-byte returns work through interface calls.
E06-S06 — Interface lifetime and failure paths (P1)
Depends on: E06-S05, E05-S03
Acceptance criteria:
delete through an interface invokes the class destructor and frees once.
delete null-interface is a no-op.
- Null calls fault predictably.
- A debug use-after-free scenario produces a detectable failure where the
approved debug policy promises detection.
objects.n8 covers multiple interfaces end to end.
E06-S07 — Interface expressions in code generation (P0)
Depends on: E06-S05, E05-S04, E04-S06, E04-S07
Acceptance criteria:
- A concrete-to-interface assignment in a statement, argument, return or
initializer emits the E06-S04 conversion path and stores all four bytes of
the object/table pair; a plain pointer copy is never emitted in its place.
null in an interface context produces the canonical null interface value,
and a call through it takes the documented fault path rather than dispatch.
- Interface-typed locals, parameters, returns and fields hold and copy the full
four bytes, including through array element assignment and struct-style
copies.
- A source-level interface call emits the
if_call trampoline with the
interface value pointer in A/X and the compile-time slot in Y, and passes
arguments and receives one- and two-byte returns correctly.
- A new on-machine fixture with two classes implementing one interface
dispatches the same call to different methods, and one class implementing two
interfaces dispatches through both, all compiled from source rather than
assembled by hand.
- Misuse stays a stable compile-time diagnostic: assigning an unrelated class
to an interface, calling an interface member the interface does not declare,
and reaching a private member through an interface each report their
catalogued code with no PRG emitted.
- MAP output names the interface tables and slots the emitted code references.
E07 — Vim and Disk Workflow
Purpose: make source creation and compilation repeatable without modifying the
original editor. Primary files: scripts/, docs/editor-workflow.md,
integration fixtures, generated build/ artifacts.
E07-S01 — Disposable development image builder (P0)
Depends on: E01-S01
Acceptance criteria:
- Copies
../vim/work.d81; never writes the original.
- Injects compiler/examples deterministically with
c1541.
- Rebuilding starts from a known clean image.
- Script clearly reports missing tools and source images.
E07-S02 — Sequential editor/compiler launchers (P1)
Depends on: E07-S01, E04-S01
Acceptance criteria:
- Editor launcher uses
x128 in 80-column mode and autostarts the C128 Vim
(../vim/vim128.prg; D151 makes this the default instead of x64sc).
- Compiler launcher uses
x128 and autostarts the compiler.
- Launchers wait for process/image flush before returning.
- Documentation and warnings prohibit simultaneous writable attachment.
E07-S03 — Vim source round-trip (P0)
Depends on: E07-S02, E02-S02
Acceptance criteria:
- A source file created entirely in Vim tokenizes on C128 without host
conversion.
- Reopening it in Vim preserves content.
- Extracted bytes match the expected PETSCII/CR fixture.
- Both supported PETSCII letter ranges are exercised.
E07-S04 — Edit/compile/run walkthrough (P1)
Depends on: E07-S03, E06-S06, E06-S07, E07-S05
Acceptance criteria:
- A new user can edit, compile, inspect diagnostics, and run an interface-based
sample from documented commands.
- Failure recovery for syntax errors and output collisions is documented.
- No step requires modifying
vim/ or a reference disk.
E07-S05 — On-machine compiler driver PRG (P0)
Depends on: E07-S01, E04-S01, E04-S06, E02-S04
Acceptance criteria:
build/n128c.prg is produced by a documented build script and is the exact
file scripts/prepare-disk.ps1 injects as n128c and
scripts/launch-compiler.ps1 autostarts, so the shipped disk and the
launcher cannot drift from the driver.
- Started on
x128 (by hand or through the compiler launcher) the driver takes
one source file name, loads it from the session disk through the buffered
PETSCII reader with no host-side conversion, runs lexer, parser and code
generation, and writes the output PRG named after the source.
- The driver writes the ERR and MAP outputs for the same run where the
corresponding stories produce them, and prints a one-screen summary naming
the source, the output, and the diagnostic count.
- A clean source produces a PRG that runs on
x128; a source with syntax or
semantic errors produces the catalogued diagnostics in the ERR file, a
non-zero diagnostic count, and no output PRG.
- Missing source, unreadable source and an existing output file each end with
the documented message and leave the previous output intact rather than a
partial file.
- A test drives the driver through
scripts/launch-compiler.ps1 on a copied
development image and checks the PRG, ERR and MAP artifacts and the summary.
docs/editor-workflow.md documents the command syntax and the recovery steps
for a failed compile, and E07-S04's walkthrough can be completed with no
undocumented command.
E08 — Hardening and Release
Purpose: prove version 1 against limits and package a reproducible release.
Primary files: tests/, monitor/, release/, and final documentation.
E08-S01 — Automated x128 regression harness (P0)
Depends on: E01-S05, E02-S04
Acceptance criteria:
- Creates a fresh D81 per test run.
- Enforces time/cycle limits and captures machine-readable results.
- Extracts PRG/ERR/MAP outputs and compares expected artifacts.
- A failed test identifies the fixture and observed signature.
E08-S02 — Golden code and disassembly suite (P1)
Depends on: E04-S04, E05-S04, E06-S05
Acceptance criteria:
- Covers scalar operations, branches, frames, object fields, construction,
deletion, conversions, and interface dispatch.
- Expected bytes/disassembly are reviewed rather than blindly regenerated.
- All emitted opcodes are documented 8502/6502 instructions.
E08-S03 — Capacity and failure stress suite (P1)
Depends on: E05-S05, E06-S06, E08-S01
Acceptance criteria:
- Exercises maximum line/file/identifier limits and every compiler table.
- Exercises disk errors, heap exhaustion, stack exhaustion, and error limit.
- Exercises many classes, interfaces, slots, fields, locals, and nested calls.
- Every limit fails cleanly with its stable code.
E08-S04 — Example and conformance suite (P1)
Depends on: E06-S06, E08-S01
Acceptance criteria:
- Includes Hello World, Counter, two class instances, two implementations of
one interface, one class with two interfaces, constructor/destructor, arrays,
and deliberate compile/runtime failures.
- Each example states expected output.
- Every normative language-spec section maps to at least one test or an
explicit non-executable review check.
E08-S05 — Release image and documentation (P1)
Depends on: E07-S04, E08-S02, E08-S03, E08-S04
Acceptance criteria:
- Clean build produces compiler PRG, copied development D81, checksums, and
release notes.
- User guide covers editor workflow, language basics, interfaces, diagnostics,
limits, and recovery.
- Developer guide covers build, memory map, ABI, tests, and adding diagnostics.
- Release artifacts are regenerated from source without manual image edits.
E08-S06 — Physical C128 smoke test (P2)
Depends on: E08-S05; physical hardware availability
Acceptance criteria:
- Compiler starts in native mode from the release media.
- Vim-created source compiles and the generated interface example runs.
- 40/80-column and disk behavior are recorded.
- Any emulator/hardware difference becomes a tracked story, not an undocumented
workaround.
Suggested First Parallel Wave After Approval
- Agent A: E01-S01 minimal native PRG
- Agent B: E00-S02 grammar fixtures
- Agent C: E02-S04 diagnostic catalog design (documentation/fixtures only until
E01 wrappers exist)
- Agent D: E07-S01 disposable image builder
The MMU probe, ABI modules, and linker configurations require deliberate
coordination; they should not be edited concurrently by unrelated stories.
Open Questions
- Which provisional decisions does the user want changed before E00-S01 closes?
- Is physical-hardware testing a release gate or a post-release validation?
- How many compiler-table records fit after E01 freezes the real memory map?
- Should separate compilation become the first post-version-1 epic?