66//!
77//! | Method | Path | Purpose |
88//! |--------|-------------------------------------------|-----------------------------------|
9+ //! | GET | /proof_attempts?limit=N&offset=M | List attempt rows (paged) |
910//! | POST | /proof_attempts | Insert a single attempt row |
1011//! | GET | /proof_attempts/strategy?class=X&limit=N | Recommend best provers for class |
1112//! | GET | /proof_attempts/certificates?class=X | PROVEN/pending cert status |
1516//! parsing only (inbound from ClickHouse, never emitted to callers).
1617//!
1718//! The ClickHouse URL is read from `VERISIM_CLICKHOUSE_URL` at request time.
19+ //! Optional write auth: if `VERISIM_PROOF_ATTEMPTS_TOKEN` is set, callers must
20+ //! provide either `X-Proof-Attempts-Token: <token>` or
21+ //! `Authorization: Bearer <token>` on `POST /proof_attempts`.
1822
1923use axum:: {
2024 extract:: Query ,
21- http:: StatusCode ,
25+ http:: { HeaderMap , StatusCode } ,
2226 response:: Response ,
2327} ;
2428use reqwest:: Client ;
@@ -51,6 +55,28 @@ fn ch_url() -> String {
5155 . unwrap_or_else ( |_| "http://localhost:8123" . to_string ( ) )
5256}
5357
58+ fn required_insert_token ( ) -> Option < String > {
59+ std:: env:: var ( "VERISIM_PROOF_ATTEMPTS_TOKEN" )
60+ . ok ( )
61+ . map ( |s| s. trim ( ) . to_string ( ) )
62+ . filter ( |s| !s. is_empty ( ) )
63+ }
64+
65+ fn provided_insert_token ( headers : & HeaderMap ) -> Option < String > {
66+ if let Some ( v) = headers
67+ . get ( "x-proof-attempts-token" )
68+ . and_then ( |v| v. to_str ( ) . ok ( ) )
69+ {
70+ return Some ( v. trim ( ) . to_string ( ) ) ;
71+ }
72+
73+ headers
74+ . get ( "authorization" )
75+ . and_then ( |v| v. to_str ( ) . ok ( ) )
76+ . and_then ( |v| v. strip_prefix ( "Bearer " ) )
77+ . map ( |v| v. trim ( ) . to_string ( ) )
78+ }
79+
5480// ── Inbound proof-attempt row (matches echidnabot VeriSimWriter schema) ───────
5581
5682/// A single proof attempt submitted by echidnabot.
@@ -79,6 +105,7 @@ pub struct ProofAttemptRow {
79105#[ derive( Debug , Deserialize ) ]
80106pub struct ListParams {
81107 pub limit : Option < usize > ,
108+ pub offset : Option < usize > ,
82109}
83110
84111#[ derive( Debug , Deserialize ) ]
@@ -94,14 +121,15 @@ pub struct ClassParam {
94121
95122// ── Handlers ─────────────────────────────────────────────────────────────────
96123
97- /// GET /proof_attempts?limit=N
124+ /// GET /proof_attempts?limit=N&offset=M
98125///
99126/// Returns up to `limit` (default 1000, max 20000) recent proof-attempt rows
100127/// from ClickHouse as an A2ML document for retraining the Julia ML models.
101128pub async fn list_proof_attempts (
102129 Query ( params) : Query < ListParams > ,
103130) -> Response {
104- let limit = params. limit . unwrap_or ( 1000 ) . min ( 20000 ) ;
131+ let limit = params. limit . unwrap_or ( 1000 ) . clamp ( 1 , 20000 ) ;
132+ let offset = params. offset . unwrap_or ( 0 ) ;
105133
106134 let sql = format ! (
107135 "SELECT attempt_id, obligation_id, repo, file, claim, obligation_class, \
@@ -110,6 +138,7 @@ pub async fn list_proof_attempts(
110138 FROM verisim.proof_attempts \
111139 ORDER BY started_at DESC \
112140 LIMIT {limit} \
141+ OFFSET {offset} \
113142 FORMAT JSONEachRow"
114143 ) ;
115144
@@ -148,8 +177,31 @@ pub async fn list_proof_attempts(
148177/// Inserts a single attempt row into `verisim.proof_attempts` via the
149178/// ClickHouse HTTP INSERT … FORMAT JSONEachRow endpoint.
150179pub async fn insert_proof_attempt (
180+ headers : HeaderMap ,
151181 axum:: Json ( row) : axum:: Json < ProofAttemptRow > ,
152182) -> Response {
183+ if let Some ( expected) = required_insert_token ( ) {
184+ match provided_insert_token ( & headers) {
185+ Some ( provided) if provided == expected => { }
186+ Some ( _) => {
187+ return a2ml_response (
188+ StatusCode :: UNAUTHORIZED ,
189+ a2ml_error_detail ( "invalid_proof_attempts_token" , 401 , "Token mismatch" ) ,
190+ ) ;
191+ }
192+ None => {
193+ return a2ml_response (
194+ StatusCode :: UNAUTHORIZED ,
195+ a2ml_error_detail (
196+ "proof_attempts_auth_required" ,
197+ 401 ,
198+ "Set X-Proof-Attempts-Token or Authorization: Bearer" ,
199+ ) ,
200+ ) ;
201+ }
202+ }
203+ }
204+
153205 let url = format ! (
154206 "{}/?query=INSERT+INTO+verisim.proof_attempts+FORMAT+JSONEachRow" ,
155207 ch_url( )
0 commit comments