Документация
Как работает ResultBond — подробно.
Для инженеров, которые будут встраивать квитанции, проверять их или проводить по ним расчёты.
Как устроена работа
- Манифест. Покупатель, исполнитель и ResultBond подписывают один манифест: снимок репозитория, публичные и скрытые наборы тестов, критерии приёмки, лимиты среды, цену и компенсацию. Его SHA-256 отпечаток — идентификатор работы.
- Скрытые тесты доказываются. До начала работы каждый скрытый тест должен падать на исходном коммите и не повторять публичный тест. Иначе работа не оценивается автоматически.
- Сдача. Исполнитель подписывает одну сдачу: отпечаток патча и снимок, который получается после патча. Оценивается ровно этот код.
- Песочница. Исходный код и кандидат запускаются в изолированной песочнице (без сети, с лимитами CPU, памяти, процессов и вывода) с публичными, скрытыми и, по желанию, собственными тестами репозитория как регрессионной проверкой. Кандидат прогоняется до трёх раз (по умолчанию три).
- Квитанция. Правила превращают подписанные доказательства в PASS, FAIL или INCONCLUSIVE, и проверяющий подписывает квитанцию. Каждый шаг — событие в журнале, связанном хэшами, с подписанными контрольными точками.
- Расчёт. В режиме с залогом квитанция закрывает эскроу-контракт. В теневом режиме деньги не двигаются — у вас просто остаются квитанции.
Квитанция
Квитанция — JSON-документ с четырьмя ключами: payload, payload_digest, signature и evaluator_public_key_b64url. Неизвестные ключи отклоняются.
| Поле payload | Значение |
|---|---|
| receipt_version | Для этого формата всегда rb.proof-receipt.v0.3. |
| job_id, partner_id | Работа и партнёр, у которого она размещена. |
| manifest_digest | Подписанные условия, к которым относится квитанция. |
| candidate_submission_digest | Подписанная исполнителем сдача: какой именно код оценивался. |
| evidence_digest | Подписанные доказательства из песочницы, на которых основано решение. |
| decision_digest | Решение по правилам. |
| outcome, reason_code | PASS, FAIL или INCONCLUSIVE и причина (см. ниже). |
| settlement | currency (USDC), payment_action (RELEASE_PAYMENT или REFUND_PAYMENT), payment_atomic, stipend_atomic (6 знаков) и requires_manual_review. |
| evaluator_id, evaluator_key_id | Кто подписал. Id ключа есть и в подписи и должен совпадать. |
| event_sequence, previous_event_digest | Место квитанции в журнале работы: обрезанный или переписанный журнал будет заметен. |
| issued_at, policy_id, receipt_id | Когда, по каким правилам и постоянный id. |
| previous_receipt_digest | Необязательно: квитанция, которую эта заменяет. |
Отпечаток. payload_digest — это sha256: + hex SHA-256 от payload в каноническом JSON: ключи отсортированы, без лишних пробелов, UTF-8, только целые числа, время в UTC с Z.
Подпись. Ed25519 над байтами RESULTBOND-CANONICAL-SIGNATURE-V0.1\0 + proof-receipt + \0 + канонический payload. Поле purpose подписи должно быть proof-receipt.
Исходы и причины
| Исход | Коды причин | Деньги |
|---|---|---|
| PASS | ALL_CHECKS_PASS | Оплата исполнителю, его залог возвращается. |
| FAIL | HIDDEN_TEST_FAILURE · PUBLIC_TEST_FAILURE · REGRESSION_FAILURE · CANDIDATE_TEST_ERROR · BOUND_TEST_SKIPPED · CANDIDATE_RUNTIME_FAILURE · TEST_HARNESS_TAMPERING | Оплата возвращается покупателю, плюс компенсация из залога исполнителя. |
| INCONCLUSIVE | BASELINE_NOT_REPRODUCIBLE · CANDIDATE_NOT_REPRODUCIBLE · INFRASTRUCTURE_ERROR · HIDDEN_INDEPENDENCE_NOT_PROVEN · EVIDENCE_BINDING_MISMATCH · EVIDENCE_INCONSISTENT · POLICY_VIOLATION | Ждёт человека. Независимый ревьюер подписывает: заплатить, вернуть или «никто не виноват» (оба депозита возвращаются). |
FAIL ставится, только если упали все прогоны кандидата. Нарушение лимитов в любом прогоне — FAIL. Хороший фикс никогда не получает FAIL из-за теста, который не удалось подтвердить: в таком случае исход INCONCLUSIVE.
Проверка квитанции
В браузере
Вставьте или перетащите квитанцию на /verify. Проверка идёт локально через WebCrypto, ничего не отправляется. Кнопка «Скопировать ссылку» кладёт саму квитанцию во фрагмент ссылки после #, который браузеры никогда не отправляют на сервер.
JavaScript (браузер или Node 20+)
import { verifyReceiptText } from "https://resultbond.com/js/receipt.mjs";
const result = await verifyReceiptText(receiptJson, {
trustedKeys: { "rb:evaluator:2026-10": "k3qnbpbsfVPtAtfgsbMs_H18mKRKJzRSrHUSWnBXDpQ" },
});
// { valid, trusted, outcome, payloadDigest, reasons }
if (!result.valid || !result.trusted) throw new Error(result.reasons.join("; "));
Чтобы доверять ключам, которые ResultBond публикует сейчас, загрузите их функцией trustedKeysFromKeySet из того же модуля (см. Ключи и доверие).
Python
resultbond verify-receipt receipt.json --online --text # набор ключей с resultbond.com
resultbond verify-receipt receipt.json --keyset resultbond-keys.json # без сети, сохранённый набор
Root-ключ встроен в CLI, поэтому набор ключей проверяется без дополнительных аргументов. Коды выхода: 0 — действительна и подписана доверенным ключом, 1 — недействительна или изменена, 3 — цела, но подписана ключом, которому вы не доверяете, 2 — ошибка настройки. Можно передать сразу несколько квитанций.
Python-пакет передаётся партнёрам пилота. Обе реализации проверяются на одних и тех же эталонных векторах канонического JSON, отпечатков и подписей, и обе привязывают ключ из набора к идентификатору проверяющего.
Ключи и доверие
Тот, кто проверяет квитанции, закрепляет один ключ — офлайн-ключ root ResultBond. Он подписывает набор рабочих ключей (проверяющего, песочницы, аудитора тестов), опубликованный на /.well-known/resultbond-keys.json.
| Id ключа root | rb:root:2026-10 |
| Публичный ключ root | k4kS-tpmIN5OQFjdt8Q8AJiaPC_iOa6jfhU5IIz3AUE |
| Id ключа проверяющего | rb:evaluator:2026-10 |
- Срок действия. У каждого набора ключей есть срок действия (у текущего — до 5 октября 2027 года), его переподписывают заранее. Истёкший набор отклоняется.
- Серийный номер. У каждого набора есть номер; запоминайте самый новый и отклоняйте более старые.
- Ротация. Добавляется новый ключ, старый остаётся в списке, чтобы его квитанции можно было проверить.
- Отзыв. У скомпрометированного ключа появляется время отзыва. С этого момента всё, что он подписал, отклоняется — какую бы дату ни указывала квитанция.
Эскроу-контракт
ResultBondEscrow (Solidity 0.8.28), по образцу ERC-8183. Один проверяющий, назначенный при создании работы, решает её один раз. Деньги только начисляются; каждая сторона выводит свои сама.
create(manifestDigest, provider, evaluator, payment, stipend, bondBy, decideBy) → jobId // клиент
cancel(jobId) // клиент, до залога
bond(jobId) // исполнитель, до bondBy
complete(jobId, receiptDigest) // проверяющий: PASS
reject(jobId, receiptDigest) // проверяющий: FAIL
hold(jobId, receiptDigest) // проверяющий: INCONCLUSIVE
voidHeld(jobId, reviewDigest) // проверяющий, после ревью «никто не виноват»
expire(jobId) // кто угодно, после срока
withdraw() // любой, у кого есть баланс
Id работы = keccak256(manifestDigest, client, provider, evaluator, payment, stipend, bondBy, decideBy, chainid, escrow). Он фиксирует все условия, поэтому квитанция может закрыть только ту работу, для которой выдана. Те же значения записаны в привязке escrow подписанного манифеста, и адаптер расчётов сверяет их все до отправки транзакции.
| Срок прошёл | Кто что получает |
|---|---|
| Нет залога к bondBy | Клиент: свою оплату. |
| Нет решения к decideBy | Клиент: оплату + компенсацию. |
| Работа заморожена, нет ревью 30 дней после decideBy | Каждая сторона: свой депозит. |
Тестнет Monad (сеть 10143)
| Эскроу | 0x07abd499e4708FAf1D09E99fb01f52dB6488A490 |
| Тестовый USDC | 0xb222e08B46D9FC8a0200f9C62E19199c0F72689E |
Только тестнет и тестовые токены. Перед реальными деньгами контракт пройдёт внешний аудит. Работы, закрытые на нём →
Как проходит пилот
От вас
- Доступ на чтение к одному Python-репозиторию.
- 30–50 реальных багов, исправленных или открытых.
- Агент, которого вы хотите оценить.
- Инженер примерно на два часа в неделю: просмотреть скрытые тесты и разметить часть вердиктов.
От нас
- Скрытые тесты «чёрного ящика», доказанно падающие на старом коде.
- Подписанная квитанция на каждую работу.
- Отчёт о совпадении с вашими ревьюерами.
- Итоговое решение: включать ли режим с залогом.