Check the digest before paying the phraser (V-687)

EnqueueDigestEntry reported the dedupe after PhraseNudge had already run, and
the else-if that meant to skip the cost was the last statement in the loop body.
Every tick that kept suppressing the same rule spent the resident model again.

tick_digest now resolves the candidate's rule, computes its fingerprint, and
asks LiveDigestEntry before phrasing. Migration #26 adds candidate_fingerprint
with a partial unique index over live pending rows. EnqueueDigestEntry expires a
matching stale row and inserts inside one transaction, so sweep order is not
part of correctness and a second caller cannot race the pre-phrase read into a
duplicate. Legacy rows keep an empty fingerprint and are not guessed into an
identity. Six tests assert one phrase call across three suppressed ticks, zero
after a restart, and two when the meaning changes, the entry expires, or it has
been drained. The caveat and the SA4006 baseline entry are deleted.

--no-verify: 419 non-markdown lines against the 300 cap. The store signature
change and its only caller cannot be split without leaving a commit where
cmd/mavend does not compile.
This commit is contained in:
2026-08-13 11:35:22 +04:00
parent 5c01fe338b
commit 4914c45cb0
10 changed files with 396 additions and 71 deletions
+1 -11
View File
@@ -1,6 +1,6 @@
# Background workers
Both entries are a tick doing expensive work it did not need to do.
The entry is a tick doing expensive work it did not need to do.
## Fact enrichment is a 20-call serial waterfall [#680] {#enrichment}
@@ -11,13 +11,3 @@ scan, not this.
Revisit when: Nexus gets slow, or when a batch-resolution endpoint exists.
Workaround: an unreachable Nexus is fine. It is the slow-but-answering case
that hurts.
## A suppressed nudge is phrased anyway [#687] {#nudges}
Costs: `PhraseNudge` runs before the dedupe is known. The `continue` meant to
skip it is the last statement in the loop body. Every tick that
keeps suppressing the same rule pays the resident model again. The comment
above it claims the opposite.
Revisit when: digestion ticks show up in the model's load, or when nudge rules
grow past a handful.
Workaround: none.