Skip to content

fix(windows): Windows CI for the oracle framework and gap CLI, and the path rule - #58

Merged
KyleAMathews merged 36 commits into
mainfrom
ci/windows
Nov 14, 2026
Merged

KyleAMathews merged 36 commits into
mainfrom
ci/windows

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Makes Windows a blocking part of CI for the oracle framework and the gap CLI, and fixes what broke there. The Windows static and e2e gap oracles are not blocking yet: they still fail on windows-latest and are tracked by class in #72 (and in the follow-up PR #73).

This revision also answers the independent review at ebc39e6 (NOT READY): the stop witness that never stopped (F1), replay quoting by the shells' real grammars with adversarial names (F2, F3), the POSIX stop hook through the supervisor (F(f)), forward-slash only on win32 (F5), the native-path misses (F6), preview's needs (F7), the #72 links (F8), and the pipe-scope limit (F9).

Changes

  • Gap CLI paths. One rule: forward slashes at entry, and in keys and report paths, on win32 (on POSIX a backslash is a name's character); native paths only at the file system. Covers the config wrapper import, the mutant-copy map, TypeScript file names, the 8.3 short names (realpathSync.native on both sides, including the temporary directory), the report, done-line, and error-log paths.
  • Stop. An unsupervised win32 run writes oracle-gaps: done stopped (<signal>) on both streams when a stop lands after it has started. The test-only hook ORACLE_GAPS_TEST_STOP=<file> takes the stop path of SIGINT: in a supervised run, the supervisor's stop, which forwards to the child (a hooked stop is done stopped, exit 130).
  • Daemon on Windows. A named pipe (\\.\pipe\oracle-gaps-<key>), keyed by the same real path as the CLI; a timeout names the end of the daemon's log.
  • Per-shell replay lines (framework). A failing property prints a PowerShell line and a cmd line on win32. The -t argument never carries a shell-hostile character (", %, !, curly quotes): each becomes the pattern's . (option c, a coordinator ruling). The exact test is in ORACLE_UNIT/ORACLE_PROPERTY: the witness decodes each PowerShell and cmd set value and compares it exactly with the failing unit's names as vitest prints them. cmd has no form for an environment value with ", %, or ! (the register's rule, corrected in round 3): its line says so and points to the PowerShell line. The -t substitution applies on every platform, so POSIX -t output also differs (a . where a hostile character was). PowerShell's quotes include U+2018 to U+201B, and each is doubled inside a single-quoted value.
  • Refusals. A package with no package.json is refused (exit 2, named in the refusal).
  • Oracles. gap-report-path-spelling (new, metamorphic); the classify oracle reads each shell's replay line by its grammar on every host, and generates adversarial names; the models' expected done lines are forward-slash; the static scratch packages have a manifest.
  • Test-only. npm spawned through a shell on Windows; the probe-form model decides production by a src directory segment; the owns test uses the native real path; the tsc link is read from npm's Windows shim; shipped citations are forward-slash.
  • CI. Blocking Windows jobs: unit suites; classify, probe-form, mutant-validity, path-spelling; the CLI fixture job with its witnesses (done lines, refusal, stop, per-shell replay for two hostile names). preview needs the blocking jobs. Non-blocking, continue-on-error, pointing at Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72: the static and e2e jobs (six shards each).

Decisions

Register entries (~/.cache/oracle-grammar/decisions-register.md) this PR touches:

  • Windows paths (C): keys and report paths are forward-slash, and drive letters uppercase, on win32; filesystem calls get native paths.
  • Deterministic replay across shells (C): the replay inputs are identical on every OS; the printed command differs per shell; each printed line replays, or the cmd line says it has no form.
  • Stop window on every platform (C): the all-or-nothing stop law applies on Windows too. Ctrl+C from a console is not exercised (the hook stands in); child.kill('SIGINT') on win32 is TerminateProcess, treated as SIGKILL.
  • (a) The win32 argv cap (C): a per-platform OS limit on a generated input (a 32,767-character command line), see Limits.
  • (b) A missing package.json is a refusal (C): user-file errors are refusals; the POSIX static oracle covers it.
  • (c) The blocking and non-blocking split (C, coordinator's ruling).
  • (d) The POSIX state and socket paths move to the temporary directory's real path (C): an older daemon is found only after its idle timeout.
  • (e) Unsupervised win32 runs are exempt from "no process outlives the CLI" (C, Limit; tracked in Windows: an unsupervised gap run can leave child processes running (no process tree kill) #74).
  • "Zero shipped bytes" (C): the replay code in src/oracle-property.ts ships inside @tanstack/oracles; test-time packages do not count against it.
  • P9: the replay change has an oracle RED (below) and Windows evidence.
  • P10: the done line on both streams matches the exit code (witness, Windows).
  • P12: every Windows job under 10 minutes. Not met yet for the static and e2e jobs (non-blocking; Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72).

Evidence

  • Law: the register entries above.
  • Reach: the existing static, e2e, classify, and path-spelling histories; the classify oracle's adversarial names are derived from each generated test's own fields (no draw: the generator is unchanged, zero fc. lines differ from main); the path-spelling oracle's POSIX spellings are an appended wide record (drawn last), and its win32 fields keep their original domains (restored in round 3; the POSIX spellings are an appended wide record); gap-report-path-spelling runs 200 histories.
  • RED (replay quoting, F2/F3): the parent printer (ebc39e6, with only the platform parameter added) fails the classify oracle on two names (the RED run recorded them before the names were derived): the PowerShell line for ^’ t0 (the PowerShell line ends its quote at U+2019, which a PowerShell reader does not read as plain words), and the cmd line for q"t t0 (which the shell does not read as plain words). Since the names are derived, the current seeds reach a double quote but not U+2019; the U+2019 PowerShell case is covered by the Windows witness's fixture (fixture ’ & | < > ( ) ^ ! replay), not by the oracle's seeds. Local, exit 1.
  • GREEN (replay quoting): classify 276/276 on Linux. Windows (run 43535601236, head b904d57): the replay witness ran four printed names, each PowerShell line and cmd line reproduced the failure; two names had the printed cmd has no form line, as designed (that run predates the round-3 cmd rule and the option-c -t rule).
  • RED (stop, F1): the witness accepted a completed run as a stop (review); fixed: a stop now requires the stopped line on both streams with exit 130.
  • GREEN (stop): POSIX local run under the e2e lock: stop outcome (a), exit 130. Windows (run 43535601236): stop outcome (a): stopped line on both streams, exit 130.
  • Mutant: the replay witness rejects a run that prints only the POSIX line on win32 (throwaway PR THROWAWAY: replay mutant for the Windows witness (do not merge) #71, closed; run 43515698242). The parent printer is the mutant for the classify oracle (RED above).
  • CI at head b904d57 (run 43535601236): every Linux job green (including Publish preview, which needs the blocking Windows jobs); blocking Windows jobs green (unit suites, classify/probe-form/mutant-validity/path-spelling, CLI fixture job with its witnesses). Non-blocking Windows static (6) and e2e (6) shards fail (Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72).
  • Path-spelling on POSIX has no narrowing: a backslash name and an x: drive are generated and kept native, with a disk-backed witness (realPathOf keeps the name; posix() leaves it; RED on ebc39e6: 2 of 5 tests).
  • Local: framework tsc --noEmit passes; classify 276/276; shipped citations 2/2.
  • Code weight (minified and gzipped, esbuild, vs origin/main): src/oracle-property.ts (the shipped runtime) +204 bytes at ebc39e6; the cmd and PowerShell helpers of this revision are not re-measured here. Test-time CLI modules add about 880 bytes in total; paths.mjs 345 (not counted against zero shipped bytes).

Limits

  • win32 argv narrowing (a): Windows caps a command line at 32,767 characters, so the static oracle's unknown long-argument case uses 30,000 characters on win32 (100,000 on POSIX).
  • Ctrl+C from a console is not exercised on Windows (no manual check was run); the hook stands in.
  • Rerun lines are coarse -t filters (coordinator ruling, F3): a fixed-seed unit has no exact selector, so its Rerun line can also run a sibling whose name the anchored pattern matches. Example: a unit fixture Q"1 replay and a sibling fixture Q21 replay. The witness counts a Rerun line only when its own failing unit's exact FAIL line appears in its output, so a sibling's failure cannot satisfy it. An exact selector is tracked in Framework: an exact selector for a fixed-seed unit (Rerun lines are coarse -t filters today) #78 (a framework feature, not part of this PR). Replay lines select exactly, through ORACLE_PROPERTY and ORACLE_UNIT.
  • cmd ! is a no-form character for environment values (a coordinator ruling, conservative: DelayedExpansion would expand it silently).
  • Pipe names are machine-global, not per user: a second user on the same machine shares the daemon's pipe name.
  • Daemon state: POSIX state and socket paths moved to the temporary directory's real path (d): an older daemon is not found until its idle timeout.
  • Unsupervised win32 process trees (e): a test's child process can outlive an unsupervised win32 run (no process groups), tracked in Windows: an unsupervised gap run can leave child processes running (no process tree kill) #74. This predates fix(windows): Windows CI for the oracle framework and gap CLI, and the path rule #58.
  • Static and e2e Windows jobs are non-blocking and failing (Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72); the 9-minute budget is not met for them.
  • The win32 classify readers are checked on Linux by construction; the Windows CI runs the real printed lines.

Follow-up

The static and e2e Windows failures, and the re-shard under 9 minutes, are tracked in #72 and continue in #73.

This pull request and its description were written by Isaac.

Final check (head 7d46701)

  • CI run: 43573384487 (head 7d46701). Every Linux job and every blocking Windows job is green; the non-blocking Windows static and e2e shards are unchanged (Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72).
  • The Windows fixtures have no ! in their names except where the cmd branch is checked: fixture 100% done! (L3) exercises the cmd env no-form branch, and the replay output is printed in the CI log (L2).
  • F9 (control-character escaping): the printed -t pattern escapes control characters as \uXXXX, so the register's "controls become ." is wrong and the code is right (coordinator's correction). Evidence: the classify oracle's control-name case (U+0001); dropping escapeControls from the printer fails 4 classify tests.
  • Shipped weight: src/oracle-property.ts (minified, gzipped, esbuild, against origin/main): 29,070 -> 29,921 minified bytes (+851); 11,059 -> 11,445 gzipped (+386).
  • Follow-ups in Windows static and e2e gap oracles: remaining failures by class (non-blocking on #58) #72: L1 (the classify reader rejects && inside quotes, so the set prefix branch is not reached) and L6 (compare Rerun pairs across shells).

The framework, the eslint plugin, and the gap CLI have never run on
Windows, and users report path problems there. Two diagnostic jobs run on
windows-latest: the unit suites (framework, eslint plugin, gap fast
oracles) and the gap CLI end to end (a fixture package written at run
time, the plain and daemon paths, and one fixed-seed e2e unit). Both are
continue-on-error and each step continues on error, so the first failure
does not hide later ones. Neither is a required check or a dependency of
preview.

Co-authored-by: Isaac <no-reply@databricks.com>
@changeset-bot

changeset-bot Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1709814

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a0c8eb15-ea1b-482d-8556-3d21a3e69d34
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pkg-pr-new

pkg-pr-new Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/TanStack/oracles/@tanstack/eslint-plugin-oracles@58
npm i https://pkg.pr.new/TanStack/oracles/@tanstack/oracles@58

commit: 1709814

KyleAMathews and others added 13 commits November 13, 2026 09:02
Diagnostic only, not a fix. The first run showed the gap fast suites and the
fixed-seed end-to-end unit hang on windows-latest (cancelled at the job
timeout, with no output after the static oracle and the e2e calibrations
started). The fast suites now run one file per step with a step timeout and
verbose output for the static oracle, so the hang is located. The fixture
gets the package.json it was missing (the CLI reported ENOENT for it). The
job timeouts are raised to 45 minutes so the split steps can finish.

Co-authored-by: Isaac <no-reply@databricks.com>
… run

Diagnostic only. Adds a bash replay of the first failing static unit (its
verdict is not printed by the run), a run of the fixture with the discovered
config instead of --config, and a dump of the gap CLI's error.log files from
the OS temp directory, which the daemon run's failure points to.

Co-authored-by: Isaac <no-reply@databricks.com>
…ines

Forward slashes at entry, native only at the file system. Paths enter the
CLI as argv, as Vite and Vitest report them, and as realpath returns them;
comparisons and keys use one spelling (oracle-gaps/paths.mjs).

- The config wrapper imports the config by a POSIX specifier. A backslash
  in an ES module specifier is a character, so every run with a config
  was refused on Windows (check.mjs, wrapper).
- Mutant copies are keyed and served in forward slashes, as Vite resolves
  and Vitest reports them. The copy map was keyed by native paths, so the
  copies were never served on Windows.
- Module IDs are kept by isAbsolute, not by a leading slash: a Windows ID
  is `C:/...`.
- The package root, the located packages, and the source names use the
  native real path on both sides (realPathOf). The JavaScript realpath
  kept 8.3 short names such as RUNNER~1 and refused every owns entry.
- The daemon listens on a named pipe on win32 (no socket file to
  remove), keys by the same real path as the CLI, and its timeout names
  the end of its log.
- A package with no package.json is refused, not an internal error.
- Replay and rerun lines print PowerShell and cmd forms on Windows; the
  POSIX form is unchanged.

Co-authored-by: Isaac <no-reply@databricks.com>
…e realpath

- npm is an npm.cmd shim on Windows; spawnSync runs it through a shell
  there (package.test.ts, shipped-citations.test.js).
- The probe-form oracle's model decides production by a directory named
  src, split on either separator, not by a substring with `/`. Production
  was right; the model was wrong on Windows.
- The owns test uses the native real path, as the CLI does.

Co-authored-by: Isaac <no-reply@databricks.com>
The diagnostic steps are gone. The Windows jobs mirror the Linux shards:
the unit suites in one job, the static gap oracle and the fixed-seed
end-to-end oracle in three shards each (pr-shards.mjs), and the gap CLI on
a fixture, including the discovered config and the daemon. Each job has a
15-minute backstop. The jobs are still continue-on-error until every one
is green; that line is removed then.

Co-authored-by: Isaac <no-reply@databricks.com>
… path

The owners and the instrumenter named files with the platform's
separators, and TypeScript matches a file's name as given, so on Windows
the owner map keyed `src\x.js` while the sources were `src/x.js`, and
CommonJS sites lost their functions. The compiler now gets forward-slash
names, and owner keys are forward-slash (schemata.mjs, owners.mjs,
analysis.mjs).

A path's drive letter is capitalised in the one spelling (paths.mjs), so a
drive's case never decides a path.

New oracle: gap-report-path-spelling (a metamorphic check). Law 1: the
instrumenter gives the same mutant ids for a source under any spelling of
its path. Law 2: relativeWithin answers from the segments alone.

Evidence block
- Law: a path's separators and a drive letter's case do not change what the
  gap CLI decides (paths.mjs, Windows support, 2026-11-13).
- Reach: 200 generated histories (fixed seed 20261113 and random), over four
  module forms, drives in both cases, mixed separators, short and spaced
  names. Reach is not declared (states: []); the histories are not
  measured as reaching a state.
- RED: on the parent commit (72b9495), the Windows jobs of
  #58 failed: the config wrapper
  import (check.mjs), the copy map, the owner keys (owners.mjs), and the
  8.3 short names. On Linux the enumeration law does NOT reproduce the
  Windows failure: the instrumenter gave the same ids on the parent. The
  Windows failure is a platform path.relative difference, which Linux
  cannot produce. The RED for those classes is the Windows CI run.
- GREEN: the Windows jobs (see the PR). Local, on macOS: the new oracle 5
  of 5, the framework 114 of 114, the eslint plugin 7335 of 7335.
- Mutant: relativeWithin as it was before (raw string comparison) fails the
  relation checkpoint; dropping the drive capitalisation fails it too. Both
  run on the parent tree with the oracle and both fail (exit 1).
- Limits: no declared reach; Law 1 uses the forward-slash spelling as its
  reference, so it claims only that the spelling changes nothing; owners,
  realpath, and OS short names are judged by the Windows end-to-end run,
  not by this oracle.

Co-authored-by: Isaac <no-reply@databricks.com>
… witnesses

- P10: the Windows CLI runs assert the done line on both streams, and that
  it matches the exit code (scripts/windows-witness.mjs done).
- A package with no package.json is refused with exit 2 and a done line
  that names it (Windows witness).
- One early stop: SIGINT once the CLI prints its first line; the run must
  end with the stop's done line on both streams, or with no output (#57).
- Per-shell replay (framework, accepted by the coordinator): a failing
  property's PowerShell and cmd lines each reproduce the failure in their
  own shell. The POSIX line is run in PowerShell and must not reproduce (the
  RED). A run that printed only the POSIX line fails here (the mutant).
- The tsc link lookup in package.test.ts reads npm's Windows shim, not a
  symlink.
- The eslint plugin suite runs even when the framework suite fails.
- Job timeouts are 20 minutes, as high backstops (2026-11-12).

Co-authored-by: Isaac <no-reply@databricks.com>
…ch packages have a manifest

Windows CI failed the classify oracle's baseline law: the CLI prints a
PowerShell and a cmd replay line there, and the law read only the POSIX
`replay:` line (Difference: "the replay of tests/f0.test.ts is undefined").
The law is unchanged: each replay line the platform prints must read as
`vitest run <file> -t <pattern>` in its own shell, and the owed test is the
one it selects. On win32 the law owes both per-shell lines; elsewhere the
POSIX line (replayLinesOf, powerShellWords, cmdWords).

The static oracle's scratch packages had no package.json, which the CLI now
refuses (args.mjs). Each fixture now writes a minimal manifest; its content
and its histories are unchanged.

Evidence block
- Law: the replay line of each shell reads as the owed command (Law 9,
  baseline; the CLI's replay lines, stream.mjs).
- Reach: the existing classify histories (276 tests); no new histories.
- RED: Windows run 43478073715, classify shard 3 (baseline law, 11
  violations) and the static shard 1 refusal (the missing manifest).
- GREEN: local POSIX classify 276 of 276. The win32 branch runs in the
  Windows job (see the PR).
- Mutant: not run; the win32 branch is exercised only by the Windows job.
- Limits: the win32 branch is checked on Windows only, not by the oracle's
  own generated histories.

Co-authored-by: Isaac <no-reply@databricks.com>
… shipped citations

Run 43483101749 (Windows, the first with the witnesses) showed:
- The CLI printed `report <pkg>\out\summary.md` and `tests\a.test.ts` in the
  done line and in the heartbeat. Report paths and display paths are now
  forward-slash (posix, check.mjs, ending.mjs), as the register's keys rule
  requires; the file system still gets native paths.
- The classify oracle's cmd reader rejected `\"` inside a double-quoted
  argument, which Node's argument parser reads as a quote. It now reads it so.
- The static and classify oracles' second scratch package had no manifest.
- Shipped citations joined paths with backslashes, and npm names files with
  forward slashes. The comparison now uses forward slashes.
- The refusal witness searches both streams (a refusal prints to stderr).
- The static and fixed-seed e2e took 3 to 6 times their Linux time on
  Windows, and the Linux shards hit the limit. Windows runs six shards of each
  (pr-shards.mjs `oracle-gaps-static-windows`, `oracle-gaps-fixed-seed-windows`,
  checked by `pr-shards.mjs check`: each test in exactly one shard). The
  classify, probe-form, mutant-validity, and path-spelling oracles run in
  their own job.

Evidence block
- Law: report and display paths are forward-slash; a cmd line reads its
  quoted quotes as Node does (register: deterministic replay; the CLI's
  keys rule).
- Reach: the existing e2e and static histories, unchanged.
- RED: run 43483101749, which printed backslash report paths and failed
  classify on `\"`.
- GREEN: pending the next Windows run; local POSIX suites pass (classify 276,
  shipped citations 2).
- Mutant: not run for this commit.
- Limits: the Windows e2e and static shard timings are measured on the next
  run before the budget claim (P12) is made.

Co-authored-by: Isaac <no-reply@databricks.com>
…and its models

Run 43493431349 (Windows) failed the static and e2e oracles on report paths:
the done line names its report in forward slashes (the register's Windows
paths rule), but the model built the expected line from the native output
directory, and the declared oracle files were keyed by native relative
paths (`tests\a.test.ts`), so a heartbeat's file was not an owner.

- analysis.mjs, check.mjs: declared oracle files and copies are keyed by
  their forward-slash relative path (relativeWithin).
- gap-report-model-oracle.mjs: the model's expected done line is
  forward-slash (inline, the model does not import production).
- shipped-citations.test.js: the rejection test's strings are forward-slash.

Evidence block
- Law: keys and report paths use forward slashes on every OS (register,
  Windows paths, #58); filesystem calls get native paths.
- Reach: the existing static and e2e histories; no new histories.
- RED: run 43493431349: static 40 refusal-ending violations, e2e 17 baseline
  lead, 12 report-shaped ending, 4 streaming, 3 greppable stream.
- GREEN: pending the next Windows run. Local POSIX: shipped citations 2 of 2,
  CLI lints clean; the Linux keys are unchanged.
- Mutant: not run.
- Limits: the Windows e2e and static timings are measured on the next run.

Co-authored-by: Isaac <no-reply@databricks.com>
The early-stop step failed on Windows (SIGINT ends the process through
TerminateProcess, so the CLI's stop handler never runs; the run ended with
a null exit code after its done line), which skipped the replay witness
behind it. The replay witness now runs regardless, so each witness reports.

Co-authored-by: Isaac <no-reply@databricks.com>
The replay witness found no per-shell lines in the fixture's failing output.
This prints the first lines of that output in the same step, so the next run
shows what vitest printed. Diagnostic, to be removed with the witness fix.

Co-authored-by: Isaac <no-reply@databricks.com>
The replay fixture failed to load (TypeError reading fixedSeeds[0]), so the
witness saw no failure. It now declares fixedSeeds: [1].

Co-authored-by: Isaac <no-reply@databricks.com>
@KyleAMathews KyleAMathews changed the title ci: add a non-blocking Windows job for the oracle framework and gap CLI fix(windows): Windows CI for the oracle framework and gap CLI, and the path rule Nov 13, 2026
KyleAMathews and others added 5 commits November 13, 2026 14:40
… forward-slash done lines

- Stop (#57, all-or-nothing) on the unsupervised win32 path: a stop of a run
  that has started now writes its `oracle-gaps: done stopped (<signal>)` line
  on both streams and exits 128 + signal, as the supervisor does. A stop
  before the run starts still prints nothing (index.mjs, runStarted).
- Test-only stop hook: when the file ORACLE_GAPS_TEST_STOP names appears, the
  CLI takes the same stop as a SIGINT (index.mjs). The Windows stop witness
  uses it (a non-console parent cannot deliver Ctrl+C there; child.kill on
  win32 is TerminateProcess, which is a SIGKILL-like limit, so no line is owed).
- Static oracle: the `unknown` long-argument case uses 30,000 characters on
  win32. Windows caps a command line at 32,767 characters; a longer one never
  starts (status null). Narrowing, recorded in the PR: the POSIX runs keep
  100,000.
- e2e and static model: the expected done line's report path is forward-slash
  (inline in the model; the e2e corruption check likewise).
- The diagnostic Get-Content line is removed.

Evidence block
- Law: the all-or-nothing stop law (#57) on every platform; keys and report
  paths forward-slash (register: Windows paths; stop window on every platform).
- Reach: the existing static and e2e histories; the stop witness is one run.
- RED: run 43498457502, stop witness `stop was not all-or-nothing (signal
  SIGINT, exit null)`; static `with unknown arguments, the refusal exited null`;
  e2e `the last stdout line is ... report D:/...`, not `...\out\summary.md`.
- GREEN: pending the next Windows run. Local: the CLI lints and loads; the
  stop witness is queued on the e2e lock for a fixture run.
- Mutant: pending (the replay witness, on a throwaway branch).
- Limits: OS delivery of Ctrl+C is not exercised on Windows; TerminateProcess
  is treated like SIGKILL; the win32 argv cap narrows the long-argument case.

Co-authored-by: Isaac <no-reply@databricks.com>
…et, and logs

The default output directory is under the OS temporary directory, which on
windows-latest is `C:\Users\RUNNER~1\...` (an 8.3 short name). The model's
expected done line names the package by its real path, so the report path
never matched (e2e: `the last stdout line is ... report C:/Users/RUNNER~1/...`).
The temporary directory is now taken by its real path (realPathOf) for the
state directory, the socket, and the error log.

Evidence block
- Law: keys and report paths use one spelling; a real path on both sides
  (register: Windows paths; the realpath rule).
- Reach: the existing e2e histories (the done-line law).
- RED: e2e run 43515364499, done line with RUNNER~1 vs the package path.
- GREEN: pending the next Windows run.
- Mutant: pending; the replay witness mutant runs on the throwaway PR.
- Limits: the stdout gap-count mismatch (`2 gap lines for 0 gaps`) and the
  cold internal error in the incremental law are not yet explained.

Co-authored-by: Isaac <no-reply@databricks.com>
… real path

The e2e oracle realpaths the OS temporary directory with the JavaScript
realpath, which keeps the 8.3 name (C:\Users\RUNNER~1). The CLI prints the
native real path, so the expected report line never matched. Use
realpathSync.native, as the CLI does.

Evidence block
- Law: one real path on both sides (the realpath rule; Windows paths).
- Reach: the existing e2e histories.
- RED: run 43515364499 and ee1a5fd: the done line names RUNNER~1.
- GREEN: pending the next Windows run.
- Limits: the static `output namespace` violations (82 in the last run) are
  not yet traced.

Co-authored-by: Isaac <no-reply@databricks.com>
…es; fix the tsc lookup type

- Blocking now: the Windows unit suites, the classify, probe-form,
  mutant-validity, and path-spelling job, and the gap CLI fixture job with
  its witnesses (done line, refusal, stop, replay). Their continue-on-error
  is removed.
- Non-blocking, stated in the workflow: the Windows static and e2e jobs,
  which fail on Windows (tracked in the follow-up PR's body by class).
- Linux `Test` failed the typecheck on package.test.ts (the tsc lookup's
  optional capture). Fixed; tsc --noEmit passes locally.

Co-authored-by: Isaac <no-reply@databricks.com>
KyleAMathews and others added 2 commits November 13, 2026 17:16
…d review items F1-F8

Review of #58 at ebc39e6 (NOT READY). This commit fixes:

- F1 (stop never stops): the witness's stop file is absolute (the CLI's cwd is
  the package), a stop requires the stopped line on both streams with exit 130,
  and the stop lands 400 ms after the run starts (the fixture's output is written
  in one burst near its end, so the first output line is no clock).
- F2/F3 (replay quoting): PowerShell reads U+2018 to U+201B as quotes, so every
  such character is doubled inside single quotes. cmd toggles quoting on every
  `"` and expands `%`; a name with either has no cmd form, and its cmd line
  says `use the PowerShell line for this name` (stream.mjs, src/oracle-property.ts).
  The classify oracle reads each shell's line by that shell's grammar (the
  PowerShell quote set; cmd's quote toggling, `^`, and `%`), checks the win32
  printer on every host, and generates adversarial names (curly quotes,
  `& | < > ( ) ^ % !`, quotes, backslashes), drawn as the last field of the test
  record (the fixed seeds' later draws shift; recorded here).
- F(f) (POSIX hook): the test-only stop hook lives in the supervisor and goes
  through its stop, which forwards to the child; a hooked stop gives
  `done stopped (SIGINT)`, exit 130 (local run: outcome (a)). Unsupervised runs
  keep the hook in the process.
- F5: posix() acts only on win32; on POSIX a backslash is a name's character.
- F6: check.mjs realpath of workspace links, report.mjs results path, and
  ending.mjs error log path are forward-slash and use the native real path.
- F7: the blocking Windows jobs are in preview's needs.
- F8: the non-blocking jobs point at #72.
- The Windows replay witness runs each printed PowerShell line and its cmd line,
  for two fixtures with hostile names (curly quote and metacharacters; a double
  quote and `%`).

Evidence block
- Law: the printed replay line replays in the shell it names (register:
  deterministic replay across shells; each printed line must replay on Windows);
  a hooked stop is a stopped line with exit 130 (register: stop window on every
  platform).
- Reach: the classify oracle's 276 generated histories (new adversarial name
  dimension, drawn last); the Windows replay fixtures; one stop per run.
- RED: the parent printer (ebc39e6, with only the platform parameter added) fails
  the new classify oracle on two names: `"vitest run tests/f0.test.ts -t '^’ t0$'"`
  (the PowerShell line ends its quote at U+2019) and the cmd line for `q"t`
  (`which the shell does not read as plain words`). Run locally, exit 1.
- GREEN: classify 276/276 on Linux (current code); POSIX stop witness outcome (a),
  exit 130 (local, under the e2e lock). Windows: pending CI on this head.
- Mutant: the parent printer is the mutant (the curly-quote and cmd forms before
  this commit); the RED run above is its rejection.
- Limits:
  - the stop timing (400 ms after spawn) is an assumption about the fixture's
    length; a run that ends first is reported as a failure, not passed;
  - cmd's `!` is literal (delayed expansion off), an assumption;
  - the classify fixed seeds' later draws shift (the new field is drawn last);
  - the win32 argv cap, the pipe name's machine scope, the POSIX state paths
    moving to the temporary directory's real path (an older daemon is found only
    after its idle timeout), and the unsupervised win32 process-tree exemption
    (#74) are recorded in the PR body.

Co-authored-by: Isaac <no-reply@databricks.com>
… drives only on win32

The Linux run of 50b4ab5 failed gap-report-path-spelling: posix() acts only on
win32 (review F5), so on POSIX a backslash is a name's character and a drive
letter's case is a different name. The oracle now generates backslash joints and
mixed drive letters only on win32; on POSIX it generates `/` joints and `C`.
This narrows the law on POSIX (recorded): the POSIX law is the forward-slash
spelling, and the separator and drive-case laws are judged on win32 (the
Windows classify job runs the oracle there).

Evidence block
- Law: a path's separators and a drive's case change nothing the gap CLI decides
  on win32; on POSIX they are name characters (paths.mjs, F5).
- Reach: the same 200 histories, with the separator and drive alphabets by platform.
- RED: Linux shard 3 of 50b4ab5: "observed value differs" on the path-spelling
  oracle (2 of 5 tests).
- GREEN: local POSIX 5/5.
- Mutant: the win32 mutants run in the Windows classify job; not re-run on POSIX.
- Limits: on POSIX the separator and drive laws are not generated.

Co-authored-by: Isaac <no-reply@databricks.com>
KyleAMathews and others added 7 commits November 13, 2026 18:05
…e POSIX F5 witness

Coordinator rulings, applied:
1. Stop trigger: an event, not a clock. The witness writes the stop file on the
   CLI's first stderr line. Measured (2026-11-14): on a pipe the CLI streams its
   progress on stderr and prints the done summary (stdout) only at the end, so
   stdout is no start marker. No stream.log exists on this branch; the stderr
   line is the event. The 400 ms timer is gone.
2. Classify generator: the hostile names are derived from the test's own fields
   (HOSTILE[(ms+ti) % 7] for one test in four), not drawn. A drawn field would
   shift every later draw of the fixed seeds. Proof: `git diff origin/main` on the
   classify oracle changes no `fc.` line (zero), so the generator is unchanged.
3. Path spelling on POSIX: the oracle generates backslash joints and `x:` drives
   on every platform. The model splits the spelled strings per platform (win32:
   both separators, case-insensitive drive; POSIX: `/` only, a backslash is a
   name's character). On POSIX a disk witness creates the backslash name and
   asserts it exists, realPathOf keeps it native, and posix() leaves it unchanged
   (F5). This removes the earlier POSIX narrowing.

Evidence block
- Law: the stop is delivered at a run event and ends stopped (register: stop
  window on every platform); a backslash name on POSIX is kept native (review F5).
- Reach: the path-spelling oracle's 200 histories, now with backslash and `x:`
  names on POSIX (disk-backed); the classify oracle's existing histories, with
  hostile names on one test in four.
- RED: ebc39e6 with this oracle: 2 of 5 tests fail, "the observed value differs
  from the owed value" (the relation and disk checks).
- GREEN: POSIX local 5/5 (path-spelling); stop witness local POSIX outcome (a),
  exit 130 (event trigger). Windows: pending CI on this head.
- Mutant: the parent (ebc39e6) is the mutant for F5 (posix() rewrites backslashes
  on POSIX); its RED is above.
- Limits: the stdout summary arrives only at the end on pipes (a finding, not a
  fix here); the stop trigger assumes the CLI prints a stderr line before its
  work completes (measured on the fixture only).

Co-authored-by: Isaac <no-reply@databricks.com>
The derived hostile names reached constructed tests too (ms 0 at index 0), which
broke the name-relationship reach of two constructed histories ("a failing
baseline test whose name another test's contains" and "... ends another
test's"). A hostile name now applies to generated tests only (ms >= 1).

Evidence block
- Law: the constructed histories reach their declared states (the oracle's own
  reach rule).
- RED: de8a373 run: "constructed history ... did not enter a baseline test whose
  name another test's contains" (Linux shard 3 and the Windows classify job).
- GREEN: local classify 276/276.
- Mutant: not run.
- Limits: as recorded in the previous commit.

Co-authored-by: Isaac <no-reply@databricks.com>
…prefix rule, witness

Round-2 review of #58 (NOT READY). Items addressed:
1. Rerun (cmd) fell back on win32 every time: an absent command was passed as
   undefined and read as "no cmd form". An absent command is now nothing; only a
   value that cannot be represented has no form (oracle-property.ts commandOf).
   The witness runs the Rerun lines (as `vitest run` plus the line) in pwsh,
   Windows PowerShell 5.1, and cmd.
2. `!` is in the cmd no-form set (framework and printer; DelayedExpansion expands
   it silently). The classify oracle's fallback test follows.
3. The path-spelling generator's original drive and joint domains are restored
   (the win32 form at b904d57); the POSIX spelling's backslash names and `x:`
   drives are an appended `wide` record, used on POSIX only.
4. The witness header, the stop failure text, and the replay comments describe
   the code (event trigger on the first stderr line; the no-form set).
5. isOutside, the owners' node_modules split, and the capture-setup machinery
   regex split on `\` only on win32; on POSIX a backslash is a name's character.
6. (see 4)
7. Windows PowerShell 5.1 (`powershell.exe`) runs each PowerShell line, as well
   as pwsh.
8. configureOracles rejects an envPrefix that is not `[A-Z][A-Z0-9_]*`, with a
   message (the prefix is printed in replay lines). The unit test follows.

Evidence block
- Law: the printed command replays in the shell it names, or says it has no form
  (register: deterministic replay across shells); a Rerun line replays too;
  `!` is a no-form character (coordinator ruling); a POSIX backslash is a name's
  character (register: Windows paths, as amended).
- Reach: the same histories (the win32 domains are unchanged; POSIX uses the
  appended wide record).
- RED (item 1): round-2 review: plain Rerun lines printed "use the PowerShell line"
  on win32.
- GREEN: classify 276/276, path-spelling 5/5, framework 114/114 (locally, POSIX);
  Windows: CI on this head.
- Mutant: the round-2 Rerun behaviour is the mutant (rerunOf passed an absent
  command as no form).
- Limits: U+2019 is not reached by the seeds in the path-spelling or replay
  histories; the hostile names are exercised by the witness's fixture names.

Co-authored-by: Isaac <no-reply@databricks.com>
…an argument

Run 43548823073 (head 2b7b7f3): the Windows CLI job failed on Windows PowerShell 5.1
("Replay 3 did not reproduce in powershell", a parse exception on the fixture
with a double-quoted name). The witness passed the line as a -Command argument,
so Node's argument quoting turned the double quote into \" and 5.1 does not read
that as an escape. A typed line never passes through an argv: the witness now
pipes the line to `-Command -` on stdin, for pwsh and powershell.exe alike.

Evidence block
- Law: each printed line replays in the shell it names, as a user types it (the
  register's per-shell rule).
- RED: run 43548823073, witness step: "Replay 3 did not reproduce in powershell"
  (the Windows PowerShell 5.1 parse exception).
- GREEN: pending the next Windows run.
- Mutant: the argument passing is the mutant (the run above).
- Limits: a cmd line is still passed verbatim as an argument (cmd has no stdin
  command mode here).

Co-authored-by: Isaac <no-reply@databricks.com>
…ne that does not reproduce

Run 43551132190 (abc8b45): "Replay 3 did not reproduce in powershell" with no
reason. The failure now carries the shell's exit code and output, so the Windows
PowerShell 5.1 error for the double-quoted name is visible. Diagnostic; the
witness's pass and fail rules are unchanged.

Co-authored-by: Isaac <no-reply@databricks.com>
… (option c)

PowerShell 5.1 passes an embedded double quote in a native .cmd argument
wrongly (run 43553461458: a `"`-named fixture selected no test, exit 0). The
coordinator's ruling (option c): `-t` is a coarse regular-expression filter, and
the exact test is carried by ORACLE_UNIT where a line sets it.

- The `-t` pattern (CLI baseline and framework Rerun) replaces each character a
  shell reads unsafely (`"`, `%`, `!`, the curly quotes) with `.`: still anchored,
  only slightly broader.
- Framework environment values: PowerShell (5.1 and 7) doubles the single and
  curly quotes, which works for any name; cmd's `set "NAME=value"` tolerates a
  double quote, and `%` and `!` have no cmd form (environment values only).
- Classify oracle: a CLI line has no environment values, so a cmd fallback line
  is a breach; the -t argument must carry no shell-hostile character.
- Witness: each PowerShell Replay line's ORACLE_UNIT and ORACLE_PROPERTY decode
  to the printed text (round-trip), in addition to the reproduction in pwsh,
  Windows PowerShell 5.1, and cmd.

Evidence block
- Law: a printed command replays exactly the unit it names, in each shell
  (register: deterministic replay across shells; the coordinator's option c).
- Reach: the classify oracle's 276 histories (the adversarial names, derived);
  the Windows fixtures (`’`, `"`, `%`).
- RED: run 43553461458: "Replay 3 did not reproduce in powershell", exit 0, PowerShell
  5.1 with an embedded double quote in the -t argument.
- GREEN: classify 276/276 and framework 114/114 locally (POSIX); the Windows
  witness runs on this head.
- Mutant: the pre-fix pattern (a raw double quote in -t) is the mutant; the RED
  above is its rejection.
- Limits: the -t pattern is slightly broader for names with a hostile character
  (the wildcard may select a test whose name differs in that position, which the
  classify oracle's names cannot produce).

Co-authored-by: Isaac <no-reply@databricks.com>
…for a line that does not reproduce"

This reverts commit 69c82eb.
KyleAMathews and others added 4 commits November 13, 2026 22:23
… fixtures (round-3 review)

- F1: a cmd environment value containing `"`, `%`, or `!` has no form (the
  register's rule); `set "VAR=value" &&` is only emitted for a plain value
  (oracle-property.ts commandOf). Fixtures: one with a curly-quote property and
  no `"%!` (a cmd set line runs); one with a single `"` in its property (its cmd
  line points to PowerShell).
- F2: the PowerShell decoder's offset is the value's own position, and decoded
  values are compared exactly with a failing unit's property and unit, as vitest
  prints them (`FAIL <file> > <property> > <unit>`). cmd `set` lines decode too
  and must agree with the PowerShell line.
- F3 (partial): Rerun lines carry no ORACLE_UNIT: the framework reads ORACLE_UNIT
  only for a random unit during a path replay, so a fixed-seed Rerun cannot be
  selected exactly. Reported to the coordinator.
- F6: the path-spelling comment states what it means (no history to keep).
- F7: the classify readers reject `!` and judge `set … &&` prefixes; the fallback
  is allowed wherever the printer uses it (a file path with a hostile character).
- F9: control characters in rerunPatternOf are escaped as stream.mjs does (by
  code point, not a control-character regex).
- The witness fails when a failing unit prints no per-shell line (FAIL lines are
  counted per unit).

Evidence block
- Law: a printed command replays the failing unit it names, in each shell
  (register: deterministic replay across shells; the set rule).
- Reach: the classify oracle's 276 histories; the Windows fixtures.
- RED: run 43555531142 and the coordinator's round-3 review at ae44184 (a `"` in a
  set value broke `&&`).
- GREEN: classify 276/276, framework 114/114, locally (POSIX). Windows: this head.
- Mutant: the pre-fix env rule (a `"` in a set value) is the mutant.
- Limits: Rerun lines are not exact (see F3).

Co-authored-by: Isaac <no-reply@databricks.com>
…uns on the package's PATH

Run 43561333340 (9698922), Windows CLI job: "2 random units failed, but 4 Replay
lines printed" (vitest repeats a failing unit's error text, so its replay lines
repeat), and every line failed with "'vitest' is not recognized" (the rewritten
runIn dropped the PATH that adds the package's node_modules/.bin).

- Each distinct printed line counts once, in first-occurrence order.
- Every shell runs with the package's binaries on PATH.

Evidence block
- Law: a printed command replays in each shell it names (the register's per-shell
  rule); each failing unit prints one line (witness rule).
- RED: run 43561333340, the witness: "4 Replay lines printed" for 2 random units;
  "'vitest' is not recognized".
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: as in the previous commit (Rerun lines are not exact).

Co-authored-by: Isaac <no-reply@databricks.com>
… line and checks coverage

Run 43563021693 (257a5b0): "2 random units failed, but 4 Replay lines printed"
and "Replay 4 has no cmd line": a failing fixed unit prints its replay under the
random unit's name, so one failing unit can have more than one replay line, and
index pairing breaks. A random unit's violation also prints its replay under the
Rerun label, so a Rerun line can carry ORACLE_ variables, and running it with
`vitest run` in front broke it.

- Each distinct PowerShell line pairs with the cmd line printed after it.
- A line that carries ORACLE_ variables is a replay and runs as printed; a bare
  -t line is a rerun and runs as `vitest run` plus its arguments.
- Coverage: every failing unit is matched by a replay whose ORACLE_PROPERTY and
  ORACLE_UNIT decode to its names (a fixed unit by the random unit it replays).

Evidence block
- Law: every failing unit prints a replay that names it exactly, and each printed
  command replays in each shell it names (register: deterministic replay; the
  witness rule).
- RED: run 43563021693: "2 random units failed, but 4 Replay lines printed";
  "Replay 4 has no cmd line"; "Rerun 2 did not reproduce in cmd".
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: a bare Rerun line is not exact (see F3).

Co-authored-by: Isaac <no-reply@databricks.com>
…ewrite removed

Run 0c42c33 (the Windows CLI job): "ReferenceError: decodePs is not defined". The
pairing rewrite replaced the block that held the FAIL map, the PowerShell and cmd
decoders, and the no-form constant. They are restored, and a local smoke run of
the replay branch on a fabricated output reaches the report (pwsh is absent on
this Mac, so its runs fail as expected; no reference error).

Evidence block
- Law: the replay witness reports a failing unit's printed commands (witness rule).
- RED: run 0c42c33: ReferenceError in the replay step.
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: as before.

Co-authored-by: Isaac <no-reply@databricks.com>
KyleAMathews and others added 4 commits November 14, 2026 00:07
… (F3 ruling b)

The coordinator's ruling: Rerun lines stay coarse -t filters (a sibling whose name
the anchored pattern matches also runs). The witness now counts a Rerun line only
when the failing fixed unit whose exact name it selects shows its own FAIL line in
its output, so a sibling's failure cannot satisfy it. An exact selector is tracked
in #78; Replay lines select exactly, through ORACLE_PROPERTY and ORACLE_UNIT.

Evidence block
- Law: a Rerun line runs the failing unit it names, and only it counts (register
  amendment: Replay lines select exactly; Rerun lines are anchored, coarse filters).
- Reach: the Windows fixtures (the `Q"1` unit has no Rerun line in CI; the sibling
  case is the Limit's example).
- RED: none in CI yet; the sibling case is not exercised by the fixtures.
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: a sibling case is not in the CI fixtures (recorded in the PR body).

Co-authored-by: Isaac <no-reply@databricks.com>
… 1: <name>`)

Run 43569602268 (bd208ac): "Rerun 1 selects no failing fixed unit" for both
fixtures. The FAIL regex expected `fixed seed: ` with no number, but vitest prints
`fixed seed 1: <name>`, so no fixed unit was recorded. (The earlier fix attempt
did not apply; this commit applies it and checks the match.)

Evidence block
- Law: a Rerun line counts only for the failing fixed unit whose exact name it
  selects (witness rule; register: Rerun lines are anchored coarse filters).
- RED: run 43569602268: "Rerun 1 selects no failing fixed unit".
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: as recorded in the PR body (sibling case, #78).

Co-authored-by: Isaac <no-reply@databricks.com>
Run 43571581118 (3b97795): each Rerun line reproduced (exit 1, "Failed Tests 1"),
but the check that the failing unit's exact name appears in its output failed:
vitest colors the output, so the name is split by color codes. The witness now
strips the color codes before it matches a unit's name.

Evidence block
- Law: a Rerun line counts for the failing fixed unit whose exact name it selects
  and whose FAIL line its output shows (witness rule).
- RED: run 43571581118: "Rerun 1 did not reproduce in pwsh (exit 1 ... Failed
  Tests 1)" with the name check failing.
- GREEN: pending the next Windows run.
- Mutant: not run.
- Limits: as recorded in the PR body (sibling case, #78).

Co-authored-by: Isaac <no-reply@databricks.com>
… control-name oracle case (F3, F9, L2, L3)

- F3: a Rerun line counts only when its target's whole FAIL line appears,
  anchored to the end of the line, after the color codes are removed. `generated2`
  does not satisfy `generated`. The comment now says so.
- F9: the classify oracle's hostile names include a control character (U+0001).
  The printed `-t` pattern escapes it as `\u0001` (stream.mjs escapeControls).
  The register says controls become `.`; the code escapes them, and the code is
  right (the coordinator's correction).
- L2: the CI step prints replay-out.txt before the witness reads it.
- L3: a third fixture, `fixture 100% done!`, witnesses the cmd env no-form branch.

Evidence block
- Law: a printed pattern carries no raw control character (the printer's escape
  rule); a Rerun line counts only for its exact target (witness rule).
- RED (F9): dropping escapeControls from the CLI printer fails 4 classify tests
  ("the stdout has a line that is not a line of the stream"), exit 1, locally.
- GREEN (F9): classify 276/276 with the U+0001 name, locally (POSIX).
- GREEN (F3): the exact-match regex accepts `generated` and rejects `generated2`
  (checked locally); Windows: the next run.
- Mutant: dropping escapeControls (above).
- Limits: the framework's own Rerun escaping has no oracle; the Windows fixtures are
  the only witness for it (L6 and L1 are filed).

Co-authored-by: Isaac <no-reply@databricks.com>
@KyleAMathews
KyleAMathews merged commit 35422e3 into main Nov 14, 2026
34 of 46 checks passed
@KyleAMathews
KyleAMathews deleted the ci/windows branch November 14, 2026 08:59
KyleAMathews added a commit that referenced this pull request Nov 14, 2026
Both sides kept: #58's path rule (isAbsolute for module ids, posix keys
only on win32) and #55's fs inputs. The fs recorder now keys a read by
the same rule (paths.mjs, which the copied capture setup cannot import):
forward slashes and a capital drive letter on win32, the path as it is on
POSIX, and the native path for the file system. #55's fixed-seed units
take places in the Windows e2e shards (pr-shards.mjs).

Co-authored-by: Isaac <no-reply@databricks.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant