40 lines
2.9 KiB
Markdown
40 lines
2.9 KiB
Markdown
# Human Gates producer and notification contract
|
|
|
|
Human Gates is an account-bound release-candidate inbox. The canonical mobile route is `#/my-work/human-gates`. Reads may use the last account-scoped browser cache, but Release/Hold decisions require a live authenticated identity and an online server round trip.
|
|
|
|
## Producer intake
|
|
|
|
Authenticated producers submit `POST /api/v1/human-gates/intake` with a unique `Idempotency-Key` header and JSON such as:
|
|
|
|
```json
|
|
{
|
|
"source": "release-bot",
|
|
"project": "stackchain/dashboard",
|
|
"candidate_hash": "abc123",
|
|
"title": "Dashboard candidate",
|
|
"priority": 7,
|
|
"artifacts": [{"name": "manifest", "url": "https://forge.example/artifacts/manifest.json"}],
|
|
"links": [{"label": "change", "url": "https://forge.example/pulls/1415"}],
|
|
"checks": [{"name": "browser", "state": "success", "required": true}],
|
|
"score": {"value": 92, "provenance": "release-evaluator/v2"},
|
|
"provenance": {"producer": "release-bot", "run_id": "run-9"}
|
|
}
|
|
```
|
|
|
|
The immutable identity is authenticated account + `source` + `project` + `candidate_hash`. Retrying the same key and body returns the same gate. Reusing a key for different facts, or redefining an existing candidate hash, returns 409. A newer hash from the same source/project atomically marks older pending candidates `superseded`; detail history remains available for audit. Configure durable storage with `STACKCHAIN_HUMAN_GATE_DB` (default: `$STACKCHAIN_STATE_DIR/human-gates.sqlite3`).
|
|
|
|
Consumers list `GET /api/v1/human-gates`, inspect `GET /api/v1/human-gates/{id}`, and submit `POST /api/v1/human-gates/{id}/decision` with a new `Idempotency-Key`, `expected_revision`, and either `release` or `hold`. Hold requires a reason. Release requires all three checklist confirmations; if any required check is not successful it also requires an explicit override reason. Durable receipts are available at `GET /api/v1/human-gate-receipts/{receipt_id}`. All endpoints are authenticated, account-bound, and `Cache-Control: no-store`.
|
|
|
|
## Telegram coalescing contract
|
|
|
|
Telegram or lock-screen adapters MUST coalesce pending changes per authenticated account and expose **count and route only**:
|
|
|
|
```json
|
|
{
|
|
"pending_count": 3,
|
|
"route": "#/my-work/human-gates"
|
|
}
|
|
```
|
|
|
|
The notification text may say “3 Human Gates pending” and provide the route. It MUST NOT include project names, candidate hash values, titles, artifact/link URLs, checks, scores, provenance, decision history, superseded candidate facts, reasons, or receipts. Multiple intake/supersession events before delivery replace the pending notification with the latest count rather than emitting one message per candidate. A transition to zero clears the outstanding notification; it does not send candidate detail. Producers and adapters must fetch current state after authenticated route open rather than treating notification delivery as an action authorization.
|