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.
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.
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
x64sc and autostarts Vim.
- 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
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.
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?