Skip to content

Decision records ​

One file per decision, kept because the reasoning is the part that rots invisibly: a config line can be re-read, but the four options we rejected and why cannot be recovered from the tree. An agent reaching a fork already covered here should find the answer instead of re-deriving it, and more importantly should find out when the answer was withdrawn.

That last part is why this index exists. Five of these records no longer say what they appear to say, and until now the only way to learn that was to open the file. A retracted ADR read as live guidance is worse than no ADR at all: ADR 0018's mechanism (splice a module's source into vbaProject.bin) was verified, documented, confidently written, and does not work.

Status is the column to read first. Retracted records are kept rather than deleted, because the disproof is the valuable part, but they are guidance about history, never about what to do now.

The acceptance date orders these, not the number. ADR 0029 was renumbered out of a collision and sits last while dating from 2026-07-19; renumbering the twenty-seven records after it would have broken far more cross-references than the collision did.

#DecisionStatus
0001Rewrite runtime & toolchain: run .ts directly, defer the bundlerAccepted 2026-07-11 · build slice resolved 07-19 by addendum
0002Microsoft OpenXmlValidator as an external conformance oracleAccepted 2026-07-11 · mechanism superseded 2026-08-15 by 0033; the stance stands
0003Zip container is fflate; the write path emits XML directlyAccepted 2026-07-12
0004The XML read path is a lean, hand-written SAX pull parserAccepted 2026-07-12
0005WorksheetModel stays a semantic value; attached parts are out of scopeAccepted 2026-07-18
0006API docs generated from the types, not a docs frameworkAccepted 2026-07-19
0007Spec reference: vendored OOXML schemas + Microsoft Learn MCPAccepted 2026-07-19 · schema half superseded 2026-08-15 by 0034; the Learn MCP half stands
0008Upgrade to TypeScript 6; hold at 6 (not 7) until the printer API portsSuperseded in part 2026-08-05 by 0028 · Accepted 07-19
0009Tighten the lint/type gates where free; decline isolatedDeclarationsAccepted 2026-07-20 · the posture stands; the tool enforcing it changed 2026-08-25, see 0036
0010Make the correctness net easy for agents to dispatchAccepted 2026-07-20
0011Type-check the harness: migrate test/ + scripts/ to strict .tsAccepted 2026-07-20
0012Three tiers of correctness evidence; round-trip proves consistency, not conformanceAccepted 2026-07-21
0013Excel Desktop is an automatable Tier-3 oracle for state-observable behaviorAccepted 2026-07-21
0014Charts, vector shapes, slicers, and form controls stay round-trip-only for 1.0Accepted 2026-07-21
0015Package name, SemVer, and the first published versionAccepted 2026-07-21
0016The VBA project is readable through a typed view; authoring stays deferredAccepted 2026-07-22 · amended 07-23 by 0017, which 0019 then retracted; read 0019 before relying on the amendment
0017VBA authoring is in scope; the consumer gate is liftedRetracted 2026-07-24 by 0019 · originally Accepted 07-23
0018Editing an existing macro's source is done by splicing the original .binRetracted 2026-07-24 by 0019
0019VBA authoring needs real, compiled p-code; the "recompile cookie" premise is retractedAccepted 2026-07-24
0020The customUI ribbon is readable through a typed view; authoring stays deferredAccepted 2026-07-24
0021The VBA project signature is readable as presence, not verified as validityAccepted 2026-07-24
0022Verification is one cached, parallel entrypointAccepted 2026-07-27
0023Seven subpath entry points, disjoint by construction, with the error taxonomy as its own faceAccepted 2026-07-29
0024Async is one writer, not a mirrored pairAccepted 2026-07-29
0025The workbook default font is declared, not assumedAccepted 2026-07-29
0026Releasing is a GitHub release, and npm follows with no credentialAccepted 2026-07-29
0027Dependencies are updated by a bot, and CI is the reviewerAccepted 2026-07-30
0028Move to TypeScript 7; the compiler API scripts move to unstable/*Accepted 2026-08-05
0029Toolchain standup: Biome for lint/format, node --test kept, tsc for type testsAccepted 2026-07-19 · lint/format half superseded 2026-08-25 by 0036; the rest stands · renumbered 2026-08-08 from a collision at 0002
0030src/io/xlsx/ stays flat; the read/write directory split is rejectedAccepted 2026-08-08
0031The emitted declarations are typechecked too; two more gate flags go onAccepted 2026-08-08
0032Package output is reproducible: entry timestamps are pinned, not clockedAccepted 2026-08-11
0033The OOXML oracle is a shared package, not a repo-owned .NET toolAccepted 2026-08-15 · supersedes the mechanism of 0002
0034The schema reference is a queryable graph, not a vendored XSD dumpAccepted 2026-08-15 · supersedes part 1 of 0007
0035Coverage is the union of both suites, measured with node's own implementationAccepted 2026-08-25 · picks up the coverage thread deferred by 0029
0036oxlint and oxfmt replace Biome; the type-aware rules come from tsgolintAccepted 2026-08-25 · supersedes the toolchain half of 0029 · its exemption counts superseded 2026-08-26 by 0037 + 0038
0037Every tree the linter type-checks has a tsconfig.json the linter can findAccepted 2026-08-26 · corrects a mechanism 0036 observed but did not diagnose
0038The corpus keeps its untyped boundary, and it costs six rules rather than sixteenAccepted 2026-08-26 · answers the question 0036 deferred
0039The website is generated from the docs tree, and drift is a build errorAccepted 2026-08-27
0040The browser boundary is an entry point, and a gate walks the graph to prove itAccepted 2026-08-28 · narrows the entry-point set of 0023
0041One date-format vocabulary, and it is the spreadsheet'sAccepted 2026-09-03 · changes the meaning of CsvWriteOptions.dateFormat without changing its type
0042A hyperlink belongs to the sheet, not to a cell's valueAccepted 2026-09-12

Writing one ​

Take the next free number. State the decision in the title as a claim, not a topic. "Async is one writer, not a mirrored pair" tells a reader what changed; "Async I/O" does not. Give the status line a date and, when the record depends on or alters another, say which and how. Then add the row here, because an index nobody updates is how a retracted record gets read as live guidance.

When a decision turns out to be wrong, retract it in place: mark the status, name the record that retracts it, keep the body, and say in one line what specifically failed. Do not delete it and do not quietly edit the body into being correct. The disproof is why the file is worth keeping, and a body edited to match hindsight destroys exactly the evidence that would stop the next agent trying the same thing.

Released under the MIT License.