feat(phase 2.2 F1): Windows soak — both strategies pass, 0 torn reads #30

Merged
deco merged 1 commit from feat/phase-2.2-f1-windows-soak into main 2026-05-22 04:42:23 +03:00
Owner

Summary

Closes the Phase 2.2 F1 follow-up from PR #24. Re-ran the atomic-write soak on the Windows production OBS host (bridge) via Tailscale shell. Both strategies survive 30 minutes on NTFS with zero observable torn reads:

Strategy Duration Writes Reads Verdict
write (fs.writeFileSync) 1800 s 1782 58,207 PASS (0 torn)
rename (fs.writeFileSync + fs.renameSync) 1800 s 1782 58,462 PASS (0 torn)

Strategy A (rename) — already shipped via PR #24 — is confirmed safe on the real production target. Both strategies behaved identically on the soak: zero empty, zero enoent, zero mismatch, zero read_error across ~116k total reads.

Port: TS → MJS

Same algorithm in plain ESM so hosts without tsx (the Windows OBS host, etc) can run directly with node:

  • scripts/atomicWriteSoak.mjs — CLI entry
  • scripts/atomicWriteSoak/strategies.mjs
  • scripts/atomicWriteSoak/classifyRead.mjs
  • scripts/atomicWriteSoak/runSoak.mjs
  • scripts/atomicWriteSoak/reporter.mjs
  • package.json — add npm run soak:atomic-write:mjs

The .mjs files are a 1:1 mirror of the existing .ts implementations. Comments on each .mjs file note: if the algorithm changes here, update the .ts side too.

Observations

  • Reader cadence on Windows is ~32 Hz vs Mac ~53 Hz. Default node setInterval scheduling is more lossy on Windows, but the read count remains plenty to surface any tearing class that exists.
  • The soak target on bridge was a tmp file in `C:\Users\derek\sat-phase42\` — NOT a real switcher .txt — so production state was never affected.

Plan housekeeping (also in this PR)

.omc/plans/stream-a-thon-2026-06-13.md gains a new Pre-release housekeeping section sequencing what happens between this PR's merge and the public GitHub release:

  • H1 — rename project to `cuesheet` (npm name, README, AGENTS.md cross-refs, Gitea repo rename)
  • H2 — audit + rewrite git history with `git-filter-repo` to a canonical `Derek Slenk derek.slenk@gmail.com` identity (today the history contains a mix of 4 emails across deco / derekslenk identities; the user keeps them un-mixed on public repos)
  • H3 — force-push rewritten history to the already-existing private `github.com/derekslenk/cuesheet` repo, then flip visibility public

Not June 13 event scope — pre-release housekeeping that runs after this PR lands and before the canonical name + identity are published.

Test plan

  • 220/220 jest tests pass
  • `tsc --noEmit` clean
  • `npm run audit:sqlite-opens` clean
  • Mac smoke (3s per strategy) before the real run — passed
  • Bridge smoke (3s rename) before the 60-min sequential run — passed
  • Bridge soak (30 min × 2 = 60 min wall, sequential) — both strategies passed with 0 torn reads
  • Optional: Phase 4.1 dress rehearsal will exercise the actual setActive write path under encoder load — any regression would surface there
## Summary Closes the **Phase 2.2 F1** follow-up from PR #24. Re-ran the atomic-write soak on the Windows production OBS host (bridge) via Tailscale shell. Both strategies survive 30 minutes on NTFS with zero observable torn reads: | Strategy | Duration | Writes | Reads | Verdict | |---|---|---|---|---| | `write` (`fs.writeFileSync`) | 1800 s | 1782 | 58,207 | **PASS** (0 torn) | | `rename` (`fs.writeFileSync` + `fs.renameSync`) | 1800 s | 1782 | 58,462 | **PASS** (0 torn) | Strategy A (rename) — already shipped via PR #24 — is **confirmed safe on the real production target**. Both strategies behaved identically on the soak: zero `empty`, zero `enoent`, zero `mismatch`, zero `read_error` across ~116k total reads. ## Port: TS → MJS Same algorithm in plain ESM so hosts without tsx (the Windows OBS host, etc) can run directly with `node`: - `scripts/atomicWriteSoak.mjs` — CLI entry - `scripts/atomicWriteSoak/strategies.mjs` - `scripts/atomicWriteSoak/classifyRead.mjs` - `scripts/atomicWriteSoak/runSoak.mjs` - `scripts/atomicWriteSoak/reporter.mjs` - `package.json` — add `npm run soak:atomic-write:mjs` The .mjs files are a 1:1 mirror of the existing .ts implementations. Comments on each .mjs file note: if the algorithm changes here, update the .ts side too. ## Observations - Reader cadence on Windows is ~32 Hz vs Mac ~53 Hz. Default node `setInterval` scheduling is more lossy on Windows, but the read count remains plenty to surface any tearing class that exists. - The soak target on bridge was a tmp file in \`C:\\Users\\derek\\sat-phase42\\\` — NOT a real switcher .txt — so production state was never affected. ## Plan housekeeping (also in this PR) `.omc/plans/stream-a-thon-2026-06-13.md` gains a new **Pre-release housekeeping** section sequencing what happens between this PR's merge and the public GitHub release: - **H1** — rename project to \`cuesheet\` (npm name, README, AGENTS.md cross-refs, Gitea repo rename) - **H2** — audit + rewrite git history with \`git-filter-repo\` to a canonical \`Derek Slenk <derek.slenk@gmail.com>\` identity (today the history contains a mix of 4 emails across deco / derekslenk identities; the user keeps them un-mixed on public repos) - **H3** — force-push rewritten history to the already-existing private \`github.com/derekslenk/cuesheet\` repo, then flip visibility public Not June 13 event scope — pre-release housekeeping that runs after this PR lands and before the canonical name + identity are published. ## Test plan - [x] 220/220 jest tests pass - [x] \`tsc --noEmit\` clean - [x] \`npm run audit:sqlite-opens\` clean - [x] Mac smoke (3s per strategy) before the real run — passed - [x] Bridge smoke (3s rename) before the 60-min sequential run — passed - [x] **Bridge soak (30 min × 2 = 60 min wall, sequential)** — both strategies passed with 0 torn reads - [ ] Optional: Phase 4.1 dress rehearsal will exercise the actual setActive write path under encoder load — any regression would surface there
feat(phase 2.2 F1): Windows soak — both strategies pass, 0 torn reads / 116k+ reads
All checks were successful
Lint and Build / build (pull_request) Successful in 2m55s
f44bd31217
Closes the Phase 2.2 F1 follow-up from PR #24. Re-ran the atomic-write
soak on the Windows production OBS host (bridge) via Tailscale shell.
Both strategies survive 30 minutes on NTFS with zero observable torn
reads:

  write   1800 s  1782 writes  58 207 reads  PASS  (0 torn)
  rename  1800 s  1782 writes  58 462 reads  PASS  (0 torn)

Reader cadence dropped from ~53 Hz on Mac to ~32 Hz on Windows (default
node setInterval scheduling is more lossy on Windows), but the read
count is plenty to surface any tearing class that exists. Strategy A
(rename) — already shipped via PR #24 — is confirmed safe on the real
production target.

Port: scripts/atomicWriteSoak.{ts → mjs} + 4 modules. The .mjs entries
are a 1:1 ESM mirror of the TS soak so hosts without tsx (the Windows
OBS host) can run the same algorithm directly with `node`. Keep
behavior identical between the two; if the algorithm changes here,
update the .ts side too.

- scripts/atomicWriteSoak.mjs — CLI entry (ESM, runs with bare node)
- scripts/atomicWriteSoak/strategies.mjs
- scripts/atomicWriteSoak/classifyRead.mjs
- scripts/atomicWriteSoak/runSoak.mjs
- scripts/atomicWriteSoak/reporter.mjs
- package.json — add `npm run soak:atomic-write:mjs`
- docs/plugin-contract.md — Windows results subsection; F1 marked done
- docs/atomic-write-soak-win.{write,rename}.json — evidence artifacts

Plan housekeeping also folded into this PR (.omc/plans/stream-a-thon-2026-06-13.md):
adds a new "Pre-release housekeeping" section sequencing H1 (rename to
`cuesheet`), H2 (rewrite history to canonical identity via
git-filter-repo), H3 (force-push to existing private github.com/
derekslenk/cuesheet, flip visibility). These run between this PR's
merge and the public release; not part of June 13 event scope.

220/220 jest tests pass; type-check + audit:sqlite-opens clean.
deco merged commit 5edeb32cc3 into main 2026-05-22 04:42:23 +03:00
deco deleted branch feat/phase-2.2-f1-windows-soak 2026-05-22 04:42:24 +03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
deco/cuesheet!30
No description provided.