@pome-sh/checks 0.1.6 → 0.1.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,68 @@
1
1
  # @pome-sh/checks
2
2
 
3
+ ## 0.1.7
4
+
5
+ A section a check's verdict reads is now measured HERE, where the worlds are
6
+ authored, instead of being left to an instrument that cannot see it (F-1437).
7
+
8
+ pome-cloud's `findVacuousStateSectionReaders` derives its candidate sections
9
+ from what DIFFERS between a check's two discriminating worlds. That rule is what
10
+ stops it reporting every section a world carries for realism, and it is also a
11
+ blind spot it has documented rather than folded into its zero: a section
12
+ IDENTICAL in both worlds is never a candidate, so it is never deleted, so a
13
+ verdict that reads it vacuously is invisible there. No widening fixes that — with
14
+ both worlds carrying the same value there is no failing value to swap in, hence
15
+ no proof the verdict reads the section at all.
16
+
17
+ `test/section-read-sweep.test.ts` reaches it from the other side. It hands
18
+ `evaluate` a recording view of the state tree, so every top-level section the
19
+ predicate ASKS FOR is on the record whether or not the worlds disagree about it;
20
+ then, for exactly the sections the worlds agree on, it runs the detector's own
21
+ step 3 — delete from the passing world, re-evaluate — and a verdict that stays a
22
+ bare `passed` is named. Both trees, `seed` as well as `final`, because the
23
+ detector probes `final` only. Over the shipped vocabulary: 38 state
24
+ declarations and 34 agreed-on section reads (28 on `final`, 6 on `seed`), of
25
+ which 26 are discharged by measurement — 22 return `state_incomplete` and 4 fail
26
+ honestly — and 8 are declared exceptions where the twin reads an absent section
27
+ as a VALUE: the
28
+ `exportBounds` block, whose absence `isTruncated` deliberately answers as "not
29
+ truncated" so an export predating the cap is not skipped wholesale, and
30
+ `gmail.mailbox-label-count`'s `mailboxes`, where an absent collection means
31
+ "count by `mailboxEmail`" and the evidence collections are guarded by name one
32
+ line above. The exception list is pinned in both directions, so a row that stops
33
+ being needed fails the same way an unexplained finding does.
34
+
35
+ **ONE DECLARATION MOVED, AND IT IS A FIXTURE, NOT A VERDICT.**
36
+ `gmail.message-has-label`'s discriminating worlds built their user label as
37
+ `userLabel(label, label)` — an `id === name` shape only a SYSTEM label has. With
38
+ it, `labelIdsFor`'s bare-display-name fallback answered the join unaided, so
39
+ deleting `labels` from the passing world changed nothing and the verdict stayed
40
+ `passed`: a section the verdict demonstrably reads, proven unread by the only
41
+ world that speaks for it. The label now carries a minted id (`Label_1`) and the
42
+ `messageLabels` rows carry that id, so the deletion moves the verdict to
43
+ `failed` and the read is on the record.
44
+
45
+ Nothing in any `evaluate` changed. No check id, template, params, polarity,
46
+ subject or vacuity mutant moved, and no criterion changes from bound to unbound
47
+ or from passing to failing on any real export. `discriminatingWorlds` is a
48
+ fixture the probes run; a run's grade does not read it.
49
+
50
+ `labelIdsFor`'s comment counted TWO callers that must guard `state.labels`. There
51
+ are three — `messageCarriesLabel` in the same file is the third, reached by
52
+ `gmail.message-has-label`, and it answers `false` rather than refusing. That is
53
+ the safe direction for a check whose polarity is always positive, so it is left
54
+ alone and the comment now says which caller does which, with the sweep as the
55
+ thing that keeps it measured rather than assumed.
56
+
57
+ **What pome-cloud must do.** Pin `0.1.7` in `apps/control-plane` AND `apps/mcp`
58
+ — they must move together or `save_task` accepts criteria the grader cannot
59
+ bind — and restate the blind spot in `findVacuousStateSectionReaders`' doc
60
+ comment as a property of the declarations rather than of the detector, with
61
+ `docs/grading/a3-bucket-ledger.md` §5 item 9 following it. `declared-pin.test.ts`
62
+ needs no other edit: the detector's finding set over the new declarations is
63
+ byte-identical, because `gmail.message-has-label`'s worlds still differ on
64
+ `messageLabels` alone and deleting it still returns `state_incomplete`.
65
+
3
66
  ## 0.1.6
4
67
 
5
68
  `gmail.mailbox-label-count` now refuses instead of scoring a free pass (F-1441)
@@ -119,9 +119,25 @@ export declare function resolveMessage(state: GmailCheckState, id: string): Reso
119
119
  *
120
120
  * So: this function cannot refuse — it returns a Set, and an empty Set is
121
121
  * indistinguishable from "the label was never applied". **Every caller must
122
- * guard `state.labels` absence and truncation itself before calling**, and both
123
- * callers in check-messages.ts now do. Adding a third without that guard
124
- * reintroduces the F-1159 class.
122
+ * decide what an absent or capped `labels` collection means before calling**.
123
+ *
124
+ * THERE ARE THREE CALLERS, not the two F-1441 counted, and the third is in this
125
+ * very file:
126
+ * * `gmail.mailbox-label-count` and `gmail.one-message-per-recipient` in
127
+ * check-messages.ts REFUSE — `state_incomplete` / `collection_truncated` —
128
+ * because the first flips NEGATIVE at count 0, where an empty Set is a free
129
+ * point for an agent that did the forbidden thing.
130
+ * * `messageCarriesLabel` below, reached by `gmail.message-has-label`, does
131
+ * NOT refuse: it answers `false`, so an absent `labels` costs that check's
132
+ * agent a point rather than gifting one. Its polarity is always positive, so
133
+ * the direction is safe — but safe-by-polarity is how this class survives
134
+ * review, so it is measured rather than assumed. `section-read-sweep.test.ts`
135
+ * in @pome-sh/checks deletes `labels` from that check's own passing world on
136
+ * every run and asserts the verdict MOVES; before F-1437 it did not, because
137
+ * that world minted the label with `id === name` and the fallback above
138
+ * answered the join unaided.
139
+ *
140
+ * A fourth caller must pick one of those two and say which.
125
141
  */
126
142
  export declare function labelIdsFor(state: GmailCheckState, wanted: string): Set<string>;
127
143
  /**
@@ -5,16 +5,35 @@
5
5
  * and the CLI reads (`recorder-events.ts`), the OpenTelemetry-native extension
6
6
  * of that union (`otel/`), and the secret redactor applied on the way to disk
7
7
  * (`redaction.ts`). Every twin, the sdk, the adapter and the CLI depend on this
8
- * package; NOTHING here knows about sessions, tasks, runs or the cloud REST
9
- * surface — those live in `cli/src/contract/` (F-942).
8
+ * package; NOTHING ON THIS BARREL knows about sessions, tasks, runs or the
9
+ * cloud REST surface — those live in `cli/src/contract/` (F-942).
10
10
  *
11
- * Two SUBPATH-ONLY surfaces are deliberately absent from this barrel, because
12
- * only some consumers should pay to load them: `@pome-sh/wire/otel/fixtures`
13
- * (the golden-fixture corpus, a test/dev artifact) and
14
- * `@pome-sh/wire/correlation` (F-950 the agent-side AsyncLocalStorage +
15
- * fetch-patching plumbing that stamps `x-pome-correlation-id`; importing it
16
- * constructs an AsyncLocalStorage, and no twin is the agent side of that
17
- * protocol). `test/export-surface.test.ts` pins both halves of that call.
11
+ * F-1416 NARROWED THAT CLAIM ONCE, and this is the whole of the narrowing: the
12
+ * package now also ships `@pome-sh/wire/run-completeness`, four symbols that
13
+ * read two fields of a `criteria_results` row (`skipped`, `reason`) and return
14
+ * whether a finished run has a verdict to state. That is the one predicate
15
+ * pome-cloud's dashboard and control plane and this repo's CLI all have to
16
+ * agree on, and until F-1416 the CLI's agreement test kept a hand-written copy
17
+ * of it that went stale green. It is run-ADJACENT, so the sentence above would
18
+ * be false if it said "this package"; it is not run vocabulary, because it
19
+ * names no session, task, run id, REST route or column, imports nothing, and
20
+ * takes structural inputs so no cloud type crosses with it. Keeping it OFF this
21
+ * barrel is what keeps the sentence above enforceable rather than merely
22
+ * written down — see below.
23
+ *
24
+ * Three SUBPATH-ONLY surfaces are deliberately absent from this barrel.
25
+ * `@pome-sh/wire/otel/fixtures` (the golden-fixture corpus, a test/dev
26
+ * artifact) and `@pome-sh/wire/correlation` (F-950 — the agent-side
27
+ * AsyncLocalStorage + fetch-patching plumbing that stamps
28
+ * `x-pome-correlation-id`) are absent because only some consumers should pay to
29
+ * LOAD them: importing correlation constructs an AsyncLocalStorage, and no twin
30
+ * is the agent side of that protocol. `@pome-sh/wire/run-completeness` (F-1416)
31
+ * is absent for a different reason — SCOPE, not cost. The five twins, the sdk
32
+ * and the adapter import this barrel and not one of them has a run to ask
33
+ * about, so a symbol they cannot use has no business in their namespace, and an
34
+ * opt-in subpath is what makes the F-942 boundary above a thing CI can check.
35
+ * `test/export-surface.test.ts` pins all three: each subpath's own surface, and
36
+ * its absence from the snapshot below.
18
37
  *
19
38
  * This file is a THIN BARREL: it re-exports only.
20
39
  */
@@ -373,10 +373,14 @@ var messageHasLabel = defineCheck({
373
373
  // lookup rather than the assertion. The label is the scanned literal.
374
374
  vacuityMutant: (args) => ({ ...args, label: VACUITY_SENTINEL }),
375
375
  discriminatingWorlds: ({ message: id2, label }) => {
376
- const labels = [systemLabel("INBOX"), userLabel(label, label)];
376
+ const labelId = "Label_1";
377
+ const labels = [systemLabel("INBOX"), userLabel(labelId, label)];
377
378
  const base = { messages: [message(id2)], labels };
378
379
  return {
379
- passing: finalWorld(gmailState({ ...base, messageLabels: [messageLabel(id2, "INBOX"), messageLabel(id2, label)] })),
380
+ passing: finalWorld(gmailState({
381
+ ...base,
382
+ messageLabels: [messageLabel(id2, "INBOX"), messageLabel(id2, labelId)]
383
+ })),
380
384
  failing: finalWorld(gmailState({ ...base, messageLabels: [messageLabel(id2, "INBOX")] }))
381
385
  };
382
386
  },
package/dist/gmail.js CHANGED
@@ -1,2 +1,2 @@
1
- export { GMAIL_CHECKS, defaultSeedState, gmailSeedSchema, parseSeed } from './chunk-SNTLDQSZ.js';
1
+ export { GMAIL_CHECKS, defaultSeedState, gmailSeedSchema, parseSeed } from './chunk-KTTJCEDH.js';
2
2
  import './chunk-W2JNYULF.js';
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import './chunk-ZXE6LAM3.js';
2
2
  import { GITHUB_CHECKS } from './chunk-JVCGWAZQ.js';
3
3
  export { GITHUB_CHECKS, defaultSeedState as defaultGitHubSeed, seedSchema as githubSeedSchema, parseSeed as parseGitHubSeed } from './chunk-JVCGWAZQ.js';
4
- import { GMAIL_CHECKS } from './chunk-SNTLDQSZ.js';
5
- export { GMAIL_CHECKS, defaultSeedState as defaultGmailSeed, gmailSeedSchema, parseSeed as parseGmailSeed } from './chunk-SNTLDQSZ.js';
4
+ import { GMAIL_CHECKS } from './chunk-KTTJCEDH.js';
5
+ export { GMAIL_CHECKS, defaultSeedState as defaultGmailSeed, gmailSeedSchema, parseSeed as parseGmailSeed } from './chunk-KTTJCEDH.js';
6
6
  import { LINEAR_CHECKS } from './chunk-THOSO63W.js';
7
7
  export { LINEAR_CHECKS, defaultSeedState as defaultLinearSeed, linearSeedSchema, parseSeed as parseLinearSeed } from './chunk-THOSO63W.js';
8
8
  import { SLACK_CHECKS } from './chunk-MJOHK2NI.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/checks",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Pome's grading vocabulary — the check declarations, seed schemas and default seeds of all five digital twins, plus the check DSL they are written in. Declarations only: no twin server, no database, no routes, no tools.",
5
5
  "private": false,
6
6
  "type": "module",