@mmnto/totem 2.1.0 → 2.2.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/gate-engine.d.ts +11 -1
- package/dist/gate-engine.d.ts.map +1 -1
- package/dist/gate-engine.js +27 -5
- package/dist/gate-engine.js.map +1 -1
- package/dist/gate-types.d.ts +17 -2
- package/dist/gate-types.d.ts.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/parity-detect.d.ts +41 -4
- package/dist/parity-detect.d.ts.map +1 -1
- package/dist/parity-detect.js +264 -1
- package/dist/parity-detect.js.map +1 -1
- package/dist/parity-detect.orientation-rows.test.d.ts +17 -0
- package/dist/parity-detect.orientation-rows.test.d.ts.map +1 -0
- package/dist/parity-detect.orientation-rows.test.js +357 -0
- package/dist/parity-detect.orientation-rows.test.js.map +1 -0
- package/dist/parity-label-canon.d.ts +160 -0
- package/dist/parity-label-canon.d.ts.map +1 -0
- package/dist/parity-label-canon.js +220 -0
- package/dist/parity-label-canon.js.map +1 -0
- package/dist/parity-label-canon.test.d.ts +11 -0
- package/dist/parity-label-canon.test.d.ts.map +1 -0
- package/dist/parity-label-canon.test.js +296 -0
- package/dist/parity-label-canon.test.js.map +1 -0
- package/dist/parity-manifest.d.ts +9 -0
- package/dist/parity-manifest.d.ts.map +1 -1
- package/dist/parity-manifest.js +47 -0
- package/dist/parity-manifest.js.map +1 -1
- package/dist/parity-manifest.test.js +45 -0
- package/dist/parity-manifest.test.js.map +1 -1
- package/dist/recurrence-stats.d.ts +10 -10
- package/dist/retrospect.d.ts +42 -42
- package/dist/transport-shield.d.ts +190 -0
- package/dist/transport-shield.d.ts.map +1 -0
- package/dist/transport-shield.fold.test.d.ts +2 -0
- package/dist/transport-shield.fold.test.d.ts.map +1 -0
- package/dist/transport-shield.fold.test.js +439 -0
- package/dist/transport-shield.fold.test.js.map +1 -0
- package/dist/transport-shield.js +1040 -0
- package/dist/transport-shield.js.map +1 -0
- package/dist/transport-shield.test.d.ts +2 -0
- package/dist/transport-shield.test.d.ts.map +1 -0
- package/dist/transport-shield.test.js +298 -0
- package/dist/transport-shield.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure derivations for the two ORIENTATION parity rows the network-read-only
|
|
3
|
+
* family senses (mmnto-ai/totem#2791; the 472 charter's § 4b / § 4c requests,
|
|
4
|
+
* mmnto-ai/totem-strategy:operations/472-issue-disposition-preregistration.md):
|
|
5
|
+
*
|
|
6
|
+
* - `gh-issue-label-canon` — the label canon is PARSED from
|
|
7
|
+
* `mmnto-ai/totem:scripts/sync-labels.ps1` at run time (Tenet 20: derived,
|
|
8
|
+
* never mirrored) and a repo's live label list is judged against it.
|
|
9
|
+
* - `gh-project-vocabulary` — the canonical option sets are PARSED from the
|
|
10
|
+
* manifest row's own `expected-value-or-derivation` text, and a bound
|
|
11
|
+
* project's single-select fields are judged against them.
|
|
12
|
+
*
|
|
13
|
+
* Everything here is pure over text / parsed JSON: no I/O, no network, no
|
|
14
|
+
* module-level state. The verdict LINES (status / message) are rendered by
|
|
15
|
+
* `parity-detect.ts`'s network-posture dispatch, which owns the cannot-verify
|
|
16
|
+
* ladder; this module returns the drift FACTS only. The semantics are aligned
|
|
17
|
+
* with the strategy-local twin (`mmnto-ai/totem-strategy:tools/gh-parity-twins.cjs`,
|
|
18
|
+
* rung 1 of mmnto-ai/totem-strategy#472) so the two readers agree on every
|
|
19
|
+
* cohort repo: colour compares without `#` and case-insensitively, description
|
|
20
|
+
* compares exactly (untrimmed), the namespace token keeps its trailing space,
|
|
21
|
+
* option ORDER is information and never a fault, and a governed field that is
|
|
22
|
+
* absent IS a fault (its option set is empty, which is not the canonical set).
|
|
23
|
+
* One disclosed asymmetry: this module strips a leading `#` from the CANON's
|
|
24
|
+
* colour too (the twin lower-cases both sides but strips `#` on the live side
|
|
25
|
+
* only), so a `#`-prefixed hex in the script would still match here — identical
|
|
26
|
+
* readings while the script writes bare hex, as every one of its eighteen calls
|
|
27
|
+
* does today. Option NAMES are compared exactly on the live side; the canon's
|
|
28
|
+
* authoring whitespace is trimmed (the prose grammar cannot avoid it, and a
|
|
29
|
+
* quoted YAML member may carry it), so a padded live option name is a real
|
|
30
|
+
* difference the board shows, never smoothed away.
|
|
31
|
+
*/
|
|
32
|
+
/** The `gh label edit` calls that DEFINE the canon; only quoted arguments count. */
|
|
33
|
+
const LABEL_EDIT_RE = /gh\s+label\s+edit\s+"([^"]+)"\s+--color\s+"([^"]+)"\s+--description\s+"([^"]*)"/g;
|
|
34
|
+
/** The `Merge-Label` calls that RETIRE a name into a canonical one (positional or named parameters). */
|
|
35
|
+
const MERGE_LABEL_RE = /Merge-Label\s+(?:-OldName\s+)?"([^"]+)"\s+(?:-NewName\s+)?"([^"]+)"/g;
|
|
36
|
+
/** Plain code-unit order — a deterministic sort with no locale dependence (the twin's `byteOrder`). */
|
|
37
|
+
function codeUnitOrder(a, b) {
|
|
38
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
39
|
+
}
|
|
40
|
+
/** Normalize a colour to the API's shape: no leading `#`, lower-case. */
|
|
41
|
+
export function normalizeLabelColor(raw) {
|
|
42
|
+
return (raw ?? '').replace(/^#/, '').toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse the label canon out of the script text. PURE. An empty `labels` array
|
|
46
|
+
* means the text defined nothing — the CALLER refuses to judge against it
|
|
47
|
+
* (never a conformance verdict from an empty canon).
|
|
48
|
+
*/
|
|
49
|
+
export function parseLabelCanon(scriptText) {
|
|
50
|
+
const labels = [];
|
|
51
|
+
for (const match of scriptText.matchAll(LABEL_EDIT_RE)) {
|
|
52
|
+
const name = match[1];
|
|
53
|
+
const color = match[2];
|
|
54
|
+
const description = match[3];
|
|
55
|
+
if (name === undefined || color === undefined || description === undefined)
|
|
56
|
+
continue;
|
|
57
|
+
labels.push({ name, color: normalizeLabelColor(color), description });
|
|
58
|
+
}
|
|
59
|
+
const merges = [];
|
|
60
|
+
for (const match of scriptText.matchAll(MERGE_LABEL_RE)) {
|
|
61
|
+
const from = match[1];
|
|
62
|
+
const to = match[2];
|
|
63
|
+
if (from === undefined || to === undefined)
|
|
64
|
+
continue;
|
|
65
|
+
merges.push({ from, to });
|
|
66
|
+
}
|
|
67
|
+
return { labels, namespaces: namespaceTokensOf(labels.map((l) => l.name)), merges };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The namespace tokens the canonical names imply: the name through its first
|
|
71
|
+
* `: ` (the space IS part of the token — `type:audit` does not squat on
|
|
72
|
+
* `type: `), else through its first `-` (`tier-1` → `tier-`). A name with
|
|
73
|
+
* neither contributes no token. Derived, so a new namespace in the script
|
|
74
|
+
* becomes a sensed namespace here without a code change.
|
|
75
|
+
*/
|
|
76
|
+
export function namespaceTokensOf(names) {
|
|
77
|
+
const tokens = new Set();
|
|
78
|
+
for (const name of names) {
|
|
79
|
+
const colon = name.indexOf(': ');
|
|
80
|
+
if (colon !== -1) {
|
|
81
|
+
tokens.add(name.slice(0, colon + 2));
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const dash = name.indexOf('-');
|
|
85
|
+
if (dash !== -1)
|
|
86
|
+
tokens.add(name.slice(0, dash + 1));
|
|
87
|
+
}
|
|
88
|
+
return [...tokens].sort(codeUnitOrder);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The § 4c predicate over one repo's live labels. PURE.
|
|
92
|
+
*
|
|
93
|
+
* Faults: a canonical name absent; a canonical name present with a different
|
|
94
|
+
* colour or description; a live name inside a canonical namespace that is not
|
|
95
|
+
* in the canon (the "never redefine a canonical namespace" half). Live names
|
|
96
|
+
* outside every canonical namespace (`routine:*`, `disposition:*`, bare words)
|
|
97
|
+
* are permitted additions, reported and never flagged; a retired name still
|
|
98
|
+
* present is reported the same way.
|
|
99
|
+
*/
|
|
100
|
+
export function labelCanonDrift(live, canon) {
|
|
101
|
+
const byName = new Map();
|
|
102
|
+
for (const label of live)
|
|
103
|
+
byName.set(label.name, label);
|
|
104
|
+
const missing = [];
|
|
105
|
+
const redefined = [];
|
|
106
|
+
for (const canonical of canon.labels) {
|
|
107
|
+
const found = byName.get(canonical.name);
|
|
108
|
+
if (found === undefined) {
|
|
109
|
+
missing.push(canonical.name);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const entry = { name: canonical.name };
|
|
113
|
+
const actualColor = normalizeLabelColor(found.color);
|
|
114
|
+
if (actualColor !== canonical.color) {
|
|
115
|
+
entry.color = { expected: canonical.color, actual: actualColor };
|
|
116
|
+
}
|
|
117
|
+
if ((found.description ?? '') !== canonical.description) {
|
|
118
|
+
entry.description = true;
|
|
119
|
+
}
|
|
120
|
+
if (entry.color !== undefined || entry.description === true)
|
|
121
|
+
redefined.push(entry);
|
|
122
|
+
}
|
|
123
|
+
const canonNames = new Set(canon.labels.map((l) => l.name));
|
|
124
|
+
const retiredNames = new Set(canon.merges.map((m) => m.from));
|
|
125
|
+
const squatters = [];
|
|
126
|
+
const extra = [];
|
|
127
|
+
const retiredPresent = [];
|
|
128
|
+
for (const label of live) {
|
|
129
|
+
if (canonNames.has(label.name))
|
|
130
|
+
continue;
|
|
131
|
+
if (retiredNames.has(label.name)) {
|
|
132
|
+
retiredPresent.push(label.name);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const namespace = canon.namespaces.find((token) => label.name.startsWith(token));
|
|
136
|
+
if (namespace !== undefined)
|
|
137
|
+
squatters.push({ name: label.name, namespace });
|
|
138
|
+
else
|
|
139
|
+
extra.push(label.name);
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
conforming: missing.length === 0 && redefined.length === 0 && squatters.length === 0,
|
|
143
|
+
missing,
|
|
144
|
+
redefined,
|
|
145
|
+
squatters,
|
|
146
|
+
extra: extra.sort(codeUnitOrder),
|
|
147
|
+
retiredPresent: retiredPresent.sort(codeUnitOrder),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Parse the canonical option sets out of the row's `expected-value-or-derivation`
|
|
152
|
+
* text. The grammar is strict and small: clauses split on `;`, each clause
|
|
153
|
+
* `Field = a | b | c`; a clause without `=` (e.g. "extra fields permitted") is
|
|
154
|
+
* ignored; an empty field name or an empty option list drops the clause. The
|
|
155
|
+
* Map preserves clause order. An EMPTY map means the row text yields no
|
|
156
|
+
* governed field — the caller renders cannot-verify, never a hardcoded pass.
|
|
157
|
+
*/
|
|
158
|
+
export function parseExpectedOptionSets(text) {
|
|
159
|
+
const sets = new Map();
|
|
160
|
+
for (const clause of text.split(';')) {
|
|
161
|
+
const eq = clause.indexOf('=');
|
|
162
|
+
if (eq === -1)
|
|
163
|
+
continue;
|
|
164
|
+
const field = clause.slice(0, eq).trim();
|
|
165
|
+
const options = clause
|
|
166
|
+
.slice(eq + 1)
|
|
167
|
+
.split('|')
|
|
168
|
+
.map((option) => option.trim())
|
|
169
|
+
.filter((option) => option.length > 0);
|
|
170
|
+
if (field.length === 0 || options.length === 0)
|
|
171
|
+
continue;
|
|
172
|
+
sets.set(field, options);
|
|
173
|
+
}
|
|
174
|
+
return sets;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* `{ Status: [...], Priority: [...] }` for every single-select field on the
|
|
178
|
+
* project. Option names are kept RAW: the live side is what the board shows, and
|
|
179
|
+
* the canon side is the one that carries authoring whitespace (trimmed there).
|
|
180
|
+
*/
|
|
181
|
+
export function optionSetsOfProjectFields(fields) {
|
|
182
|
+
const sets = new Map();
|
|
183
|
+
for (const field of fields) {
|
|
184
|
+
sets.set(field.name, field.options.map((option) => option.name));
|
|
185
|
+
}
|
|
186
|
+
return sets;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* The § 4b predicate: every governed field (a key of `expected`) present on the
|
|
190
|
+
* project with EXACTLY the canonical option set, order-insensitive. PURE.
|
|
191
|
+
*/
|
|
192
|
+
export function projectVocabularyDrift(actual, expected) {
|
|
193
|
+
const faults = [];
|
|
194
|
+
const orderDiffers = [];
|
|
195
|
+
for (const [field, expectedOptions] of expected) {
|
|
196
|
+
const actualOptions = actual.get(field);
|
|
197
|
+
if (actualOptions === undefined) {
|
|
198
|
+
faults.push({ field, kind: 'field-missing', missing: [...expectedOptions], extra: [] });
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const expectedSet = new Set(expectedOptions);
|
|
202
|
+
const actualSet = new Set(actualOptions);
|
|
203
|
+
const missing = expectedOptions.filter((option) => !actualSet.has(option));
|
|
204
|
+
const extra = actualOptions.filter((option) => !expectedSet.has(option));
|
|
205
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
206
|
+
faults.push({ field, kind: 'option-set-differs', missing, extra });
|
|
207
|
+
}
|
|
208
|
+
else if (
|
|
209
|
+
// Equal SETS can still differ in length (a duplicated option name) or in
|
|
210
|
+
// order; both are information, and neither needs a joined string to see
|
|
211
|
+
// (pass 2 p2-F2 removed the NUL separator; pass 3 p3-F2 kept the length).
|
|
212
|
+
actualOptions.length !== expectedOptions.length ||
|
|
213
|
+
expectedOptions.some((option, index) => option !== actualOptions[index])) {
|
|
214
|
+
orderDiffers.push(field);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const added = [...actual.keys()].filter((field) => !expected.has(field)).sort(codeUnitOrder);
|
|
218
|
+
return { conforming: faults.length === 0, faults, orderDiffers, added };
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=parity-label-canon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parity-label-canon.js","sourceRoot":"","sources":["../src/parity-label-canon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the pure § 4b / § 4c derivations behind the two orientation parity
|
|
3
|
+
* rows (mmnto-ai/totem#2791): the label canon parsed from the REAL
|
|
4
|
+
* `scripts/sync-labels.ps1` in this repository (the Tenet 20 check — the parser
|
|
5
|
+
* must derive the script's actual sets, not a fixture that flatters it), the
|
|
6
|
+
* namespace tokens derived from the canonical names, the § 4c drift predicate,
|
|
7
|
+
* the option-set grammar over the row's own text, and the § 4b drift predicate.
|
|
8
|
+
* Zero I/O beyond the one in-repo script read; no network; no spawns.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=parity-label-canon.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parity-label-canon.test.d.ts","sourceRoot":"","sources":["../src/parity-label-canon.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the pure § 4b / § 4c derivations behind the two orientation parity
|
|
3
|
+
* rows (mmnto-ai/totem#2791): the label canon parsed from the REAL
|
|
4
|
+
* `scripts/sync-labels.ps1` in this repository (the Tenet 20 check — the parser
|
|
5
|
+
* must derive the script's actual sets, not a fixture that flatters it), the
|
|
6
|
+
* namespace tokens derived from the canonical names, the § 4c drift predicate,
|
|
7
|
+
* the option-set grammar over the row's own text, and the § 4b drift predicate.
|
|
8
|
+
* Zero I/O beyond the one in-repo script read; no network; no spawns.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { describe, expect, it } from 'vitest';
|
|
14
|
+
import { labelCanonDrift, namespaceTokensOf, normalizeLabelColor, optionSetsOfProjectFields, parseExpectedOptionSets, parseLabelCanon, projectVocabularyDrift, } from './parity-label-canon.js';
|
|
15
|
+
import { parseParityManifest } from './parity-manifest.js';
|
|
16
|
+
/** The canon of record, read from this repository (packages/core/src → the repo root). */
|
|
17
|
+
const REAL_SCRIPT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../scripts/sync-labels.ps1');
|
|
18
|
+
/** The pinned 0.1.42 row text for `gh-project-vocabulary` (verbatim). */
|
|
19
|
+
const ROW_TEXT = 'Status = Todo | In Progress | Done | Closed-Lateral | Closed-Superseded | Closed-Done | Informs-Design; Priority = Now | Next | Blocked | Horizon; extra fields permitted';
|
|
20
|
+
const STATUS = [
|
|
21
|
+
'Todo',
|
|
22
|
+
'In Progress',
|
|
23
|
+
'Done',
|
|
24
|
+
'Closed-Lateral',
|
|
25
|
+
'Closed-Superseded',
|
|
26
|
+
'Closed-Done',
|
|
27
|
+
'Informs-Design',
|
|
28
|
+
];
|
|
29
|
+
const PRIORITY = ['Now', 'Next', 'Blocked', 'Horizon'];
|
|
30
|
+
/** A three-label canon for the drift cases: one per token shape. */
|
|
31
|
+
const FIXTURE_SCRIPT = [
|
|
32
|
+
'gh label edit "tier-1" --color "d73a4a" --description "Immediate priority" --repo $Repo 2>$null',
|
|
33
|
+
'gh label edit "type: bug" --color "#D73A4A" --description "Something is not working" --repo $Repo',
|
|
34
|
+
'gh label edit "scope: cli" --color "de89ff" --description "" --repo $Repo',
|
|
35
|
+
'Merge-Label "bug" "type: bug"',
|
|
36
|
+
'Merge-Label -OldName "enhancement" -NewName "type: feature"',
|
|
37
|
+
].join('\n');
|
|
38
|
+
function live(name, color = 'd73a4a', description = 'x') {
|
|
39
|
+
return { name, color, description };
|
|
40
|
+
}
|
|
41
|
+
// ─── parseLabelCanon ─────────────────────────────────────
|
|
42
|
+
describe('parseLabelCanon — the real scripts/sync-labels.ps1', () => {
|
|
43
|
+
const canon = parseLabelCanon(readFileSync(REAL_SCRIPT_PATH, 'utf8'));
|
|
44
|
+
it('derives exactly the 18 canonical labels the row names (tier ×3 · type ×6 · scope ×4 · domain ×3 · status ×2)', () => {
|
|
45
|
+
expect(canon.labels).toHaveLength(18);
|
|
46
|
+
const names = canon.labels.map((l) => l.name);
|
|
47
|
+
expect(names.filter((n) => n.startsWith('tier-'))).toHaveLength(3);
|
|
48
|
+
expect(names.filter((n) => n.startsWith('type: '))).toHaveLength(6);
|
|
49
|
+
expect(names.filter((n) => n.startsWith('scope: '))).toHaveLength(4);
|
|
50
|
+
expect(names.filter((n) => n.startsWith('domain: '))).toHaveLength(3);
|
|
51
|
+
expect(names.filter((n) => n.startsWith('status: '))).toHaveLength(2);
|
|
52
|
+
});
|
|
53
|
+
it('derives exactly the five namespace tokens, the space kept on the colon tokens', () => {
|
|
54
|
+
expect(canon.namespaces).toEqual(['domain: ', 'scope: ', 'status: ', 'tier-', 'type: ']);
|
|
55
|
+
});
|
|
56
|
+
it('carries the colour and description of each definition, colour lower-case without #', () => {
|
|
57
|
+
const bug = canon.labels.find((l) => l.name === 'type: bug');
|
|
58
|
+
expect(bug).toEqual({
|
|
59
|
+
name: 'type: bug',
|
|
60
|
+
color: 'd73a4a',
|
|
61
|
+
description: 'Something is not working',
|
|
62
|
+
});
|
|
63
|
+
for (const label of canon.labels)
|
|
64
|
+
expect(label.color).toMatch(/^[0-9a-f]{6}$/);
|
|
65
|
+
});
|
|
66
|
+
it('records the Merge-Label retirements (the strays the script folds into canonical names)', () => {
|
|
67
|
+
// Exact, on purpose (Tenet 20): the script performs 22 retirements today,
|
|
68
|
+
// and a script change moves this number — that is the test doing its job.
|
|
69
|
+
expect(canon.merges).toHaveLength(22);
|
|
70
|
+
expect(canon.merges).toContainEqual({ from: 'bug', to: 'type: bug' });
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('parseLabelCanon — shapes', () => {
|
|
74
|
+
it('normalizes a #-prefixed upper-case colour and admits an empty description', () => {
|
|
75
|
+
const canon = parseLabelCanon(FIXTURE_SCRIPT);
|
|
76
|
+
expect(canon.labels).toEqual([
|
|
77
|
+
{ name: 'tier-1', color: 'd73a4a', description: 'Immediate priority' },
|
|
78
|
+
{ name: 'type: bug', color: 'd73a4a', description: 'Something is not working' },
|
|
79
|
+
{ name: 'scope: cli', color: 'de89ff', description: '' },
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
it('reads both Merge-Label spellings (positional and named parameters)', () => {
|
|
83
|
+
expect(parseLabelCanon(FIXTURE_SCRIPT).merges).toEqual([
|
|
84
|
+
{ from: 'bug', to: 'type: bug' },
|
|
85
|
+
{ from: 'enhancement', to: 'type: feature' },
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
it('yields an EMPTY canon from text with no gh label edit call (the caller refuses to judge on it)', () => {
|
|
89
|
+
expect(parseLabelCanon('Write-Host "nothing here"').labels).toEqual([]);
|
|
90
|
+
expect(parseLabelCanon('').namespaces).toEqual([]);
|
|
91
|
+
});
|
|
92
|
+
it('ignores an unquoted or partial edit call (only the quoted three-argument shape defines the canon)', () => {
|
|
93
|
+
expect(parseLabelCanon('gh label edit tier-9 --color abc123 --description nope').labels).toEqual([]);
|
|
94
|
+
expect(parseLabelCanon('gh label edit "tier-9" --color "abc123"').labels).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
// ─── namespaceTokensOf ───────────────────────────────────
|
|
98
|
+
describe('namespaceTokensOf', () => {
|
|
99
|
+
it('takes the name through its first ": " (space included), else through its first "-"', () => {
|
|
100
|
+
expect(namespaceTokensOf(['tier-1', 'type: bug', 'scope: cli', 'type: docs'])).toEqual([
|
|
101
|
+
'scope: ',
|
|
102
|
+
'tier-',
|
|
103
|
+
'type: ',
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
it('contributes no token for a name with neither separator, and none for a colon without a space', () => {
|
|
107
|
+
expect(namespaceTokensOf(['plain', 'type:bug'])).toEqual([]);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
// ─── normalizeLabelColor ─────────────────────────────────
|
|
111
|
+
describe('normalizeLabelColor', () => {
|
|
112
|
+
it('strips one leading # and lower-cases; null / undefined become the empty string', () => {
|
|
113
|
+
expect(normalizeLabelColor('#ABCDEF')).toBe('abcdef');
|
|
114
|
+
expect(normalizeLabelColor('abcdef')).toBe('abcdef');
|
|
115
|
+
expect(normalizeLabelColor(null)).toBe('');
|
|
116
|
+
expect(normalizeLabelColor(undefined)).toBe('');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
// ─── labelCanonDrift ─────────────────────────────────────
|
|
120
|
+
describe('labelCanonDrift (§ 4c)', () => {
|
|
121
|
+
const canon = parseLabelCanon(FIXTURE_SCRIPT);
|
|
122
|
+
const conformant = [
|
|
123
|
+
live('tier-1', 'D73A4A', 'Immediate priority'),
|
|
124
|
+
live('type: bug', '#d73a4a', 'Something is not working'),
|
|
125
|
+
live('scope: cli', 'de89ff', null),
|
|
126
|
+
];
|
|
127
|
+
it('conforms when every canonical name is present with its colour (any case, with or without #) and description (null == empty)', () => {
|
|
128
|
+
const drift = labelCanonDrift(conformant, canon);
|
|
129
|
+
expect(drift.conforming).toBe(true);
|
|
130
|
+
expect(drift).toMatchObject({
|
|
131
|
+
missing: [],
|
|
132
|
+
redefined: [],
|
|
133
|
+
squatters: [],
|
|
134
|
+
extra: [],
|
|
135
|
+
retiredPresent: [],
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
it('names a missing canonical label', () => {
|
|
139
|
+
const drift = labelCanonDrift(conformant.slice(1), canon);
|
|
140
|
+
expect(drift.conforming).toBe(false);
|
|
141
|
+
expect(drift.missing).toEqual(['tier-1']);
|
|
142
|
+
});
|
|
143
|
+
it('names a redefined colour with expected and actual, both normalized', () => {
|
|
144
|
+
const drift = labelCanonDrift([live('tier-1', '#FBCA04', 'Immediate priority'), ...conformant.slice(1)], canon);
|
|
145
|
+
expect(drift.redefined).toEqual([
|
|
146
|
+
{ name: 'tier-1', color: { expected: 'd73a4a', actual: 'fbca04' } },
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
it('names a redefined description (exact compare; a null description against canonical text is a redefinition)', () => {
|
|
150
|
+
const drift = labelCanonDrift([
|
|
151
|
+
live('tier-1', 'd73a4a', 'Immediate priority '),
|
|
152
|
+
live('type: bug', 'd73a4a', null),
|
|
153
|
+
conformant[2],
|
|
154
|
+
], canon);
|
|
155
|
+
expect(drift.redefined).toEqual([
|
|
156
|
+
{ name: 'tier-1', description: true },
|
|
157
|
+
{ name: 'type: bug', description: true },
|
|
158
|
+
]);
|
|
159
|
+
});
|
|
160
|
+
it('flags a name inside a canonical namespace that is not in the canon (the space is part of the token)', () => {
|
|
161
|
+
const drift = labelCanonDrift([...conformant, live('scope: docs'), live('type:audit'), live('tier-4')], canon);
|
|
162
|
+
expect(drift.squatters).toEqual([
|
|
163
|
+
{ name: 'scope: docs', namespace: 'scope: ' },
|
|
164
|
+
{ name: 'tier-4', namespace: 'tier-' },
|
|
165
|
+
]);
|
|
166
|
+
expect(drift.extra).toEqual(['type:audit']);
|
|
167
|
+
expect(drift.conforming).toBe(false);
|
|
168
|
+
});
|
|
169
|
+
it('permits and reports labels outside every canonical namespace, sorted; a retired name is reported apart', () => {
|
|
170
|
+
const drift = labelCanonDrift([
|
|
171
|
+
...conformant,
|
|
172
|
+
live('routine: weekly'),
|
|
173
|
+
live('1.11.0'),
|
|
174
|
+
live('disposition: done'),
|
|
175
|
+
live('bug'),
|
|
176
|
+
], canon);
|
|
177
|
+
expect(drift.conforming).toBe(true);
|
|
178
|
+
expect(drift.extra).toEqual(['1.11.0', 'disposition: done', 'routine: weekly']);
|
|
179
|
+
expect(drift.retiredPresent).toEqual(['bug']);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
// ─── parseExpectedOptionSets ─────────────────────────────
|
|
183
|
+
describe('parseExpectedOptionSets (the row grammar)', () => {
|
|
184
|
+
it('reads the pinned row text into the two governed sets, in clause order, ignoring the prose clause', () => {
|
|
185
|
+
const sets = parseExpectedOptionSets(ROW_TEXT);
|
|
186
|
+
expect([...sets.keys()]).toEqual(['Status', 'Priority']);
|
|
187
|
+
expect(sets.get('Status')).toEqual(STATUS);
|
|
188
|
+
expect(sets.get('Priority')).toEqual(PRIORITY);
|
|
189
|
+
});
|
|
190
|
+
// The PINNED doctrine row, not a mirrored literal (falsification pass 1, F4):
|
|
191
|
+
// a doctrine reword that the grammar reads differently fails HERE instead of
|
|
192
|
+
// darkening the sensor with a green suite. The pack is an optionalDependency
|
|
193
|
+
// that never materializes on an unauthenticated install (mmnto-ai/totem#2289),
|
|
194
|
+
// so the case is skipped when the manifest is absent (vitest reports the skip
|
|
195
|
+
// in its counts; this case's title names the artifact whose absence skips it).
|
|
196
|
+
const PINNED_MANIFEST = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../node_modules/@mmnto/strategy-doctrine/parity-manifest.yaml');
|
|
197
|
+
it.skipIf(!existsSync(PINNED_MANIFEST))('reads the PINNED gh-project-vocabulary row (the installed doctrine manifest) into the two governed sets', () => {
|
|
198
|
+
const parsed = parseParityManifest(readFileSync(PINNED_MANIFEST, 'utf8'));
|
|
199
|
+
expect(parsed.status).toBe('ok');
|
|
200
|
+
if (parsed.status !== 'ok')
|
|
201
|
+
return;
|
|
202
|
+
const row = parsed.manifest.contracts.find((c) => c.id === 'gh-project-vocabulary');
|
|
203
|
+
expect(row).toBeDefined();
|
|
204
|
+
if (row === undefined)
|
|
205
|
+
return;
|
|
206
|
+
// The PROSE is always parsed — it stays a pinned contract even after the
|
|
207
|
+
// structured field lands (pass 2, p2-F1) — and when the structured field
|
|
208
|
+
// is present the two must agree, or the doctrine row contradicts itself.
|
|
209
|
+
const prose = parseExpectedOptionSets(row.expectedValueOrDerivation);
|
|
210
|
+
expect([...prose.keys()]).toEqual(['Status', 'Priority']);
|
|
211
|
+
expect(prose.get('Status')).toEqual(STATUS);
|
|
212
|
+
expect(prose.get('Priority')).toEqual(PRIORITY);
|
|
213
|
+
if (row.expectedOptionSets !== undefined) {
|
|
214
|
+
// Same fields, same members with the same multiplicity, order ignored
|
|
215
|
+
// (option order is ungoverned — the design's invariants; pass 3 p3-F5,
|
|
216
|
+
// strengthened pass 4 p4-F1: sorted arrays, so a duplicated member is
|
|
217
|
+
// caught where a Set would have collapsed it). DISCLOSED: at the 0.1.42
|
|
218
|
+
// pin the row carries no structured field, so this branch is inert until
|
|
219
|
+
// doctrine 0.1.44 lands the field (pass 4, p4-F6).
|
|
220
|
+
const structured = row.expectedOptionSets;
|
|
221
|
+
expect(Object.keys(structured).sort()).toEqual([...prose.keys()].sort());
|
|
222
|
+
for (const [field, options] of prose) {
|
|
223
|
+
expect([...(structured[field] ?? [])].sort()).toEqual([...options].sort());
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
it('yields an EMPTY map from text without a Field = a | b clause (never a hardcoded set)', () => {
|
|
228
|
+
expect(parseExpectedOptionSets('').size).toBe(0);
|
|
229
|
+
expect(parseExpectedOptionSets('extra fields permitted').size).toBe(0);
|
|
230
|
+
expect(parseExpectedOptionSets('Status =').size).toBe(0);
|
|
231
|
+
expect(parseExpectedOptionSets(' = Todo | Done').size).toBe(0);
|
|
232
|
+
});
|
|
233
|
+
it('trims whitespace around fields and options and drops empty options', () => {
|
|
234
|
+
expect(parseExpectedOptionSets(' Status = Todo | | Done ;')).toEqual(new Map([['Status', ['Todo', 'Done']]]));
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
// ─── optionSetsOfProjectFields + projectVocabularyDrift ─
|
|
238
|
+
describe('projectVocabularyDrift (§ 4b)', () => {
|
|
239
|
+
const expected = parseExpectedOptionSets(ROW_TEXT);
|
|
240
|
+
const field = (name, options) => ({
|
|
241
|
+
name,
|
|
242
|
+
options: options.map((o) => ({ name: o })),
|
|
243
|
+
});
|
|
244
|
+
it('conforms when both governed sets equal the canon; extra fields are reported as additions', () => {
|
|
245
|
+
const actual = optionSetsOfProjectFields([
|
|
246
|
+
field('Status', STATUS),
|
|
247
|
+
field('Priority', PRIORITY),
|
|
248
|
+
field('M', ['M0', 'M1']),
|
|
249
|
+
]);
|
|
250
|
+
expect(projectVocabularyDrift(actual, expected)).toEqual({
|
|
251
|
+
conforming: true,
|
|
252
|
+
faults: [],
|
|
253
|
+
orderDiffers: [],
|
|
254
|
+
added: ['M'],
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
it('treats a duplicated live option (equal set, longer list) as information, never a fault — the length check (pass 3, p3-F2)', () => {
|
|
258
|
+
const actual = optionSetsOfProjectFields([
|
|
259
|
+
field('Status', [...STATUS, 'Done']),
|
|
260
|
+
field('Priority', PRIORITY),
|
|
261
|
+
]);
|
|
262
|
+
const drift = projectVocabularyDrift(actual, expected);
|
|
263
|
+
expect(drift.conforming).toBe(true);
|
|
264
|
+
expect(drift.faults).toEqual([]);
|
|
265
|
+
// Pinned so the length check cannot be dropped again silently (pass 4, p4-F2).
|
|
266
|
+
expect(drift.orderDiffers).toEqual(['Status']);
|
|
267
|
+
});
|
|
268
|
+
it('treats a different option ORDER as information, never a fault', () => {
|
|
269
|
+
const actual = optionSetsOfProjectFields([
|
|
270
|
+
field('Status', [...STATUS].reverse()),
|
|
271
|
+
field('Priority', PRIORITY),
|
|
272
|
+
]);
|
|
273
|
+
const drift = projectVocabularyDrift(actual, expected);
|
|
274
|
+
expect(drift.conforming).toBe(true);
|
|
275
|
+
expect(drift.orderDiffers).toEqual(['Status']);
|
|
276
|
+
});
|
|
277
|
+
it('faults a missing option and an extra option on the same field, naming each', () => {
|
|
278
|
+
const actual = optionSetsOfProjectFields([
|
|
279
|
+
field('Status', [...STATUS.filter((o) => o !== 'Done'), 'Shipped']),
|
|
280
|
+
field('Priority', PRIORITY),
|
|
281
|
+
]);
|
|
282
|
+
const drift = projectVocabularyDrift(actual, expected);
|
|
283
|
+
expect(drift.conforming).toBe(false);
|
|
284
|
+
expect(drift.faults).toEqual([
|
|
285
|
+
{ field: 'Status', kind: 'option-set-differs', missing: ['Done'], extra: ['Shipped'] },
|
|
286
|
+
]);
|
|
287
|
+
});
|
|
288
|
+
it('faults an ABSENT governed field (its set is empty, which is not the canon)', () => {
|
|
289
|
+
const actual = optionSetsOfProjectFields([field('Status', STATUS)]);
|
|
290
|
+
const drift = projectVocabularyDrift(actual, expected);
|
|
291
|
+
expect(drift.faults).toEqual([
|
|
292
|
+
{ field: 'Priority', kind: 'field-missing', missing: PRIORITY, extra: [] },
|
|
293
|
+
]);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=parity-label-canon.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parity-label-canon.test.js","sourceRoot":"","sources":["../src/parity-label-canon.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -139,6 +139,15 @@ export interface ParityContract {
|
|
|
139
139
|
* registry (CLI edge), not on this field.
|
|
140
140
|
*/
|
|
141
141
|
probeClass?: string;
|
|
142
|
+
/**
|
|
143
|
+
* Optional STRUCTURED canonical option sets on a `gh-project-vocabulary` row
|
|
144
|
+
* (mmnto-ai/totem#2791): field name → its canonical option names, e.g.
|
|
145
|
+
* `{ Status: [...], Priority: [...] }`. When present the detector reads the
|
|
146
|
+
* canon from here; when absent it parses `expectedValueOrDerivation`'s prose
|
|
147
|
+
* (`Field = a | b; …`). Narrowed per-row: every key non-empty, every value a
|
|
148
|
+
* non-empty list of non-empty strings, else absent on that row.
|
|
149
|
+
*/
|
|
150
|
+
expectedOptionSets?: Record<string, string[]>;
|
|
142
151
|
}
|
|
143
152
|
/** A fully parsed + validated parity manifest. */
|
|
144
153
|
export interface ParityManifest {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parity-manifest.d.ts","sourceRoot":"","sources":["../src/parity-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAIjD;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,mEAInC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,uJA0BxB,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,sDAAuD,CAAC;AAClF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"parity-manifest.d.ts","sourceRoot":"","sources":["../src/parity-manifest.ts"],"names":[],"mappings":"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"}
|