@pome-sh/cli 0.14.0 → 0.16.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/dist/src/cli/checks.d.ts +15 -0
- package/dist/src/cli/checks.js +41 -4
- package/node_modules/@pome-sh/twin-gmail/CHANGELOG.md +39 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-drafts.d.ts +7 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-drafts.js +138 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-drafts.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-kind.d.ts +3 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-kind.js +9 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-kind.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-labels.d.ts +4 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-labels.js +56 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-labels.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-messages.d.ts +14 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-messages.js +207 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-messages.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-params.d.ts +10 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-params.js +96 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-params.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-state.d.ts +113 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-state.js +145 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-state.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-tape.d.ts +2 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-tape.js +103 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-tape.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-worlds.d.ts +17 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-worlds.js +62 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/check-worlds.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/checks.d.ts +19 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/checks.js +42 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/checks.js.map +1 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/index.d.ts +2 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/index.js +4 -0
- package/node_modules/@pome-sh/twin-gmail/dist/src/index.js.map +1 -1
- package/node_modules/@pome-sh/twin-gmail/package.json +1 -1
- package/node_modules/@pome-sh/twin-linear/CHANGELOG.md +41 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-comments.d.ts +10 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-comments.js +117 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-comments.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-issues.d.ts +25 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-issues.js +211 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-issues.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-kind.d.ts +3 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-kind.js +9 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-kind.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-params.d.ts +8 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-params.js +94 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-params.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-state.d.ts +98 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-state.js +131 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-state.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-tape.d.ts +2 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-tape.js +100 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-tape.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-worlds.d.ts +44 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-worlds.js +93 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/check-worlds.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/checks.d.ts +29 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/checks.js +52 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/checks.js.map +1 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/index.d.ts +2 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/index.js +7 -0
- package/node_modules/@pome-sh/twin-linear/dist/src/index.js.map +1 -1
- package/node_modules/@pome-sh/twin-linear/package.json +1 -1
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-kind.d.ts +3 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-kind.js +9 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-kind.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-params.d.ts +8 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-params.js +123 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-params.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-payments.d.ts +18 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-payments.js +264 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-payments.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-refunds.d.ts +8 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-refunds.js +122 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-refunds.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-state.d.ts +83 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-state.js +95 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-state.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-tape.d.ts +9 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-tape.js +338 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-tape.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-worlds.d.ts +24 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-worlds.js +131 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/check-worlds.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/checks.d.ts +22 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/checks.js +97 -0
- package/node_modules/@pome-sh/twin-stripe/dist/src/checks.js.map +1 -0
- package/node_modules/@pome-sh/twin-stripe/package.json +1 -1
- package/package.json +4 -4
- package/tasks/11-stripe-handle-failed-payment.md +2 -2
- package/tasks/12-stripe-reconcile-event.md +1 -1
- package/tasks/13-stripe-x402-payment-required.md +2 -2
- package/tasks/14-stripe-refund-retry.md +22 -9
- package/tasks/24-linear-issue-triage.md +2 -2
- package/tasks/25-linear-comment-label-triage.md +3 -3
- package/tasks/26-github-linear-handoff.md +3 -4
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CheckParamType } from "@pome-sh/sdk/checks";
|
|
2
|
+
export declare const messageId: CheckParamType;
|
|
3
|
+
export declare const labelRef: CheckParamType;
|
|
4
|
+
export declare const labelName: CheckParamType;
|
|
5
|
+
export declare const emailAddress: CheckParamType;
|
|
6
|
+
export declare const mailboxRef: CheckParamType;
|
|
7
|
+
export declare const exactCount: CheckParamType;
|
|
8
|
+
export declare const countWord: CheckParamType;
|
|
9
|
+
/** A `countWord` slot's value as a number, or null when it is neither. */
|
|
10
|
+
export declare function parseCount(raw: string): number | null;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// The typed slots Gmail's declared checks fill (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// They live in the twin, not the sdk, for the same reason the declarations do:
|
|
6
|
+
// the twin owns what a Gmail message id or label name may look like. Every
|
|
7
|
+
// pattern is NARROW on purpose — a slot type is what turns "the author typed
|
|
8
|
+
// something wrong" into a corrupted instance reported by name, rather than a
|
|
9
|
+
// lookup that quietly finds nothing.
|
|
10
|
+
//
|
|
11
|
+
// All patterns are capture-group-free; `defineCheck` throws otherwise, because
|
|
12
|
+
// every consumer reads capture group i+1 as slot i and one smuggled group hands
|
|
13
|
+
// each predicate its neighbour's argument.
|
|
14
|
+
// Ids the twin mints (`nextId` → `msg_1`, `Label_3`, `draft_2`) and the ids a
|
|
15
|
+
// seed may pin (`msg_support`, `msg_parity`). No spaces and no dots, which is
|
|
16
|
+
// what separates this slot from `labelName` below.
|
|
17
|
+
export const messageId = {
|
|
18
|
+
name: "message",
|
|
19
|
+
pattern: "[A-Za-z0-9_-]{1,128}",
|
|
20
|
+
example: "msg_support",
|
|
21
|
+
render: (value) => value,
|
|
22
|
+
parse: (raw) => raw,
|
|
23
|
+
};
|
|
24
|
+
// A label REFERENCE: either the minted id (`Label_follow_up`) or a system label,
|
|
25
|
+
// whose id and display name are the same string (`INBOX`, `SENT`, `STARRED`).
|
|
26
|
+
// Deliberately excludes spaces — a label whose NAME has spaces is addressed by
|
|
27
|
+
// `labelName`, and keeping the two slots distinct is what stops
|
|
28
|
+
// `gmail.message-has-label` and `gmail.label-exists` claiming one sentence.
|
|
29
|
+
export const labelRef = {
|
|
30
|
+
name: "label",
|
|
31
|
+
pattern: "[A-Za-z0-9_-]{1,128}",
|
|
32
|
+
example: "STARRED",
|
|
33
|
+
render: (value) => value,
|
|
34
|
+
parse: (raw) => raw,
|
|
35
|
+
};
|
|
36
|
+
// A label's DISPLAY NAME, which Gmail permits spaces in (`Parity Complete`,
|
|
37
|
+
// `Follow Up`). Anchored to start on a word character so the template's
|
|
38
|
+
// surrounding literals cannot be eaten by a leading space.
|
|
39
|
+
export const labelName = {
|
|
40
|
+
name: "label",
|
|
41
|
+
pattern: "[A-Za-z0-9][A-Za-z0-9 _-]{0,127}",
|
|
42
|
+
example: "Parity Complete",
|
|
43
|
+
render: (value) => value,
|
|
44
|
+
parse: (raw) => raw,
|
|
45
|
+
};
|
|
46
|
+
// An addressee. Quote and backtick are excluded as well as whitespace so the
|
|
47
|
+
// slot cannot swallow a template's own delimiters.
|
|
48
|
+
export const emailAddress = {
|
|
49
|
+
name: "email",
|
|
50
|
+
pattern: "[^\\s@\"'`]+@[^\\s@\"'`]+",
|
|
51
|
+
example: "alice@example.com",
|
|
52
|
+
render: (value) => value,
|
|
53
|
+
parse: (raw) => raw,
|
|
54
|
+
};
|
|
55
|
+
// The same shape, named for the slot it fills — a mailbox is addressed by its
|
|
56
|
+
// email in every collection the export emits.
|
|
57
|
+
export const mailboxRef = {
|
|
58
|
+
name: "mailbox",
|
|
59
|
+
pattern: "[^\\s@\"'`]+@[^\\s@\"'`]+",
|
|
60
|
+
example: "pome-agent@pome-twin.test",
|
|
61
|
+
render: (value) => value,
|
|
62
|
+
parse: (raw) => raw,
|
|
63
|
+
};
|
|
64
|
+
// A bare digit count. Nine digits wide so `VACUITY_SENTINEL_NUMBER` re-binds:
|
|
65
|
+
// a mutant that stops matching evaluates to `unmatched`, which reads as "the
|
|
66
|
+
// verdict moved -> healthy" and blesses the very criterion the probe exists to
|
|
67
|
+
// catch.
|
|
68
|
+
export const exactCount = {
|
|
69
|
+
name: "count",
|
|
70
|
+
pattern: "\\d{1,9}",
|
|
71
|
+
example: "5",
|
|
72
|
+
render: (value) => value,
|
|
73
|
+
parse: (raw) => raw,
|
|
74
|
+
};
|
|
75
|
+
// Digits OR the English number words, because the corpus says both — `exactly 5
|
|
76
|
+
// messages` and `each of the five recipients`. Non-capturing, so the alternation
|
|
77
|
+
// costs no capture group.
|
|
78
|
+
export const countWord = {
|
|
79
|
+
name: "count",
|
|
80
|
+
pattern: "(?:\\d{1,9}|zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)",
|
|
81
|
+
example: "two",
|
|
82
|
+
render: (value) => value,
|
|
83
|
+
parse: (raw) => raw,
|
|
84
|
+
};
|
|
85
|
+
const NUMBER_WORDS = {
|
|
86
|
+
zero: 0, one: 1, two: 2, three: 3, four: 4, five: 5,
|
|
87
|
+
six: 6, seven: 7, eight: 8, nine: 9, ten: 10, eleven: 11, twelve: 12,
|
|
88
|
+
};
|
|
89
|
+
/** A `countWord` slot's value as a number, or null when it is neither. */
|
|
90
|
+
export function parseCount(raw) {
|
|
91
|
+
const trimmed = raw.trim().toLowerCase();
|
|
92
|
+
if (/^\d+$/.test(trimmed))
|
|
93
|
+
return Number(trimmed);
|
|
94
|
+
return NUMBER_WORDS[trimmed] ?? null;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=check-params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-params.js","sourceRoot":"","sources":["../../src/check-params.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/** A resolver must be able to say WHY it found nothing: the ways of finding
|
|
2
|
+
* nothing get different verdicts. Same shape and same reason as twin-github's. */
|
|
3
|
+
export type Resolved<T> = {
|
|
4
|
+
found: T;
|
|
5
|
+
} | {
|
|
6
|
+
missing: string;
|
|
7
|
+
};
|
|
8
|
+
export interface GmailCheckStateMailbox {
|
|
9
|
+
email?: string;
|
|
10
|
+
displayName?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface GmailCheckStateMessage {
|
|
13
|
+
mailboxEmail?: string;
|
|
14
|
+
id?: string;
|
|
15
|
+
threadId?: string;
|
|
16
|
+
from?: string;
|
|
17
|
+
to?: string[] | null;
|
|
18
|
+
cc?: string[] | null;
|
|
19
|
+
bcc?: string[] | null;
|
|
20
|
+
subject?: string;
|
|
21
|
+
bodyOmitted?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface GmailCheckStateLabel {
|
|
24
|
+
mailboxEmail?: string;
|
|
25
|
+
id?: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
type?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface GmailCheckStateMessageLabel {
|
|
30
|
+
mailboxEmail?: string;
|
|
31
|
+
messageId?: string;
|
|
32
|
+
labelId?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface GmailCheckStateDraft {
|
|
35
|
+
mailboxEmail?: string;
|
|
36
|
+
id?: string;
|
|
37
|
+
messageId?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface GmailCheckStateBounds {
|
|
40
|
+
messageBodiesOmitted?: boolean;
|
|
41
|
+
largeMailbox?: boolean;
|
|
42
|
+
truncatedCollections?: string[] | null;
|
|
43
|
+
}
|
|
44
|
+
export interface GmailCheckState {
|
|
45
|
+
mailboxes?: GmailCheckStateMailbox[] | null;
|
|
46
|
+
messages?: GmailCheckStateMessage[] | null;
|
|
47
|
+
drafts?: GmailCheckStateDraft[] | null;
|
|
48
|
+
labels?: GmailCheckStateLabel[] | null;
|
|
49
|
+
messageLabels?: GmailCheckStateMessageLabel[] | null;
|
|
50
|
+
exportBounds?: GmailCheckStateBounds | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Was this collection capped on the way out?
|
|
54
|
+
*
|
|
55
|
+
* An export with no `exportBounds` block at all predates the cap and answers
|
|
56
|
+
* false — the same answer it would have given honestly. Treating absence as
|
|
57
|
+
* "truncated" would skip every criterion on an older snapshot.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isTruncated(state: GmailCheckState, collection: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* The message a criterion names, with the outcomes a negative criterion must
|
|
62
|
+
* tell apart:
|
|
63
|
+
* - no `messages` key → `state_incomplete`; we cannot attest anything
|
|
64
|
+
* - present, id absent, collection CAPPED → `collection_truncated`; absent from
|
|
65
|
+
* a truncated list is not absent, and answering `not_found` here would
|
|
66
|
+
* false-fail a correct agent on a large mailbox
|
|
67
|
+
* - present, id absent, not capped → `message_not_found`
|
|
68
|
+
* - present in more than one mailbox → `message_ambiguous`
|
|
69
|
+
*
|
|
70
|
+
* The ambiguity arm is gmail's answer to github's `{repo}` slot. GitHub's legacy
|
|
71
|
+
* patterns took the repo as an optional qualifier and, absent it, scanned
|
|
72
|
+
* first-match-wins, so a two-repo world graded whichever sorted first. Gmail's
|
|
73
|
+
* corpus sentences carry no mailbox and ids are minted per mailbox, so rather
|
|
74
|
+
* than inventing a slot that would stop every existing criterion binding, this
|
|
75
|
+
* REFUSES on the world where the ambiguity is real.
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveMessage(state: GmailCheckState, id: string): Resolved<GmailCheckStateMessage>;
|
|
78
|
+
/**
|
|
79
|
+
* Every label id that counts as `wanted`, lower-cased for comparison.
|
|
80
|
+
*
|
|
81
|
+
* Matches a label row by id OR by display name, because the corpus names both
|
|
82
|
+
* kinds: `Label_follow_up` is an id, `Follow Up` is the name of the same label.
|
|
83
|
+
* The bare `wanted` is always included so the join still works when the `labels`
|
|
84
|
+
* collection was capped away — a `messageLabels` row carries the bare id
|
|
85
|
+
* regardless.
|
|
86
|
+
*/
|
|
87
|
+
export declare function labelIdsFor(state: GmailCheckState, wanted: string): Set<string>;
|
|
88
|
+
/**
|
|
89
|
+
* Does this message carry the named label?
|
|
90
|
+
*
|
|
91
|
+
* Reads the `messageLabels` join. A capped join is refused rather than answered:
|
|
92
|
+
* a missing row there is indistinguishable from a label that was never applied,
|
|
93
|
+
* and on a negative criterion that difference is a leaking agent's free point.
|
|
94
|
+
*/
|
|
95
|
+
export declare function messageCarriesLabel(state: GmailCheckState, messageId: string, wanted: string): Resolved<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* The label a criterion names BY NAME.
|
|
98
|
+
*
|
|
99
|
+
* Deliberately does not fall back to the id. "A label named `Parity Complete`
|
|
100
|
+
* exists" asks about the display name; letting it also match an id would make
|
|
101
|
+
* the sentence mean two things, and `gmail.message-has-label` is the check that
|
|
102
|
+
* speaks ids.
|
|
103
|
+
*/
|
|
104
|
+
export declare function resolveLabelByName(state: GmailCheckState, name: string): Resolved<GmailCheckStateLabel>;
|
|
105
|
+
/**
|
|
106
|
+
* Who a draft is addressed to — `to` + `cc`, from the backing MESSAGE.
|
|
107
|
+
*
|
|
108
|
+
* The exported draft row carries no addressing at all, so a predicate reading it
|
|
109
|
+
* alone would answer "no draft is addressed to anyone", always. A draft whose
|
|
110
|
+
* message did not survive the export contributes nothing rather than throwing;
|
|
111
|
+
* the caller decides whether that emptiness is answerable.
|
|
112
|
+
*/
|
|
113
|
+
export declare function draftRecipients(state: GmailCheckState, draft: GmailCheckStateDraft): string[];
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// How a declared check READS the exported Gmail mailbox (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// pome-cloud kept a hand-maintained mirror of this shape in
|
|
6
|
+
// `deterministic/gmail.ts`. That mirror is deleted in the same milestone; this
|
|
7
|
+
// is the only model, and it lives here because the twin owns the shape.
|
|
8
|
+
//
|
|
9
|
+
// Written against the EXPORT (`state.ts exportGmailState()`), never the seed.
|
|
10
|
+
// The two diverge in ways that each produce a wrong verdict:
|
|
11
|
+
// - the seed says `labels: ["INBOX", "Build"]` on the message, mixing ids and
|
|
12
|
+
// display names; the export hoists them to a flat `messageLabels` JOIN keyed
|
|
13
|
+
// by `labelId`.
|
|
14
|
+
// - the seed puts `to` on the draft; the export's `drafts` row carries only
|
|
15
|
+
// `{mailboxEmail, id, messageId, createdAt, updatedAt}` and the addressing
|
|
16
|
+
// lives on the backing message.
|
|
17
|
+
//
|
|
18
|
+
// Every field is optional and every list nullable, because `exportGmailState`
|
|
19
|
+
// spreads raw SQLite rows: an older snapshot, a partial upload, or a schema that
|
|
20
|
+
// gained a column all arrive here as absent fields. A predicate that assumes
|
|
21
|
+
// presence throws inside the evaluator; one that reads this model returns a
|
|
22
|
+
// NAMED verdict instead. That is the D4 bargain — a criterion may leave the
|
|
23
|
+
// denominator, but it may never fabricate one.
|
|
24
|
+
//
|
|
25
|
+
// Four shapes are counter-intuitive and each has a wrong-verdict story:
|
|
26
|
+
// - MESSAGE BODIES ARE NEVER EXPORTED. `boundMessageExport` strips `text`,
|
|
27
|
+
// `html`, `snippet` and `headers` unconditionally and leaves digests plus
|
|
28
|
+
// `bodyOmitted: true`. A slack-style substring scan over message prose has
|
|
29
|
+
// no substrate here at all — `subject` is the only prose that survives.
|
|
30
|
+
// - COLLECTIONS TRUNCATE at `STATE_EXPORT_COLLECTION_CAP`, and the capped
|
|
31
|
+
// names land in `exportBounds.truncatedCollections`. Absent-from-a-truncated
|
|
32
|
+
// -collection is not absent, so it must skip rather than answer.
|
|
33
|
+
// - LABELS ARE A JOIN. A user label's `id` and `name` differ
|
|
34
|
+
// (`Label_follow_up` / `Follow Up`); a system label carries `id === name`.
|
|
35
|
+
// - EVERYTHING IS MAILBOX-SCOPED via `mailboxEmail`, and ids are minted per
|
|
36
|
+
// mailbox, so `deliveryMode: "seeded-mailboxes"` can put one id in two.
|
|
37
|
+
const lower = (value) => (value ?? "").toLowerCase();
|
|
38
|
+
/**
|
|
39
|
+
* Was this collection capped on the way out?
|
|
40
|
+
*
|
|
41
|
+
* An export with no `exportBounds` block at all predates the cap and answers
|
|
42
|
+
* false — the same answer it would have given honestly. Treating absence as
|
|
43
|
+
* "truncated" would skip every criterion on an older snapshot.
|
|
44
|
+
*/
|
|
45
|
+
export function isTruncated(state, collection) {
|
|
46
|
+
return (state.exportBounds?.truncatedCollections ?? []).includes(collection);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The message a criterion names, with the outcomes a negative criterion must
|
|
50
|
+
* tell apart:
|
|
51
|
+
* - no `messages` key → `state_incomplete`; we cannot attest anything
|
|
52
|
+
* - present, id absent, collection CAPPED → `collection_truncated`; absent from
|
|
53
|
+
* a truncated list is not absent, and answering `not_found` here would
|
|
54
|
+
* false-fail a correct agent on a large mailbox
|
|
55
|
+
* - present, id absent, not capped → `message_not_found`
|
|
56
|
+
* - present in more than one mailbox → `message_ambiguous`
|
|
57
|
+
*
|
|
58
|
+
* The ambiguity arm is gmail's answer to github's `{repo}` slot. GitHub's legacy
|
|
59
|
+
* patterns took the repo as an optional qualifier and, absent it, scanned
|
|
60
|
+
* first-match-wins, so a two-repo world graded whichever sorted first. Gmail's
|
|
61
|
+
* corpus sentences carry no mailbox and ids are minted per mailbox, so rather
|
|
62
|
+
* than inventing a slot that would stop every existing criterion binding, this
|
|
63
|
+
* REFUSES on the world where the ambiguity is real.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveMessage(state, id) {
|
|
66
|
+
if (state.messages == null)
|
|
67
|
+
return { missing: "state_incomplete" };
|
|
68
|
+
const hits = state.messages.filter((message) => lower(message.id) === lower(id));
|
|
69
|
+
if (hits.length > 1) {
|
|
70
|
+
return { missing: `message_ambiguous ("${id}" exists in ${hits.length} mailboxes)` };
|
|
71
|
+
}
|
|
72
|
+
if (hits.length === 1)
|
|
73
|
+
return { found: hits[0] };
|
|
74
|
+
if (isTruncated(state, "messages"))
|
|
75
|
+
return { missing: 'collection_truncated ("messages")' };
|
|
76
|
+
return { missing: `message_not_found ("${id}")` };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Every label id that counts as `wanted`, lower-cased for comparison.
|
|
80
|
+
*
|
|
81
|
+
* Matches a label row by id OR by display name, because the corpus names both
|
|
82
|
+
* kinds: `Label_follow_up` is an id, `Follow Up` is the name of the same label.
|
|
83
|
+
* The bare `wanted` is always included so the join still works when the `labels`
|
|
84
|
+
* collection was capped away — a `messageLabels` row carries the bare id
|
|
85
|
+
* regardless.
|
|
86
|
+
*/
|
|
87
|
+
export function labelIdsFor(state, wanted) {
|
|
88
|
+
const ids = new Set([lower(wanted)]);
|
|
89
|
+
for (const label of state.labels ?? []) {
|
|
90
|
+
const matches = lower(label.name) === lower(wanted) || lower(label.id) === lower(wanted);
|
|
91
|
+
if (matches && label.id != null)
|
|
92
|
+
ids.add(lower(label.id));
|
|
93
|
+
}
|
|
94
|
+
return ids;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Does this message carry the named label?
|
|
98
|
+
*
|
|
99
|
+
* Reads the `messageLabels` join. A capped join is refused rather than answered:
|
|
100
|
+
* a missing row there is indistinguishable from a label that was never applied,
|
|
101
|
+
* and on a negative criterion that difference is a leaking agent's free point.
|
|
102
|
+
*/
|
|
103
|
+
export function messageCarriesLabel(state, messageId, wanted) {
|
|
104
|
+
if (state.messageLabels == null)
|
|
105
|
+
return { missing: "state_incomplete" };
|
|
106
|
+
const ids = labelIdsFor(state, wanted);
|
|
107
|
+
const carried = state.messageLabels.some((row) => lower(row.messageId) === lower(messageId) && ids.has(lower(row.labelId)));
|
|
108
|
+
if (!carried && isTruncated(state, "messageLabels")) {
|
|
109
|
+
return { missing: 'collection_truncated ("messageLabels")' };
|
|
110
|
+
}
|
|
111
|
+
return { found: carried };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The label a criterion names BY NAME.
|
|
115
|
+
*
|
|
116
|
+
* Deliberately does not fall back to the id. "A label named `Parity Complete`
|
|
117
|
+
* exists" asks about the display name; letting it also match an id would make
|
|
118
|
+
* the sentence mean two things, and `gmail.message-has-label` is the check that
|
|
119
|
+
* speaks ids.
|
|
120
|
+
*/
|
|
121
|
+
export function resolveLabelByName(state, name) {
|
|
122
|
+
if (state.labels == null)
|
|
123
|
+
return { missing: "state_incomplete" };
|
|
124
|
+
const hit = state.labels.find((label) => lower(label.name) === lower(name));
|
|
125
|
+
if (hit)
|
|
126
|
+
return { found: hit };
|
|
127
|
+
if (isTruncated(state, "labels"))
|
|
128
|
+
return { missing: 'collection_truncated ("labels")' };
|
|
129
|
+
return { missing: `label_not_found ("${name}")` };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Who a draft is addressed to — `to` + `cc`, from the backing MESSAGE.
|
|
133
|
+
*
|
|
134
|
+
* The exported draft row carries no addressing at all, so a predicate reading it
|
|
135
|
+
* alone would answer "no draft is addressed to anyone", always. A draft whose
|
|
136
|
+
* message did not survive the export contributes nothing rather than throwing;
|
|
137
|
+
* the caller decides whether that emptiness is answerable.
|
|
138
|
+
*/
|
|
139
|
+
export function draftRecipients(state, draft) {
|
|
140
|
+
const message = (state.messages ?? []).find((candidate) => lower(candidate.id) === lower(draft.messageId));
|
|
141
|
+
if (!message)
|
|
142
|
+
return [];
|
|
143
|
+
return [...(message.to ?? []), ...(message.cc ?? [])];
|
|
144
|
+
}
|
|
145
|
+
//# 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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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What Gmail's declared checks can assert about the RUN — the recorded call tape
|
|
4
|
+
// rather than the exported end state (F-1128).
|
|
5
|
+
//
|
|
6
|
+
// Why this class has to exist at all: an unsupported call leaves NO STATE TRACE.
|
|
7
|
+
// The twin answers 501 and mutates nothing, so `state_final.json` is
|
|
8
|
+
// byte-identical whether the examinee reached for an unimplemented route or
|
|
9
|
+
// never tried. The runtime stamps `fidelity: "unsupported"` on the recorded
|
|
10
|
+
// event instead, and that stamp is the only place the fact survives.
|
|
11
|
+
//
|
|
12
|
+
// This was the SHARED `unsupportedEndpointRule` in pome-cloud, registered by
|
|
13
|
+
// gmail and linear alike. Deleting `deterministic/gmail.ts` takes gmail's
|
|
14
|
+
// registration with it, so the declaration has to carry the assertion across or
|
|
15
|
+
// the criterion falls out of the vocabulary. `endpoints.ts` stays in the cloud
|
|
16
|
+
// for linear, which is still undeclared.
|
|
17
|
+
import { defineCheck } from "@pome-sh/sdk/checks";
|
|
18
|
+
import { tapeWorld } from "./check-worlds.js";
|
|
19
|
+
export const noUnsupportedEndpoint = defineCheck({
|
|
20
|
+
id: "gmail.no-unsupported-endpoint",
|
|
21
|
+
description: "Scans the recorded call tape for any request the twin answered with " +
|
|
22
|
+
'fidelity "unsupported" — a route it does not implement, answered 501. It asserts nothing ' +
|
|
23
|
+
"about whether the run SUCCEEDED, and nothing about calls that were merely rejected: a 404 " +
|
|
24
|
+
"or a 422 from a route the twin does implement is a semantic answer and passes this check. " +
|
|
25
|
+
"The tape is scoped to this twin by the engine before the check sees it, so an unsupported " +
|
|
26
|
+
"call to a DIFFERENT twin in a multi-twin session cannot fail it — which matters here, " +
|
|
27
|
+
"because task 27 runs gmail and github together.",
|
|
28
|
+
// No slots, and no twin word. The legacy cloud rule accepted "No unsupported
|
|
29
|
+
// Gmail endpoint was called" alongside the bare form, plus plural and `were`
|
|
30
|
+
// variants, because an author typed English. Under position 2 an author PICKS
|
|
31
|
+
// the check, so those variants are retired rather than ported — the same
|
|
32
|
+
// decision `github.no-unsupported-endpoint` made, and this is now the same
|
|
33
|
+
// sentence on both twins, resolved per-twin by the engine.
|
|
34
|
+
template: "No unsupported endpoint was called",
|
|
35
|
+
params: {},
|
|
36
|
+
substrate: "tape",
|
|
37
|
+
// A prohibition. Nothing is required to happen; only the examinee reaching for
|
|
38
|
+
// an unimplemented route can break it.
|
|
39
|
+
polarity: () => "negative",
|
|
40
|
+
// No caller-supplied literal is hunted for in any substrate, so there is
|
|
41
|
+
// nothing a redactor could silently delete out from under this check.
|
|
42
|
+
subject: () => null,
|
|
43
|
+
// No slots, so the sentence carries no literal to falsify. The trigger is "a
|
|
44
|
+
// call with fidelity=unsupported exists", which lives on the tape and not in
|
|
45
|
+
// the sentence. Reported as `no_trigger`, never as clean.
|
|
46
|
+
vacuityMutant: () => null,
|
|
47
|
+
discriminatingWorlds: () => ({
|
|
48
|
+
passing: tapeWorld([
|
|
49
|
+
{
|
|
50
|
+
twin: "gmail",
|
|
51
|
+
method: "GET",
|
|
52
|
+
path: "/gmail/v1/users/me/messages",
|
|
53
|
+
status: 200,
|
|
54
|
+
fidelity: "semantic",
|
|
55
|
+
event_id: "evt_ok",
|
|
56
|
+
},
|
|
57
|
+
]),
|
|
58
|
+
failing: tapeWorld([
|
|
59
|
+
{
|
|
60
|
+
twin: "gmail",
|
|
61
|
+
method: "POST",
|
|
62
|
+
path: "/gmail/v1/users/me/watch",
|
|
63
|
+
status: 501,
|
|
64
|
+
fidelity: "unsupported",
|
|
65
|
+
event_id: "evt_bad",
|
|
66
|
+
},
|
|
67
|
+
]),
|
|
68
|
+
}),
|
|
69
|
+
evaluate(_args, { tape }) {
|
|
70
|
+
// The engine guards this before calling; the check guards too, so a consumer
|
|
71
|
+
// that forgets gets a named skip rather than a vacuous pass. For a NEGATIVE
|
|
72
|
+
// criterion that distinction is the whole ballgame — passing here would be a
|
|
73
|
+
// clean bill of health issued over a tape nobody read.
|
|
74
|
+
//
|
|
75
|
+
// Note `null` and `[]` are deliberately different: an EMPTY tape is a real
|
|
76
|
+
// world (the agent called nothing, so it called nothing unsupported) and
|
|
77
|
+
// reaches a real verdict below.
|
|
78
|
+
if (tape === null)
|
|
79
|
+
return { passed: false, reason: "tape_missing", status: "skipped" };
|
|
80
|
+
const unsupported = tape.filter((event) => event.fidelity === "unsupported");
|
|
81
|
+
if (unsupported.length === 0) {
|
|
82
|
+
// No evidence on the pass branch (F-980). This asserts a NEGATIVE over the
|
|
83
|
+
// whole tape and a negative over an empty set has no single call to point
|
|
84
|
+
// at; citing all N inspected calls would be a copy of the trace.
|
|
85
|
+
return {
|
|
86
|
+
passed: true,
|
|
87
|
+
reason: `no unsupported Gmail endpoint was called (${tape.length} call(s) inspected)`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Cite the offenders. A row with no `event_id` drops out of the CITATION but
|
|
91
|
+
// not out of the count or the prose: losing an id must never lose a finding.
|
|
92
|
+
const evidenceEventIds = unsupported
|
|
93
|
+
.map((event) => event.event_id)
|
|
94
|
+
.filter((id) => typeof id === "string" && id !== "");
|
|
95
|
+
const outcome = {
|
|
96
|
+
passed: false,
|
|
97
|
+
reason: `${unsupported.length} unsupported Gmail call(s): ` +
|
|
98
|
+
`[${unsupported.map((event) => event.path ?? "?").join(", ")}]`,
|
|
99
|
+
};
|
|
100
|
+
return evidenceEventIds.length > 0 ? { ...outcome, evidenceEventIds } : outcome;
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=check-tape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-tape.js","sourceRoot":"","sources":["../../src/check-tape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CheckSubstrate, CheckTapeEvent } from "@pome-sh/sdk/checks";
|
|
2
|
+
import type { GmailCheckState, GmailCheckStateDraft, GmailCheckStateLabel, GmailCheckStateMessage, GmailCheckStateMessageLabel } from "./check-state.js";
|
|
3
|
+
export declare const FIXTURE_MAILBOX = "pome-agent@pome-twin.test";
|
|
4
|
+
export declare function gmailState(parts?: Partial<GmailCheckState>): GmailCheckState;
|
|
5
|
+
export declare function finalWorld(final: GmailCheckState): CheckSubstrate<GmailCheckState>;
|
|
6
|
+
export declare function tapeWorld(tape: readonly CheckTapeEvent[]): CheckSubstrate<GmailCheckState>;
|
|
7
|
+
export declare function message(id: string, parts?: Partial<GmailCheckStateMessage>): GmailCheckStateMessage;
|
|
8
|
+
export declare function systemLabel(name: string): GmailCheckStateLabel;
|
|
9
|
+
export declare function userLabel(id: string, name: string): GmailCheckStateLabel;
|
|
10
|
+
export declare function messageLabel(messageId: string, labelId: string): GmailCheckStateMessageLabel;
|
|
11
|
+
export declare function draft(id: string, messageId: string): GmailCheckStateDraft;
|
|
12
|
+
/** A draft plus the message its addressing lives on — the pair, because either
|
|
13
|
+
* alone is a world the export could not produce. */
|
|
14
|
+
export declare function draftAddressedTo(id: string, recipients: string[]): {
|
|
15
|
+
draft: GmailCheckStateDraft;
|
|
16
|
+
message: GmailCheckStateMessage;
|
|
17
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// The fixture worlds Gmail's declarations name (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// In `src/` rather than `test/` for the same reason twin-github's and
|
|
6
|
+
// twin-slack's are: `discriminatingWorlds` is a DECLARED field read from npm by
|
|
7
|
+
// pome-cloud and the CLI, so a builder that shipped only in the test tree would
|
|
8
|
+
// make the field unusable outside this repo.
|
|
9
|
+
//
|
|
10
|
+
// `gmailState` fills every collection explicitly, including the empty ones.
|
|
11
|
+
// Omitting one makes the reader answer `state_incomplete`, which is a SKIP, and
|
|
12
|
+
// a skip satisfies neither arm of the discrimination gate — so the explicitness
|
|
13
|
+
// is load-bearing, not tidiness.
|
|
14
|
+
export const FIXTURE_MAILBOX = "pome-agent@pome-twin.test";
|
|
15
|
+
export function gmailState(parts = {}) {
|
|
16
|
+
return {
|
|
17
|
+
mailboxes: [{ email: FIXTURE_MAILBOX }],
|
|
18
|
+
messages: [],
|
|
19
|
+
drafts: [],
|
|
20
|
+
labels: [],
|
|
21
|
+
messageLabels: [],
|
|
22
|
+
exportBounds: { messageBodiesOmitted: true, largeMailbox: false, truncatedCollections: [] },
|
|
23
|
+
...parts,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function finalWorld(final) {
|
|
27
|
+
return { seed: null, final, tape: null };
|
|
28
|
+
}
|
|
29
|
+
// A well-formed but EMPTY mailbox, deliberately not `{}`. A tape check must not
|
|
30
|
+
// read state, and handing it a shape that would satisfy a state check hides the
|
|
31
|
+
// difference — twin-github's `tapeWorld` makes the same choice for the same
|
|
32
|
+
// reason.
|
|
33
|
+
export function tapeWorld(tape) {
|
|
34
|
+
return { seed: null, final: gmailState(), tape };
|
|
35
|
+
}
|
|
36
|
+
export function message(id, parts = {}) {
|
|
37
|
+
return { mailboxEmail: FIXTURE_MAILBOX, id, to: [FIXTURE_MAILBOX], bodyOmitted: true, ...parts };
|
|
38
|
+
}
|
|
39
|
+
export function systemLabel(name) {
|
|
40
|
+
// System labels carry `id === name`. Building them any other way would make a
|
|
41
|
+
// fixture that the twin's own export could never produce.
|
|
42
|
+
return { mailboxEmail: FIXTURE_MAILBOX, id: name, name, type: "system" };
|
|
43
|
+
}
|
|
44
|
+
export function userLabel(id, name) {
|
|
45
|
+
return { mailboxEmail: FIXTURE_MAILBOX, id, name, type: "user" };
|
|
46
|
+
}
|
|
47
|
+
export function messageLabel(messageId, labelId) {
|
|
48
|
+
return { mailboxEmail: FIXTURE_MAILBOX, messageId, labelId };
|
|
49
|
+
}
|
|
50
|
+
export function draft(id, messageId) {
|
|
51
|
+
return { mailboxEmail: FIXTURE_MAILBOX, id, messageId };
|
|
52
|
+
}
|
|
53
|
+
/** A draft plus the message its addressing lives on — the pair, because either
|
|
54
|
+
* alone is a world the export could not produce. */
|
|
55
|
+
export function draftAddressedTo(id, recipients) {
|
|
56
|
+
const messageId = `${id}_message`;
|
|
57
|
+
return {
|
|
58
|
+
draft: draft(id, messageId),
|
|
59
|
+
message: message(messageId, { to: recipients }),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=check-worlds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-worlds.js","sourceRoot":"","sources":["../../src/check-worlds.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,yDAAyD;AACzD,EAAE;AACF,sEAAsE;AACtE,gFAAgF;AAChF,gFAAgF;AAChF,6CAA6C;AAC7C,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,iCAAiC;AAWjC,MAAM,CAAC,MAAM,eAAe,GAAG,2BAA2B,CAAC;AAE3D,MAAM,UAAU,UAAU,CAAC,QAAkC,EAAE;IAC7D,OAAO;QACL,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;QACvC,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,EAAE;QACV,aAAa,EAAE,EAAE;QACjB,YAAY,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,EAAE;QAC3F,GAAG,KAAK;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,UAAU;AACV,MAAM,UAAU,SAAS,CAAC,IAA+B;IACvD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,EAAU,EACV,QAAyC,EAAE;IAE3C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;AACnG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,8EAA8E;IAC9E,0DAA0D;IAC1D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAU,EAAE,IAAY;IAChD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,OAAe;IAC7D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,SAAiB;IACjD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;AAC1D,CAAC;AAED;qDACqD;AACrD,MAAM,UAAU,gBAAgB,CAC9B,EAAU,EACV,UAAoB;IAEpB,MAAM,SAAS,GAAG,GAAG,EAAE,UAAU,CAAC;IAClC,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,CAAC;QAC3B,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type { Check } from "./check-kind.js";
|
|
2
|
+
export type { GmailCheckState, GmailCheckStateDraft, GmailCheckStateLabel, GmailCheckStateMailbox, GmailCheckStateMessage, GmailCheckStateMessageLabel, } from "./check-state.js";
|
|
3
|
+
export declare const GMAIL_CHECKS: readonly [import("./check-kind.js").Check<{
|
|
4
|
+
message: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}>, import("./check-kind.js").Check<{
|
|
7
|
+
label: string;
|
|
8
|
+
}>, import("./check-kind.js").Check<{
|
|
9
|
+
email: string;
|
|
10
|
+
}>, import("./check-kind.js").Check<{
|
|
11
|
+
count: string;
|
|
12
|
+
}>, import("./check-kind.js").Check<{
|
|
13
|
+
mailbox: string;
|
|
14
|
+
count: string;
|
|
15
|
+
label: string;
|
|
16
|
+
}>, import("./check-kind.js").Check<{
|
|
17
|
+
label: string;
|
|
18
|
+
count: string;
|
|
19
|
+
}>, import("./check-kind.js").Check<Record<string, never>>];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// The Gmail twin's assertable check vocabulary (F-1128, milestone A3).
|
|
4
|
+
//
|
|
5
|
+
// These live HERE, next to the state they read, because the twin owns that
|
|
6
|
+
// state's shape. pome-cloud imports this module from npm and adapts each
|
|
7
|
+
// declaration onto its predicate engine, so there is no second copy to
|
|
8
|
+
// reconcile — only a pin that can fall behind, which is what its drift gate
|
|
9
|
+
// exists to catch. The cloud's `deterministic/gmail.ts`, and the mirror of the
|
|
10
|
+
// state shape inside it, are deleted in the same milestone.
|
|
11
|
+
//
|
|
12
|
+
// Gmail comes third in A3 and is the first that needed PLUMBING before
|
|
13
|
+
// vocabulary: unlike slack and stripe it had no in-process seed loader in the
|
|
14
|
+
// control plane at all, so every gmail criterion reported `no_seed_loader` —
|
|
15
|
+
// not a wrong verdict, an absent one. Six criteria across tasks 22, 23 and 27
|
|
16
|
+
// resolved zero of six before this.
|
|
17
|
+
//
|
|
18
|
+
// This file is the ASSEMBLY. Declarations are grouped by what they assert about
|
|
19
|
+
// — `check-messages.ts`, `check-labels.ts`, `check-drafts.ts`, `check-tape.ts` —
|
|
20
|
+
// with typed slots in `check-params.ts`, fixture worlds in `check-worlds.ts`,
|
|
21
|
+
// and the reading of the exported tree in `check-state.ts`.
|
|
22
|
+
import { draftAddressedTo, draftCountAtLeast } from "./check-drafts.js";
|
|
23
|
+
import { labelExists } from "./check-labels.js";
|
|
24
|
+
import { mailboxLabelCount, messageHasLabel, oneMessagePerRecipient } from "./check-messages.js";
|
|
25
|
+
import { noUnsupportedEndpoint } from "./check-tape.js";
|
|
26
|
+
// Order is not first-match-wins — the generated patterns are anchored and
|
|
27
|
+
// mutually exclusive, and `checks-contract.test.ts` proves no sentence is
|
|
28
|
+
// claimed by two. It is the order an authoring surface lists them in, running
|
|
29
|
+
// from the assertion an author reaches for first to the ones a specialised task
|
|
30
|
+
// needs.
|
|
31
|
+
export const GMAIL_CHECKS = [
|
|
32
|
+
messageHasLabel,
|
|
33
|
+
labelExists,
|
|
34
|
+
draftAddressedTo,
|
|
35
|
+
draftCountAtLeast,
|
|
36
|
+
mailboxLabelCount,
|
|
37
|
+
oneMessagePerRecipient,
|
|
38
|
+
// Last, because these are the only ones that assert about the RUN rather than
|
|
39
|
+
// the world it left behind — twin-github orders its tape checks the same way.
|
|
40
|
+
noUnsupportedEndpoint,
|
|
41
|
+
];
|
|
42
|
+
//# sourceMappingURL=checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/checks.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,uEAAuE;AACvE,EAAE;AACF,2EAA2E;AAC3E,yEAAyE;AACzE,uEAAuE;AACvE,4EAA4E;AAC5E,+EAA+E;AAC/E,4DAA4D;AAC5D,EAAE;AACF,uEAAuE;AACvE,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,oCAAoC;AACpC,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,4DAA4D;AAE5D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAYxD,0EAA0E;AAC1E,0EAA0E;AAC1E,8EAA8E;AAC9E,gFAAgF;AAChF,SAAS;AACT,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,eAAe;IACf,WAAW;IACX,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,sBAAsB;IACtB,8EAA8E;IAC9E,8EAA8E;IAC9E,qBAAqB;CACb,CAAC"}
|