diff --git a/contracts/seats/git/fixtures/events.json b/contracts/seats/git/fixtures/events.json new file mode 100644 index 00000000..877f105b --- /dev/null +++ b/contracts/seats/git/fixtures/events.json @@ -0,0 +1,122 @@ +[ + { + "name": "pull.updated is said", + "of": "event:pull-updated", + "subject": "mesh.seat.git.event.pull-updated", + "given": { + "repository": "novox/mesh-sdk", + "number": 178, + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "title": "One wiring", + "author": "jochen", + "url": "https://forge.test/p/178", + "base-head": "cccccccccccccccccccccccccccccccccccccccc", + "change": { + "paths": [ + "go/seatlist/seatlist.go" + ], + "module-dirs": [ + "go" + ] + } + } + }, + { + "name": "pull.merged is said", + "of": "event:pull-merged", + "subject": "mesh.seat.git.event.pull-merged", + "given": { + "repository": "novox/mesh-sdk", + "number": 178, + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "merge-commit": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "merged-at": "2026-11-09T19:40:00Z", + "change": { + "paths": [ + "go/seatlist/seatlist.go" + ], + "module-dirs": [ + "go" + ] + }, + "head-checks": { + "mesh/check": "success" + } + } + }, + { + "name": "pull.closed is said", + "of": "event:pull-closed", + "subject": "mesh.seat.git.event.pull-closed", + "given": { + "repository": "novox/mesh-sdk", + "number": 179, + "branch": "fix/x", + "head": "cccccccccccccccccccccccccccccccccccccccc", + "base": "main" + } + }, + { + "name": "forge.pull is said", + "of": "event:forge-pull", + "subject": "mesh.seat.git.event.forge-pull", + "given": { + "action": "synchronized", + "repository": "novox/mesh-sdk", + "number": 178, + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "author": "jochen", + "sender": "jochen" + } + }, + { + "name": "forge.status is said", + "of": "event:forge-status", + "subject": "mesh.seat.git.event.forge-status", + "given": { + "repository": "novox/mesh-sdk", + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "context": "mesh/check", + "state": "failure", + "description": "failed", + "sender": "mesh-delivery-checker" + } + }, + { + "name": "forge.delete is said", + "of": "event:forge-delete", + "subject": "mesh.seat.git.event.forge-delete", + "given": { + "repository": "novox/mesh-sdk", + "ref": "feat/47-G", + "ref-type": "branch", + "sender": "jochen" + } + }, + { + "name": "repo.writable is said", + "of": "event:repo-writable", + "subject": "mesh.seat.git.event.repo-writable", + "given": { + "repository": "jochen/notes", + "account": "mesh-delivery" + } + }, + { + "name": "a branch moved by a merge", + "of": "event:branch-moved", + "subject": "mesh.seat.git.event.branch-moved", + "given": { + "repository": "novox/mesh-catalog", + "branch": "main", + "head": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "at": "2026-11-10T10:00:00Z" + } + } +] diff --git a/contracts/seats/git/fixtures/states.json b/contracts/seats/git/fixtures/states.json new file mode 100644 index 00000000..89510c7c --- /dev/null +++ b/contracts/seats/git/fixtures/states.json @@ -0,0 +1,19 @@ +[ + { + "name": "a failed required step kept", + "of": "state:failed-steps/..", + "given": { + "v": 1, + "module": "nats", + "fingerprint": "fp-0123", + "step": "unit", + "artifact": "nats:program", + "run": "main.12.nats", + "commits": [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ], + "said": "TestTheBusWhole failed", + "at": "2026-11-10T10:00:00Z" + } + } +] diff --git a/contracts/seats/git/fixtures/verbs.json b/contracts/seats/git/fixtures/verbs.json new file mode 100644 index 00000000..ac8ceb50 --- /dev/null +++ b/contracts/seats/git/fixtures/verbs.json @@ -0,0 +1,522 @@ +[ + { + "name": "pull asks", + "of": "verb:pull.input", + "given": { + "repository": "novox/mesh-sdk", + "merge-commit": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + }, + { + "name": "pull answers", + "of": "verb:pull.answer", + "given": { + "pull": { + "repository": "novox/mesh-sdk", + "number": 178, + "title": "One wiring of the seat list", + "author": "jochen", + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "state": "merged", + "merge-commit": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "merged-at": "2026-11-09T19:40:00Z", + "url": "https://forge.test/novox/mesh-sdk/pulls/178" + } + } + }, + { + "name": "pull answers an open one with what the forge would merge now", + "of": "verb:pull.answer", + "given": { + "pull": { + "repository": "novox/mesh-sdk", + "number": 179, + "title": "One wiring of the seat list", + "author": "jochen", + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "state": "open", + "url": "https://forge.test/novox/mesh-sdk/pulls/179" + }, + "merging": { + "mergeable": false, + "protected": true, + "required": [ + "mesh/check" + ], + "writes": true + } + } + }, + { + "name": "pull answers an error, never none", + "of": "verb:pull.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge holds no pull request novox/mesh-sdk#999", + "error-kind": "refused" + } + }, + { + "name": "open-pulls asks", + "of": "verb:open-pulls.input", + "given": {} + }, + { + "name": "open-pulls answers", + "of": "verb:open-pulls.answer", + "given": { + "pulls": [ + { + "pull": { + "repository": "novox/mesh-sdk", + "number": 178, + "title": "One wiring of the seat list", + "author": "jochen", + "branch": "feat/47-G", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "base": "main", + "state": "open", + "url": "https://forge.test/novox/mesh-sdk/pulls/178" + }, + "required": [ + "mesh/check" + ], + "checks": { + "mesh/check": { + "context": "mesh/check", + "state": "success", + "description": "passed", + "target": "https://forge.test/x", + "at": "2026-11-09T19:00:00Z", + "by": "mesh-delivery-checker" + } + } + } + ] + } + }, + { + "name": "open-pulls answers none open as an empty list", + "of": "verb:open-pulls.answer", + "given": { + "pulls": [] + } + }, + { + "name": "open-pulls answers an error, never none", + "of": "verb:open-pulls.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 502", + "error-kind": "failed", + "pulls": [] + } + }, + { + "name": "tags asks", + "of": "verb:tags.input", + "given": { + "repository": "novox/mesh-sdk", + "prefix": "go/v", + "page": 1 + } + }, + { + "name": "tags answers", + "of": "verb:tags.answer", + "given": { + "repository": "novox/mesh-sdk", + "tags": [ + "go/v0.1.15", + "go/v0.1.14" + ], + "page": 1, + "bound": 50, + "more": true + } + }, + { + "name": "tags answers an error, never none", + "of": "verb:tags.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 404 for novox/nothing", + "error-kind": "refused" + } + }, + { + "name": "trees asks", + "of": "verb:trees.input", + "given": { + "repository": "novox/mesh-delivery", + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "files": [ + "contracts" + ], + "paths": { + "": [ + "go.work" + ] + } + } + }, + { + "name": "trees answers", + "of": "verb:trees.answer", + "given": { + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "root": "dddddddddddddddddddddddddddddddddddddddd", + "trees": { + "": "dddddddddddddddddddddddddddddddddddddddd", + "contracts": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + "files": { + "contracts": { + "module.json": "ffffffffffffffffffffffffffffffffffffffff" + } + }, + "paths": { + "": { + "go.work": "1111111111111111111111111111111111111111" + } + } + } + }, + { + "name": "trees answers an error, never none", + "of": "verb:trees.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge's tree listing of novox/mesh-delivery at aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa was cut; no trees are answered from a part", + "error-kind": "refused" + } + }, + { + "name": "file asks", + "of": "verb:file.input", + "given": { + "repository": "novox/mesh-contracts", + "path": "seats/index.json", + "ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "name": "file answers", + "of": "verb:file.answer", + "given": { + "path": "seats/index.json", + "ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "blob": "2222222222222222222222222222222222222222", + "size": 31, + "content": "{\"format\":1,\"seats\":[\"mesh-broker\"]}" + } + }, + { + "name": "file answers", + "of": "verb:file.answer", + "given": { + "path": "seats/gone.json", + "ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "absent": true + }, + "why": "the forge said no such file: absent, never an empty content" + }, + { + "name": "file answers an error, never none", + "of": "verb:file.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "seats/big.json is over 512 KiB", + "error-kind": "refused" + } + }, + { + "name": "contains asks", + "of": "verb:contains.input", + "given": { + "repository": "novox/mesh-sdk", + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "in": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + }, + { + "name": "contains answers", + "of": "verb:contains.answer", + "given": { + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "in": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "contains": true + } + }, + { + "name": "contains answers an error, never none", + "of": "verb:contains.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge cannot compare bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "error-kind": "refused" + } + }, + { + "name": "contains answers a commit the forge does not have as not-found", + "of": "verb:contains.answer", + "why": "a caller tells a commit the forge no longer has from a failed read by its kind, never by the forge's status in error's words", + "given": { + "error": "the forge has no commit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "error-kind": "not-found" + } + }, + { + "name": "statuses asks", + "of": "verb:statuses.input", + "given": { + "repository": "novox/mesh-sdk", + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "name": "statuses answers", + "of": "verb:statuses.answer", + "given": { + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "combined": "success", + "statuses": [ + { + "context": "mesh/check", + "state": "success", + "description": "passed", + "target": "https://forge.test/x", + "at": "2026-11-09T19:00:00Z", + "by": "mesh-delivery-checker" + } + ] + } + }, + { + "name": "statuses answers an error, never none", + "of": "verb:statuses.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 500", + "error-kind": "failed" + } + }, + { + "name": "status asks", + "of": "verb:status.input", + "given": { + "id": "owed-1", + "repository": "novox/mesh-sdk", + "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "context": "mesh/check", + "state": "pending", + "description": "checking" + } + }, + { + "name": "status answers", + "of": "verb:status.answer", + "given": { + "id": "owed-1", + "performed": true + } + }, + { + "name": "status answers an error, never none", + "of": "verb:status.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge account cannot write novox/mesh-sdk", + "error-kind": "refused" + } + }, + { + "name": "comment asks", + "of": "verb:comment.input", + "given": { + "id": "owed-2", + "repository": "novox/mesh-sdk", + "number": 178, + "text": "the delivery reached every node" + } + }, + { + "name": "comment answers", + "of": "verb:comment.answer", + "given": { + "id": "owed-2", + "held": true + }, + "why": "an id the pull request already holds is skipped" + }, + { + "name": "comment answers an error, never none", + "of": "verb:comment.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 403", + "error-kind": "refused" + } + }, + { + "name": "view asks", + "of": "verb:view.input", + "given": { + "id": "owed-3", + "repository": "novox/mesh-sdk", + "number": 178, + "text": "## Delivery" + } + }, + { + "name": "view answers", + "of": "verb:view.answer", + "given": { + "id": "owed-3", + "performed": true + } + }, + { + "name": "view answers an error, never none", + "of": "verb:view.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 502", + "error-kind": "failed" + } + }, + { + "name": "note asks", + "of": "verb:note.input", + "given": { + "id": "owed-4", + "repository": "novox/mesh-sdk", + "commit": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "line": "owed-4 delivered to ace" + } + }, + { + "name": "note answers", + "of": "verb:note.answer", + "given": { + "id": "owed-4", + "performed": true + } + }, + { + "name": "note answers an error, never none", + "of": "verb:note.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the note ref could not be pushed", + "error-kind": "failed" + } + }, + { + "name": "merge-pull asks", + "of": "verb:merge-pull.input", + "given": { + "id": "owed-5", + "repository": "novox/mesh-sdk", + "number": 178, + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "name": "merge-pull answers", + "of": "verb:merge-pull.answer", + "given": { + "id": "owed-5", + "performed": true, + "merge-commit": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + }, + { + "name": "merge-pull answers", + "of": "verb:merge-pull.answer", + "given": { + "id": "owed-5", + "refused": "the head moved: cccccccccccccccccccccccccccccccccccccccc, not the named aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "refused-kind": "head-moved" + }, + "why": "a head that moved is refused by name, not performed" + }, + { + "name": "merge-pull answers an error, never none", + "of": "verb:merge-pull.answer", + "why": "a failed read or act is an error the caller reads as a failure (design 47 *The seat git*)", + "given": { + "error": "the forge answered 502", + "error-kind": "failed" + } + }, + { + "name": "merge-pull refuses a failed required step, naming the run, the module and the step", + "of": "verb:merge-pull.answer", + "given": { + "id": "merge-7", + "refused": "unit of nats:program failed at fp-0123 in main.12.nats", + "refused-kind": "policy-failed", + "run": "main.12.nats", + "module": "nats", + "step": "unit" + } + }, + { + "name": "branch asks a branch", + "of": "verb:branch.input", + "given": { + "repository": "novox/mesh-catalog", + "branch": "main" + } + }, + { + "name": "branch answers its head and protection", + "of": "verb:branch.answer", + "given": { + "repository": "novox/mesh-catalog", + "branch": "main", + "head": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "protected": true + } + }, + { + "name": "branch answers a branch the forge does not hold", + "of": "verb:branch.answer", + "given": { + "error": "no branch beta in novox/mesh-catalog", + "error-kind": "not-found" + }, + "why": "an unknown branch is an error, never an absent head" + }, + { + "name": "tag asks", + "of": "verb:tag.input", + "given": { + "repository": "novox/mesh-sdk", + "tag": "go/v0.1.15", + "commit": "0123456789abcdef0123456789abcdef01234567" + } + }, + { + "name": "tag answers performed", + "of": "verb:tag.answer", + "given": { + "tag": "go/v0.1.15", + "performed": true + } + }, + { + "name": "tag answers an error, never none", + "of": "verb:tag.answer", + "why": "a failed act is an error the caller reads as a failure (design 47 G section 312)", + "given": { + "error": "the forge answered 403", + "error-kind": "refused" + } + } +] diff --git a/contracts/seats/git/seat.json b/contracts/seats/git/seat.json index b7c55a10..283ca432 100644 --- a/contracts/seats/git/seat.json +++ b/contracts/seats/git/seat.json @@ -2,8 +2,1567 @@ "format": 1, "seat": "git", "scope": "mesh", - "grain": "seat-list", + "grain": "whole", "domain": "Delivery", "decision": "novox/hq ADR 0111", - "delivers": "git" + "description": "The forge: every read and act a delivery part makes of the mesh's git repositories, and what the forge says happened (design 47 *The seat git*, ADR 0596 \u00a71, \u00a72). A failed read answers an error, never an empty answer. The act verbs are the forge bridge's alone.", + "delivers": "git", + "verbs": [ + { + "name": "pull", + "description": "One pull request, by its repository and number or by its merge commit: its number, base, head branch, head, merge commit, author and state; for an open one, also what the forge would merge now (merging). A pull request the forge does not hold answers an error naming it.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "its number" + }, + "merge-commit": { + "type": "string", + "description": "instead of the number: the merge commit it made" + } + }, + "additionalProperties": false, + "required": [ + "repository" + ] + }, + "answer": { + "type": "object", + "properties": { + "pull": { + "$ref": "#/defs/Pull" + }, + "merging": { + "$ref": "#/defs/Merging" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what pull answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "branch", + "description": "A branch's head, and whether a protection rule refuses a direct push and admits only merges (design 47 *The seat git*, *Watched branches and the catalog graph per branch*). A branch the forge does not hold answers the error kind not-found.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "branch": { + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "repository", + "branch" + ] + }, + "answer": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "branch": { + "type": "string" + }, + "head": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "protected": { + "type": "boolean", + "description": "a protection rule refuses a direct push and admits only merges" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what branch answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "open-pulls", + "description": "Every open pull request of every repository, its head and base, the statuses its base's protection requires and those its head has.", + "input": { + "type": "object", + "properties": {}, + "additionalProperties": false + }, + "answer": { + "type": "object", + "properties": { + "pulls": { + "type": "array", + "items": { + "$ref": "#/defs/OpenPull" + }, + "description": "every open pull request; said empty when none is open, so an answer that lacks it is never read as none" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what open-pulls answers; pulls always said, empty when none is open; error and error-kind beside an empty pulls when it fails", + "required": [ + "pulls" + ] + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "tags", + "description": "A repository's tags, a page at a time, newest first; the page's bound is said, and more when another page exists.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "prefix": { + "type": "string", + "description": "only tags starting with it" + }, + "page": { + "type": "integer", + "description": "the page, from 1" + } + }, + "additionalProperties": false, + "required": [ + "repository" + ] + }, + "answer": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the tags of this page" + }, + "page": { + "type": "integer", + "description": "the page" + }, + "bound": { + "type": "integer", + "description": "how many tags a page holds" + }, + "more": { + "type": "boolean", + "description": "another page exists" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what tags answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "trees", + "description": "The trees of one commit: the root tree and the tree of every directory that holds a module.json, by their git hashes; with files, every blob under each named directory; with paths, the object of each named path. A listing the forge cut is refused, never answered in part.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "paths": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "{directory: [path relative to it]}; the root is the empty name" + }, + "files": { + "type": "array", + "items": { + "type": "string" + }, + "description": "directories whose every blob is answered; the root is the empty name" + } + }, + "additionalProperties": false, + "required": [ + "repository", + "commit" + ] + }, + "answer": { + "type": "object", + "properties": { + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "root": { + "type": "string", + "description": "the root tree's hash" + }, + "trees": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "directory to its tree's hash, the root as the empty name" + }, + "files": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": "directory to {path: blob id}" + }, + "paths": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": "directory to {path: object id}" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what trees answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "file", + "description": "One file at one commit, branch or tag, decoded; a file over 512 KiB is refused. An absent file is answered absent only when the forge said so.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "path": { + "type": "string", + "description": "the file's path from the repository's root", + "minLength": 1 + }, + "ref": { + "type": "string", + "description": "a commit, branch or tag; the default branch when absent" + } + }, + "additionalProperties": false, + "required": [ + "repository", + "path" + ] + }, + "answer": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "the path" + }, + "ref": { + "type": "string", + "description": "what was read" + }, + "blob": { + "type": "string", + "description": "the file's git blob id" + }, + "size": { + "type": "integer", + "description": "its size in bytes" + }, + "content": { + "type": "string", + "description": "its content" + }, + "absent": { + "type": "boolean", + "description": "the forge holds no such file there" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what file answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "contains", + "description": "Whether one commit contains another: an ancestor of it, or the same.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "the commit asked about", + "minLength": 1 + }, + "in": { + "type": "string", + "description": "the commit it may be contained in", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "repository", + "commit", + "in" + ] + }, + "answer": { + "type": "object", + "properties": { + "commit": { + "type": "string", + "description": "the commit" + }, + "in": { + "type": "string", + "description": "the other" + }, + "contains": { + "type": "boolean", + "description": "in contains commit" + }, + "ahead": { + "type": "integer", + "description": "how many commits commit is ahead of in" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what contains answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "statuses", + "description": "The statuses a commit carries, the newest of each context.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + } + }, + "additionalProperties": false, + "required": [ + "repository", + "commit" + ] + }, + "answer": { + "type": "object", + "properties": { + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "combined": { + "type": "string", + "description": "the forge's combined state" + }, + "statuses": { + "type": "array", + "items": { + "$ref": "#/defs/Status" + }, + "description": "the newest of each context" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what statuses answers; error and error-kind alone when it fails" + }, + "callers": [ + "invokers" + ], + "class": "read" + }, + { + "name": "status", + "description": "Set a commit status. An act: its id is the caller's, and the same id said again sets it again to the same.", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id", + "minLength": 1 + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "context": { + "type": "string", + "description": "the context, such as mesh/check", + "minLength": 1 + }, + "state": { + "type": "string", + "description": "the state", + "enum": [ + "pending", + "success", + "failure", + "error", + "warning" + ] + }, + "description": { + "type": "string", + "description": "what it says" + }, + "target": { + "type": "string", + "description": "the page it links to" + } + }, + "additionalProperties": false, + "required": [ + "id", + "repository", + "commit", + "context", + "state" + ] + }, + "answer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id, as the caller gave it" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the act now" + }, + "held": { + "type": "boolean", + "description": "the id was already held on the pull request or the note, so nothing was done again" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what status answers; error and error-kind alone when it fails" + }, + "callers": [ + "module:mesh-delivery-forge-bridge" + ], + "class": "act" + }, + { + "name": "comment", + "description": "Add a comment to a pull request. The comment carries the act's id, and an id the pull request already holds is skipped (held).", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id", + "minLength": 1 + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "text": { + "type": "string", + "description": "the comment, markdown", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "id", + "repository", + "number", + "text" + ] + }, + "answer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id, as the caller gave it" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the act now" + }, + "held": { + "type": "boolean", + "description": "the id was already held on the pull request or the note, so nothing was done again" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what comment answers; error and error-kind alone when it fails" + }, + "callers": [ + "module:mesh-delivery-forge-bridge" + ], + "class": "act" + }, + { + "name": "view", + "description": "Keep the delivery's one view comment on a pull request: made the first time, edited in place after; it carries the act's id, and an id already held is skipped (held).", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id", + "minLength": 1 + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "text": { + "type": "string", + "description": "the view, markdown", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "id", + "repository", + "number", + "text" + ] + }, + "answer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id, as the caller gave it" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the act now" + }, + "held": { + "type": "boolean", + "description": "the id was already held on the pull request or the note, so nothing was done again" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what view answers; error and error-kind alone when it fails" + }, + "callers": [ + "module:mesh-delivery-forge-bridge" + ], + "class": "act" + }, + { + "name": "note", + "description": "Append one line to a commit's note under refs/notes/mesh-plan. The line carries the act's id, and an id the note already holds is skipped (held).", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id", + "minLength": 1 + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "line": { + "type": "string", + "description": "the line, one line", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "id", + "repository", + "commit", + "line" + ] + }, + "answer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id, as the caller gave it" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the act now" + }, + "held": { + "type": "boolean", + "description": "the id was already held on the pull request or the note, so nothing was done again" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what note answers; error and error-kind alone when it fails" + }, + "callers": [ + "module:mesh-delivery-forge-bridge" + ], + "class": "act" + }, + { + "name": "merge-pull", + "description": "Merge a pull request with the forge tools' account at the head the caller names (design 47 *Approval is a step, and a session merges a pull request*). It judges that this is still the pull request's head and that the base branch's protection refuses a direct push, read again on every branch-moved, and refuses a head when any run at its build-input fingerprint failed a required step, judged from its own state failed-steps heard from the runner's step-ended, never by a call; a head with no run yet or a passed one merges, it never waits for a run and never asks an Approve (ADR 0666 section 11). Refused, naming why: a head that moved, a branch no protection guards, a failed required step (naming the run, the module and the step), no registrations yet (ADR 0667 section 10), a merge git refuses. A pull request already merged at that head is answered performed.", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id", + "minLength": 1 + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "head": { + "type": "string", + "description": "the head the caller names", + "pattern": "^[0-9a-f]{40}$" + } + }, + "additionalProperties": false, + "required": [ + "id", + "repository", + "number", + "head" + ] + }, + "answer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "the act's id, as the caller gave it" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the act now" + }, + "held": { + "type": "boolean", + "description": "the id was already held on the pull request or the note, so nothing was done again" + }, + "merge-commit": { + "type": "string", + "description": "the merge commit" + }, + "refused": { + "type": "string", + "description": "why the forge or the holder refused the merge; the act is not performed" + }, + "refused-kind": { + "type": "string", + "enum": [ + "head-moved", + "unprotected", + "policy-failed", + "no-registrations", + "git-refused" + ], + "description": "which refusal, set with refused: head-moved, the pull request's head is not the one named; unprotected, the base branch's protection does not refuse a direct push; policy-failed, a run at the head's fingerprint failed a required step (run, module and step name it); no-registrations, no registration-changed heard yet (ADR 0667 section 10); git-refused, git refused the merge" + }, + "run": { + "type": "string", + "description": "for policy-failed, the run that failed the step: the runner's pipeline key" + }, + "module": { + "type": "string", + "description": "for policy-failed, the module" + }, + "step": { + "type": "string", + "description": "for policy-failed, the step" + }, + "error": { + "type": "string", + "description": "why the forge could not answer, or refused: set alone with error-kind, and a caller reads it as a failure, never as none" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what merge-pull answers; error and error-kind alone when it fails" + }, + "callers": [ + "persons", + "sessions" + ], + "class": "act" + }, + { + "name": "tag", + "class": "act", + "callers": [ + "seat:mesh-builds" + ], + "description": "Write the git tag of a released version, go/vMAJOR.MINOR.PATCH, at the commit its build was made from; the builder writes it only on the catalog's version-released (design 47 G section 370). A tag already at that commit is answered performed. An error answer carries error and error-kind.", + "input": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /" + }, + "tag": { + "type": "string", + "description": "the tag" + }, + "commit": { + "type": "string", + "description": "the commit it is written at" + } + }, + "additionalProperties": false, + "required": [ + "repository", + "tag", + "commit" + ] + }, + "answer": { + "type": "object", + "properties": { + "tag": { + "type": "string", + "description": "the tag, as asked" + }, + "performed": { + "type": "boolean", + "description": "the forge holds the tag at that commit now" + }, + "error": { + "type": "string", + "description": "why the forge could not write it: set alone with error-kind" + }, + "error-kind": { + "$ref": "#/defs/ErrorKind" + } + }, + "description": "what tag answers; error and error-kind alone when it fails" + } + } + ], + "events": [ + { + "name": "pull-updated", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "branch": { + "type": "string", + "description": "its head branch" + }, + "head": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "base": { + "type": "string", + "description": "the branch it merges into" + }, + "title": { + "type": "string", + "description": "its title" + }, + "author": { + "type": "string", + "description": "who opened it" + }, + "url": { + "type": "string", + "description": "its page" + }, + "base-head": { + "type": "string", + "description": "the base branch's head as the head was announced; absent when it could not be read" + }, + "change": { + "$ref": "#/defs/Change" + } + }, + "description": "a pull request's new head, announced once per head and trunk commit", + "required": [ + "repository", + "number", + "branch", + "head", + "base" + ] + } + }, + { + "name": "pull-merged", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "branch": { + "type": "string", + "description": "its head branch" + }, + "head": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "base": { + "type": "string", + "description": "the branch it merges into" + }, + "title": { + "type": "string", + "description": "its title" + }, + "author": { + "type": "string", + "description": "who opened it" + }, + "url": { + "type": "string", + "description": "its page" + }, + "merge-commit": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "merged-at": { + "type": "string", + "description": "when", + "format": "date-time" + }, + "change": { + "$ref": "#/defs/Change" + }, + "head-checks": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "the head's statuses by context, their states; absent when they could not be read" + } + }, + "description": "a pull request merged, announced once by its merge commit", + "required": [ + "repository", + "number", + "branch", + "head", + "base", + "merge-commit" + ] + } + }, + { + "name": "pull-closed", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "branch": { + "type": "string", + "description": "its head branch" + }, + "head": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "base": { + "type": "string", + "description": "the branch it merges into" + }, + "title": { + "type": "string", + "description": "its title" + }, + "author": { + "type": "string", + "description": "who opened it" + }, + "url": { + "type": "string", + "description": "its page" + } + }, + "description": "a pull request closed without a merge, announced once by its head", + "required": [ + "repository", + "number", + "branch", + "head", + "base" + ] + } + }, + { + "name": "forge-pull", + "body": { + "type": "object", + "properties": { + "action": { + "type": "string", + "description": "what the forge said: opened, reopened, synchronized, edited, closed, merged" + }, + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "its number" + }, + "branch": { + "type": "string", + "description": "its head branch" + }, + "head": { + "type": "string", + "description": "its head commit" + }, + "base": { + "type": "string", + "description": "its base branch" + }, + "author": { + "type": "string", + "description": "who opened it" + }, + "merged": { + "type": "boolean", + "description": "merged" + }, + "merge-commit": { + "type": "string", + "description": "the merge commit" + }, + "sender": { + "type": "string", + "description": "who acted" + } + }, + "description": "the forge's own webhook of a pull request, trimmed; never its description", + "required": [ + "action", + "repository", + "number" + ] + } + }, + { + "name": "forge-status", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "commit": { + "type": "string", + "description": "the commit" + }, + "context": { + "type": "string", + "description": "the context" + }, + "state": { + "type": "string", + "description": "the state" + }, + "description": { + "type": "string", + "description": "what it says" + }, + "sender": { + "type": "string", + "description": "who set it" + } + }, + "description": "the forge's own webhook of a commit status", + "required": [ + "repository", + "commit", + "context", + "state" + ] + } + }, + { + "name": "forge-delete", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "ref": { + "type": "string", + "description": "the deleted branch or tag" + }, + "ref-type": { + "type": "string", + "description": "branch or tag" + }, + "sender": { + "type": "string", + "description": "who deleted it" + } + }, + "description": "the forge's own webhook of a deleted branch or tag", + "required": [ + "repository", + "ref" + ] + } + }, + { + "name": "repo-writable", + "body": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "account": { + "type": "string", + "description": "the account that writes it now" + } + }, + "description": "a repository the forge's account can write again", + "required": [ + "repository", + "account" + ] + } + }, + { + "name": "branch-moved", + "body": { + "type": "object", + "description": "a branch's new head, by a merge or an admitted push, from the forge's push webhook (design 47 lines 507-512): its hearer takes the head from the forge's own record by the verb branch, never from this body", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "branch": { + "type": "string", + "minLength": 1 + }, + "head": { + "type": "string", + "description": "the head the webhook said, a commit's full 40-hex sha; read again by branch", + "pattern": "^[0-9a-f]{40}$" + }, + "at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "repository", + "branch" + ] + }, + "keep": { + "max-age-days": 90, + "max-mib": 64 + } + } + ], + "family": { + "name": "git.events", + "max-age-days": 7 + }, + "states": [ + { + "name": "failed-steps", + "template": "state", + "history": 1, + "description": "each failed required step by module and build-input fingerprint, heard from the runner's step-ended; an entry is deleted once none of its commits is a watched branch's head or the head an open pull request names (design 47 *The runner's kept data*)", + "key-forms": [ + { + "key": "..", + "value": { + "$ref": "#/defs/FailedStep" + }, + "description": "a failed required step" + } + ] + } + ], + "defs": { + "Pull": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "the repository, /", + "minLength": 1 + }, + "number": { + "type": "integer", + "description": "the pull request's number" + }, + "title": { + "type": "string", + "description": "its title" + }, + "author": { + "type": "string", + "description": "who opened it, the forge's login" + }, + "branch": { + "type": "string", + "description": "its head branch: what a delivery group is named by" + }, + "head": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "base": { + "type": "string", + "description": "the branch it merges into" + }, + "state": { + "type": "string", + "description": "open, merged or closed", + "enum": [ + "open", + "merged", + "closed" + ] + }, + "merge-commit": { + "type": "string", + "description": "the merge commit, once merged" + }, + "merged-at": { + "type": "string", + "description": "when it merged", + "format": "date-time" + }, + "url": { + "type": "string", + "description": "its page on the forge" + } + }, + "description": "one pull request as the forge holds it; never its description (ADR 0659 \u00a71)", + "required": [ + "repository", + "number", + "branch", + "head", + "base", + "state" + ] + }, + "Merging": { + "type": "object", + "properties": { + "mergeable": { + "type": "boolean", + "description": "the forge's own word on whether it merges into its base now: false while it is in conflict with its base, or while the forge works that out after the base moved" + }, + "protected": { + "type": "boolean", + "description": "whether a protection rule guards its base branch" + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the status contexts the base branch's protection requires; none when it requires none" + }, + "writes": { + "type": "boolean", + "description": "whether the forge's merging account may write the repository: false, its statuses and its merge are refused" + } + }, + "description": "what the forge would merge now, for an open pull request (issues 1275, 1945; ADR 0441 \u00a71): answered whole or not at all, and a read the forge could not make answers the verb's error, never a guess; absent for a merged or closed one", + "required": [ + "mergeable", + "protected", + "required", + "writes" + ] + }, + "Status": { + "type": "object", + "properties": { + "context": { + "type": "string", + "description": "the status's context, such as mesh/check" + }, + "state": { + "type": "string", + "description": "pending, success, failure, error or warning" + }, + "description": { + "type": "string", + "description": "what it says" + }, + "target": { + "type": "string", + "description": "the page it links to" + }, + "at": { + "type": "string", + "description": "when it was set", + "format": "date-time" + }, + "by": { + "type": "string", + "description": "who set it" + } + }, + "description": "the newest status of one context on a commit", + "required": [ + "context", + "state" + ] + }, + "OpenPull": { + "type": "object", + "properties": { + "pull": { + "$ref": "#/defs/Pull" + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the contexts the base branch's protection requires; none when it requires none" + }, + "checks": { + "type": "object", + "additionalProperties": { + "$ref": "#/defs/Status" + }, + "description": "the head's statuses by context, the newest of each" + } + }, + "description": "an open pull request, with the statuses its base requires and those its head has", + "required": [ + "pull", + "required", + "checks" + ] + }, + "Change": { + "type": "object", + "properties": { + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the paths it changed" + }, + "paths-truncated": { + "type": "boolean", + "description": "the forge cut the list" + }, + "removed": { + "type": "array", + "items": { + "type": "string" + }, + "description": "which of them it deleted" + }, + "module-dirs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the changed directories that hold a module at its head; absent when they could not be read" + } + }, + "description": "what a pull request changed", + "required": [ + "paths" + ] + }, + "ErrorKind": { + "type": "string", + "enum": [ + "refused", + "not-found", + "failed" + ], + "description": "which kind of error, set with error alone: refused, the forge or the holder refused and error says why in the forge's own words; not-found, the forge said that what was asked about (a repository, a commit, a pull request, a branch or a tag) does not exist, so a caller never reads it out of error's words; failed, the forge failed or could not be reached, so the act or read could not be performed" + }, + "FailedStep": { + "type": "object", + "description": "a failed required step at a build-input fingerprint, with the commits it was seen at and the run that failed it (design 47 *Judged from its own state, never by a call*); cleared by a later passing rerun of that step whose proved caller is the operator or a healer", + "properties": { + "v": { + "type": "integer", + "description": "the layout version" + }, + "module": { + "type": "string" + }, + "fingerprint": { + "type": "string", + "description": "the build-input fingerprint the step failed at" + }, + "step": { + "type": "string" + }, + "artifact": { + "type": "string", + "description": "the artifact reference, :" + }, + "run": { + "type": "string", + "description": "the run that failed it: the runner's pipeline key" + }, + "commits": { + "type": "array", + "items": { + "type": "string", + "description": "a commit, its full 40-hex sha", + "pattern": "^[0-9a-f]{40}$" + }, + "description": "every commit it was seen at" + }, + "said": { + "type": "string", + "description": "why it failed, as the runner's step-ended said" + }, + "at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "module", + "fingerprint", + "step", + "run", + "commits" + ] + } + } }