Skip to content

feat(proof): Proof challenge + dynamic topics + RLM judge digest pin - #209

Merged
echobt merged 3 commits into
mainfrom
cursor/proof-challenge-86c8
Sep 4, 2026
Merged

feat(proof): Proof challenge + dynamic topics + RLM judge digest pin#209
echobt merged 3 commits into
mainfrom
cursor/proof-challenge-86c8

Conversation

@echobt

@echobt echobt commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the fifth live challenge proof (2000 bps) with dynamic operator-published topics and a digest-pinned RLM judge. Topics are signed research problems (topic_id), not a frozen catalog in git. The eval image pin (config/proof-pin.toml) ships with an empty eval_image_digest until CI publishes one — live submits fail closed with 503. Do not invent a sha256.

Emission retune (sum 10000): relearn 3000, relearn-image 1000, relearn-agent 1000, bounty 3000, proof 2000. Trust root re-signed with the existing throwaway owner key ceremony (config/CEREMONY.md). Existing challenge public keys were kept; only shares + the new proof row + a new throwaway owner pubkey.

Paid score is the mean of per-topic lattices over currently open topics. Empty open set → NoScore(ChallengeInternal), not a paid 0.

What landed

  • Crates: proof-task, proof-score, proof-store, proof-eval, proof-http, proof-harvest, proof-challenge + bins/proof-challenge on :8100
  • Pin: config/proof-pin.toml (topic_pubkey matches the trust-root proof row; empty eval digest)
  • Deploy: compose :8100 / local :28100, Dockerfile target, images.yml, PROOF_FORCE_SIM banned on droplet overlays
  • xtask: proof-holdout, proof-topic, external-docs-check pins for proof.md
  • Docs: docs/PROOF.md, docs/external-miner/proof.md, AGENTS / NAMING / COMPLETENESS
  • Site: ArenaSlug::Proof listed with scoring reproduced
  • CI unblock: Cargo.lock wnaf 0.14.0 → 0.14.1 (yanked today via primeorder/p256/dcap-qvl)

No Modal. No secrets/mnemonics in git. There is no bins/ctx in this repo.

Greptile

Every PR is reviewed by Greptile before merge. Config: .greptile/.

  • Greptile has reviewed this PR; findings are fixed or answered
  • If the bot was silent, I commented @greptileai review (echobt already requested)

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • cargo test -p trustroot --test trustroot_verify s9_repo_config_loads_when_present (5 rows, 3000/1000/1000/3000/2000, proof pk 3ea26595…)
  • cargo run -p xtask -- loc-cap
  • cargo run -p xtask -- consensus-lint
  • cargo run -p xtask -- spec-check
  • cargo run -p xtask -- design-check
  • cargo run -p xtask -- external-docs-check
  • cargo deny check (local 0.20.2: advisories/bans/licenses/sources ok after wnaf 0.14.1)
  • ./deploy/scripts/assert-compose-matrix.sh (docker not installed here)

Risk

Emission impact: live shares change (relearn 4000→3000, image/agent 1500→1000, proof 2000). Seal D23 will fail until every challenge still covers E. Trust root: new throwaway owner pubkey; production rotation still follows CEREMONY.md with the offline owner key. Eval image: empty digest is intentional pre-launch 503. No Modal. No secrets/mnemonics in git. PROOF_FORCE_SIM is local/CI only and banned on droplet overlays.

Naming

I did not rename BASE_* environment variables, deployed host paths
(/opt/base, /run/base, …), GHCR baseintelligence/base package names, or
base-*-v1 cryptographic domain tags, unless this PR’s purpose is a coordinated
cutover documented in docs/NAMING.md.

Open in Web Open in Cursor 

cursoragent and others added 2 commits September 3, 2026 21:12
Introduce the fifth live challenge (`proof`, 2000 bps) with operator-published
signed topics, a digest-pinned RLM judge (empty digest fails closed), and
throwaway trust-root re-sign of the five-row emission split.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Keep Proof HTTP tests compiling under -D warnings, list the proof
arena on the site, and match the five-row trust-root emission set.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
@echobt
echobt marked this pull request as ready for review September 3, 2026 21:24
@echobt

echobt commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai review

primeorder 0.14.0 (via p256/dcap-qvl) pulled wnaf 0.14.0, yanked today
in favor of 0.14.1. Smallest lockfile bump to keep cargo-deny green.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
@echobt

echobt commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

CI after wnaf bump: deny cleared; failure is unrelated flake design-challenge::screenshot::tests::capture_success_full_pipeline (None vs fake PNG). Re-running failed jobs.

@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds the Proof challenge service, scoring, signed topics, and deployment integration. Validation reproduced three failures that block reliable production operation: submissions can be credited to an arbitrary miner and trigger live scoring without a bound payer, the service never emits signed epoch leaves to a gateway, and topic availability is permanently evaluated at epoch zero. These issues undermine score integrity and prevent Proof results from participating in epoch sealing.

Confidence Score: 1/5

The change is not safe to merge until submission identity and payer binding, epoch-aware topic evaluation, and signed-leaf delivery are implemented.

Direct execution reproduced arbitrary-hotkey attribution, confirmed that the running service has no reachable emission handoff, and demonstrated that the same signed topic fails at epoch zero but succeeds during its configured validity window.

Files Needing Attention: crates/proof-http/src/lib.rs needs authenticated miner and payer binding; bins/proof-challenge/src/main.rs needs live epoch wiring and production leaf-emission orchestration.

Security Review

The submission endpoint allows a caller to provide another miner's hotkey without proving ownership or presenting a payer credential bound to that miner. The service accepts the request, invokes live Lium scoring, and stores the resulting lattice under the selected hotkey, enabling unauthorized score attribution and rental consumption.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced proofs for posted P1 findings, including a focused unauthenticated hotkey attribution test, with supporting harness sources and runtime outputs.
  • The team documented end-to-end harnesses for the emission workflow, including startup-to-emission steps and startup status checks, with related logs.
  • Epoch-regression tests were executed, validating behavior at immutable epoch zero and at the current valid epoch seven, with explicit wiring locations and cleanup verification.
  • In-router API end-to-end validation was performed using an attacker authorization value and a victim-controlled hotkey, demonstrating expected response states and persistence behavior.
  • Additional end-to-end validations were performed for startup-emission state and epoch predicate enforcement, supported by multiple proofs documenting sources, outputs, and provenance.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (3)

  1. General comment

    P1 Submission endpoint lets callers score an arbitrary miner hotkey

    • Bug
      • POST /v1/submissions accepts a caller-provided miner_hotkey without authenticating ownership or binding it to a Lium payer. A runtime request with an untrusted Authorization token and no X-Lium-Api-Key returned 201 Created, invoked live Lium scoring once, stored the victim hotkey in the submission, and wrote its topic lattice as 1000000.
    • Cause
      • crates/proof-http/src/lib.rs:179 only parses the supplied hotkey as hex. Lines 181-184 merely compute unused _lium_present; no submission authentication, hotkey signature, or payer identity check follows. The untrusted hotkey is persisted at lines 383-407, especially record_topic_score(&row.miner_hotkey, &topic_id, lattice) at lines 405-407.
    • Fix
      • Require an authenticated miner identity or a signature over the submission fields, compare that verified identity with miner_hotkey, and bind the Lium payment credential/account to that verified hotkey before unsealing holdout or invoking the live scorer.

    T-Rex Ran code and verified through T-Rex

  2. General comment

    P1 Proof challenge startup never emits or delivers signed epoch leaves

    • Bug
      • The service startup path initializes a MemoryStore, constructs AppState, then starts only the Axum HTTP router. It neither obtains the required expected-hotkey/epoch inputs nor invokes emit_epoch; it also has no gateway/aggregator submission client or endpoint. The actual server was run and returned HTTP 404 for an emission request, while status stayed unchanged after requests. Consequently, accepted/scored Proof submissions remain local in process and no signed Proof leaves are supplied for D24 epoch sealing.
    • Cause
      • emit_epoch and store_scores were implemented as library helpers but were never wired into a production scheduler, shutdown/epoch transition, HTTP admin handler, or outbound leaf submission path. main.rs validates challenge_sk_file only and discards the loaded secret, so signing material is unavailable after initialization as well.
    • Fix
      • Add a production emission orchestration path that retains the challenge secret, receives/pins epoch and expected hotkeys, obtains store_scores and open topics, invokes emit_epoch, and submits the complete signed leaf set to the configured gateway/aggregator with retry/idempotency and observability. Exercise it with an integration test that starts the binary (or equivalent application wiring), scores a submission, triggers one epoch, and verifies gateway receipt plus successful seal.

    T-Rex Ran code and verified through T-Rex

  3. General comment

    P1 Proof challenge service permanently evaluates topic windows at epoch zero

    • Bug
      • The proof-challenge operator binary initializes AppState.epoch to 0 and never supplies a current epoch. Topics valid only at later epochs are rejected before evaluation and are omitted from the service's open/scorable topic calculations.
    • Cause
      • bins/proof-challenge/src/main.rs:137 hard-codes epoch: 0, while the HTTP submission and store scoring paths consistently call is_open_at(st.epoch) / is_open_at(epoch).
    • Fix
      • Wire AppState.epoch to the current authoritative chain epoch and refresh it as epochs advance; add a permanent regression test covering a topic with a nonzero validity window through the operator/service configuration path.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix(proof): satisfy clippy and site aren..." | Re-trigger Greptile

Comment on lines +179 to +184
let hotkey = parse_hex64(&body.miner_hotkey, "miner_hotkey")?;
let artifact = parse_hex64(&body.artifact_digest, "artifact_digest")?;
let _lium_present = headers
.get("x-lium-api-key")
.and_then(|v| v.to_str().ok())
.is_some_and(|s| !s.is_empty());

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 security Submission identity is unauthenticated

POST /v1/submissions accepts a caller-selected miner_hotkey without verifying that the caller owns it or binding it to a Lium payer. A request using an untrusted authorization value, no X-Lium-Api-Key, and a victim hotkey returned 201 Created, invoked live scoring, persisted the victim hotkey, and wrote that miner's topic lattice score. This permits score attribution or overwrites under another miner identity while consuming rental work without a caller-bound payment credential.

Require a verified miner identity or signature over the submission, require it to match miner_hotkey, and bind the Lium credential or account to that verified identity before invoking live evaluation.

Artifacts

Focused unauthenticated hotkey attribution test source

  • The executed Rust test builds a live-Lium-configured in-router application, submits an attacker artifact under a victim hotkey without a Lium key, and asserts the resulting attribution and score write; the takeaway is that it directly exercises only the claimed missing binding.

Before and after hotkey validation harness source

  • The executed shell harness injects the focused test into clean archives of parent `cebceda` and current `HEAD`, then runs it against both revisions; the takeaway is that it provides a same-scope before/after comparison.

Runtime output for unauthenticated victim-hotkey submissions before and after

  • The captured command output records exit code 0 and passing endpoint tests on both revisions: POST returned 201 with no message, GET returned 200 with no message, one live score call occurred, and the victim lattice was written as 1000000; the takeaway is that the failure path is confirmed and unchanged across the comparison.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment on lines +304 to +321
async fn serve(bind: SocketAddr, state: AppState) -> Result<(), String> {
let app = proof_router(state);
let listener = TcpListener::bind(bind)
.await
.map_err(|e| format!("bind {bind}: {e}"))?;
tracing::info!(
%bind,
challenge_id = CHALLENGE_ID,
scoring_version = SCORING_VERSION,
"proof-challenge listening"
);
axum::serve(listener, app)
.with_graceful_shutdown(async {
let _ = tokio::signal::ctrl_c().await;
})
.await
.map_err(|e| e.to_string())
}

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 Proof leaves are never emitted

The production entrypoint builds the HTTP application and waits on axum::serve, but never invokes proof_challenge::emit_epoch or delivers signed leaves to a gateway. The emission helper has only test call sites. As a result, scored Proof submissions remain in the local store and the Proof challenge cannot provide the signed leaves required for its trust-root share during epoch sealing.

Wire an epoch-aware production emission path that retains the signing key, generates the complete leaf set, submits it to the configured gateway with retry and idempotency, and covers the startup-to-gateway handoff with an integration test.

Artifacts

Focused Proof startup-to-emission harness source

  • The authored executable harness starts the compiled Proof service, calls status and submission APIs, probes an emission route, and compares final status; the takeaway is that the executed scope directly covers startup through the absent emission handoff.

Proof service startup status before submission

  • The real proof-challenge binary was started without configured inputs and queried before any submission, showing it only serves HTTP state with no emission activity; the takeaway is that startup itself creates no signed Proof leaves.

Proof service status after submission and emission request

  • The real service received a submission attempt and a POST to the candidate emission route, returned HTTP 400 then HTTP 404, and retained identical status; the takeaway is that the startup-to-request path has no emission endpoint or state transition.

Proof emission helper call-site search

  • The executed repository-wide Rust call-site search lists the Proof helper definition and only its unit-test invocations, with no production wiring from the binary, router, or gateway; the takeaway is that signed Proof emission is unreachable in production.

Targeted Proof package test output

  • The targeted Proof library, HTTP, and binary test suites completed with 18 passing tests; the takeaway is that existing tests validate helpers and HTTP scoring but do not validate an end-to-end emission handoff.

View artifacts

T-Rex Ran code and verified through T-Rex

backend,
live_scorer,
admin_hashes: Arc::new(load_admin_hashes(cli.admin_tokens_file.as_deref())),
epoch: 0,

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 Topic epoch remains zero

The service initializes AppState.epoch to 0 and never refreshes it from the authoritative epoch. Submission and scoring paths use this value for is_open_at, so a topic valid only at a later epoch is permanently treated as closed. A signed topic valid in epochs 7–9 returned 400 topic is not open at epoch 0 but returned an eligible 201 through the identical request path at epoch 7.

Source the current epoch from the authoritative chain and refresh it as epochs advance; retain a regression test that exercises a nonzero topic validity window through the service wiring.

Artifacts

Temporary nonzero epoch window regression test source

  • The complete temporary test creates a signed topic valid only in epochs 7–9 and submits through the Axum router at epochs 0 and 7, with the takeaway.

Submission at immutable epoch zero

  • Executed `PROOF_EPOCH_PROBE=zero cargo test -p proof-http nonzero_window_rejects_at_epoch_zero_and_accepts_at_current_epoch -- --nocapture` in `/home/user/repo` and captured HTTP 400 `topic is not open`, with the takeaway.

Submission at current valid epoch seven

  • Executed `cargo test -p proof-http nonzero_window_rejects_at_epoch_zero_and_accepts_at_current_epoch -- --nocapture` in `/home/user/repo` and captured the matching HTTP 201 eligible submission at epoch 7, with the takeaway.

Exact epoch wiring and evaluation source locations

  • Captured numbered source locations for the hard-coded operator epoch, HTTP submission gate, status/scoring selection, store filters, and topic predicate, with the takeaway.

Temporary regression test cleanup verification

  • Executed `git diff --exit-code -- crates/proof-http/src/lib.rs` after validation and confirmed exit code 0, showing the temporary test left no source modification, with the takeaway.

View artifacts

T-Rex Ran code and verified through T-Rex

@echobt
echobt merged commit ed17664 into main Sep 4, 2026
5 of 6 checks passed
@echobt
echobt deleted the cursor/proof-challenge-86c8 branch September 4, 2026 04:15
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.

2 participants