Skip to content

fix(design): split manual vs scheduled run quota; harden self-sim exclusion - #76

Merged
echobt merged 1 commit into
mainfrom
fix/design-quota-selfsim
Aug 7, 2026
Merged

fix(design): split manual vs scheduled run quota; harden self-sim exclusion#76
echobt merged 1 commit into
mainfrom
fix/design-quota-selfsim

Conversation

@echobt

@echobt echobt commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Miner was right: DAILY_RUN_QUOTA=10 charged every sandbox run while schedule is 10 rounds × 3 prompts = 30 scheduled runs/day → honest harness locked out after ~3 rounds
  • Fix: RunOrigin::{Manual,Scheduled}; manual quota 10/day; scheduled cap = schedule × headroom (default 60)
  • Same-hotkey revisions: already partly excluded; centralized in corpus.rs so v2 isn't flagged as copy of own v1; cross-hotkey copies still caught
  • Migration 0013_design_quota_manual.sql required on deploy

Test plan

  • Full-day scheduled participation never quota-blocked
  • Manual spam still blocked at 10
  • Same-hotkey resubmission not self-copy flagged
  • Cross-hotkey copy still flagged
  • Apply migration 0013 on design-challenge deploy
  • Gates already green on branch

Summary by CodeRabbit

  • New Features

    • Separated daily limits for manual submissions and scheduled runs.
    • Added quota reporting for total, manual, and scheduled usage, limits, and remaining capacity.
    • Scheduled runs now support expanded daily capacity without consuming the manual quota.
    • Improved anti-cheat comparisons by excluding a miner’s own previous harness versions.
  • Bug Fixes

    • Prevented scheduling beyond available quota and clarified related error reporting.
  • Documentation

    • Updated quota rules, API guidance, troubleshooting, and checklist documentation.

Organizer-scheduled round runs were sharing the 10/day anti-spam ceiling with
POST /v1/harness, so a full day of 10×3 runs locked honest harnesses out after
~3 rounds. Charge manual and scheduled work separately, and keep same-hotkey
revisions out of the copy-gate/review corpus so self-iteration is not cheat.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR separates manual and scheduled run quotas across configuration, storage, scheduling, and reporting. It also centralizes anti-cheat corpus construction so self-owned harnesses are excluded from copy detection and review comparisons.

Changes

Origin-aware quota accounting

Layer / File(s) Summary
Quota contracts and accounting
crates/db/migrations/..., crates/design-challenge-task/src/lib.rs, crates/design-store/..., crates/design-db/src/lib.rs, crates/design-challenge/src/lib.rs
Quota configuration derives separate manual and scheduled limits. Database and store APIs persist and return total and manual usage by RunOrigin.
Origin-aware scheduling and reporting
crates/design-http/src/api.rs, crates/design-http/src/stats.rs, crates/design-challenge/src/orchestrator.rs
Scheduling applies origin-specific caps, charges usage by origin, rejects incomplete prompt batches, and reports separate quota values.
Quota requirements and documentation
docs/DESIGN_CHALLENGE.md, docs/DESIGN_CHALLENGE_CHECKLIST.md, docs/external-miner/design.md, docs/external-miner/troubleshoot.md
Documentation and content checks describe manual and scheduled quotas, reporting fields, and reset behavior.

Shared anti-cheat corpora

Layer / File(s) Summary
Corpus selection rules and tests
crates/design-challenge/src/corpus.rs
The shared module builds gate and review corpora. It filters self-owned harnesses case-insensitively, applies timestamp rules, and always includes the baseline for review.
Corpus integration and regression coverage
crates/design-challenge/src/orchestrator.rs, crates/design-challenge/tests/cheat_fixtures.rs, docs/DESIGN_CHALLENGE.md, docs/external-miner/design.md, xtask/src/design_check.rs
The orchestrator uses the shared corpora for copy gating and agentic review. Tests verify self-revisions remain clean and cross-owner copies are detected.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Miner
  participant DesignHTTP
  participant DesignStore
  participant DesignDatabase
  Miner->>DesignHTTP: submit harness
  DesignHTTP->>DesignStore: check manual quota
  DesignStore->>DesignDatabase: read quota usage
  DesignDatabase-->>DesignStore: return total and manual usage
  DesignHTTP->>DesignStore: schedule manual run
  DesignStore->>DesignDatabase: increment origin usage
  DesignHTTP-->>Miner: return schedule or quota response
Loading
sequenceDiagram
  participant Orchestrator
  participant HarnessStore
  participant Corpus
  participant CopyGate
  participant AgenticReview
  Orchestrator->>HarnessStore: fetch recent harnesses
  HarnessStore-->>Orchestrator: return candidate and recent rows
  Orchestrator->>Corpus: build gate corpus
  Corpus-->>CopyGate: return other-owner harnesses
  Orchestrator->>Corpus: build review corpus
  Corpus-->>AgenticReview: return baseline and earlier other-owner harnesses
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes both primary changes: separate manual and scheduled quotas and stronger self-simulation exclusion.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/design-quota-selfsim

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🧹 Nitpick comments (7)
docs/DESIGN_CHALLENGE_CHECKLIST.md (1)

47-49: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Pin the full quota and corpus semantics.

design-check currently requires only DESIGN_SCHEDULED_DAILY_RUN_CAP and other hotkeys' prior art only. Add markers for SCHEDULED_DAILY_RUN_HEADROOM, the default 60-run calculation, and strict earlier created_at ordering. Otherwise, a future specification edit can remove these rules while the check remains green.

As per coding guidelines, normative documentation is the source of truth for contracts and must protect the complete contract.

🤖 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/DESIGN_CHALLENGE_CHECKLIST.md` around lines 47 - 49, Update the
design-check contract markers in the checklist table to require
SCHEDULED_DAILY_RUN_HEADROOM, the default 60-run calculation, and strict earlier
created_at ordering alongside the existing quota and corpus semantics. Ensure
design-check validates all of these normative rules so removing any one causes
the check to fail.

Source: Coding guidelines

crates/design-challenge-task/src/lib.rs (1)

248-253: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The clamp test exercises env_u64, not scheduled_daily_run_cap.

Lines 250-253 set BASE_SCHEDULED_CAP_CLAMP_TEST and assert that env_u64 clamps to the floor. This proves the helper, not the caller wiring. A regression that passes the wrong min argument in scheduled_daily_run_cap would still pass this test. The comment explains the reason: the process environment is global. The existing env_knob_parse_and_clamp test already covers env_u64, so this block adds little.

Consider asserting the caller instead, in a serialized test that sets and removes DESIGN_SCHEDULED_DAILY_RUN_CAP.

🤖 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/design-challenge-task/src/lib.rs` around lines 248 - 253, Replace the
direct env_u64 assertion in the clamp test with a serialized caller-level test
that sets DESIGN_SCHEDULED_DAILY_RUN_CAP below the scheduled floor, invokes
scheduled_daily_run_cap, and asserts the result equals scheduled_runs_per_day().
Remove the temporary BASE_SCHEDULED_CAP_CLAMP_TEST variable usage while
preserving environment cleanup.
crates/db/migrations/0013_design_quota_manual.sql (1)

20-21: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add the CHECK constraint as NOT VALID, then validate it separately.

ADD CONSTRAINT ... CHECK takes an ACCESS EXCLUSIVE lock and scans the whole table before the migration commits. design_quota grows with (hotkey, day) rows, so the scan cost grows over time. The two-step pattern keeps the blocking window at metadata-only.

♻️ Proposed two-step constraint
 ALTER TABLE design_quota
-    ADD CONSTRAINT design_quota_manual_runs_nonneg CHECK (manual_runs_used >= 0);
+    ADD CONSTRAINT design_quota_manual_runs_nonneg CHECK (manual_runs_used >= 0) NOT VALID;
+
+ALTER TABLE design_quota
+    VALIDATE CONSTRAINT design_quota_manual_runs_nonneg;
🤖 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/db/migrations/0013_design_quota_manual.sql` around lines 20 - 21,
Update the design_quota_manual_runs_nonneg constraint on design_quota to add the
CHECK constraint with NOT VALID, then validate that same constraint in a
separate ALTER TABLE statement. Preserve the manual_runs_used >= 0 condition and
constraint name.

Source: Linters/SAST tools

crates/design-challenge/src/lib.rs (1)

13-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Scope the new cast allowances to the sites that need them.

Lines 13 and 15 disable cast_possible_truncation, cast_sign_loss, and cast_possible_wrap for the whole crate. These lints catch real numeric defects in quota and score arithmetic. A crate-wide allow silences future occurrences that nobody reviewed. The new quota code in design-challenge-task already uses try_from with explicit fallbacks instead of raw casts, so the crate-wide suppression is broader than the change needs.

Prefer #[allow(...)] on the specific functions or expressions that require the cast.

🤖 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/design-challenge/src/lib.rs` around lines 13 - 15, Remove the
crate-level allowances for cast_possible_truncation, cast_sign_loss, and
cast_possible_wrap in lib.rs. Identify the specific reviewed cast sites that
still require suppression and apply #[allow(...)] narrowly to their containing
functions or expressions, while leaving unrelated duration_suboptimal_units,
map_unwrap_or, and result_large_err allowances unchanged.
crates/design-store/src/store.rs (2)

53-58: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

scheduled() depends on the manual <= total invariant.

scheduled() derives its value with saturating_sub. If a row ever holds manual > total, the method reports 0 scheduled runs and widens the scheduled budget instead of narrowing it. Both write paths keep the invariant today: quota_bump always raises total, and raises manual only in addition. The DB CHECK in 0013_design_quota_manual.sql guards only non-negativity, not manual_runs_used <= runs_used.

Consider adding that second CHECK to the migration so the database enforces the invariant that this method assumes.

🛡️ Proposed additional constraint in the migration
ALTER TABLE design_quota
    ADD CONSTRAINT design_quota_manual_le_total
    CHECK (manual_runs_used <= runs_used) NOT VALID;

ALTER TABLE design_quota
    VALIDATE CONSTRAINT design_quota_manual_le_total;
🤖 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/design-store/src/store.rs` around lines 53 - 58, Add a database
constraint in migration 0013_design_quota_manual.sql enforcing manual_runs_used
<= runs_used, using the proposed NOT VALID creation followed by validation.
Preserve the existing non-negativity checks and ensure the constraint is applied
to design_quota so QuotaUsage::scheduled can rely on its invariant.

1083-1089: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use or_default() for the default QuotaUsage entry.

QuotaUsage derives Default, so or_default() is the direct form for HashMap::Entry::or_default().

♻️ Proposed simplification
         let e = m
             .entry((miner.to_owned(), day.to_owned()))
-            .or_insert_with(QuotaUsage::default);
+            .or_default();
🤖 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/design-store/src/store.rs` around lines 1083 - 1089, In the quota
usage update block, replace the `or_insert_with(QuotaUsage::default)` call on
the `(miner.to_owned(), day.to_owned())` entry with `or_default()`, preserving
the existing `e.total` and `e.manual` updates.

Source: Coding guidelines

crates/design-http/src/api.rs (1)

510-521: 🔒 Security & Privacy | 🔵 Trivial

The cap check and the charge are not atomic.

Line 515 compares the cap against a value read at line 483. Lines 559-561 charge the quota one run at a time inside the loop. Two concurrent requests for the same hotkey and day can both pass the check and then both charge, so the combined usage exceeds the origin cap by up to prompts_per_round runs per racing request.

The exposure is bounded today: post_harness gates a hotkey after its first accepted submission, and the scheduled cap carries 2× headroom. The race predates this change; moving the check from per-prompt to up-front widens the window slightly.

For a strict ceiling, make the database perform the conditional charge in one statement, for example an upsert whose DO UPDATE carries a WHERE runs_used + $3 <= $cap predicate, and treat "no row returned" as a refusal.

🤖 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/design-http/src/api.rs` around lines 510 - 521, The quota validation
in post_harness is separate from the per-prompt charges, allowing concurrent
requests to exceed the origin cap. Replace the check-and-charge flow around
origin_daily_cap, the upfront needed calculation, and the loop’s quota update
with a single database conditional upsert whose update predicate only succeeds
when the full prompt count remains within cap; treat no affected/returned row as
a quota refusal, then proceed with prompt creation only after the atomic charge
succeeds.
🤖 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/design-challenge-task/src/lib.rs`:
- Around line 237-247: Allow clippy::unwrap_used within the #[cfg(test)] mod
tests module in lib.rs, or replace its unwrap() calls with equivalent
non-panicking handling; preserve the existing test assertions and behavior.

In `@crates/design-challenge/src/orchestrator.rs`:
- Around line 799-805: Update MemoryDesignStore::list_recent_harnesses to order
harnesses by created_at_ms descending before applying the limit, matching the
documented newest-first behavior and SQL adapter ordering. Preserve the existing
limit and return type so gate_corpus receives the most recent harnesses
consistently across adapters.

In `@crates/design-challenge/tests/cheat_fixtures.rs`:
- Around line 94-160: The existing test only exercises corpus helpers and
SimAgent directly; add a master challenge service end-to-end regression test
covering both self-revision and cross-hotkey copy submissions. Submit each
harness through master intake, poll /events and /logs, verify the self-revision
reaches challenge-specific scoring, emits a leaf, seals a bundle, and reports
sealed: true, and verify the cross-hotkey copy is rejected through the same
path; do not rely on static page fixtures as execution evidence.

In `@crates/design-http/src/api.rs`:
- Around line 640-644: Update the manual quota response in the quota-building
logic around manual_limit and used.manual so manual.remaining reports only
spendable whole prompt sets, matching the all-or-nothing prompts_per_round()
scheduling behavior. Reuse the same quota and round-size values used by
submission validation, while preserving the existing limit and runs_used fields.

In `@crates/design-http/src/stats.rs`:
- Around line 98-100: The daily_run_quota wire field is a sum of separate manual
and scheduled caps, not a single enforced refusal limit. In the stats
serialization around daily_run_quota(), manual_daily_run_quota(), and
scheduled_daily_run_cap() in crates/design-http/src/stats.rs lines 98-100,
rename or clearly document the field as an aggregate, or replace it with an
unused summary field; update the corresponding definition or use in
crates/design-challenge/src/lib.rs lines 31-34 as needed so both sites expose
the same meaningful contract.

In `@docs/external-miner/design.md`:
- Around line 130-136: Update docs/external-miner/design.md lines 130-136 to
identify 10 manual runs/day and 60 scheduled runs/day as configurable defaults,
name the corresponding operator overrides, and retain the 10-round × 3-prompt
calculation. Update docs/external-miner/troubleshoot.md line 12 to replace the
fixed 10/day wording with the manual quota default and instruct miners to check
manual.limit and manual.remaining.

In `@xtask/src/design_check.rs`:
- Line 41: Update the design-check content pins near
DESIGN_SCHEDULED_DAILY_RUN_CAP to separately require the scheduled quota
formula, configurable headroom setting, and default headroom value of 60. Keep
the manual quota pin independent, and source the required wording from the
normative documentation so the check validates the complete contract.

---

Nitpick comments:
In `@crates/db/migrations/0013_design_quota_manual.sql`:
- Around line 20-21: Update the design_quota_manual_runs_nonneg constraint on
design_quota to add the CHECK constraint with NOT VALID, then validate that same
constraint in a separate ALTER TABLE statement. Preserve the manual_runs_used >=
0 condition and constraint name.

In `@crates/design-challenge-task/src/lib.rs`:
- Around line 248-253: Replace the direct env_u64 assertion in the clamp test
with a serialized caller-level test that sets DESIGN_SCHEDULED_DAILY_RUN_CAP
below the scheduled floor, invokes scheduled_daily_run_cap, and asserts the
result equals scheduled_runs_per_day(). Remove the temporary
BASE_SCHEDULED_CAP_CLAMP_TEST variable usage while preserving environment
cleanup.

In `@crates/design-challenge/src/lib.rs`:
- Around line 13-15: Remove the crate-level allowances for
cast_possible_truncation, cast_sign_loss, and cast_possible_wrap in lib.rs.
Identify the specific reviewed cast sites that still require suppression and
apply #[allow(...)] narrowly to their containing functions or expressions, while
leaving unrelated duration_suboptimal_units, map_unwrap_or, and result_large_err
allowances unchanged.

In `@crates/design-http/src/api.rs`:
- Around line 510-521: The quota validation in post_harness is separate from the
per-prompt charges, allowing concurrent requests to exceed the origin cap.
Replace the check-and-charge flow around origin_daily_cap, the upfront needed
calculation, and the loop’s quota update with a single database conditional
upsert whose update predicate only succeeds when the full prompt count remains
within cap; treat no affected/returned row as a quota refusal, then proceed with
prompt creation only after the atomic charge succeeds.

In `@crates/design-store/src/store.rs`:
- Around line 53-58: Add a database constraint in migration
0013_design_quota_manual.sql enforcing manual_runs_used <= runs_used, using the
proposed NOT VALID creation followed by validation. Preserve the existing
non-negativity checks and ensure the constraint is applied to design_quota so
QuotaUsage::scheduled can rely on its invariant.
- Around line 1083-1089: In the quota usage update block, replace the
`or_insert_with(QuotaUsage::default)` call on the `(miner.to_owned(),
day.to_owned())` entry with `or_default()`, preserving the existing `e.total`
and `e.manual` updates.

In `@docs/DESIGN_CHALLENGE_CHECKLIST.md`:
- Around line 47-49: Update the design-check contract markers in the checklist
table to require SCHEDULED_DAILY_RUN_HEADROOM, the default 60-run calculation,
and strict earlier created_at ordering alongside the existing quota and corpus
semantics. Ensure design-check validates all of these normative rules so
removing any one causes the check to fail.
🪄 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: f432506e-10f7-444e-aea9-b395852c3772

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef8528 and d778287.

📒 Files selected for processing (17)
  • crates/db/migrations/0013_design_quota_manual.sql
  • crates/design-challenge-task/src/lib.rs
  • crates/design-challenge/src/corpus.rs
  • crates/design-challenge/src/lib.rs
  • crates/design-challenge/src/orchestrator.rs
  • crates/design-challenge/tests/cheat_fixtures.rs
  • crates/design-db/src/lib.rs
  • crates/design-http/src/api.rs
  • crates/design-http/src/stats.rs
  • crates/design-store/src/dbstore.rs
  • crates/design-store/src/lib.rs
  • crates/design-store/src/store.rs
  • docs/DESIGN_CHALLENGE.md
  • docs/DESIGN_CHALLENGE_CHECKLIST.md
  • docs/external-miner/design.md
  • docs/external-miner/troubleshoot.md
  • xtask/src/design_check.rs

Comment on lines +237 to +247
assert_eq!(
scheduled_runs_per_day(),
u32::try_from(ROUNDS_PER_DAY).unwrap() * u32::try_from(PROMPTS_PER_ROUND).unwrap()
);
assert_eq!(scheduled_runs_per_day(), 30);
assert!(scheduled_daily_run_cap() >= scheduled_runs_per_day());
assert_eq!(
scheduled_daily_run_cap(),
scheduled_runs_per_day() * SCHEDULED_DAILY_RUN_HEADROOM
);
assert!(daily_run_quota() > scheduled_runs_per_day());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check lint configuration for design-challenge-task and its test module.
set -euo pipefail

fd -t f 'lib.rs' crates/design-challenge-task/src --exec sed -n '1,30p' {}
rg -n 'unwrap_used' crates/design-challenge-task Cargo.toml crates/design-challenge-task/Cargo.toml 2>/dev/null || true
rg -n 'unwrap_used|\[workspace.lints|\[lints' Cargo.toml

Repository: BaseIntelligence/base

Length of output: 1234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workspace lint config =="
sed -n '1,40p' Cargo.toml

echo
echo "== crate config around lib.rs and workspace package config =="
sed -n '70,180p' Cargo.toml
echo
sed -n '1,80p' crates/design-store/src/store.rs

echo
echo "== design-challenge-task files and test module outline =="
git ls-files 'crates/design-challenge-task/src/**'
rg -n 'mod tests|#\[cfg\(test\)\]|assert_eq!|unwrap\(\)' crates/design-challenge-task/src/lib.rs crates/design-challenge-task/src -S

Repository: BaseIntelligence/base

Length of output: 9614


Allow clippy::unwrap_used in the design-challenge-task test module.

Cargo.toml denies clippy::unwrap_used, and crates/design-challenge-task/src/lib.rs uses unwrap() inside #[cfg(test)] mod tests. Add #![allow(clippy::unwrap_used)] at the top of that module, or remove/replace the unwrap() calls before Clippy gates fail.

🤖 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/design-challenge-task/src/lib.rs` around lines 237 - 247, Allow
clippy::unwrap_used within the #[cfg(test)] mod tests module in lib.rs, or
replace its unwrap() calls with equivalent non-panicking handling; preserve the
existing test assertions and behavior.

Source: Coding guidelines

Comment on lines +799 to +805
// Pre-LLM copy gate → terminal `rejected` (one fetch for gate + review).
let recent = self
.store
.list_recent_harnesses(64)
.await
.map_err(|e| RunFailure::new(ErrorClass::AstInfra, e.to_string()))?;
let gate_corpus = corpus::gate_corpus(&harness, &recent);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare the ordering contract of list_recent_harnesses across store adapters.
set -euo pipefail

echo '--- trait doc ---'
rg -n -B2 -A2 'fn list_recent_harnesses' crates/design-store/src/store.rs

echo '--- memory impl ---'
ast-grep run --pattern 'async fn list_recent_harnesses($$$) { $$$ }' --lang rust crates/design-store/src/store.rs

echo '--- SQL query ---'
rg -n -A12 'fn list_recent_design_harnesses' crates/design-db/src/lib.rs

Repository: BaseIntelligence/base

Length of output: 780


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- locate relevant files ---'
git ls-files | rg 'crates/(design-store|design-db)/src/.+\.rs$|crates/design-challenge/src/orchestrator.rs' | sed -n '1,120p'

echo '--- store.rs around trait and memory impl ---'
sed -n '316,575p' crates/design-store/src/store.rs

echo '--- search SQL list_recent implementation ---'
rg -n -C 8 'list_recent_design_harnesses|list_recent_harnesses|created_at|created_at_ms|ORDER BY|limit' crates/design-db crates/design-store crates/design-challenge/src/orchestrator.rs | sed -n '1,240p'

echo '--- orchestrator corpus gate call ---'
sed -n '788,812p' crates/design-challenge/src/orchestrator.rs

Repository: BaseIntelligence/base

Length of output: 28384


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- design-db list_recent_design_harnesses implementation ---'
rg -n -C 16 'fn list_recent_design_harnesses|LIST_RECENT_DESIGN_HARNESS|copy-gate|created_at' crates/design-db/src/lib.rs

echo '--- find query definitions ---'
rg -n 'list_recent_design_harnesses|LIST_RECENT|design_harness' crates design-db crates/design-db crates/design-store crates/design-challenge src 2>/dev/null | sed -n '1,220p'

echo '--- dbstore full query-related context if no direct function ---'
rg -n -C 8 'created_at_ms|max\\(|ORDER BY|LIMIT' crates/design-db/src/lib.rs | sed -n '1,260p'

Repository: BaseIntelligence/base

Length of output: 21313


Replace digest ordering in MemoryDesignStore::list_recent_harnesses.

list_recent_harnesses() is documented to return harnesses newest first. The SQL adapter orders by created_at DESC, but the memory adapter sorts by h.id before truncating to 64 rows. Since gate_corpus filters by created_at_ms, the memory-backed corpus can omit newer harnesses and behave differently from production.

🤖 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/design-challenge/src/orchestrator.rs` around lines 799 - 805, Update
MemoryDesignStore::list_recent_harnesses to order harnesses by created_at_ms
descending before applying the limit, matching the documented newest-first
behavior and SQL adapter ordering. Preserve the existing limit and return type
so gate_corpus receives the most recent harnesses consistently across adapters.

Comment on lines +94 to +160
#[tokio::test]
async fn self_revision_is_clean_but_cross_hotkey_copy_is_a_copy() {
let miner_a = "aa".repeat(32);
let miner_b = "bb".repeat(32);
let original = harness_row("h-orig", &miner_a, BASELINE_AGENT, 1_000);

// Same hotkey, later revision of its own (here byte-identical) harness.
let own_revision = harness_row("h-rev", &miner_a, BASELINE_AGENT, 2_000);
// Different hotkey, same bytes: a copy of someone else's prior art.
let foreign_copy = harness_row("h-copy", &miner_b, BASELINE_AGENT, 2_000);

let recent = vec![foreign_copy.clone(), own_revision.clone(), original.clone()];

// Pre-LLM gate: the corpus for a self-revision has no victim to hit.
let own_gate = corpus::gate_corpus(&own_revision, &recent);
assert!(
copy_gate(
&own_revision.agent_py,
own_revision.created_at_ms,
&own_gate
)
.is_none(),
"a miner's own earlier harness must never trip the copy gate"
);
let foreign_gate = corpus::gate_corpus(&foreign_copy, &recent);
let hit = copy_gate(
&foreign_copy.agent_py,
foreign_copy.created_at_ms,
&foreign_gate,
)
.expect("cross-hotkey byte copy must still be rejected");
assert_eq!(hit.nearest_id, "harness:h-orig");
assert!(hit.byte_identical);

// LLM review: same asymmetry in the corpus handed to the reviewer.
let pages: &[(&str, &str)] = &[("index.html", "<html data-agent=\"design-baseline\"></html>")];
let own_dir = tempdir().unwrap();
let own_verdict = SimAgent::new()
.review(&review_req(
own_dir.path(),
&own_revision.agent_py,
corpus::review_corpus(&own_revision, &recent),
Some(pages),
))
.await
.unwrap();
assert_eq!(
own_verdict.verdict,
VerdictKind::Clean,
"iterating on your own harness must not read as copying: {own_verdict:?}"
);

let copy_dir = tempdir().unwrap();
let copy_verdict = SimAgent::new()
.review(&review_req(
copy_dir.path(),
&foreign_copy.agent_py,
corpus::review_corpus(&foreign_copy, &recent),
Some(pages),
))
.await
.unwrap();
assert_eq!(copy_verdict.verdict, VerdictKind::Cheat);
assert!(copy_verdict
.cheat_codes
.contains(&CheatCode::NearIdenticalHarnessCopy));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Add a master challenge E2E regression test.

This test calls the corpus helpers and SimAgent directly. It uses a static page fixture. It does not execute either harness through master intake.

Add a master-path test for both submissions. Poll /events and /logs. Verify the self-revision reaches challenge-specific scoring, emits a leaf, seals a bundle, and produces sealed: true. Verify the cross-hotkey copy is rejected through the same path.

As per coding guidelines, challenge verification must simulate an end-to-end submission through the master challenge service, and stub pages are not proof of execution.

🤖 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/design-challenge/tests/cheat_fixtures.rs` around lines 94 - 160, The
existing test only exercises corpus helpers and SimAgent directly; add a master
challenge service end-to-end regression test covering both self-revision and
cross-hotkey copy submissions. Submit each harness through master intake, poll
/events and /logs, verify the self-revision reaches challenge-specific scoring,
emits a leaf, seals a bundle, and reports sealed: true, and verify the
cross-hotkey copy is rejected through the same path; do not rely on static page
fixtures as execution evidence.

Source: Coding guidelines

Comment on lines +640 to +644
"manual": {
"runs_used": used.manual,
"limit": manual_limit,
"remaining": manual_limit.saturating_sub(used.manual),
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

manual.remaining overstates the usable budget.

Scheduling is all-or-nothing for a whole prompt set. With the defaults, manual.limit is 10 and prompts_per_round() is 3, so the fourth submission of a day is refused at 9 used. The response then reports "remaining": 1 while every further manual submission fails with daily manual run quota exceeded (9+3/10). A miner reading /v1/quota/{hotkey} sees budget that cannot be spent.

Report the remaining budget in whole prompt sets, or set MANUAL_DAILY_RUN_QUOTA to a multiple of PROMPTS_PER_ROUND.

🐛 Proposed fix: report the spendable remainder
+    // All-or-nothing scheduling: only whole prompt sets are spendable.
+    let per_set = u32::try_from(design_challenge_task::prompts_per_round()).unwrap_or(1);
+    let manual_remaining = (manual_limit.saturating_sub(used.manual) / per_set) * per_set;
+    let scheduled_remaining = (scheduled_limit.saturating_sub(used.scheduled()) / per_set) * per_set;
     json!({
         "miner_hotkey": hotkey,
         "day": day,
         "runs_used": used.total,
         "limit": manual_limit.saturating_add(scheduled_limit),
         "manual": {
             "runs_used": used.manual,
             "limit": manual_limit,
-            "remaining": manual_limit.saturating_sub(used.manual),
+            "remaining": manual_remaining,
         },
🤖 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/design-http/src/api.rs` around lines 640 - 644, Update the manual
quota response in the quota-building logic around manual_limit and used.manual
so manual.remaining reports only spendable whole prompt sets, matching the
all-or-nothing prompts_per_round() scheduling behavior. Reuse the same quota and
round-size values used by submission validation, while preserving the existing
limit and runs_used fields.

Comment on lines +98 to +100
"daily_run_quota": daily_run_quota(),
"manual_daily_run_quota": manual_daily_run_quota(),
"scheduled_daily_run_cap": scheduled_daily_run_cap(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Trace the old single-quota name and value through code, dashboard assets, and miner docs.
set -euo pipefail

echo '=== 1. removed Rust constant ==='
rg -n --type=rust '\bDAILY_RUN_QUOTA\b' || echo 'no references'

echo '=== 2. consumers of the daily_run_quota JSON field ==='
rg -n --iglob '!target' -e 'daily_run_quota' -g '!crates/design-http/src/stats.rs' || echo 'no other consumers'

echo '=== 3. quota response consumers (dashboard / site assets) ==='
rg -n --iglob '*.{js,ts,jsx,tsx,html,svelte,vue}' -e 'daily_run_quota|runs_used|/v1/quota' || echo 'none'

echo '=== 4. miner-facing documentation of the ceiling ==='
fd -t f -e md . docs/external-miner --exec rg -n -i 'quota|runs per day|10 runs|rate limit' {} \; || echo 'none'

Repository: BaseIntelligence/base

Length of output: 206


🏁 Script executed:

#!/bin/bash
# Describe the current quota-related sources and remaining consumers without running repository code.
set -euo pipefail

echo '=== repository files mentioning daily_run_quota / quota / DAILY_RUN_QUOTA ==='
rg -n --iglob '!target/**' -e 'daily_run_quota|manual_daily_run_quota|scheduled_daily_run_cap|scheduled_runs_per_day|DAILY_RUN_QUOTA|runs_used|/v1/quota|quota' . || true

echo '=== design-http stats.rs relevant sections ==='
cat -n crates/design-http/src/stats.rs | sed -n '70,115p;165,190p'

echo '=== design-challenge lib.rs relevant section ==='
cat -n crates/design-challenge/src/lib.rs | sed -n '1,50p'

echo '=== docs external miner files ==='
fd -t f -e md . docs/external-miner -d 5 2>/dev/null | sort

Repository: BaseIntelligence/base

Length of output: 22789


🏁 Script executed:

#!/bin/bash
# Check for tracked external miner repos/configs and any stale miner-facing references.
set -euo pipefail

echo '=== tracked files under docs/external-miner ==='
git ls-files 'docs/external-miner/**' | sed -n '1,120p'

echo '=== repo config refs likely external miner ==='
rg -n --iglob '!target/**' -i 'external.*miner|miner|quota|v1/quota|daily_run_quota|runs_per_day|10 runs' .github README.md docs AGENTS.md || true

echo '=== quota JSON producer ==='
cat -n crates/design-http/src/api.rs | sed -n '500,665p;628,655p'

echo '=== stats producer context ==='
cat -n crates/design-http/src/stats.rs | sed -n '55,102p;188,238p'

Repository: BaseIntelligence/base

Length of output: 50377


🌐 Web query:

BaseIntelligence design-challenge quota docs GET /v1/quota/{hotkey} manual scheduled remaining

💡 Result:

Based on the technical documentation for the BASE ecosystem (BaseIntelligence), there is no official GET /v1/quota/{hotkey} endpoint documented for managing manual, scheduled, or remaining quota allocations. The BASE framework utilizes specific subnets—such as Bounty Challenge, Prism, and Agent Challenge—that operate on specialized APIs [1][2][3]. Review of the BASE infrastructure and challenge-specific documentation confirms that: 1. Quota management is not a standardized feature exposed via a global v1/quota/{hotkey} route across these subnets [4][5]. 2. Subnet operations typically rely on authenticated submission paths, weight normalization, and internal evaluation APIs (e.g., /internal/v1/get_weights or challenge-specific submission routes) rather than a centralized quota API for hotkeys [1][3][4]. If you are encountering this path in an error log or debugging context, it is likely either: - A custom, non-public, or deprecated internal endpoint specific to a private implementation. - A misidentified route, as similar patterns exist in other unrelated third-party APIs (e.g., Nomad or other SaaS platforms) that manage quota resources via GET /v1/quota/... patterns [6][7][8]. For authoritative guidance on your specific subnet, you should refer to the docs/ directory within the respective GitHub repository for your challenge (e.g., BaseIntelligence/agent-challenge or BaseIntelligence/bounty-challenge) [1][3].

Citations:


Keep the daily quota wire value meaningful. daily_run_quota() is the sum of the two per-origin caps, but miners only hit manual_daily_run_quota() and scheduled_daily_run_cap() on their own paths. Rename or document this field clearly, or replace it with an unused summary field, so nobody treats it as one enforced refusal limit.

📍 Affects 2 files
  • crates/design-http/src/stats.rs#L98-L100 (this comment)
  • crates/design-challenge/src/lib.rs#L31-L34
🤖 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/design-http/src/stats.rs` around lines 98 - 100, The daily_run_quota
wire field is a sum of separate manual and scheduled caps, not a single enforced
refusal limit. In the stats serialization around daily_run_quota(),
manual_daily_run_quota(), and scheduled_daily_run_cap() in
crates/design-http/src/stats.rs lines 98-100, rename or clearly document the
field as an aggregate, or replace it with an unused summary field; update the
corresponding definition or use in crates/design-challenge/src/lib.rs lines
31-34 as needed so both sites expose the same meaningful contract.

Source: Coding guidelines

Comment on lines +130 to +136
- Daily run quota is **split by origin**, so participating in every round can
never lock you out:
- **Manual** — **10** runs/day, charged only by your own `POST /v1/harness`.
This is anti-spam on resubmission, not a cap on participation.
- **Scheduled** — organizer round dispatch, capped well above the full day's
schedule (10 rounds × 3 prompts = **30** runs; cap **60**). You never spend
manual quota by being scheduled.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Document quota defaults and active limits separately.

The runtime supports configurable quota limits. The values 10 and 60 are defaults. Public documentation must not present them as fixed limits.

  • docs/external-miner/design.md#L130-L136: label both values as defaults, name the operator overrides, and retain the 10-round × 3-prompt calculation.
  • docs/external-miner/troubleshoot.md#L12-L12: replace fixed 10/day wording with the default and tell miners to check manual.limit and manual.remaining.

As per coding guidelines, docs/external-miner/ must remain current when challenge APIs or rules change.

📍 Affects 2 files
  • docs/external-miner/design.md#L130-L136 (this comment)
  • docs/external-miner/troubleshoot.md#L12-L12
🤖 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/external-miner/design.md` around lines 130 - 136, Update
docs/external-miner/design.md lines 130-136 to identify 10 manual runs/day and
60 scheduled runs/day as configurable defaults, name the corresponding operator
overrides, and retain the 10-round × 3-prompt calculation. Update
docs/external-miner/troubleshoot.md line 12 to replace the fixed 10/day wording
with the manual quota default and instruct miners to check manual.limit and
manual.remaining.

Source: Coding guidelines

Comment thread xtask/src/design_check.rs
("scoring_window", "SCORING_WINDOW_ROUNDS = 10"),
("daily_quota", "DAILY_RUN_QUOTA = 10"),
("daily_quota", "MANUAL_DAILY_RUN_QUOTA = 10"),
("scheduled_quota", "DESIGN_SCHEDULED_DAILY_RUN_CAP"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Pin the scheduled quota formula and default value.

This pin only requires DESIGN_SCHEDULED_DAILY_RUN_CAP. The design check can pass when the specification omits schedule-size multiplication, the headroom setting, or the default value 60.

Add content pins for the formula, the configurable headroom, and its default value. Keep the manual quota pin separate.

As per coding guidelines, treat normative documentation as the source of truth for contracts and status.

🤖 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 `@xtask/src/design_check.rs` at line 41, Update the design-check content pins
near DESIGN_SCHEDULED_DAILY_RUN_CAP to separately require the scheduled quota
formula, configurable headroom setting, and default headroom value of 60. Keep
the manual quota pin independent, and source the required wording from the
normative documentation so the check validates the complete contract.

Source: Coding guidelines

@echobt
echobt merged commit aef598f into main Aug 7, 2026
3 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