Spaces:
Running on Zero
Running on Zero
feat: add prize ledger
Browse filesCo-authored-by: Codex <noreply@openai.com>
- README.md +6 -0
- app.py +9 -1
- hackathon_advisor/prize_ledger.py +91 -0
- static/app.js +33 -0
- static/index.html +4 -0
- static/styles.css +58 -1
- tests/test_app.py +10 -0
- tests/test_prize_ledger.py +13 -0
README.md
CHANGED
|
@@ -75,6 +75,12 @@ The `chapter` Gradio API endpoint and `Chapter` button export the public-facing
|
|
| 75 |
one fate page per idea, each with verdict, score, targets, and closest cited pages. It is the shareable companion to
|
| 76 |
the private Field Notes artifact.
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
## Wood Map
|
| 79 |
|
| 80 |
Every scored fate page now carries a deterministic `wood_map` artifact: background dots for inked Spaces, red dots for
|
|
|
|
| 75 |
one fate page per idea, each with verdict, score, targets, and closest cited pages. It is the shareable companion to
|
| 76 |
the private Field Notes artifact.
|
| 77 |
|
| 78 |
+
## Prize Ledger
|
| 79 |
+
|
| 80 |
+
`/api/prize-ledger` and the in-app Prize Ledger panel expose submission evidence: the documented model stack, total
|
| 81 |
+
parameter budget, Tiny Titan eligibility, runtime backend, and badge readiness. This keeps the demo's prize claims tied
|
| 82 |
+
to visible app state rather than hidden notes.
|
| 83 |
+
|
| 84 |
## Wood Map
|
| 85 |
|
| 86 |
Every scored fate page now carries a deterministic `wood_map` artifact: background dots for inked Spaces, red dots for
|
app.py
CHANGED
|
@@ -12,6 +12,7 @@ from hackathon_advisor.agent import AdvisorEngine
|
|
| 12 |
from hackathon_advisor.chapter import build_chapter_markdown
|
| 13 |
from hackathon_advisor.data import ProjectIndex
|
| 14 |
from hackathon_advisor.field_notes import build_field_notes_markdown
|
|
|
|
| 15 |
from hackathon_advisor.tool_contracts import resolve_tool_call, tool_schemas
|
| 16 |
from hackathon_advisor.tools import TARGETS
|
| 17 |
from hackathon_advisor.trace_export import build_trace_jsonl, trace_metadata
|
|
@@ -57,15 +58,17 @@ def health() -> dict:
|
|
| 57 |
|
| 58 |
@app.get("/api/bootstrap")
|
| 59 |
def bootstrap() -> dict:
|
|
|
|
| 60 |
return {
|
| 61 |
"project_count": len(index.projects),
|
| 62 |
-
"runtime":
|
| 63 |
**trace_metadata(index),
|
| 64 |
"top_projects": [project.to_public_dict() for project in index.top_projects(limit=8)],
|
| 65 |
"whitespace": [item.to_dict() for item in index.find_whitespace(limit=5)],
|
| 66 |
"target_options": TARGETS,
|
| 67 |
"default_targets": TARGETS[:3],
|
| 68 |
"profile_fields": PROFILE_FIELDS,
|
|
|
|
| 69 |
}
|
| 70 |
|
| 71 |
|
|
@@ -74,6 +77,11 @@ def runtime() -> dict:
|
|
| 74 |
return engine.runtime_status()
|
| 75 |
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
@app.get("/api/tool-contracts")
|
| 78 |
def tool_contracts() -> dict:
|
| 79 |
return {
|
|
|
|
| 12 |
from hackathon_advisor.chapter import build_chapter_markdown
|
| 13 |
from hackathon_advisor.data import ProjectIndex
|
| 14 |
from hackathon_advisor.field_notes import build_field_notes_markdown
|
| 15 |
+
from hackathon_advisor.prize_ledger import prize_ledger
|
| 16 |
from hackathon_advisor.tool_contracts import resolve_tool_call, tool_schemas
|
| 17 |
from hackathon_advisor.tools import TARGETS
|
| 18 |
from hackathon_advisor.trace_export import build_trace_jsonl, trace_metadata
|
|
|
|
| 58 |
|
| 59 |
@app.get("/api/bootstrap")
|
| 60 |
def bootstrap() -> dict:
|
| 61 |
+
runtime_status = engine.runtime_status()
|
| 62 |
return {
|
| 63 |
"project_count": len(index.projects),
|
| 64 |
+
"runtime": runtime_status,
|
| 65 |
**trace_metadata(index),
|
| 66 |
"top_projects": [project.to_public_dict() for project in index.top_projects(limit=8)],
|
| 67 |
"whitespace": [item.to_dict() for item in index.find_whitespace(limit=5)],
|
| 68 |
"target_options": TARGETS,
|
| 69 |
"default_targets": TARGETS[:3],
|
| 70 |
"profile_fields": PROFILE_FIELDS,
|
| 71 |
+
"prize_ledger": prize_ledger(runtime_status),
|
| 72 |
}
|
| 73 |
|
| 74 |
|
|
|
|
| 77 |
return engine.runtime_status()
|
| 78 |
|
| 79 |
|
| 80 |
+
@app.get("/api/prize-ledger")
|
| 81 |
+
def prize_ledger_endpoint() -> dict:
|
| 82 |
+
return prize_ledger(engine.runtime_status())
|
| 83 |
+
|
| 84 |
+
|
| 85 |
@app.get("/api/tool-contracts")
|
| 86 |
def tool_contracts() -> dict:
|
| 87 |
return {
|
hackathon_advisor/prize_ledger.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from typing import Any
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
MODEL_STACK = [
|
| 7 |
+
{
|
| 8 |
+
"role": "LLM brain",
|
| 9 |
+
"model": "openbmb/MiniCPM5-1B",
|
| 10 |
+
"params_b": 1.08,
|
| 11 |
+
"status": "optional runtime adapter",
|
| 12 |
+
"runtime": "transformers / GGUF-ready",
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"role": "Retriever",
|
| 16 |
+
"model": "offline TF-IDF snapshot",
|
| 17 |
+
"params_b": 0.0,
|
| 18 |
+
"status": "deployed",
|
| 19 |
+
"runtime": "local sparse index",
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"role": "Planned embedder",
|
| 23 |
+
"model": "google/embeddinggemma-300m",
|
| 24 |
+
"params_b": 0.30,
|
| 25 |
+
"status": "documented build path",
|
| 26 |
+
"runtime": "sentence-transformers / llama.cpp",
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"role": "Voice bonus",
|
| 30 |
+
"model": "nvidia/nemotron-speech-streaming-en-0.6b",
|
| 31 |
+
"params_b": 0.60,
|
| 32 |
+
"status": "deferred bonus",
|
| 33 |
+
"runtime": "batch ASR",
|
| 34 |
+
},
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
BADGE_LEDGER = [
|
| 39 |
+
{
|
| 40 |
+
"name": "Off the Grid",
|
| 41 |
+
"status": "ready",
|
| 42 |
+
"evidence": "Runtime uses a checked-in snapshot and local search; no proprietary inference API.",
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"name": "Off-Brand",
|
| 46 |
+
"status": "ready",
|
| 47 |
+
"evidence": "Custom gr.Server frontend renders the agent as The Unwritten Almanac.",
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"name": "Sharing is Caring",
|
| 51 |
+
"status": "ready",
|
| 52 |
+
"evidence": "JSONL trace export and checked-in sample trace are published with the Space.",
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"name": "Field Notes",
|
| 56 |
+
"status": "ready",
|
| 57 |
+
"evidence": "Field Notes markdown export is generated from exact session state.",
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"name": "Tiny Titan",
|
| 61 |
+
"status": "eligible",
|
| 62 |
+
"evidence": "Documented stack stays under 4B parameters; largest model is MiniCPM5-1B.",
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"name": "Well-Tuned",
|
| 66 |
+
"status": "planned",
|
| 67 |
+
"evidence": "Plan includes a MiniCPM5 LoRA path; adapter publication remains a separate build milestone.",
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"name": "Llama Champion",
|
| 71 |
+
"status": "planned",
|
| 72 |
+
"evidence": "MiniCPM5 GGUF and EmbeddingGemma GGUF paths are documented; runtime does not depend on them yet.",
|
| 73 |
+
},
|
| 74 |
+
]
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def prize_ledger(runtime: dict[str, Any]) -> dict[str, Any]:
|
| 78 |
+
total_params = round(sum(float(item["params_b"]) for item in MODEL_STACK), 2)
|
| 79 |
+
largest = max(MODEL_STACK, key=lambda item: float(item["params_b"]))
|
| 80 |
+
return {
|
| 81 |
+
"runtime": runtime,
|
| 82 |
+
"model_stack": MODEL_STACK,
|
| 83 |
+
"total_params_b": total_params,
|
| 84 |
+
"largest_model": {
|
| 85 |
+
"model": largest["model"],
|
| 86 |
+
"params_b": largest["params_b"],
|
| 87 |
+
},
|
| 88 |
+
"tiny_titan_limit_b": 4.0,
|
| 89 |
+
"tiny_titan_eligible": total_params <= 4.0 and float(largest["params_b"]) <= 4.0,
|
| 90 |
+
"badges": BADGE_LEDGER,
|
| 91 |
+
}
|
static/app.js
CHANGED
|
@@ -10,6 +10,7 @@ const whitespaceEl = document.querySelector("#whitespace");
|
|
| 10 |
const ideasEl = document.querySelector("#ideas");
|
| 11 |
const targetsEl = document.querySelector("#targets");
|
| 12 |
const profileEl = document.querySelector("#profile");
|
|
|
|
| 13 |
const woodMapEl = document.querySelector("#wood-map");
|
| 14 |
const scoreEl = document.querySelector("#score");
|
| 15 |
const planEl = document.querySelector("#plan");
|
|
@@ -145,6 +146,7 @@ async function bootstrap() {
|
|
| 145 |
renderProvenance(data);
|
| 146 |
renderTargets(session.targets);
|
| 147 |
renderProfile(session.profile);
|
|
|
|
| 148 |
renderRestoredSession(data);
|
| 149 |
renderWhitespace(data.whitespace || []);
|
| 150 |
}
|
|
@@ -266,6 +268,37 @@ function renderProfile(profile) {
|
|
| 266 |
}
|
| 267 |
}
|
| 268 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
function handleEvent(event) {
|
| 270 |
if (event.type === "start") {
|
| 271 |
if (event.corrections?.length) {
|
|
|
|
| 10 |
const ideasEl = document.querySelector("#ideas");
|
| 11 |
const targetsEl = document.querySelector("#targets");
|
| 12 |
const profileEl = document.querySelector("#profile");
|
| 13 |
+
const prizeLedgerEl = document.querySelector("#prize-ledger");
|
| 14 |
const woodMapEl = document.querySelector("#wood-map");
|
| 15 |
const scoreEl = document.querySelector("#score");
|
| 16 |
const planEl = document.querySelector("#plan");
|
|
|
|
| 146 |
renderProvenance(data);
|
| 147 |
renderTargets(session.targets);
|
| 148 |
renderProfile(session.profile);
|
| 149 |
+
renderPrizeLedger(data.prize_ledger || null);
|
| 150 |
renderRestoredSession(data);
|
| 151 |
renderWhitespace(data.whitespace || []);
|
| 152 |
}
|
|
|
|
| 268 |
}
|
| 269 |
}
|
| 270 |
|
| 271 |
+
function renderPrizeLedger(ledger) {
|
| 272 |
+
prizeLedgerEl.innerHTML = "";
|
| 273 |
+
if (!ledger) {
|
| 274 |
+
prizeLedgerEl.innerHTML = `<div class="empty">No prize ledger loaded.</div>`;
|
| 275 |
+
return;
|
| 276 |
+
}
|
| 277 |
+
const readyBadges = (ledger.badges || []).filter((badge) => badge.status === "ready").length;
|
| 278 |
+
const badgeCount = (ledger.badges || []).length;
|
| 279 |
+
const header = document.createElement("div");
|
| 280 |
+
header.className = "ledger-summary";
|
| 281 |
+
header.innerHTML = `
|
| 282 |
+
<strong>${Number(ledger.total_params_b || 0).toFixed(2)}B params</strong>
|
| 283 |
+
<span>${ledger.tiny_titan_eligible ? "Tiny Titan eligible" : "Over Tiny Titan limit"}</span>
|
| 284 |
+
<span>${readyBadges}/${badgeCount} ready</span>
|
| 285 |
+
<span>${escapeHtml(ledger.runtime?.backend || "runtime")}</span>
|
| 286 |
+
`;
|
| 287 |
+
const badges = document.createElement("div");
|
| 288 |
+
badges.className = "badge-list";
|
| 289 |
+
for (const badge of (ledger.badges || []).slice(0, 7)) {
|
| 290 |
+
const item = document.createElement("div");
|
| 291 |
+
item.className = `badge-item ${badge.status || "planned"}`;
|
| 292 |
+
item.title = badge.evidence || badge.name;
|
| 293 |
+
item.innerHTML = `
|
| 294 |
+
<strong>${escapeHtml(badge.name)}</strong>
|
| 295 |
+
<span>${escapeHtml(badge.status)}</span>
|
| 296 |
+
`;
|
| 297 |
+
badges.append(item);
|
| 298 |
+
}
|
| 299 |
+
prizeLedgerEl.append(header, badges);
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
function handleEvent(event) {
|
| 303 |
if (event.type === "start") {
|
| 304 |
if (event.corrections?.length) {
|
static/index.html
CHANGED
|
@@ -61,6 +61,10 @@
|
|
| 61 |
<h2>Profile</h2>
|
| 62 |
<div id="profile" class="profile-grid"></div>
|
| 63 |
</article>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
<article>
|
| 65 |
<h2>Idea Board</h2>
|
| 66 |
<div id="ideas" class="idea-list"></div>
|
|
|
|
| 61 |
<h2>Profile</h2>
|
| 62 |
<div id="profile" class="profile-grid"></div>
|
| 63 |
</article>
|
| 64 |
+
<article class="wide-panel">
|
| 65 |
+
<h2>Prize Ledger</h2>
|
| 66 |
+
<div id="prize-ledger" class="prize-ledger"></div>
|
| 67 |
+
</article>
|
| 68 |
<article>
|
| 69 |
<h2>Idea Board</h2>
|
| 70 |
<div id="ideas" class="idea-list"></div>
|
static/styles.css
CHANGED
|
@@ -302,7 +302,8 @@ button:disabled {
|
|
| 302 |
.trace-list,
|
| 303 |
.target-list,
|
| 304 |
.profile-grid,
|
| 305 |
-
.wood-map
|
|
|
|
| 306 |
display: grid;
|
| 307 |
gap: 9px;
|
| 308 |
}
|
|
@@ -426,6 +427,57 @@ button:disabled {
|
|
| 426 |
box-shadow: 0 0 0 3px rgba(47, 122, 73, 0.13);
|
| 427 |
}
|
| 428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
.wood-map-field {
|
| 430 |
position: relative;
|
| 431 |
min-height: 138px;
|
|
@@ -526,6 +578,11 @@ button:disabled {
|
|
| 526 |
grid-template-columns: 1fr;
|
| 527 |
}
|
| 528 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
.command-row {
|
| 530 |
grid-template-columns: repeat(3, minmax(0, 1fr));
|
| 531 |
}
|
|
|
|
| 302 |
.trace-list,
|
| 303 |
.target-list,
|
| 304 |
.profile-grid,
|
| 305 |
+
.wood-map,
|
| 306 |
+
.prize-ledger {
|
| 307 |
display: grid;
|
| 308 |
gap: 9px;
|
| 309 |
}
|
|
|
|
| 427 |
box-shadow: 0 0 0 3px rgba(47, 122, 73, 0.13);
|
| 428 |
}
|
| 429 |
|
| 430 |
+
.ledger-summary {
|
| 431 |
+
display: grid;
|
| 432 |
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
| 433 |
+
gap: 8px;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
.ledger-summary strong,
|
| 437 |
+
.ledger-summary span,
|
| 438 |
+
.badge-item {
|
| 439 |
+
min-width: 0;
|
| 440 |
+
border-left: 3px solid rgba(80, 47, 22, 0.48);
|
| 441 |
+
border-radius: 0 8px 8px 0;
|
| 442 |
+
background: rgba(255, 241, 196, 0.34);
|
| 443 |
+
padding: 8px 10px;
|
| 444 |
+
color: #2a170d;
|
| 445 |
+
font-size: 0.76rem;
|
| 446 |
+
line-height: 1.25;
|
| 447 |
+
font-weight: 900;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
.badge-list {
|
| 451 |
+
display: grid;
|
| 452 |
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
| 453 |
+
gap: 7px;
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
.badge-item {
|
| 457 |
+
display: flex;
|
| 458 |
+
align-items: center;
|
| 459 |
+
justify-content: space-between;
|
| 460 |
+
gap: 8px;
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
.badge-item.ready {
|
| 464 |
+
border-left-color: var(--leaf);
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
.badge-item.eligible {
|
| 468 |
+
border-left-color: var(--gold);
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
.badge-item.planned {
|
| 472 |
+
border-left-color: var(--muted-ink);
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
.badge-item span {
|
| 476 |
+
color: var(--muted-ink);
|
| 477 |
+
font-size: 0.68rem;
|
| 478 |
+
text-transform: uppercase;
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
.wood-map-field {
|
| 482 |
position: relative;
|
| 483 |
min-height: 138px;
|
|
|
|
| 578 |
grid-template-columns: 1fr;
|
| 579 |
}
|
| 580 |
|
| 581 |
+
.ledger-summary,
|
| 582 |
+
.badge-list {
|
| 583 |
+
grid-template-columns: 1fr;
|
| 584 |
+
}
|
| 585 |
+
|
| 586 |
.command-row {
|
| 587 |
grid-template-columns: repeat(3, minmax(0, 1fr));
|
| 588 |
}
|
tests/test_app.py
CHANGED
|
@@ -7,6 +7,7 @@ from app import (
|
|
| 7 |
field_notes_artifact,
|
| 8 |
health,
|
| 9 |
index,
|
|
|
|
| 10 |
runtime,
|
| 11 |
tool_contract_check,
|
| 12 |
tool_contracts,
|
|
@@ -34,6 +35,7 @@ def test_bootstrap_exposes_index_metadata() -> None:
|
|
| 34 |
assert payload["top_projects"]
|
| 35 |
assert payload["default_targets"] == payload["target_options"][:3]
|
| 36 |
assert "skills" in payload["profile_fields"]
|
|
|
|
| 37 |
|
| 38 |
|
| 39 |
def test_trace_artifact_endpoint_exports_jsonl() -> None:
|
|
@@ -94,3 +96,11 @@ def test_runtime_endpoint_reports_planner() -> None:
|
|
| 94 |
assert payload["backend"] == "rules"
|
| 95 |
assert payload["model_id"] == "deterministic-tool-router"
|
| 96 |
assert payload["loaded"] is True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
field_notes_artifact,
|
| 8 |
health,
|
| 9 |
index,
|
| 10 |
+
prize_ledger_endpoint,
|
| 11 |
runtime,
|
| 12 |
tool_contract_check,
|
| 13 |
tool_contracts,
|
|
|
|
| 35 |
assert payload["top_projects"]
|
| 36 |
assert payload["default_targets"] == payload["target_options"][:3]
|
| 37 |
assert "skills" in payload["profile_fields"]
|
| 38 |
+
assert payload["prize_ledger"]["tiny_titan_eligible"] is True
|
| 39 |
|
| 40 |
|
| 41 |
def test_trace_artifact_endpoint_exports_jsonl() -> None:
|
|
|
|
| 96 |
assert payload["backend"] == "rules"
|
| 97 |
assert payload["model_id"] == "deterministic-tool-router"
|
| 98 |
assert payload["loaded"] is True
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def test_prize_ledger_endpoint_reports_submission_evidence() -> None:
|
| 102 |
+
payload = prize_ledger_endpoint()
|
| 103 |
+
|
| 104 |
+
assert payload["runtime"]["backend"] == "rules"
|
| 105 |
+
assert payload["tiny_titan_eligible"] is True
|
| 106 |
+
assert any(badge["name"] == "Sharing is Caring" for badge in payload["badges"])
|
tests/test_prize_ledger.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from hackathon_advisor.prize_ledger import prize_ledger
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_prize_ledger_tracks_param_budget_and_badges() -> None:
|
| 5 |
+
payload = prize_ledger({"backend": "rules", "model_id": "deterministic-tool-router"})
|
| 6 |
+
|
| 7 |
+
assert payload["runtime"]["backend"] == "rules"
|
| 8 |
+
assert payload["total_params_b"] <= payload["tiny_titan_limit_b"]
|
| 9 |
+
assert payload["tiny_titan_eligible"] is True
|
| 10 |
+
assert payload["largest_model"]["model"] == "openbmb/MiniCPM5-1B"
|
| 11 |
+
badges = {badge["name"]: badge["status"] for badge in payload["badges"]}
|
| 12 |
+
assert badges["Off the Grid"] == "ready"
|
| 13 |
+
assert badges["Well-Tuned"] == "planned"
|