<!--{"section": "home", "order": 3, "navTitle": "Assumptions", "pin": "bottom"}-->

# Assumptions ledger

Every design decision here rests on a belief about how code, models, or attackers behave.
Most such beliefs are never checked. This is the list of ours, each with a **verdict** and a
link to the evidence.

**The point is the verdict column.** Detail lives in linked documents; this page exists so
the current state of what we actually know is readable in thirty seconds, and so a refuted
assumption is impossible to miss.

| Status           | Meaning                                  |
| ---------------- | ---------------------------------------- |
| ✅ **supported** | tested, held up                          |
| ❌ **refuted**   | tested, was wrong — and what we changed  |
| ⚠️ **nuanced**   | true only under conditions worth knowing |
| 🔍 **untested**  | believed, not yet measured               |

---

## Security & cost model

| #   | Assumption                                               | Verdict                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Evidence                                                           |
| --- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
| S1  | Fuel bounds the work a program can do                    | ❌→✅ **was refuted, now fixed** — size-proportional atoms charged a flat cost; `jsonStringify` serialized **2,000,000 elements for 1.2 fuel** under a 10-fuel budget. Fixed with `chargeForSize`; fuel now scales linearly.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | [`cost-invariant.test.ts`](src/vm/cost-invariant.test.ts)          |
| S2  | Fuel also bounds memory                                  | ❌→✅ **was refuted, now fixed** — fuel is a _time_ budget; at ~10KB/fuel a legitimate 100k budget bought ~1GB of live string. Added `maxHeapBytes` (64MB default).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | [`cost-invariant.test.ts`](src/vm/cost-invariant.test.ts)          |
| S3  | A capability can't hand the guest a live host reference  | ❌→✅ **was refuted in SCOPE on 2026-08-26 (#38), now fixed** — enforced by the structured-clone membrane at one choke point; adversarially tested. Hardened 2026-08-03: the pre-walk used to read `v[k]`, **invoking getters** — so the boundary ran host code while inspecting it. Accessors are now rejected via descriptors. **The caveat:** `membraneValue` has exactly one call site, inside `if (atom.effects === 'io')`, and `defineAtom` defaulted to `'pure'` — so an embedder atom that did not opt in bypassed the choke point entirely, getters intact. Not a weaker guarantee for that population: **no guarantee at all**, and silently. Fixed in 0.13.6 by inverting the default to `'io'` (BREAKING); core atoms are swept back to `'pure'` explicitly. The row now holds for the VM, not for a subset. | [`malicious-actor.test.ts`](src/use-cases/malicious-actor.test.ts) |
| S4  | Termination is guaranteed                                | ✅ **supported by construction** — fuel makes bounded execution a precondition; the halting question never arises. Not _formally proven_ — see the honest scope note in the README.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | [README](README.md#safe-eval)                                      |
| S5  | Recursive agent calls can't amplify across an open graph | ⚠️ **nuanced, and inherently so (re-framed 2026-08-03)** — the `X-Agent-Depth` guard is **cooperative** and cannot be otherwise: budget does not cross a system boundary, only tokens and data do, and the other side takes care of itself. So the honest guarantee is over what we control — a **time box** on every run, **abort on every exit path** so we never leave outbound work alive, and **per-atom quotas** on what we summon. Chasing a carried fuel envelope was the wrong goal.                                                                                                                                                                                                                                                                                                                            | [README](README.md#safe-eval)                                      |
| S6  | Our sandbox resists a determined attacker                | 🔍 **untested** — layered and adversarially reviewed, never externally red-teamed. An escape-attempt corpus (vm2 CVEs, SES challenges) is the open item.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | —                                                                  |

## Agent legibility

| #   | Assumption                                                             | Verdict                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | Evidence                                                                                                                 |
| --- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| A1  | Our error messages help a model fix its code                           | ❌ **refuted** — shipped diagnostics produced a **0%** repair rate, identical to saying nothing. Worked examples: 80%. **Fixed**: remedies now show code, locked by a deterministic test.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | [FINDINGS](experiments/agent-legibility/FINDINGS.md) · [`diagnostic-remedy.test.ts`](src/lang/diagnostic-remedy.test.ts) |
| A2  | More documentation helps small models                                  | ❌ **refuted** — a 0.6k cheat sheet beat our 7.6k guide **2×**; adding the missing prose rule changed nothing. Guidance matters enormously (no guidance = 0%) but is **not monotonic**.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A3  | Models learn our rules from prose                                      | ❌ **refuted, three times independently** — prose rule added to the guide: no change. Prose remedy in a diagnostic: 50% vs 80% for the same remedy shown as code. **Models repair from examples, not rules.**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A4  | Syntax choice (braces/indentation/parens) drives model comprehension   | ❌ **refuted** — it's the **paradigm**, not the surface. Explicit state-threading scored 80% and mutation 20% _regardless of syntax_; s-expressions and braces tied once the paradigm was held constant.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A5  | Newline-terminated statements (`TjsStandard`) don't hurt comprehension | ⚠️ **weakly supported** — braces-with-semicolons and braces-without were indistinguishable (same rate, same error mode). N=5; suggestive only.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A6  | AJS is easy for small models to write                                  | ⚠️ **nuanced** — achievable (67% with a good cheat sheet) but sensitive to guidance; the dominant failure is reaching for `for` loops.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | [`ajs-grokkability.test.ts`](src/use-cases/ajs-grokkability.test.ts)                                                     |
| A7  | Small models can write TJS                                             | ❌ **refuted, and not expected to hold** — a 1.5B model reverts to TypeScript syntax even when told otherwise, and emits **hybrids** (`nums: [number]`) that TJS quietly accepts. TJS targets larger models; AJS is the small-model surface.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A8  | Executed verdicts repair better than type errors                       | 🔍 **untested** — the obvious experiment is confounded by training-data asymmetry. The clean version is **within-TJS**: same language, vary only the feedback string.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | [FINDINGS](experiments/agent-legibility/FINDINGS.md)                                                                     |
| A11 | Leaning on TS convention costs us the autocomplete work                | ⚠️ **nuanced — mostly not.** Measured 2026-07-31: the completion engine is driven by the **type descriptor**, not by example values (`.type` 35×, `.kind` 13×, `.params` 11×, `.example` only 3×) — and `: string` yields the same descriptor as `: ''`, so the engine is indifferent to spelling. The three example sites are a menu that becomes _additive_ (offer `string`/`int` alongside `''`/`5`) plus hover detail. The differentiating work is untouched: predicate-mined **value** completion (`suggest()`, guaranteed-valid because candidates are run through the compiled predicate) and introspection-driven member completion — neither references examples, and neither is expressible in TypeScript. Net: lose ~one completion list, gain tsserver/`.d.ts`/TS-tooling leverage.                                                  | [`predicate.ts`](src/lang/predicate.ts) · [`ajs-language.ts`](editors/codemirror/ajs-language.ts)                        |
| A15 | A `.tjs` file's EXTENSION tells a reader which semantics apply         | ❌ **refuted (2026-08-27)** — it carries **nothing**. Shown one `switch` as `.js` a model traced C fallthrough 5/5 and explicit `break` 5/5; shown the identical text as `.tjs` it scored **0/5**, applying C fallthrough every time — the worst possible result, and not from uncertainty. Its own reasoning: _"there is a language 'TJS'… maybe"_. There is no prior for the extension. **A one-line comment stating the RULE restored it to 5/5** — but only on a 27B; a 4B model is unmoved by anything in the file (0/5 every arm), extending A7 to reading. Naming the language WITHOUT the rule is worse than silence: 5 no-answers, the model speculating about what tjs is rather than concluding. So the affordance must be IN THE CODE and must be a rule, not a pointer. Probe every `.tjs`-only semantic change before shipping it. | [FINDINGS](experiments/agent-legibility/FINDINGS.md) · [`switch-probe.ts`](experiments/agent-legibility/switch-probe.ts) |
| A9  | Autocomplete meaningfully helps                                        | 🔍 **untested** — and testable _without a model_: truncate valid programs and measure hit@k of `suggest()` against the real next token.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | —                                                                                                                        |
| A10 | Types-by-example is the right **identity** for TJS                     | ⚠️ **nuanced — resolved 2026-07-31 as a decision, not a measurement: it is neither/both.** TJS accepts **TS type names OR examples**, equal standing, with examples buying **finer grain than TS can express** (`int`, `unsigned`, and pattern-constrained strings). So the on-ramp is "keep writing TypeScript" — which needs no teaching, satisfying A3/A7 — and examples are a **feature you graduate into**, not a concept you must learn first. The ladder: TS name → example → `Predicate(…)`. Asymmetric get/set is explicitly **not** a pillar of this (see A12).                                                                                                                                                                                                                                                                        | [`ts-type-names.test.ts`](src/lang/ts-type-names.test.ts)                                                                |
| A12 | Asymmetric get/set types are a core language need                      | ❌ **refuted (by scope, 2026-07-31)** — the general case is already covered: **computed properties work**, and **proxy behaviour is effectively computed types**. Asymmetry is chiefly needed for (a) **autocomplete** quality and (b) **describing external/ambient types** — a tooling and contracts concern, not a missing language primitive. Re-scoped to [`ambient-contracts`](docs/ambient-contracts.md); no longer gates positioning.                                                                                                                                                                                                                                                                                                                                                                                                    | [ambient contracts](docs/ambient-contracts.md)                                                                           |
| A13 | Developers (and models) would ADOPT TJS after using it                 | 🔍 **untested — never measured, and it is the actual product question.** The legibility harness measures whether a model can _write_ TJS; nobody has asked whether, after converting real code and reading real errors, it would _switch_. Two bars, scored separately: **(1) DX alone** — inline tests, docs, flight recorder, observe mode — which requires no belief in runtime types and is likely the easier win; **(2) capabilities** — runtime safety, inline WASM, safe eval. Needs a plain-TS control and forced comparisons rather than direct approval questions, which measure agreeableness.                                                                                                                                                                                                                                        | —                                                                                                                        |
| A14 | You can adopt TJS without changing program behavior                    | ❌ **refuted (2026-08-01)** — there is no observe mode. All three configured behaviors (return / log / throw) change what a function returns, so validating a legacy codebase necessarily alters it. The zero-risk bottom rung of the migration ladder does not exist.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | [`runtime.ts`](src/lang/runtime.ts)                                                                                      |

## Language & platform

| #   | Assumption                                                                    | Verdict                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | Evidence                                                                                                                                         |
| --- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| L1  | TJS is a superset of JS (`dialect: 'js'` preserves JS semantics)              | ✅ **supported** — enforced as a guardrail; a subset violation is a bug.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | [`subset-invariant.test.ts`](src/lang/subset-invariant.test.ts)                                                                                  |
| L2  | A verified predicate can serve as cache key, pushdown payload and auth object | ✅ **supported** — canonical form collapses formatting/naming, distinguishes meaning and cluster helpers; demonstrated end-to-end. ⚠️ _structural_: refactoring into a local mints a new identity.                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | [`predicate-canonical.test.ts`](src/lang/predicate-canonical.test.ts) · [`predicate-pushdown.test.ts`](src/use-cases/predicate-pushdown.test.ts) |
| L3  | Verified predicates compile to fast native JS ("safe is fast")                | ⚠️ **nuanced** — measured on one workload (~0.5ms to validate a whole theme); the systematic overhead campaign that would generalise it is unfinished. **2026-10-02, measured: 0.20ms → 7.3ms per theme (~36×; ~15× per value, isDimension 0.10 → 1.47µs)**, because predicate regexes now run on the VM's linear engine (safety over speed — a native match cannot be fuel-bounded, and the star-height screen certified the polynomial `/a*a*c/`). Regex is the whole difference; the engine's constant (literal-prefix skip, DFA) is the open lever.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | [`css/perf.bench.test.ts`](src/css/perf.bench.test.ts)                                                                                           |
| L4  | Published bundle-size claims are accurate                                     | ❌→✅ **was refuted, now guarded** — every row of the README table was stale (VM 66→74KB gz). Corrected, dated, and pinned by a test that fails on drift.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | [`bundle-size.test.ts`](src/bundle-size.test.ts)                                                                                                 |
| L5  | Emitted code runs standalone without a runtime                                | ❌→✅ **was refuted, now fixed (2026-08-06)** — held until parameter annotations began routing through declared `Type`s, at which point the `Type(…)` schema gate optional-chained to a `globalThis.__tjs.validate` the inline stub does not have, went falsy, and made every declared type reject **every value**: `double(4)` errored standalone while returning 8 under the full runtime. The gate now fails OPEN — unchecked-but-working is the correct degradation (TJS ⊇ JS); turning a working program into a broken one based on whether a runtime happens to be loaded is not. Nothing else in the suite exercises the inline stub, which is why it shipped. | [`codegen.test.ts`](src/lang/codegen.test.ts) · [`declared-type-annotation.test.ts`](src/lang/declared-type-annotation.test.ts)                  |

| L6 | Block syntax is self-evident — nobody assumes an implicit last-expression return | ❌ **refuted (2026-08-06)** — **five** functions in shipped teaching material ended a `wasm { }` block with a bare expression and returned `undefined`: `dot`, `addInts`, `factorial`, `lerp`, `sumArray`. The tell is that every `fallback { }` twin has an explicit `return` — the authors knew the JS rule and assumed the block was expression-oriented. Silent: it compiles, and `:!` returns mean no signature test. **Decision it feeds:** a block declaring a non-void return with no reachable `return` should be an ERROR; `predicate { … }` requires `return`. (A `predicate => …` one-liner was built and then removed before 0.14.0 final, 2026-10-06: it saved only `{ return }` and was a third spelling to learn.) | [`examples.test.ts`](demo/src/examples.test.ts) |

---

## Engineering practice

Assumptions about **our own process** rather than about models, users or the language.
These had no home before 2026-08-06, which is why the scanner-consolidation bet went
unrecorded through the release that made it.

| #   | Assumption                                                   | Verdict                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Evidence                                                                                                                      |
| --- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| E1  | Consolidating onto one shared scanner ends literal blindness | ❌ **refuted (2026-08-16), and the test was pre-registered** — `0.13.0` routed fifteen call sites through `scanLiterals()`, and issue #25 stated the deciding evidence in advance: "how many NEW literal-blindness defects appear now that one scanner exists". Answer within 24 hours: **two** — `splitParameters` (parser-params) and `splitParams` (js-tests), both evading the sweep by splitting on **commas** rather than scanning quotes, so neither _looked_ like a literal scanner. **Answer by 2026-08-16: at least FOURTEEN.** Six more found by review (`transformConstBang`'s raw `.replace` rewriting the contents of user strings; all five declaration scanners detecting on raw source, where the single-quoted form injected unescaped quotes and REJECTED legal JavaScript — a JS ⊆ TJS breach; `/* unsafe */` read out of a parameter default, turning validation OFF for the whole function; two `dts.ts` scanners emitting a phantom exported type into consumers' `.d.ts`), plus **nine revealed at once** when the dogfood conversion ratchet finally ran — six of them labelled "undiagnosed" for weeks and all nine the same defect, invisible because both ratchets gate on `SKIP_BENCHMARKS`, which `test:fast` sets and CI inherits. Consolidation removes duplication; it does not remove the class, because the class is "a pass that reads source without understanding it" and that has more shapes than one. Two refinements from the later batch: a comment can be **accurate about the wrong implementation**, and the obvious fix is sometimes **wrong in a way that looks right** (`maskLiterals` blanks comments too, so using it to find `/* unsafe */` erases the marker and passes every hostile test while deleting the feature). | [`literal-blindness.test.ts`](src/lang/literal-blindness.test.ts) · [#25](https://github.com/tonioloewald/tjs-lang/issues/25) |
| E2  | A gate that compiles an artifact proves the artifact works   | ❌ **refuted (2026-08-06)** — the playground examples were compile-checked and their inline tests run, but their **bodies never executed**, so an example with no inline tests was never run at all. Adding execution found five functions printing `undefined` against their own comments. Compiling is a claim about syntax; running is a claim about meaning, and only the second is what a reader experiences.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | [`examples.test.ts`](demo/src/examples.test.ts)                                                                               |
| E3  | A benchmark with a fixed iteration count stays valid         | ❌ **refuted twice (2026-08-06)** — a count is tuned to the hardware of the day and rots silently as hardware improves. `wasm-memory` timed a single pass at 0.17ms and printed **"0.00ms"** under Firefox's 1ms clock clamp; the vector benchmark's ratio swung ~20×–80× on an M5 Max because its **denominator** went sub-millisecond. Size by duration, and calibrate against the FASTEST path, since that is the term that vanishes first.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | [`vector-search.bench.test.ts`](src/linalg/vector-search.bench.test.ts)                                                       |

---

## Decisions and their outcomes

The ledger above records what we _believe_. This records what we _did_, and what
happened — including when the outcome was worse than expected, which is the only
entry type that changes future behaviour.

| Date       | Decision                                                                                 | Why                                                                                                                                    | Outcome                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ---------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 2026-08-06 | `:` in a destructuring pattern means **required**, not defaulted                         | the colon value is a type and a worked example; conflating it with a default made `:` mean nothing                                     | ✅ **clean** — **no pre-existing test depended on the old behaviour.** The only failures were three repro cases written an hour earlier. For a semantic change, that is about as strong a safety signal as exists.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| 2026-08-06 | `Type X<T>` subsumes `Generic X<T>`; `Generic` becomes an alias                          | two keywords made `type` → `Type` non-mechanical in both directions (disposal tax)                                                     | ✅ **clean** — no regressions; both spellings pinned byte-identical so they cannot drift into two implementations.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| 2026-08-06 | Route parameter annotations through declared `Type`s                                     | the other half of 0.13.0's sound-type-names work; prerequisite for `type` → `Type`                                                     | ⚠️ **caused a regression** — standalone emitted code then rejected **every** value, because the schema gate optional-chains to a `validate` the inline stub lacks and so failed CLOSED. Fixed same day by failing open. Refutes L5 as previously written.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| 2026-08-06 | **Revert** type arguments (`Box<int>`) rather than ship them                             | parsing worked, but `Box<0>` accepted `1.5` standalone — the inline stub's `Generic` does `typeof` where the real one infers structure | ✅ **right call** — shipping would have been a knowing silent under-check, the exact class the release spent a week removing. Blocker is now a stated design question rather than a latent defect.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| 2026-08-06 | Calibrate benchmarks by **duration**, in two passes                                      | fixed counts rot; one pass measures a cold loop and under-scales                                                                       | ✅ **better than expected** — run-to-run spread fell from 14–21% to ~6.5%, **and** revealed the old numbers were biased _low_: 500×128 reported ~8.5× for something that is ~12.7×.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| 2026-08-06 | Add a run gate for playground examples                                                   | compiling is not running                                                                                                               | ✅ **found five broken functions immediately**, all shipped in the npm package and the live playground.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| 2026-08-07 | **Do not** convert `===` → `==` in `fromTS` output; comment only where it would SIMPLIFY | `===` is already safe; TJS's `==` is safer than JS's but strictly more work                                                            | ✅ **decided against, on a measurement that was not in the original framing** — `Eq` costs **1.23×** a raw `===` on a comparison-dominated loop, so the rewrite is a pessimization paid for nothing whenever operands cannot be boxed or null. It is also not semantics-preserving: `x === null` discriminates null from undefined and TJS `==` does not, so the rewrite would need to skip exactly the comparisons TS authors write deliberately under `strictNullChecks`. And a TS reader seeing `==` in converted output distrusts the converter, which is the conversion's whole value. Narrowed to a **comment** where the source manually reimplements `==` (`x === null \|\| x === undefined`, `a.valueOf() === b`) — teaching where there is something to teach, silent otherwise. |

---

## How to add to this ledger

1. **State the assumption as something that could be false.** "Our errors are helpful" is
   checkable; "our errors are good" is not.
2. **Build the cheapest probe that could refute it.** `experiments/agent-legibility/` has
   runnable examples. Comprehension probes need no parser; autocomplete probes need no model.
3. **Record the verdict here in one line**, with the number that decides it. Detail goes in
   the linked document — this page must stay skimmable.
4. **Act on refutations**, then encode the fix as a _deterministic_ test where possible. The
   experiment justifies the invariant; the invariant then holds without rerunning the
   experiment. (A1 → `diagnostic-remedy.test.ts` is the worked example.)
5. **Re-check the entries a change touches.** L5 read "✅ supported" for three days after the
   work that broke it — because nobody looked. A ledger nobody revisits records the moment it
   was written, not the state of the project.

## How to add a decision

The assumptions table records what we _believe_. The decisions table records what we _did_
and what followed, which is the half that changes future behaviour.

1. **Log it when the outcome is known**, not when the decision is made — an entry with no
   outcome is a TODO wearing a ledger's clothes.
2. **Say what would have made it wrong**, in the "Why" column. "Because it seemed better" is
   not reviewable a year later.
3. **Record bad outcomes in the same table as good ones.** A decisions log with no ⚠️ rows is
   a marketing document. Routing annotations through declared types is in there precisely
   because it caused a same-day regression; that row is worth more than the four clean ones.
4. **Prefer the surprising result to the confirming one.** "No pre-existing test depended on
   the old behaviour" and "the old benchmark numbers were biased _low_, not merely noisy" are
   both facts nobody predicted, and both change how the next change gets made.

**Pre-registration works and is nearly free.** Issue #25 stated its own deciding evidence
("how many NEW literal-blindness defects appear now that one scanner exists") before any had
appeared. Two arrived within 24 hours, and because the question was written down first, the
answer was unambiguous instead of arguable. Where a decision has an observable consequence,
say what would count as evidence _at the time you decide_ (E1).

**Methodological lessons paid for in this repo**, worth reading before designing a probe:
an apparatus that fails closed looks exactly like a strong negative result (a harness bug
scored 0/8 while the model was correct); an instrument saturated at its floor discriminates
nothing; and changing two things at once will hand you a confident, wrong conclusion — a
"Lisp wins" result evaporated once syntax and paradigm were separated.
