# Independent runtime oracle

**253 assertions: 250 JS-upstream comparisons and 3 explicitly documented
Python-backed saved-term-scope profile cases.** This is not a claim that all 253
match JavaScript Fluent. Read `comparison-report.md` for the actual last run.
Everything here and in `runtime_oracle/` is test tooling, excluded from production
MoonBit LOC. No runtime/Intl implementation is imported into the reference generator.

## Pinned references and evidence

- `package.json` / `package-lock.json`: real npm `@fluent/bundle@0.19.1`, exact
  version, tarball and integrity; no lifecycle scripts.
- `requirements.lock`: `fluent.runtime==0.4.0` and every transitive dependency,
  exact versions and SHA-256 universal-wheel hashes.
- `make-fixtures.mjs` / `fixtures.json`: deterministic recipes and **253 readable
  input cases**, with source-line arrays, locale, isolation, typed args and request.
- `generate.mjs`: executes real JS upstream for **all 253** cases and independently
  invokes `python-reference.py` for just the three named scope-profile cases.
- `expected.json`: **unmodified JS results for all 253**, including all diagnostics.
- `python-expected.json`: raw Python values/errors, dependency versions, source
  hashes, input/policy hashes, plus the explicit profile projection where required.
- `compatibility-profile.json`: the three named cases and their public policy;
  never an implicit skip list.
- `metadata.json`: upstream integrity, input/output hashes, Node **v24.14.0**, ICU
  **78.2**, CLDR **48.0**, Unicode/tz/V8 versions, locale resolution and counts.
- `runtime_oracle/cases_*_test.mbt`: 13 bounded generated test shards. Each test
  names its reference profile and checks exact string, error count and locale.
- `last-test-output.txt`, `comparison-report.json` / `.md`: actual completed test
  evidence, including the three measured JS compatibility differences. No stale
  failure report is presented as the current run.

`node_modules/`, `python_deps/`, `python_wheels/`, `__pycache__/` and `_build/` are
locally ignored. Dependencies, wheels and build products must not be committed.

## Install and reproduce (repository root)

Use **Node 24.14.0 with ICU 78.2** for generation and the JS test runner. Use a
Python 3.8+ interpreter for the scope oracle (the original run used Python 3.8.5).
Set `PYTHON` if its executable is not `python` on Windows or `python3` elsewhere.
The Python cases use text only, not Babel/ICU numeric formatting.

```sh
npm ci --ignore-scripts --no-audit --no-fund --prefix scripts/runtime-oracle
python -m pip install --require-hashes --only-binary=:all: --no-compile --target scripts/runtime-oracle/python_deps -r scripts/runtime-oracle/requirements.lock
node scripts/runtime-oracle/generate.mjs
moon fmt runtime_oracle --target-dir runtime_oracle/_build
```

`generate.mjs` executes **both** references. No manual expected edits are needed.
Only after intentionally changing recipes:

```sh
node scripts/runtime-oracle/make-fixtures.mjs
node scripts/runtime-oracle/generate.mjs
moon fmt runtime_oracle --target-dir runtime_oracle/_build
```

Run the MoonBit package with a UTC default host timezone. For POSIX shells:

```sh
TZ=UTC moon test --target js -p chenliyi-cly/moonfluent/runtime_oracle --target-dir runtime_oracle/_build --deny-warn --no-render > scripts/runtime-oracle/last-test-output.txt 2>&1
node scripts/runtime-oracle/report.mjs
```

For PowerShell:

```powershell
$env:TZ = 'UTC'
moon test --target js -p chenliyi-cly/moonfluent/runtime_oracle --target-dir runtime_oracle/_build --deny-warn --no-render 2>&1 | Tee-Object -FilePath scripts/runtime-oracle/last-test-output.txt
# Preserve/check $LASTEXITCODE before running another command.
node scripts/runtime-oracle/report.mjs
```

The report validates completed totals and failure evidence; compilation failures
cannot become a passing report. The Moon test exit code is authoritative; report
creation itself is not a replacement for it. Typed dates explicitly use UTC,
except the one deliberate caller-timezone preservation case. No wall clock or
randomness is used. No whole-root format/info operation is needed.

A separate non-JS `portable_smoke_test.mbt` checks text resolution and explicit
unsupported Intl results. It is **one portable smoke test**, not part of the 253
JS assertions. Its imports also keep non-JS `--deny-warn` builds warning-free.

## CI read-only consistency check

After the exact npm/pip installations above and Node pin:

```sh
npm --prefix scripts/runtime-oracle run check
# Equivalently:
node scripts/runtime-oracle/make-fixtures.mjs --check
node scripts/runtime-oracle/generate.mjs --check
```

`--check` re-executes **both real reference implementations**, compares recipe
output, both expected artifacts, metadata and every generated shard/manifest;
nonzero means stale/changed evidence. It does not write files (Python runs with
`-B`, so even a cold import does not write bytecode). JSON reference artifacts are
compared byte-for-byte. Generated MoonBit is compared ignoring formatting,
comments and optional trailing commas only; string contents are never normalized.
Run package-scoped `moon fmt ... --check` separately for formatting.

Node/ICU/CLDR/Unicode/tz/V8 and locale metadata must match. The recorded
`platform`/`arch` are provenance only, so Linux CI is allowed. A different Node
version fails even normal generation before writing artifacts. **Do not refresh
expected outputs just to accommodate a different Node/ICU host.**

## Explicit saved-term-scope profile

JS 0.19.1 resets `scope.params` to `null` after a nested term; Python 0.4.0
restores the saved environment. MoonFluent intentionally follows restoration.
The three fixtures remain present and tested, with JS evidence retained:

| Case suffix | JS observed / errors | Python observed / errors | Exact tested profile value / errors |
| --- | --- | --- | --- |
| `nested-parameter-after` | `outer/inner/{$case}` / 1 | `outer/inner/outer` / 0 | `outer/inner/outer` / 0 |
| `nested-external-after` | `outer/Inner/external` / 0 | `outer/Inner/outer` / 0 | `outer/Inner/outer` / 0 |
| `nested-no-param-after` | `{$missing}/{$missing}` / 1 | `missing/missing` / 0 | `{$missing}/{$missing}` / 0 |

**The third case is not raw Python byte equality.** Python renders FluentNone as
bare names; the explicit policy projects only the exact whole string
`missing/missing` to the Fluent-style placeholder spelling
`{$missing}/{$missing}`. The generator rejects a changed raw Python value rather
than applying a broad replacement. Both raw values and the rule are recorded.
All three exact error counts come from real Python, not a fabricated result.
These cases are reported as Python-backed profile assertions, not JS matches.

For raw Python-only evidence (JSON stdout, no writes):

```sh
python -B scripts/runtime-oracle/python-reference.py
```

## Comparison rules and coverage

- Output is exact, including localized whitespace, Unicode, bidi and placeholders.
  Resolution-error **counts** are exact; raw upstream names/messages are recorded
  without equating them to MoonFluent's separate diagnostic-code taxonomy.
- JS FluentResource silently skips junk. MoonFluent's extra syntax:Junk diagnostics
  are an explicit API addition: resource comparisons count duplicate definitions,
  not syntax diagnostics. Duplicate-attribute selection itself is compared exactly.
- Runtime locale is checked against configured locale; JS formatPattern returns no
  locale field. No fictional upstream Localizer/fallback API is used.
- Typed options are native JSON scalars to upstream and string-encoded maps to
  MoonFluent. Translation literal coercions are not normalized away; hour12 and
  useGrouping each cover numeric 0/1 and string "false". Direct application bool
  options retain their separate string-map contract.
- Coverage includes en/fr/ru/ar/pl/cs/zh/ja plural/number/date formats, exact/string
  and nested selects, decimal precision, NUMBER legal option filtering, currency,
  DATETIME UTC and caller timezone, both cross-type conversions, attributes and
  duplicate attrs, legal **term attribute selectors**, scopes, duplicate recovery,
  custom functions, errors, cycles and bidi isolation.
- `NUMBER({ $n })` and deeper inline placeables are valid in pinned upstream;
  four dedicated cases include precision and missing arguments. Unknown functions
  and missing terms include expression arguments to test evaluation order.
- Intentional depth64/placeable100/work10000/UTF16-output100000 limits are excluded.
  Every unexpected profile mismatch remains a failing assertion.
