@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
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "pome-sh",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"git_sha": "
|
|
5
|
-
"build_time": "2026-07-
|
|
3
|
+
"version": "0.16.0",
|
|
4
|
+
"git_sha": "1d69d644c3acee14dc92d621968b1322c40a0bf0",
|
|
5
|
+
"build_time": "2026-07-31T00:23:39.731Z"
|
|
6
6
|
}
|
package/dist/src/cli/checks.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { type CheckDefinition } from "@pome-sh/sdk/checks";
|
|
2
2
|
export type DeclaredCheck = CheckDefinition<unknown, Record<string, string>>;
|
|
3
3
|
export declare function twinsWithChecks(): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Twins that exist but declare nothing yet.
|
|
6
|
+
*
|
|
7
|
+
* Exported because the no-vocabulary PATH is a real behaviour with its own
|
|
8
|
+
* tests, and those tests need a twin on this list to exercise it. Naming one
|
|
9
|
+
* inline is what broke five of them when stripe left the list (F-1127) — a
|
|
10
|
+
* literal there asserts the MEMBERSHIP of the set, where the test means to
|
|
11
|
+
* assert the behaviour, which is the same defect F-1075 hit with a hard-coded
|
|
12
|
+
* picker index.
|
|
13
|
+
*
|
|
14
|
+
* A3 empties this list, and F-1129 answered the question that raised: the PATH
|
|
15
|
+
* stays, the LITERAL goes. It is now `MOUNTED_TWINS` minus the registry, so an
|
|
16
|
+
* empty result is a fact about the world rather than a list nobody updated.
|
|
17
|
+
*/
|
|
18
|
+
export declare function twinsWithoutChecks(): string[];
|
|
4
19
|
export declare function checksFor(twin: string): readonly DeclaredCheck[];
|
|
5
20
|
export declare function findCheck(id: string): DeclaredCheck | undefined;
|
|
6
21
|
export declare function twinOf(id: string): string | undefined;
|
package/dist/src/cli/checks.js
CHANGED
|
@@ -11,20 +11,57 @@
|
|
|
11
11
|
import { readFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { checksDigest, templateSlots } from "@pome-sh/sdk/checks";
|
|
14
|
+
import { MOUNTED_TWINS } from "@pome-sh/shared-types";
|
|
14
15
|
import { GITHUB_CHECKS } from "@pome-sh/twin-github/checks";
|
|
16
|
+
import { GMAIL_CHECKS } from "@pome-sh/twin-gmail/checks";
|
|
17
|
+
import { LINEAR_CHECKS } from "@pome-sh/twin-linear/checks";
|
|
15
18
|
import { SLACK_CHECKS } from "@pome-sh/twin-slack/checks";
|
|
19
|
+
import { STRIPE_CHECKS } from "@pome-sh/twin-stripe/checks";
|
|
16
20
|
import { resolvePackageRoot } from "./resolve-package-root.js";
|
|
17
21
|
const REGISTRIES = {
|
|
18
22
|
github: GITHUB_CHECKS,
|
|
19
23
|
slack: SLACK_CHECKS,
|
|
24
|
+
stripe: STRIPE_CHECKS,
|
|
25
|
+
gmail: GMAIL_CHECKS,
|
|
26
|
+
linear: LINEAR_CHECKS,
|
|
20
27
|
};
|
|
21
|
-
// Twins that EXIST but declare nothing yet
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
28
|
+
// Twins that EXIST but declare nothing yet — DERIVED, not listed.
|
|
29
|
+
//
|
|
30
|
+
// The distinction is still real: `pome checks <twin>` must answer "not migrated
|
|
31
|
+
// yet" for a twin that exists, and "no such twin" for a typo. What is no longer
|
|
32
|
+
// real is the hand-maintained literal. F-1126 removed slack from it, F-1127
|
|
33
|
+
// stripe, F-1128 gmail, and F-1129 would have emptied it — four tickets each
|
|
34
|
+
// editing one line of a list that `MOUNTED_TWINS` already knows.
|
|
35
|
+
//
|
|
36
|
+
// So it is a set difference instead. Today it is EMPTY, which is A3's whole
|
|
37
|
+
// acceptance criterion. The day a sixth twin mounts, it repopulates itself and
|
|
38
|
+
// the "not migrated yet" path comes back live without anyone remembering to add
|
|
39
|
+
// a literal — which is the failure this project is named for, one level down.
|
|
40
|
+
// Annotated `string[]` on purpose: `MOUNTED_TWINS` is a literal-union tuple, so
|
|
41
|
+
// the filtered result keeps that union and `isKnownTwin` cannot ask it about an
|
|
42
|
+
// arbitrary string. Widening here is what keeps the caller's question — "is this
|
|
43
|
+
// user-typed word a twin?" — expressible.
|
|
44
|
+
const TWINS_WITHOUT_CHECKS = MOUNTED_TWINS.filter((twin) => !(twin in REGISTRIES));
|
|
25
45
|
export function twinsWithChecks() {
|
|
26
46
|
return Object.keys(REGISTRIES).sort();
|
|
27
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Twins that exist but declare nothing yet.
|
|
50
|
+
*
|
|
51
|
+
* Exported because the no-vocabulary PATH is a real behaviour with its own
|
|
52
|
+
* tests, and those tests need a twin on this list to exercise it. Naming one
|
|
53
|
+
* inline is what broke five of them when stripe left the list (F-1127) — a
|
|
54
|
+
* literal there asserts the MEMBERSHIP of the set, where the test means to
|
|
55
|
+
* assert the behaviour, which is the same defect F-1075 hit with a hard-coded
|
|
56
|
+
* picker index.
|
|
57
|
+
*
|
|
58
|
+
* A3 empties this list, and F-1129 answered the question that raised: the PATH
|
|
59
|
+
* stays, the LITERAL goes. It is now `MOUNTED_TWINS` minus the registry, so an
|
|
60
|
+
* empty result is a fact about the world rather than a list nobody updated.
|
|
61
|
+
*/
|
|
62
|
+
export function twinsWithoutChecks() {
|
|
63
|
+
return [...TWINS_WITHOUT_CHECKS];
|
|
64
|
+
}
|
|
28
65
|
export function checksFor(twin) {
|
|
29
66
|
return REGISTRIES[twin] ?? [];
|
|
30
67
|
}
|
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @pome-sh/twin-gmail — CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-07-30
|
|
4
|
+
|
|
5
|
+
Gmail declares its assertable check vocabulary (F-1128, milestone A3).
|
|
6
|
+
|
|
7
|
+
- New `./checks` subpath: `GMAIL_CHECKS`, seven declarations, plus the
|
|
8
|
+
`GmailCheckState` model they read (`check-state.ts`). pome-cloud deletes its
|
|
9
|
+
hand-maintained mirror of that shape in the same milestone — the twin's model
|
|
10
|
+
is now the only one.
|
|
11
|
+
- Four declarations are new and bind the six criteria A3 found unbound across
|
|
12
|
+
tasks 22, 23 and 27: `gmail.message-has-label` (which clears three of them,
|
|
13
|
+
because two tasks say the same sentence), `gmail.label-exists`,
|
|
14
|
+
`gmail.draft-addressed-to` and `gmail.draft-count-at-least`.
|
|
15
|
+
- Three are carried across from pome-cloud's hand-written regexes:
|
|
16
|
+
`gmail.mailbox-label-count`, `gmail.one-message-per-recipient` and
|
|
17
|
+
`gmail.no-unsupported-endpoint`. The last drops the twin word — it is now the
|
|
18
|
+
same sentence twin-github declares, resolved per-twin by the engine — so
|
|
19
|
+
`examples/gmail-retry-notify` is rewritten to the rendered templates in the
|
|
20
|
+
same commit.
|
|
21
|
+
- `gmail.draft-addressed-to` declares its recipient as the check's `subject`.
|
|
22
|
+
pome-cloud has carried a prediction since F-1028 that this exact criterion
|
|
23
|
+
becomes an unguarded redaction hazard the day a gmail draft-recipient
|
|
24
|
+
predicate ships without one.
|
|
25
|
+
- Two shapes drove the state model and are pinned by tests rather than left as
|
|
26
|
+
comments: an exported draft row carries no addressing at all (the recipient
|
|
27
|
+
lives on the backing message, reached through `messageId`), and message
|
|
28
|
+
bodies are digested away unconditionally — so no check on this twin can scan
|
|
29
|
+
message prose.
|
|
30
|
+
- Ambiguity is closed in the reader rather than the grammar: a message id
|
|
31
|
+
present in more than one mailbox returns `message_ambiguous` instead of
|
|
32
|
+
grading whichever sorted first. Gmail mints ids per mailbox, and the corpus
|
|
33
|
+
sentences carry no mailbox.
|
|
34
|
+
- New `test/fidelity-contract.test.ts` adds the state-shape parity arm gmail
|
|
35
|
+
never had. The existing parity harness's rings are all about the tool surface;
|
|
36
|
+
nothing had ever compared `exportGmailState()` against the shape a consumer
|
|
37
|
+
reads.
|
|
38
|
+
- `vitest.config.ts` replaces the `test` script's hand-maintained file list.
|
|
39
|
+
`faults.test.ts` had already fallen off it — a suite that exists, passes, and
|
|
40
|
+
never ran.
|
|
41
|
+
|
|
3
42
|
|
|
4
43
|
## 0.2.1 — 2026-07-30
|
|
5
44
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What Gmail's declared checks can assert about DRAFTS (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// The shape that makes this its own module: an exported draft row is
|
|
6
|
+
// `{mailboxEmail, id, messageId, createdAt, updatedAt}` and carries NO
|
|
7
|
+
// addressing. Who a draft is for lives on the backing message, reachable only
|
|
8
|
+
// through `messageId`. A predicate that read the draft row alone would answer
|
|
9
|
+
// "no draft is addressed to anyone", always — a negative that can never fail,
|
|
10
|
+
// which is the exact defect A3 exists to eliminate.
|
|
11
|
+
import { defineCheck, VACUITY_SENTINEL, VACUITY_SENTINEL_NUMBER } from "@pome-sh/sdk/checks";
|
|
12
|
+
import { countWord, emailAddress, parseCount } from "./check-params.js";
|
|
13
|
+
import { draftRecipients, isTruncated } from "./check-state.js";
|
|
14
|
+
import { draftAddressedTo as draftFor, finalWorld, gmailState } from "./check-worlds.js";
|
|
15
|
+
export const draftAddressedTo = defineCheck({
|
|
16
|
+
id: "gmail.draft-addressed-to",
|
|
17
|
+
description: "Joins every draft to its backing message and asks whether any of them addresses this " +
|
|
18
|
+
"recipient in `to` or `cc`, compared case-insensitively as an EXACT address rather than a " +
|
|
19
|
+
"substring. It asserts nothing about the draft's body — message bodies are digested out of " +
|
|
20
|
+
"the state export unconditionally, so no check on this twin can read one — and nothing about " +
|
|
21
|
+
"whether the draft was left unsent, which is a separate claim. A draft whose backing message " +
|
|
22
|
+
"did not survive the export contributes no recipients rather than throwing.",
|
|
23
|
+
template: "A draft addressed to {email} exists",
|
|
24
|
+
params: { email: emailAddress },
|
|
25
|
+
substrate: "final",
|
|
26
|
+
// An achievement: task 22's seed ships one draft addressed to bob, so an
|
|
27
|
+
// examinee that does nothing does not satisfy this.
|
|
28
|
+
polarity: () => "positive",
|
|
29
|
+
//
|
|
30
|
+
// THE LOAD-BEARING DECLARATION ON THIS CHECK.
|
|
31
|
+
//
|
|
32
|
+
// pome-cloud's `corpus.ts` has carried a prediction about this exact criterion
|
|
33
|
+
// since F-1028: `22-gmail-inbox-triage`'s `alice@example.com` "becomes visible
|
|
34
|
+
// here as 'unguarded' the day a gmail draft-recipient predicate lands without a
|
|
35
|
+
// `subject`, which is precisely when it starts to matter." An email address is
|
|
36
|
+
// squarely inside what a team's redaction config may destroy. Without this
|
|
37
|
+
// field the evaluator has no way to turn an impossible comparison into an
|
|
38
|
+
// honest skip, so the criterion scores a vacuous verdict at both doors
|
|
39
|
+
// instead — and the count of unguarded hazards must stay at zero.
|
|
40
|
+
subject: ({ email }) => email,
|
|
41
|
+
// The address is the scanned literal, so the mutant points at it. It stays
|
|
42
|
+
// email-shaped so it re-binds to this same check: a mutant that stops matching
|
|
43
|
+
// evaluates to `unmatched`, which reads as "the verdict moved -> healthy" and
|
|
44
|
+
// hands the criterion a clean bill it did not earn.
|
|
45
|
+
vacuityMutant: (args) => ({ ...args, email: `${VACUITY_SENTINEL}@example.invalid` }),
|
|
46
|
+
discriminatingWorlds: ({ email }) => {
|
|
47
|
+
const wanted = draftFor("draft_target", [email]);
|
|
48
|
+
const other = draftFor("draft_other", ["someone-else@example.com"]);
|
|
49
|
+
// Both worlds carry a draft, so the failing world fails on the ASSERTION
|
|
50
|
+
// rather than on an empty collection — the degenerate arm the probe rejects.
|
|
51
|
+
return {
|
|
52
|
+
passing: finalWorld(gmailState({ drafts: [wanted.draft], messages: [wanted.message] })),
|
|
53
|
+
failing: finalWorld(gmailState({ drafts: [other.draft], messages: [other.message] })),
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
evaluate({ email }, { final }) {
|
|
57
|
+
if (final.drafts == null || final.messages == null) {
|
|
58
|
+
return { passed: false, status: "skipped", reason: "state_incomplete" };
|
|
59
|
+
}
|
|
60
|
+
const wanted = email.toLowerCase();
|
|
61
|
+
const hit = final.drafts.find((entry) => draftRecipients(final, entry).some((to) => to.toLowerCase() === wanted));
|
|
62
|
+
if (hit) {
|
|
63
|
+
return { passed: true, reason: `draft ${hit.id ?? "?"} is addressed to ${email}` };
|
|
64
|
+
}
|
|
65
|
+
// Only refuse once the answer would otherwise be "no". A capped collection
|
|
66
|
+
// that still contains the draft is a real pass, and skipping it would drop a
|
|
67
|
+
// criterion the export could actually answer.
|
|
68
|
+
if (isTruncated(final, "drafts") || isTruncated(final, "messages")) {
|
|
69
|
+
return { passed: false, status: "skipped", reason: "collection_truncated" };
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
passed: false,
|
|
73
|
+
reason: `no draft is addressed to ${email} (${final.drafts.length} draft(s) inspected)`,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
export const draftCountAtLeast = defineCheck({
|
|
78
|
+
id: "gmail.draft-count-at-least",
|
|
79
|
+
description: "Counts the rows in the exported `drafts` collection and asserts there are AT LEAST this " +
|
|
80
|
+
"many — a lower bound, so a mailbox with more drafts than asked still passes. It counts " +
|
|
81
|
+
"drafts the SEED placed there as well as any the examinee created, which means a criterion " +
|
|
82
|
+
"whose number the seed already satisfies can be passed by an agent that does nothing. That " +
|
|
83
|
+
"is a property of the task, not of this check, and `measure-criterion-discrimination` is " +
|
|
84
|
+
"where it surfaces.",
|
|
85
|
+
template: "At least {count} drafts exist",
|
|
86
|
+
params: { count: countWord },
|
|
87
|
+
substrate: "final",
|
|
88
|
+
polarity: () => "positive",
|
|
89
|
+
// A threshold, not a literal hunted for inside state — there is nothing here a
|
|
90
|
+
// redactor could silently delete.
|
|
91
|
+
subject: () => null,
|
|
92
|
+
//
|
|
93
|
+
// The NUMERIC sentinel, and the argument D10 demands before it may be used.
|
|
94
|
+
//
|
|
95
|
+
// In every other pattern a numeric capture is a SELECTOR — an issue number, a
|
|
96
|
+
// PR number — that the predicate RESOLVES before it scans anything, so
|
|
97
|
+
// falsifying it early-returns "not found" and moves the verdict for a reason
|
|
98
|
+
// that never reaches the assertion. Here the count is the ONLY slot and there
|
|
99
|
+
// is nothing to resolve: it is compared directly against a cardinality the
|
|
100
|
+
// predicate computes, so falsifying it moves the verdict THROUGH the
|
|
101
|
+
// assertion. That is the same argument `stripe.payment-intent-amount` makes,
|
|
102
|
+
// and it is why this check is the second entry in pome-cloud's
|
|
103
|
+
// `NUMERIC_SENTINEL_ALLOWED`.
|
|
104
|
+
vacuityMutant: (args) => ({ ...args, count: String(VACUITY_SENTINEL_NUMBER) }),
|
|
105
|
+
discriminatingWorlds: ({ count }) => {
|
|
106
|
+
const wanted = parseCount(count) ?? 1;
|
|
107
|
+
const build = (n) => {
|
|
108
|
+
const pairs = Array.from({ length: n }, (_, i) => draftFor(`draft_${i}`, ["a@example.com"]));
|
|
109
|
+
return gmailState({
|
|
110
|
+
drafts: pairs.map((p) => p.draft),
|
|
111
|
+
messages: pairs.map((p) => p.message),
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
// The failing world is one SHORT, not empty: `wanted - 1` keeps the drafts
|
|
115
|
+
// collection non-null so the failure is the count, not the absence.
|
|
116
|
+
return { passing: finalWorld(build(wanted)), failing: finalWorld(build(Math.max(0, wanted - 1))) };
|
|
117
|
+
},
|
|
118
|
+
evaluate({ count }, { final }) {
|
|
119
|
+
const wanted = parseCount(count);
|
|
120
|
+
if (wanted === null) {
|
|
121
|
+
// Unreachable through the generated pattern, which only admits digits and
|
|
122
|
+
// the number words `parseCount` knows. Named rather than assumed, so a
|
|
123
|
+
// widened slot type surfaces here instead of as a silent `NaN` comparison.
|
|
124
|
+
return { passed: false, status: "skipped", reason: `uncountable ("${count}")` };
|
|
125
|
+
}
|
|
126
|
+
if (final.drafts == null)
|
|
127
|
+
return { passed: false, status: "skipped", reason: "state_incomplete" };
|
|
128
|
+
const total = final.drafts.length;
|
|
129
|
+
if (total < wanted && isTruncated(final, "drafts")) {
|
|
130
|
+
return { passed: false, status: "skipped", reason: 'collection_truncated ("drafts")' };
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
passed: total >= wanted,
|
|
134
|
+
reason: `${total} draft(s) exist (wanted at least ${wanted})`,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=check-drafts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-drafts.js","sourceRoot":"","sources":["../../src/check-drafts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// The one type every Gmail check declaration is written against, mirroring
|
|
4
|
+
// twin-github's and twin-slack's `check-kind.ts`. It exists so the declaration
|
|
5
|
+
// files can be split by what they assert about without each re-deriving the
|
|
6
|
+
// binding to the state tree — and so a declaration that forgets to name
|
|
7
|
+
// `GmailCheckState` cannot compile.
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=check-kind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-kind.js","sourceRoot":"","sources":["../../src/check-kind.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,oCAAoC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What Gmail's declared checks can assert about LABEL DEFINITIONS (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// Separate from `check-messages.ts` because it asks a different question of a
|
|
6
|
+
// different collection: whether a label EXISTS in the mailbox at all, not
|
|
7
|
+
// whether a message carries one. Gmail's own API splits them the same way —
|
|
8
|
+
// `create_label` is mailbox-scoped, `label_message` is message-scoped — and
|
|
9
|
+
// `github.no-new-labels` records what happens when one sentence blurs the two.
|
|
10
|
+
import { defineCheck, VACUITY_SENTINEL } from "@pome-sh/sdk/checks";
|
|
11
|
+
import { labelName } from "./check-params.js";
|
|
12
|
+
import { resolveLabelByName } from "./check-state.js";
|
|
13
|
+
import { finalWorld, gmailState, systemLabel, userLabel } from "./check-worlds.js";
|
|
14
|
+
export const labelExists = defineCheck({
|
|
15
|
+
id: "gmail.label-exists",
|
|
16
|
+
description: "Asks whether the mailbox defines a label with this DISPLAY NAME, compared case-insensitively " +
|
|
17
|
+
"the way the twin's own seeder keys its uniqueness lookup. It reads the `labels` collection " +
|
|
18
|
+
"only — a label that exists but has been applied to nothing still passes, and a message " +
|
|
19
|
+
"carrying a label is `gmail.message-has-label`'s question, not this one. It deliberately does " +
|
|
20
|
+
"NOT match on the minted id: `Label_follow_up` is an id and `Follow Up` is the name of that " +
|
|
21
|
+
"same label, and letting one sentence mean both would make the assertion unreadable.",
|
|
22
|
+
// The name slot admits spaces, which is what the corpus needs (`Parity
|
|
23
|
+
// Complete`) and what separates this template from `gmail.message-has-label`'s
|
|
24
|
+
// id slot. The two cannot claim one sentence: this one says "A label named",
|
|
25
|
+
// that one says "Message ... has label".
|
|
26
|
+
template: "A label named {label} exists",
|
|
27
|
+
params: { label: labelName },
|
|
28
|
+
substrate: "final",
|
|
29
|
+
// An achievement — task 23's seed defines no `Parity Complete`, so the
|
|
30
|
+
// examinee has to create it.
|
|
31
|
+
polarity: () => "positive",
|
|
32
|
+
// The name is a caller-supplied literal compared against state.
|
|
33
|
+
subject: ({ label }) => label,
|
|
34
|
+
vacuityMutant: (args) => ({ ...args, label: VACUITY_SENTINEL }),
|
|
35
|
+
discriminatingWorlds: ({ label }) => ({
|
|
36
|
+
// Both worlds carry a non-empty `labels` collection, so the failing world
|
|
37
|
+
// fails on the ASSERTION (`label_not_found`) rather than reproducing the
|
|
38
|
+
// `state_incomplete` an empty world gives — the degenerate arm the probe
|
|
39
|
+
// rejects.
|
|
40
|
+
passing: finalWorld(gmailState({ labels: [systemLabel("INBOX"), userLabel("Label_1", label)] })),
|
|
41
|
+
failing: finalWorld(gmailState({ labels: [systemLabel("INBOX")] })),
|
|
42
|
+
}),
|
|
43
|
+
evaluate({ label }, { final }) {
|
|
44
|
+
const found = resolveLabelByName(final, label);
|
|
45
|
+
if ("missing" in found) {
|
|
46
|
+
// `state_incomplete` and `collection_truncated` are unanswerable; a label
|
|
47
|
+
// genuinely not there is the honest FAIL this check exists to deliver.
|
|
48
|
+
if (found.missing.startsWith("label_not_found")) {
|
|
49
|
+
return { passed: false, reason: `no label named "${label}" exists` };
|
|
50
|
+
}
|
|
51
|
+
return { passed: false, status: "skipped", reason: found.missing };
|
|
52
|
+
}
|
|
53
|
+
return { passed: true, reason: `label "${label}" exists (id ${found.found.id ?? "?"})` };
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=check-labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-labels.js","sourceRoot":"","sources":["../../src/check-labels.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,4EAA4E;AAC5E,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,4EAA4E;AAC5E,4EAA4E;AAC5E,+EAA+E;AAE/E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnF,MAAM,CAAC,MAAM,WAAW,GAA6B,WAAW,CAAC;IAC/D,EAAE,EAAE,oBAAoB;IACxB,WAAW,EACT,+FAA+F;QAC/F,6FAA6F;QAC7F,yFAAyF;QACzF,+FAA+F;QAC/F,6FAA6F;QAC7F,qFAAqF;IACvF,uEAAuE;IACvE,+EAA+E;IAC/E,6EAA6E;IAC7E,yCAAyC;IACzC,QAAQ,EAAE,8BAA8B;IACxC,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;IAC5B,SAAS,EAAE,OAAO;IAClB,uEAAuE;IACvE,6BAA6B;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU;IAC1B,gEAAgE;IAChE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK;IAC7B,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC/D,oBAAoB,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACpC,0EAA0E;QAC1E,yEAAyE;QACzE,yEAAyE;QACzE,WAAW;QACX,OAAO,EAAE,UAAU,CACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAC5E;QACD,OAAO,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;KACpE,CAAC;IACF,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE;QAC3B,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;YACvB,0EAA0E;YAC1E,uEAAuE;YACvE,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,KAAK,UAAU,EAAE,CAAC;YACvE,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QACrE,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,KAAK,gBAAgB,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,GAAG,EAAE,CAAC;IAC3F,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Check } from "./check-kind.js";
|
|
2
|
+
export declare const messageHasLabel: Check<{
|
|
3
|
+
message: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const mailboxLabelCount: Check<{
|
|
7
|
+
mailbox: string;
|
|
8
|
+
count: string;
|
|
9
|
+
label: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const oneMessagePerRecipient: Check<{
|
|
12
|
+
label: string;
|
|
13
|
+
count: string;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
//
|
|
3
|
+
// What Gmail's declared checks can assert about MESSAGES (F-1128).
|
|
4
|
+
//
|
|
5
|
+
// All three read the exported end state. Note what is NOT here and cannot be:
|
|
6
|
+
// message bodies are digested out of `/_pome/state` unconditionally
|
|
7
|
+
// (`state.ts boundMessageExport`), so there is no gmail analogue of
|
|
8
|
+
// `slack.no-message-containing` — a substring scan over message prose has no
|
|
9
|
+
// substrate to read. `subject` is the only message prose that survives, and
|
|
10
|
+
// nothing in the corpus asserts on it yet.
|
|
11
|
+
//
|
|
12
|
+
// Declarations only. The grammar rules they obey are in `checks.ts`, which
|
|
13
|
+
// assembles them.
|
|
14
|
+
import { defineCheck, VACUITY_SENTINEL } from "@pome-sh/sdk/checks";
|
|
15
|
+
import { countWord, exactCount, labelRef, mailboxRef, messageId, parseCount } from "./check-params.js";
|
|
16
|
+
import { isTruncated, labelIdsFor, messageCarriesLabel, resolveMessage, } from "./check-state.js";
|
|
17
|
+
import { finalWorld, gmailState, message, messageLabel, systemLabel, userLabel, } from "./check-worlds.js";
|
|
18
|
+
// The workhorse of gmail's corpus: it binds three of the six criteria A3 found
|
|
19
|
+
// unbound, because tasks 22 and 27 say the same sentence about `msg_support` and
|
|
20
|
+
// task 23 says it about `msg_parity`. One check, three criteria — the same way
|
|
21
|
+
// `github.no-new-labels` cleared five.
|
|
22
|
+
export const messageHasLabel = defineCheck({
|
|
23
|
+
id: "gmail.message-has-label",
|
|
24
|
+
description: "Looks the message up by id, then asks the `messageLabels` JOIN whether any row links it to " +
|
|
25
|
+
"the named label. The label may be given as its minted id (`Label_follow_up`) or as the " +
|
|
26
|
+
"display name of the same label (`Follow Up`); a system label carries both as one string " +
|
|
27
|
+
"(`INBOX`, `STARRED`). It asserts nothing about the message's OTHER labels — a message " +
|
|
28
|
+
"carrying the named label plus five more passes. A message the export does not carry is a " +
|
|
29
|
+
"SKIP, not a fail, and so is a label collection the export truncated: absent from a capped " +
|
|
30
|
+
"list is not absent.",
|
|
31
|
+
template: "Message {message} has label {label}",
|
|
32
|
+
params: { message: messageId, label: labelRef },
|
|
33
|
+
substrate: "final",
|
|
34
|
+
// An achievement. The seed leaves `msg_support` on INBOX/UNREAD only, so the
|
|
35
|
+
// examinee has to act for this to hold.
|
|
36
|
+
polarity: () => "positive",
|
|
37
|
+
// The label is a caller-supplied literal compared against state, so it is
|
|
38
|
+
// declared. No first-party redactor pattern touches a Gmail label id, which is
|
|
39
|
+
// exactly why declaring it keeps that a verified fact rather than an
|
|
40
|
+
// assumption — a team's own redaction config is not first-party.
|
|
41
|
+
subject: ({ label }) => label,
|
|
42
|
+
// The message id only SELECTS; falsifying it moves the verdict through the
|
|
43
|
+
// lookup rather than the assertion. The label is the scanned literal.
|
|
44
|
+
vacuityMutant: (args) => ({ ...args, label: VACUITY_SENTINEL }),
|
|
45
|
+
discriminatingWorlds: ({ message: id, label }) => {
|
|
46
|
+
// The message is PRESENT in both worlds and only the JOIN row moves. A world
|
|
47
|
+
// without the message would fail through the selector, reproducing the reason
|
|
48
|
+
// an empty world already gives — which the probe rejects as degenerate.
|
|
49
|
+
const labels = [systemLabel("INBOX"), userLabel(label, label)];
|
|
50
|
+
const base = { messages: [message(id)], labels };
|
|
51
|
+
return {
|
|
52
|
+
passing: finalWorld(gmailState({ ...base, messageLabels: [messageLabel(id, "INBOX"), messageLabel(id, label)] })),
|
|
53
|
+
failing: finalWorld(gmailState({ ...base, messageLabels: [messageLabel(id, "INBOX")] })),
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
evaluate({ message: id, label }, { final }) {
|
|
57
|
+
const found = resolveMessage(final, id);
|
|
58
|
+
if ("missing" in found)
|
|
59
|
+
return { passed: false, status: "skipped", reason: found.missing };
|
|
60
|
+
const carried = messageCarriesLabel(final, id, label);
|
|
61
|
+
if ("missing" in carried)
|
|
62
|
+
return { passed: false, status: "skipped", reason: carried.missing };
|
|
63
|
+
return {
|
|
64
|
+
passed: carried.found,
|
|
65
|
+
reason: carried.found
|
|
66
|
+
? `message ${id} carries label ${label}`
|
|
67
|
+
: `message ${id} does not carry label ${label}`,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
// Carried across from pome-cloud's `gmail.mailbox-label-count` regex, which
|
|
72
|
+
// graded the retry/partial-failure curriculum class. The legacy pattern was
|
|
73
|
+
// case-insensitive and tolerated `labelled`, a trailing period and three quote
|
|
74
|
+
// styles; under position 2 an author PICKS the check rather than typing it, so
|
|
75
|
+
// those variants are retired rather than ported — exactly as F-1075 retired
|
|
76
|
+
// `issue-has-label-generic`.
|
|
77
|
+
export const mailboxLabelCount = defineCheck({
|
|
78
|
+
id: "gmail.mailbox-label-count",
|
|
79
|
+
description: "Counts the messages in the named mailbox that the `messageLabels` JOIN links to the named " +
|
|
80
|
+
"label, and asserts the total is EXACTLY the number given. Not 'at least' — a mailbox with " +
|
|
81
|
+
"six SENT messages fails a criterion asking for five, which is what makes it able to catch " +
|
|
82
|
+
"a duplicate send. A mailbox the export lists but does not contain is a SKIP; so is a " +
|
|
83
|
+
"truncated collection.",
|
|
84
|
+
template: "The mailbox `{mailbox}` has exactly {count} messages labeled {label}",
|
|
85
|
+
params: { mailbox: mailboxRef, count: exactCount, label: labelRef },
|
|
86
|
+
substrate: "final",
|
|
87
|
+
// The count carries the direction: asserting zero is a prohibition, any
|
|
88
|
+
// other count is work the examinee must do. Preserved from the legacy rule,
|
|
89
|
+
// which computed the same thing per match.
|
|
90
|
+
polarity: ({ count }) => (Number(count) === 0 ? "negative" : "positive"),
|
|
91
|
+
subject: ({ label }) => label,
|
|
92
|
+
// The mailbox resolves and the count is compared to a derived total; the
|
|
93
|
+
// label is the literal actually scanned in state. Pointing the mutant at the
|
|
94
|
+
// count would falsify a threshold rather than a lookup — see
|
|
95
|
+
// `gmail.draft-count-at-least`, where the count IS the only slot.
|
|
96
|
+
vacuityMutant: (args) => ({ ...args, label: VACUITY_SENTINEL }),
|
|
97
|
+
discriminatingWorlds: ({ mailbox, count, label }) => {
|
|
98
|
+
const wanted = Number(count);
|
|
99
|
+
const world = (n) => {
|
|
100
|
+
const messages = Array.from({ length: n }, (_, i) => message(`msg_${i}`, { mailboxEmail: mailbox }));
|
|
101
|
+
return gmailState({
|
|
102
|
+
mailboxes: [{ email: mailbox }],
|
|
103
|
+
messages,
|
|
104
|
+
labels: [systemLabel(label)],
|
|
105
|
+
messageLabels: messages.map((m) => ({ mailboxEmail: mailbox, messageId: m.id, labelId: label })),
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
// The mailbox resolves in BOTH worlds and only the count moves. `wanted + 1`
|
|
109
|
+
// rather than zero so the failing world is never also the empty one.
|
|
110
|
+
return { passing: finalWorld(world(wanted)), failing: finalWorld(world(wanted + 1)) };
|
|
111
|
+
},
|
|
112
|
+
evaluate({ mailbox, count, label }, { final }) {
|
|
113
|
+
const wanted = Number(count);
|
|
114
|
+
if (final.messages == null || final.messageLabels == null) {
|
|
115
|
+
return { passed: false, status: "skipped", reason: "state_incomplete" };
|
|
116
|
+
}
|
|
117
|
+
if (isTruncated(final, "messages") || isTruncated(final, "messageLabels")) {
|
|
118
|
+
return { passed: false, status: "skipped", reason: "collection_truncated" };
|
|
119
|
+
}
|
|
120
|
+
// A mailboxes collection that is present and omits this mailbox means we
|
|
121
|
+
// cannot attest anything about it. An ABSENT collection is a different
|
|
122
|
+
// fact — proceed by email, the way the export's own rows are keyed.
|
|
123
|
+
if (final.mailboxes != null &&
|
|
124
|
+
!final.mailboxes.some((mb) => (mb.email ?? "").toLowerCase() === mailbox.toLowerCase())) {
|
|
125
|
+
return { passed: false, status: "skipped", reason: `mailbox_not_found ("${mailbox}")` };
|
|
126
|
+
}
|
|
127
|
+
const ids = labelIdsFor(final, label);
|
|
128
|
+
const labeled = new Set(final.messageLabels
|
|
129
|
+
.filter((row) => ids.has((row.labelId ?? "").toLowerCase()))
|
|
130
|
+
.map((row) => (row.messageId ?? "").toLowerCase()));
|
|
131
|
+
const total = final.messages.filter((msg) => (msg.mailboxEmail ?? "").toLowerCase() === mailbox.toLowerCase() &&
|
|
132
|
+
msg.id != null &&
|
|
133
|
+
labeled.has(msg.id.toLowerCase())).length;
|
|
134
|
+
return {
|
|
135
|
+
passed: total === wanted,
|
|
136
|
+
reason: `mailbox "${mailbox}" has ${total} message(s) labeled ${label} (wanted ${wanted})`,
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
// Also carried across from pome-cloud. This is the one that catches a duplicate
|
|
141
|
+
// send, which is the whole point of the retry curriculum class: a naive retry
|
|
142
|
+
// loop sends twice to the same address and this is what notices.
|
|
143
|
+
export const oneMessagePerRecipient = defineCheck({
|
|
144
|
+
id: "gmail.one-message-per-recipient",
|
|
145
|
+
description: "Flattens every addressee across the messages carrying the named label and asserts each " +
|
|
146
|
+
"address appears EXACTLY ONCE — and, when a count is named, that there are that many " +
|
|
147
|
+
"messages, that many distinct recipients, and no more addressee slots than that. It is the " +
|
|
148
|
+
"assertion that separates 'sent to everyone' from 'sent to everyone, some of them twice', " +
|
|
149
|
+
"which an exact total alone cannot do.",
|
|
150
|
+
template: "Exactly one {label} message is addressed to each of the {count} recipients",
|
|
151
|
+
params: { label: labelRef, count: countWord },
|
|
152
|
+
substrate: "final",
|
|
153
|
+
polarity: () => "positive",
|
|
154
|
+
subject: ({ label }) => label,
|
|
155
|
+
// The label is scanned; the count is a declared arity compared to a derived
|
|
156
|
+
// one. Same argument as `mailboxLabelCount`.
|
|
157
|
+
vacuityMutant: (args) => ({ ...args, label: VACUITY_SENTINEL }),
|
|
158
|
+
discriminatingWorlds: ({ label, count }) => {
|
|
159
|
+
const wanted = parseCount(count) ?? 1;
|
|
160
|
+
const recipients = Array.from({ length: wanted }, (_, i) => `user${i}@example.com`);
|
|
161
|
+
const build = (addressees) => {
|
|
162
|
+
const messages = addressees.map((to, i) => message(`msg_${i}`, { to }));
|
|
163
|
+
return finalWorld(gmailState({
|
|
164
|
+
messages,
|
|
165
|
+
labels: [systemLabel(label)],
|
|
166
|
+
messageLabels: messages.map((m) => messageLabel(m.id, label)),
|
|
167
|
+
}));
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
passing: build(recipients.map((r) => [r])),
|
|
171
|
+
// The DUPLICATE SEND, not a missing one: the same number of messages, one
|
|
172
|
+
// recipient served twice and another not at all. A world with fewer
|
|
173
|
+
// messages would fail on arity, which the exact-count check already covers.
|
|
174
|
+
failing: build([[recipients[0]], ...recipients.slice(2).map((r) => [r]), [recipients[0]]]),
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
evaluate({ label, count }, { final }) {
|
|
178
|
+
const wanted = parseCount(count);
|
|
179
|
+
if (final.messages == null || final.messageLabels == null) {
|
|
180
|
+
return { passed: false, status: "skipped", reason: "state_incomplete" };
|
|
181
|
+
}
|
|
182
|
+
if (isTruncated(final, "messages") || isTruncated(final, "messageLabels")) {
|
|
183
|
+
return { passed: false, status: "skipped", reason: "collection_truncated" };
|
|
184
|
+
}
|
|
185
|
+
const ids = labelIdsFor(final, label);
|
|
186
|
+
const labeled = new Set(final.messageLabels
|
|
187
|
+
.filter((row) => ids.has((row.labelId ?? "").toLowerCase()))
|
|
188
|
+
.map((row) => (row.messageId ?? "").toLowerCase()));
|
|
189
|
+
const sent = final.messages.filter((msg) => msg.id != null && labeled.has(msg.id.toLowerCase()));
|
|
190
|
+
const addressees = sent.flatMap((msg) => (msg.to ?? []).map((to) => to.toLowerCase()));
|
|
191
|
+
const distinct = new Set(addressees);
|
|
192
|
+
const noDuplicates = addressees.length === distinct.size;
|
|
193
|
+
const arityOk = wanted == null
|
|
194
|
+
? sent.length === distinct.size
|
|
195
|
+
: sent.length === wanted && distinct.size === wanted && addressees.length === wanted;
|
|
196
|
+
const passed = noDuplicates && arityOk;
|
|
197
|
+
return {
|
|
198
|
+
passed,
|
|
199
|
+
reason: passed
|
|
200
|
+
? `${sent.length} ${label} message(s), one per distinct recipient, no duplicates`
|
|
201
|
+
: `${sent.length} ${label} message(s) to ${distinct.size} distinct recipient(s) ` +
|
|
202
|
+
`(${addressees.length} addressee slot(s)${wanted == null ? "" : `, wanted ${wanted}`}` +
|
|
203
|
+
`${noDuplicates ? "" : ", duplicate send detected"})`,
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
//# sourceMappingURL=check-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-messages.js","sourceRoot":"","sources":["../../src/check-messages.ts"],"names":[],"mappings":"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"}
|