Repository navigation
feat(proof): lock emission 2000/8000 and add WTA/discovery payouts - #220
Conversation
Lock the live trust root at bounty 2000 / proof 8000 (20%/80%) regardless of eval digest. Proof still 503s until a digest is pinned; do not invent one. Re-sign challenges.toml + staging twin + measurements with a throwaway owner ceremony. Topics now carry signed payout_mode (wta|discovery), English validation (score_on/accept_if/reject_if), and discovery floor/novelty shares. Epoch scoring sums per-topic masses: WTA winner-only (exact ties split), discovery pass-floor + novelty vs sealed baseline/champion. Empty open set is NoScore(ChallengeInternal). Operator POST /v1/admin/proof/topics accepts the full signed document. xtask proof-topic accepts YAML/JSON drafts and fills the holdout commitment. ctx proof submit sends claim + declared_flops. listed custom id harness_success_rate publishes and fail-closes until a real harness exists. Co-authored-by: Mathis <echobt@users.noreply.github.com>
Greptile SummaryThis change adds Proof payout calculations and topic-run tracking, but three payout-critical paths are incomplete or incorrect: the running service never emits signed Proof leaves, duplicate novelty ownership is chosen by hotkey order rather than claimant provenance, and later topic submissions can erase earlier qualifying results. These failures must be fixed before merging. Confidence Score: 2/5Unsafe to merge: accepted Proof work may never be emitted, and payout ownership or eligibility can be lost or assigned incorrectly. Three independently reproduced payout failures affect the production emission path, duplicate attribution, and persisted submission selection. Files Needing Attention: crates/proof-challenge/src/lib.rs, crates/proof-score/src/payout.rs, and crates/proof-store/src/lib.rs
What T-Rex did
|
| fn mark_digest_duplicates(passers: &mut [(String, MinerTopicRun)]) { | ||
| passers.sort_by(|a, b| a.0.cmp(&b.0)); | ||
| let mut seen: BTreeMap<String, String> = BTreeMap::new(); | ||
| for (miner, run) in passers.iter_mut() { | ||
| let digest = run.artifact_digest.trim().to_ascii_lowercase(); | ||
| if digest.is_empty() { | ||
| continue; | ||
| } | ||
| if let Some(first) = seen.get(&digest) { | ||
| if first != miner { | ||
| run.near_duplicate = true; | ||
| } | ||
| } else { | ||
| seen.insert(digest, miner.clone()); | ||
| } | ||
| } |
There was a problem hiding this comment.
For passing Discovery submissions with the same artifact digest, this code sorts miners by hotkey and treats the first one as the novelty owner. That is unrelated to when the artifact was submitted or otherwise proven to belong to a miner, so a later copier with a lexicographically earlier hotkey can receive the novelty reward while the original claimant receives only the pass floor. Select the owner using validated submission provenance instead of hotkey order.
Artifacts
- Authored executable source invokes the changed public payout API with identical-digest passers in reversed provenance orders, showing that hotkey ordering determines novelty ownership.
- Authored shell command source creates the temporary Cargo manifest and runs the exact focused executable against the repository crates.
- Executed output for the zulu-first provenance case exited 0 and shows alpha still received 850000 while zulu received 150000, proving provenance order did not control novelty.
- Executed output for the alpha-first provenance case exited 0 and shows the same alpha=850000 and zulu=150000 payout, confirming the comparison result.
| pub fn record_topic_run( | ||
| &self, | ||
| hotkey: &str, | ||
| topic_id: &str, | ||
| run: MinerTopicRun, | ||
| ) -> Result<(), StoreError> { | ||
| self.lock()? | ||
| .scores | ||
| .entry(hotkey.to_owned()) | ||
| .or_default() | ||
| .insert(topic_id.to_owned(), lattice); | ||
| .insert(topic_id.to_owned(), run); | ||
| Ok(()) |
There was a problem hiding this comment.
record_topic_run stores one value for each hotkey and topic, unconditionally replacing the previous value. A miner can submit a later failed or worse run that replaces an earlier passing result before payout calculation, causing an earned payout to disappear. The storage key and method also contain no epoch, so attempts are not isolated to the epoch being paid. Retain the best eligible run per epoch, hotkey, and topic, or reject inferior follow-up submissions.
Knowledge Base Used: Challenge network and submission lifecycle
Artifacts
- The exact authored Rust program compiled against the actual proof-store crate; it records an initial passing run and then a later failing run for the same hotkey and topic.
- The exact authored shell command source used to build proof-store, compile the Rust harness, and capture both executions.
- The first executed harness capture shows one stored passing result with primary 1.0 before any later submission.
- The second executed harness capture shows the same single entry now holds the later failing result, proving overwrite and no epoch scope.
- The captured zero-context diff identifies the changed store implementation and HTTP persistence call sites; the takeaway is that all paths invoke the unscoped overwrite method.
Summary
Locks live emission at bounty 2000 / proof 8000 (20%/80%, sum 10000) and makes Proof topics carry two payout modes plus English validation so Mathis can inject research challenges from the operator path.
This is the control-plane half of the Mathis lock. Proof still 503s until a real
eval_image_digestis pinned. Do not invent a digest — that pin is owned by Développeur (bc-898689d3). This PR leaves the digest empty.Emission
config/challenges.toml+ staging twin: two rows, same pubkeys, bounty 2000 / proof 8000.challenges.toml,challenges.staging.toml, andmeasurements.toml(secret stayed in/tmp, never git).Topic schema (
crates/proof-task)Signed with the rest of the document:
payout_mode:wta|discovery(defaultdiscovery)validation.{score_on, accept_if, reject_if}— English criteria the RLM + harness enforcediscovery.{pass_floor_share_bps, novelty_pool_share_bps}— default 3000/7000, must sum to 10000; ignored forwtametric.familynll|throughput|customunchanged. v0supported_custom()listsharness_success_rateso the agent-harness topic publishes; scoring fail-closes until a real harness fillscustom_value.dt-no-ib-v0remains the throughput wta example.Scoring (
crates/proof-score)Pass gates unchanged (fail-closed). After pass:
pass=truethis epoch takes 100% of that topic’s mass. Exact ties split equally. Non-winners get 0 on that topic.NoScore(ChallengeInternal).Operator inject path
POST /v1/admin/proof/topicsaccepts the full signed document (English statement + validation + payout_mode + metric).GET /v1/proof/topicslists published topics.xtask proof-topicaccepts YAML/JSON drafts, fills holdout commitment (--syntheticor--holdout), and signs.Miner docs +
ctx proof submitnow sendclaimanddeclared_flops. Artifact is a reproducible train/eval recipe under budget, not weights-only. Verdict is the agent envelope after eval.Fail-closed (unchanged)
Empty
eval_image_digest→ 503. NoFORCE_SIMon droplets. No invented sha256. No Modal. No secrets in git.proxy_modelmay stay empty until the image exists.Stacking
If Développeur’s digest/harvest PR also touches
challenges.tomlorproof-tasktopic schema, rebase that PR onto this one. This PR does not publish a proof-eval image.Greptile
Every PR is reviewed by Greptile before merge. Config:
.greptile/.@greptileai reviewTest plan
cargo fmt --allcargo clippy -p proof-task -p proof-score -p proof-store -p proof-eval -p proof-http -p proof-challenge -p proof-harvest -p ctx -p xtask -p site-api -p site-data -p site-types --all-targets -- -D warningscargo test -p proof-task -p proof-score -p proof-store -p proof-eval -p proof-http -p proof-challenge -p proof-harvest -p ctx -p xtask -p trustroot -p site-api -p site-data -p site-typescargo run -p xtask -- loc-capcargo run -p xtask -- external-docs-checkcargo test --workspace(not run here; focused proof/site/trustroot/xtask/ctx subset above)Tests cover WTA winner-only, equal-tie WTA, discovery floor+novelty (duplicates get floor only), empty open →
NoScore,harness_success_ratepublish + fail-closed score, YAML topic draft parse, and trust-root 2000/8000 verify.Risk
Emission impact: Proof now holds 80% of the subnet. Until a digest is pinned, that 8000 bps still cannot score (503 /
NoScore) and burns rather than paying. Challenge pubkeys were not rotated — only the throwaway owner key and emission bps. NoBASE_*renames, no domain-tag changes, no digest invention.Naming
I did not rename
BASE_*environment variables, deployed host paths (/opt/base,/run/base, …), GHCRbaseintelligence/basepackage names, orbase-*-v1cryptographic domain tags.