📝 DM2S-NX_v10_0_Checkpoint_2026-10-05.mdv4.5.1 · 2026-10-02

DM2S/NX v10.0 — Chapter 1 Checkpoint

Date: 2026-10-05, about 03:25 → 06:30 AEDT (written 11:57 AEDT) Session: v10.0 Chapter 1 — atomic store writes for the four in-place writers, manual update Participants: Andrew.human & Claude.ai Status: OPEN. Three of four writers delivered and tested in isolation; MiscIndexer.py must be redone against its current file. Nothing here has been deployed or run against the real DB.


1. Read this first — one thing must not be deployed

The MiscIndexer.py inside ISE_Atomic_Writers_v1.0.0.zip is built on a stale base. Do not deploy it.

Root cause on my side: I patched an uploaded file without first comparing its @version against the version the manual records for it. That check is now a proposed standing step (section 6).


2. What this session was about

Carry-over from the v9.9 closing checkpoint, item 10: convert the four scripts that still write their stores in place (IndexBuilder.py, MediaIndexer.py, MiscIndexer.py, orphan_check.py) to temp-file-then-rename. Reason (OVERSEER checkpoint 5.7): until that is done, a mirror, rsync or gzip during an index run can catch a half-written store, and the gated mirror can't be relied on.

Scope decision (Andrew): mirrorISE_Clone, mirrorISE_Dev and json_push_media_Clone_to_Live (which replaced json_push_audio_Clone_to_Live) are Andrew's to look after. Claude does not touch them. This removed v9.9 items 8 and 9 (gated mirror, ls diff) from this session.


3. Changes made (Problem & Resolution / Risk / Code Change)

3.1 Atomic store writes — IndexBuilder.py 7.4.3, MediaIndexer.py ISE v9.9.2, orphan_check.py 7.4.3

Problem & Resolution. Each script opened its store with open(path, "w") and dumped into it, so the real file is truncated and half-written for the duration of the dump. Fix: a helper, write_json_files_atomic(items, **dump_kwargs), copied inline into each script (no shared module, to avoid a new dependency across unrelated scripts). It writes every object to <path>.tmp, flushes and fsyncs, then renames all of them over their final names back to back with os.replace(). On any failure the .tmp files are removed and the live files are untouched. The old file's permissions are copied to the new one, and its owner too where permitted.

Risk Analysis.

Code Change. The write block in each script replaced by one helper call. orphan_check.py writes orphan_state.json with indent=2; MediaIndexer.py writes media_store.json with indent=4; IndexBuilder.py writes both stores with default json.dump settings. Python 3.6 compatible (Live runs 3.6 and 3.8).

3.2 IndexBuilder.py clean-ups (approved by Andrew: "fix all the anomalies")

3.3 Manual — ISE_Python_Scripts_Manual_v6.md (from v5)


4. Verification

Done:

Not done:


5. Findings that were not fixed

  1. MediaIndexer.py can wipe media_store.json. If the DB query fails, or pymysql is missing, fetch_media_from_db() prints the error and returns {}; a plain run then writes {} over the store. Reproduced in the sandbox (0 items after the run). The atomic write does not prevent it. In --single mode a corrupt existing store is treated as {}, so the rewrite would leave only that one attachment. A proposed fix (abort with exit code 1 and leave the store untouched) was not approved and is not in any delivered file.
  2. Unexplained file in the working folder. Near the end of the session the working folder contained patch_media2.py and a MediaIndexer.py marked ISE v9.9.3 implementing exactly that safeguard. Neither was created in this conversation, and I don't know their origin. I restored the approved v9.9.2 (verified byte-identical to v1.0.0) and left the v9.9.3 code out of every delivered zip. If it came from you or another session, say so; either way the safeguard stays unshipped until you approve it.
  3. MegaIndexer.sh passes --monitor to IndexBuilder.py, which has no argument parsing, so the flag is silently ignored. Harmless; untouched. MegaIndexer.sh runs Posts, PDF (--fast) and Text, but not MediaIndexer.py.
  4. PDFIndexer.py writes pdf_store.json but was not on the four-writer list and not examined. Unknown whether it is already atomic.
  5. Manual gaps: no section for IndexBuilder.py (despite the opening saying it covers every script); MediaProcessor.py still quoted as v9.18, unconfirmed.

6. Standing rules — confirmed this session, plus one proposal

Confirmed in use:

Proposed (not yet agreed): before patching any uploaded file, compare its @version with the version the manual (or checkpoint version map) records for it, and stop if they differ. This would have caught the stale MiscIndexer.py before it was patched. It costs one grep per file.


7. Deliverables

File State
ISE_Atomic_Writers_v1.0.0.zip IndexBuilder.py, MiscIndexer.py, MediaIndexer.py, orphan_check.py. Do not deploy its MiscIndexer.py. Other three fine
ISE_Atomic_Writers_v1.0.1.zip IndexBuilder.py 7.4.3, MediaIndexer.py ISE v9.9.2, orphan_check.py 7.4.3, ISE_Python_Scripts_Manual_v6.md. No MiscIndexer.py
DM2S-NX_v10_0_Checkpoint_2026-10-05.md This file

Module versions at close:

Module Version Note
IndexBuilder.py 7.4.3 delivered, not deployed
MediaIndexer.py ISE v9.9.2 delivered, not deployed
orphan_check.py 7.4.3 delivered, not deployed
MiscIndexer.py 7.5.0 (production, per manual) not converted; v1.0.0 copy is stale
ISE_Python_Scripts_Manual v6 (Master v6) delivered

Version map entries from the v9.9 close (search.py 7.6.0, PDFsearch.py 7.7.0, MiscSearch.py 7.6.0, MediaSearch.py 1.8.0, SortEngine.py 8.1, COI_Chain.py 1.0.1) are unchanged by this session.


8. Open items — carry forward

Blocked on something from Andrew

  1. Upload the current MiscIndexer.py from Live (should say 7.5.0). Then convert it, add its manual entry, ship as the next dotted zip.
  2. Say whether ISE_Atomic_Writers_v1.0.0.zip was deployed anywhere. If so, restore MiscIndexer.py there.
  3. Decide on the MediaIndexer.py store-wipe safeguard (finding 1), and say where patch_media2.py / the v9.9.3 file came from.
  4. Decide whether the manual should gain an IndexBuilder.py section, and confirm the current MediaProcessor.py version.

Still open from the v9.9 list (unchanged unless noted)

New


9. Machine state

Not observed this session. No commands were run on Live, Clone or Dev; all work was on uploaded copies in the sandbox. The v9.9 close state (Live under swap pressure with media_store.json at 2723 items; Clone with free memory and no swap, mirror needed before MediaProcessor.py) is the last known state.


DM2S/NX v10.0 Chapter 1 checkpoint — 2026-10-05 11:57 AEDT