- Keep commits small and testable.
- Prefer correctness gates over feature breadth.
- Do not promote deferred sugar into core without spec updates.
- Fix semantic correctness bugs immediately; schedule DRY/YAGNI refactors separately.
- Before major feature expansion, stabilize touched types and remove dead code in the affected subsystem.
- 0.1 – 3: Prep and YAGNI cleanup
- 4 – 8: Core syntax and parser
- 9 – 10: Desugaring and contracts
- 11 – 12: Binding and symbols
- 13: Args parsing
- 14 – 15: Lua evaluator
- 16 – 18: DOCX emitter and lists/tables
- 19 – 21: CLI and LSP basics
- 22: Layout evaluation (columns, box, header/footer)
- 23: Include resolution + params validation
- 24: LSP directive autocompletion from contracts
- 25: DOCX section/column emission
- 26: OOXML assertion harness
- 27: Evaluator + include regression fixtures
- 28: LSP reference lookup for @def usages
- 29: Directive suggestions and fix-it diagnostics
- 30: Dead code removal
- 31: Type system migration
- 32: Spec correctness fixes
- 33: Architectural debt purge
Removed 390 lines across 5 dead files (recovery.ts, highlight.ts, style-names.ts, filters.ts, utils.ts). Zero consumers, zero imports.
Branch: refactor/remove-deprecated-cst-aliases
Migrated deprecated v2 CST aliases (CSTDocument, CSTNode, CSTDirective, CSTArgument) across 11 files in 3 commits by dependency boundary. Removed alias exports from src/types/cst.ts.
Branch: fix/spec-correctness + fix/oracle-review-bugs
Fixed all spec promises that failed silently — compiler accepted input, did nothing, emitted no warning. 8 items parser → evaluator → emitter:
- Escape sequences (§3.3),
@documentconfig wiring,@anchor/bookmark IR, cross-references (@ref),@style(ref:)resolution, list marker args (start/continue), legal numbering mode, Lua sandbox limits. - Oracle review follow-up: removed dead token types (
LUA_BLOCK_OPEN,LIST_CONTINUATION,NUMBER,LENGTH,BOOLEAN), preserved quote char in STRING tokens, removed comment.trim(), added EOF-close recovery for inline directives, whitespace tolerance between directive name/args/body (§5.1), diagnostic for structural-level text, inline whitespace preservation before non-delimiters.
107 tests, 0 type errors at merge.
Branch: refactor/architectural-debt — 20 commits, 6 review rounds (Codex + oracle)
Plan: PRESCRIPTION.md | Audit: REVIEW.md | Spec: LDOC-V3-SPEC.md §15.3, §18, §18.2
Full architectural audit covering every compiler phase. Evaluator split from 1,227-line monolith into per-directive handlers. 9 prescription steps + 6 review fix rounds.
Parse phase:
- Args parsed once into CST nodes; downstream re-parsing removed.
@lua{...}raw-body via balanced brace scanner;@lua[...]sugar rejected (P005).- SOL list marker gating; mid-line stacked
@@preserved as text. - Raw-body token sync uses precomputed line-start offsets (linear).
- Tagged union for
ParseArgsResult(fixes@foo(ok: false)false-positive). - Diagnostic locations rebased to source coordinates for args spans.
Bind phase:
@anchor/@refvalidation with cross-file resolution viaparsedDocuments.@paramsarity validation at bind time viaincludeEdges(§16).- Duplicate anchor detection per include site (not per unique file).
BinderOptionsflags for selective validation.- Symbol values deep-frozen at bind boundary; runtime defs cloned during evaluate execution (§18.1.1).
- Shared helpers in
src/shared/include-params.ts(DRY with evaluator).
Evaluate phase:
- Evaluator modularized into handler registry + per-directive files.
IR / Types:
- Anchors modeled as block
Anchornodes; inlineBookmarkremoved. - Dead CST surfaces removed (Table, TableRow, LayoutDirective, Include, IR Heading).
- Dead style-cycle branch and
STYLE_CYCLEdiagnostic removed. Object.create(null)in args parser (prototype safety).- All bare diagnostic code strings replaced with
DiagnosticCode.Xconstants.
Phase boundaries: Hardened parse → bind → evaluate contracts. Dead code across all phases purged.
Final stats: 162 tests, 374 expect() calls, 0 type errors.
Branch: feat/professional-output — 7 commits, 4 review rounds (Oracle + Codex)
Visual and formatting emission for real legal document output. Enabled by PR #4's anchor IR cleanup.
- Wired
@document(orientation: "landscape")to DOCX section properties with portrait-normalization. - Completed
toParagraphOptions()— indent, spacing, border, keep flags, shading, highlight. - Split Box from Blockquote IR;
@blockquotedirective with left-border indent;@boxas single-cell bordered table. - Table layout controls:
headerRows,cellPadding,cantSplit, horizontal/vertical merge markers (>,^). - Full diagnostic coverage: E010–E018 for table validation, type mismatches, invalid merge markers.
- Vertical merge chain propagation fix for 3+ row spans.
Final stats: 182 tests, 411 expect() calls, 0 type errors.
Branch: feat/footnotes-core — merged via PR #6
Closed §15.3 end-to-end:
- Added
@footnotedirective contract + LSP completion. - Implemented structural and inline footnote handlers with deferred registration.
- Stabilized DOCX footnote emission (ordering, include-boundary ordering, non-paragraph recovery diagnostics).
- Added IR-level and OOXML-level regression coverage.
Final stats at merge: 192 tests, 463 expect() calls, 0 type errors.
7. PR: Args-first deferred tranche (header/footer variants + typed include params) — DONE (merged to main)
Branch: feat/args-first-deferred-tranche-1
Apply an args-first rule to deferred items: extend existing directives instead of creating new directive names. Scope this PR to two high-ROI deferred features with tight tests.
LDOC-V3-SPEC.md: define@header(variant: "default" | "first" | "even")@footer(variant: "default" | "first" | "even")@params(types: { key: "string|number|boolean|object|array[?]" })
SUGAR_BACKLOG.md: markSG-001active for this PR.
Done when: spec and backlog clearly define accepted args, fallback behavior, and diagnostics for invalid values/types.
src/bind/contracts.ts: allowvariantarg on@header/@footer.src/evaluate/directives/block-header-footer.ts: route header/footer body to metadata slot (default/first/even) fromvariant.src/emit/docx/index.tsandsrc/emit/docx/sections.ts: read and emit all configured slots (not onlydefault).
Done when: variant-specific header/footer content is emitted to the correct DOCX references, with diagnostics for invalid variant or duplicate slot overwrites.
src/bind/contracts.ts: permittypeson@params.src/shared/include-params.ts+ binder/validator wiring: validate include callsite args against child@params(types: ...)declarations.src/types/diagnostics.ts: add explicit codes for malformed type literals and include arg type mismatch.
Done when: include arg type mismatches produce source-located diagnostics; existing untyped @params(names: [...]) behavior remains unchanged.
src/evaluate/layout.test.ts+src/emit/docx/ooxml-harness.test.ts: default/first/even header/footer variant behavior.src/evaluate/include.test.ts+ binder tests: typed include params happy/mismatch/malformed cases.
Done when: all new argument surfaces have positive + negative tests and no silent fallback behavior.
Explicit non-goals for PR #7
- No new directives for these capabilities (
@headerFirst,@paramType, etc.). - No direct expression-valued args (
SG-002) and no runtime coercion/casting. - No markdown sugar (
SG-003/SG-004/SG-005) and no control-flow directives (@if,@for).
- Typed include params (
SG-001, shipped in PR #7: arity + type validation) - Direct expression args (
SG-002) - Markdown emphasis sugar (
SG-004) - Table of contents generation
- Section-specific header/footer variants (shipped in PR #7: first/even via
variantarg) - Images/logo embedding API
- Watermarks and background text
- Defined-terms system (first occurrence styling)
- Exhibit/appendix packaging
- Track changes compatibility