瀏覽 1.1.1 文件
1.1.1

ait-server REST API 參考

呼叫每一個 1.1.1 ait-server HTTP 操作,包含與實作對齊的請求欄位、響應、錯誤、恢復流程和安全邊界。

適用對象: 整合方、runner 作者與維運

這份參考涵蓋什麼#

這是 1.1.1 版 ait-server 發布版路由器對外暴露的完整 HTTP 介面面。 它包含 51 個路由模板71 個 HTTP 方法繫結,以及把共享路由所 接受的動作字尾展開之後的 78 個可呼叫操作

這套 API 是 JSON over HTTP,既有資源讀寫,也有 :runCi:close:submit 這類顯式的動作端點。這些動作端點是有意為之的;整個介面面 並不是嚴格統一的 CRUD API。

本章記錄的是 aitait-runner 和恢復工具所使用的服務端介面。普通 使用者應優先看 `ait` 命令指南, 因為客戶端會強制執行時序和相容性檢查,而裸 HTTP 呼叫方得自己實作 這些。

安全與傳輸邊界#

把 1.1.1 的監聽器當成可信網路內的服務邊界。不要把裸監聽器暴露到公網。 把它放在環回地址或經過審查的私有網路上,並在可信入口處終結 TLS、呼叫 方校驗、請求限額和訪問策略。預設監聽器是 127.0.0.1:8088;要換繫結地址,請使用服務端命令的顯式選項。

恢復令牌和 Worker Job 租約令牌屬於維運能力,不能替代入口處的認證。 不要記錄或洩露它們。

下面的示例中:

程式碼 · bash
BASE=http://127.0.0.1:8088
REPOSITORY_INDEX=17

通用協議規則#

定址與識別符號#

  • {repository_index}{worker_job_index} 是規範的無符號十進位制 u32 值。0 有效;01、正負號、空格以及超過 4294967295 的值 都會被拒絕。
  • Repository 名稱屬於展示和發現用的資料。名稱可以重複,也不決定權威 歸屬;決定權威的是數字形式的 Repository 索引。
  • Task、Change、Patchset、Snapshot、Land、Plan 和 revision 識別符號都是 不透明的公開識別符號。請保持它們原樣的拼寫,必要時對路徑段做 URL 編碼。
  • _at_s 結尾的時間欄位是無符號 Unix 秒。created_at 這類欄位 是 RFC 3339 字串。某個事件不存在時,投影裡通常是 null,而不是 編造一個時間戳。

請求頭與請求體限額#

JSON 請求用 Content-Type: application/json,JSON 響應用 Accept: application/json。標準 JSON 提取器套用框架預設的 2 MiB 請求體上限。 以下批次路由把請求上限提高到 2 GiB

  • zstd 批次 plan、commit 和 pull-manifest 請求;
  • zstd Object Pack 與 Tree Pack 傳輸路由;以及
  • Repository 恢復檔案上傳。

裸 pack 和恢復檔案的請求體要求確切的媒體型別:

請求體必需的 Content-Type響應型別
Object Packapplication/vnd.ait.remote-sync.object-pack+zstd同一值
Tree Packapplication/vnd.ait.remote-sync.tree-pack+zstd同一值
退役或恢復檔案application/vnd.ait.remote-authority-file.v1同一值

空的 Object Pack 和 Tree Pack 上傳會被拒絕。超過目前生效體積限額的 請求,在進入處理器之前就會被拒絕。

成功與錯誤響應#

多數成功操作傳回 200 OK,並帶上該路由特有的 JSON 值。Repository 註冊 在追加了新權威時傳回 201 Created,在傳回已匹配的既有註冊時傳回 200 OK。啟動 Repository 恢復會話傳回 201 Created

服務端生成的應用錯誤使用這個穩定的響應體:

程式碼 · json
{"error":"human-readable diagnostic"}
狀態碼含義
200讀取、冪等重放、更新、動作或二進位下載成功。
201新建了 Repository 權威或恢復會話。
400路徑值、請求欄位或狀態遷移無效,或路由自行處理的 JSON 格式有誤。
404未知的路由、Repository、實體、pack、檔案或動作字尾。
405路由存在,但這個 HTTP 方法沒有繫結。
409權威衝突、生命週期衝突、Line head 過期、受治理的目標 Line 移動,或退役確認不匹配。
413請求體超過該路由目前生效的限額。
415JSON 提取器或二進位路由拒絕了這個請求的媒體型別。
422JSON 語法可以接受,但沒法反序列化成帶型別的請求。
500權威操作損壞、不相容、I/O 失敗,或其他內部原因失敗。
503啟動尚未完成,或某個權威正忙但可重試。應用生成的 503 錯誤會帶上 Retry-After: 1

不要把診斷文字當成長期有效的機器契約來解析。請按 HTTP 狀態碼和文件 寫明的響應欄位做分支;文字留給維運人員診斷用。

啟動行為#

監聽器在全部服務權威開啟完成之前就已經可用。啟用之前:

  • GET /healthz 傳回 503{"ready":false,"status":"starting"}
  • 其他所有路徑傳回 503{"error":"ait-server is starting","ready":false,"status":"starting"}

就緒路由器會原子地替換掉啟動期代理。啟用之後, GET /healthz 傳回 200,且 ready: true

Repository 生命週期準入#

GETHEADOPTIONS 請求可以透過生命週期準入。 /v1/native/repository-authorities/{repository_index}/... 下的寫操作 通常要求 Repository 處於 active 狀態。

退役狀態查詢/啟動、退役清除、退役中止,以及 Worker Job 的 :claim:heartbeat:complete:fail 這幾個排空動作,在 Repository 退役期間仍然可用。針對退役中或已清除的 Repository 的其他寫操作會被 拒絕。這樣在途工作能排空,備份或恢復流程能走完,同時又不再接納新的 工作流程工作。

完整操作索引#

握手傳回的緊湊 endpoints 陣列只是發現用的提示,不是完整的路由列表。 下面這些表才是 1.1.1 發布版的完整介面面。

服務發現#

方法與路徑操作
GET /healthz讀取就緒狀態和權威後端。
GET /v1/handshake讀取協議、包、CI、runner 和緊湊端點能力。
GET /v1/native/capabilities讀取維運層面的 Repository 與 Worker Job 契約。

Repository 登錄檔、備份、恢復與作業#

方法與路徑操作
GET /v1/native/repository-authorities列出或發現 Repository 權威。
POST /v1/native/repository-authorities註冊一個 Repository 權威。
GET /v1/native/repository-authorities/{repository_index}讀取一個 Repository 權威。
POST /v1/native/repository-authorities/{repository_index}:runCi入隊 Repository CI。
GET /v1/native/repository-authorities/{repository_index}/retirement讀取退役的排空/匯出狀態。
POST /v1/native/repository-authorities/{repository_index}/retirement開始退役。
GET /v1/native/repository-authorities/{repository_index}/retirement/files/{file_path}下載清單中列出的一個權威檔案。
POST /v1/native/repository-authorities/{repository_index}/retirement/purge在收到確切的匯出確認之後清除。
POST /v1/native/repository-authorities/{repository_index}/retirement/abort把退役中的 Repository 恢復成 active 狀態。
POST /v1/native/repository-restores開始一次恢復會話。
PUT /v1/native/repository-restores/{restore_token}/files/{file_path}上傳清單中列出的一個恢復檔案。
POST /v1/native/repository-restores/{restore_token}/commit校驗並啟用恢復出來的 Repository。
POST /v1/native/worker-jobs:claim認領下一個匹配的外部 runner 作業。
GET /v1/native/repository-authorities/{repository_index}/worker-jobs列出 Repository 的 Worker Job。
GET /v1/native/repository-authorities/{repository_index}/worker-jobs/{worker_job_index}讀取一個 Worker Job。
POST /v1/native/repository-authorities/{repository_index}/worker-jobs/{worker_job_index}:claim認領指定的那一個作業。
POST /v1/native/repository-authorities/{repository_index}/worker-jobs/{worker_job_index}:heartbeat延長活動中的租約。
POST /v1/native/repository-authorities/{repository_index}/worker-jobs/{worker_job_index}:complete提交一次成功的嘗試。
POST /v1/native/repository-authorities/{repository_index}/worker-jobs/{worker_job_index}:fail記錄一次可重試或終態的嘗試失敗。

Line、Snapshot 與遠端同步#

方法與路徑操作
GET /v1/native/repository-authorities/{repository_index}/lines列出 Line。
GET /v1/native/repository-authorities/{repository_index}/lines/{line_name}讀取一個 Line。
PUT /v1/native/repository-authorities/{repository_index}/lines/{line_name}以比較並設定的方式建立或更新一個 Line。
POST /v1/native/repository-authorities/{repository_index}/lines/{line_name}:close關閉一個 Line。
POST /v1/native/repository-authorities/{repository_index}/snapshots:exists批次檢測 Snapshot 是否存在。
GET /v1/native/repository-authorities/{repository_index}/snapshots/{snapshot_id}匯出 Snapshot 後設資料,可選帶上內容。
POST /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/plan區分出已有和缺失的 Snapshot 與 pack。
POST /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/commit提交已上傳的 pack 後設資料、定位符、Snapshot,以及可選的 Line 更新。
GET /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/import-manifests/{snapshot_id}取得一個 Snapshot 的匯入閉包。
POST /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/pull-manifests取得一個有界祖先範圍的匯入閉包。
GET /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/object-packs/{pack_id}下載一個 Object Pack。
PUT /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/object-packs/{pack_id}上傳一個 Object Pack。
GET /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/tree-packs/{pack_id}下載一個 Tree Pack。
PUT /v1/native/repository-authorities/{repository_index}/remote-sync/zstd-bulk/tree-packs/{pack_id}上傳一個 Tree Pack。

Task 與佇列讀模型#

方法與路徑操作
GET /v1/native/repository-authorities/{repository_index}/tasks列出 Task,最新的在前。
POST /v1/native/repository-authorities/{repository_index}/tasks建立一個 Task,可選擇繫結 Plan。
POST /v1/native/repository-authorities/{repository_index}/task-start原子地建立/修訂/選定 Plan 條目、Task 和第一個 Change。
GET /v1/native/repository-authorities/{repository_index}/tasks/{task_ref}讀取一個 Task。
POST /v1/native/repository-authorities/{repository_index}/tasks/{task_ref}:close完成或放棄一個 Task。
GET /v1/native/repository-authorities/{repository_index}/read/tasks/{task_id}/audit讀取 Task 收尾證據。
GET /v1/native/repository-authorities/{repository_index}/read/queue-summary讀取佇列彙總投影。
GET /v1/native/repository-authorities/{repository_index}/read/task-queue讀取 Task 佇列投影。
GET /v1/native/repository-authorities/{repository_index}/read/reviewer-inbox讀取分配給該 Repository 的評審工作。

Change、Patchset、評審、策略、CI 與 Land#

方法與路徑操作
GET /v1/native/repository-authorities/{repository_index}/changes列出 Change,最新的在前。
POST /v1/native/repository-authorities/{repository_index}/changes在某個 Task 下建立一個 Change。
GET /v1/native/repository-authorities/{repository_index}/changes/{change_ref}讀取一個 Change。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}:close歸檔、放棄或替代一個 Change。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}:selectPatchset選定一個 Patchset。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}:requestReview向一個評審組發起評審。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}:submit為一個 Change 提交直接 Land。
GET /v1/native/repository-authorities/{repository_index}/changes/{change_ref}/patchsets按序號順序列出 Patchset。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}/patchsets發布一個 Patchset。
GET /v1/native/repository-authorities/{repository_index}/changes/{change_ref}/reviews讀取評審記錄行和彙總計數。
POST /v1/native/repository-authorities/{repository_index}/changes/{change_ref}/reviews記錄一次評審動作。
GET /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}讀取一個 Patchset 及其 CI 投影。
POST /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}:runCi啟動或複用 Patchset CI,必要時入隊一個 Worker Job。
POST /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}:evaluatePolicy評估目前的 attestation、CI 和評審關卡。
GET /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}/attestation讀取最新的 attestation。
PUT /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}/attestation追加一條新的 attestation。
GET /v1/native/repository-authorities/{repository_index}/patchsets/{patchset_id}/policy讀取最新的策略決定,或待評估狀態的投影。
GET /v1/native/repository-authorities/{repository_index}/read/patchsets/{patchset_id}/ci-status讀取緊湊的 CI 就緒度以及近期作業。
GET /v1/native/repository-authorities/{repository_index}/lands/{submission_id}讀取一次 Land 嘗試。
POST /v1/native/repository-authorities/{repository_index}/task-land原子地解析並 Land 一個 Task 或指定的 Change。
POST /v1/native/repository-authorities/{repository_index}/history-promotion:prepare為受治理的遠端 Land 準備已記錄的本地 land 歷史。

Sprint 與 Plan 權威#

方法與路徑操作
GET /v1/native/repository-authorities/{repository_index}/sprints列出 Plan,可按 artifact 路徑過濾。
POST /v1/native/repository-authorities/{repository_index}/sprints建立一個 Plan 和它的第一個 revision。
GET /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}讀取 Plan 詳情和 head revision。
PATCH /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}修改 Plan 狀態。
GET /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}/revisions列出 Plan revision,最新的在前。
POST /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}/revisions追加一個 revision,可選帶 head 比較並設定。
GET /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}/revisions/{plan_revision_id}讀取一個完整的 revision。
GET /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}/revisions/{plan_revision_id}/artifacts讀取同一個完整 revision,並帶上它打包後的 artifact 投影。
PUT /v1/native/repository-authorities/{repository_index}/sprints/{plan_id}/revisions/{plan_revision_id}/artifacts預留路由;1.1.1 拒絕寫入支撐性 artifact。
POST /v1/native/repository-authorities/{repository_index}/sprint-plan-ids/by-contains查詢匹配全部歸一化詞條的活動 Plan ID。
POST /v1/native/repository-authorities/{repository_index}/sprint-task-linkage/resolve歸一化並校驗 Task 到 Plan 的關聯。
GET /v1/native/repository-authorities/{repository_index}/read/plans/candidate-inputs讀取匹配的 Plan 及其關聯的 Task 候選。

發現類端點#

健康檢查#

程式碼 · bash
curl --fail-with-body "$BASE/healthz"

就緒時的響應:

程式碼 · json
{
  "ready": true,
  "authority_backend": "binary_v0",
  "repository_identity": "repository_index",
  "operational_capabilities": {
    "contract": "ait.server.operational-capabilities.v1",
    "repository_identity": "binary-repository-index.v0",
    "worker_job_identity": "binary-worker-job-key.v0",
    "runner_contracts": ["ait.runner.native-job.v3"]
  }
}

把 HTTP 200 加上 ready: true 當作程序已就緒。它並不能證明備份是 最新的,或者是可恢復的。

握手#

程式碼 · bash
curl --fail-with-body "$BASE/v1/handshake"

響應欄位如下:

欄位含義
ready就緒路由器的狀態。
contract_versionagent/服務端的協議相容版本。
package_version正在執行的 ait-server 包版本。
authority_backend1.1.1 中是 binary_v0
repository_identityrepository_index
ci_capabilities遠端同步特性和原生 runner 契約。
operational_capabilitiesRepository 與 Worker Job 的身份契約。
supported_async_job_types服務端已知的十種持久作業型別名。
endpoints緊湊的發現子集;不是完整的操作索引。

原生 runner 能力宣告的是 ait.runner.native-job.v3、結果契約 ait.runner.native-result.v1、佇列契約 ait.server.worker-job.service.v1、遠端 Snapshot 輸入、直接引數 執行,以及平臺對應的 ci/run.shci/run.ps1 入口。

維運能力#

GET /v1/native/capabilities 傳回 operational_capabilities 物件, 不帶更大的握手載荷。在動手寫直連的 Worker Job 客戶端之前先看它。

Repository 註冊與 Repository CI#

註冊一個權威#

程式碼 · bash
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d '{"repository_name":"ait-native-site","namespace":"w","policy_flags":0}' \
  "$BASE/v1/native/repository-authorities"
請求欄位是否必需規則
repository_name非空的 UTF-8 展示名;允許重複。
namespace零個、一個或兩個 ASCII 字母、數字、_-。服務端按確切的零填充位元組儲存。
policy_flags無符號 u8

未知欄位會被拒絕。一個非空名稱空間如果已被某個存活的 Repository 佔用, 只有在名稱和策略標誌也一致時才會走重放;否則註冊就是衝突。

程式碼 · json
{
  "contract": "ait.server.repository-registration.v1",
  "created": true,
  "repository": {
    "repository_index": 17,
    "repository_name": "ait-native-site",
    "lifecycle_kind": 1,
    "namespace": "w",
    "policy_flags": 0,
    "created_at_s": 1786800000,
    "updated_at_s": 1786800000,
    "tombstoned": false
  }
}

把響應裡的 repository_index 持久化下來。不要在多個權威共用同一個 展示名時,靠名稱重新發現再猜一個。

發現並讀取權威#

程式碼 · bash
curl --get --fail-with-body \
  --data-urlencode 'repository_name=ait-native-site' \
  "$BASE/v1/native/repository-authorities"

curl --fail-with-body \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX"

列表響應包含 contractrepositoriescount 和一個 discovery 物件。discovery.routing_authorityfalse:按名稱過濾是用來盤點 清單的,不是用來選路由的。單項響應把一個 repository 包在 ait.server.repository-authority.v1 裡。

生命週期取值為 1 active、2 retiring、3 purged。已 purged 的條目 不出現在列表發現裡。

入隊 Repository CI#

這個路由在 Repository 段上使用動作字尾:

程式碼 · bash
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d '{"snapshot_id":"SNP-EXAMPLE"}' \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX:runCi"

snapshot_id 是可選的。不填時,服務端選用邏輯 main 的目前 head。 兩種途徑都解析不到 Snapshot 時,請求失敗。響應包含 repository_indexsnapshot_id、物理的 snapshot_indexqueued、 Worker Job 投影,以及 delivery: "binary_worker_job"

Repository 退役、匯出與恢復#

退役是 API 層面針對一個完整數字 Repository 權威的備份/匯出流程。它被 刻意拆成多段:先停掉新的寫操作,讓 Worker Job 排空,校驗每個匯出檔案, 最後清除還要求一次確切的確認。

1. 開始並輪詢退役#

下面這些 POST 操作沒有請求體:

程式碼 · bash
curl --fail-with-body -X POST \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/retirement"

curl --fail-with-body \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/retirement"

響應內容為:

程式碼 · json
{
  "contract": "ait.server.repository-retirement.v1",
  "repository": {"repository_index":17,"lifecycle_kind":2},
  "drain": {"queued_worker_jobs":0,"running_worker_jobs":0},
  "ready_for_export": true,
  "manifest": {
    "schema": "ait.remote-export.v1",
    "state": "complete",
    "repo_name": "ait-native-site",
    "namespace": "w",
    "exported_at_s": 1786800100,
    "files": [
      {"path":"...","size":1234,"sha256":"..."}
    ]
  }
}

在排隊中和執行中的 Worker Job 雙雙歸零之前,manifest 一直是 null。 只有 ready_for_export: true 才是取用所列檔案的許可。

2. 下載並校驗每個檔案#

manifest.files[] 的每一條,把它的相對 path 做 URL 編碼後取用:

程式碼 · bash
curl --fail-with-body \
  -o authority-file.bin \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/retirement/files/<encoded-path>"

響應是裸的 application/vnd.ait.remote-authority-file.v1。請對照清單校驗 size 和小寫十六進位制的 sha256。目前清單裡沒有的路徑傳回 404

3. 只在匯出已持久化之後才清除#

整個未經改動的 manifest 物件 作為清除請求體 POST 過去:

程式碼 · bash
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  --data-binary @remote-export-manifest.json \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/retirement/purge"

服務端會重新計算它目前的完整匯出,並要求完全相等。不完整的確認、變過 的檔案清單,或者作業尚未排空,都會被拒絕。成功時傳回 contractpurgedalready_purged 和終態的 Repository 投影。重放同一份有效的 確認是冪等的。

中止退役#

在清除之前,這個無請求體的操作會把 Repository 恢復成 active 狀態:

程式碼 · bash
curl --fail-with-body -X POST \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/retirement/abort"

響應會報告 aborted: truealready_aborted。已 purged 的權威無法 重新啟用。

恢復一個已匯出的權威#

用校驗過的清單,加上新登錄檔條目要用的 u8 策略標誌,開一個會話:

程式碼 · bash
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d '{"manifest":<complete-manifest>,"policy_flags":0}' \
  "$BASE/v1/native/repository-restores"

帶型別的請求只接受 manifestpolicy_flags 兩個欄位。清單必須 滿足:

欄位規則
schemaait.remote-export.v1
statecomplete
repo_name非空的源 Repository 名稱。
namespace匯出時的確切名稱空間。它不能已被某個存活的 Repository 佔用。
exported_at_s以 Unix 秒錶示的匯出時間。
files{path, size, sha256} 條目組成的確切陣列。

201 響應傳回一個隨機的 32 個字元的十六進位制 restore_token,以及 state: "uploading"。未提交的會話最多接納 64 個。

按每個檔案確切的相對路徑和媒體型別逐個上傳:

程式碼 · bash
curl --fail-with-body -X PUT \
  -H 'Content-Type: application/vnd.ait.remote-authority-file.v1' \
  --data-binary @authority-file.bin \
  "$BASE/v1/native/repository-restores/$RESTORE_TOKEN/files/<encoded-path>"

每次上傳都會對照清單裡的大小和摘要做檢查。然後用無請求體的方式提交:

程式碼 · bash
curl --fail-with-body -X POST \
  "$BASE/v1/native/repository-restores/$RESTORE_TOKEN/commit"

提交會校驗整個暫存歸檔,追加一條新的數字 Repository 條目,把恢復出來 的權威歸一化到那個新索引上,並傳回 ait.server.repository-restore.v1。在同一個存活會話上重放提交,會傳回 已記錄的響應。恢復不保留舊的數字索引;響應裡的新索引才是權威。

Worker Job 相關 API#

服務端認識十種持久作業型別,但 1.1.1 的外部 runner 只能認領 7patchset.ci)和 11repo.ci)。其餘型別屬於服務端內部操作, 外部認領端點會拒絕它們。

Worker Job 狀態是 1 queued、2 running、3 succeeded 和 4 failed。 (repository_index, worker_job_index) 這一對就是公開身份。

列出與檢視#

程式碼 · bash
curl --get --fail-with-body \
  --data 'state_kind=1' \
  --data 'limit=50' \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/worker-jobs"

state_kind 可選,取值必須在 1..4limit 預設 50,必須在 11000 之間。結果按最新在前排列。每個作業投影包含識別符號、 kind/type、狀態、重試狀態、結果、嘗試次數上限、錯誤型別、Patchset 或 Snapshot 引用、可用性、加鎖與更新時間,以及墓碑狀態。Patchset CI 作業 還會帶上目前的緊湊 CI 投影。

讀取指定的某個作業:

程式碼 · bash
curl --fail-with-body \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/worker-jobs/42"

認領下一個或認領指定的#

全域性認領可以帶一個可選的 Repository 過濾條件:

程式碼 · json
{
  "accepted_job_kinds": [7, 11],
  "repository_indexes": [17],
  "accepted_runtime_contracts": ["ait.runner.native-job.v3"]
}

把它發到 POST /v1/native/worker-jobs:claim。兩個陣列都不能有重複項。 repository_indexes 為空陣列表示所有正在服務的 Repository。沒有任何 匹配時,響應是 200claimed_job: null

要認領一個已經選好的作業,把下面這個確切的請求體 POST 到 .../worker-jobs/{worker_job_index}:claim

程式碼 · json
{"accepted_runtime_contracts":["ait.runner.native-job.v3"]}

認領成功會傳回 attempt_count、十六進位制的 lease_tokenlease_expires_at_s、作業身份和 runtime_request。這個執行時請求會 選定一個遠端 Snapshot,宣告直接執行的 ci/run 引數向量,並設定超時。 請嚴格按這個請求執行;不要拿目前工作區頂替。

心跳、完成與失敗#

心跳要求帶上目前的嘗試次數和租約,並且禁止帶 detail

程式碼 · json
{"attempt_count":1,"lease_token":"<hex-token>"}

在租約到期之前,把它 POST 到 .../{worker_job_index}:heartbeat

完成必須帶 detail。對 repo.ci 來說,固定的作業型別就足以完成持久 化。對 patchset.cidetail 必須標明作業型別 7,並攜帶一份 ait.runner.native-result.v1 結果:

程式碼 · json
{
  "attempt_count": 1,
  "lease_token": "<hex-token>",
  "detail": {
    "job_kind": 7,
    "result": {
      "contract": "ait.runner.native-result.v1",
      "status": "succeeded",
      "tests_status": "pass",
      "suite_result_count": 1,
      "suite_results": [
        {"suite_id":"cargo_test","status":"pass","blocking":true}
      ]
    }
  }
}

終態結果的 statussucceededcommand_failedtimed_outtests_statuspassfail;每個 suite 的狀態是 passfailsuite_result_count 必須等於陣列長度。服務端會據此推匯出緊湊 的 CI 證據,並原子地掛到選定的 Patchset 上。

失敗必須帶上錯誤資訊和重試判斷:

程式碼 · json
{
  "attempt_count": 1,
  "lease_token": "<hex-token>",
  "detail": {
    "retryable": true,
    "error": "runner lost its isolated attempt process"
  }
}

error 的取值上限是 4,096 個字元。只有 retryable 為 true 且還有剩餘 嘗試次數時,服務端才會重新入隊。 完成、失敗和心跳都會拒絕過期的嘗試次數或租約令牌。

Line 與 Snapshot#

讀取與更新 Line#

GET .../lines 傳回全部 Line 投影。GET .../lines/{line_name} 傳回 一個投影,包含它的名稱、狀態和目前的 head_snapshot_id

用下面這個請求體建立 Line,或對它做比較並設定:

程式碼 · json
{
  "head_snapshot_id": "SNP-NEW",
  "expected_head_snapshot_id": "SNP-OLD"
}

兩個欄位都是可選且可為 null 的。expected_head_snapshot_id 是比較並 設定的守衛。直接的遠端同步可以給一條空的預設 Line 做引導、重放它目前 的 head,或者移動另一條 Line。但它不能把已初始化的預設 main 移到 另一個 Snapshot;那會傳回 409GOVERNED_TARGET_LINE_REQUIRES_LAND,必須走 Land 完成。

關閉一條 Line,POST 到 .../lines/{line_name}:close

程式碼 · json
{"status":"archived"}

省略時 status 預設為 archived

檢測 Snapshot 是否存在#

程式碼 · bash
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d '{"snapshot_ids":["SNP-A","SNP-B"]}' \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/snapshots:exists"

響應會對給定的 Snapshot ID 做分類,而不傳輸它們的內容。

匯出單個 Snapshot#

程式碼 · bash
curl --get --fail-with-body \
  --data 'include_content=true' \
  --data-urlencode 'path=src/main.rs' \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/snapshots/SNP-EXAMPLE"

include_content 預設為 truepath 可選,用來收窄匯出的檔案投影。 這是 JSON 形式的 Snapshot 匯出,不是裸 pack 下載。

zstd 批次遠端同步#

安全的傳輸順序是:先請求一個 plan,上傳缺失的裸 pack,提交它們的清單 行和 Snapshot,然後按受治理 Line 的規則讀取或更新 Line。拉取則是反向 過程:先請求一份清單,再下載它列出的 pack。

存在性 plan#

程式碼 · json
{
  "snapshot_ids": ["SNP-HEAD"],
  "object_packs": ["OPK-A", {"pack_id":"OPK-B"}],
  "tree_packs": ["TPK-A"]
}

POST 到 .../remote-sync/zstd-bulk/plan。這三個陣列都可以為空。pack 條目可以是 ID,也可以是帶 pack_id 的清單物件。響應在下面這些欄位裡 保持請求順序:

  • checked_snapshot_ids
  • present_snapshot_idsmissing_snapshot_ids
  • present_object_pack_idsmissing_object_pack_ids;以及
  • present_tree_pack_idsmissing_tree_pack_ids

裸 pack 上傳與下載#

程式碼 · bash
curl --fail-with-body -X PUT \
  -H 'Content-Type: application/vnd.ait.remote-sync.object-pack+zstd' \
  --data-binary @object-pack.zst \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/remote-sync/zstd-bulk/object-packs/OPK-A"

Tree Pack 傳輸走對應的 tree-packs 路徑和媒體型別。路徑裡的 pack_id 必須是合法的單個路徑段,而且要和上傳的 pack 後設資料一致。上傳響應會 描述被接受的 pack;GET 傳回確切的原始位元組。

Commit#

程式碼 · json
{
  "contract": "ait.remote_sync.zstd_bulk.commit.v1",
  "object_packs": [],
  "tree_packs": [],
  "blob_locators": [],
  "tree_locators": [],
  "snapshots": [],
  "line_update": null
}

每個清單欄位都接受陣列或 null;缺失的欄位按空處理。pack、定位符和 Snapshot 物件就是 import 或 pull 清單原樣給出的那些行。不要自行合成, 也不要丟掉它們的完整性欄位。line_update 存在時,包含 line_name、 可為 null 的 head_snapshot_id 和可為 null 的 expected_head_snapshot_id

響應會報告被更新插入和被跳過的 Object Pack、Tree Pack、Blob、Tree 和 Snapshot,另外還有 remote_lineline_head_updated_after_ingestraw_binary_upload: true。已有的 不可變內容只有在與權威一致時才會被跳過;不一致就是錯誤,而不是覆蓋。

import 與 pull 清單#

GET .../import-manifests/{snapshot_id} 傳回一個完整的閉包:

程式碼 · json
{
  "contract": "ait.remote_sync.zstd_bulk.import_manifest.v1",
  "repo_name": "ait-native-site",
  "snapshot_id": "SNP-HEAD",
  "snapshots": [],
  "object_packs": [],
  "tree_packs": [],
  "blob_locators": [],
  "tree_locators": [],
  "line_update": null
}

要取有界的祖先範圍,POST:

程式碼 · json
{
  "contract": "ait.remote_sync.zstd_bulk.pull_manifest.request.v1",
  "head_snapshot_id": "SNP-HEAD",
  "have_snapshot_ids": ["SNP-BOUNDARY"]
}

have_snapshot_ids 不能有重複項,條目上限是 100,000。響應契約是 ait.remote_sync.zstd_bulk.pull_manifest.v1,並額外帶上 head_snapshot_idboundary_snapshot_ids。Snapshot 行按從所需的 祖先邊界指向請求 head 的順序排列;pack 清單則做過去重並按依賴排序。 下載傳回的 pack ID,並把傳回的那些行陣列原封不動傳給目標端的 commit。

Task 生命週期#

建立與讀取 Task#

建立一個不繫結 Plan 的 Task:

程式碼 · json
{"title":"Correct release readback","intent":"Verify the published artifact"}

可選的 task_id 只有在等於服務端推匯出的下一個 ID 時才被接受。可選的 Plan 關聯要三個欄位一起用:

程式碼 · json
{
  "title": "Correct release readback",
  "intent": "Verify the published artifact",
  "plan_id": "PR-12",
  "origin_plan_revision_id": "plan-revision:19",
  "plan_item_ref": "site/release/readback"
}

如果給了 plan_id 而沒給 revision,路由會解析出目前的 head。如果給了 revision 而沒給 Plan ID,它會在選定的 Repository 內搜尋。條目必須存在 於那個 revision 中。repo_idrepository_index 這類由路由自己掌握 的欄位會被拒絕。

Task 響應包含 task_id、Repository 身份、序號、標題、意圖、Plan 關聯 和漂移投影、狀態,以及時間戳。狀態是 activecompletedabandoned

GET .../tasks 列出,用 GET .../tasks/{task_ref} 讀取,關閉則 POST 到 .../tasks/{task_ref}:close

程式碼 · json
{"status":"completed"}

關閉時接受的狀態是 completedabandonedcanceledcancelled;後三個都會投影成 abandoned

原子式 Task 啟動#

POST .../task-start 會建立或選定確切的 Plan revision 和條目,然後在 一次操作裡追加 Task 和第一個 Change:

程式碼 · json
{
  "contract": "task-start-atomic/v1",
  "idempotency_key": "client-unique-key",
  "plan_item_ref": "site/release/readback",
  "plan": {
    "action": "existing",
    "plan_id": "PR-12",
    "plan_revision_id": "plan-revision:19"
  },
  "task": {
    "title": "Correct release readback",
    "intent": "Verify the published artifact"
  },
  "change": {
    "title": "Implement verified readback",
    "base_line": "main"
  }
}

idempotency_key 必填,上限 256 位元組。plan.action 取值為:

  • existing:需要 plan_id 和目前 head 的 plan_revision_id
  • create:需要在 plan.payload 下給出一份 Plan revision 載荷;或者
  • revise:需要 plan_idplan.payload,以及目前的 expected_head_revision_id,除非那個確切的 revision 已經存在。

Task 的 Plan 關聯和 Change 的 task_id 由服務端推導;呼叫方不得自行 提供這些推導欄位。用同樣的繫結和載荷重放,會傳回已記錄的原子結果。

Task 審計與佇列#

GET .../read/tasks/{task_id}/audit?target_line=main 傳回該 Task、 它的全部 Change、目標 Line 的 head、未關閉和已 land 的 Change 計數, 以及一個結論:task_completedtask_abandonedready_to_closeno_changesin_progress

GET .../read/queue-summaryGET .../read/task-queue 接受可選的 status=<value>。前者傳回工作流程的聚合計數,後者傳回 Task 佇列的行。 GET .../read/reviewer-inbox 傳回該 Repository 目前的評審工作。這些 都是派生出來的讀模型:寫入權威請用實體路由。

Change、Patchset、評審、策略、CI 與 Land#

建立與關閉 Change#

程式碼 · json
{
  "task_id": "T-0001",
  "title": "Implement verified readback",
  "base_line": "main",
  "fork_snapshot_id": "SNP-BASE"
}

task_idtitlebase_line 是必填的。fork_snapshot_id 可選, 但如果給了,就必須等於建立時基礎 Line 的 head。可選的 change_id 必須等於服務端推匯出的完整身份或短身份。

Change 響應包含 change_id、完整的 change_ref、Task 和 Repository、 標題、基礎 Line、fork Snapshot、狀態、目前和選定的 Patchset、 land 目標,以及時間戳。狀態可以是 draftactivereviewlandedarchivedsupersededabandoned

用下列狀態之一關閉:

程式碼 · json
{"status":"archived"}

接受的取值是 archivedsupersededabandonedcanceledcancelledlanded 會被拒絕,因為那個狀態由成功的 Land 推導得出。

發布與選定 Patchset#

POST 到 .../changes/{change_ref}/patchsets

程式碼 · json
{
  "base_snapshot_id": "SNP-BASE",
  "revision_snapshot_id": "SNP-REVISION",
  "summary": "Add verified readback",
  "author_mode": "ai_with_human_review"
}

必填的作者模式取值是 human_onlyhuman_with_ai_assistai_with_human_reviewai_only_experimental。可選的 patchset_idpatchset_number 只有在與推匯出的下一個身份一致時才被接受。 用同樣的 Change/base/revision 三元組重放,會傳回已有的那個 Patchset。

Patchset 響應包含身份、Snapshot、摘要、作者與發布狀態、撤回標誌、 改動檔案的統計和路徑、評估狀態、建立時間、CI 執行序號,以及緊湊的 overall/tests/lint 證據。

選定 Patchset,POST 到 .../changes/{change_ref}:selectPatchset

程式碼 · json
{"patchset_id":"T-0001/C-01/P-02"}

這個 Patchset 必須屬於該 Change,而且不能已被撤回或作廢。

發起與記錄評審#

一次只發起一個評審組:

程式碼 · json
{
  "patchset_id": "T-0001/C-01/P-02",
  "reviewer_groups": ["maintainers"],
  "note": "Please check release semantics"
}

把它發到 .../changes/{change_ref}:requestReview。可選的 review_id 只有在與推匯出的身份一致時才被接受。

記錄一次評審,POST 到 .../changes/{change_ref}/reviews

程式碼 · json
{
  "patchset_id": "T-0001/C-01/P-02",
  "reviewer": "reviewer@example.invalid",
  "action": "approve",
  "comment": "Verified",
  "blocking": false
}

動作取值是 requestcommenttask_commentcode_review_summaryapprovetask_approverequest_changestask_request_changesdefertask_deferdismisscomment 預設為空,blocking 預設為 false。這個 Patchset 必須是其 Change 目前選定的 Patchset。

評審列表響應包含 reviews,以及核准、阻塞、評論和總計這幾個彙總計數。

Attestation 與策略#

PUT .../patchsets/{patchset_id}/attestation 追加一條 attestation:

程式碼 · json
{
  "author_mode": "ai_with_human_review",
  "verification_state": "pass",
  "revoked": false,
  "require_tests_pass": true,
  "require_human_review": true,
  "require_lint_pass": true
}

verification_state 取值為 unknownpendingpassfail。 預設值是 unknownrevoked: falserequire_tests_pass: true,人工 評審和 lint 這兩項要求預設為 false。如果給了 author_mode,它必須與 Patchset 一致。呼叫方提供的 detail.patchset_ci 會被拒絕,因為 CI 的 完成歸 Patchset 和 Worker Job 權威管。

GET .../attestation 傳回最新的 attestation,沒有時傳回 404。它包含 各項要求標誌、這條記錄是否有 CI 支撐、作者模式,以及目前的 tests/lint 彙總。

POST .../patchsets/{patchset_id}:evaluatePolicy 接受一個空 JSON 物件, 並基於最新的 attestation、緊湊 CI 和即時的評審核准追加一條決定。 GET .../policy 傳回那條決定和它的各項檢查。首次評估之前,它傳回:

程式碼 · json
{"patchset_id":"...","decision":"pending","checks":[]}

執行與檢視 Patchset CI#

用下面這個請求體啟動 CI:

程式碼 · json
{"trigger":"manual_rerun"}

POST 到 .../patchsets/{patchset_id}:runCi。不給 trigger 時預設是 manual_rerunmanual_rerunbase_stale_after_land_rerun 會顯式 推進這次執行;其他非空的 trigger 在有可用的既有終態證據時會複用它。 新啟動或仍在進行的執行透過 Worker Job 送達。響應會報告 queuedjobdeliverytrigger 和 Patchset 的 CI 投影。

檢視用:

程式碼 · bash
curl --get --fail-with-body \
  --data 'recent_limit=10' \
  --data 'projection=readiness' \
  "$BASE/v1/native/repository-authorities/$REPOSITORY_INDEX/read/patchsets/<patchset-id>/ci-status"

recent_limit 預設 10,必須在 11000 之間;唯一有名字的 投影是 readiness。 響應會報告可用性、執行序號、完成時間、狀態和計數、是否存在可用的證據、 選定的/最新的作業,以及近期作業。1.1.1 的緊湊權威在這裡不保留完整的 逐 suite 歷史,所以這個讀模型裡的 selected_suite_idssuite_results 是空的。

原子式 Task Land#

優先用這個路由,而不是直接對 Change 用 :submit

程式碼 · json
{
  "contract": "task-land-atomic/v1",
  "idempotency_key": "client-unique-land-key",
  "task_or_change_ref": "T-0001/C-01",
  "target_line": "main",
  "mode": "direct",
  "patchset_id": "T-0001/C-01/P-02",
  "expected_head_snapshot_id": "SNP-BASE"
}

contractidempotency_keytask_or_change_refmode 是必填的。 key 的上限是 256 位元組。只有當某個 Task 恰好只有一個可 land 的 Change 時,task_or_change_ref 才可以是 Task;否則請傳確切的 Change。 target_line 預設取 Change 的基礎 Line。mode 取值為 directmergeff-onlypatchset_id 可選,但必須是已選定的那個。比較並設定的 守衛可以叫 expected_head_snapshot_id,也可以叫 expected_target_line_head

成功或重放會傳回原子契約、重放標誌、頂層的 Task、Change、Patchset、 目標和已 land 的 Snapshot 識別符號,外加完整的 taskchangepatchsetland 投影,以及可選的 history_promotion 投影。

直接呼叫 POST .../changes/{change_ref}:submit 也接受這些 Land 欄位, 但不要求原子契約。它更底層,也不提供同樣的 Task 解析和冪等聚合結果。

GET .../lands/{submission_id} 讀取任意一次嘗試。Land 投影包含 選定的 Patchset、目標 Line、模式、狀態、失敗型別、結果、已 land 的 Snapshot、Line 動作,以及時間戳。失敗型別包括基礎過期、策略/評審/CI 被阻塞、衝突、目標更新失敗和內部錯誤。

history promotion 的 prepare 操作#

這個專用操作會把已記錄的本地 land 歷史,在受治理的遠端 Land 之前轉換 成遠端工作流程記錄。頂層請求是:

程式碼 · json
{
  "contract": "history-promotion-prepare/v1",
  "idempotency_key": "client-unique-promotion-key",
  "target_line": "main",
  "base_snapshot_id": "SNP-BASE",
  "revision_snapshot_id": "SNP-FINAL",
  "author_mode": "ai_with_human_review",
  "summary": "Promote recorded local history",
  "entries": []
}

entries 必須包含 1 到 64 個條目。每個條目包含:

欄位含義
local_task_idlocal_change_idlocal_change_ref原來的本地身份。
expected_remote_task_idexpected_remote_change_ref可選的失敗即中止的發布身份。
task{title, intent, plan_id?, origin_plan_revision_id?, plan_item_ref?}
change{title, base_line, fork_snapshot_id}
pre_land_target_snapshot_idlanded_snapshot_idlanded_at_s已記錄的本地 Land 邊界。
snapshots該邊界對應的 1 到 64 個 {snapshot_id, created_at_s} 條目。

這個端點會在準備聚合 Patchset 之前,校驗順序、身份、Snapshot 祖先、 Plan 繫結和冪等性。裸呼叫方應當使用相容的 ait 客戶端生成的確切回執, 而不是手工拼這份載荷。

Sprint 與 Plan API#

HTTP 路徑用的是 sprints;響應物件用的是 Plan 識別符號。一個 Plan revision 由一份 Markdown artifact 加上歸一化的條目後設資料支撐。

Plan revision 載荷#

建立和修訂共用這些欄位:

欄位是否必需含義
title建立:是;修訂:否Plan 標題,或對 revision 標題的覆蓋值。
statusdraftactivearchivedsuperseded;預設是 draftactive 會按 draft/open 狀態儲存和投影。
summaryrevision 摘要。
artifact_path相對 Repository 的 Markdown artifact 路徑。
artifact_selectorartifact 內部的穩定選擇符。
artifact_heading給人看的根標題。
items歸一化的條目陣列;預設為空。
artifact_body用來打包 revision artifact 的確切 Markdown 正文。
packed_artifact相容客戶端在用時給出的既有打包 artifact 描述符。
expected_head_revision_id僅修訂時可用,否併發修訂的比較並設定守衛。

每個 items[] 物件可以包含 plan_item_ref、條目文字、 checkbox_stateheading_path。沒有可用引用的條目,無法被 Task 關聯選中。

POST .../sprints 建立。呼叫方自行提供的 plan_id 會被拒絕,因為 它由服務端推導。用 GET .../sprints 列出;可選的 artifact_path=<exact-path> 用來收窄結果。用 GET .../sprints/{plan_id} 讀取其中一個。

更新狀態用:

程式碼 · json
{"status":"archived"}

把共用的 revision 載荷 POST 到 .../sprints/{plan_id}/revisions 就能 追加一個 revision。列出或讀取 revision 用對應的 GET 路由。

/artifacts 的 GET 路由傳回的完整 revision 投影,和 revision 的 GET 路由一樣。對應的 PUT 存在只是為了協議相容,但 1.1.1 一律拒絕它,因為 單獨寫支撐性 artifact 不屬於目前生效的緊湊 Plan 佈局。請改為把 artifact 正文放進 Plan 的建立或修訂操作裡。

Plan 查詢與 Task 關聯輔助介面#

查詢包含全部給定歸一化詞條的活動 Plan:

程式碼 · json
{"contains_terms":["release","readback"]}

POST 到 .../sprint-plan-ids/by-contains。詞條必須是 JSON 字串陣列; 歸一化後為空集時傳回空陣列。

解析 Task 關聯,把下面這些欄位的任意組合 POST 過去:

程式碼 · json
{
  "plan_id": "PR-12",
  "origin_plan_revision_id": "plan-revision:19",
  "plan_item_ref": "site/release/readback"
}

既沒有 Plan 也沒有 revision 時,三個欄位都傳回 null。沒有 Plan 關聯 的條目會被拒絕。缺失的 Plan 或 revision 身份會在這個數字 Repository 內部解析,然後再校驗歸屬關係和條目是否存在。

GET .../read/plans/candidate-inputs?contains=release,readback 會把 逗號分隔的詞條歸一化,傳回匹配的活動 Plan 以及關聯的 Task 候選。它是 給選擇類介面用的讀模型,不是寫入端點。

端到端裸 HTTP 示例#

這段精簡過的流程展示了這些較底層的 API 是怎麼串起來的。生產環境的 客戶端必須保留每一個傳回的識別符號,並在遇到任何非成功狀態時停下。

  1. GET /healthz,直到 200ready: true
  2. GET /v1/handshake;核對協議和 runner 契約。
  3. POST /v1/native/repository-authorities 註冊一次;把數字形式的 Repository 索引持久化下來。
  4. 用遠端同步的 plan、裸 pack 上傳和 commit 來發布不可變的 Snapshot 內容,同時不推進已初始化的受治理 main Line。
  5. 建立,或者原子地啟動繫結 Plan 的 Task 和 Change。
  6. 發布並選定那個 revision Snapshot 已上傳的 Patchset。
  7. 加上 attestation 和所需的評審請求。
  8. POST Patchset 的 :runCi;由一個 ait-runner 認領、心跳並完成由此 產生的 Worker Job。
  9. POST Patchset 的 :evaluatePolicy;檢視傳回的決定。
  10. POST /task-land,帶上冪等鍵和期望的目標 head。
  11. 讀取 Land 和 Task 審計;只有成功的 Land 才會推進受治理的 main, 也才允許最終完成 Task。

日常使用請讓 ait workflow readyait-runnerait task finish 來 走這套流程。直接的 API 是留給相容整合,以及需要顯式控制傳輸層的維運 人員的。

維運核驗清單#

  • 監聽器處於私有網路,或者由可信的 TLS 入口保護。
  • 健康檢查和握手分開確認;不要把緊湊的端點列表當成完整的 API 目錄。
  • 每個請求都用儲存下來的數字 Repository 索引來選路。
  • 寫操作的重試,在契約提供冪等鍵時使用冪等鍵,在 Line 可能移動的地方 使用比較並設定的 head。
  • 503 要尊重 Retry-After409 要去查清楚,而不是悶頭重試。
  • 二進位媒體型別、位元組限額、pack ID、檔案大小和摘要都要嚴格校驗。
  • 退役匯出已完整,並且獨立持久化之後,才做清除。
  • 恢復流程在隔離的伺服器上演練過,並且記下了新分配的 Repository 索引。
  • worker 租約令牌只留在記憶體或受保護的臨時狀態裡,絕不拿來當通用的 API 認證。

關於部署、儲存邊界和災難恢復流程,參見 `ait-server`:遠端權威與恢復; 關於服務端/runner 的執行邊界,參見 遠端基礎設施

版本權威

對照 1.1.1 原始碼逐條核對

這一頁是公開文件,不是第二份產品契約。要確認發布權威,請以確切的原始碼和分發契約為準。

所屬元件 Snapshot
  • ait-coreSNP-ED7593DBF982
  • ait-serverSNP-0CCD7DD2A077
  • ait-runnerSNP-35C9C133D2EE
  • ait-pythonSNP-756C731A4CC0
  • ait-nodeSNP-55E90D0A81F1