Skip to content

Re-sign or rebuild knowledge PRs whose verdict went stale - #214

Merged
tzhouam merged 1 commit into
mainfrom
kb/resign-stale-verdicts
Sep 28, 2026
Merged

tzhouam merged 1 commit into
mainfrom
kb/resign-stale-verdicts

Conversation

@tzhouam

@tzhouam tzhouam commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Knowledge-service redesign follow-up: knowledge PRs whose signed verdict stopped verifying no longer get stuck.

  • Re-sign:
    • A posted verdict older than 48 hours (the issue window is 72) is re-signed.
    • A queued PR with an ageing verdict, or one stalled 2 hours in the queue, is first dequeued with a pause item. It is re-signed only after that ack, so the one-queued-PR-per-repo slot is never freed on a timer.
    • An unexpired, un-acked enqueue blocks re-signing and holds the queue slot.
  • Gate failures (only statuses posted after the current verdict count):
    • transient problems (hold list, unreachable, verifier error, our own kb:hold): wait;
    • expired or missing verdict: re-sign;
    • context changed, consistency pages moved, no clean merge, or manifest mismatch: rebuild;
    • anything else: gate_failed, sent to people once.
  • Rebuild: only the lease-holding scheduler rebuilds. It re-applies the same operations on current main and re-gates them.
    • The staged evidence carries a rebuild of <id> mark, so an interrupted rebuild resumes instead of staging twice.
    • Only a rebuild that passes the gate replaces the PR. The old change set waits in superseding, re-issuing its close item until GitHub shows it closed; it is not counted as overturned by people.
    • A failing rebuild, or operations that no longer apply, goes to people as rebuild_failed, with the old PR left open.
  • Re-signing and superseding are traced as outcomes.

Commit hook approved; full suite and SPEC freshness pass locally.

🤖 Generated with Claude Code

A knowledge PR used to stay in verdict_posted forever once its signed verdict
stopped verifying: when it neared its 72-hour issue window, when main moved
the context pages under it, or when a merge group dropped it from the queue.

- merge.advance records when each verdict was signed (verdict_issued_at) and
  when the PR was queued (queued_at).
- A posted verdict older than 48 hours goes back to pr_open for a fresh
  verdict on the same head. A queued PR (with an ageing verdict, or queued 2
  hours without merging) never frees its queue slot on a timer: a pause item
  dequeues it and makes it a draft, and only that ack returns it to pr_open
  for re-signing and re-enqueueing. A verdict_posted change set with an unexpired
  enqueue outstanding is never re-signed; that ack decides. Such a change
  set also holds the repository's single queue slot, like a queued one.
- A failing PR-stage kb-gate is classified by its description (the
  verifier's first problem):
  - only statuses posted after the current verdict count;
  - transient (hold list, unreachable, verifier error, the kb:hold our own
    pause left): wait;
  - verdict expired or missing: re-sign;
  - context changed, consistency pages moved, no clean merge, manifest
    mismatch: rebuild. The same operations are re-applied to current main
    and gated again as a "rebuild" change set (its evidence carries a
    rebuild-of mark written atomically with staging, so an interrupted
    rebuild resumes instead of staging twice). Only a rebuild that PASSES the
    gate replaces the PR: the old change set waits in superseding, re-issuing
    its close item when one expires, until GitHub shows the PR closed, and is
    then marked superseded (it does not count as overturned by people). A
    failing rebuild, operations that no longer apply, or a mechanical change
    set with none go to people as rebuild_failed, with the old PR left open.
    Only the scheduler, holding the lease, rebuilds;
  - anything else (a real problem with the change): gate_failed, to people
    once.
- Re-signing and superseding are traced as outcomes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T15:08:24.080846Z 36841ec PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36841ec2cc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +261 to +262
_request_close(rt, lifecycle.repo, rt.ledger.changeset(changeset["id"]))
publish(rt, lifecycle, new_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Open the replacement before closing the original PR

When publish() cannot create the replacement—such as when the current judge calibration is missing/outdated, the service has switched to shadow mode, or the publisher later rejects open_pr—the close item has already been issued and is always executable. This closes the original PR while the replacement becomes calibration_required, shadow_recorded, or failed, leaving no replacement PR; publish and confirm the rebuilt PR before requesting closure of the original.

Useful? React with 👍 / 👎.

Comment on lines +318 to +322
signed_at = float(changeset["detail"].get("verdict_issued_at") or 0)
stale_verdict = bool(signed_at) and rt.clock() - signed_at > RESIGN_AFTER
queued_at = float(changeset["detail"].get("queued_at") or 0)
if changeset["status"] == "queued" and (
stale_verdict or (queued_at and rt.clock() - queued_at > QUEUE_STALL)):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Initialize timers for pre-existing queued changesets

On deployment, changesets that were already in queued have neither verdict_issued_at nor queued_at, since this commit only writes those fields during future verdict issuance and enqueue acknowledgements. Both values therefore remain zero and this timeout condition can never fire, so an existing PR dropped from a merge group stays queued indefinitely and permanently blocks the repository's single queue slot; use a persisted fallback such as the changeset timestamps or backfill these fields.

Useful? React with 👍 / 👎.

return None
rt.ledger.update_changeset(changeset["id"], status="superseding",
detail={**detail, "rebuilt_as": new_id, "superseded_because": why})
_outcome(rt, changeset, "superseded", reason=why, replaced_by=new_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record superseded only after observing closure

If the close item cannot be delivered or executed, this immediately writes a terminal superseded outcome while the ledger remains superseding and the original PR remains open. These outcome records are permanent gold labels consumed by dataset export, so an outage can incorrectly label an unresolved change as superseded; emit this outcome in the branch that actually observes the PR closed instead.

Useful? React with 👍 / 👎.

@tzhouam
tzhouam merged commit 87ebb46 into main Sep 28, 2026
5 checks passed
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