Commit 54ce20f
content-review: close the loop between the claims detector and the fixer (#20968)
* content-review: close the loop between the claims detector and the fixer
The nightly claims re-verification finds real bugs and the per-article
review worker never acts on them. Observed end-to-end in #20927:
concepts/providers/_index.md was flagged 2026-08-15 for a contradicted
version pin, boosted to the front of the queue on that marker, reviewed,
reported "0 contradicted" across 74 re-extracted claims, and merged a
one-line unrelated repair — with the flagged bug still on master (it took
a hand-written PR, #20961). The marker then cleared, so the entity
returned to the pool to be re-flagged and re-missed on a ~2-day cycle.
Three defects, three fixes:
1. The evidence never reached the worker. select-articles.py put only
`len(stale_claims)` — an integer — into the queue item, while the
review skill was told to "treat the ledger markers' entity keys and
evidence as priority findings". It was being asked to act on data it
was never given, so it re-derived from scratch and missed. The queue
item now carries `stale_claim_markers` in full, and the skill
documents them as must-address findings.
2. Unresolved markers were silently cleared. build_record rebuilt the
ledger entry from the queue and dropped `stale_claims` whether or not
anything had been done. A marker now retires only when the verdict
names its entity in the new optional `resolved_claims` field; anything
else carries forward with `unresolved_reviews` incremented. Since an
unboundedly-boosted page would starve the queue, a marker that
survives MARKER_ESCALATION_CAP (2) reviews is flagged `escalated`:
still recorded and still visible, but no longer boosting — the signal
that a human, not another identical pass, is the next step.
3. Markers on generated pages could never be cleared at all.
select-articles.py globs content/docs/**/*.md, so an adapter-generated
page (the pre-built policy-pack tables) can never be selected — while
already_marked() excluded its entities from re-verification forever.
Three entities were lost this way over five nights
(iam-user-unused-credentials-90, redshift-backup-enabled,
cloud-logging-retention-period-365). apply_markers() now skips pages
with no source file and reports the verdict instead, leaving the
entity in the pool; those contradictions are real but the fix is
upstream of this repo.
make test-review-pipeline and make lint pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hp4LqiP4u81uT48MS8Hea4
* content-review: keep escalated markers on the ledger through a review
Review feedback on #20968 (thanks @unblocked) found a real hole in the
escalation path, and a smaller inconsistency next to it.
Escalated markers were filtered out of the queue item, but
record-review.py rebuilds the ledger entry *from the queue* and writes
back only what survives — so the first time an escalated marker's page
was reviewed for any other reason (ordinary staleness, or --paths), that
marker was dropped from the ledger entirely. already_marked() in
reverify-claims.py would then stop seeing the entity and let it back into
the nightly pool, restarting the detect/boost/miss/clear cycle this PR
exists to break, just two reviews later. The PR body claimed the opposite
invariant ("the marker stays on the ledger entry"), and it did not hold.
Relatedly, the queue's `stale_claims` count was computed over all markers
while `stale_claim_markers` carried only the non-escalated ones, so a page
whose only marker was escalated advertised `stale_claims: 1` alongside an
empty list — contradicting what SKILL.md tells the worker those two fields
mean.
Both come from the same root cause: escalation was being enforced at the
wrong layer. It is a *boost* policy, not a visibility policy. So the queue
item now carries every marker (new all_markers()) and the count is taken
over that same list, while active_markers() — non-escalated only — is used
solely for the scoring boost. Escalated markers travel, persist, and stay
resolvable; they simply stop jumping the page to the front of the queue.
SKILL.md documents the `escalated` flag so the worker knows what it means
rather than inferring it.
Regression coverage for the exact failure: an escalated marker rides the
queue item, reaches a --paths review, survives build_record with its
counter still incrementing, and can still be retired via resolved_claims;
plus the count/list agreement. All three new select-articles checks fail
against the previous code and pass against this one.
make test-review-pipeline and make lint pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hp4LqiP4u81uT48MS8Hea4
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 579534e commit 54ce20f
5 files changed
Lines changed: 299 additions & 10 deletions
File tree
- .claude/commands/review-existing-content
- scripts/content-review
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
55 | 64 | | |
56 | 65 | | |
57 | 66 | | |
| |||
60 | 69 | | |
61 | 70 | | |
62 | 71 | | |
63 | | - | |
64 | | - | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
65 | 97 | | |
66 | 98 | | |
67 | 99 | | |
| |||
335 | 367 | | |
336 | 368 | | |
337 | 369 | | |
| 370 | + | |
338 | 371 | | |
339 | 372 | | |
340 | 373 | | |
| |||
362 | 395 | | |
363 | 396 | | |
364 | 397 | | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
365 | 404 | | |
366 | 405 | | |
367 | 406 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
133 | 136 | | |
134 | 137 | | |
135 | 138 | | |
| |||
243 | 246 | | |
244 | 247 | | |
245 | 248 | | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
246 | 286 | | |
247 | 287 | | |
248 | 288 | | |
| |||
285 | 325 | | |
286 | 326 | | |
287 | 327 | | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
288 | 331 | | |
289 | 332 | | |
290 | 333 | | |
| |||
456 | 499 | | |
457 | 500 | | |
458 | 501 | | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
459 | 560 | | |
460 | 561 | | |
461 | 562 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
| 236 | + | |
| 237 | + | |
237 | 238 | | |
238 | 239 | | |
239 | 240 | | |
| |||
243 | 244 | | |
244 | 245 | | |
245 | 246 | | |
246 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
247 | 260 | | |
248 | 261 | | |
249 | 262 | | |
| |||
254 | 267 | | |
255 | 268 | | |
256 | 269 | | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
257 | 276 | | |
258 | 277 | | |
259 | 278 | | |
| |||
395 | 414 | | |
396 | 415 | | |
397 | 416 | | |
398 | | - | |
| 417 | + | |
399 | 418 | | |
400 | 419 | | |
401 | 420 | | |
| |||
413 | 432 | | |
414 | 433 | | |
415 | 434 | | |
| 435 | + | |
416 | 436 | | |
417 | 437 | | |
418 | 438 | | |
| |||
514 | 534 | | |
515 | 535 | | |
516 | 536 | | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
517 | 562 | | |
518 | 563 | | |
519 | 564 | | |
| |||
522 | 567 | | |
523 | 568 | | |
524 | 569 | | |
525 | | - | |
526 | 570 | | |
527 | 571 | | |
528 | 572 | | |
| |||
0 commit comments