Skip to content

qualification: reproduce certifications sealed before a reviewed additive field - #2134

Merged
abrichr merged 3 commits into
mainfrom
fix/cert-digest-sealed-omissions
Nov 9, 2026
Merged

abrichr merged 3 commits into
mainfrom
fix/cert-digest-sealed-omissions

Conversation

@abrichr

@abrichr abrichr commented Nov 9, 2026

Copy link
Copy Markdown
Member

Problem

Every bundle certified before Anchor.form_identity and TokenTemplate.bearing were added now fails Workflow.load with "governed authorization template cannot be reproduced from the sealed certification". The certification's workflow-contract digest is a plain dump of the workflow. It now writes both new fields as null, so it no longer matches the digest the certification was signed against. The content digest is unaffected, because it already leaves such fields out through the reviewed _SEALED_CANONICAL_OMISSIONS_BY_VERSION list. The certified OpenEMR referral program (ec096afa…, used by #1431 and the lifecycle arm) is one of the bundles this breaks.

Rule

  • The current digest is computed first, exactly as before, and wins whenever the persisted qualification is bound to it, or to nothing.
  • Otherwise an older form is tried. It reuses the same omission list, more narrowly. A field is left out only when all of these hold:
    • its owner and name are on the list for the bundle's format version;
    • the rule accepts None;
    • its value is None;
    • the loaded file never set it (model_fields_set).
  • A field the file wrote, even as null, stays in the digest, and so does any non-null value.
  • The older form is used only if it reproduces a bound digest exactly.
  • Workflow.load records which form matched (qualification.certified_contract_form).

Tests

tests/test_certification_sealed_omissions.py, with the real OpenEMR bundle copied in as a fixture:

  • the pre-field certified bundle loads, and the older form is recorded;
  • a non-null bearing is refused, in the file and in memory;
  • an explicit null that the sealed file never held is refused;
  • a field taken off the list is refused;
  • a rule that does not accept None is not used;
  • a format version with no rules gets no fallback;
  • a bundle bound to the current digest gets no fallback.

The existing qualification, governed-authorization, run-gate and seal suites pass.

…tive field

The certification's workflow-contract digest is a plain dump of the
workflow, so adding Anchor.form_identity and TokenTemplate.bearing (both
None by default) changed it for every bundle certified before them. The
content digest already leaves such fields out through the reviewed
_SEALED_CANONICAL_OMISSIONS_BY_VERSION list; the contract digest did not,
so those bundles failed to load.

The current digest is still computed first. Only when the persisted
qualification is bound to a different digest is the older form tried:
a field is left out when it is on that list for the bundle's format
version, the rule accepts None, its value is None, and the loaded file
never set it. The older form is used only if it reproduces a bound digest
exactly. Workflow.load records which form matched.
@abrichr

abrichr commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

Codex review: APPROVE at 56c0d32. Codex found no path where a changed contract loads as certified. The current digest wins. The historical form needs the exact version, owner and name, a rule that accepts None, a None value, a field the file never set, and an exact bound digest. The other certification checks still apply independently. 309 cases passed on an independent Linux run.

@abrichr

abrichr commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

Reopening to retrigger CI: the last run's packages and smoke jobs were abandoned by the runner, no test failed.

@abrichr abrichr closed this Nov 9, 2026
@abrichr abrichr reopened this Nov 9, 2026
@abrichr

abrichr commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

Codex delta review: APPROVE at 217ffae for the fixture reformat (its AST equals the approved fixture). The main merge reproduces a clean three-way merge.

@abrichr
abrichr merged commit c5e64e6 into main Nov 9, 2026
49 checks passed
@abrichr
abrichr deleted the fix/cert-digest-sealed-omissions branch November 9, 2026 22:10
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