Uh oh!
There was an error while loading. Please reload this page.
fix(prism-emit): carry positive scores across epochs - #75
Conversation
Exactly-once outbox assignment left winners silent after the first emit, so a reject-only follow-up epoch burned the prism share. Re-include active Score>0 rows in every epoch's competition set until a better score supersedes via max.
📝 WalkthroughWalkthroughThe emitter now combines fresh outbox rows with active positive scores during each epoch. Store implementations provide eligible scores, tests cover carry-forward and recovery behavior, and documentation describes the updated emission semantics. ChangesCross-epoch score carry
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant emit_rows
participant PrismStore
participant LeafBuilder
emit_rows->>PrismStore: retrieve fresh outbox rows
emit_rows->>PrismStore: retrieve active positive score rows
emit_rows->>emit_rows: merge competition rows
emit_rows->>LeafBuilder: build signed leaves
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/prism-emit/src/lib.rs`:
- Around line 167-171: Persist the complete competition inputs or signed leaves
for each assigned epoch in emit_assigned instead of relying on a fresh
active_score_rows read during recovery. Update replay to use that stored
snapshot so first-write-wins leaves remain identical after later score
finalization, and add a recovery test covering a higher score finalized between
the initial submission and replay.
In `@docs/PRISM.md`:
- Around line 113-143: Update the competition-credit rules in the next section
of docs/PRISM.md to use the complete competition set passed by emit_rows to
competition_scores, including carried active positive scores, rather than only
the epoch outbox batch. Explicitly distinguish batch assignment from the unioned
competition input while preserving the normative documentation wording.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 93a5e24a-1c1c-4916-948c-b05b72fcc73f
📒 Files selected for processing (9)
crates/prism-challenge/src/orchestrator.rscrates/prism-emit/src/lib.rscrates/prism-emit/tests/epoch_semantics.rscrates/prism-store/src/dbprism.rscrates/prism-store/src/emit.rscrates/prism-store/src/store.rsdocs/COMPLETENESS.mddocs/PRISM.mddocs/external-miner/prism.md
| let active = self.store.active_score_rows(self.netuid).await?; | ||
| let competition = merge_competition_rows(&batch, &active); | ||
| let owners: BTreeMap<String, String> = | ||
| self.store.arch_owners().await?.into_iter().collect(); | ||
| let signed = build_epoch_leaves(&self.sk, epoch, expected, &batch, &owners)?; | ||
| let signed = build_epoch_leaves(&self.sk, epoch, expected, &competition, &owners)?; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Persist the competition snapshot for recovery.
emit_assigned also reaches this dynamic active_score_rows read. If a positive score finalizes after an epoch set was submitted but before the cursor advances, recovery rebuilds that old epoch with different leaf values.
This breaks the documented identical replay requirement for first-write-wins gateway leaves. Persist the complete competition input or signed leaf set per assigned epoch, and replay that snapshot. Add a recovery test that finalizes a higher score between the initial submit and replay.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/prism-emit/src/lib.rs` around lines 167 - 171, Persist the complete
competition inputs or signed leaves for each assigned epoch in emit_assigned
instead of relying on a fresh active_score_rows read during recovery. Update
replay to use that stored snapshot so first-write-wins leaves remain identical
after later score finalization, and add a recovery test covering a higher score
finalized between the initial submission and replay.
| **Leaf emission (epoch-close, exactly-once outbox + score carry).** A | ||
| submission row's acceptance epoch (`prism_submission.epoch`) is intake | ||
| metadata only. A dedicated emitter loop (`prism-emit`, one tick per chain | ||
| epoch) emits **one D24-complete leaf set per chain epoch**: the first tick | ||
| that observes epoch `E` assigns every submission finalized since the | ||
| previously emitted epoch — the outbox batch, | ||
| `kind IS NOT NULL AND emitted_epoch IS NULL` — to `E`, competition-aggregates | ||
| that batch **unioned with every still-active positive lattice score** | ||
| (`kind = 'score' AND score > 0`), signs the full expected set | ||
| (`NoScore(NotAttempted)` for everyone else), submits it, and advances the | ||
| per-netuid emit cursor (`prism_emit_cursor`, migration 0012). This fixes the | ||
| two acceptance-epoch bugs: independent scorers finalized in the same epoch | ||
| used to lock each other out (gateway leaves are append-only first-write-wins | ||
| per `(challenge, epoch, hotkey)`), and a submission accepted in epoch `X` but | ||
| finalized in `X+k` (prod trains up to 6h ≫ 72-min epochs) never scored at | ||
| all. | ||
| Exactly-once **outbox assignment** per scoring run: batch assignment is sticky | ||
| before submit, the cursor advances only after the full set landed, and a crash | ||
| mid-submit replays the identical assigned set on the next tick | ||
| (first-write-wins with identical values converges). After assignment, a | ||
| positive `Score(v>0)` keeps participating in every later epoch's competition | ||
| set until a better/valid score supersedes it via lattice `max` (not WTA) — so | ||
| an empty or reject-only fresh batch does not burn the prism share. `Score(0)` | ||
| rejects and `NoScore` absences do not carry. A manually retried + re-scored | ||
| row re-enters the outbox (`reset_for_retry` clears the watermark); its old | ||
| leaf stays immutable history in its original epoch. Epochs during a master | ||
| outage carry no *new* outbox rows; the first epoch after recovery still | ||
| includes active positive scores plus any backlog (seals always pin fresh | ||
| epochs — stale bundles can never Match on-chain). Run **exactly one** | ||
| prism-challenge emitter instance per netuid (single master topology). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Align the competition-credit wording with score carry.
The next section still defines challenger and architecture-owner credit from the epoch batch. emit_rows now passes the union of the batch and active scores to competition_scores, so carried scores also affect these credits.
Replace “batch” in those credit rules with the complete competition set, or explicitly distinguish the two inputs. As per coding guidelines, “Treat normative documentation—including architecture files, frozen specifications, threat and operator-security documents, completeness status, runbooks, and external-miner/—as the source of truth for contracts, operations, and status.”
🧰 Tools
🪛 LanguageTool
[grammar] ~130-~130: Ensure spelling is correct
Context: ...in epochs) never scored at all. Exactly-once outbox assignment per scoring run: ...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/PRISM.md` around lines 113 - 143, Update the competition-credit rules in
the next section of docs/PRISM.md to use the complete competition set passed by
emit_rows to competition_scores, including carried active positive scores,
rather than only the epoch outbox batch. Explicitly distinguish batch assignment
from the unioned competition input while preserving the normative documentation
wording.
Source: Coding guidelines
Summary
max(lattice-proportional, not WTA).Score(0)) burned the prism share after a prior winner had already been stamped withemitted_epoch.BUNDLE_SPEC.Test plan
cargo test -p prism-emit -p prism-storeScorecargo fmt --check, clippy on touched crates,external-docs-check,loc-capprism-challengeonly (no gateway/metagraph/real-seal churn)Summary by CodeRabbit
New Features
Documentation