Skip to content

Revert the anchor-scoped payout-artifact reuse line (#103, #102) - #104

Merged
RobertClarke merged 2 commits into
1.x.xfrom
revert-103-102
Jul 30, 2026
Merged

Revert the anchor-scoped payout-artifact reuse line (#103, #102)#104
RobertClarke merged 2 commits into
1.x.xfrom
revert-103-102

Conversation

@RobertClarke

@RobertClarke RobertClarke commented Jul 30, 2026

Copy link
Copy Markdown
Member

Reverts #103 (cd32c13) and #102 (fcc2c3e) from 1.x.x, in reverse order, as two plain git revert commits. The result is tree-identical to the #101 squash commit (e2fb33d) — the state mainnet has been pinned to since the second rollback.

Why: two production incidents in two days

2026-07-29 — born-expired artifact livelock (#102). At production reward windows (100k+ shares) the window walk takes multiple seconds, and #102 measured reuse freshness from the wall-clock snapshot anchor — stamped before the walk — so every artifact arrived already past the 10s staleness bound and was discarded as born expired. Installs unconditionally reset the re-arm backoff, so the single preparation worker re-walked the reward window continuously while holding the prepare lock every synchronous ready build needs, driving tip refreshes from 1–6s to a 27s mean and parking initial jobs into the 90s client timeout; the deploy was emergency-rolled-back after ~15 minutes.

2026-07-30 — generation-churn brownout (#103 re-land). The re-land moved reuse freshness to install time and re-gated cached bundles on artifact-generation currency, but under production template-generation churn those validity paths kept superseding and rebuilding otherwise-valid artifacts, and job delivery browned out. It was emergency-rolled-back the same day, and mainnet has run pinned to #101 (e2fb33d) since.

Decision

The anchor-scoped payout-artifact reuse line is abandoned on 1.x.x rather than re-landed a third time. This PR removes all #102/#103 behavior:

What stays

PR #99's serve-daemon/spool plumbing is not part of this revert: it predates #102, is dormant without publishable artifacts (the pre-#102 state), and ran harmlessly in prod under #101 for two days. Note the two remaining PRISM_PAYOUT_ARTIFACT_REARM_* names in lab/prism/prism_coordinator.py (rebuild-pacing floor and backoff cap) are #99's, introduced in 5a0b1fc and present in e2fb33d — they are part of the pinned mainnet state, not #102/#103 residue.

Validation

  • git diff --exit-code e2fb33d HEAD — empty; tree-identical to the PRISM: converge tip refreshes on latest epochs #101 pin
  • python3 -m unittest discover -s tests -p 'test_*.py' — 1347 tests, OK (3 skipped)
  • cargo test -p qbit-prism — all green
  • grep: no REUSE_STALENESS / MAX_ANCHOR_AGE / admission-deadline / payout_artifact_events_total / anchor-age / install-age references remain in lab/ or tests/

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

High Risk
This is a large revert of payout-artifact reuse and job-build admission paths in the prism coordinator—production-critical coordination logic that already caused two emergency rollbacks when the replaced line shipped.

Overview
Reverts the anchor-scoped payout-ledger-artifact reuse line (#102/#103) and restores the pre-incident coordinator behavior pinned on mainnet after the 2026-07-29/30 rollbacks.

Payout ledger artifact validity and install ordering again use accepted-share counts (with bracketed capture per template generation via _job_build_anchor_counts), not snapshot-anchor age or install-time staleness. Background and synchronous builds abort when a pending commit clamps the anchor, when before/after share counts disagree mid-read, or when the live count no longer matches the anchor-scoped count—rather than publishing anchor-exact windows under continuous share traffic.

Removed: env knobs PRISM_PAYOUT_ARTIFACT_REUSE_STALENESS_SECONDS, PRISM_PAYOUT_ARTIFACT_MAX_ANCHOR_AGE_SECONDS, and PRISM_ROUTINE_ADMISSION_DEADLINE_SECONDS; born-expired / anchor-ceiling install paths; payout_artifact_events_total metrics and JSON lifecycle logging; JobBuildAdmissionDeadlineExceeded and routine admission deadline parking; cached-bundle freshness gates tied to build age or declared anchor age.

Adjusted: _job_snapshot_anchor_ms no longer forces anchors strictly below the clamp instant when no pending floor is held; in-flight reuse re-validation calls _usable_payout_ledger_artifact again instead of only generation/balances fences.

Reviewed by Cursor Bugbot for commit 6aca4fa. Bugbot is set up for automated code reviews on this repo. Configure here.

RobertClarke and others added 2 commits July 30, 2026 13:26
…26-07-29 re-land) (#103)"

This reverts commit cd32c13.

The re-land brownouted mainnet on 2026-07-30 (generation-churn brownout);
the payout-artifact reuse line is abandoned and 1.x.x returns to the #101
(e2fb33d) behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s production share rates (#102)"

This reverts commit fcc2c3e.

Anchor-scoped reuse livelocked mainnet payouts on 2026-07-29 (born-expired
artifact livelock); together with the #103 revert this restores the
payout-artifact machinery to its #101 (e2fb33d) state: exact-count fence
semantics, no staleness/rearm/anchor-age knobs, no admission-deadline
machinery.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: 6aca4fa5f2

ℹ️ 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 18363 to +18365
if floor_ms is None:
return issued_at_ms - 1
return min(issued_at_ms - 1, floor_ms - 1)
return issued_at_ms
return min(issued_at_ms, floor_ms - 1)

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 Keep the snapshot anchor below the current millisecond

When a share is stamped after this clamp but within the same millisecond, returning the inclusive issued_at_ms lets that share fall inside the declared audit window even though it was absent from the snapshot because its commit was still pending. A later qbit_audit_share_window replay then includes the share and cannot reproduce the published bundle; the accepted-count fences do not close this race because the commit can land after their final read. Preserve the one-millisecond subtraction even when no pending floor is currently visible.

Useful? React with 👍 / 👎.

@RobertClarke
RobertClarke merged commit 1c474c5 into 1.x.x Jul 30, 2026
10 checks passed
djh58 added a commit that referenced this pull request Aug 3, 2026
…witch (#107)

* Revert "Revert the anchor-scoped payout-artifact reuse line (#103, #102) (#104)"

This reverts commit 1c474c5.

* Make payout-artifact reuse event-driven below the audit ceiling

The 2026-07-29 rollback and the 2026-07-30 brownout were the same
arithmetic error at different anchors: a wall-clock validity budget
shorter than the production interval between consecutive shared
builds, on an object whose rebuild pays a multi-second reward-window
walk. Round 1 measured the budget from the pre-walk anchor, so every
artifact arrived born expired; round 2 moved it to install time, so
the budget expired between consecutive builds and every build fell
back to the synchronous walk while the re-arm worker walked the same
window in parallel.

Wall-clock time is no longer a validity input below the audit ceiling:

- The reuse probe serves any armed artifact whose payout generation,
  difficulty, and balances fences hold and whose declared anchor is
  inside PRISM_PAYOUT_ARTIFACT_MAX_ANCHOR_AGE_SECONDS. Past the new
  PRISM_PAYOUT_ARTIFACT_REANCHOR_SECONDS floor it schedules the
  debounced background re-anchor and KEEPS SERVING; post-anchor
  shares settle in the next window by construction, so a re-anchor is
  freshness maintenance, not correctness.
- PRISM_PAYOUT_ARTIFACT_REUSE_STALENESS_SECONDS is removed. Cached
  no-artifact ready bundles gate on the re-anchor floor instead
  (their declared anchor is already ceiling-gated, and the
  bundle-cache TTL bounds them tighter in production).
- PRISM_PAYOUT_ARTIFACT_REUSE (default on) is a master kill-switch:
  off restores the pre-reuse deployment exactly -- probe refuses, no
  background walks -- so a production regression is an env flip
  instead of an emergency rollback (both prior incidents required
  redeploys).

Test changes mirror the semantics: install-age rejection tests become
serve-past-install-age brownout regressions, rearm/debounce and
landed-preview suppression drive aging through the anchor, in-flight
retention ages through the ceiling, and the kill-switch has dedicated
coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add reuse probe outcomes, semantic work-currency gauge, slow-wave log

Three observability gaps the incident review had to work around:

- The reuse probe was invisible: nothing distinguished served reuse
  from ceiling rejections. served_reuse / probe_rejected_ceiling join
  the payout-artifact event family (recorded outside the cache lock,
  matching the family's lock ordering).
- current_tip_job_coverage demands template-generation equality and
  template object identity, so under generation churn it reads 0.0
  essentially continuously even while every miner holds semantically
  current work. The new semantic_current_work_ratio gauge compares
  template fingerprint and payout generation only. The strict gauge
  is untouched -- it drives mining-health gating and stays
  fail-closed.
- Slow waves logged nothing attributable: latency had to be
  reconstructed by pairing tip-observation lines with "refreshed N
  client job(s)" lines, which cannot see superseded passes. Waves
  over 1s now log outcome, refreshed count, pass count, and elapsed
  time in one line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Flush worker-thread build phases into the exported counters

The job-build executor and payout-artifact preparation workers never
pass through the per-client delivery entry points that clear and
flush the thread-local phase dict, so every wave-level phase they
accrued -- template, ledger, assembly, bundle, payout_artifact --
exported as exactly 0.0 forever despite continuous template fetches
and multi-second window walks. The bundle-build cost had to be
discovered from the separate tip_refresh_bundle_phase histograms and
ad-hoc profiling because this family was blind.

_flush_job_build_phases folds phase seconds only (build counts and
the duration histogram stay per-delivery) and clears the dict so a
long-lived worker cannot double-report an earlier request's accruals.
Wired at the two worker boundaries: _execute_job_build_request and
each _payout_artifact_preparation_loop iteration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Harden the reuse re-land per adversarial review

Review verdicts: the revert purity, round-2 diagnosis, serve-window
correctness, test archaeology, and zero-regression claims survived;
the kill-switch equivalence claim was refuted as written, and the
review surfaced one genuinely dangerous miss plus four smaller ones.
This commit addresses all of them:

- Startup validation (the dangerous miss): a ceiling at or below what
  the background re-anchor can beat re-creates the 2026-07-30
  walk-per-build shape with a single env var. __init__ now refuses
  MAX_ANCHOR_AGE <= 2x REANCHOR via
  validate_payout_artifact_age_bounds, with direct test coverage.
- Kill-switch now gates ARMING too: _install_payout_ledger_artifact,
  the payout-publication pointer swap, and sync-build window seeding
  all no-op while disabled. Previously artifacts kept arming with the
  switch off, churning install events and re-keying the idle-bundle
  fast path to a generation the probe refuses -- a permanent idle
  cache miss in the disabled state. Comments and the PR description
  no longer claim the disabled state matches the pre-reuse deployment
  "exactly": it restores pre-reuse delivery economics while the
  synchronous path keeps the re-landed anchor-selection semantics.
- prior_balances_sha256 is memoized on the artifact at construction
  and re-derived at the accepted-preview balance patch; the reuse
  probe and both reused-build fences stop paying O(accounts) JSON
  canonicalization per serving decision. The restamp-race test now
  drives the un-memoized fallback path it was written to protect.
- The idle issuance path enforces the anchor ceiling like every other
  NEW serving decision (it was the one route that could issue a
  window past the ceiling), and the probe docstring states the
  in-flight-retention exception instead of overselling the ceiling.
- probe_past_floor joins the event family so the canary can
  distinguish serving-past-floor from never-crossing-the-floor;
  rearm_scheduled alone under-counts through debounce/suppression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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