@groundnuty/macf-core 0.2.35 → 0.2.37

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/index.d.ts CHANGED
@@ -17,6 +17,9 @@ export * from './config.js';
17
17
  export * from './token.js';
18
18
  export * from './types.js';
19
19
  export * from './semver.js';
20
+ export * from './reflection.js';
21
+ export * from './norm.js';
22
+ export * from './protected-invariant-norms.js';
20
23
  export * from './mtls-health-ping.js';
21
24
  export * from './certs/index.js';
22
25
  export * from './registry/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AAIpC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AAIpC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -17,6 +17,9 @@ export * from './config.js';
17
17
  export * from './token.js';
18
18
  export * from './types.js';
19
19
  export * from './semver.js';
20
+ export * from './reflection.js';
21
+ export * from './norm.js';
22
+ export * from './protected-invariant-norms.js';
20
23
  export * from './mtls-health-ping.js';
21
24
  export * from './certs/index.js';
22
25
  export * from './registry/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AAEpC,kEAAkE;AAClE,oEAAoE;AACpE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AAEpC,kEAAkE;AAClE,oEAAoE;AACpE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/norm.d.ts ADDED
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Versioned structured-norm (Moise-style) representation + deontic
3
+ * conflict-checker (groundnuty/macf#504, DR-026 G2 — PR-1).
4
+ *
5
+ * This module gives the coordination protocol a *machine-checkable* form for
6
+ * its norms. A "norm" is a deontic statement — an obligation, permission, or
7
+ * prohibition — bound to a `(role, action, condition)` triple. G3's SECP
8
+ * invariant-validator (macf#505) consumes this representation to mechanically
9
+ * check that a proposed rule change never contradicts a protected invariant.
10
+ *
11
+ * --------------------------------------------------------------------------
12
+ * G2 MODELS, IT DOES NOT ENFORCE.
13
+ * --------------------------------------------------------------------------
14
+ * This is a *data model* only. The runtime governor is the existing set of
15
+ * `check-*.sh` PreToolUse/PostToolUse hooks plus the DR-026 auditor — they
16
+ * are what actually block/warn at tool-call time. `SceneSchema` below models
17
+ * the issue-lifecycle scene as data (states + transitions); it carries NO
18
+ * enforcement code. Nothing here runs at coordination time.
19
+ *
20
+ * --------------------------------------------------------------------------
21
+ * CONTROLLED VOCABULARIES — the load-bearing guardrail.
22
+ * --------------------------------------------------------------------------
23
+ * The conflict-checker matches norms on three keys: `role`, `action`,
24
+ * `condition`. If two genuinely-conflicting norms are spelled differently
25
+ * (`after_merge` vs `after-merge`), a naive checker silently fails to match
26
+ * them — producing FALSE CONFIDENCE, which is worse than no checker at all.
27
+ *
28
+ * To close that silent-miss, every match-key is a CLOSED Zod enum over a
29
+ * canonical token set, and `normalizeToken` is applied to inputs first
30
+ * (lowercase, collapse runs of `_`/whitespace/`-` to a single `-`). An
31
+ * unknown token after normalization is REJECTED by the schema, forcing a
32
+ * deliberate vocabulary extension rather than an accidental synonym.
33
+ *
34
+ * --------------------------------------------------------------------------
35
+ * POSITIVE-ACTION CONVENTION.
36
+ * --------------------------------------------------------------------------
37
+ * The `Action` enum carries ONLY positive actions (`self-merge`,
38
+ * `close-issue`, …) — NEVER negated forms (`not-self-merge`). Negation lives
39
+ * exclusively in the `deontic` field. This is deliberate: if negated actions
40
+ * were allowed, a `prohibition(merge-pr)` could be silently dodged by
41
+ * re-expressing it as `obligation(not-merge-pr)` — the same constraint under
42
+ * a key the conflict-checker would never group together. Keeping actions
43
+ * positive means a clash on a constraint is always visible on one shared key.
44
+ *
45
+ * --------------------------------------------------------------------------
46
+ * DEONTIC-CONFLICT MATRIX (within one (role, action, condition) group).
47
+ * --------------------------------------------------------------------------
48
+ * obligation ∧ prohibition → CONFLICT ("must" vs "must not")
49
+ * permission ∧ prohibition → CONFLICT ("may" vs "must not")
50
+ * obligation ∧ permission → consistent (obligation ⊨ permission)
51
+ * Same deontic on the same key is not a logical conflict; duplicate
52
+ * obligations get a NON-BLOCKING warning (likely a redundant rule).
53
+ *
54
+ * v1 SCOPE: matching is exact-token on the canonical triple. Condition
55
+ * subsumption (one condition implies another), temporal/deadline logic, and
56
+ * role-hierarchy inheritance are DEFERRED to the G3 increment (macf#505).
57
+ */
58
+ import { z } from 'zod';
59
+ /** Current norm schema version. Bump on a breaking shape change. */
60
+ export declare const NORM_SCHEMA_VERSION: "1.0";
61
+ /** Stable type-tag distinguishing norm records on a multi-kind ledger. */
62
+ export declare const NORM_KIND: "macf.norm";
63
+ /**
64
+ * Canonicalize a vocabulary token: lowercase, then collapse any run of
65
+ * underscores / whitespace / hyphens into a single hyphen, and trim leading
66
+ * and trailing hyphens. This is what makes `after_merge`, `after merge`,
67
+ * `After-Merge`, and `after--merge` all map to the ONE canonical token
68
+ * `after-merge`. Applied to every match-key before enum validation so the
69
+ * enum only ever sees canonical forms.
70
+ */
71
+ export declare function normalizeToken(s: string): string;
72
+ /**
73
+ * Canonical ROLE vocabulary — the coordination actors a norm can bind to.
74
+ * Closed set: an unknown role is rejected (extend deliberately).
75
+ */
76
+ export declare const ROLE_TOKENS: readonly ["reporter", "implementer", "reviewer", "auditor", "operator", "deployment", "agent"];
77
+ export declare const RoleSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
78
+ agent: "agent";
79
+ reporter: "reporter";
80
+ implementer: "implementer";
81
+ reviewer: "reviewer";
82
+ auditor: "auditor";
83
+ operator: "operator";
84
+ deployment: "deployment";
85
+ }>>;
86
+ export type Role = (typeof ROLE_TOKENS)[number];
87
+ /**
88
+ * Canonical ACTION vocabulary — POSITIVE actions only (see file header). Each
89
+ * is a thing an actor *does*; prohibition/obligation/permission is expressed
90
+ * via `deontic`, never by negating the action name.
91
+ */
92
+ export declare const ACTION_TOKENS: readonly ["close-issue", "merge-pr", "self-merge", "auto-close-keyword", "implement", "mutate-universal-rule", "ratify-rule-change"];
93
+ export declare const ActionSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
94
+ "close-issue": "close-issue";
95
+ "merge-pr": "merge-pr";
96
+ "self-merge": "self-merge";
97
+ "auto-close-keyword": "auto-close-keyword";
98
+ implement: "implement";
99
+ "mutate-universal-rule": "mutate-universal-rule";
100
+ "ratify-rule-change": "ratify-rule-change";
101
+ }>>;
102
+ export type Action = (typeof ACTION_TOKENS)[number];
103
+ /**
104
+ * Canonical CONDITION vocabulary — the circumstance under which the norm
105
+ * applies. `always` is the unconditioned default. Conditions are exact-match
106
+ * keys in v1 (no subsumption — deferred to G3).
107
+ */
108
+ export declare const CONDITION_TOKENS: readonly ["always", "after-merge", "without-non-author-approval", "on-foreign-reporter-issue"];
109
+ export declare const ConditionSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
110
+ always: "always";
111
+ "after-merge": "after-merge";
112
+ "without-non-author-approval": "without-non-author-approval";
113
+ "on-foreign-reporter-issue": "on-foreign-reporter-issue";
114
+ }>>;
115
+ export type Condition = (typeof CONDITION_TOKENS)[number];
116
+ /** The three deontic modalities. */
117
+ export declare const DeonticSchema: z.ZodEnum<{
118
+ obligation: "obligation";
119
+ permission: "permission";
120
+ prohibition: "prohibition";
121
+ }>;
122
+ export type Deontic = z.infer<typeof DeonticSchema>;
123
+ /** Which tier a norm belongs to (constitutional vs deployment-local). */
124
+ export declare const NormTierSchema: z.ZodEnum<{
125
+ project: "project";
126
+ universal: "universal";
127
+ }>;
128
+ export type NormTier = z.infer<typeof NormTierSchema>;
129
+ /**
130
+ * A single structured norm.
131
+ *
132
+ * `role` / `action` / `condition` are the three CANONICAL match-keys the
133
+ * conflict-checker groups on. `deontic` is the modality. `deadline` and
134
+ * `sanction` are optional descriptive fields (not used by the v1 checker —
135
+ * room for G3's temporal logic). `tier` + `provenance` record where the norm
136
+ * came from (the source rule / invariant), so a flagged conflict is traceable
137
+ * back to a human-readable rule.
138
+ */
139
+ export declare const NormSchema: z.ZodObject<{
140
+ id: z.ZodString;
141
+ schema_version: z.ZodLiteral<"1.0">;
142
+ kind: z.ZodLiteral<"macf.norm">;
143
+ role: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
144
+ agent: "agent";
145
+ reporter: "reporter";
146
+ implementer: "implementer";
147
+ reviewer: "reviewer";
148
+ auditor: "auditor";
149
+ operator: "operator";
150
+ deployment: "deployment";
151
+ }>>;
152
+ deontic: z.ZodEnum<{
153
+ obligation: "obligation";
154
+ permission: "permission";
155
+ prohibition: "prohibition";
156
+ }>;
157
+ action: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
158
+ "close-issue": "close-issue";
159
+ "merge-pr": "merge-pr";
160
+ "self-merge": "self-merge";
161
+ "auto-close-keyword": "auto-close-keyword";
162
+ implement: "implement";
163
+ "mutate-universal-rule": "mutate-universal-rule";
164
+ "ratify-rule-change": "ratify-rule-change";
165
+ }>>;
166
+ condition: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
167
+ always: "always";
168
+ "after-merge": "after-merge";
169
+ "without-non-author-approval": "without-non-author-approval";
170
+ "on-foreign-reporter-issue": "on-foreign-reporter-issue";
171
+ }>>;
172
+ deadline: z.ZodOptional<z.ZodString>;
173
+ sanction: z.ZodOptional<z.ZodString>;
174
+ tier: z.ZodEnum<{
175
+ project: "project";
176
+ universal: "universal";
177
+ }>;
178
+ provenance: z.ZodString;
179
+ }, z.core.$strip>;
180
+ export type Norm = z.infer<typeof NormSchema>;
181
+ /**
182
+ * A transition in the issue-lifecycle scene. `from`/`to` are state names;
183
+ * `roleGate` (optional) names the role permitted to drive the transition;
184
+ * `normRef` (optional) points at a `Norm.id` that governs it. Data-model
185
+ * only — no transition is *executed* anywhere; the runtime governor is the
186
+ * hooks + auditor.
187
+ */
188
+ export declare const TransitionSchema: z.ZodObject<{
189
+ from: z.ZodString;
190
+ to: z.ZodString;
191
+ roleGate: z.ZodOptional<z.ZodString>;
192
+ normRef: z.ZodOptional<z.ZodString>;
193
+ }, z.core.$strip>;
194
+ export type Transition = z.infer<typeof TransitionSchema>;
195
+ /**
196
+ * The issue-lifecycle scene: the set of states an issue moves through and the
197
+ * legal transitions between them, mirroring `coordination.md` §Issue
198
+ * Lifecycle + the agent-identity label table (open → in-progress → in-review
199
+ * → closed, with a blocked side-state). DATA ONLY — see file header.
200
+ */
201
+ export declare const SceneSchema: z.ZodObject<{
202
+ id: z.ZodString;
203
+ schema_version: z.ZodLiteral<"1.0">;
204
+ kind: z.ZodLiteral<"macf.scene">;
205
+ states: z.ZodArray<z.ZodString>;
206
+ transitions: z.ZodArray<z.ZodObject<{
207
+ from: z.ZodString;
208
+ to: z.ZodString;
209
+ roleGate: z.ZodOptional<z.ZodString>;
210
+ normRef: z.ZodOptional<z.ZodString>;
211
+ }, z.core.$strip>>;
212
+ }, z.core.$strip>;
213
+ export type Scene = z.infer<typeof SceneSchema>;
214
+ /** The kind of deontic clash the checker found. */
215
+ export declare const ConflictTypeSchema: z.ZodEnum<{
216
+ "obligation-vs-prohibition": "obligation-vs-prohibition";
217
+ "permission-vs-prohibition": "permission-vs-prohibition";
218
+ }>;
219
+ export type ConflictType = z.infer<typeof ConflictTypeSchema>;
220
+ /** A detected conflict: the two clashing norms + the clash type. */
221
+ export interface NormConflict {
222
+ readonly a: Norm;
223
+ readonly b: Norm;
224
+ readonly type: ConflictType;
225
+ }
226
+ /** A non-blocking advisory: same-key duplicate obligations (redundant rule). */
227
+ export interface NormWarning {
228
+ readonly a: Norm;
229
+ readonly b: Norm;
230
+ readonly kind: 'duplicate-obligation';
231
+ }
232
+ /** The result of a conflict-check pass. */
233
+ export interface ConflictCheckResult {
234
+ readonly conflicts: readonly NormConflict[];
235
+ readonly warnings: readonly NormWarning[];
236
+ }
237
+ /**
238
+ * Detect deontic conflicts among a set of norms.
239
+ *
240
+ * Groups norms by their already-canonical `(role, action, condition)` triple,
241
+ * then within each group compares every pair:
242
+ * - opposite-modality clashes (obligation/prohibition, permission/prohibition)
243
+ * are returned as CONFLICTS;
244
+ * - duplicate obligations on the same key are returned as non-blocking
245
+ * WARNINGS (a likely-redundant rule, not a contradiction).
246
+ *
247
+ * Because the keys are canonical (the schema normalized them), two norms that
248
+ * conflict but were spelled differently on input (`after_merge` vs
249
+ * `after-merge`) land in the SAME group and are correctly flagged — that is
250
+ * the whole point of the controlled vocabulary.
251
+ *
252
+ * v1 is exact-token grouping only. Condition subsumption, temporal/deadline
253
+ * reasoning, and role-hierarchy inheritance are DEFERRED to G3 (macf#505).
254
+ */
255
+ export declare function detectNormConflicts(norms: readonly Norm[]): ConflictCheckResult;
256
+ //# sourceMappingURL=norm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"norm.d.ts","sourceRoot":"","sources":["../src/norm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,EAAG,KAAc,CAAC;AAElD,0EAA0E;AAC1E,eAAO,MAAM,SAAS,EAAG,WAAoB,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKhD;AAUD;;;GAGG;AACH,eAAO,MAAM,WAAW,gGAQd,CAAC;AACX,eAAO,MAAM,UAAU;;;;;;;;GAAiC,CAAC;AACzD,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,aAAa,sIAQhB,CAAC;AACX,eAAO,MAAM,YAAY;;;;;;;;GAAmC,CAAC;AAC7D,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gGAKnB,CAAC;AACX,eAAO,MAAM,eAAe;;;;;GAAsC,CAAC;AACnE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,oCAAoC;AACpC,eAAO,MAAM,aAAa;;;;EAAsD,CAAC;AACjF,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,yEAAyE;AACzE,eAAO,MAAM,cAAc;;;EAAmC,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAYrB,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;;;iBAK3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;iBAMtB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,mDAAmD;AACnD,eAAO,MAAM,kBAAkB;;;EAG7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;CAC7B;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;CACvC;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC3C;AAyBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,mBAAmB,CA4B/E"}
package/dist/norm.js ADDED
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Versioned structured-norm (Moise-style) representation + deontic
3
+ * conflict-checker (groundnuty/macf#504, DR-026 G2 — PR-1).
4
+ *
5
+ * This module gives the coordination protocol a *machine-checkable* form for
6
+ * its norms. A "norm" is a deontic statement — an obligation, permission, or
7
+ * prohibition — bound to a `(role, action, condition)` triple. G3's SECP
8
+ * invariant-validator (macf#505) consumes this representation to mechanically
9
+ * check that a proposed rule change never contradicts a protected invariant.
10
+ *
11
+ * --------------------------------------------------------------------------
12
+ * G2 MODELS, IT DOES NOT ENFORCE.
13
+ * --------------------------------------------------------------------------
14
+ * This is a *data model* only. The runtime governor is the existing set of
15
+ * `check-*.sh` PreToolUse/PostToolUse hooks plus the DR-026 auditor — they
16
+ * are what actually block/warn at tool-call time. `SceneSchema` below models
17
+ * the issue-lifecycle scene as data (states + transitions); it carries NO
18
+ * enforcement code. Nothing here runs at coordination time.
19
+ *
20
+ * --------------------------------------------------------------------------
21
+ * CONTROLLED VOCABULARIES — the load-bearing guardrail.
22
+ * --------------------------------------------------------------------------
23
+ * The conflict-checker matches norms on three keys: `role`, `action`,
24
+ * `condition`. If two genuinely-conflicting norms are spelled differently
25
+ * (`after_merge` vs `after-merge`), a naive checker silently fails to match
26
+ * them — producing FALSE CONFIDENCE, which is worse than no checker at all.
27
+ *
28
+ * To close that silent-miss, every match-key is a CLOSED Zod enum over a
29
+ * canonical token set, and `normalizeToken` is applied to inputs first
30
+ * (lowercase, collapse runs of `_`/whitespace/`-` to a single `-`). An
31
+ * unknown token after normalization is REJECTED by the schema, forcing a
32
+ * deliberate vocabulary extension rather than an accidental synonym.
33
+ *
34
+ * --------------------------------------------------------------------------
35
+ * POSITIVE-ACTION CONVENTION.
36
+ * --------------------------------------------------------------------------
37
+ * The `Action` enum carries ONLY positive actions (`self-merge`,
38
+ * `close-issue`, …) — NEVER negated forms (`not-self-merge`). Negation lives
39
+ * exclusively in the `deontic` field. This is deliberate: if negated actions
40
+ * were allowed, a `prohibition(merge-pr)` could be silently dodged by
41
+ * re-expressing it as `obligation(not-merge-pr)` — the same constraint under
42
+ * a key the conflict-checker would never group together. Keeping actions
43
+ * positive means a clash on a constraint is always visible on one shared key.
44
+ *
45
+ * --------------------------------------------------------------------------
46
+ * DEONTIC-CONFLICT MATRIX (within one (role, action, condition) group).
47
+ * --------------------------------------------------------------------------
48
+ * obligation ∧ prohibition → CONFLICT ("must" vs "must not")
49
+ * permission ∧ prohibition → CONFLICT ("may" vs "must not")
50
+ * obligation ∧ permission → consistent (obligation ⊨ permission)
51
+ * Same deontic on the same key is not a logical conflict; duplicate
52
+ * obligations get a NON-BLOCKING warning (likely a redundant rule).
53
+ *
54
+ * v1 SCOPE: matching is exact-token on the canonical triple. Condition
55
+ * subsumption (one condition implies another), temporal/deadline logic, and
56
+ * role-hierarchy inheritance are DEFERRED to the G3 increment (macf#505).
57
+ */
58
+ import { z } from 'zod';
59
+ /** Current norm schema version. Bump on a breaking shape change. */
60
+ export const NORM_SCHEMA_VERSION = '1.0';
61
+ /** Stable type-tag distinguishing norm records on a multi-kind ledger. */
62
+ export const NORM_KIND = 'macf.norm';
63
+ /**
64
+ * Canonicalize a vocabulary token: lowercase, then collapse any run of
65
+ * underscores / whitespace / hyphens into a single hyphen, and trim leading
66
+ * and trailing hyphens. This is what makes `after_merge`, `after merge`,
67
+ * `After-Merge`, and `after--merge` all map to the ONE canonical token
68
+ * `after-merge`. Applied to every match-key before enum validation so the
69
+ * enum only ever sees canonical forms.
70
+ */
71
+ export function normalizeToken(s) {
72
+ return s
73
+ .toLowerCase()
74
+ .replace(/[\s_-]+/g, '-')
75
+ .replace(/^-+|-+$/g, '');
76
+ }
77
+ /**
78
+ * A Zod preprocessor that normalizes the input token before the wrapped enum
79
+ * validates it. Non-string inputs pass through untouched so the enum produces
80
+ * its normal type error.
81
+ */
82
+ const canonical = (schema) => z.preprocess((v) => (typeof v === 'string' ? normalizeToken(v) : v), schema);
83
+ /**
84
+ * Canonical ROLE vocabulary — the coordination actors a norm can bind to.
85
+ * Closed set: an unknown role is rejected (extend deliberately).
86
+ */
87
+ export const ROLE_TOKENS = [
88
+ 'reporter',
89
+ 'implementer',
90
+ 'reviewer',
91
+ 'auditor',
92
+ 'operator',
93
+ 'deployment',
94
+ 'agent',
95
+ ];
96
+ export const RoleSchema = canonical(z.enum(ROLE_TOKENS));
97
+ /**
98
+ * Canonical ACTION vocabulary — POSITIVE actions only (see file header). Each
99
+ * is a thing an actor *does*; prohibition/obligation/permission is expressed
100
+ * via `deontic`, never by negating the action name.
101
+ */
102
+ export const ACTION_TOKENS = [
103
+ 'close-issue',
104
+ 'merge-pr',
105
+ 'self-merge',
106
+ 'auto-close-keyword',
107
+ 'implement',
108
+ 'mutate-universal-rule',
109
+ 'ratify-rule-change',
110
+ ];
111
+ export const ActionSchema = canonical(z.enum(ACTION_TOKENS));
112
+ /**
113
+ * Canonical CONDITION vocabulary — the circumstance under which the norm
114
+ * applies. `always` is the unconditioned default. Conditions are exact-match
115
+ * keys in v1 (no subsumption — deferred to G3).
116
+ */
117
+ export const CONDITION_TOKENS = [
118
+ 'always',
119
+ 'after-merge',
120
+ 'without-non-author-approval',
121
+ 'on-foreign-reporter-issue',
122
+ ];
123
+ export const ConditionSchema = canonical(z.enum(CONDITION_TOKENS));
124
+ /** The three deontic modalities. */
125
+ export const DeonticSchema = z.enum(['obligation', 'permission', 'prohibition']);
126
+ /** Which tier a norm belongs to (constitutional vs deployment-local). */
127
+ export const NormTierSchema = z.enum(['universal', 'project']);
128
+ /**
129
+ * A single structured norm.
130
+ *
131
+ * `role` / `action` / `condition` are the three CANONICAL match-keys the
132
+ * conflict-checker groups on. `deontic` is the modality. `deadline` and
133
+ * `sanction` are optional descriptive fields (not used by the v1 checker —
134
+ * room for G3's temporal logic). `tier` + `provenance` record where the norm
135
+ * came from (the source rule / invariant), so a flagged conflict is traceable
136
+ * back to a human-readable rule.
137
+ */
138
+ export const NormSchema = z.object({
139
+ id: z.string(),
140
+ schema_version: z.literal(NORM_SCHEMA_VERSION),
141
+ kind: z.literal(NORM_KIND),
142
+ role: RoleSchema,
143
+ deontic: DeonticSchema,
144
+ action: ActionSchema,
145
+ condition: ConditionSchema,
146
+ deadline: z.string().optional(),
147
+ sanction: z.string().optional(),
148
+ tier: NormTierSchema,
149
+ provenance: z.string(),
150
+ });
151
+ /**
152
+ * A transition in the issue-lifecycle scene. `from`/`to` are state names;
153
+ * `roleGate` (optional) names the role permitted to drive the transition;
154
+ * `normRef` (optional) points at a `Norm.id` that governs it. Data-model
155
+ * only — no transition is *executed* anywhere; the runtime governor is the
156
+ * hooks + auditor.
157
+ */
158
+ export const TransitionSchema = z.object({
159
+ from: z.string(),
160
+ to: z.string(),
161
+ roleGate: z.string().optional(),
162
+ normRef: z.string().optional(),
163
+ });
164
+ /**
165
+ * The issue-lifecycle scene: the set of states an issue moves through and the
166
+ * legal transitions between them, mirroring `coordination.md` §Issue
167
+ * Lifecycle + the agent-identity label table (open → in-progress → in-review
168
+ * → closed, with a blocked side-state). DATA ONLY — see file header.
169
+ */
170
+ export const SceneSchema = z.object({
171
+ id: z.string(),
172
+ schema_version: z.literal(NORM_SCHEMA_VERSION),
173
+ kind: z.literal('macf.scene'),
174
+ states: z.array(z.string()),
175
+ transitions: z.array(TransitionSchema),
176
+ });
177
+ /** The kind of deontic clash the checker found. */
178
+ export const ConflictTypeSchema = z.enum([
179
+ 'obligation-vs-prohibition',
180
+ 'permission-vs-prohibition',
181
+ ]);
182
+ /** The canonical group key for a norm: its (role, action, condition) triple. */
183
+ function groupKey(n) {
184
+ // Values are already canonical (validated by the enums), so JSON-joining is
185
+ // a stable, collision-free key for grouping.
186
+ return JSON.stringify([n.role, n.action, n.condition]);
187
+ }
188
+ /**
189
+ * Is this an actual deontic conflict per the matrix? Returns the conflict
190
+ * type, or `null` if the pair is consistent.
191
+ *
192
+ * obligation ∧ prohibition → conflict
193
+ * permission ∧ prohibition → conflict
194
+ * obligation ∧ permission → consistent (obligation entails permission)
195
+ * same modality → consistent (handled as a warning elsewhere)
196
+ */
197
+ function clashType(d1, d2) {
198
+ const pair = new Set([d1, d2]);
199
+ if (pair.has('prohibition') && pair.has('obligation'))
200
+ return 'obligation-vs-prohibition';
201
+ if (pair.has('prohibition') && pair.has('permission'))
202
+ return 'permission-vs-prohibition';
203
+ return null;
204
+ }
205
+ /**
206
+ * Detect deontic conflicts among a set of norms.
207
+ *
208
+ * Groups norms by their already-canonical `(role, action, condition)` triple,
209
+ * then within each group compares every pair:
210
+ * - opposite-modality clashes (obligation/prohibition, permission/prohibition)
211
+ * are returned as CONFLICTS;
212
+ * - duplicate obligations on the same key are returned as non-blocking
213
+ * WARNINGS (a likely-redundant rule, not a contradiction).
214
+ *
215
+ * Because the keys are canonical (the schema normalized them), two norms that
216
+ * conflict but were spelled differently on input (`after_merge` vs
217
+ * `after-merge`) land in the SAME group and are correctly flagged — that is
218
+ * the whole point of the controlled vocabulary.
219
+ *
220
+ * v1 is exact-token grouping only. Condition subsumption, temporal/deadline
221
+ * reasoning, and role-hierarchy inheritance are DEFERRED to G3 (macf#505).
222
+ */
223
+ export function detectNormConflicts(norms) {
224
+ const groups = new Map();
225
+ for (const n of norms) {
226
+ const key = groupKey(n);
227
+ const bucket = groups.get(key);
228
+ if (bucket)
229
+ bucket.push(n);
230
+ else
231
+ groups.set(key, [n]);
232
+ }
233
+ const conflicts = [];
234
+ const warnings = [];
235
+ for (const bucket of groups.values()) {
236
+ for (let i = 0; i < bucket.length; i++) {
237
+ for (let j = i + 1; j < bucket.length; j++) {
238
+ const a = bucket[i];
239
+ const b = bucket[j];
240
+ const type = clashType(a.deontic, b.deontic);
241
+ if (type) {
242
+ conflicts.push({ a, b, type });
243
+ }
244
+ else if (a.deontic === 'obligation' && b.deontic === 'obligation') {
245
+ warnings.push({ a, b, kind: 'duplicate-obligation' });
246
+ }
247
+ }
248
+ }
249
+ }
250
+ return { conflicts, warnings };
251
+ }
252
+ //# sourceMappingURL=norm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"norm.js","sourceRoot":"","sources":["../src/norm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { Norm } from './norm.js';
2
+ import { z } from 'zod';
3
+ /**
4
+ * A protected invariant that is a structural PROPERTY rather than a deontic
5
+ * norm. `statement` restates the guarantee; `whyNotANorm` records why it
6
+ * resists the `(role, action, condition)` shape; `enforcement` names the
7
+ * mechanism that actually guarantees it at runtime.
8
+ */
9
+ export declare const StructuralInvariantSchema: z.ZodObject<{
10
+ id: z.ZodString;
11
+ statement: z.ZodString;
12
+ whyNotANorm: z.ZodString;
13
+ enforcement: z.ZodString;
14
+ }, z.core.$strip>;
15
+ export type StructuralInvariant = z.infer<typeof StructuralInvariantSchema>;
16
+ /**
17
+ * The norm-expressible protected invariants. Each `provenance` points back at
18
+ * the numbered entry in `design/protected-invariants.md`.
19
+ */
20
+ export declare const PROTECTED_INVARIANT_NORMS: readonly Norm[];
21
+ /**
22
+ * The structural-property protected invariants. These are guarantees the
23
+ * conflict-checker does NOT reason over — they are enforced by mechanisms, not
24
+ * by deontic logic. Tagged here so the full set of 10 is accounted for and G3
25
+ * knows to route them to the structural-enforcement check, not the norm
26
+ * conflict-check.
27
+ */
28
+ export declare const PROTECTED_STRUCTURAL_INVARIANTS: readonly StructuralInvariant[];
29
+ /**
30
+ * Short machine-readable taxonomy note: which of the 10 invariants became a
31
+ * norm vs a structural property. Mirrors `design/structured-norms.md`.
32
+ */
33
+ export declare const PROTECTED_INVARIANT_TAXONOMY: {
34
+ readonly normExpressible: readonly [1, 3, 5, 8, 9, 10];
35
+ readonly structural: readonly [2, 4, 6, 7];
36
+ };
37
+ //# sourceMappingURL=protected-invariant-norms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected-invariant-norms.d.ts","sourceRoot":"","sources":["../src/protected-invariant-norms.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;iBAKpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAW5E;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,IAAI,EAuFpD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,EAAE,SAAS,mBAAmB,EAqCzE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;CAG/B,CAAC"}