@veewo/gitnexus 1.5.0-rc.4 → 1.5.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.
- package/dist/benchmark/agent-context/runner.js +3 -0
- package/dist/benchmark/agent-context/runner.test.js +22 -0
- package/dist/benchmark/agent-context/tool-runner.d.ts +7 -6
- package/dist/benchmark/agent-safe-query-context/io.d.ts +2 -0
- package/dist/benchmark/agent-safe-query-context/io.js +86 -0
- package/dist/benchmark/agent-safe-query-context/io.test.d.ts +1 -0
- package/dist/benchmark/agent-safe-query-context/io.test.js +13 -0
- package/dist/benchmark/agent-safe-query-context/report.d.ts +57 -0
- package/dist/benchmark/agent-safe-query-context/report.js +159 -0
- package/dist/benchmark/agent-safe-query-context/report.test.d.ts +1 -0
- package/dist/benchmark/agent-safe-query-context/report.test.js +362 -0
- package/dist/benchmark/agent-safe-query-context/runner.d.ts +44 -0
- package/dist/benchmark/agent-safe-query-context/runner.js +406 -0
- package/dist/benchmark/agent-safe-query-context/runner.test.d.ts +1 -0
- package/dist/benchmark/agent-safe-query-context/runner.test.js +290 -0
- package/dist/benchmark/agent-safe-query-context/semantic-tuple.d.ts +20 -0
- package/dist/benchmark/agent-safe-query-context/semantic-tuple.js +225 -0
- package/dist/benchmark/agent-safe-query-context/semantic-tuple.test.d.ts +1 -0
- package/dist/benchmark/agent-safe-query-context/semantic-tuple.test.js +122 -0
- package/dist/benchmark/agent-safe-query-context/subagent-live.d.ts +47 -0
- package/dist/benchmark/agent-safe-query-context/subagent-live.js +128 -0
- package/dist/benchmark/agent-safe-query-context/subagent-live.test.d.ts +1 -0
- package/dist/benchmark/agent-safe-query-context/subagent-live.test.js +155 -0
- package/dist/benchmark/agent-safe-query-context/telemetry-tool.d.ts +9 -0
- package/dist/benchmark/agent-safe-query-context/telemetry-tool.js +77 -0
- package/dist/benchmark/agent-safe-query-context/types.d.ts +61 -0
- package/dist/benchmark/agent-safe-query-context/types.js +8 -0
- package/dist/benchmark/analyze-runner.d.ts +1 -1
- package/dist/benchmark/analyze-runner.js +4 -3
- package/dist/benchmark/analyze-runner.test.js +7 -0
- package/dist/benchmark/runtime-poc/provenance-artifact.d.ts +47 -0
- package/dist/benchmark/runtime-poc/provenance-artifact.js +89 -0
- package/dist/benchmark/runtime-poc/runner.d.ts +31 -0
- package/dist/benchmark/runtime-poc/runner.js +163 -0
- package/dist/benchmark/u2-e2e/hydration-policy-repeatability-runner.d.ts +8 -0
- package/dist/benchmark/u2-e2e/hydration-policy-repeatability-runner.js +21 -0
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.d.ts +0 -1
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.js +53 -51
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.test.js +0 -1
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.d.ts +1 -1
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.js +82 -18
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.js +1 -2
- package/dist/benchmark/u2-e2e/retrieval-runner.js +15 -7
- package/dist/benchmark/u2-e2e/retrieval-runner.test.js +46 -0
- package/dist/cli/ai-context.d.ts +0 -1
- package/dist/cli/ai-context.js +5 -6
- package/dist/cli/ai-context.test.js +8 -0
- package/dist/cli/analyze-options.js +58 -34
- package/dist/cli/analyze-options.test.js +57 -0
- package/dist/cli/analyze-runtime-summary.js +2 -0
- package/dist/cli/analyze-runtime-summary.test.js +12 -0
- package/dist/cli/analyze-summary.d.ts +4 -0
- package/dist/cli/analyze-summary.js +43 -0
- package/dist/cli/analyze-summary.test.js +65 -1
- package/dist/cli/analyze.d.ts +11 -0
- package/dist/cli/analyze.js +34 -5
- package/dist/cli/analyze.test.d.ts +1 -0
- package/dist/cli/analyze.test.js +25 -0
- package/dist/cli/benchmark-agent-context.js +1 -1
- package/dist/cli/benchmark-agent-safe-query-context.d.ts +20 -0
- package/dist/cli/benchmark-agent-safe-query-context.js +39 -0
- package/dist/cli/benchmark-agent-safe-query-context.test.d.ts +1 -0
- package/dist/cli/benchmark-agent-safe-query-context.test.js +271 -0
- package/dist/cli/benchmark-unity.js +1 -1
- package/dist/cli/benchmark-unity.test.js +5 -1
- package/dist/cli/benchmark.d.ts +29 -0
- package/dist/cli/benchmark.js +55 -0
- package/dist/cli/index.js +27 -2
- package/dist/cli/rule-lab.d.ts +3 -7
- package/dist/cli/rule-lab.js +13 -22
- package/dist/cli/rule-lab.test.js +23 -3
- package/dist/cli/scope-manifest-config.d.ts +9 -0
- package/dist/cli/scope-manifest-config.js +37 -0
- package/dist/cli/setup.js +40 -41
- package/dist/cli/setup.test.js +14 -14
- package/dist/cli/sync-manifest.d.ts +27 -0
- package/dist/cli/sync-manifest.js +200 -0
- package/dist/cli/sync-manifest.test.d.ts +1 -0
- package/dist/cli/sync-manifest.test.js +88 -0
- package/dist/cli/tool.d.ts +2 -0
- package/dist/cli/tool.js +2 -0
- package/dist/core/config/unity-config.d.ts +1 -1
- package/dist/core/config/unity-config.js +1 -1
- package/dist/core/ingestion/call-processor.d.ts +2 -1
- package/dist/core/ingestion/call-processor.js +28 -6
- package/dist/core/ingestion/heritage-processor.d.ts +2 -1
- package/dist/core/ingestion/heritage-processor.js +30 -7
- package/dist/core/ingestion/import-processor.d.ts +2 -1
- package/dist/core/ingestion/import-processor.js +28 -6
- package/dist/core/ingestion/parsing-processor.d.ts +5 -3
- package/dist/core/ingestion/parsing-processor.js +46 -13
- package/dist/core/ingestion/pipeline.js +100 -19
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.js +18 -20
- package/dist/core/ingestion/unity-parity-seed.d.ts +2 -1
- package/dist/core/ingestion/unity-parity-seed.js +8 -0
- package/dist/core/ingestion/unity-resource-processor.d.ts +11 -0
- package/dist/core/ingestion/unity-resource-processor.js +102 -0
- package/dist/core/ingestion/unity-resource-processor.test.js +449 -0
- package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +16 -1
- package/dist/core/ingestion/unity-runtime-binding-rules.js +193 -42
- package/dist/core/ingestion/workers/parse-worker.d.ts +2 -0
- package/dist/core/ingestion/workers/parse-worker.js +50 -6
- package/dist/core/lbug/csv-generator.test.js +2 -2
- package/dist/core/tree-sitter/csharp-define-profile.d.ts +6 -0
- package/dist/core/tree-sitter/csharp-define-profile.js +43 -0
- package/dist/core/tree-sitter/csharp-preproc-normalizer.d.ts +14 -0
- package/dist/core/tree-sitter/csharp-preproc-normalizer.js +261 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +10 -0
- package/dist/core/tree-sitter/parser-loader.js +19 -0
- package/dist/core/unity/doc-contract.test.d.ts +1 -0
- package/dist/core/unity/doc-contract.test.js +30 -0
- package/dist/core/unity/prefab-source-scan.d.ts +25 -0
- package/dist/core/unity/prefab-source-scan.js +152 -0
- package/dist/core/unity/prefab-source-scan.test.d.ts +1 -0
- package/dist/core/unity/prefab-source-scan.test.js +70 -0
- package/dist/core/unity/scan-context.d.ts +12 -0
- package/dist/core/unity/scan-context.js +50 -2
- package/dist/core/unity/scan-context.test.js +74 -0
- package/dist/mcp/local/agent-safe-response.d.ts +10 -0
- package/dist/mcp/local/agent-safe-response.js +639 -0
- package/dist/mcp/local/derived-process-reader.js +1 -1
- package/dist/mcp/local/local-backend.d.ts +18 -1
- package/dist/mcp/local/local-backend.js +319 -125
- package/dist/mcp/local/process-confidence.d.ts +1 -2
- package/dist/mcp/local/process-confidence.js +0 -3
- package/dist/mcp/local/process-confidence.test.js +4 -2
- package/dist/mcp/local/process-evidence.d.ts +1 -8
- package/dist/mcp/local/process-evidence.js +1 -23
- package/dist/mcp/local/process-evidence.test.js +2 -16
- package/dist/mcp/local/process-ref.d.ts +1 -1
- package/dist/mcp/local/runtime-chain-closure-evaluator.d.ts +33 -0
- package/dist/mcp/local/runtime-chain-closure-evaluator.js +273 -0
- package/dist/mcp/local/runtime-chain-graph-candidates.d.ts +23 -0
- package/dist/mcp/local/runtime-chain-graph-candidates.js +131 -0
- package/dist/mcp/local/runtime-chain-verify.d.ts +1 -1
- package/dist/mcp/local/runtime-chain-verify.js +149 -138
- package/dist/mcp/local/runtime-chain-verify.test.js +126 -68
- package/dist/mcp/local/runtime-claim-rule-registry.d.ts +4 -0
- package/dist/mcp/local/runtime-claim-rule-registry.js +4 -0
- package/dist/mcp/local/runtime-claim-rule-registry.test.js +37 -4
- package/dist/mcp/local/runtime-claim.d.ts +11 -0
- package/dist/mcp/local/runtime-claim.js +28 -0
- package/dist/mcp/local/unity-evidence-view.d.ts +1 -1
- package/dist/mcp/local/unity-evidence-view.js +1 -1
- package/dist/mcp/local/unity-evidence-view.test.js +22 -0
- package/dist/mcp/tools.js +51 -21
- package/dist/rule-lab/analyze.d.ts +2 -1
- package/dist/rule-lab/analyze.js +94 -59
- package/dist/rule-lab/analyze.test.js +238 -20
- package/dist/rule-lab/curate.d.ts +2 -1
- package/dist/rule-lab/curate.js +24 -3
- package/dist/rule-lab/curate.test.js +65 -0
- package/dist/rule-lab/curation-input-builder.d.ts +45 -0
- package/dist/rule-lab/curation-input-builder.js +133 -0
- package/dist/rule-lab/promote.js +80 -7
- package/dist/rule-lab/promote.test.js +150 -0
- package/dist/rule-lab/review-pack.d.ts +3 -0
- package/dist/rule-lab/review-pack.js +41 -1
- package/dist/rule-lab/review-pack.test.js +67 -0
- package/dist/rule-lab/types.d.ts +29 -0
- package/dist/types/pipeline.d.ts +16 -0
- package/package.json +14 -13
- package/scripts/check-sync-manifest-traceability.mjs +203 -0
- package/scripts/run-node-tests.mjs +61 -0
- package/scripts/tree-sitter-audit-classify.mjs +172 -0
- package/skills/_shared/unity-rule-authoring-contract.md +64 -0
- package/skills/_shared/unity-runtime-process-contract.md +16 -0
- package/skills/gitnexus-cli.md +44 -4
- package/skills/gitnexus-debugging.md +9 -0
- package/skills/gitnexus-exploring.md +66 -18
- package/skills/gitnexus-guide.md +42 -3
- package/skills/gitnexus-impact-analysis.md +8 -0
- package/skills/gitnexus-pr-review.md +8 -0
- package/skills/gitnexus-refactoring.md +8 -0
- package/skills/gitnexus-unity-rule-gen.md +66 -312
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const planArg = process.argv[2];
|
|
6
|
+
if (!planArg) {
|
|
7
|
+
console.error('Usage: node gitnexus/scripts/check-sync-manifest-traceability.mjs <plan.md>');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const root = process.cwd();
|
|
12
|
+
const planPath = path.resolve(root, planArg);
|
|
13
|
+
|
|
14
|
+
const requiredCriticalDc = {
|
|
15
|
+
'DC-01': {
|
|
16
|
+
semanticCases: [
|
|
17
|
+
{
|
|
18
|
+
id: 'directive parsing',
|
|
19
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
20
|
+
pattern: "resolveEffectiveAnalyzeOptions reads @extensions/@repoAlias/@embeddings from manifest",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'unknown directive fail-fast',
|
|
24
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
25
|
+
pattern: 'resolveEffectiveAnalyzeOptions rejects unknown manifest directives',
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
29
|
+
},
|
|
30
|
+
'DC-02': {
|
|
31
|
+
semanticCases: [
|
|
32
|
+
{
|
|
33
|
+
id: 'precedence merge case',
|
|
34
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
35
|
+
pattern: 'resolveEffectiveAnalyzeOptions enforces precedence CLI > manifest > meta',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
39
|
+
},
|
|
40
|
+
'DC-03': {
|
|
41
|
+
semanticCases: [
|
|
42
|
+
{
|
|
43
|
+
id: 'auto default sync-manifest load case',
|
|
44
|
+
file: 'gitnexus/src/cli/analyze.test.ts',
|
|
45
|
+
pattern: 'analyze auto-loads .gitnexus/sync-manifest.txt when CLI scope options are omitted',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze.test.js'],
|
|
49
|
+
},
|
|
50
|
+
'DC-04': {
|
|
51
|
+
semanticCases: [
|
|
52
|
+
{
|
|
53
|
+
id: 'mismatch prompt decision case',
|
|
54
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
55
|
+
pattern: 'when explicit CLI values differ from manifest, TTY mode asks whether to update manifest',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'update decision case',
|
|
59
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
60
|
+
pattern: 'policy=update rewrites manifest with normalized directives',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
commandMustInclude: [
|
|
64
|
+
'gitnexus/dist/cli/sync-manifest.test.js',
|
|
65
|
+
'gitnexus/dist/cli/analyze.test.js',
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
'DC-05': {
|
|
69
|
+
semanticCases: [
|
|
70
|
+
{
|
|
71
|
+
id: 'unknown directive fail-fast case',
|
|
72
|
+
file: 'gitnexus/src/cli/analyze-options.test.ts',
|
|
73
|
+
pattern: 'resolveEffectiveAnalyzeOptions rejects unknown manifest directives',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
commandMustInclude: ['gitnexus/dist/cli/analyze-options.test.js'],
|
|
77
|
+
},
|
|
78
|
+
'DC-08': {
|
|
79
|
+
semanticCases: [
|
|
80
|
+
{
|
|
81
|
+
id: 'placeholder rejection case',
|
|
82
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
83
|
+
pattern: 'rejects placeholder manifest path values',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'non-TTY policy gate case',
|
|
87
|
+
file: 'gitnexus/src/cli/sync-manifest.test.ts',
|
|
88
|
+
pattern: 'non-TTY without explicit policy exits with actionable error',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
commandMustInclude: [
|
|
92
|
+
'gitnexus/dist/cli/sync-manifest.test.js',
|
|
93
|
+
'gitnexus/dist/cli/analyze.test.js',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function normalizeCell(value) {
|
|
99
|
+
return value.trim().replace(/^`|`$/g, '').trim();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseTraceabilityRows(planText) {
|
|
103
|
+
const rows = [];
|
|
104
|
+
for (const line of planText.split(/\r?\n/)) {
|
|
105
|
+
if (!line.startsWith('DC-')) continue;
|
|
106
|
+
const parts = line.split(' | ').map((p) => p.trim());
|
|
107
|
+
if (parts.length < 6) continue;
|
|
108
|
+
|
|
109
|
+
const idMatch = parts[0].match(/^(DC-\d+)/);
|
|
110
|
+
if (!idMatch) continue;
|
|
111
|
+
|
|
112
|
+
rows.push({
|
|
113
|
+
id: idMatch[1],
|
|
114
|
+
criticality: parts[1],
|
|
115
|
+
mappedTasks: normalizeCell(parts[2]),
|
|
116
|
+
verificationCommand: normalizeCell(parts[3]),
|
|
117
|
+
artifactEvidenceField: normalizeCell(parts[4]),
|
|
118
|
+
failureSignal: normalizeCell(parts.slice(5).join(' | ')),
|
|
119
|
+
raw: line,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return rows;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function validateCriticalRowShape(row, errors) {
|
|
126
|
+
if (!row.mappedTasks || row.mappedTasks === '-') {
|
|
127
|
+
errors.push(`${row.id}: missing mapped tasks`);
|
|
128
|
+
}
|
|
129
|
+
if (!/Task\s*\d+/i.test(row.mappedTasks)) {
|
|
130
|
+
errors.push(`${row.id}: mapped tasks do not reference concrete task ids`);
|
|
131
|
+
}
|
|
132
|
+
if (!row.verificationCommand || row.verificationCommand === '-') {
|
|
133
|
+
errors.push(`${row.id}: missing verification command`);
|
|
134
|
+
}
|
|
135
|
+
if (!row.artifactEvidenceField || row.artifactEvidenceField === '-') {
|
|
136
|
+
errors.push(`${row.id}: missing artifact evidence field`);
|
|
137
|
+
}
|
|
138
|
+
if (!row.failureSignal || row.failureSignal === '-') {
|
|
139
|
+
errors.push(`${row.id}: missing failure signal`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function validateSemanticCases(dcId, config, errors) {
|
|
144
|
+
for (const semanticCase of config.semanticCases) {
|
|
145
|
+
const casePath = path.resolve(root, semanticCase.file);
|
|
146
|
+
let content = '';
|
|
147
|
+
try {
|
|
148
|
+
content = await fs.readFile(casePath, 'utf-8');
|
|
149
|
+
} catch {
|
|
150
|
+
errors.push(`${dcId}: missing semantic case file ${semanticCase.file}`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (!content.includes(semanticCase.pattern)) {
|
|
154
|
+
errors.push(`${dcId}: missing semantic case '${semanticCase.id}' in ${semanticCase.file}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function validateCommandCoverage(row, config, errors) {
|
|
160
|
+
for (const requiredFragment of config.commandMustInclude) {
|
|
161
|
+
if (!row.verificationCommand.includes(requiredFragment)) {
|
|
162
|
+
errors.push(`${row.id}: verification command missing '${requiredFragment}'`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function main() {
|
|
168
|
+
const planText = await fs.readFile(planPath, 'utf-8');
|
|
169
|
+
const rows = parseTraceabilityRows(planText);
|
|
170
|
+
const rowById = new Map(rows.map((row) => [row.id, row]));
|
|
171
|
+
const errors = [];
|
|
172
|
+
|
|
173
|
+
for (const dcId of Object.keys(requiredCriticalDc)) {
|
|
174
|
+
const row = rowById.get(dcId);
|
|
175
|
+
if (!row) {
|
|
176
|
+
errors.push(`missing critical row ${dcId} in Design Traceability Matrix`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (row.criticality !== 'critical') {
|
|
181
|
+
errors.push(`${dcId}: expected critical criticality, got '${row.criticality}'`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
validateCriticalRowShape(row, errors);
|
|
185
|
+
validateCommandCoverage(row, requiredCriticalDc[dcId], errors);
|
|
186
|
+
await validateSemanticCases(dcId, requiredCriticalDc[dcId], errors);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (errors.length > 0) {
|
|
190
|
+
console.error('Sync-manifest traceability check failed:\n');
|
|
191
|
+
for (const error of errors) {
|
|
192
|
+
console.error(`- ${error}`);
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log('Sync-manifest traceability check passed.');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
main().catch((error) => {
|
|
201
|
+
console.error(error?.stack || String(error));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { readdirSync, readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const repoRoot = path.resolve(__dirname, '..');
|
|
9
|
+
const srcRoot = path.join(repoRoot, 'src');
|
|
10
|
+
const distRoot = path.join(repoRoot, 'dist');
|
|
11
|
+
|
|
12
|
+
function walk(dir, out) {
|
|
13
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
14
|
+
const full = path.join(dir, entry.name);
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
walk(full, out);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (entry.isFile() && entry.name.endsWith('.test.ts')) {
|
|
20
|
+
out.push(full);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sourceTests = [];
|
|
26
|
+
walk(srcRoot, sourceTests);
|
|
27
|
+
|
|
28
|
+
const nodeTests = sourceTests
|
|
29
|
+
.filter((filePath) => {
|
|
30
|
+
const content = readFileSync(filePath, 'utf8');
|
|
31
|
+
return content.includes("from 'node:test'") || content.includes('from "node:test"');
|
|
32
|
+
})
|
|
33
|
+
.map((filePath) => {
|
|
34
|
+
const rel = path.relative(srcRoot, filePath).replace(/\.ts$/, '.js');
|
|
35
|
+
return path.join(distRoot, rel);
|
|
36
|
+
})
|
|
37
|
+
.sort();
|
|
38
|
+
|
|
39
|
+
if (nodeTests.length === 0) {
|
|
40
|
+
console.error('No node:test suites detected under src/**/*.test.ts');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const missing = nodeTests.filter((filePath) => !existsSync(filePath));
|
|
45
|
+
if (missing.length > 0) {
|
|
46
|
+
console.error('Missing compiled node:test files in dist/. Run build first.');
|
|
47
|
+
for (const filePath of missing.slice(0, 20)) {
|
|
48
|
+
console.error(`- ${filePath}`);
|
|
49
|
+
}
|
|
50
|
+
if (missing.length > 20) {
|
|
51
|
+
console.error(`... and ${missing.length - 20} more`);
|
|
52
|
+
}
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const result = spawnSync(process.execPath, ['--test', ...nodeTests], {
|
|
57
|
+
stdio: 'inherit',
|
|
58
|
+
cwd: repoRoot,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const CONTAINER_KEYS = ['class', 'interface', 'struct', 'record', 'delegate', 'enum'];
|
|
7
|
+
|
|
8
|
+
function toNumber(value) {
|
|
9
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
10
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
11
|
+
const parsed = Number(value);
|
|
12
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
13
|
+
}
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeContainerCounts(record) {
|
|
18
|
+
const counts = {
|
|
19
|
+
class: toNumber(record.class_count),
|
|
20
|
+
interface: toNumber(record.interface_count),
|
|
21
|
+
struct: toNumber(record.struct_count),
|
|
22
|
+
record: toNumber(record.record_count),
|
|
23
|
+
delegate: toNumber(record.delegate_count),
|
|
24
|
+
enum: toNumber(record.enum_count),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (record.container_counts && typeof record.container_counts === 'object') {
|
|
28
|
+
for (const key of CONTAINER_KEYS) {
|
|
29
|
+
counts[key] = toNumber(record.container_counts[key] ?? counts[key]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return counts;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function computeClassifiedType(record, containerCounts) {
|
|
37
|
+
const methodCount = toNumber(record.method_count);
|
|
38
|
+
const rootHasError = Boolean(record.root_has_error);
|
|
39
|
+
const rawErrorType = String(record.error_type || '');
|
|
40
|
+
const totalContainers = CONTAINER_KEYS.reduce((sum, key) => sum + containerCounts[key], 0);
|
|
41
|
+
const legacyMissingClass = methodCount > 0 && containerCounts.class === 0;
|
|
42
|
+
const missingContainer = methodCount > 0 && totalContainers === 0;
|
|
43
|
+
const isFalsePositiveLikely = legacyMissingClass && !missingContainer;
|
|
44
|
+
|
|
45
|
+
let errorType = 'ok';
|
|
46
|
+
if (rawErrorType === 'parse_throw') {
|
|
47
|
+
errorType = 'parse_throw';
|
|
48
|
+
} else if (rootHasError || rawErrorType === 'root_has_error') {
|
|
49
|
+
errorType = 'root_has_error';
|
|
50
|
+
} else if (missingContainer) {
|
|
51
|
+
errorType = 'missing_container_with_methods';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
errorType,
|
|
56
|
+
legacyMissingClass,
|
|
57
|
+
missingContainer,
|
|
58
|
+
isFalsePositiveLikely,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function classifyTreeSitterAuditRecords(records) {
|
|
63
|
+
const byType = {
|
|
64
|
+
parse_throw: 0,
|
|
65
|
+
root_has_error: 0,
|
|
66
|
+
missing_container_with_methods: 0,
|
|
67
|
+
ok: 0,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const containerTotals = {
|
|
71
|
+
class: 0,
|
|
72
|
+
interface: 0,
|
|
73
|
+
struct: 0,
|
|
74
|
+
record: 0,
|
|
75
|
+
delegate: 0,
|
|
76
|
+
enum: 0,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
let compatibilityMissingClassCount = 0;
|
|
80
|
+
let falsePositiveLikelyCount = 0;
|
|
81
|
+
|
|
82
|
+
const classified = records.map((record) => {
|
|
83
|
+
const containerCounts = normalizeContainerCounts(record);
|
|
84
|
+
const classification = computeClassifiedType(record, containerCounts);
|
|
85
|
+
const compatibilityTags = [];
|
|
86
|
+
|
|
87
|
+
if (classification.legacyMissingClass) {
|
|
88
|
+
compatibilityTags.push('missing_class_with_methods');
|
|
89
|
+
compatibilityMissingClassCount += 1;
|
|
90
|
+
}
|
|
91
|
+
if (classification.isFalsePositiveLikely) {
|
|
92
|
+
falsePositiveLikelyCount += 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key of CONTAINER_KEYS) {
|
|
96
|
+
containerTotals[key] += containerCounts[key];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
byType[classification.errorType] += 1;
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
...record,
|
|
103
|
+
container_counts: containerCounts,
|
|
104
|
+
classified_error_type: classification.errorType,
|
|
105
|
+
compatibility_tags: compatibilityTags,
|
|
106
|
+
is_false_positive_likely: classification.isFalsePositiveLikely,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
summary: {
|
|
112
|
+
total: classified.length,
|
|
113
|
+
byType,
|
|
114
|
+
compatibility: {
|
|
115
|
+
missing_class_with_methods: compatibilityMissingClassCount,
|
|
116
|
+
},
|
|
117
|
+
falsePositiveLikely: falsePositiveLikelyCount,
|
|
118
|
+
containerTotals,
|
|
119
|
+
},
|
|
120
|
+
records: classified,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseArgs(argv) {
|
|
125
|
+
const args = {};
|
|
126
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
127
|
+
const arg = argv[i];
|
|
128
|
+
if (arg === '--input') args.input = argv[i + 1];
|
|
129
|
+
if (arg === '--output') args.output = argv[i + 1];
|
|
130
|
+
}
|
|
131
|
+
return args;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function readJsonl(inputPath) {
|
|
135
|
+
const raw = await fs.readFile(inputPath, 'utf-8');
|
|
136
|
+
return raw
|
|
137
|
+
.split(/\r?\n/)
|
|
138
|
+
.map((line) => line.trim())
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.map((line) => JSON.parse(line));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function writeOutput(outputPath, data) {
|
|
144
|
+
const resolved = path.resolve(outputPath);
|
|
145
|
+
await fs.mkdir(path.dirname(resolved), { recursive: true });
|
|
146
|
+
await fs.writeFile(resolved, `${JSON.stringify(data, null, 2)}\n`, 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function main() {
|
|
150
|
+
const args = parseArgs(process.argv);
|
|
151
|
+
if (!args.input) {
|
|
152
|
+
console.error('Usage: node scripts/tree-sitter-audit-classify.mjs --input <diagnostics.jsonl> [--output <report.json>]');
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const records = await readJsonl(path.resolve(args.input));
|
|
158
|
+
const report = classifyTreeSitterAuditRecords(records);
|
|
159
|
+
|
|
160
|
+
if (args.output) {
|
|
161
|
+
await writeOutput(args.output, report);
|
|
162
|
+
} else {
|
|
163
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
168
|
+
main().catch((error) => {
|
|
169
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
170
|
+
process.exitCode = 1;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Unity Rule Authoring Contract
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
This contract defines the stable public authoring workflow for
|
|
6
|
+
`gitnexus-unity-rule-gen`.
|
|
7
|
+
|
|
8
|
+
The only public path is direct rule authoring and validation:
|
|
9
|
+
|
|
10
|
+
`approved/*.yaml -> rule-lab compile -> analyze -> CLI validation`
|
|
11
|
+
|
|
12
|
+
## Workflow Position
|
|
13
|
+
|
|
14
|
+
1. `gap-lab` is historical context only and not part of the active workflow.
|
|
15
|
+
2. Default authoring path is reduced `rule-lab` for sparse irregular gaps.
|
|
16
|
+
3. Query-time runtime closure remains graph-only.
|
|
17
|
+
|
|
18
|
+
## Input Schema
|
|
19
|
+
|
|
20
|
+
Each authoring item must be an exact source/target pair (or explicit pair set):
|
|
21
|
+
|
|
22
|
+
- `source_class`
|
|
23
|
+
- `source_method`
|
|
24
|
+
- `target_class`
|
|
25
|
+
- `target_method`
|
|
26
|
+
- `expected_missing_hop` (short text)
|
|
27
|
+
|
|
28
|
+
If multiple anchors match, user must select the intended anchor explicitly.
|
|
29
|
+
Auto-guessing ambiguous anchors is forbidden.
|
|
30
|
+
|
|
31
|
+
## Mandatory Guards
|
|
32
|
+
|
|
33
|
+
1. Duplicate-prevention:
|
|
34
|
+
- Block proposals already covered by `.gitnexus/rules/approved/*.yaml`.
|
|
35
|
+
2. Fail-closed binding resolution:
|
|
36
|
+
- Unresolved bindings block progress.
|
|
37
|
+
- `UnknownClass` / `UnknownMethod` placeholders are forbidden.
|
|
38
|
+
3. Non-empty evidence before promote:
|
|
39
|
+
- `confirmed_chain.steps` (or equivalent) must be non-empty.
|
|
40
|
+
|
|
41
|
+
## Artifact Expectations
|
|
42
|
+
|
|
43
|
+
Primary artifacts are under `.gitnexus/rules/lab/runs/<run_id>/...`.
|
|
44
|
+
|
|
45
|
+
Run/slice identifiers are internal artifact locators. Public operator guidance must
|
|
46
|
+
not require run orchestration as the primary flow.
|
|
47
|
+
|
|
48
|
+
## Event/Delegate Boundary
|
|
49
|
+
|
|
50
|
+
Event/delegate system-wide coverage is analyzer-native scope:
|
|
51
|
+
|
|
52
|
+
- capture `assignment_expression` (`+=`, `-=`)
|
|
53
|
+
- index delegate/action field symbols
|
|
54
|
+
- capture generic event-type metadata (`Raise<T>` / `Listen<T>`)
|
|
55
|
+
|
|
56
|
+
Rule authoring is only for sparse, explicitly scoped residual gaps.
|
|
57
|
+
|
|
58
|
+
## Verification Contract
|
|
59
|
+
|
|
60
|
+
1. Promote only after mandatory guards pass.
|
|
61
|
+
2. Compile approved rules before analyze.
|
|
62
|
+
3. Verify in a fresh CLI process (`gitnexus cypher` / `gitnexus query`).
|
|
63
|
+
4. Under `hydration_policy=strict` with `fallbackToCompact=true`, parity rerun
|
|
64
|
+
is required before final closure conclusion.
|
|
@@ -13,11 +13,16 @@ Load this contract when any of the following is true:
|
|
|
13
13
|
|
|
14
14
|
## Required Workflow
|
|
15
15
|
|
|
16
|
+
Use this order: `discovery -> seed narrowing -> closure verification`.
|
|
17
|
+
|
|
16
18
|
1. Run `query/context` with `unity_resources: "on"` and `unity_hydration_mode: "compact"` first.
|
|
19
|
+
- For `response_profile=slim`, read semantic tiers in order: `facts -> closure -> clues`.
|
|
20
|
+
- In strict-anchor mode, never let `clues` become the first-screen default when `facts` has high/medium leads.
|
|
17
21
|
2. If `hydrationMeta.needsParityRetry === true`, rerun with `unity_hydration_mode: "parity"` before conclusions.
|
|
18
22
|
3. Do not conclude "no runtime chain" from empty `processes` alone.
|
|
19
23
|
4. If Unity evidence exists, continue stitching:
|
|
20
24
|
- `processes`
|
|
25
|
+
- `resource_chains` for graph-backed `UNITY_ASSET_GUID_REF -> UNITY_GRAPH_NODE_SCRIPT_REF` bridges
|
|
21
26
|
- `resourceBindings`
|
|
22
27
|
- asset/meta mapping anchors
|
|
23
28
|
- runtime candidate symbols
|
|
@@ -26,6 +31,8 @@ Load this contract when any of the following is true:
|
|
|
26
31
|
- `target`
|
|
27
32
|
- `next_command`
|
|
28
33
|
6. Semantic closure requires hop anchors/evidence anchors for each stitched step.
|
|
34
|
+
7. Treat `clues` as narrowing evidence (`clue`) and never as standalone closure proof.
|
|
35
|
+
8. Strong graph hops can coexist with failed closure; report as partial bridge evidence until verifier-core reaches `verified_full`.
|
|
29
36
|
|
|
30
37
|
## Optional Strong Verification
|
|
31
38
|
|
|
@@ -33,6 +40,15 @@ For Reload-focused confirmation, request on-demand verification:
|
|
|
33
40
|
|
|
34
41
|
- pass `runtime_chain_verify: "on-demand"` in MCP tools, or
|
|
35
42
|
- use CLI `--runtime-chain-verify on-demand`.
|
|
43
|
+
- `queryText` is not a verifier matching signal in graph-only mode; use structured anchors/resource evidence for closure.
|
|
36
44
|
|
|
37
45
|
When on-demand verification is used, report `runtime_chain.status`, `evidence_level`, `hops`, and `gaps` before final risk/closure statements.
|
|
38
46
|
|
|
47
|
+
|
|
48
|
+
## Runtime-Chain Closure Guard
|
|
49
|
+
|
|
50
|
+
- Treat runtime-chain outputs as two layers:
|
|
51
|
+
- `verifier-core`: binary verifier result (`verified_full` | `failed`)
|
|
52
|
+
- `policy-adjusted`: user-visible result after hydration policy is applied
|
|
53
|
+
- If `hydration_policy=strict` and `hydrationMeta.fallbackToCompact=true`, the result is downgraded policy-adjusted output and is not closure.
|
|
54
|
+
- In that downgraded state, rerun with parity before final conclusions.
|
package/skills/gitnexus-cli.md
CHANGED
|
@@ -5,7 +5,25 @@ description: "Use when the user needs to run GitNexus CLI commands like analyze/
|
|
|
5
5
|
|
|
6
6
|
# GitNexus CLI Commands
|
|
7
7
|
|
|
8
|
-
Use one command alias in the session so every CLI/MCP call stays on one version line. After `setup`,
|
|
8
|
+
Use one command alias in the session so every CLI/MCP call stays on one version line. After `setup`, use `~/.gitnexus/config.json` as the CLI package spec source (`cliPackageSpec` first, then `cliVersion`). MCP wiring and skill install locations are scope-dependent (`project` vs `global`).
|
|
9
|
+
|
|
10
|
+
### setup — choose scope explicitly
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
gitnexus setup --scope project --agent codex --cli-spec @veewo/gitnexus@<version>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Rules:
|
|
17
|
+
|
|
18
|
+
- If user asks "setup this repository" / "本仓库 setup", use `--scope project`.
|
|
19
|
+
- `--scope project` updates repo-local files:
|
|
20
|
+
- Codex MCP config: `.codex/config.toml`
|
|
21
|
+
- Skills: `.agents/skills/gitnexus/`
|
|
22
|
+
- `--scope global` updates user-global files:
|
|
23
|
+
- Codex MCP config: `~/.codex/config.toml`
|
|
24
|
+
- Skills: `~/.agents/skills/gitnexus/`
|
|
25
|
+
- `--scope global` does not overwrite repo-local `.agents/skills` or `.codex/config.toml`.
|
|
26
|
+
- Never rely on setup defaults for scope; pass `--scope` explicitly to avoid global/project mismatch.
|
|
9
27
|
|
|
10
28
|
```bash
|
|
11
29
|
if command -v gitnexus >/dev/null 2>&1; then
|
|
@@ -46,16 +64,30 @@ Run from the project root. This parses all source files, builds the knowledge gr
|
|
|
46
64
|
| -------------------------- | ----------------------------------------------------------------------------------------- |
|
|
47
65
|
| `--force` | Force full re-index even if up to date |
|
|
48
66
|
| `--embeddings` | Enable embedding generation for semantic search (off by default) |
|
|
49
|
-
| `--extensions <ext>` | Limit parsing to specific file types (e.g., `--extensions ".cs
|
|
67
|
+
| `--extensions <ext>` | Limit parsing to specific file types (comma-separated, e.g., `--extensions ".cs,.meta"`) |
|
|
68
|
+
| `--csharp-define-csproj <path>` | Load C# `DefineConstants` from a `.csproj` and normalize `#if/#elif/#else/#endif` before parsing |
|
|
50
69
|
| `--scope-prefix <prefix>` | Limit analysis to a path prefix (e.g., `--scope-prefix Assets/` for Unity) |
|
|
51
70
|
| `--scope-manifest <file>` | Read scope rules from a manifest file (e.g., `.gitnexus/sync-manifest.txt`) |
|
|
71
|
+
| `--sync-manifest-policy <policy>` | Drift policy when explicit CLI values differ from manifest directives: `ask|update|keep|error` |
|
|
52
72
|
| `--skills` | Generate repo-specific skill files from detected code communities |
|
|
53
73
|
|
|
54
|
-
**Scope manifest syntax:**
|
|
74
|
+
**Scope manifest syntax:** Non-`@` lines are path-prefix scope rules (same semantics as before). `@key=value` directives set analyze options: `@extensions=<csv>`, `@repoAlias=<name>`, `@embeddings=<true|false>`. Unknown directives fail fast.
|
|
75
|
+
|
|
76
|
+
**Defaulting + drift guard:** If `.gitnexus/sync-manifest.txt` exists and you do not pass `--scope-manifest`/`--scope-prefix`, analyze auto-uses that file. When explicit CLI values (`--extensions`, `--repo-alias`, `--embeddings`) differ from manifest directives, CLI follows `--sync-manifest-policy` (default `ask`; non-TTY requires explicit policy).
|
|
55
77
|
|
|
56
78
|
**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook runs `analyze` automatically after `git commit` and `git merge`, preserving embeddings if previously generated.
|
|
57
79
|
|
|
58
|
-
**Unity projects:** Add `--extensions ".cs
|
|
80
|
+
**Unity projects:** Add `--extensions ".cs,.meta"` to ensure Unity asset edges (`UNITY_ASSET_GUID_REF`, `UNITY_COMPONENT_INSTANCE`) are parsed. Add `--scope-prefix Assets/` to limit scope if all code lives under `Assets/`.
|
|
81
|
+
|
|
82
|
+
**C# conditional-compilation projects (recommended):**
|
|
83
|
+
|
|
84
|
+
- Unity: pass `--csharp-define-csproj /path/to/Assembly-CSharp.csproj` (for neonspark, use `/Volumes/Shuttle/projects/neonspark/Assembly-CSharp.csproj`).
|
|
85
|
+
- Non-Unity: discover candidate project files first, then pass the intended one explicitly:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
rg --files -g '*.csproj'
|
|
89
|
+
$GN analyze --extensions ".cs" --csharp-define-csproj <picked-project>.csproj
|
|
90
|
+
```
|
|
59
91
|
|
|
60
92
|
### status — Check index freshness
|
|
61
93
|
|
|
@@ -157,3 +189,11 @@ $GN unity-ui-trace "Assets/NEON/VeewoUI/Uxml/BarScreen/Patch/PatchItemPreview.ux
|
|
|
157
189
|
- **"Not inside a git repository"**: Run from a directory inside a git repo
|
|
158
190
|
- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server
|
|
159
191
|
- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding
|
|
192
|
+
|
|
193
|
+
## Runtime-Chain Closure Guard
|
|
194
|
+
|
|
195
|
+
- Treat runtime-chain outputs as two layers:
|
|
196
|
+
- `verifier-core`: binary verifier result (`verified_full` | `failed`)
|
|
197
|
+
- `policy-adjusted`: user-visible result after hydration policy is applied
|
|
198
|
+
- If `hydration_policy=strict` and `hydrationMeta.fallbackToCompact=true`, the result is downgraded policy-adjusted output and is not closure.
|
|
199
|
+
- In that downgraded state, rerun with parity before final conclusions.
|
|
@@ -107,3 +107,12 @@ RETURN [n IN nodes(path) | n.name] AS chain
|
|
|
107
107
|
|
|
108
108
|
4. Root cause: fetchRates calls external API without proper timeout
|
|
109
109
|
```
|
|
110
|
+
|
|
111
|
+
## Runtime-Chain Closure Guard
|
|
112
|
+
|
|
113
|
+
- Query-time runtime closure is **graph-only** and does not require `verification_rules` / `trigger_tokens` matching.
|
|
114
|
+
- Treat runtime-chain outputs as two layers:
|
|
115
|
+
- `verifier-core`: binary verifier result (`verified_full` | `failed`)
|
|
116
|
+
- `policy-adjusted`: user-visible result after hydration policy is applied
|
|
117
|
+
- If `hydration_policy=strict` and `hydrationMeta.fallbackToCompact=true`, the result is downgraded policy-adjusted output and is not closure.
|
|
118
|
+
- In that downgraded state, rerun with parity before final conclusions.
|