dunstan 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/dunstan.mjs +258 -111
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ report a pull request's handback before it says done ([`plugins/dunstan/`](plugi
|
|
|
27
27
|
/plugin install dunstan@barglabs
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The plugin runs the MCP server with `npx -y dunstan@0.1.
|
|
30
|
+
The plugin runs the MCP server with `npx -y dunstan@0.1.9 mcp`, the `dunstan` npm package at that
|
|
31
31
|
exact version: one self-contained file, no dependencies.
|
|
32
32
|
|
|
33
33
|
**The token.** When you enable the plugin, Claude Code asks for an optional GitHub token and keeps it
|
package/dist/dunstan.mjs
CHANGED
|
@@ -8030,7 +8030,7 @@ import { readFileSync as readFileSync7 } from "node:fs";
|
|
|
8030
8030
|
import { createHash } from "node:crypto";
|
|
8031
8031
|
|
|
8032
8032
|
// src/spec/constants.ts
|
|
8033
|
-
var SPEC_VERSION = "0.1.
|
|
8033
|
+
var SPEC_VERSION = "0.1.5";
|
|
8034
8034
|
var BLOCK_VERSION = "0.1";
|
|
8035
8035
|
var SUPPORTED_BLOCK_VERSIONS = [BLOCK_VERSION];
|
|
8036
8036
|
var BLOCK_INFO_STRING = "dunstan-handback";
|
|
@@ -9468,6 +9468,7 @@ async function readCheckRuns(client, repository, commit, excludedIds) {
|
|
|
9468
9468
|
const workflow = run.checkSuiteId === void 0 ? void 0 : workflowRuns.get(run.checkSuiteId);
|
|
9469
9469
|
if (workflow === void 0) continue;
|
|
9470
9470
|
run.workflowPath = workflow.path;
|
|
9471
|
+
if (workflow.name !== void 0) run.workflowName = workflow.name;
|
|
9471
9472
|
run.workflowRunId = workflow.id;
|
|
9472
9473
|
run.runAttempt = workflow.attempt;
|
|
9473
9474
|
}
|
|
@@ -9495,6 +9496,8 @@ async function readWorkflowRunsAt(client, repository, commit) {
|
|
|
9495
9496
|
const run = { id: int(r.id), attempt: int(r.run_attempt), path: str(r.path) };
|
|
9496
9497
|
run.path = run.path.replace(/@.*$/, "");
|
|
9497
9498
|
if (run.id < 1 || run.attempt < 1 || run.path === "") throw new ShapeError();
|
|
9499
|
+
const name = strOrNull(r.name);
|
|
9500
|
+
if (name !== null && name !== "") run.name = name;
|
|
9498
9501
|
return { suite, run };
|
|
9499
9502
|
}
|
|
9500
9503
|
);
|
|
@@ -9749,7 +9752,7 @@ async function reportFromComment(client, repository, number4, login) {
|
|
|
9749
9752
|
// src/record/checker.ts
|
|
9750
9753
|
import { readFileSync } from "node:fs";
|
|
9751
9754
|
var CHECKER_NAME = "dunstan";
|
|
9752
|
-
var CHECKER_VERSION = "0.1.
|
|
9755
|
+
var CHECKER_VERSION = "0.1.9";
|
|
9753
9756
|
function checkerIdentity(artifact) {
|
|
9754
9757
|
return {
|
|
9755
9758
|
name: CHECKER_NAME,
|
|
@@ -9922,7 +9925,7 @@ var FILES = { "handback-block-0.1.schema.json": `{
|
|
|
9922
9925
|
}
|
|
9923
9926
|
}
|
|
9924
9927
|
}
|
|
9925
|
-
`, "record-0.1.schema.json": '{\n "$schema": "https://json-schema.org/draft/2020-12/schema",\n "$id": "https://barglabs.ai/dunstan/spec/schema/record-0.1.schema.json",\n "title": "Dunstan record, v0.1",\n "description": "An in-toto Statement v1 whose predicate records one check of a handback block against the record. See spec/claim-format.md.",\n "type": "object",\n "required": ["_type", "subject", "predicateType", "predicate"],\n "additionalProperties": false,\n "properties": {\n "_type": { "const": "https://in-toto.io/Statement/v1" },\n "subject": {\n "type": "array",\n "minItems": 1,\n "maxItems": 2,\n "prefixItems": [{ "$ref": "#/$defs/commitSubject" }, { "$ref": "#/$defs/blockSubject" }],\n "items": false\n },\n "predicateType": { "const": "https://barglabs.ai/dunstan/record/v0.1" },\n "predicate": { "$ref": "#/$defs/predicate" }\n },\n "allOf": [\n {\n "if": {\n "properties": {\n "predicate": {\n "properties": { "block": { "properties": { "status": { "const": "found" } } } }\n }\n }\n },\n "then": { "properties": { "subject": { "minItems": 2 } } },\n "else": { "properties": { "subject": { "maxItems": 1 } } }\n }\n ],\n "$defs": {\n "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },\n "commitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },\n "repository": {\n "description": "owner/repo",\n "type": "string",\n "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}$"\n },\n "issueRef": {\n "description": "owner/repo#N, always fully qualified in evidence.",\n "type": "string",\n "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}#[1-9][0-9]{0,9}$"\n },\n "timestamp": {\n "type": "string",\n "format": "date-time",\n "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(?:\\\\.[0-9]+)?Z$"\n },\n "sourceKind": {\n "enum": [\n "pull_request",\n "pull_request_files",\n "pull_request_commits",\n "closing_references",\n "repository",\n "issue",\n "commit",\n "compare",\n "check_runs",\n "workflow_runs",\n "artifact",\n "deployments"\n ]\n },\n "commitSubject": {\n "type": "object",\n "required": ["name", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": {\n "type": "string",\n "pattern": "^git\\\\+https://github\\\\.com/[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}@[0-9a-f]{40}$"\n },\n "digest": {\n "type": "object",\n "required": ["gitCommit"],\n "additionalProperties": false,\n "properties": { "gitCommit": { "$ref": "#/$defs/commitSha" } }\n }\n }\n },\n "blockSubject": {\n "type": "object",\n "required": ["name", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": { "const": "handback-block" },\n "digest": {\n "type": "object",\n "required": ["sha256"],\n "additionalProperties": false,\n "properties": { "sha256": { "$ref": "#/$defs/sha256" } }\n }\n }\n },\n "predicate": {\n "type": "object",\n "required": [\n "spec",\n "checker",\n "report",\n "block",\n "subject",\n "evidence",\n "claims",\n "verdict",\n "digests",\n "rerun",\n "assurance"\n ],\n "additionalProperties": false,\n "properties": {\n "spec": {\n "description": "The spec version the checker implements, semver.",\n "type": "string",\n "pattern": "^0\\\\.1\\\\.(?:0|[1-9][0-9]*)$"\n },\n "checker": {\n "type": "object",\n "required": ["name", "version", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": { "type": "string", "minLength": 1, "maxLength": 214 },\n "version": { "type": "string", "minLength": 1, "maxLength": 100 },\n "digest": {\n "type": "object",\n "required": ["sha256"],\n "additionalProperties": false,\n "properties": { "sha256": { "$ref": "#/$defs/sha256" } }\n }\n }\n },\n "report": {\n "description": "The report\'s digest and where it was read. Never its text.",\n "type": "object",\n "required": ["sha256", "source"],\n "additionalProperties": false,\n "properties": {\n "sha256": { "$ref": "#/$defs/sha256" },\n "source": {\n "type": "object",\n "required": ["kind", "locator"],\n "additionalProperties": false,\n "properties": {\n "kind": { "enum": ["pr-body", "pr-comment", "file", "stdin", "api"] },\n "locator": { "type": "string", "minLength": 1, "maxLength": 2000 }\n }\n }\n }\n },\n "block": { "$ref": "#/$defs/block" },\n "subject": {\n "type": "object",\n "required": ["repository", "pullRequest", "headSha", "mergeSha"],\n "additionalProperties": false,\n "properties": {\n "repository": { "$ref": "#/$defs/repository" },\n "pullRequest": { "type": "integer", "minimum": 1 },\n "headSha": { "$ref": "#/$defs/commitSha" },\n "mergeSha": {\n "oneOf": [{ "$ref": "#/$defs/commitSha" }, { "type": "null" }]\n }\n }\n },\n "evidence": { "$ref": "#/$defs/evidence" },\n "claims": {\n "type": "array",\n "items": { "$ref": "#/$defs/claim" }\n },\n "verdict": { "$ref": "#/$defs/verdict" },\n "digests": {\n "type": "object",\n "required": ["claims", "evidence"],\n "additionalProperties": false,\n "properties": {\n "claims": { "$ref": "#/$defs/sha256" },\n "evidence": { "$ref": "#/$defs/sha256" }\n }\n },\n "rerun": {\n "type": "object",\n "required": ["offline", "online"],\n "additionalProperties": false,\n "properties": {\n "offline": { "type": "string", "minLength": 1, "maxLength": 2000 },\n "online": { "type": "string", "minLength": 1, "maxLength": 2000 }\n }\n },\n "assurance": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "issuer"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "unsigned" },\n "issuer": { "const": "self-generated" }\n }\n },\n {\n "type": "object",\n "required": ["status", "issuer", "keyFingerprint"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "signed" },\n "issuer": { "type": "string", "minLength": 1, "maxLength": 320 },\n "keyFingerprint": { "type": "string", "pattern": "^SHA256:[A-Za-z0-9+/]{43}$" }\n }\n }\n ]\n }\n }\n },\n "verdict": { "enum": ["pass", "fail", "unverifiable"] },\n "blockError": {\n "type": "object",\n "required": ["code"],\n "additionalProperties": false,\n "properties": {\n "code": {\n "enum": [\n "unterminated_fence",\n "invalid_json",\n "duplicate_member",\n "unsupported_version",\n "schema_violation"\n ]\n },\n "pointer": { "type": "string", "pattern": "^(?:/.*)?$" },\n "keyword": { "type": "string", "minLength": 1 }\n }\n },\n "block": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "found" },\n "sha256": { "$ref": "#/$defs/sha256" },\n "value": { "$ref": "handback-block-0.1.schema.json" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "missing" },\n "reason": { "const": "block_missing" },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "count", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ambiguous" },\n "reason": { "const": "block_ambiguous" },\n "count": { "type": "integer", "minimum": 2 },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "errors", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "invalid" },\n "reason": { "const": "block_invalid" },\n "errors": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/blockError" } },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n }\n ]\n },\n "claim": {\n "type": "object",\n "required": ["id", "check", "field", "declared", "observed", "verdict"],\n "additionalProperties": false,\n "properties": {\n "id": { "type": "string", "minLength": 1 },\n "check": { "enum": ["head", "scope", "reference", "count", "time"] },\n "field": {\n "description": "A JSON Pointer (RFC 6901) into the block.",\n "type": "string",\n "pattern": "^/.+$"\n },\n "declared": true,\n "observed": true,\n "verdict": { "$ref": "#/$defs/verdict" },\n "reason": { "$ref": "#/$defs/claimReason" }\n },\n "if": { "properties": { "verdict": { "const": "pass" } } },\n "then": { "not": { "required": ["reason"] } },\n "else": { "required": ["reason"] }\n },\n "claimReason": {\n "type": "string",\n "pattern": "^(?:head_mismatch|declared_not_changed|undeclared_file|file_list_truncated|not_closing|closing_link_unsettled|closing_base_not_default|closing_event_unsettled|not_found|not_reachable|count_mismatch|all_succeeded_mismatch|checks_incomplete|no_check_runs|no_comparable_record_field|record_not_found|record_ambiguous|not_merged|premature|no_deployment|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request|pull_request_files|pull_request_commits|closing_references|repository|issue|commit|compare|check_runs|workflow_runs|artifact|deployments))$"\n },\n "unread": {\n "description": "A section the checker could not use: its source errored, or the source answered without the field.",\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "source"],\n "properties": {\n "status": { "const": "unreadable" },\n "source": { "$ref": "#/$defs/sourceKind" }\n }\n },\n {\n "type": "object",\n "required": ["status", "field"],\n "properties": {\n "status": { "const": "unpopulated" },\n "field": { "type": "string", "pattern": "^[A-Za-z0-9_.]+$" }\n }\n }\n ]\n },\n "evidence": {\n "type": "object",\n "required": ["pullRequest", "sources"],\n "additionalProperties": false,\n "properties": {\n "pullRequest": {\n "description": "Always read: a checker that cannot read the pull request writes no record.",\n "type": "object",\n "required": [\n "status",\n "number",\n "state",\n "merged",\n "mergedAt",\n "headSha",\n "mergeSha",\n "changedFiles"\n ],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "number": { "type": "integer", "minimum": 1 },\n "state": { "enum": ["open", "closed"] },\n "merged": { "type": "boolean" },\n "mergedAt": { "oneOf": [{ "$ref": "#/$defs/timestamp" }, { "type": "null" }] },\n "headSha": { "$ref": "#/$defs/commitSha" },\n "mergeSha": { "oneOf": [{ "$ref": "#/$defs/commitSha" }, { "type": "null" }] },\n "changedFiles": { "type": "integer", "minimum": 0 }\n }\n },\n "files": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "complete", "entries"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "complete": { "type": "boolean" },\n "entries": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["path", "status"],\n "additionalProperties": false,\n "properties": {\n "path": { "type": "string", "minLength": 1 },\n "status": {\n "enum": [\n "added",\n "removed",\n "modified",\n "renamed",\n "copied",\n "changed",\n "unchanged"\n ]\n },\n "previousPath": { "type": "string", "minLength": 1 }\n }\n }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "closingReferences": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "issues"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "issues": { "type": "array", "items": { "$ref": "#/$defs/issueRef" } }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "references": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["kind", "ref", "status", "exists"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "issue" },\n "ref": { "$ref": "#/$defs/issueRef" },\n "status": { "const": "ok" },\n "exists": { "type": "boolean" },\n "resolvedAs": {\n "description": "Spec 0.1.3: the owner/repo#N GitHub answered the read of ref with, when it is another issue (an issue transferred to another repository).",\n "$ref": "#/$defs/issueRef"\n }\n },\n "if": { "required": ["resolvedAs"] },\n "then": { "properties": { "exists": { "const": true } } }\n },\n {\n "type": "object",\n "required": ["kind", "ref", "status", "exists", "reachableFromHead"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "commit" },\n "ref": { "$ref": "#/$defs/commitSha" },\n "status": { "const": "ok" },\n "exists": { "type": "boolean" },\n "reachableFromHead": { "type": "boolean" }\n }\n },\n {\n "type": "object",\n "required": ["kind", "ref"],\n "properties": {\n "kind": { "enum": ["issue", "commit"] },\n "ref": { "type": "string", "minLength": 1 }\n },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "closeEvents": {\n "description": "Spec 0.1.4: who closed each closes target that exists and is not among the closing references, read under the identity it resolves to; and the pull request\'s base, its repository\'s default branch and its commit ids.",\n "type": "object",\n "required": ["pullRequest", "targets"],\n "additionalProperties": false,\n "properties": {\n "pullRequest": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "baseRef", "defaultBranch", "commits"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "baseRef": { "type": "string", "minLength": 1 },\n "defaultBranch": {\n "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }]\n },\n "commits": {\n "type": "array",\n "uniqueItems": true,\n "items": { "$ref": "#/$defs/commitSha" }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "targets": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["ref", "status", "type", "state", "events"],\n "additionalProperties": false,\n "properties": {\n "ref": { "$ref": "#/$defs/issueRef" },\n "status": { "const": "ok" },\n "type": { "enum": ["issue", "pull_request"] },\n "state": { "enum": ["open", "closed", "merged"] },\n "events": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["at", "closer"],\n "additionalProperties": false,\n "properties": {\n "at": { "$ref": "#/$defs/timestamp" },\n "closer": {\n "oneOf": [\n { "type": "null" },\n {\n "type": "object",\n "required": ["kind", "ref"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "pull_request" },\n "ref": { "$ref": "#/$defs/issueRef" }\n }\n },\n {\n "type": "object",\n "required": ["kind", "oid"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "commit" },\n "oid": { "$ref": "#/$defs/commitSha" }\n }\n },\n {\n "type": "object",\n "required": ["kind"],\n "additionalProperties": false,\n "properties": { "kind": { "const": "other" } }\n }\n ]\n }\n }\n }\n }\n },\n "if": { "properties": { "type": { "const": "issue" } } },\n "then": { "properties": { "state": { "enum": ["open", "closed"] } } }\n },\n {\n "type": "object",\n "required": ["ref"],\n "properties": { "ref": { "$ref": "#/$defs/issueRef" } },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n }\n }\n },\n "checkRuns": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "commit", "excludedIds", "runs"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "commit": { "$ref": "#/$defs/commitSha" },\n "excludedIds": {\n "description": "Check runs left out of the count: the run the checker itself executes in.",\n "type": "array",\n "items": { "type": "integer", "minimum": 1 }\n },\n "runs": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["id", "name", "status", "conclusion"],\n "additionalProperties": false,\n "dependentRequired": {\n "workflowPath": ["checkSuiteId", "workflowRunId", "runAttempt"],\n "workflowRunId": ["workflowPath"],\n "runAttempt": ["workflowPath"]\n },\n "properties": {\n "id": { "type": "integer", "minimum": 1 },\n "name": { "type": "string" },\n "status": { "type": "string", "minLength": 1 },\n "conclusion": { "type": ["string", "null"] },\n "checkSuiteId": {\n "description": "The run\'s check suite (`check_suite.id`). A run without `workflowPath` is counted as the latest per check suite and name; a run without either is keyed by its name alone. Added in spec 0.1.4, amended 2026-10-12.",\n "type": "integer",\n "minimum": 1\n },\n "appSlug": {\n "description": "The slug of the app that created the run (`app.slug`). Recorded, not read by any check. Added in spec 0.1.4, amended 2026-10-12.",\n "type": "string",\n "minLength": 1\n },\n "workflowPath": {\n "description": "The `path` of the workflow run whose `check_suite_id` is the run\'s check suite, less any `@<ref>`, from the workflow runs at the head. Runs that have it are counted as the latest per workflow path and name. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "string",\n "minLength": 1\n },\n "workflowRunId": {\n "description": "The `id` of that workflow run. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "integer",\n "minimum": 1\n },\n "runAttempt": {\n "description": "That workflow run\'s `run_attempt` as the listing gives it, its latest attempt at the read. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "integer",\n "minimum": 1\n }\n }\n }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "testRecords": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["record", "status", "runs"],\n "additionalProperties": false,\n "properties": {\n "record": { "$ref": "handback-block-0.1.schema.json#/$defs/junitRecord" },\n "status": { "const": "ok" },\n "runs": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["runId", "runAttempt", "executed", "failed"],\n "additionalProperties": false,\n "properties": {\n "runId": { "type": "integer", "minimum": 1 },\n "runAttempt": { "type": "integer", "minimum": 1 },\n "executed": { "type": "integer", "minimum": 0 },\n "failed": { "type": "integer", "minimum": 0 }\n }\n }\n }\n }\n },\n {\n "type": "object",\n "required": ["record"],\n "properties": {\n "record": { "$ref": "handback-block-0.1.schema.json#/$defs/junitRecord" }\n },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "deployments": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["environment", "status", "deployments"],\n "additionalProperties": false,\n "properties": {\n "environment": { "type": "string", "minLength": 1 },\n "status": { "const": "ok" },\n "deployments": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["id", "sha", "relation", "successAt"],\n "additionalProperties": false,\n "properties": {\n "id": { "type": "integer", "minimum": 1 },\n "sha": { "$ref": "#/$defs/commitSha" },\n "relation": {\n "enum": ["head", "merge", "descendant", "unrelated", "unknown"]\n },\n "successAt": {\n "oneOf": [{ "$ref": "#/$defs/timestamp" }, { "type": "null" }]\n }\n }\n }\n }\n }\n },\n {\n "type": "object",\n "required": ["environment"],\n "properties": { "environment": { "type": "string", "minLength": 1 } },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "sources": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["kind", "locator", "sha256", "readAt"],\n "additionalProperties": false,\n "properties": {\n "kind": { "$ref": "#/$defs/sourceKind" },\n "locator": { "type": "string", "minLength": 1, "maxLength": 2000 },\n "sha256": { "$ref": "#/$defs/sha256" },\n "etag": { "type": "string", "minLength": 1 },\n "readAt": { "$ref": "#/$defs/timestamp" },\n "error": {\n "description": "Present when the read failed: http_<status>, network, or parse.",\n "type": "string",\n "pattern": "^(?:http_[1-5][0-9]{2}|network|parse)$"\n }\n }\n }\n }\n }\n },\n "unreadOnly": {\n "allOf": [{ "$ref": "#/$defs/unread" }],\n "unevaluatedProperties": false\n }\n }\n}\n', "record-0.2-draft.schema.json": `{
|
|
9928
|
+
`, "record-0.1.schema.json": '{\n "$schema": "https://json-schema.org/draft/2020-12/schema",\n "$id": "https://barglabs.ai/dunstan/spec/schema/record-0.1.schema.json",\n "title": "Dunstan record, v0.1",\n "description": "An in-toto Statement v1 whose predicate records one check of a handback block against the record. See spec/claim-format.md.",\n "type": "object",\n "required": ["_type", "subject", "predicateType", "predicate"],\n "additionalProperties": false,\n "properties": {\n "_type": { "const": "https://in-toto.io/Statement/v1" },\n "subject": {\n "type": "array",\n "minItems": 1,\n "maxItems": 2,\n "prefixItems": [{ "$ref": "#/$defs/commitSubject" }, { "$ref": "#/$defs/blockSubject" }],\n "items": false\n },\n "predicateType": { "const": "https://barglabs.ai/dunstan/record/v0.1" },\n "predicate": { "$ref": "#/$defs/predicate" }\n },\n "allOf": [\n {\n "if": {\n "properties": {\n "predicate": {\n "properties": { "block": { "properties": { "status": { "const": "found" } } } }\n }\n }\n },\n "then": { "properties": { "subject": { "minItems": 2 } } },\n "else": { "properties": { "subject": { "maxItems": 1 } } }\n }\n ],\n "$defs": {\n "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },\n "commitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },\n "repository": {\n "description": "owner/repo",\n "type": "string",\n "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}$"\n },\n "issueRef": {\n "description": "owner/repo#N, always fully qualified in evidence.",\n "type": "string",\n "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}#[1-9][0-9]{0,9}$"\n },\n "timestamp": {\n "type": "string",\n "format": "date-time",\n "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(?:\\\\.[0-9]+)?Z$"\n },\n "sourceKind": {\n "enum": [\n "pull_request",\n "pull_request_files",\n "pull_request_commits",\n "closing_references",\n "repository",\n "issue",\n "commit",\n "compare",\n "check_runs",\n "workflow_runs",\n "artifact",\n "deployments"\n ]\n },\n "commitSubject": {\n "type": "object",\n "required": ["name", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": {\n "type": "string",\n "pattern": "^git\\\\+https://github\\\\.com/[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})/[A-Za-z0-9._-]{1,100}@[0-9a-f]{40}$"\n },\n "digest": {\n "type": "object",\n "required": ["gitCommit"],\n "additionalProperties": false,\n "properties": { "gitCommit": { "$ref": "#/$defs/commitSha" } }\n }\n }\n },\n "blockSubject": {\n "type": "object",\n "required": ["name", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": { "const": "handback-block" },\n "digest": {\n "type": "object",\n "required": ["sha256"],\n "additionalProperties": false,\n "properties": { "sha256": { "$ref": "#/$defs/sha256" } }\n }\n }\n },\n "predicate": {\n "type": "object",\n "required": [\n "spec",\n "checker",\n "report",\n "block",\n "subject",\n "evidence",\n "claims",\n "verdict",\n "digests",\n "rerun",\n "assurance"\n ],\n "additionalProperties": false,\n "properties": {\n "spec": {\n "description": "The spec version the checker implements, semver.",\n "type": "string",\n "pattern": "^0\\\\.1\\\\.(?:0|[1-9][0-9]*)$"\n },\n "checker": {\n "type": "object",\n "required": ["name", "version", "digest"],\n "additionalProperties": false,\n "properties": {\n "name": { "type": "string", "minLength": 1, "maxLength": 214 },\n "version": { "type": "string", "minLength": 1, "maxLength": 100 },\n "digest": {\n "type": "object",\n "required": ["sha256"],\n "additionalProperties": false,\n "properties": { "sha256": { "$ref": "#/$defs/sha256" } }\n }\n }\n },\n "report": {\n "description": "The report\'s digest and where it was read. Never its text.",\n "type": "object",\n "required": ["sha256", "source"],\n "additionalProperties": false,\n "properties": {\n "sha256": { "$ref": "#/$defs/sha256" },\n "source": {\n "type": "object",\n "required": ["kind", "locator"],\n "additionalProperties": false,\n "properties": {\n "kind": { "enum": ["pr-body", "pr-comment", "file", "stdin", "api"] },\n "locator": { "type": "string", "minLength": 1, "maxLength": 2000 }\n }\n }\n }\n },\n "block": { "$ref": "#/$defs/block" },\n "subject": {\n "type": "object",\n "required": ["repository", "pullRequest", "headSha", "mergeSha"],\n "additionalProperties": false,\n "properties": {\n "repository": { "$ref": "#/$defs/repository" },\n "pullRequest": { "type": "integer", "minimum": 1 },\n "headSha": { "$ref": "#/$defs/commitSha" },\n "mergeSha": {\n "oneOf": [{ "$ref": "#/$defs/commitSha" }, { "type": "null" }]\n }\n }\n },\n "evidence": { "$ref": "#/$defs/evidence" },\n "claims": {\n "type": "array",\n "items": { "$ref": "#/$defs/claim" }\n },\n "verdict": { "$ref": "#/$defs/verdict" },\n "digests": {\n "type": "object",\n "required": ["claims", "evidence"],\n "additionalProperties": false,\n "properties": {\n "claims": { "$ref": "#/$defs/sha256" },\n "evidence": { "$ref": "#/$defs/sha256" }\n }\n },\n "rerun": {\n "type": "object",\n "required": ["offline", "online"],\n "additionalProperties": false,\n "properties": {\n "offline": { "type": "string", "minLength": 1, "maxLength": 2000 },\n "online": { "type": "string", "minLength": 1, "maxLength": 2000 }\n }\n },\n "assurance": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "issuer"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "unsigned" },\n "issuer": { "const": "self-generated" }\n }\n },\n {\n "type": "object",\n "required": ["status", "issuer", "keyFingerprint"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "signed" },\n "issuer": { "type": "string", "minLength": 1, "maxLength": 320 },\n "keyFingerprint": { "type": "string", "pattern": "^SHA256:[A-Za-z0-9+/]{43}$" }\n }\n }\n ]\n }\n }\n },\n "verdict": { "enum": ["pass", "fail", "unverifiable"] },\n "blockError": {\n "type": "object",\n "required": ["code"],\n "additionalProperties": false,\n "properties": {\n "code": {\n "enum": [\n "unterminated_fence",\n "invalid_json",\n "duplicate_member",\n "unsupported_version",\n "schema_violation"\n ]\n },\n "pointer": { "type": "string", "pattern": "^(?:/.*)?$" },\n "keyword": { "type": "string", "minLength": 1 }\n }\n },\n "block": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "found" },\n "sha256": { "$ref": "#/$defs/sha256" },\n "value": { "$ref": "handback-block-0.1.schema.json" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "missing" },\n "reason": { "const": "block_missing" },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "count", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ambiguous" },\n "reason": { "const": "block_ambiguous" },\n "count": { "type": "integer", "minimum": 2 },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n },\n {\n "type": "object",\n "required": ["status", "reason", "errors", "sha256", "value"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "invalid" },\n "reason": { "const": "block_invalid" },\n "errors": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/blockError" } },\n "sha256": { "type": "null" },\n "value": { "type": "null" }\n }\n }\n ]\n },\n "claim": {\n "type": "object",\n "required": ["id", "check", "field", "declared", "observed", "verdict"],\n "additionalProperties": false,\n "properties": {\n "id": { "type": "string", "minLength": 1 },\n "check": { "enum": ["head", "scope", "reference", "count", "time"] },\n "field": {\n "description": "A JSON Pointer (RFC 6901) into the block.",\n "type": "string",\n "pattern": "^/.+$"\n },\n "declared": true,\n "observed": true,\n "verdict": { "$ref": "#/$defs/verdict" },\n "reason": { "$ref": "#/$defs/claimReason" }\n },\n "if": { "properties": { "verdict": { "const": "pass" } } },\n "then": { "not": { "required": ["reason"] } },\n "else": { "required": ["reason"] }\n },\n "claimReason": {\n "type": "string",\n "pattern": "^(?:head_mismatch|declared_not_changed|undeclared_file|file_list_truncated|not_closing|closing_link_unsettled|closing_base_not_default|closing_event_unsettled|not_found|not_reachable|count_mismatch|all_succeeded_mismatch|checks_incomplete|no_check_runs|no_comparable_record_field|record_not_found|record_ambiguous|not_merged|premature|no_deployment|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request|pull_request_files|pull_request_commits|closing_references|repository|issue|commit|compare|check_runs|workflow_runs|artifact|deployments))$"\n },\n "unread": {\n "description": "A section the checker could not use: its source errored, or the source answered without the field.",\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "source"],\n "properties": {\n "status": { "const": "unreadable" },\n "source": { "$ref": "#/$defs/sourceKind" }\n }\n },\n {\n "type": "object",\n "required": ["status", "field"],\n "properties": {\n "status": { "const": "unpopulated" },\n "field": { "type": "string", "pattern": "^[A-Za-z0-9_.]+$" }\n }\n }\n ]\n },\n "evidence": {\n "type": "object",\n "required": ["pullRequest", "sources"],\n "additionalProperties": false,\n "properties": {\n "pullRequest": {\n "description": "Always read: a checker that cannot read the pull request writes no record.",\n "type": "object",\n "required": [\n "status",\n "number",\n "state",\n "merged",\n "mergedAt",\n "headSha",\n "mergeSha",\n "changedFiles"\n ],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "number": { "type": "integer", "minimum": 1 },\n "state": { "enum": ["open", "closed"] },\n "merged": { "type": "boolean" },\n "mergedAt": { "oneOf": [{ "$ref": "#/$defs/timestamp" }, { "type": "null" }] },\n "headSha": { "$ref": "#/$defs/commitSha" },\n "mergeSha": { "oneOf": [{ "$ref": "#/$defs/commitSha" }, { "type": "null" }] },\n "changedFiles": { "type": "integer", "minimum": 0 }\n }\n },\n "files": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "complete", "entries"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "complete": { "type": "boolean" },\n "entries": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["path", "status"],\n "additionalProperties": false,\n "properties": {\n "path": { "type": "string", "minLength": 1 },\n "status": {\n "enum": [\n "added",\n "removed",\n "modified",\n "renamed",\n "copied",\n "changed",\n "unchanged"\n ]\n },\n "previousPath": { "type": "string", "minLength": 1 }\n }\n }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "closingReferences": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "issues"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "issues": { "type": "array", "items": { "$ref": "#/$defs/issueRef" } }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "references": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["kind", "ref", "status", "exists"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "issue" },\n "ref": { "$ref": "#/$defs/issueRef" },\n "status": { "const": "ok" },\n "exists": { "type": "boolean" },\n "resolvedAs": {\n "description": "Spec 0.1.3: the owner/repo#N GitHub answered the read of ref with, when it is another issue (an issue transferred to another repository).",\n "$ref": "#/$defs/issueRef"\n }\n },\n "if": { "required": ["resolvedAs"] },\n "then": { "properties": { "exists": { "const": true } } }\n },\n {\n "type": "object",\n "required": ["kind", "ref", "status", "exists", "reachableFromHead"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "commit" },\n "ref": { "$ref": "#/$defs/commitSha" },\n "status": { "const": "ok" },\n "exists": { "type": "boolean" },\n "reachableFromHead": { "type": "boolean" }\n }\n },\n {\n "type": "object",\n "required": ["kind", "ref"],\n "properties": {\n "kind": { "enum": ["issue", "commit"] },\n "ref": { "type": "string", "minLength": 1 }\n },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "closeEvents": {\n "description": "Spec 0.1.4: who closed each closes target that exists and is not among the closing references, read under the identity it resolves to; and the pull request\'s base, its repository\'s default branch and its commit ids.",\n "type": "object",\n "required": ["pullRequest", "targets"],\n "additionalProperties": false,\n "properties": {\n "pullRequest": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "baseRef", "defaultBranch", "commits"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "baseRef": { "type": "string", "minLength": 1 },\n "defaultBranch": {\n "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }]\n },\n "commits": {\n "type": "array",\n "uniqueItems": true,\n "items": { "$ref": "#/$defs/commitSha" }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "targets": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["ref", "status", "type", "state", "events"],\n "additionalProperties": false,\n "properties": {\n "ref": { "$ref": "#/$defs/issueRef" },\n "status": { "const": "ok" },\n "type": { "enum": ["issue", "pull_request"] },\n "state": { "enum": ["open", "closed", "merged"] },\n "events": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["at", "closer"],\n "additionalProperties": false,\n "properties": {\n "at": { "$ref": "#/$defs/timestamp" },\n "closer": {\n "oneOf": [\n { "type": "null" },\n {\n "type": "object",\n "required": ["kind", "ref"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "pull_request" },\n "ref": { "$ref": "#/$defs/issueRef" }\n }\n },\n {\n "type": "object",\n "required": ["kind", "oid"],\n "additionalProperties": false,\n "properties": {\n "kind": { "const": "commit" },\n "oid": { "$ref": "#/$defs/commitSha" }\n }\n },\n {\n "type": "object",\n "required": ["kind"],\n "additionalProperties": false,\n "properties": { "kind": { "const": "other" } }\n }\n ]\n }\n }\n }\n }\n },\n "if": { "properties": { "type": { "const": "issue" } } },\n "then": { "properties": { "state": { "enum": ["open", "closed"] } } }\n },\n {\n "type": "object",\n "required": ["ref"],\n "properties": { "ref": { "$ref": "#/$defs/issueRef" } },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n }\n }\n },\n "checkRuns": {\n "oneOf": [\n {\n "type": "object",\n "required": ["status", "commit", "excludedIds", "runs"],\n "additionalProperties": false,\n "properties": {\n "status": { "const": "ok" },\n "commit": { "$ref": "#/$defs/commitSha" },\n "excludedIds": {\n "description": "Check runs left out of the count: the run the checker itself executes in.",\n "type": "array",\n "items": { "type": "integer", "minimum": 1 }\n },\n "runs": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["id", "name", "status", "conclusion"],\n "additionalProperties": false,\n "dependentRequired": {\n "workflowPath": ["checkSuiteId", "workflowRunId", "runAttempt"],\n "workflowName": ["workflowPath"],\n "workflowRunId": ["workflowPath"],\n "runAttempt": ["workflowPath"]\n },\n "properties": {\n "id": { "type": "integer", "minimum": 1 },\n "name": { "type": "string" },\n "status": { "type": "string", "minLength": 1 },\n "conclusion": { "type": ["string", "null"] },\n "checkSuiteId": {\n "description": "The run\'s check suite (`check_suite.id`). A run without `workflowPath` is counted as the latest per check suite and name; a run without either is keyed by its name alone. Added in spec 0.1.4, amended 2026-10-12.",\n "type": "integer",\n "minimum": 1\n },\n "appSlug": {\n "description": "The slug of the app that created the run (`app.slug`). Recorded, not read by any check. Added in spec 0.1.4, amended 2026-10-12.",\n "type": "string",\n "minLength": 1\n },\n "workflowPath": {\n "description": "The `path` of the workflow run whose `check_suite_id` is the run\'s check suite, less any `@<ref>`, from the workflow runs at the head. Runs that have it are counted as the latest per workflow path and name. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "string",\n "minLength": 1\n },\n "workflowName": {\n "description": "The `name` of that workflow run, as the listing gives it; absent where the listing gives none, null or the empty string. No 0.1 check reads it. Added in spec 0.1.5.",\n "type": "string",\n "minLength": 1\n },\n "workflowRunId": {\n "description": "The `id` of that workflow run. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "integer",\n "minimum": 1\n },\n "runAttempt": {\n "description": "That workflow run\'s `run_attempt` as the listing gives it, its latest attempt at the read. Added in spec 0.1.4, amended 2026-10-13.",\n "type": "integer",\n "minimum": 1\n }\n }\n }\n }\n }\n },\n { "$ref": "#/$defs/unreadOnly" }\n ]\n },\n "testRecords": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["record", "status", "runs"],\n "additionalProperties": false,\n "properties": {\n "record": { "$ref": "handback-block-0.1.schema.json#/$defs/junitRecord" },\n "status": { "const": "ok" },\n "runs": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["runId", "runAttempt", "executed", "failed"],\n "additionalProperties": false,\n "properties": {\n "runId": { "type": "integer", "minimum": 1 },\n "runAttempt": { "type": "integer", "minimum": 1 },\n "executed": { "type": "integer", "minimum": 0 },\n "failed": { "type": "integer", "minimum": 0 }\n }\n }\n }\n }\n },\n {\n "type": "object",\n "required": ["record"],\n "properties": {\n "record": { "$ref": "handback-block-0.1.schema.json#/$defs/junitRecord" }\n },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "deployments": {\n "type": "array",\n "items": {\n "oneOf": [\n {\n "type": "object",\n "required": ["environment", "status", "deployments"],\n "additionalProperties": false,\n "properties": {\n "environment": { "type": "string", "minLength": 1 },\n "status": { "const": "ok" },\n "deployments": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["id", "sha", "relation", "successAt"],\n "additionalProperties": false,\n "properties": {\n "id": { "type": "integer", "minimum": 1 },\n "sha": { "$ref": "#/$defs/commitSha" },\n "relation": {\n "enum": ["head", "merge", "descendant", "unrelated", "unknown"]\n },\n "successAt": {\n "oneOf": [{ "$ref": "#/$defs/timestamp" }, { "type": "null" }]\n }\n }\n }\n }\n }\n },\n {\n "type": "object",\n "required": ["environment"],\n "properties": { "environment": { "type": "string", "minLength": 1 } },\n "allOf": [{ "$ref": "#/$defs/unread" }]\n }\n ]\n }\n },\n "sources": {\n "type": "array",\n "items": {\n "type": "object",\n "required": ["kind", "locator", "sha256", "readAt"],\n "additionalProperties": false,\n "properties": {\n "kind": { "$ref": "#/$defs/sourceKind" },\n "locator": { "type": "string", "minLength": 1, "maxLength": 2000 },\n "sha256": { "$ref": "#/$defs/sha256" },\n "etag": { "type": "string", "minLength": 1 },\n "readAt": { "$ref": "#/$defs/timestamp" },\n "error": {\n "description": "Present when the read failed: http_<status>, network, or parse.",\n "type": "string",\n "pattern": "^(?:http_[1-5][0-9]{2}|network|parse)$"\n }\n }\n }\n }\n }\n },\n "unreadOnly": {\n "allOf": [{ "$ref": "#/$defs/unread" }],\n "unevaluatedProperties": false\n }\n }\n}\n', "record-0.2-draft.schema.json": `{
|
|
9926
9929
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
9927
9930
|
"$id": "https://barglabs.ai/dunstan/spec/schema/record-0.2-draft.schema.json",
|
|
9928
9931
|
"title": "Dunstan record, DRAFT 0.2.0",
|
|
@@ -10408,7 +10411,7 @@ var FILES = { "handback-block-0.1.schema.json": `{
|
|
|
10408
10411
|
},
|
|
10409
10412
|
"readerReason": {
|
|
10410
10413
|
"type": "string",
|
|
10411
|
-
"pattern": "^(?:no_matching_record_item|declared_item_not_among_candidates|candidate_not_in_evidence|ambiguous_candidates|no_comparable_record_field|file_list_truncated|checks_incomplete|all_succeeded_mismatch|test_not_executed|test_outcome_mismatch|not_closing|not_found|closing_link_unsettled|closing_base_not_default|closing_event_unsettled|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request_files|check_runs|pull_request_commits|closing_references|repository|issue|timeline|artifact))$"
|
|
10414
|
+
"pattern": "^(?:no_matching_record_item|declared_item_not_among_candidates|candidate_not_in_evidence|ambiguous_candidates|workflow_not_in_record|workflow_name_ambiguous|no_comparable_record_field|file_list_truncated|checks_incomplete|all_succeeded_mismatch|test_not_executed|test_outcome_mismatch|not_closing|not_found|closing_link_unsettled|closing_base_not_default|closing_event_unsettled|evidence_field_unpopulated:[A-Za-z0-9_.]+|source_unreadable:(?:pull_request_files|check_runs|pull_request_commits|closing_references|repository|issue|timeline|artifact))$"
|
|
10412
10415
|
}
|
|
10413
10416
|
}
|
|
10414
10417
|
}
|
|
@@ -12332,6 +12335,196 @@ function extractClaims(report) {
|
|
|
12332
12335
|
return out;
|
|
12333
12336
|
}
|
|
12334
12337
|
|
|
12338
|
+
// src/retrieval/identifiers.ts
|
|
12339
|
+
var MIN_NAME_LENGTH = 4;
|
|
12340
|
+
var SHA2 = /(?<![0-9A-Za-z])[0-9a-fA-F]{7,40}(?![0-9A-Za-z])/g;
|
|
12341
|
+
var ISSUE2 = /(?<![\w/.-])((?:[A-Za-z0-9][A-Za-z0-9-]{0,38}\/[A-Za-z0-9._-]{1,100})?#[1-9][0-9]{0,9})(?![0-9])/g;
|
|
12342
|
+
var WORD = /[A-Za-z0-9_]/;
|
|
12343
|
+
var PATH_CHAR = /[A-Za-z0-9._/-]/;
|
|
12344
|
+
var JOB_NAME_CHAR = /[A-Za-z0-9_-]/;
|
|
12345
|
+
function stringLeaves(value, out) {
|
|
12346
|
+
if (typeof value === "string") out.push(value);
|
|
12347
|
+
else if (Array.isArray(value)) for (const v of value) stringLeaves(v, out);
|
|
12348
|
+
else if (value !== null && typeof value === "object")
|
|
12349
|
+
for (const v of Object.values(value)) stringLeaves(v, out);
|
|
12350
|
+
return out;
|
|
12351
|
+
}
|
|
12352
|
+
function claimTexts(claim2) {
|
|
12353
|
+
return [claim2.text, ...stringLeaves(claim2.declaredValue, [])];
|
|
12354
|
+
}
|
|
12355
|
+
function boundedAt(haystack, needle, inside) {
|
|
12356
|
+
const out = [];
|
|
12357
|
+
if (needle.length === 0) return out;
|
|
12358
|
+
for (let at = haystack.indexOf(needle); at !== -1; at = haystack.indexOf(needle, at + 1)) {
|
|
12359
|
+
const before = haystack[at - 1];
|
|
12360
|
+
const after = haystack[at + needle.length];
|
|
12361
|
+
const next = haystack[at + needle.length + 1];
|
|
12362
|
+
const openBefore = before === void 0 || !inside.test(before);
|
|
12363
|
+
const openAfter = after === void 0 || !inside.test(after) || after === "." && (next === void 0 || !/[A-Za-z0-9]/.test(next));
|
|
12364
|
+
if (openBefore && openAfter) out.push(at);
|
|
12365
|
+
}
|
|
12366
|
+
return out;
|
|
12367
|
+
}
|
|
12368
|
+
function occursBounded(haystack, needle, inside) {
|
|
12369
|
+
return boundedAt(haystack, needle, inside).length > 0;
|
|
12370
|
+
}
|
|
12371
|
+
function classnameSpans(text, classname) {
|
|
12372
|
+
const forms = /* @__PURE__ */ new Set([classname, classname.replaceAll(".", " ")]);
|
|
12373
|
+
return [...forms].flatMap(
|
|
12374
|
+
(form) => boundedAt(text, form, WORD).map((at) => [at, at + form.length])
|
|
12375
|
+
);
|
|
12376
|
+
}
|
|
12377
|
+
function classnameNamed(text, classname, classnames) {
|
|
12378
|
+
const longer = classnames.filter((c) => c.length > classname.length).flatMap((c) => classnameSpans(text, c));
|
|
12379
|
+
return classnameSpans(text, classname).some(
|
|
12380
|
+
([from, to]) => !longer.some(([l, r]) => l <= from && to <= r)
|
|
12381
|
+
);
|
|
12382
|
+
}
|
|
12383
|
+
var CHECK_RUN_EVENTS = ["push", "pull_request", "pull_request_target", "merge_group"];
|
|
12384
|
+
var EVENT_SUFFIX = new RegExp(`^ \\((?:${CHECK_RUN_EVENTS.join("|")})\\)`);
|
|
12385
|
+
var WORKFLOW_JOB = /(\S+) \/ /g;
|
|
12386
|
+
function afterWorkflows(text) {
|
|
12387
|
+
return [...text.matchAll(WORKFLOW_JOB)].map((m) => m.index + m[0].length);
|
|
12388
|
+
}
|
|
12389
|
+
function jobNamed(text, name, longer) {
|
|
12390
|
+
if (text === name) return true;
|
|
12391
|
+
const workflowed = afterWorkflows(text);
|
|
12392
|
+
return boundedAt(text, name, JOB_NAME_CHAR).some(
|
|
12393
|
+
(at) => jobNamedAt(text, name, at, longer, workflowed.includes(at))
|
|
12394
|
+
);
|
|
12395
|
+
}
|
|
12396
|
+
function jobNamedAt(text, name, at, longer, withWorkflow) {
|
|
12397
|
+
const end = at + name.length;
|
|
12398
|
+
return (!text.startsWith(" (", end) || withWorkflow && EVENT_SUFFIX.test(text.slice(end))) && !longer.some(
|
|
12399
|
+
(l) => boundedAt(text, l, JOB_NAME_CHAR).some((from) => from <= at && end <= from + l.length)
|
|
12400
|
+
);
|
|
12401
|
+
}
|
|
12402
|
+
var longest = (names) => [...names].sort((a, b) => b.length - a.length)[0];
|
|
12403
|
+
function jobAt(text, at, jobNames) {
|
|
12404
|
+
return longest(
|
|
12405
|
+
jobNames.filter((name) => {
|
|
12406
|
+
const longer = jobNames.filter((n) => n.length > name.length && n.includes(name));
|
|
12407
|
+
return boundedAt(text, name, JOB_NAME_CHAR).includes(at) && jobNamedAt(text, name, at, longer, true);
|
|
12408
|
+
})
|
|
12409
|
+
);
|
|
12410
|
+
}
|
|
12411
|
+
function workflowBefore(text, slash, token, workflows) {
|
|
12412
|
+
const whole = workflows.filter((w) => {
|
|
12413
|
+
const from = slash - w.length;
|
|
12414
|
+
return w.length > 0 && from >= 0 && text.startsWith(w, from) && !PATH_CHAR.test(text[from - 1] ?? " ");
|
|
12415
|
+
});
|
|
12416
|
+
return longest(whole) ?? token;
|
|
12417
|
+
}
|
|
12418
|
+
function workflowJobs(text, jobNames, workflows = []) {
|
|
12419
|
+
const out = [];
|
|
12420
|
+
for (const m of text.matchAll(WORKFLOW_JOB)) {
|
|
12421
|
+
const at = m.index + m[0].length;
|
|
12422
|
+
const job = jobAt(text, at, jobNames);
|
|
12423
|
+
if (job === void 0) continue;
|
|
12424
|
+
out.push({ workflow: workflowBefore(text, at - 3, m[1], workflows), job });
|
|
12425
|
+
}
|
|
12426
|
+
return out;
|
|
12427
|
+
}
|
|
12428
|
+
var PARENTHESIS = /^ \([^()]*\)/;
|
|
12429
|
+
function unheldSuffixJobs(text, jobNames) {
|
|
12430
|
+
const out = [];
|
|
12431
|
+
for (const at of afterWorkflows(text)) {
|
|
12432
|
+
if (jobAt(text, at, jobNames) !== void 0) continue;
|
|
12433
|
+
const job = longest(
|
|
12434
|
+
jobNames.filter((name) => {
|
|
12435
|
+
const rest = text.slice(at + name.length);
|
|
12436
|
+
return boundedAt(text, name, JOB_NAME_CHAR).includes(at) && PARENTHESIS.test(rest) && !EVENT_SUFFIX.test(rest);
|
|
12437
|
+
})
|
|
12438
|
+
);
|
|
12439
|
+
if (job !== void 0) out.push(job);
|
|
12440
|
+
}
|
|
12441
|
+
return out;
|
|
12442
|
+
}
|
|
12443
|
+
function shaTokens(texts) {
|
|
12444
|
+
const out = [];
|
|
12445
|
+
for (const text of texts) {
|
|
12446
|
+
for (const m of text.matchAll(SHA2)) {
|
|
12447
|
+
const token = m[0].toLowerCase();
|
|
12448
|
+
if (token.length === 40 || /[0-9]/.test(token)) out.push(token);
|
|
12449
|
+
}
|
|
12450
|
+
}
|
|
12451
|
+
return out;
|
|
12452
|
+
}
|
|
12453
|
+
function issueRefs(texts, repository) {
|
|
12454
|
+
const out = [];
|
|
12455
|
+
for (const text of texts) {
|
|
12456
|
+
for (const m of text.matchAll(ISSUE2)) out.push(qualifyIssue(m[1], repository));
|
|
12457
|
+
}
|
|
12458
|
+
return out;
|
|
12459
|
+
}
|
|
12460
|
+
function identifierMatches(claim2, items, repository) {
|
|
12461
|
+
const texts = claimTexts(claim2);
|
|
12462
|
+
const shas = shaTokens(texts);
|
|
12463
|
+
const issues = issueRefs(texts, repository);
|
|
12464
|
+
const named = (value, inside) => texts.some((t) => t === value || occursBounded(t, value, inside));
|
|
12465
|
+
const qualified = (item) => item.type === "test" && item.id !== item.fields[0]?.[1] && named(item.id, WORD);
|
|
12466
|
+
const qualifiedNames = new Set(
|
|
12467
|
+
items.filter(qualified).map((item) => item.fields[0]?.[1])
|
|
12468
|
+
);
|
|
12469
|
+
const classnameOf = (item) => item.fields.find(([f]) => f === "classname")?.[1];
|
|
12470
|
+
const classnames = [
|
|
12471
|
+
...new Set(items.filter((item) => item.type === "test").map(classnameOf))
|
|
12472
|
+
].filter((c) => c !== void 0);
|
|
12473
|
+
const bareNamed = /* @__PURE__ */ new Map();
|
|
12474
|
+
for (const item of items) {
|
|
12475
|
+
const name = item.fields[0]?.[1];
|
|
12476
|
+
if (item.type !== "test" || name.length < MIN_NAME_LENGTH || qualifiedNames.has(name) || !named(name, WORD))
|
|
12477
|
+
continue;
|
|
12478
|
+
bareNamed.set(name, [...bareNamed.get(name) ?? [], item]);
|
|
12479
|
+
}
|
|
12480
|
+
const namedClassnames = /* @__PURE__ */ new Map();
|
|
12481
|
+
for (const [name, cases] of bareNamed) {
|
|
12482
|
+
if (cases.length < 2) continue;
|
|
12483
|
+
const said = cases.map(classnameOf).filter(
|
|
12484
|
+
(c) => c !== void 0 && c.length >= MIN_NAME_LENGTH && texts.some((t) => classnameNamed(t, c, classnames))
|
|
12485
|
+
);
|
|
12486
|
+
if (said.length > 0) namedClassnames.set(name, new Set(said));
|
|
12487
|
+
}
|
|
12488
|
+
const underNamedClassname = (item, name) => {
|
|
12489
|
+
const said = namedClassnames.get(name);
|
|
12490
|
+
const classname = classnameOf(item);
|
|
12491
|
+
return said === void 0 || classname !== void 0 && said.has(classname);
|
|
12492
|
+
};
|
|
12493
|
+
const jobNames = items.filter((item) => item.type === "check_run").map((item) => item.fields[0]?.[1]);
|
|
12494
|
+
const matches = /* @__PURE__ */ new Map();
|
|
12495
|
+
items.forEach((item, i) => {
|
|
12496
|
+
for (const [field, value] of item.fields) {
|
|
12497
|
+
let hit = false;
|
|
12498
|
+
switch (`${item.type}.${field}`) {
|
|
12499
|
+
case "commit.sha":
|
|
12500
|
+
hit = shas.some((s) => value.startsWith(s));
|
|
12501
|
+
break;
|
|
12502
|
+
case "timeline_event.ref":
|
|
12503
|
+
hit = /^[0-9a-f]{40}$/.test(value) ? shas.some((s) => value.startsWith(s)) : issues.some((ref) => sameIssue(ref, value));
|
|
12504
|
+
break;
|
|
12505
|
+
case "file.path":
|
|
12506
|
+
case "file.previousPath":
|
|
12507
|
+
hit = named(value, PATH_CHAR);
|
|
12508
|
+
break;
|
|
12509
|
+
case "check_run.name": {
|
|
12510
|
+
const longer = jobNames.filter((n) => n.length > value.length && n.includes(value));
|
|
12511
|
+
hit = value.length >= MIN_NAME_LENGTH && texts.some((t) => jobNamed(t, value, longer));
|
|
12512
|
+
break;
|
|
12513
|
+
}
|
|
12514
|
+
case "test.name":
|
|
12515
|
+
hit = value.length >= MIN_NAME_LENGTH && named(value, WORD) && (!qualifiedNames.has(value) || qualified(item)) && underNamedClassname(item, value);
|
|
12516
|
+
break;
|
|
12517
|
+
}
|
|
12518
|
+
if (hit) {
|
|
12519
|
+
matches.set(i, field);
|
|
12520
|
+
return;
|
|
12521
|
+
}
|
|
12522
|
+
}
|
|
12523
|
+
if (qualified(item)) matches.set(i, "id");
|
|
12524
|
+
});
|
|
12525
|
+
return matches;
|
|
12526
|
+
}
|
|
12527
|
+
|
|
12335
12528
|
// src/retrieval/items.ts
|
|
12336
12529
|
function testId(test) {
|
|
12337
12530
|
return test.classname === void 0 ? test.name : `${test.classname}.${test.name}`;
|
|
@@ -12473,110 +12666,6 @@ var Bm25Index = class {
|
|
|
12473
12666
|
}
|
|
12474
12667
|
};
|
|
12475
12668
|
|
|
12476
|
-
// src/retrieval/identifiers.ts
|
|
12477
|
-
var MIN_NAME_LENGTH = 4;
|
|
12478
|
-
var SHA2 = /(?<![0-9A-Za-z])[0-9a-fA-F]{7,40}(?![0-9A-Za-z])/g;
|
|
12479
|
-
var ISSUE2 = /(?<![\w/.-])((?:[A-Za-z0-9][A-Za-z0-9-]{0,38}\/[A-Za-z0-9._-]{1,100})?#[1-9][0-9]{0,9})(?![0-9])/g;
|
|
12480
|
-
var WORD = /[A-Za-z0-9_]/;
|
|
12481
|
-
var PATH_CHAR = /[A-Za-z0-9._/-]/;
|
|
12482
|
-
var JOB_NAME_CHAR = /[A-Za-z0-9_-]/;
|
|
12483
|
-
function stringLeaves(value, out) {
|
|
12484
|
-
if (typeof value === "string") out.push(value);
|
|
12485
|
-
else if (Array.isArray(value)) for (const v of value) stringLeaves(v, out);
|
|
12486
|
-
else if (value !== null && typeof value === "object")
|
|
12487
|
-
for (const v of Object.values(value)) stringLeaves(v, out);
|
|
12488
|
-
return out;
|
|
12489
|
-
}
|
|
12490
|
-
function claimTexts(claim2) {
|
|
12491
|
-
return [claim2.text, ...stringLeaves(claim2.declaredValue, [])];
|
|
12492
|
-
}
|
|
12493
|
-
function boundedAt(haystack, needle, inside) {
|
|
12494
|
-
const out = [];
|
|
12495
|
-
if (needle.length === 0) return out;
|
|
12496
|
-
for (let at = haystack.indexOf(needle); at !== -1; at = haystack.indexOf(needle, at + 1)) {
|
|
12497
|
-
const before = haystack[at - 1];
|
|
12498
|
-
const after = haystack[at + needle.length];
|
|
12499
|
-
const next = haystack[at + needle.length + 1];
|
|
12500
|
-
const openBefore = before === void 0 || !inside.test(before);
|
|
12501
|
-
const openAfter = after === void 0 || !inside.test(after) || after === "." && (next === void 0 || !/[A-Za-z0-9]/.test(next));
|
|
12502
|
-
if (openBefore && openAfter) out.push(at);
|
|
12503
|
-
}
|
|
12504
|
-
return out;
|
|
12505
|
-
}
|
|
12506
|
-
function occursBounded(haystack, needle, inside) {
|
|
12507
|
-
return boundedAt(haystack, needle, inside).length > 0;
|
|
12508
|
-
}
|
|
12509
|
-
function jobNamed(text, name, longer) {
|
|
12510
|
-
if (text === name) return true;
|
|
12511
|
-
return boundedAt(text, name, JOB_NAME_CHAR).some(
|
|
12512
|
-
(at) => !text.startsWith(" (", at + name.length) && !longer.some(
|
|
12513
|
-
(l) => boundedAt(text, l, JOB_NAME_CHAR).some(
|
|
12514
|
-
(from) => from <= at && at + name.length <= from + l.length
|
|
12515
|
-
)
|
|
12516
|
-
)
|
|
12517
|
-
);
|
|
12518
|
-
}
|
|
12519
|
-
function shaTokens(texts) {
|
|
12520
|
-
const out = [];
|
|
12521
|
-
for (const text of texts) {
|
|
12522
|
-
for (const m of text.matchAll(SHA2)) {
|
|
12523
|
-
const token = m[0].toLowerCase();
|
|
12524
|
-
if (token.length === 40 || /[0-9]/.test(token)) out.push(token);
|
|
12525
|
-
}
|
|
12526
|
-
}
|
|
12527
|
-
return out;
|
|
12528
|
-
}
|
|
12529
|
-
function issueRefs(texts, repository) {
|
|
12530
|
-
const out = [];
|
|
12531
|
-
for (const text of texts) {
|
|
12532
|
-
for (const m of text.matchAll(ISSUE2)) out.push(qualifyIssue(m[1], repository));
|
|
12533
|
-
}
|
|
12534
|
-
return out;
|
|
12535
|
-
}
|
|
12536
|
-
function identifierMatches(claim2, items, repository) {
|
|
12537
|
-
const texts = claimTexts(claim2);
|
|
12538
|
-
const shas = shaTokens(texts);
|
|
12539
|
-
const issues = issueRefs(texts, repository);
|
|
12540
|
-
const named = (value, inside) => texts.some((t) => t === value || occursBounded(t, value, inside));
|
|
12541
|
-
const qualified = (item) => item.type === "test" && item.id !== item.fields[0]?.[1] && named(item.id, WORD);
|
|
12542
|
-
const qualifiedNames = new Set(
|
|
12543
|
-
items.filter(qualified).map((item) => item.fields[0]?.[1])
|
|
12544
|
-
);
|
|
12545
|
-
const jobNames = items.filter((item) => item.type === "check_run").map((item) => item.fields[0]?.[1]);
|
|
12546
|
-
const matches = /* @__PURE__ */ new Map();
|
|
12547
|
-
items.forEach((item, i) => {
|
|
12548
|
-
for (const [field, value] of item.fields) {
|
|
12549
|
-
let hit = false;
|
|
12550
|
-
switch (`${item.type}.${field}`) {
|
|
12551
|
-
case "commit.sha":
|
|
12552
|
-
hit = shas.some((s) => value.startsWith(s));
|
|
12553
|
-
break;
|
|
12554
|
-
case "timeline_event.ref":
|
|
12555
|
-
hit = /^[0-9a-f]{40}$/.test(value) ? shas.some((s) => value.startsWith(s)) : issues.some((ref) => sameIssue(ref, value));
|
|
12556
|
-
break;
|
|
12557
|
-
case "file.path":
|
|
12558
|
-
case "file.previousPath":
|
|
12559
|
-
hit = named(value, PATH_CHAR);
|
|
12560
|
-
break;
|
|
12561
|
-
case "check_run.name": {
|
|
12562
|
-
const longer = jobNames.filter((n) => n.length > value.length && n.includes(value));
|
|
12563
|
-
hit = value.length >= MIN_NAME_LENGTH && texts.some((t) => jobNamed(t, value, longer));
|
|
12564
|
-
break;
|
|
12565
|
-
}
|
|
12566
|
-
case "test.name":
|
|
12567
|
-
hit = value.length >= MIN_NAME_LENGTH && named(value, WORD) && (!qualifiedNames.has(value) || qualified(item));
|
|
12568
|
-
break;
|
|
12569
|
-
}
|
|
12570
|
-
if (hit) {
|
|
12571
|
-
matches.set(i, field);
|
|
12572
|
-
return;
|
|
12573
|
-
}
|
|
12574
|
-
}
|
|
12575
|
-
if (qualified(item)) matches.set(i, "id");
|
|
12576
|
-
});
|
|
12577
|
-
return matches;
|
|
12578
|
-
}
|
|
12579
|
-
|
|
12580
12669
|
// src/retrieval/retrieve.ts
|
|
12581
12670
|
var FILL_TO_K = "to-k";
|
|
12582
12671
|
var ARM_A_FILL = "A-fill";
|
|
@@ -12720,6 +12809,53 @@ function ambiguousCandidates(combined, outcome) {
|
|
|
12720
12809
|
const tied = combined.filter((_, i) => scores[i] === top);
|
|
12721
12810
|
return tied.length >= 2 && new Set(tied.map(outcome)).size > 1;
|
|
12722
12811
|
}
|
|
12812
|
+
function namedWorkflowRuns(text, combined, evidence) {
|
|
12813
|
+
const section = evidence.checkRuns;
|
|
12814
|
+
if (section?.status !== "ok") return [...combined];
|
|
12815
|
+
const jobNames = [...new Set(section.runs.map((r) => r.name))];
|
|
12816
|
+
if (unheldSuffixJobs(text, jobNames).length > 0) return { reason: "no_matching_record_item" };
|
|
12817
|
+
const recordedWorkflows = [
|
|
12818
|
+
...new Set(
|
|
12819
|
+
section.runs.flatMap((r) => [r.workflowPath, r.workflowName]).filter((w) => w !== void 0)
|
|
12820
|
+
)
|
|
12821
|
+
];
|
|
12822
|
+
const named = workflowJobs(text, jobNames, recordedWorkflows);
|
|
12823
|
+
if (named.length === 0) return [...combined];
|
|
12824
|
+
const counted = new Map(
|
|
12825
|
+
countedCheckRuns(section.runs, section.excludedIds).map((r) => [String(r.id), r])
|
|
12826
|
+
);
|
|
12827
|
+
const runOf = (c) => counted.get(c.id);
|
|
12828
|
+
const isOf = (r, workflow) => r.workflowPath === workflow || r.workflowName === workflow;
|
|
12829
|
+
let kept = [...combined];
|
|
12830
|
+
for (const job of new Set(named.map((n) => n.job))) {
|
|
12831
|
+
const runs = section.runs.filter((r) => r.name === job);
|
|
12832
|
+
if (runs.some((r) => r.workflowPath === void 0)) {
|
|
12833
|
+
if (runs.length >= 2) return { reason: "workflow_not_in_record" };
|
|
12834
|
+
continue;
|
|
12835
|
+
}
|
|
12836
|
+
const workflows = new Set(named.filter((n) => n.job === job).map((n) => n.workflow));
|
|
12837
|
+
for (const workflow of workflows) {
|
|
12838
|
+
const byPath = runs.some((r) => r.workflowPath === workflow);
|
|
12839
|
+
if (!byPath && runs.some((r) => r.workflowName === void 0)) {
|
|
12840
|
+
return { reason: "workflow_not_in_record" };
|
|
12841
|
+
}
|
|
12842
|
+
const paths = new Set(runs.filter((r) => isOf(r, workflow)).map((r) => r.workflowPath));
|
|
12843
|
+
if (paths.size >= 2) return { reason: "workflow_name_ambiguous" };
|
|
12844
|
+
}
|
|
12845
|
+
kept = kept.filter((c) => {
|
|
12846
|
+
const run = runOf(c);
|
|
12847
|
+
return run?.name !== job || [...workflows].some((w) => isOf(run, w));
|
|
12848
|
+
});
|
|
12849
|
+
for (const workflow of workflows) {
|
|
12850
|
+
const of = (r) => r?.name === job && isOf(r, workflow);
|
|
12851
|
+
if (kept.some((c) => of(runOf(c)))) continue;
|
|
12852
|
+
return {
|
|
12853
|
+
reason: [...counted.values()].some(of) ? "declared_item_not_among_candidates" : "workflow_not_in_record"
|
|
12854
|
+
};
|
|
12855
|
+
}
|
|
12856
|
+
}
|
|
12857
|
+
return kept;
|
|
12858
|
+
}
|
|
12723
12859
|
function checkReaderClaim(claim2, evidence, repository) {
|
|
12724
12860
|
const type = READER_CLAIM_KINDS.get(claim2.kind);
|
|
12725
12861
|
if (type === void 0) return unverifiable2("no_comparable_record_field");
|
|
@@ -12742,12 +12878,17 @@ function checkReaderClaim(claim2, evidence, repository) {
|
|
|
12742
12878
|
if (typed.some((c) => entries.get(c.id) === void 0)) {
|
|
12743
12879
|
return unverifiable2("candidate_not_in_evidence");
|
|
12744
12880
|
}
|
|
12745
|
-
|
|
12746
|
-
const observed = relevant.map((c) => entries.get(c.id));
|
|
12881
|
+
let relevant = combinedCandidates(typed, claim2.retrieval.floor);
|
|
12747
12882
|
const truncated = type === "file" && evidence.files?.status === "ok" && !evidence.files.complete;
|
|
12748
12883
|
if (relevant.length === 0) {
|
|
12749
12884
|
return unverifiable2(truncated ? "file_list_truncated" : "no_matching_record_item");
|
|
12750
12885
|
}
|
|
12886
|
+
if (type === "check_run") {
|
|
12887
|
+
const scoped = namedWorkflowRuns(claim2.text, relevant, evidence);
|
|
12888
|
+
if (!Array.isArray(scoped)) return unverifiable2(scoped.reason);
|
|
12889
|
+
relevant = scoped;
|
|
12890
|
+
}
|
|
12891
|
+
const observed = relevant.map((c) => entries.get(c.id));
|
|
12751
12892
|
if (wantsBoolean && ambiguousCandidates(relevant, (c) => outcomeOf(type, entries.get(c.id)))) {
|
|
12752
12893
|
return unverifiable2("ambiguous_candidates");
|
|
12753
12894
|
}
|
|
@@ -12804,7 +12945,13 @@ function readReaderClaim(input2, evidence, repository) {
|
|
|
12804
12945
|
retrieval,
|
|
12805
12946
|
candidates,
|
|
12806
12947
|
...checkReaderClaim(
|
|
12807
|
-
{
|
|
12948
|
+
{
|
|
12949
|
+
text: input2.text,
|
|
12950
|
+
kind: input2.kind,
|
|
12951
|
+
declaredValue: input2.declaredValue,
|
|
12952
|
+
candidates,
|
|
12953
|
+
retrieval
|
|
12954
|
+
},
|
|
12808
12955
|
evidence,
|
|
12809
12956
|
repository
|
|
12810
12957
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dunstan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"mcpName": "io.github.BargLabs/dunstan",
|
|
5
5
|
"description": "Holds a coding agent's completion report to the record: deterministic checks of a declared handback block against the repository's own metadata.",
|
|
6
6
|
"license": "AGPL-3.0-only",
|