Skip to content

feat(OMN-18988): re-emit a lab-pass receipt for any sha the converged image contains whose only failures were binding-class - #3921

Closed
jonahgabriel wants to merge 1 commit into
devfrom
jonah/omn-18988-reemit-v3
Closed

jonahgabriel wants to merge 1 commit into
devfrom
jonah/omn-18988-reemit-v3

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

Ticket: OMN-18988, a child of OMN-18976. Option (1) per the team lead's ruling, then widened by the team lead's scope extension (the section The widening below). Part one merged as e5af728ee (#3914), so this branch is rebuilt on current dev and the diff is part two alone.

What part one left

#3910 stopped a queued merge being recorded as a terminal FAIL. That left the sha with no receipt at all, which is strictly better and still not an answer: the delivery gate keeps refusing it, and its own verify run is over. Only a later run can speak for it.

The window, and why it is not ancestry

A verify run reads the lane twice: at the revision it started on, and at the one it converged to. Every merge that landed strictly between those two was queued behind this one — its own verify run found the lane still on the earlier revision and exited without a receipt. That set, and only that set, is what a convergence may answer for.

The bound is the whole point. It is emphatically not every ancestor of the converged revision: the lane has run for weeks and contains thousands of shas it never individually converged on, and emitting for those would manufacture receipts for merges nothing observed. A queue is not a history.

Every unresolved case yields an empty window — no previous revision, no converged revision, a lane that never moved, an unreadable comparison. Emitting nothing leaves the gate refusing exactly as it does today; a wrong PASS is the one outcome this must not introduce while removing a wrong FAIL.

The evidence is re-keyed, not re-taken

The converged run's probes were read against the image the lane came to run, and that image contains each of these shas — so they are precisely the reads a lab pass for that sha would have made, at the only moment it could. Re-probing here would read a newer lane state and attribute it to an older sha, which is the weaker claim and the easier one to get wrong.

A failing convergence re-emits a failure. Every sha in the window inherits what the run found. A re-emission that quietly upgraded to PASS would be the worst possible outcome of this ticket, and there is a test for exactly that direction.

Provenance, and two refusals

Each re-emitted receipt carries converged_via, so a receipt written by a sha's own run and one written by a later convergence stay tellable apart. Both are honest; they are not the same evidence. The field is written only when non-empty, on the same terms as node_inventory, so RECEIPT_VERSION is unchanged and every receipt already in flight parses byte-identically — there is a test asserting an ordinary receipt's wire shape is unchanged.

The re-key refuses two things outright: onto its own sha, which would race two artifacts of one name from one job; and from a receipt that is itself a re-emission, because provenance that chains is provenance nobody can read.

Shape

A matrix job, because the number of queued shas is discovered at run time and a uses: step cannot be looped. fromJSON over the verify job's output, and an empty array skips the job — the common case, since the lane usually converges on the very next merge.

Five gates refused the first draft, each fixed at cause

Worth listing, because every one of them was right:

gate what it caught
lab-pass receipt isolation paths not derived from a per-run variable
CI evidence policy an if-no-files-found: error uploader undeclared, and then its pre-upload assertion missing if: always()
rebuild-trigger ceiling a job with no timeout-minutes
runner routing audit a hardcoded ubuntu-latest instead of the fork-aware selector
CI workflow resilience raw setup-uv instead of the shared CI Python environment

The matrix leg keys its receipt directory by sha as well as run and attempt, because two legs sharing one directory would upload each other's receipt.

Verification

tests/ci/ and tests/unit/ci/ are green whole -- 4453 passed, 7 skipped -- with mypy --strict and ruff clean on both changed modules. The window and re-key have nineteen tests, all boundaries: two-sha queue in, converged sha excluded, outside-the-window excluded, empty window, both missing endpoints, unresolvable comparison, lane that never moved, dedup. The failing-convergence direction is among them: a FAIL convergence re-emits a FAIL. The widening adds twenty-five: the eligibility decision over every failure shape (binding-only, one health check among binding ones, deployed_revision FAIL rather than INDETERMINATE, already-passing, unreadable), and surface resolution over each of the three surfaces winning, a readable non-containing surface not vetoing a later one, and all three silent yielding no candidate.

The last two commits also re-point the two OMN-18144 tests the part-one rename moved, which splits 1 and 2 were correctly red on. Re-pointed, not relaxed: each now asserts the not-a-lane-failure property directly rather than via whichever enum member carries it.

Split 12 is red on the committed lane census aging past its 3-day threshold. Unrelated, pre-existing on dev, left alone.

The semantic, stated plainly

A re-emitted PASS for S means: the converged image containing S passed the lane's
checks at X.
It does not mean the lane was observed applying S by itself, and it
never can — S was queued behind another deploy and no run watched it land alone. That
is what a lab pass for a queued-behind merge can ever mean, and converged_via is on the
receipt so a reader gets that sentence rather than reconstructing it from timestamps.

The widening

Part one and the first draft of this PR answered for one class only: a sha that was
queued behind another deploy and therefore emitted no receipt at all. The trigger is
now wider, and the widening is what makes this the path that unblocks a cut.

A receipt can also exist and say FAIL for a reason that is not about the software. The
two checks deployed_revision and probe_generation_bound are binding-class: they
answer whether the run could bind its own observation to the sha under test, not whether
the lane was healthy. A run that could not read the lane's revision records a binding
failure and the sha is then refused delivery forever, on evidence that was never about
the code. That receipt is now eligible.

Three refusals bound it, and each is a separate test:

  • deployed_revision must be INDETERMINATE, never FAIL. A FAIL is a measured
    mismatch, the lane demonstrably running something else; an INDETERMINATE is an
    unreadable one. Treating the two alike would re-emit over a real mismatch.
  • Every failing check must be binding-class. One failing health check and the receipt
    is refused by name. A receipt whose health checks genuinely failed is never re-emitted,
    under any combination.
  • A passing receipt is left alone, and a re-emission never chains from another
    re-emission.

The binding is re-established, never inherited

The converged run may itself have failed to bind — that is the case this widening exists
for — so its answer is not evidence for anybody else. Each candidate's binding is resolved
fresh, in the verify job that already holds the lane, across three surfaces tried in
order: the container's revision label, the deploy agent's /health loaded_code_sha,
and the lane's /ready version.

The first surface that establishes containment wins. A surface that is readable but
does not contain
the candidate does not veto a later one: it is one lane fact
disagreeing, not a verdict, and a single stale label must not suppress a correct answer
the agent already has. If all three are silent the candidate is omitted and named in
the log
rather than answered for — no receipt, the gate keeps refusing, and the refusal
is visible where a reader of that run will find it. Silence is not a pass.

The surface that won is written to the receipt as converged_via, so a reader gets
which lane fact bound the sha rather than a bare assertion that something did.

Replaces #3915

#3915 was stacked on the part-one branch. When part one landed as a squash its commits
were re-minted, so the stacked branch conflicted with dev on check_dev_lane_staleness.py
and could not be merged or rebased in place: the shared-clone guard refuses both inside a
worktree (OMN-18974, filed). Rebuilt on current dev by re-applying the part-two diff with
a three-way apply.

That apply is also the proof the two changes coexist: OMN-18990 landed its queue-lag
staleness arm in the same module while this branch was open, and it is present here
untouched -- MAX_QUEUE_LAG_AGE_SECONDS and _stale_lag_reason are in the file beside
the window and the binding resolver. No version bump; no package behaviour changes.

Evidence-Ticket: OMN-18988
Evidence-Source: OCC#10667

The companion below belongs to #3915, which this pull request replaces. It is retained
only because the branch-protection guard refuses an edit that drops a change-control
evidence line, and the receipt gate reads the first such line, which is the one above.

Evidence-Source: OCC#10656

…e only failures were binding-class

Part one (OMN-18976, #3914) stopped a queued merge being recorded as a
terminal FAIL, which left the sha with no receipt at all: strictly better,
still not an answer. A later run has to speak for it, and this is that run.

THE WINDOW, and why it is not ancestry. A verify run reads the lane twice,
at the revision it started on and at the one it converged to. Every merge
strictly between those two was queued behind this one. That set, and only
that set, is what a convergence may answer for -- emphatically not every
ancestor of the converged revision, because the lane contains thousands of
shas it never individually converged on. A queue is not a history. Every
unresolved case yields an empty window, because a wrong PASS is the one
outcome this must not introduce while removing a wrong FAIL.

THE WIDENING. A receipt can also exist and say FAIL for a reason that is
not about the software. deployed_revision and probe_generation_bound are
binding-class: they answer whether the run could bind its own observation
to the sha, not whether the lane was healthy. Such a receipt is now
eligible, under three refusals, each with its own test: deployed_revision
must be INDETERMINATE and never FAIL, because a FAIL is a measured
mismatch and an INDETERMINATE an unreadable one; every failing check must
be binding-class, so one failing health check refuses the whole receipt;
and a passing receipt is left alone.

THE BINDING IS RE-ESTABLISHED, never inherited. The converged run may
itself have failed to bind -- that is the case this exists for -- so its
answer is not evidence for anybody else. Each candidate is resolved fresh,
in the verify job that already holds the lane, across the container
revision label, the agent's /health loaded_code_sha and the lane's /ready
version, in that order. First to establish containment wins. A surface
readable but not containing the candidate does not veto a later one: that
is one lane fact disagreeing, not a verdict. All three silent means the
candidate is omitted and named in the log, and no receipt is written --
silence is not a pass. The winning surface is recorded as converged_via,
so a reader gets which lane fact bound the sha.

The evidence is re-keyed, not re-taken: the converged run's probes were
read against the image that contains each of these shas, so they are the
reads a lab pass for that sha would have made at the only moment it could.
A failing convergence re-emits a failure.

Rebuilt on dev after #3914 squashed; carries OMN-18990's queue-lag staleness
arm untouched. Replaces #3915.
@jonahgabriel
jonahgabriel enabled auto-merge (squash) September 21, 2026 12:07
@onexbot-occ-writer

Copy link
Copy Markdown
Contributor

No OCC evidence companion was minted for this PR.

this PR is already bound to OCC#10656; its evidence companion exists and nothing needs authoring

To clear this: Nothing to do — the companion already exists.

Reported by node_occ_companion_effect (decline code already_bound, OMN-16665). This decision was made against the PR's LIVE state at compute time, not at publish time — a green publisher job only means the command reached the broker.

@onexbot-occ-writer

Copy link
Copy Markdown
Contributor

OCC autobind did not rebind this PR.

This PR's evidence-source stamp line names OCC#10656, which is merged. A second companion, OCC#10667, was minted for this PR, but a merged companion is settled evidence — the merged-companion gate may already have passed against it — so the stamp was left pointing at OCC#10656 and nothing was written.

To clear this: OCC#10667 is redundant and can be closed. If the binding really should move, change the stamp by hand.

Reported by occ_companion_emitter (OMN-18089).

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 21, 2026
…ibase_infra#3921 (#10667)

* evidence(OMN-18988): author OCC companion for OmniNode-ai/omnibase_infra#3921

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head ebad7030132f997658fc6293b43287374bc09481.

* evidence(OMN-18988): self-bind OCC#10667 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Critical findings: 0
Major findings: 0
Total findings: 0
Models succeeded: glm-review

Note: Fewer than 2 reviewer models succeeded. Degraded results are informational (OMN-8468/OMN-8524) and do not block merge. Error: cli_review exit 2 (fewer than 2 models succeeded — partial/total outage)


Semantics (OMN-17492 — the model finds, thread resolution gates)

Surface Meaning Blocks merge?
Review threads Per-finding, posted by the reviewer No (informational)
Hostile Review Thread Gate Deterministic: unresolved hostile-reviewer threads exist Fails until resolved (not yet a required context)
degraded verdict Fewer than 2 models succeeded (infra) No

Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review, qwen3-review-b, glm-review (OMN-8468/OMN-8524/OMN-17492)

@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Superseded by a replacement on the same branch. Not a code problem: this description was copied from #3915 and carried #3915's change-control evidence line, so when autobind minted the companion for #3921 the description held two. The receipt gate refuses two; the body-stamp guard refuses any edit that removes one, including the fenced form the receipt gate itself recommends, because it discounts a fenced line. No edit satisfies both. Filed as OMN-19015. The replacement carries a description that never held the stale line. Nothing is disabled and nothing is relaxed.

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