Skip to content

feat(stovepipe): record the validation fact and decide greenness from it - #555

Merged
roychying merged 2 commits into
mainfrom
chenghan.ying/stovepipe-record-validation-fact
Aug 11, 2026
Merged

feat(stovepipe): record the validation fact and decide greenness from it#555
roychying merged 2 commits into
mainfrom
chenghan.ying/stovepipe-record-validation-fact

Conversation

@roychying

@roychying roychying commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Why?

record currently derives greenness straight from request.State and writes nothing durable except the queue's last-green bookmark. This PR switchs to read the fact from the fact store

What?

Restructured record's greenness track:

Request State Before After
succeeded advance bookmark write fact at degree 0, then advance if the stored fact is green
failed ack, no write write fact at degree 1, no advance
cancelled folded in with failed split out — no fact, since a cancelled build decided nothing
superseded / other unchanged unchanged

The new recordFact returns the fact that is actually stored, which is not always the one just built. On ErrAlreadyExists it loads the winner: same RequestID means this delivery's own prior write (a redelivery after the fact landed but before the bookmark moved), so it adopts it and continues; a different RequestID is an invariant violation — two requests can't validate one URI given ingest's (queue, uri) dedup — and is non-retryable.

Ordering is fact first, bookmark second. The fact is the durable record; the bookmark is a derived cache that self-heals, since CompareRequestID only moves forward. The reverse order could leave a bookmark with no fact behind it.

Now it only handles the whole repo greenness. Project-scope greenness should come in the analyze step.

Test Plan

Issue

Every succeeded or failed request now writes an immutable whole-repository
fact before the bookmark moves, and the advance is gated on the stored
fact rather than the request state, so a redelivery cannot reach a
different verdict than the original.
…the interval

The previous wording claimed intermediate values describe partial breakage
without saying for what, which read as though a whole-repository build could
be partly green. Addresses review feedback on #552.
@roychying
roychying requested review from a team, behinddwalls and sbalabanov as code owners August 10, 2026 17:22
@roychying
roychying added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 74c6656 Aug 11, 2026
15 checks passed
@behinddwalls
behinddwalls deleted the chenghan.ying/stovepipe-record-validation-fact branch August 11, 2026 22:40
mnoah1 added a commit that referenced this pull request Aug 13, 2026
…mework

The record stage landed in #555 while this doc still read as a proposal,
so the RFC described a design rather than the code. Re-frames it as-built
and corrects the contract details that drifted: ValidationFact carries no
Queue field (the queue is the store binding and the leading PK column),
Get takes (uri, project), the Record payload carries queue_name beside the
request id, degrees are the named DegreeGreen/DegreeBroken constants,
LastGreenRequestID is shipped rather than proposed, and the bookmark's CAS
conflict is absorbed by the retry loop rather than returned. Adds the two
algorithm steps the doc omitted (deserialize, per-queue storage resolution)
and the ordering rationale for advancing the bookmark only after the fact
is durable.

Replaces the inline Hooks design with integration against hook-framework.md,
which supersedes it: a HookEvent published to a per-domain hook topic and
dispatched to a pluggable extension, not a Notify() call out of the stage.
Records where the publish belongs, the event shape, and the decision that
`type` names the scope (validation.repository.recorded) rather than the
outcome, since scope is the axis consumers cannot route on later.

Documents that record_dlq has no consumer even though dead-lettering is
enabled on the subscription, so rejected messages accumulate unread.
mnoah1 added a commit that referenced this pull request Aug 13, 2026
…mework

The record stage landed in #555 while this doc still read as a proposal,
so the RFC described a design rather than the code. Re-frames it as-built
and corrects the contract details that drifted: ValidationFact carries no
Queue field (the queue is the store binding and the leading PK column),
Get takes (uri, project), the Record payload carries queue_name beside the
request id, degrees are the named DegreeGreen/DegreeBroken constants,
LastGreenRequestID is shipped rather than proposed, and the bookmark's CAS
conflict is absorbed by the retry loop rather than returned. Adds the two
algorithm steps the doc omitted (deserialize, per-queue storage resolution)
and the ordering rationale for advancing the bookmark only after the fact
is durable.

Replaces the inline Hooks design with integration against hook-framework.md,
which supersedes it: a HookEvent published to a per-domain hook topic and
dispatched to a pluggable extension, not a Notify() call out of the stage.
Records where the publish belongs, the event shape, and the decision that
`type` names the scope (validation.repository.recorded) rather than the
outcome, since scope is the axis consumers cannot route on later.

Documents that record_dlq has no consumer even though dead-lettering is
enabled on the subscription, so rejected messages accumulate unread.
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.

2 participants