codai docs
Resolve

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ă)
StatusSemnificațieFacturat?
triageTranzitoriu — issue-ul este citit. Nu îl vezi niciodată într-un răspuns.—
declinedTriajul a considerat un fix verificat improbabil (stack greșit, fără reproducere clară, are nevoie de credențiale…). decline_reason spune de ce.Nu
quotedS-a stabilit un preț fix (tier, quote_micro_usd). Nu rulează nimic până nu accepți.Încă nu
acceptedAi acceptat (sau s-a aplicat nivelul gratuit). În coadă pentru un runner.Încă nu
runningSandbox-ul clonează, reproduce, repară, verifică.Încă nu
resolvedReproducerea a trecut de la eșec la succes, suita de regresie e verde, atestarea scrisă. attestation_url este setat.Da — cotația
failedNiciun candidat nu a trecut ambele porți în bugetul de ture și timp. fail_reason explică.Nu
errorProblemă 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âmpCe îți permite să verifici
repo_url + base_commitArborele exact pe care a fost verificat fix-ul. git checkout <base_commit> și reproduci singur.
patchDiff-ul unificat complet. Nimic în afara lui nu a fost schimbat.
repro_testTestul 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_beforeComanda FAIL_TO_PASS și output-ul ei pe commit-ul de bază — „înainte”.
test_output_afterAceeași comandă după patch — „după”.
regression_command / regression_outputSuita proprie a repo-ului, în continuare verde.
runner_image_digestImaginea de container în care au rulat testele, fixată prin digest.
started_at / verified_atFereastra 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ă devine error, 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 codai sub un id de sesiune resolve-<jobId>-…, așa că costul upstream per job este auditabil în usage_events ca 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.

Pe această pagină