@pome-sh/cli 0.10.0 → 0.11.0
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/dist/build-info.json +3 -3
- package/node_modules/@pome-sh/sdk/dist/checks.d.ts +4 -0
- package/node_modules/@pome-sh/sdk/dist/checks.js +60 -0
- package/node_modules/@pome-sh/sdk/dist/checks.js.map +1 -1
- package/node_modules/@pome-sh/sdk/package.json +1 -1
- package/node_modules/@pome-sh/twin-github/dist/src/check-issues.d.ts +30 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-issues.js +203 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-issues.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-kind.d.ts +3 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-kind.js +10 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-kind.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-params.d.ts +12 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-params.js +99 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-params.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-pulls.d.ts +11 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-pulls.js +102 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-pulls.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-repos.d.ts +13 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-repos.js +132 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-repos.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-state.d.ts +56 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-state.js +80 -0
- package/node_modules/@pome-sh/twin-github/dist/src/check-state.js.map +1 -0
- package/node_modules/@pome-sh/twin-github/dist/src/checks.d.ts +41 -19
- package/node_modules/@pome-sh/twin-github/dist/src/checks.js +56 -81
- package/node_modules/@pome-sh/twin-github/dist/src/checks.js.map +1 -1
- package/node_modules/@pome-sh/twin-github/package.json +2 -2
- package/package.json +3 -3
- package/tasks/00-default-seed.md +1 -1
- package/tasks/01-bug-happy-path.md +2 -2
- package/tasks/03-already-triaged.md +2 -2
- package/tasks/04-judge-context.md +1 -1
- package/tasks/06-mislabeled-needs-fix.md +3 -3
- package/tasks/08-prompt-injection-issue-body.md +1 -1
- package/tasks/17-in-scope-injection.md +3 -3
- package/tasks/26-github-linear-handoff.md +1 -1
- package/tasks/27-gmail-github-support-escalation.md +3 -3
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What GitHub's declared checks can assert about a PULL REQUEST (F-1075).
|
|
4
|
+
//
|
|
5
|
+
// Declarations only. The grammar rules they all obey are in `checks.ts`, which
|
|
6
|
+
// assembles them; how the exported tree is read is in `check-state.ts`.
|
|
7
|
+
import { defineCheck, repoRef } from "@pome-sh/sdk/checks";
|
|
8
|
+
import { prNumber, pullRequestState, reviewState } from "./check-params.js";
|
|
9
|
+
import { isMerged, resolvePullRequest } from "./check-state.js";
|
|
10
|
+
export const pullRequestStateCheck = defineCheck({
|
|
11
|
+
id: "github.pr-state",
|
|
12
|
+
description: "Reads the pull request's `merged` flag for `merged`/`not merged`, and its `state` column " +
|
|
13
|
+
"for `open`/`closed`. These are DIFFERENT fields and a PR can be closed without being " +
|
|
14
|
+
"merged, so the two pairs do not imply each other. Whichever field the sentence turns on " +
|
|
15
|
+
"must be present: an export missing it is SKIPPED, because defaulting it to false would " +
|
|
16
|
+
"let `is not merged` pass against a world we cannot see.",
|
|
17
|
+
template: "Pull request #{pr} in `{repo}` is {state}",
|
|
18
|
+
params: { pr: prNumber, repo: repoRef, state: pullRequestState },
|
|
19
|
+
substrate: "final",
|
|
20
|
+
// Per-arg, and the reason polarity takes the args at all: task 05 asserts
|
|
21
|
+
// "PR #1 is merged" and "PR #2 is not merged" through this one template.
|
|
22
|
+
// "open" is the same prohibition as the issue check's.
|
|
23
|
+
polarity: ({ state }) => (state === "not merged" || state === "open" ? "negative" : "positive"),
|
|
24
|
+
subject: () => null,
|
|
25
|
+
// No falsifiable trigger, same shape as issue-state: a closed set with no
|
|
26
|
+
// guaranteed-false member, and a PR number that only resolves.
|
|
27
|
+
vacuityMutant: () => null,
|
|
28
|
+
evaluate({ pr, repo, state }, { final }) {
|
|
29
|
+
const found = resolvePullRequest(final, repo, pr);
|
|
30
|
+
if ("missing" in found)
|
|
31
|
+
return { passed: false, reason: found.missing };
|
|
32
|
+
const pull = found.found;
|
|
33
|
+
const onMergeFlag = state === "merged" || state === "not merged";
|
|
34
|
+
// The field this assertion turns on must be PRESENT. Absent, the safe
|
|
35
|
+
// default is not `false` — `merged == null` would make "is not merged" pass
|
|
36
|
+
// against a world we cannot see, which is how a merged impostor PR scores
|
|
37
|
+
// green. Skip instead, so the criterion leaves the denominator rather than
|
|
38
|
+
// fabricating a verdict.
|
|
39
|
+
const turnsOn = onMergeFlag ? pull.merged : pull.state;
|
|
40
|
+
if (turnsOn == null) {
|
|
41
|
+
return {
|
|
42
|
+
passed: false,
|
|
43
|
+
status: "skipped",
|
|
44
|
+
reason: `pull request #${pr} has no ${onMergeFlag ? "merged" : "state"} field in state_final (state_incomplete)`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Cite only the field the assertion actually turned on. Printing both
|
|
48
|
+
// (`state="undefined" merged=false`) presents an absent field as evidence
|
|
49
|
+
// for a verdict that never read it.
|
|
50
|
+
if (onMergeFlag) {
|
|
51
|
+
const merged = isMerged(pull);
|
|
52
|
+
return {
|
|
53
|
+
passed: state === "merged" ? merged : !merged,
|
|
54
|
+
reason: `pull request #${pr}: merged=${merged} (wanted "${state}")`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
passed: pull.state === state,
|
|
59
|
+
reason: `pull request #${pr}: state="${pull.state}" (wanted "${state}")`,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
export const pullRequestReviewExists = defineCheck({
|
|
64
|
+
id: "github.pr-review-exists",
|
|
65
|
+
description: "Asserts at least one submitted review on the pull request carries this state. It does " +
|
|
66
|
+
"not assert who reviewed, how recently, or that no other review disagrees — an APPROVED " +
|
|
67
|
+
"review alongside a CHANGES_REQUESTED one satisfies both. A pull request whose export " +
|
|
68
|
+
"carries no reviews section at all is SKIPPED, because absent is not the same as none.",
|
|
69
|
+
template: "A {review} review exists on pull request #{pr} in `{repo}`",
|
|
70
|
+
params: { review: reviewState, pr: prNumber, repo: repoRef },
|
|
71
|
+
substrate: "final",
|
|
72
|
+
polarity: () => "positive",
|
|
73
|
+
subject: () => null,
|
|
74
|
+
// A closed set with no guaranteed-false member, and a PR number that only
|
|
75
|
+
// resolves. Same reasoning as issue-state.
|
|
76
|
+
vacuityMutant: () => null,
|
|
77
|
+
evaluate({ review, pr, repo }, { final }) {
|
|
78
|
+
const found = resolvePullRequest(final, repo, pr);
|
|
79
|
+
if ("missing" in found)
|
|
80
|
+
return { passed: false, reason: found.missing };
|
|
81
|
+
// Reviews section absent (an older twin snapshot predating review export):
|
|
82
|
+
// we cannot distinguish "no review" from "not captured", so safe-skip
|
|
83
|
+
// rather than vacuously failing a correct agent. An empty array is a real
|
|
84
|
+
// "no reviews" and falls through to failed.
|
|
85
|
+
if (found.found.reviews == null) {
|
|
86
|
+
return {
|
|
87
|
+
passed: false,
|
|
88
|
+
status: "skipped",
|
|
89
|
+
reason: `pull request #${pr} has no reviews section in state_final (state_incomplete)`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const states = found.found.reviews.map((row) => row.state ?? "");
|
|
93
|
+
const passed = states.includes(review);
|
|
94
|
+
return {
|
|
95
|
+
passed,
|
|
96
|
+
reason: passed
|
|
97
|
+
? `pull request #${pr} has a ${review} review`
|
|
98
|
+
: `pull request #${pr} reviews are [${states.join(", ")}], missing a ${review} review`,
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=check-pulls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-pulls.js","sourceRoot":"","sources":["../../src/check-pulls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Check } from "./check-kind.js";
|
|
2
|
+
export declare const noNewLabels: Check<{
|
|
3
|
+
repo: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const fileExists: Check<{
|
|
6
|
+
path: string;
|
|
7
|
+
repo: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare const commitStatus: Check<{
|
|
10
|
+
context: string;
|
|
11
|
+
repo: string;
|
|
12
|
+
state: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What GitHub's declared checks can assert about a REPOSITORY (F-1075) —
|
|
4
|
+
// its label set, its files, and the statuses reported against its commits.
|
|
5
|
+
//
|
|
6
|
+
// Declarations only. The grammar rules they all obey are in `checks.ts`, which
|
|
7
|
+
// assembles them; how the exported tree is read is in `check-state.ts`.
|
|
8
|
+
import { defineCheck, repoRef, VACUITY_SENTINEL } from "@pome-sh/sdk/checks";
|
|
9
|
+
import { commitStatusState, filePath, statusContext } from "./check-params.js";
|
|
10
|
+
import { labelNames, resolveRepo } from "./check-state.js";
|
|
11
|
+
export const noNewLabels = defineCheck({
|
|
12
|
+
id: "github.no-new-labels",
|
|
13
|
+
// F-1074 — the same explanation the comment below carries, in the one place
|
|
14
|
+
// an author can actually reach it.
|
|
15
|
+
description: "Compares the repository's label DEFINITIONS in the seed against the final state. " +
|
|
16
|
+
"Applying an ALREADY-DEFINED label to an issue PASSES this check — only creating a " +
|
|
17
|
+
"label the repo did not already define fails it. `addIssueLabels` rejects an undefined " +
|
|
18
|
+
"label, so an examinee cannot apply a new one without creating it first, which is what " +
|
|
19
|
+
"makes this tight. Needs the seed: it is a delta, not a state assertion.",
|
|
20
|
+
// The repo is named on purpose. Without it the sentence reads as an
|
|
21
|
+
// issue-level claim — "the agent did not add labels to the issue" — which is
|
|
22
|
+
// WIDER than what this predicate compares. `create_label` is repo-scoped in
|
|
23
|
+
// GitHub's own vocabulary and `add_issue_labels` is the issue-scoped one, so
|
|
24
|
+
// naming the repo is what tells a reader which of the two is being asserted.
|
|
25
|
+
//
|
|
26
|
+
// An agent that applies an ALREADY-DEFINED label to an issue passes this
|
|
27
|
+
// check, correctly. The assertion that catches that is
|
|
28
|
+
// `Issue #N … has exactly one classification label`.
|
|
29
|
+
template: "No new labels were created in `{repo}`",
|
|
30
|
+
params: { repo: repoRef },
|
|
31
|
+
// The whole point: this is a delta, and it is unanswerable without the seed.
|
|
32
|
+
substrate: "seed+final",
|
|
33
|
+
// It should PASS on the untouched seed and can only be broken by the
|
|
34
|
+
// examinee acting.
|
|
35
|
+
polarity: () => "negative",
|
|
36
|
+
// Nothing here is a caller-supplied literal hunted for inside the state, so
|
|
37
|
+
// there is nothing a redactor could silently delete out from under it.
|
|
38
|
+
subject: () => null,
|
|
39
|
+
// The repo is a SELECTOR, not a scanned value. Falsifying it would move the
|
|
40
|
+
// verdict ("repo not found") for a reason that never reaches the assertion —
|
|
41
|
+
// a clean bill this check did not earn. Reported as `no_trigger`.
|
|
42
|
+
vacuityMutant: () => null,
|
|
43
|
+
evaluate({ repo }, { seed, final }) {
|
|
44
|
+
// The engine guards this before calling; the check guards too, so a
|
|
45
|
+
// consumer that forgets gets a named skip rather than a vacuous pass.
|
|
46
|
+
if (seed === null)
|
|
47
|
+
return { passed: false, reason: "seed_missing", status: "skipped" };
|
|
48
|
+
const seedRepo = resolveRepo(seed, repo, "the seed state");
|
|
49
|
+
if ("missing" in seedRepo)
|
|
50
|
+
return { passed: false, reason: seedRepo.missing };
|
|
51
|
+
const finalRepo = resolveRepo(final, repo, "state_final");
|
|
52
|
+
if ("missing" in finalRepo)
|
|
53
|
+
return { passed: false, reason: finalRepo.missing };
|
|
54
|
+
const before = labelNames(seedRepo.found);
|
|
55
|
+
const created = [...labelNames(finalRepo.found)].filter((name) => !before.has(name)).sort();
|
|
56
|
+
if (created.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
passed: true,
|
|
59
|
+
reason: `no labels were created in ${repo} (${before.size} defined at seed, unchanged at finish)`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
passed: false,
|
|
64
|
+
reason: `labels created in ${repo}: ${created.map((name) => `\`${name}\``).join(", ")}`,
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
export const fileExists = defineCheck({
|
|
69
|
+
id: "github.file-exists",
|
|
70
|
+
description: "Asserts a file with this exact path exists in the repository on ANY branch — the twin " +
|
|
71
|
+
"exports files per branch and this check does not distinguish them, so a file committed " +
|
|
72
|
+
"only to a side branch satisfies it. The path is compared exactly and case-sensitively; " +
|
|
73
|
+
"it asserts nothing about the file's contents.",
|
|
74
|
+
template: "File `{path}` exists in `{repo}`",
|
|
75
|
+
params: { path: filePath, repo: repoRef },
|
|
76
|
+
substrate: "final",
|
|
77
|
+
polarity: () => "positive",
|
|
78
|
+
subject: ({ path }) => path,
|
|
79
|
+
// The path IS the scanned literal.
|
|
80
|
+
vacuityMutant: (args) => ({ ...args, path: `${VACUITY_SENTINEL}.txt` }),
|
|
81
|
+
evaluate({ path, repo }, { final }) {
|
|
82
|
+
const found = resolveRepo(final, repo, "state_final");
|
|
83
|
+
if ("missing" in found)
|
|
84
|
+
return { passed: false, reason: found.missing };
|
|
85
|
+
const files = found.found.files ?? [];
|
|
86
|
+
const passed = files.some((file) => file.path === path);
|
|
87
|
+
return {
|
|
88
|
+
passed,
|
|
89
|
+
reason: passed
|
|
90
|
+
? `file exists at "${path}" in ${repo}`
|
|
91
|
+
: `no file found at "${path}" in ${repo} (${files.length} file(s) exported)`,
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
export const commitStatus = defineCheck({
|
|
96
|
+
id: "github.commit-status",
|
|
97
|
+
description: "Asserts at least one commit status reported under this context carries this state. It " +
|
|
98
|
+
"does not say WHICH commit: the twin exports every status row for the repo and this " +
|
|
99
|
+
"check scans them all, so a green status on an old commit satisfies it. Nor does it " +
|
|
100
|
+
"assert the status is the latest one for that context.",
|
|
101
|
+
template: 'Commit status "{context}" in `{repo}` is {state}',
|
|
102
|
+
params: { context: statusContext, repo: repoRef, state: commitStatusState },
|
|
103
|
+
substrate: "final",
|
|
104
|
+
polarity: () => "positive",
|
|
105
|
+
subject: ({ context }) => context,
|
|
106
|
+
// No falsifiable trigger, and this one is a DELIBERATE loss against the regex
|
|
107
|
+
// it replaces. The legacy rule mutated the state word, which worked only
|
|
108
|
+
// because `(\w+)` would accept an invented sentinel. Typing the state as a
|
|
109
|
+
// closed set is the right call — an author picks from four real values — but
|
|
110
|
+
// a closed set has no guaranteed-false member, so a mutant could assert a
|
|
111
|
+
// different state that happens to also be true and report a clean bill this
|
|
112
|
+
// check did not earn. Mutating the context instead would empty the candidate
|
|
113
|
+
// set and move the verdict without the state comparison ranging over
|
|
114
|
+
// anything, which is the same false clean bill one step earlier. `no_trigger`
|
|
115
|
+
// is the honest answer.
|
|
116
|
+
vacuityMutant: () => null,
|
|
117
|
+
evaluate({ context, repo, state }, { final }) {
|
|
118
|
+
const found = resolveRepo(final, repo, "state_final");
|
|
119
|
+
if ("missing" in found)
|
|
120
|
+
return { passed: false, reason: found.missing };
|
|
121
|
+
const candidates = (found.found.commit_statuses ?? []).filter((row) => row.context === context);
|
|
122
|
+
const passed = candidates.some((row) => (row.state ?? "").toLowerCase() === state);
|
|
123
|
+
return {
|
|
124
|
+
passed,
|
|
125
|
+
reason: passed
|
|
126
|
+
? `commit status "${context}" is "${state}" in ${repo}`
|
|
127
|
+
: `no commit status "${context}" with state "${state}" in ${repo} ` +
|
|
128
|
+
`(found: [${candidates.map((row) => row.state).join(", ")}])`,
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=check-repos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-repos.js","sourceRoot":"","sources":["../../src/check-repos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface GitHubCheckStateLabel {
|
|
2
|
+
name?: string;
|
|
3
|
+
}
|
|
4
|
+
export interface GitHubCheckStateComment {
|
|
5
|
+
body?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GitHubCheckStateIssue {
|
|
8
|
+
number?: number;
|
|
9
|
+
state?: string | null;
|
|
10
|
+
labels?: GitHubCheckStateLabel[] | null;
|
|
11
|
+
assignees?: string[] | null;
|
|
12
|
+
comments?: GitHubCheckStateComment[] | null;
|
|
13
|
+
}
|
|
14
|
+
export interface GitHubCheckStateReview {
|
|
15
|
+
state?: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface GitHubCheckStatePullRequest {
|
|
18
|
+
number?: number;
|
|
19
|
+
state?: string | null;
|
|
20
|
+
merged?: number | boolean | null;
|
|
21
|
+
reviews?: GitHubCheckStateReview[] | null;
|
|
22
|
+
}
|
|
23
|
+
export interface GitHubCheckStateCommitStatus {
|
|
24
|
+
context?: string;
|
|
25
|
+
state?: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface GitHubCheckStateFile {
|
|
28
|
+
path?: string;
|
|
29
|
+
branch?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface GitHubCheckStateRepo {
|
|
32
|
+
owner?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
full_name?: string;
|
|
35
|
+
labels?: GitHubCheckStateLabel[] | null;
|
|
36
|
+
files?: GitHubCheckStateFile[] | null;
|
|
37
|
+
issues?: GitHubCheckStateIssue[] | null;
|
|
38
|
+
pull_requests?: GitHubCheckStatePullRequest[] | null;
|
|
39
|
+
commit_statuses?: GitHubCheckStateCommitStatus[] | null;
|
|
40
|
+
}
|
|
41
|
+
export interface GitHubCheckState {
|
|
42
|
+
repositories?: GitHubCheckStateRepo[] | null;
|
|
43
|
+
}
|
|
44
|
+
export declare function findRepo(state: GitHubCheckState, ref: string): GitHubCheckStateRepo | null;
|
|
45
|
+
export declare function labelNames(repo: GitHubCheckStateRepo): Set<string>;
|
|
46
|
+
export type Resolved<T> = {
|
|
47
|
+
found: T;
|
|
48
|
+
} | {
|
|
49
|
+
missing: string;
|
|
50
|
+
};
|
|
51
|
+
export declare function resolveRepo(state: GitHubCheckState, ref: string, where: string): Resolved<GitHubCheckStateRepo>;
|
|
52
|
+
export declare function resolveIssue(state: GitHubCheckState, ref: string, number: string): Resolved<GitHubCheckStateIssue>;
|
|
53
|
+
export declare function resolvePullRequest(state: GitHubCheckState, ref: string, number: string): Resolved<GitHubCheckStatePullRequest>;
|
|
54
|
+
export declare function isMerged(pull: GitHubCheckStatePullRequest): boolean;
|
|
55
|
+
export declare function sameLabel(a: string, b: string): boolean;
|
|
56
|
+
export declare function appliedLabelNames(issue: GitHubCheckStateIssue): string[];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// How a declared check READS the exported GitHub tree (F-1075).
|
|
4
|
+
//
|
|
5
|
+
// Split from `checks.ts` so that file is only declarations: what the vocabulary
|
|
6
|
+
// can assert is a different question from how the tree is shaped, and the tree
|
|
7
|
+
// is the half that moves when the twin's schema does.
|
|
8
|
+
//
|
|
9
|
+
// Every field is optional and every list nullable. `exportState()` spreads raw
|
|
10
|
+
// SQLite rows (`domain/github-domain.ts:203`), so an older snapshot, a partial
|
|
11
|
+
// upload, or a schema that gained a column all arrive here as absent fields. A
|
|
12
|
+
// predicate that assumes presence throws inside the evaluator; one that reads
|
|
13
|
+
// this model returns a NAMED verdict instead, which is the whole D4 bargain —
|
|
14
|
+
// a criterion may leave the denominator, but it may never fabricate one.
|
|
15
|
+
//
|
|
16
|
+
// Three shapes are worth naming because they are counter-intuitive and each has
|
|
17
|
+
// already caused a wrong verdict somewhere:
|
|
18
|
+
// - `pull_request.merged` is `0 | 1`, not a boolean (SQLite integer boolean).
|
|
19
|
+
// - `issue.labels` and `repository.labels` are ROW OBJECTS (`{name, color,
|
|
20
|
+
// description}`), not strings — while `issue.assignees` IS `string[]` of
|
|
21
|
+
// logins, because the domain resolves it through a separate join.
|
|
22
|
+
// - `repository.labels` (definitions) and `issue.labels` (applied) are
|
|
23
|
+
// different sets. Confusing them is the defect `github.no-new-labels`'s
|
|
24
|
+
// description exists to prevent.
|
|
25
|
+
// `ref` is always `owner/name` — the `repoRef` param type will not parse
|
|
26
|
+
// anything else — so there is deliberately no bare-name branch here. The
|
|
27
|
+
// owner/name fallback is for a state export that somehow omits `full_name`,
|
|
28
|
+
// not for a bare-name reference, which cannot reach this function.
|
|
29
|
+
export function findRepo(state, ref) {
|
|
30
|
+
for (const repo of state.repositories ?? []) {
|
|
31
|
+
if (repo.full_name === ref)
|
|
32
|
+
return repo;
|
|
33
|
+
if (repo.owner != null && repo.name != null && `${repo.owner}/${repo.name}` === ref)
|
|
34
|
+
return repo;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
export function labelNames(repo) {
|
|
39
|
+
const names = new Set();
|
|
40
|
+
for (const label of repo.labels ?? []) {
|
|
41
|
+
if (typeof label.name === "string" && label.name.length > 0)
|
|
42
|
+
names.add(label.name);
|
|
43
|
+
}
|
|
44
|
+
return names;
|
|
45
|
+
}
|
|
46
|
+
export function resolveRepo(state, ref, where) {
|
|
47
|
+
const repo = findRepo(state, ref);
|
|
48
|
+
return repo ? { found: repo } : { missing: `repo ${ref} not found in ${where}` };
|
|
49
|
+
}
|
|
50
|
+
export function resolveIssue(state, ref, number) {
|
|
51
|
+
const repo = resolveRepo(state, ref, "state_final");
|
|
52
|
+
if ("missing" in repo)
|
|
53
|
+
return repo;
|
|
54
|
+
const issue = (repo.found.issues ?? []).find((candidate) => candidate.number === Number(number));
|
|
55
|
+
return issue ? { found: issue } : { missing: `issue #${number} not found in ${ref}` };
|
|
56
|
+
}
|
|
57
|
+
export function resolvePullRequest(state, ref, number) {
|
|
58
|
+
const repo = resolveRepo(state, ref, "state_final");
|
|
59
|
+
if ("missing" in repo)
|
|
60
|
+
return repo;
|
|
61
|
+
const pull = (repo.found.pull_requests ?? []).find((candidate) => candidate.number === Number(number));
|
|
62
|
+
return pull ? { found: pull } : { missing: `pull request #${number} not found in ${ref}` };
|
|
63
|
+
}
|
|
64
|
+
export function isMerged(pull) {
|
|
65
|
+
return pull.merged === 1 || pull.merged === true;
|
|
66
|
+
}
|
|
67
|
+
// Label-name comparison is case-INSENSITIVE. GitHub treats label names
|
|
68
|
+
// case-insensitively for creation but preserves display casing, and the twin
|
|
69
|
+
// stores whatever casing the API caller sent (`domain/github-domain.ts` inserts
|
|
70
|
+
// the name verbatim) — so a criterion saying `Bug` against an export saying
|
|
71
|
+
// `bug` must not read as a missing label.
|
|
72
|
+
export function sameLabel(a, b) {
|
|
73
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
export function appliedLabelNames(issue) {
|
|
76
|
+
return (issue.labels ?? [])
|
|
77
|
+
.map((label) => label.name)
|
|
78
|
+
.filter((name) => typeof name === "string");
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=check-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-state.js","sourceRoot":"","sources":["../../src/check-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface GitHubCheckStateIssue {
|
|
6
|
-
number?: number;
|
|
7
|
-
labels?: string[] | null;
|
|
8
|
-
}
|
|
9
|
-
export interface GitHubCheckStateRepo {
|
|
10
|
-
owner?: string;
|
|
11
|
-
name?: string;
|
|
12
|
-
full_name?: string;
|
|
13
|
-
labels?: GitHubCheckStateLabel[] | null;
|
|
14
|
-
issues?: GitHubCheckStateIssue[] | null;
|
|
15
|
-
}
|
|
16
|
-
export interface GitHubCheckState {
|
|
17
|
-
repositories?: GitHubCheckStateRepo[] | null;
|
|
18
|
-
}
|
|
19
|
-
export declare const GITHUB_CHECKS: readonly [CheckDefinition<GitHubCheckState, {
|
|
1
|
+
export type { Check } from "./check-kind.js";
|
|
2
|
+
export type { GitHubCheckState, GitHubCheckStateComment, GitHubCheckStateCommitStatus, GitHubCheckStateFile, GitHubCheckStateIssue, GitHubCheckStateLabel, GitHubCheckStatePullRequest, GitHubCheckStateRepo, GitHubCheckStateReview, } from "./check-state.js";
|
|
3
|
+
export declare const GITHUB_CHECKS: readonly [import("./check-kind.js").Check<{
|
|
4
|
+
issue: string;
|
|
20
5
|
repo: string;
|
|
6
|
+
}>, import("./check-kind.js").Check<{
|
|
7
|
+
issue: string;
|
|
8
|
+
repo: string;
|
|
9
|
+
state: string;
|
|
10
|
+
}>, import("./check-kind.js").Check<{
|
|
11
|
+
issue: string;
|
|
12
|
+
repo: string;
|
|
13
|
+
label: string;
|
|
14
|
+
}>, import("./check-kind.js").Check<{
|
|
15
|
+
issue: string;
|
|
16
|
+
repo: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}>, import("./check-kind.js").Check<{
|
|
19
|
+
issue: string;
|
|
20
|
+
repo: string;
|
|
21
|
+
login: string;
|
|
22
|
+
}>, import("./check-kind.js").Check<{
|
|
23
|
+
needle: string;
|
|
24
|
+
issue: string;
|
|
25
|
+
repo: string;
|
|
26
|
+
}>, import("./check-kind.js").Check<{
|
|
27
|
+
repo: string;
|
|
28
|
+
}>, import("./check-kind.js").Check<{
|
|
29
|
+
pr: string;
|
|
30
|
+
repo: string;
|
|
31
|
+
state: string;
|
|
32
|
+
}>, import("./check-kind.js").Check<{
|
|
33
|
+
review: string;
|
|
34
|
+
pr: string;
|
|
35
|
+
repo: string;
|
|
36
|
+
}>, import("./check-kind.js").Check<{
|
|
37
|
+
path: string;
|
|
38
|
+
repo: string;
|
|
39
|
+
}>, import("./check-kind.js").Check<{
|
|
40
|
+
context: string;
|
|
41
|
+
repo: string;
|
|
42
|
+
state: string;
|
|
21
43
|
}>];
|
|
@@ -1,90 +1,65 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
//
|
|
3
|
-
// The GitHub twin's assertable check vocabulary (F-1073,
|
|
3
|
+
// The GitHub twin's assertable check vocabulary (F-1073, widened in F-1075).
|
|
4
4
|
//
|
|
5
5
|
// These live HERE, next to the state they read, because the twin owns that
|
|
6
6
|
// state's shape. pome-cloud imports this module from npm and adapts each
|
|
7
7
|
// declaration onto its predicate engine, so there is no second copy to
|
|
8
8
|
// reconcile — only a pin that can fall behind, which is what its drift gate
|
|
9
9
|
// exists to catch.
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// The engine guards this before calling; the check guards too, so a
|
|
66
|
-
// consumer that forgets gets a named skip rather than a vacuous pass.
|
|
67
|
-
if (seed === null)
|
|
68
|
-
return { passed: false, reason: "seed_missing", status: "skipped" };
|
|
69
|
-
const seedRepo = findRepo(seed, repo);
|
|
70
|
-
if (!seedRepo)
|
|
71
|
-
return { passed: false, reason: `repo ${repo} not found in the seed state` };
|
|
72
|
-
const finalRepo = findRepo(final, repo);
|
|
73
|
-
if (!finalRepo)
|
|
74
|
-
return { passed: false, reason: `repo ${repo} not found in state_final` };
|
|
75
|
-
const before = labelNames(seedRepo);
|
|
76
|
-
const created = [...labelNames(finalRepo)].filter((name) => !before.has(name)).sort();
|
|
77
|
-
if (created.length === 0) {
|
|
78
|
-
return {
|
|
79
|
-
passed: true,
|
|
80
|
-
reason: `no labels were created in ${repo} (${before.size} defined at seed, unchanged at finish)`,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
passed: false,
|
|
85
|
-
reason: `labels created in ${repo}: ${created.map((name) => `\`${name}\``).join(", ")}`,
|
|
86
|
-
};
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
export const GITHUB_CHECKS = [noNewLabels];
|
|
10
|
+
//
|
|
11
|
+
// This file is the ASSEMBLY. The declarations themselves are grouped by the
|
|
12
|
+
// entity they assert about — `check-issues.ts`, `check-pulls.ts`,
|
|
13
|
+
// `check-repos.ts` — with the typed slots in `check-params.ts` and the reading
|
|
14
|
+
// of the exported tree in `check-state.ts`.
|
|
15
|
+
//
|
|
16
|
+
// F-1075 moved the remaining ten GitHub predicates here from
|
|
17
|
+
// `apps/control-plane/.../deterministic/github.ts`, where they were regexes.
|
|
18
|
+
// Three things changed in the move, and each is load-bearing:
|
|
19
|
+
//
|
|
20
|
+
// 1. THE REGEX IS GONE. The matcher is generated from `template`, so a
|
|
21
|
+
// declaration and its pattern cannot drift. An author never types the
|
|
22
|
+
// sentence, so binding cannot fail (position 2, ratified 2026-07-27).
|
|
23
|
+
//
|
|
24
|
+
// 2. EVERY CHECK NAMES ITS REPO. The legacy patterns took `in owner/repo` as
|
|
25
|
+
// an OPTIONAL qualifier and, when it was absent, scanned repos
|
|
26
|
+
// first-match-wins. That is a latent wrong-match: a multi-repo world
|
|
27
|
+
// reuses issue numbers, and the criterion would silently grade whichever
|
|
28
|
+
// repo sorted first. Under a picked check the repo costs the author
|
|
29
|
+
// nothing — the picker asks for it — so the ambiguity is simply removed.
|
|
30
|
+
// It also matches `no-new-labels`, which has always named its repo, and
|
|
31
|
+
// for the same reason: the repo is what tells a reader WHICH scope is
|
|
32
|
+
// being asserted. `checks-contract.test.ts` asserts it of every check.
|
|
33
|
+
//
|
|
34
|
+
// 3. TWO PHRASINGS BECAME ONE CHECK. The legacy registry carried both
|
|
35
|
+
// `issue-has-label` ("has the `bug` label") and `issue-has-label-generic`
|
|
36
|
+
// ("has label bug") for one predicate, because free English arrives in
|
|
37
|
+
// more than one word order. Nothing renders the second one now, so it is
|
|
38
|
+
// retired rather than ported.
|
|
39
|
+
//
|
|
40
|
+
// What did NOT move: `No unsupported endpoint was called`. It reads the call
|
|
41
|
+
// TAPE, and whether a check may read the ordered tape is D1's open half —
|
|
42
|
+
// F-1076 settles it and brings that check here. Declaring it now would mean
|
|
43
|
+
// declaring a substrate nothing supplies.
|
|
44
|
+
import { issueAssignee, issueCommentContains, issueExactlyOneLabel, issueExists, issueHasLabel, issueStateCheck, } from "./check-issues.js";
|
|
45
|
+
import { pullRequestReviewExists, pullRequestStateCheck } from "./check-pulls.js";
|
|
46
|
+
import { commitStatus, fileExists, noNewLabels } from "./check-repos.js";
|
|
47
|
+
// Order is not first-match-wins here — the generated patterns are anchored and
|
|
48
|
+
// mutually exclusive, and `checks-contract.test.ts` proves no sentence is
|
|
49
|
+
// claimed by two checks. It is the order an authoring surface lists them in, so
|
|
50
|
+
// it runs from the assertion an author reaches for first to the ones a
|
|
51
|
+
// specialised task needs.
|
|
52
|
+
export const GITHUB_CHECKS = [
|
|
53
|
+
issueExists,
|
|
54
|
+
issueStateCheck,
|
|
55
|
+
issueHasLabel,
|
|
56
|
+
issueExactlyOneLabel,
|
|
57
|
+
issueAssignee,
|
|
58
|
+
issueCommentContains,
|
|
59
|
+
noNewLabels,
|
|
60
|
+
pullRequestStateCheck,
|
|
61
|
+
pullRequestReviewExists,
|
|
62
|
+
fileExists,
|
|
63
|
+
commitStatus,
|
|
64
|
+
];
|
|
90
65
|
//# sourceMappingURL=checks.js.map
|