@boyingliu01/xp-gate 0.36.0 → 0.36.1

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.
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @test REQ-758 `xp-gate principles <dir>` must reach every file the engine has an adapter for
3
+ * @intent `principles.js` keeps its own literal `SOURCE_EXTENSIONS` because the file must
4
+ * stay loadable by plain Node with no transpile step. Its own comment said the
5
+ * list "Must match `getAdapterForFile`'s adapterMap" — and it did not.
6
+ * `analyzer.ts` registered `.cs` and `.csx` since #717, but this walk never
7
+ * offered those files to the checker, so a directory of C# sources reported
8
+ * `Files checked: 0`, which reads exactly like "no violations".
9
+ *
10
+ * How the expected set is derived matters more than the assertion, because two
11
+ * weaker designs both shipped a guard that could pass while the defect lived:
12
+ *
13
+ * 1. A regex over analyzer.ts. Measured: changing `'.ts'` to `".ts"` — cosmetic,
14
+ * same semantics — dropped the parsed set from 21 to 20 and the test still
15
+ * passed. A guard that weakens under a legal refactor is the same "covered
16
+ * but cannot block" shape as the bug.
17
+ * 2. A hand-written candidate list probed through `getAdapterForFile`. Measured:
18
+ * adding `.fs` to BOTH adapterMap and the walk left every test green, because
19
+ * the candidate list simply did not contain `.fs`.
20
+ *
21
+ * So: parse `adapterMap` with the TypeScript compiler API (syntax-aware — key
22
+ * quoting, comments and line breaks do not change the result; verified against
23
+ * three cosmetic refactors), and separately confirm through `getAdapterForFile`
24
+ * that each such extension is genuinely analysable. No hand-maintained list
25
+ * bounds the expectation, so an extension added to the analyzer alone fails here
26
+ * by name.
27
+ * @covers AC-758-01, AC-758-02, AC-758-03, AC-758-04, AC-758-05
28
+ */
29
+ const ts = require('typescript');
30
+ const fs = require('fs');
31
+ const path = require('path');
32
+ const os = require('os');
33
+ const { pathToFileURL } = require('url');
34
+
35
+ const { collectSourceFiles } = require('../principles');
36
+
37
+ const REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..');
38
+ const ANALYZER = path.join(REPO_ROOT, 'src', 'principles', 'analyzer.ts');
39
+
40
+ let TMP;
41
+ let getAdapterForFile;
42
+
43
+ beforeAll(async () => {
44
+ TMP = fs.mkdtempSync(path.join(os.tmpdir(), 'principles-csharp-'));
45
+ const mod = await import(pathToFileURL(ANALYZER).href);
46
+ getAdapterForFile = mod.getAdapterForFile;
47
+ });
48
+
49
+ afterAll(() => {
50
+ fs.rmSync(TMP, { recursive: true, force: true });
51
+ });
52
+
53
+ /**
54
+ * Write a file inside the temp tree.
55
+ * @param {string} rel - path relative to TMP
56
+ * @param {string} content - file body
57
+ */
58
+ function touch(rel, content) {
59
+ const abs = path.join(TMP, rel);
60
+ try {
61
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
62
+ fs.writeFileSync(abs, content);
63
+ } catch (err) {
64
+ const msg = err instanceof Error ? err.message : String(err);
65
+ throw new Error(`fixture setup failed writing ${rel}: ${msg}`);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Keys of the `adapterMap` object literal in a TypeScript source string.
71
+ *
72
+ * Uses the compiler API rather than a regex so that formatting is irrelevant: quoted
73
+ * any way, reordered, commented or reformatted, the key set is the same. Throws when
74
+ * the map cannot be found at all — a silently empty result would make every assertion
75
+ * below pass vacuously.
76
+ *
77
+ * @param {string} source - TypeScript source text
78
+ * @returns {string[]} extensions including the leading dot
79
+ */
80
+ function adapterMapKeys(source) {
81
+ const sf = ts.createSourceFile('analyzer.ts', source, ts.ScriptTarget.Latest, true);
82
+ const keys = [];
83
+ /**
84
+ * @param {import('typescript').Node} node
85
+ */
86
+ function visit(node) {
87
+ if (
88
+ ts.isVariableDeclaration(node) &&
89
+ node.name.getText(sf) === 'adapterMap' &&
90
+ node.initializer &&
91
+ ts.isObjectLiteralExpression(node.initializer)
92
+ ) {
93
+ for (const prop of node.initializer.properties) {
94
+ if (
95
+ (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) &&
96
+ prop.name &&
97
+ ts.isStringLiteralLike(prop.name)
98
+ ) {
99
+ keys.push(prop.name.text);
100
+ continue;
101
+ }
102
+ // A spread or a computed key would make this extraction return FEWER extensions
103
+ // than the map really holds: the derived expectation shrinks, every assertion
104
+ // still passes, and the guard quietly stops covering what it claims to cover.
105
+ // That is the exact failure shape this file was written to prevent, so fail
106
+ // loudly instead of under-reporting.
107
+ if (ts.isSpreadAssignment(prop) || ts.isComputedPropertyName(prop.name)) {
108
+ throw new Error(
109
+ 'adapterMap contains a spread or computed key, so this guard cannot derive ' +
110
+ 'the full extension set from it. Extend adapterMapKeys() rather than ' +
111
+ 'letting it silently under-report.',
112
+ );
113
+ }
114
+ }
115
+ }
116
+ ts.forEachChild(node, visit);
117
+ }
118
+ visit(sf);
119
+ if (keys.length === 0) {
120
+ throw new Error('adapterMap not found (or holds no string keys) in analyzer.ts');
121
+ }
122
+ return keys;
123
+ }
124
+
125
+ describe('principles walk covers every language the engine has an adapter for', () => {
126
+ test('AC-758-01: a .cs file in the target directory is offered to the checker', () => {
127
+ touch('cs-only/Program.cs', 'namespace Aot { class P { static void Main() {} } }\n');
128
+
129
+ const found = collectSourceFiles(path.join(TMP, 'cs-only'));
130
+
131
+ expect(found.map(f => path.basename(f))).toContain('Program.cs');
132
+ });
133
+
134
+ test('AC-758-02: every extension in adapterMap is collected by the walk', () => {
135
+ const expected = adapterMapKeys(fs.readFileSync(ANALYZER, 'utf8'));
136
+
137
+ // The C# entries are what this file exists for; assert them explicitly so a
138
+ // regression names the extension rather than just shrinking a count.
139
+ expect(expected).toContain('.cs');
140
+ expect(expected).toContain('.csx');
141
+
142
+ for (const ext of expected) {
143
+ touch(`all-ext/file${ext}`, '// fixture\n');
144
+ }
145
+
146
+ const names = new Set(
147
+ collectSourceFiles(path.join(TMP, 'all-ext')).map(f => path.basename(f)),
148
+ );
149
+
150
+ const missing = expected
151
+ .filter(ext => !names.has(`file${ext}`))
152
+ .map(ext => `${ext} is registered in adapterMap but the walk never collected file${ext}`);
153
+
154
+ expect(missing).toEqual([]);
155
+ });
156
+
157
+ test('AC-758-04: each adapterMap extension is genuinely analysable, not just listed', () => {
158
+ // adapterMap could name an extension whose adapter is broken. Confirm through the
159
+ // real entry point that a file with that extension produces an adapter at all.
160
+ //
161
+ // The function is asserted to BE a function first. Without that, a broken dynamic
162
+ // import (interop change, undefined export) would make every probe throw a
163
+ // TypeError, the catch below would swallow each one, `notAnalysable` would stay
164
+ // empty, and this test would report success while asserting nothing. A guard that
165
+ // goes green when its own instrument is missing is the defect class this file is
166
+ // about.
167
+ expect(typeof getAdapterForFile).toBe('function');
168
+
169
+ const expected = adapterMapKeys(fs.readFileSync(ANALYZER, 'utf8'));
170
+ const notAnalysable = [];
171
+ let answered = 0;
172
+ for (const ext of expected) {
173
+ touch(path.join('analysable', `probe${ext}`), '// fixture\n');
174
+ const abs = path.join(TMP, 'analysable', `probe${ext}`);
175
+ try {
176
+ const adapter = getAdapterForFile(abs);
177
+ answered += 1;
178
+ if (adapter === null) notAnalysable.push(ext);
179
+ } catch (err) {
180
+ // Adapters read their file in the constructor, so content the adapter rejects
181
+ // still proves registration. Anything else (a TypeError from a missing
182
+ // function) must not be mistaken for that, so the error type is checked.
183
+ const name = err && err.constructor ? err.constructor.name : '';
184
+ if (name === 'TypeError') throw err;
185
+ if (!/Could not read file|ENOENT|parse/i.test(String(err && err.message))) throw err;
186
+ answered += 1;
187
+ }
188
+ }
189
+ // Every extension must have produced a real answer, otherwise the loop above
190
+ // proved nothing.
191
+ expect(answered).toBe(expected.length);
192
+ expect(notAnalysable).toEqual([]);
193
+ });
194
+
195
+ test('AC-758-03: a directory of ONLY C# sources is not reported as empty', () => {
196
+ touch('only-cs/Alpha.cs', 'class A {}\n');
197
+ touch('only-cs/sub/Beta.cs', 'class B {}\n');
198
+
199
+ const found = collectSourceFiles(path.join(TMP, 'only-cs'));
200
+
201
+ expect(found.length).toBe(2);
202
+ expect(found.map(f => path.basename(f)).sort()).toEqual(['Alpha.cs', 'Beta.cs']);
203
+ });
204
+
205
+ test('AC-758-05: .cs files survive upper/lower case variants, end to end', () => {
206
+ // Both halves of the claim in the acceptance criterion, because either one alone
207
+ // leaves the original symptom reachable:
208
+ // - the WALK must collect `Program.CS`, and
209
+ // - `getAdapterForFile` must accept it, since it lowercases the extension before
210
+ // lookup. If that normalisation regressed while the walk still collected the
211
+ // file, the adapter would be null, the file would be skipped, and a directory of
212
+ // all-uppercase C# would once again report Files checked: 0.
213
+ touch('mixed-case/Upper.CS', 'class U {}\n');
214
+ touch('mixed-case/Mixed.Cs', 'class M {}\n');
215
+
216
+ const collected = collectSourceFiles(path.join(TMP, 'mixed-case'));
217
+ const names = collected.map(f => path.basename(f));
218
+
219
+ expect(names.sort()).toEqual(['Mixed.Cs', 'Upper.CS']);
220
+
221
+ // The end-to-end half: every file the walk collected must also resolve to an
222
+ // adapter, so "collected" cannot silently degrade into "collected then dropped".
223
+ for (const file of collected) {
224
+ expect(getAdapterForFile(file)).not.toBeNull();
225
+ }
226
+ });
227
+ });
@@ -2,6 +2,6 @@
2
2
  "verdict": "PASS",
3
3
  "license_type": "MIT",
4
4
  "sha256": "0e7ac423bf2c6e223b7c5b156f8cf72da49d748e56a1641402c31f22ad07dbb5",
5
- "checked_at": "2026-11-05T12:23:08.769Z",
5
+ "checked_at": "2026-11-05T16:16:15.014Z",
6
6
  "source": "network"
7
7
  }
package/lib/principles.js CHANGED
@@ -209,10 +209,18 @@ function findPrinciplesEntry() {
209
209
  // Extensions the principles engine has an adapter for. Kept as a literal rather
210
210
  // than imported from src/principles/analyzer.ts because this file must stay
211
211
  // loadable by plain Node with no transpile step (the package ships zero runtime
212
- // dependencies and no build). Must match `getAdapterForFile`'s adapterMap.
212
+ // dependencies and no build). Must match `getAdapterForFile`'s adapterMap —
213
+ // `__tests__/principles-csharp-coverage.test.js` now derives the expected set
214
+ // from that adapterMap and fails when the two drift, because "kept in sync by
215
+ // comment" did not survive contact with #717.
216
+ //
217
+ // `.cs`/`.csx` were the gap: analyzer.ts registered CSharpAdapter, this walk
218
+ // never offered the files, so `xp-gate principles <csharp-dir>` reported
219
+ // "Files checked: 0" — indistinguishable from "no violations".
213
220
  const SOURCE_EXTENSIONS = new Set([
214
221
  '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
215
222
  '.py', '.go', '.java', '.kt', '.kts',
223
+ '.cs', '.csx',
216
224
  '.dart', '.swift', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp',
217
225
  '.m', '.mm',
218
226
  ]);
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/xp-gate",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "description": "AI-driven development workflow: 6 quality gates + Delphi review + Sprint Flow",
5
5
  "bin": {
6
6
  "xp-gate": "bin/xp-gate.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xp-gate",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 phases), and Delphi multi-expert review (>=90% consensus).",
6
6
  "author": {
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/dsh-plugin-xp-gate",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "description": "XP-Gate deterministic quality gates + AI workflow skills as a DeepSeek Harness (DSH) native plugin: gate-check / gate-principles / gate-arch tools + 12 SKILL.md skills",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/opencode-plugin",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "XP-Gate quality gates + AI workflow skills for OpenCode",
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xp-gate",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 phases), and Delphi multi-expert review (>=90% consensus).",
6
6
  "author": {
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -3,7 +3,7 @@
3
3
  **Generated:** 2026-11-04
4
4
  **Commit:** eb2097b0
5
5
  **Branch:** sprint/2026-11-03-02
6
- **Version:** 0.36.0.0
6
+ **Version:** 0.36.1.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.