Skip to content

[MC-463] Atomic enrichment writes + harden merge contract (follow-up to #655)#656

Merged
TarahAssistant merged 2 commits into
mainfrom
fix/atomic-write-json-file
Jun 15, 2026
Merged

[MC-463] Atomic enrichment writes + harden merge contract (follow-up to #655)#656
TarahAssistant merged 2 commits into
mainfrom
fix/atomic-write-json-file

Conversation

@TrueNorth49

Copy link
Copy Markdown
Collaborator

MC Task: MC-463 — Fix enrichments recompute wiping manual_overrides / Lane MC-463-B

Follow-up hardening to #655 (the manual_overrides persistence fix), addressing the review's hardening suggestions.

Changes

  • Atomic _write_json_file (python/server.py): writes to a sibling .tmp then os.fsync + os.replace, with cleanup on failure. A crash, a concurrent reader, or two interleaved read-modify-write callers (the recompute job thread and a POST /api/enrichments now both do RMW) can no longer observe — or be left with — a half-written or truncated parse-enrichments.json. This is the durability gap flagged in the [MC-463] Preserve manual overrides on enrichment recompute #655 review.
  • Docstring on _api_post_enrichments (python/server_routes/compare.py): documents that the endpoint deep-merges (does NOT replace), so non-frontend callers (scripts, external API) know omitted keys are preserved and a deletion must send an emptied shape.
  • Tests:
    • test_write_json_file_atomic.py — content round-trip (incl. unicode + trailing newline), no .tmp residue after success, clean overwrite.
    • test_compare_enrichments_manual_overrides.py — locks the deep-merge contract: a full snapshot that empties cognate group B leaves B == [] on disk (not re-populated). Guards against a future 'prune empty groups' change silently reintroducing deletion-suppression.
  • LoC budget bump (test_server_route_modularization.py): server.py thin-orchestrator budget 2050 → 2070 to absorb the atomic-write helper (same documented mechanism used for PR [MC-368-B] feat: compare-bundle API + canonical-lexemes storage #368).

Validation (PC, kurdish_asr env)

PYTHONPATH=python python3 -m pytest python/ -q -k 'not test_ortho_section_defaults_cascade_guard and not test_ortho_explicit_override_beats_defaults'
1926 passed, 3 skipped, 2 deselected, 10 warnings, 3 subtests passed in 58.79s

uvx ruff check python/ --select E9,F63,F7,F82
All checks passed!

Out of scope

  • Serializing concurrent enrichment writes (a lock) — atomicity here removes the corruption risk; lost-update ordering is a separate, lower-severity concern.

🤖 Generated with Claude Code

TrueNorth49 and others added 2 commits June 15, 2026 12:35
- _write_json_file: tmp + fsync + os.replace so a crash, a concurrent
  reader, or two interleaved read-modify-write callers never see (or are
  left with) a half-written or truncated file.
- _api_post_enrichments: docstring documenting deep-merge (not replace)
  semantics so non-frontend callers know omitted keys are preserved and
  deletions must send an emptied shape.
- Tests: atomic-write round-trip + no .tmp residue; POST empty-group
  deep-merge contract lock (emptied cognate group stays []).

Follow-up hardening to #655 (MC-463).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e helper

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TrueNorth49 TrueNorth49 added safeguard Safety guardrail test Test coverage changes MC-463 Mission Control MC-463 labels Jun 15, 2026
@TarahAssistant TarahAssistant merged commit c3984f4 into main Jun 15, 2026
4 checks passed
@TarahAssistant TarahAssistant deleted the fix/atomic-write-json-file branch June 15, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MC-463 Mission Control MC-463 safeguard Safety guardrail test Test coverage changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants