@ogygie/core 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogygie/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Ogygie framework core: manifest/spec/error schemas, generic tenancy and gate tooling. Ships TypeScript sources — Ogygie products run tsx/vitest by construction (D1).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -121,9 +121,25 @@ describe("auditProductVocabulary — B4 : la pureté des fichiers gouvernés", (
121
121
  const violations = auditProductVocabulary({
122
122
  vocabulary: VOCABULARY,
123
123
  sourceFiles: [],
124
- governedFiles: [{ path: "tsconfig.base.json", content: "// tuned for the gizmo pipeline" }],
124
+ governedFiles: [{ path: "tsconfig.base.json", content: "// tuned for the gadget pipeline" }],
125
125
  });
126
- expect(violations.map((violation) => violation.match.root)).toEqual(["gizmo"]);
126
+ expect(violations.map((violation) => violation.match.root)).toEqual(["gadget"]);
127
+ });
128
+
129
+ it("un ALIAS interdit dans un fichier gouverné ne déclenche RIEN (v2)", () => {
130
+ // An alias is by definition a word the product does NOT use, so finding it
131
+ // in a generic file proves no contamination — while the framework's own
132
+ // neutral domain and plain computing English produce such collisions in
133
+ // bulk (eight false positives out of eighteen on the first real migration).
134
+ expect(
135
+ auditProductVocabulary({
136
+ vocabulary: VOCABULARY,
137
+ sourceFiles: [],
138
+ governedFiles: [
139
+ { path: "AGENTS.md", content: "const widgetId = 1; // gizmo everywhere" },
140
+ ],
141
+ }),
142
+ ).toEqual([]);
127
143
  });
128
144
 
129
145
  it("un fichier gouverné strictement générique passe", () => {
@@ -8,10 +8,17 @@
8
8
  * - PRODUCT SOURCE (B3): only forbidden ALIASES are hunted, and only in the
9
9
  * machine identifiers — comments are blanked out first. The business prose
10
10
  * of the project keeps its own words; the code has one term per concept.
11
- * - GOVERNED FILES (B4): EVERY declared root is hunted — canonical terms
12
- * included — in the RAW text, comments and all. A governed file is identical
13
- * in every Ogygie project, so it may know no product's domain at all, not
14
- * even in a comment. That is the framework/product boundary made mechanical.
11
+ * - GOVERNED FILES (B4): the CANONICAL terms are hunted in the RAW text,
12
+ * comments and all. A governed file is identical in every Ogygie project, so
13
+ * it may know no product's domain at all, not even in a comment. That is the
14
+ * framework/product boundary made mechanical.
15
+ * Forbidden aliases are deliberately NOT hunted there (spec v2): an alias is
16
+ * by definition a word the product does NOT use, so finding one in a generic
17
+ * file proves no contamination — while the framework's own neutral domain
18
+ * (`orders`, `customerId`) and plain computing English (`level`, `register`)
19
+ * collide with it in bulk. Eight false positives out of eighteen on the first
20
+ * real migration, and a gate whose verdicts one learns to ignore protects
21
+ * nothing.
15
22
  *
16
23
  * The filesystem is injected (files come in as text), so the whole judgement
17
24
  * is a pure function proven in memory with its mutations.
@@ -49,7 +56,11 @@ export interface VocabularyAuditInput {
49
56
  readonly governedFiles: readonly ScannedFile[];
50
57
  }
51
58
 
52
- /** Every root the vocabulary declares: canonical terms AND forbidden aliases. */
59
+ /**
60
+ * Every root the vocabulary declares: canonical terms AND forbidden aliases.
61
+ * Kept for callers that need the full list; the governed-file rule uses the
62
+ * canonical terms alone (see above).
63
+ */
53
64
  export function vocabularyRootsOf(vocabulary: ProductVocabulary): readonly string[] {
54
65
  return vocabulary.entries.flatMap((entry) => [entry.canonical, ...entry.forbiddenAliases]);
55
66
  }
@@ -71,7 +82,7 @@ export function auditProductVocabulary(
71
82
 
72
83
  const canonicalOfAlias = canonicalByAlias(vocabulary);
73
84
  const forbiddenAliases = [...canonicalOfAlias.keys()];
74
- const everyRoot = vocabularyRootsOf(vocabulary);
85
+ const canonicalTerms = vocabulary.entries.map((entry) => entry.canonical);
75
86
  const violations: VocabularyViolation[] = [];
76
87
 
77
88
  for (const file of input.sourceFiles) {
@@ -86,7 +97,7 @@ export function auditProductVocabulary(
86
97
  }
87
98
 
88
99
  for (const file of input.governedFiles) {
89
- for (const match of findProductVocabulary(file.content, everyRoot)) {
100
+ for (const match of findProductVocabulary(file.content, canonicalTerms)) {
90
101
  violations.push({
91
102
  kind: "GOVERNED_FILE",
92
103
  filePath: file.path,