Cum funcționează
Ciclul de viață al unui job Resolve de la triaj la atestare, ce dovedește de fapt documentul public de dovadă și ce atinge și ce nu atinge runner-ul izolat.
Un job Resolve este o mică mașină de stări cu o regulă dură la final: taxa nu poate exista fără atestare. Tot ce urmează este cum ajunge un job acolo — sau nu.
Ciclul de viață al job-ului
POST /v1/resolve/jobs
│
▼
triage ──── decline ───▶ declined (0 $, final)
│
quote t7|t19|t49
│
├── nivel gratuit rămas ──▶ accepted (auto)
│
▼
quoted ── POST …/accept ──▶ accepted
│
▼
running ──▶ resolved (atestare + taxă)
│
├──────▶ failed (0 $ — niciun fix verificat în buget)
└──────▶ error (0 $ — infrastructură; retrimiți fără grijă)| Status | Semnificație | Facturat? |
|---|---|---|
triage | Tranzitoriu — issue-ul este citit. Nu îl vezi niciodată într-un răspuns. | — |
declined | Triajul a considerat un fix verificat improbabil (stack greșit, fără reproducere clară, are nevoie de credențiale…). decline_reason spune de ce. | Nu |
quoted | S-a stabilit un preț fix (tier, quote_micro_usd). Nu rulează nimic până nu accepți. | Încă nu |
accepted | Ai acceptat (sau s-a aplicat nivelul gratuit). În coadă pentru un runner. | Încă nu |
running | Sandbox-ul clonează, reproduce, repară, verifică. | Încă nu |
resolved | Reproducerea a trecut de la eșec la succes, suita de regresie e verde, atestarea scrisă. attestation_url este setat. | Da — cotația |
failed | Niciun candidat nu a trecut ambele porți în bugetul de ture și timp. fail_reason explică. | Nu |
error | Problemă de mediu sau infrastructură (clonă defectă, sandbox indisponibil, worker pierdut). Retrimiți liber. | Nu |
Statusurile merg doar înainte; resolved, failed, error și declined sunt terminale. GET /v1/resolve/jobs/{id} este limitat la utilizatorul cheii — id-ul de job al altui utilizator este 404.
Triaj
Rulează inline în POST-ul tău, pe modelul codai, și răspunde cu exact o linie: QUOTE t7|t19|t49 <motiv> sau DECLINE <motiv>. Sensul aproximativ al pragurilor: t7 — mic, bine delimitat (un fișier, reproducere clară); t19 — moderat (mai multe fișiere, are nevoie de investigație); t49 — greu dar plauzibil (subtil, transversal). Dacă triajul în sine este indisponibil, job-ul este refuzat cu triage unavailable, please retry — Resolve nu cotează niciodată orb.
Nivelul gratuit
Fiecare utilizator primește 3 remedieri verificate gratuite. Revendicarea este atomică: când sosește un job cotabil și mai ai un loc gratuit, job-ul este creat cu tier: "free", quote_micro_usd: 0, status: "accepted" și pornește imediat. free_tier_remaining din răspuns îți spune câte mai rămân după acesta. Un job gratuit care se termină failed sau error dă locul înapoi.
Acceptare
Doar job-urile quoted acceptă; orice altceva este 409 job is <status>, only quoted jobs can be accepted. Acceptarea este momentul în care ești de acord cu cotația — dar plătești în continuare doar dacă se rezolvă.
Rularea
Reproduce întâi
Runner-ul clonează repo-ul la HEAD (înregistrat ca base_commit). Dacă ai furnizat test_command, îl rulează: trebuie să eșueze pe commit-ul de bază, altfel job-ul se termină cu supplied test_command already passes on HEAD — nothing to fix. Fără comandă, agentul scrie un test de reproducere — un singur fișier pytest / vitest / jest — și confirmă că eșuează. Acel output de eșec devine test_output_before.
Repară
Agentul primește issue-ul, repo-ul și testul care eșuează, și editează cod într-o buclă limitată la cel mult 4 ture per candidat (editări SEARCH/REPLACE plus citiri de fișiere). Pragurile plătite se ramifică în până la 4 candidați (primul la temperatură 0, restul la 0,8) și se opresc la primul care trece; nivelul gratuit rulează unul singur. Un candidat trece doar dacă reproducerea trece acum și suita proprie a repo-ului trece în continuare.
Verifică
Verificarea nu eșuează niciodată permisiv. Două comenzi rulează în sandbox pe base_commit + patch: comanda FAIL_TO_PASS (test_command) și o comandă de regresie PASS_TO_PASS (regression_command) — suita completă a repo-ului cu fișierul de reproducere exclus. Un mediu defect, timeout-urile sau un runner dispărut sunt error, niciodată resolved.
Atestă, apoi taxează
Se scrie rândul de atestare, apoi — și doar atunci — rândul resolve_charges pentru suma cotată. Dacă ceva eșuează între cele două, ai o dovadă și nicio factură, niciodată invers.
Ce dovedește atestarea
GET /v1/resolve/attestations/{id} nu are nevoie de nicio autentificare: UUID-ul este capabilitatea. Oricine are linkul poate audita fix-ul. Returnează:
{
"id": "a45764d8-…",
"kind": "codai.resolve.attestation.v0",
"repo_url": "https://github.com/owner/repo",
"base_commit": "3f9c…",
"patch": "diff --git a/src/parse.ts b/src/parse.ts\n…",
"repro_test": { "path": "tests/test_issue_42.py", "content": "…" },
"test_command": "python -m pytest -q tests/test_issue_42.py",
"regression_command": "python -m pytest -q --deselect tests/test_issue_42.py --ignore=tests/test_issue_42.py",
"test_output_before": "… 1 failed …",
"test_output_after": "… 1 passed …",
"regression_output": "… 212 passed …",
"runner_image_digest": "sha256:…",
"started_at": "2026-09-23T09:12:04.118Z",
"verified_at": "2026-09-23T09:19:41.402Z"
}| Câmp | Ce îți permite să verifici |
|---|---|
repo_url + base_commit | Arborele exact pe care a fost verificat fix-ul. git checkout <base_commit> și reproduci singur. |
patch | Diff-ul unificat complet. Nimic în afara lui nu a fost schimbat. |
repro_test | Testul care codifică bug-ul (null când ai furnizat test_command). Îl citești ca să judeci dacă surprinde issue-ul. |
test_command / test_output_before | Comanda FAIL_TO_PASS și output-ul ei pe commit-ul de bază — „înainte”. |
test_output_after | Aceeași comandă după patch — „după”. |
regression_command / regression_output | Suita proprie a repo-ului, în continuare verde. |
runner_image_digest | Imaginea de container în care au rulat testele, fixată prin digest. |
started_at / verified_at | Fereastra de timp a încercării. |
Ce nu dovedește: că testul de reproducere este testul potrivit pentru issue, sau că fix-ul este cel pe care l-ai fi scris tu. Pentru asta sunt acolo diff-ul și conținutul testului — le citești ca pe un PR, cu avantajul că dovada de execuție este atașată.
Atestarea este imutabilă și rămâne publică; același URL este cel pe care acțiunea GitHub îl leagă din PR.
Siguranță: ce atinge runner-ul
Resolve rulează cod de repository în care nu are încredere — testele tale, scripturile tale de instalare — așa că modelul de execuție este intenționat îngust.
- Execuție izolată. Testele, setup-ul și candidații de fix rulează într-un job Cloud Run separat și fără privilegii (
codai-swe-exec), fără acces la baza de date și fără credențiale de gateway; rezultatele revin ca artefacte. Procesul API în sine doar clonează repo-ul, citește fișiere și construiește diff-uri. În producție, API-ul refuză să ruleze cod de repository în proces — o configurare greșită devineerror, niciodată cod rulând lângă secrete. - Repo-uri publice, doar citire. Resolve preia
https://github.com/<owner>/<repo>anonim. Nu face niciodată push; acțiunea GitHub face asta cu token-ul tău, în workflow-ul tău. - Schimbări doar prin diff. Patch-ul din atestare este întreaga întindere a ceea ce s-a schimbat. Agentul editează prin blocuri SEARCH/REPLACE; nu poate rula shell arbitrar în procesul API.
- Bugete limitate. Cel mult 4 ture de agent per candidat, cel mult 4 candidați, un timeout per job de 30 de minute cu o limită de 15 minute per rulare în sandbox, și un watchdog de orfani care marchează un job
error(și returnează un loc gratuit) dacă worker-ul lui dispare. - Nimic ascuns. Apelurile către model se fac pe gateway-ul
codaisub un id de sesiuneresolve-<jobId>-…, așa că costul upstream per job este auditabil înusage_eventsca orice altă cerere.
Beta privat înseamnă o listă onestă de limite: doar repo-uri publice github.com; Python (pytest) și JavaScript/TypeScript (vitest, jest, node:test); repo-urile ale căror teste au nevoie de secrete, servicii sau setup de sistem netrivial vor fi de regulă refuzate sau se termină în error.
Acțiunea GitHub
Instalezi acțiunea Codai Resolve — etichetezi un issue codai-fix și primești un PR cu un fix verificat și o atestare publică. Intrări, ieșiri, secrete, permisiuni și workflow-uri exemplu.
Prețuri și limite
Cotații fixe de 7 $, 19 $ sau 49 $ facturate doar la un fix verificat; trei remedieri gratuite; cum ajunge o taxă pe factura ta Stripe; plafoane per utilizator și timeout-uri.