Repository navigation
Mastering writes a batch once: outbox by batch, Company fields once, no repeated write - #907
Merged
Merged
Conversation
paulananth
pushed a commit
that referenced
this pull request
Oct 11, 2026
…t save is recorded, one rule-proposal check Spec review: an unrelated batch saved between the assessment and the save made the save fail on its fixed generation; the spec says an unrelated generation alone does not invalidate a proposal. The save now takes the current generation under the lock (the effects hash leaves it out), after the snapshot and rule-proposal checks. A batch PostgreSQL refuses at save now keeps a rejected assessment, as one refused when assessed does. Standards and GoF: the policy, check_policy and rule-proposal re-check are one method used by _execute and the save (the save had skipped the missing policy check); recording a proposal in a caller's transaction is assessment.record_in; the load-bearing `except StaleAssessment: raise` says why. candidate-assessments.md describes the new apply path. Tests: an unrelated batch saved between assessment and save; a refusal at save. test_clean_assess_and_apply.py 5, the concurrent-correction race 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
paulananth
marked this pull request as ready for review
October 11, 2026 17:18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFKdv4nqKXKM9d5Cf2hEFk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFKdv4nqKXKM9d5Cf2hEFk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFKdv4nqKXKM9d5Cf2hEFk
One batch of 919 Companies (1.4 MB of records) writes about 35 MB: each step keeps its own whole copy (readings 5 times, golden records 7, decisions 4), and the write runs twice (preview, then save). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…no repeated write Root cause (ticket): each step that handles a batch kept its own whole copy, and a batch with identity work was written twice (preview, then save). - 014: an outbox row keeps the hash of what it sends, not a copy. What a consumer is sent is built from the batch row (outbox_payload_of); a row stored before keeps and sends its own payload (outbox_payload). The new hash equals the hash the 001 write stored, for every consumer. - 015: company.fields was body->'fields' a second time; the company_master_field view reads body, and the column is dropped. Versions stored before read the same after. - MergeStage.apply with identity work: the batch is assessed once (no preview_batch write, no second computation), its proposal committed before any master write as before (Q13), then saved in the next transaction after re-checking the snapshot and each rule proposal under the lock. A refused batch keeps a rejected proposal; a stale one is superseded and re-proposed. `assess` and `apply_assessment` keep their preview for a proposal made on its own. Tests: test_clean_outbox_names_batch.py (3), test_clean_company_fields_once.py (2), test_clean_assess_and_apply.py (3); readers moved to outbox_payload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ace test hooks the save step migrate revokes every mdm function from PUBLIC (the fence), so a verifier login, which holds SELECT only, could not call the payload function. What a row sends is now the view mdm.outbox_delivery; write_batch hashes it, claim_outbox and the publishers read it. The concurrent-correction test injects its race at _save_assessed, the step apply now uses. 239 MDM Postgres tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t save is recorded, one rule-proposal check Spec review: an unrelated batch saved between the assessment and the save made the save fail on its fixed generation; the spec says an unrelated generation alone does not invalidate a proposal. The save now takes the current generation under the lock (the effects hash leaves it out), after the snapshot and rule-proposal checks. A batch PostgreSQL refuses at save now keeps a rejected assessment, as one refused when assessed does. Standards and GoF: the policy, check_policy and rule-proposal re-check are one method used by _execute and the save (the save had skipped the missing policy check); recording a proposal in a caller's transaction is assessment.record_in; the load-bearing `except StaleAssessment: raise` says why. candidate-assessments.md describes the new apply path. Tests: an unrelated batch saved between assessment and save; a refusal at save. test_clean_assess_and_apply.py 5, the concurrent-correction race 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erred Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aster merges Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
paulananth
force-pushed
the
claude/mdm-request-dedup
branch
from
October 11, 2026 17:44
1f4bdd9 to
41f5c3f
Compare
paulananth
added a commit
that referenced
this pull request
Oct 11, 2026
paulananth
added a commit
that referenced
this pull request
Oct 11, 2026
* Skill audit: skills state today's Company and GLEIF status data-onboarding, refining-rules, READING.md and COMBINING.md no longer call the installed proof, whole-capture equivalence and the older readers' deletion open (#901, #904, #905, #907); they name what is open (in-process Company preparation, adapters.py, capture). Prose says Name Frequency, file names stay. The handoff's finished lines are ticked with evidence. data-platform/SKILL.md waits for Codex's responsibility-map branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Skill audit: review fixes; one open-work list READING.md and COMBINING.md: remaining census prose says Name Frequency, stale status passages state today, a dated 2026-10-11 qualification section, the retired builder and reader named. The open-work list lives in data-onboarding; refining-rules points to it (GoF finding). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Aneena Ananth <aneenaananth@MacBook-Air.local> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mastering writes a batch once
Ticket:
.planning/workstreams/mdm-request-dedup/TICKET.md.Root cause
Each step that handled a batch kept its own whole copy of it, and a batch with identity work was written twice. On cm27 chunk 1 (919 Companies, a 1.4 MB records file), one batch wrote about 36 MB into the store:
source_reading,stage_record.reading,batch.effects, the journal outbox row, the match proposalcompany.body,company.fields,batch.effects, the journal outbox row twice, the graph and export outbox rowsdecision,batch.effects, the journal outbox row, the proposalThe write itself ran twice:
preview_batch(all ofwrite_batch, rolled back), thensave_batch.What
mdm.outbox_delivery, built from the batch row. It is a view becausemigraterevokes every function fromPUBLICand a publisher's verifier holdsSELECTonly. A row stored before keeps and sends its own payload.company.fieldswasbody->'fields'again;company_master_fieldreadsbody, and the column is dropped.MergeStage.applywith identity work assesses once (no preview write, no second computation), commits the proposal before any master write (Q13), then saves the computed batch after re-checking its snapshot and each rule proposal under the lock.assess/apply_assessmentkeep their preview for a proposal made on its own.Not done, per the GoF consult (reasons on the ticket): the Stage's copy of the winning reading, per-field policy digests, the publication key per reading.
Evidence
companytest_clean_outbox_names_batch.py,test_clean_company_fields_once.py,test_clean_assess_and_apply.py. Each migration is tested on rows written by the 001 functions. The built outbox payload and hash equal what the 001 write stored, for journal, export and graph.Full proof (passed)
The installed empty-store proof on the 7 raw-capture cm27 bundles, 12:47–13:14 ET 2026-10-11: 6,414 Companies; GLEIF 3,716 records, 3,052 bound; bindings
9216cc18…, equal to the checkout replay and to #905's proof on the same bundles; recovery on attempt 2; the second pass changed nothing. SEC merge 4.0 to 2.8 min, GLEIF merge 1.9 to 1.3 min against #905's proof. Report.planning/workstreams/mdm-request-dedup/evidence/installed-company-proof-20261011.json.Three-axis review done; its two faults (an unrelated batch between assessment and save; a refusal at save) fixed and tested in
3024c745. 241 MDM Postgres tests pass.🤖 Generated with Claude Code