Spaces:
Running
Running
File size: 7,008 Bytes
d9ba8d6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | """routers/lambda_bounty.py — Λ-BOUNTY INTAKE receiver (moved verbatim from serve.py).
Wave-K Dev4 refactor-only extraction. Route group:
GET /api/lambda-bounty/healthz
POST /api/lambda-bounty/submit
GET /api/lambda-bounty/receipts
Mirrors szl-holdings/lambda-bounty/webhook/intake.py so the endpoint advertised in
lutar-lean/BOUNTY.md is REAL, not a 404.
HONESTY: a receipt acknowledges INTAKE only. Award eligibility is decided SOLELY by
the verify-proof CI on a PR to szl-holdings/lambda-bounty. This receiver never
declares a winner and never moves money. Λ = Conjecture 1, NOT a theorem. Registered
BEFORE the SPA catch-all /{full_path:path}.
DSSE/HMAC receipts are REAL when LAMBDA_BOUNTY_HMAC_KEY is present; an honest
"dev-key" placeholder hmac is emitted (and flagged) when absent. The ledger is
in-memory (ring buffer) on the Space — honest disclosure; durable receipts land in
the repo via the bounty-webhook GitHub Action. ADDITIVE ONLY.
This module is fully self-contained: it uses only stdlib + FastAPI response types.
The state (ring buffer + keys) lives here now instead of at serve.py module scope.
Behavior is byte-identical to the pre-refactor inline block.
Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
"""
from __future__ import annotations
import collections as _pr_col
import hashlib as _lb_hashlib
import hmac as _lb_hmac
import json
import os
import re as _lb_re
import threading as _pr_thr
from fastapi import Request
from fastapi.responses import JSONResponse
# --- module state (was serve.py module-scope) --------------------------------
_LB_SIGN_KEY = os.environ.get("LAMBDA_BOUNTY_HMAC_KEY", "dev-key-not-for-prod")
_LB_HMAC_IS_DEV = _LB_SIGN_KEY == "dev-key-not-for-prod"
_LB_PR_RE = _lb_re.compile(r"^https://github\.com/szl-holdings/lambda-bounty/pull/\d+$")
_LB_ALLOWED_AXIOMS = ("propext", "Quot.sound", "Classical.choice")
_LB_LEDGER: _pr_col.deque = _pr_col.deque(maxlen=500)
_LB_LEDGER_LOCK = _pr_thr.Lock()
_LB_CONJECTURE = {
"id": "Conjecture 1",
"formula": "F23",
"status": "OPEN — NOT a theorem",
"statement": "Any two 9-axis aggregators satisfying A1 idempotence, A2 monotonicity, "
"A3 symmetry, A4 zero-absorption agree on every input.",
"arbiter": "verify-proof CI on a PR to szl-holdings/lambda-bounty (sole, no-bypass)",
}
def _lb_now() -> str:
import datetime as _dt
return _dt.datetime.now(_dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def _lb_validate(payload: dict) -> list:
errs = []
for k in ("submitter", "pr_url", "lean_toolchain", "axiom_print", "sorry_free_claim"):
if k not in payload:
errs.append(f"missing required field: {k}")
if "pr_url" in payload and not _LB_PR_RE.match(str(payload.get("pr_url", ""))):
errs.append("pr_url must be https://github.com/szl-holdings/lambda-bounty/pull/<n>")
if payload.get("lean_toolchain") not in (None, "leanprover/lean4:v4.13.0"):
errs.append("lean_toolchain must be leanprover/lean4:v4.13.0")
if payload.get("sorry_free_claim") is not True:
errs.append("sorry_free_claim must be true (CI verifies independently)")
sub = payload.get("submitter")
if not isinstance(sub, dict) or not sub.get("name"):
errs.append("submitter.name is required")
ap = payload.get("axiom_print", "")
if ap and "sorryAx" in str(ap):
errs.append("axiom_print contains sorryAx — proof is incomplete")
return errs
def _lb_prev_hash() -> str:
if not _LB_LEDGER:
return "genesis"
return _LB_LEDGER[-1].get("hash", "genesis")
def _lb_make_receipt(payload: dict, accepted: bool, errors: list) -> dict:
body = {
"receipt_type": "lambda_bounty_intake",
"conjecture": "Conjecture 1 (F23 Λ-aggregator uniqueness)",
"ts": _lb_now(),
"submitter": (payload.get("submitter") or {}).get("name", "?"),
"pr_url": payload.get("pr_url"),
"accepted_intake": accepted,
"errors": errors,
"eligibility_note": "Intake acknowledgement only. Award eligibility = verify-proof CI green on the PR.",
"prev": _lb_prev_hash(),
}
digest = _lb_hashlib.sha256(json.dumps(body, sort_keys=True).encode()).hexdigest()
sig = _lb_hmac.new(_LB_SIGN_KEY.encode(), digest.encode(), _lb_hashlib.sha256).hexdigest()
body["hash"] = digest
body["hmac_sha256"] = sig
body["hmac_key"] = "dev-key-placeholder (set LAMBDA_BOUNTY_HMAC_KEY for a real signature)" if _LB_HMAC_IS_DEV else "env-provided"
return body
def register(app) -> dict:
"""Attach the Λ-bounty intake route group to `app`, identically to the prior
inline serve.py block. Called BEFORE the SPA catch-all."""
@app.get("/api/lambda-bounty/healthz")
async def _lb_healthz():
"""Λ-bounty intake liveness + live Conjecture-1 status. Λ = NOT a theorem."""
return JSONResponse({"status": "ok", "service": "lambda-bounty-intake",
"conjecture": _LB_CONJECTURE, "doctrine": "v11",
"receipts_buffered": len(_LB_LEDGER)})
@app.post("/api/lambda-bounty/submit")
async def _lb_submit(request: Request):
"""Validate a Conjecture-1 submission payload, emit a hash-chained Khipu
intake receipt. 200 + receipt (accepted) or 422 + errors (rejected); a
receipt is appended either way. Eligibility is decided ONLY by verify-proof
CI on the PR — this never declares a winner."""
try:
payload = await request.json()
except Exception:
return JSONResponse({"error": "invalid JSON"}, status_code=400)
if not isinstance(payload, dict):
return JSONResponse({"error": "payload must be a JSON object"}, status_code=400)
errors = _lb_validate(payload)
accepted = len(errors) == 0
receipt = _lb_make_receipt(payload, accepted, errors)
with _LB_LEDGER_LOCK:
_LB_LEDGER.append(receipt)
return JSONResponse(status_code=(200 if accepted else 422), content={
"accepted_intake": accepted, "errors": errors, "receipt": receipt,
"next_step": "Open a PR to szl-holdings/lambda-bounty; verify-proof CI is the sole arbiter.",
})
@app.get("/api/lambda-bounty/receipts")
async def _lb_receipts():
"""Append-only intake receipt ledger as NDJSON. In-memory ring buffer
(maxlen=500); resets on Space rebuild (honest disclosure). Durable receipts
are committed to the repo by the bounty-webhook GitHub Action."""
from fastapi.responses import PlainTextResponse as _LBPlain
with _LB_LEDGER_LOCK:
lines = "\n".join(json.dumps(r) for r in _LB_LEDGER)
return _LBPlain(lines, media_type="application/x-ndjson")
return {"ok": True, "ns": "lambda-bounty", "routes": [
"/api/lambda-bounty/healthz",
"/api/lambda-bounty/submit",
"/api/lambda-bounty/receipts",
]}
|