@veewo/gitnexus 1.5.0 → 1.5.2
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/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.js +2 -12
- package/dist/cli/ai-context.test.js +8 -0
- package/dist/cli/analyze-runtime-summary.js +1 -0
- package/dist/cli/analyze-runtime-summary.test.js +2 -0
- package/dist/cli/analyze-summary.d.ts +2 -0
- package/dist/cli/analyze-summary.js +24 -0
- package/dist/cli/analyze-summary.test.js +65 -1
- package/dist/cli/analyze.js +5 -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.d.ts +29 -0
- package/dist/cli/benchmark.js +55 -0
- package/dist/cli/index.js +23 -0
- 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/tool.d.ts +2 -0
- package/dist/cli/tool.js +2 -0
- package/dist/core/config/unity-config.d.ts +0 -1
- package/dist/core/config/unity-config.js +0 -1
- package/dist/core/ingestion/pipeline.js +35 -6
- 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 +15 -0
- package/dist/core/ingestion/unity-runtime-binding-rules.js +178 -30
- package/dist/core/lbug/csv-generator.test.js +2 -2
- 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 +3 -0
- package/package.json +4 -3
- package/scripts/run-node-tests.mjs +61 -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 +8 -0
- 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
|
@@ -5,10 +5,43 @@ import path from 'node:path';
|
|
|
5
5
|
import { test } from 'vitest';
|
|
6
6
|
import { RuleRegistryLoadError, loadRuleRegistry } from './runtime-claim-rule-registry.js';
|
|
7
7
|
test('loads active runtime claim rules from project catalog', async () => {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-runtime-claim-rules-'));
|
|
9
|
+
const repoPath = path.join(tempRoot, 'repo');
|
|
10
|
+
const rulesRoot = path.join(repoPath, '.gitnexus', 'rules');
|
|
11
|
+
await fs.mkdir(path.join(rulesRoot, 'approved'), { recursive: true });
|
|
12
|
+
await fs.writeFile(path.join(rulesRoot, 'catalog.json'), JSON.stringify({
|
|
13
|
+
rules: [
|
|
14
|
+
{
|
|
15
|
+
id: 'demo.reload.rule.v1',
|
|
16
|
+
version: '1.2.3',
|
|
17
|
+
file: 'approved/demo.reload.rule.v1.yaml',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
}), 'utf-8');
|
|
21
|
+
await fs.writeFile(path.join(rulesRoot, 'approved', 'demo.reload.rule.v1.yaml'), [
|
|
22
|
+
'id: demo.reload.rule.v1',
|
|
23
|
+
'version: 1.2.3',
|
|
24
|
+
'trigger_family: reload',
|
|
25
|
+
'resource_types:',
|
|
26
|
+
' - asset',
|
|
27
|
+
'host_base_type:',
|
|
28
|
+
' - ReloadBase',
|
|
29
|
+
'required_hops:',
|
|
30
|
+
' - resource',
|
|
31
|
+
'guarantees:',
|
|
32
|
+
' - reload_chain_closed',
|
|
33
|
+
'non_guarantees:',
|
|
34
|
+
' - no_runtime_execution',
|
|
35
|
+
'next_action: gitnexus query "reload"',
|
|
36
|
+
].join('\n'), 'utf-8');
|
|
37
|
+
try {
|
|
38
|
+
const registry = await loadRuleRegistry(repoPath);
|
|
39
|
+
assert.equal(registry.activeRules[0].id, 'demo.reload.rule.v1');
|
|
40
|
+
assert.equal(registry.activeRules[0].version, '1.2.3');
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
44
|
+
}
|
|
12
45
|
});
|
|
13
46
|
test('throws rule_catalog_missing when target repo has no catalog (no ancestor fallback)', async () => {
|
|
14
47
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'gitnexus-runtime-claim-rules-'));
|
|
@@ -16,9 +16,19 @@ export interface RuntimeClaim {
|
|
|
16
16
|
non_guarantees: string[];
|
|
17
17
|
hops: RuntimeChainHop[];
|
|
18
18
|
gaps: RuntimeChainGap[];
|
|
19
|
+
verification_core_status?: 'verified_full' | 'failed';
|
|
20
|
+
verification_core_evidence_level?: RuntimeChainEvidenceLevel;
|
|
21
|
+
policy_adjusted?: boolean;
|
|
22
|
+
policy_adjust_reason?: string;
|
|
19
23
|
reason?: RuntimeClaimReason;
|
|
20
24
|
next_action?: string;
|
|
21
25
|
}
|
|
26
|
+
type HydrationPolicyOption = 'fast' | 'balanced' | 'strict';
|
|
27
|
+
export declare function adjustRuntimeClaimForPolicy(input: {
|
|
28
|
+
claim: RuntimeClaim;
|
|
29
|
+
hydrationPolicy: HydrationPolicyOption;
|
|
30
|
+
fallbackToCompact: boolean;
|
|
31
|
+
}): RuntimeClaim;
|
|
22
32
|
export declare function buildRuntimeClaimFromRule(input: {
|
|
23
33
|
rule: RuntimeClaimRule;
|
|
24
34
|
status: Exclude<RuntimeChainStatus, 'pending'>;
|
|
@@ -36,3 +46,4 @@ export declare function buildReloadRuntimeClaim(input: {
|
|
|
36
46
|
reason?: RuntimeClaimReason;
|
|
37
47
|
next_action?: string;
|
|
38
48
|
}): RuntimeClaim;
|
|
49
|
+
export {};
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
export function adjustRuntimeClaimForPolicy(input) {
|
|
2
|
+
const base = input.claim;
|
|
3
|
+
const coreStatus = base.status === 'verified_full' ? 'verified_full' : 'failed';
|
|
4
|
+
const adjusted = {
|
|
5
|
+
...base,
|
|
6
|
+
verification_core_status: coreStatus,
|
|
7
|
+
verification_core_evidence_level: base.evidence_level,
|
|
8
|
+
policy_adjusted: false,
|
|
9
|
+
};
|
|
10
|
+
if (input.hydrationPolicy === 'strict' && input.fallbackToCompact) {
|
|
11
|
+
let changed = false;
|
|
12
|
+
if (adjusted.status === 'verified_full') {
|
|
13
|
+
adjusted.status = 'verified_partial';
|
|
14
|
+
changed = true;
|
|
15
|
+
}
|
|
16
|
+
if (adjusted.evidence_level === 'verified_chain' || adjusted.status === 'verified_partial') {
|
|
17
|
+
if (adjusted.evidence_level !== 'verified_segment') {
|
|
18
|
+
adjusted.evidence_level = 'verified_segment';
|
|
19
|
+
changed = true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (changed) {
|
|
23
|
+
adjusted.policy_adjusted = true;
|
|
24
|
+
adjusted.policy_adjust_reason = 'strict_fallback_to_compact';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return adjusted;
|
|
28
|
+
}
|
|
1
29
|
function resolveNonGuarantees(rule) {
|
|
2
30
|
if (rule && Array.isArray(rule.non_guarantees) && rule.non_guarantees.length > 0) {
|
|
3
31
|
return [...rule.non_guarantees];
|
|
@@ -10,7 +10,7 @@ export interface UnityEvidenceMeta {
|
|
|
10
10
|
}
|
|
11
11
|
export interface UnityEvidenceViewResult {
|
|
12
12
|
resourceBindings: ResolvedUnityBinding[];
|
|
13
|
-
serializedFields
|
|
13
|
+
serializedFields?: UnitySerializedFields;
|
|
14
14
|
evidence_meta: UnityEvidenceMeta;
|
|
15
15
|
filter_diagnostics: string[];
|
|
16
16
|
}
|
|
@@ -89,7 +89,7 @@ export function buildUnityEvidenceView(input) {
|
|
|
89
89
|
};
|
|
90
90
|
return {
|
|
91
91
|
resourceBindings: filtered,
|
|
92
|
-
serializedFields: aggregateSerializedFields(filtered),
|
|
92
|
+
serializedFields: input.mode === 'full' ? aggregateSerializedFields(filtered) : undefined,
|
|
93
93
|
evidence_meta,
|
|
94
94
|
filter_diagnostics: diagnostics,
|
|
95
95
|
};
|
|
@@ -36,4 +36,26 @@ test('unity evidence view emits truncation metadata and fetch hint', () => {
|
|
|
36
36
|
assert.equal(out.evidence_meta.truncated, true);
|
|
37
37
|
assert.ok(out.evidence_meta.omitted_count > 0);
|
|
38
38
|
assert.match(out.evidence_meta.next_fetch_hint || '', /unity_evidence_mode=full/i);
|
|
39
|
+
assert.equal(out.serializedFields, undefined);
|
|
40
|
+
});
|
|
41
|
+
test('unity evidence view keeps serialized fields in full mode', () => {
|
|
42
|
+
const out = buildUnityEvidenceView({
|
|
43
|
+
resourceBindings: [
|
|
44
|
+
{
|
|
45
|
+
resourcePath: 'Assets/A.prefab',
|
|
46
|
+
resourceType: 'prefab',
|
|
47
|
+
bindingKind: 'direct',
|
|
48
|
+
componentObjectId: '1',
|
|
49
|
+
evidence: { line: 1, lineText: 'x' },
|
|
50
|
+
serializedFields: {
|
|
51
|
+
scalarFields: [{ name: 'scalarA', sourceLayer: 'base' }],
|
|
52
|
+
referenceFields: [{ name: 'refA', sourceLayer: 'base' }],
|
|
53
|
+
},
|
|
54
|
+
resolvedReferences: [],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
mode: 'full',
|
|
58
|
+
});
|
|
59
|
+
assert.equal(out.serializedFields?.scalarFields.length, 1);
|
|
60
|
+
assert.equal(out.serializedFields?.referenceFields.length, 1);
|
|
39
61
|
});
|
package/dist/mcp/tools.js
CHANGED
|
@@ -34,19 +34,32 @@ Returns results grouped by process (execution flow):
|
|
|
34
34
|
- processes: ranked execution flows with relevance priority
|
|
35
35
|
- process_symbols: all symbols in those flows with file locations and module (functional area)
|
|
36
36
|
- definitions: standalone types/interfaces not in any process
|
|
37
|
-
- processes[].evidence_mode: direct_step | method_projected
|
|
37
|
+
- processes[].evidence_mode: direct_step | method_projected
|
|
38
38
|
- processes[].confidence: high | medium | low
|
|
39
39
|
- processes[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
40
40
|
- processes[].runtime_chain_confidence: high | medium | low
|
|
41
41
|
- processes[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain
|
|
42
42
|
- processes[].verification_hint: { action, target, next_command } (required when confidence=low)
|
|
43
|
-
- process_symbols[].process_evidence_mode: direct_step | method_projected
|
|
43
|
+
- process_symbols[].process_evidence_mode: direct_step | method_projected
|
|
44
44
|
- process_symbols[].process_confidence: high | medium | low
|
|
45
45
|
- process_symbols[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
46
46
|
- process_symbols[].runtime_chain_confidence: high | medium | low
|
|
47
47
|
- process_symbols[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain
|
|
48
48
|
- process_symbols[].verification_hint: { action, target, next_command }
|
|
49
49
|
|
|
50
|
+
Default response_profile=slim shape:
|
|
51
|
+
- summary, candidates, process_hints, resource_hints, decision, upgrade_hints, runtime_preview
|
|
52
|
+
- facts, closure, clues, tier_envelope
|
|
53
|
+
- missing_proof_targets, suggested_context_targets
|
|
54
|
+
- read order in strict-anchor mode: facts -> closure -> clues
|
|
55
|
+
- suggested_context_targets[]: { name, uid?, filePath?, why } for direct context disambiguation
|
|
56
|
+
- upgrade_hints may include exact \`context --uid\` follow-ups when same-name symbols are ambiguous
|
|
57
|
+
- decision.recommended_follow_up prefers narrowing hints (for example resource_path_prefix/name) before response_profile=full fallback
|
|
58
|
+
- response_profile=slim is the default and sufficient for all normal agent workflows
|
|
59
|
+
- response_profile=full is for debugging and deep evidence inspection only
|
|
60
|
+
- recommended runtime retrieval sequence: discovery -> seed narrowing -> closure verification
|
|
61
|
+
- strong graph hops can coexist with failed closure when verifier-core remains failed
|
|
62
|
+
|
|
50
63
|
Hybrid ranking: BM25 keyword + semantic vector search, ranked by Reciprocal Rank Fusion.
|
|
51
64
|
Supports optional scope controls for noisy codebases:
|
|
52
65
|
- scope_preset=unity-gameplay to prioritize project gameplay code and suppress plugin-heavy paths.
|
|
@@ -56,6 +69,9 @@ Includes optional Unity retrieval contract:
|
|
|
56
69
|
- Set unity_resources=on|auto to include Unity resource evidence.
|
|
57
70
|
- Default unity_hydration_mode=compact (fast path).
|
|
58
71
|
- Check response hydrationMeta: when needsParityRetry=true, rerun with unity_hydration_mode=parity for completeness.
|
|
72
|
+
- Runtime-chain semantics are two-layered:
|
|
73
|
+
- verifier-core: binary (verified_full | failed)
|
|
74
|
+
- policy-adjusted: query-visible result; under strict policy fallback (hydrationMeta.fallbackToCompact=true) this may downgrade to partial semantics.
|
|
59
75
|
- Returns next_hops[] with ranked follow-up actions when Unity evidence is available.`,
|
|
60
76
|
inputSchema: {
|
|
61
77
|
type: 'object',
|
|
@@ -66,6 +82,12 @@ Includes optional Unity retrieval contract:
|
|
|
66
82
|
limit: { type: 'number', description: 'Max processes to return (default: 5)', default: 5 },
|
|
67
83
|
max_symbols: { type: 'number', description: 'Max symbols per process (default: 10)', default: 10 },
|
|
68
84
|
include_content: { type: 'boolean', description: 'Include full symbol source code (default: false)', default: false },
|
|
85
|
+
response_profile: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
enum: ['slim', 'full'],
|
|
88
|
+
description: 'Response payload profile: slim (default, sufficient for normal workflows) or full (debug-only for deep evidence inspection).',
|
|
89
|
+
default: 'slim',
|
|
90
|
+
},
|
|
69
91
|
scope_preset: {
|
|
70
92
|
type: 'string',
|
|
71
93
|
enum: ['unity-gameplay', 'unity-all'],
|
|
@@ -188,17 +210,32 @@ AFTER THIS: Use impact() if planning changes, or READ gitnexus://repo/{name}/pro
|
|
|
188
210
|
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results.
|
|
189
211
|
|
|
190
212
|
Process participation metadata:
|
|
191
|
-
- processes[].evidence_mode: direct_step | method_projected
|
|
213
|
+
- processes[].evidence_mode: direct_step | method_projected
|
|
192
214
|
- processes[].confidence: high | medium | low
|
|
193
215
|
- processes[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
194
216
|
- processes[].runtime_chain_confidence: high | medium | low
|
|
195
217
|
- processes[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain
|
|
196
218
|
- processes[].verification_hint: { action, target, next_command } (required when confidence=low)
|
|
197
219
|
|
|
220
|
+
Default response_profile=slim shape:
|
|
221
|
+
- summary, symbol, incoming, outgoing, processes, resource_hints, verification_hint, upgrade_hints, runtime_preview
|
|
222
|
+
- facts, closure, clues, tier_envelope
|
|
223
|
+
- missing_proof_targets, suggested_context_targets
|
|
224
|
+
- read order in strict-anchor mode: facts -> closure -> clues
|
|
225
|
+
- suggested_context_targets[]: { name, uid?, filePath?, why } for direct context disambiguation
|
|
226
|
+
- upgrade_hints may include exact \`context --uid\` follow-ups when same-name symbols are ambiguous
|
|
227
|
+
- response_profile=slim is the default and sufficient for all normal agent workflows
|
|
228
|
+
- response_profile=full is for debugging and deep evidence inspection only
|
|
229
|
+
- recommended runtime retrieval sequence: discovery -> seed narrowing -> closure verification
|
|
230
|
+
- strong graph hops can coexist with failed closure when verifier-core remains failed
|
|
231
|
+
|
|
198
232
|
Unity retrieval contract:
|
|
199
233
|
- Set unity_resources=on|auto to include Unity resource evidence.
|
|
200
234
|
- Default unity_hydration_mode=compact (fast path).
|
|
201
235
|
- Check response hydrationMeta: when needsParityRetry=true, rerun with unity_hydration_mode=parity for completeness.
|
|
236
|
+
- Runtime-chain semantics are two-layered:
|
|
237
|
+
- verifier-core: binary (verified_full | failed)
|
|
238
|
+
- policy-adjusted: context-visible result; under strict policy fallback (hydrationMeta.fallbackToCompact=true) this may downgrade to partial semantics.
|
|
202
239
|
- Returns next_hops[] with ranked follow-up actions when Unity evidence is available.`,
|
|
203
240
|
inputSchema: {
|
|
204
241
|
type: 'object',
|
|
@@ -207,6 +244,12 @@ Unity retrieval contract:
|
|
|
207
244
|
uid: { type: 'string', description: 'Direct symbol UID from prior tool results (zero-ambiguity lookup)' },
|
|
208
245
|
file_path: { type: 'string', description: 'File path to disambiguate common names' },
|
|
209
246
|
include_content: { type: 'boolean', description: 'Include full symbol source code (default: false)', default: false },
|
|
247
|
+
response_profile: {
|
|
248
|
+
type: 'string',
|
|
249
|
+
enum: ['slim', 'full'],
|
|
250
|
+
description: 'Response payload profile: slim (default, sufficient for normal workflows) or full (debug-only for deep evidence inspection).',
|
|
251
|
+
default: 'slim',
|
|
252
|
+
},
|
|
210
253
|
unity_resources: {
|
|
211
254
|
type: 'string',
|
|
212
255
|
enum: ['off', 'on', 'auto'],
|
|
@@ -340,27 +383,14 @@ Output enforces unique-result policy and includes path+line evidence hops.`,
|
|
|
340
383
|
required: ['target', 'goal'],
|
|
341
384
|
},
|
|
342
385
|
},
|
|
343
|
-
{
|
|
344
|
-
name: 'rule_lab_discover',
|
|
345
|
-
description: `Start a Rule Lab run by discovering deterministic slices and persisting a manifest under .gitnexus/rules/lab/runs.`,
|
|
346
|
-
inputSchema: {
|
|
347
|
-
type: 'object',
|
|
348
|
-
properties: {
|
|
349
|
-
scope: { type: 'string', enum: ['full', 'diff'], description: 'Discovery scope (default: full)' },
|
|
350
|
-
seed: { type: 'string', description: 'Optional deterministic seed' },
|
|
351
|
-
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
352
|
-
},
|
|
353
|
-
required: [],
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
386
|
{
|
|
357
387
|
name: 'rule_lab_analyze',
|
|
358
|
-
description: `Analyze one
|
|
388
|
+
description: `Analyze one Rule Lab slice and emit anchor-backed candidates.jsonl.`,
|
|
359
389
|
inputSchema: {
|
|
360
390
|
type: 'object',
|
|
361
391
|
properties: {
|
|
362
392
|
run_id: { type: 'string', description: 'Rule Lab run id' },
|
|
363
|
-
slice_id: { type: 'string', description: '
|
|
393
|
+
slice_id: { type: 'string', description: 'Rule Lab slice id' },
|
|
364
394
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
365
395
|
},
|
|
366
396
|
required: ['run_id', 'slice_id'],
|
|
@@ -373,7 +403,7 @@ Output enforces unique-result policy and includes path+line evidence hops.`,
|
|
|
373
403
|
type: 'object',
|
|
374
404
|
properties: {
|
|
375
405
|
run_id: { type: 'string', description: 'Rule Lab run id' },
|
|
376
|
-
slice_id: { type: 'string', description: '
|
|
406
|
+
slice_id: { type: 'string', description: 'Rule Lab slice id' },
|
|
377
407
|
max_tokens: { type: 'number', description: 'Token budget cap (default: 6000)', default: 6000 },
|
|
378
408
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
379
409
|
},
|
|
@@ -387,7 +417,7 @@ Output enforces unique-result policy and includes path+line evidence hops.`,
|
|
|
387
417
|
type: 'object',
|
|
388
418
|
properties: {
|
|
389
419
|
run_id: { type: 'string', description: 'Rule Lab run id' },
|
|
390
|
-
slice_id: { type: 'string', description: '
|
|
420
|
+
slice_id: { type: 'string', description: 'Rule Lab slice id' },
|
|
391
421
|
input_path: { type: 'string', description: 'Absolute or repo-relative path to curation input JSON' },
|
|
392
422
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
393
423
|
},
|
|
@@ -401,7 +431,7 @@ Output enforces unique-result policy and includes path+line evidence hops.`,
|
|
|
401
431
|
type: 'object',
|
|
402
432
|
properties: {
|
|
403
433
|
run_id: { type: 'string', description: 'Rule Lab run id' },
|
|
404
|
-
slice_id: { type: 'string', description: '
|
|
434
|
+
slice_id: { type: 'string', description: 'Rule Lab slice id' },
|
|
405
435
|
version: { type: 'string', description: 'Promoted rule version (default: 1.0.0)', default: '1.0.0' },
|
|
406
436
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
407
437
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getRuleLabPaths } from './paths.js';
|
|
2
|
-
import type { RuleLabCandidate } from './types.js';
|
|
2
|
+
import type { RuleLabCandidate, RuleLabSlice } from './types.js';
|
|
3
3
|
export interface AnalyzeInput {
|
|
4
4
|
repoPath: string;
|
|
5
5
|
runId: string;
|
|
@@ -8,5 +8,6 @@ export interface AnalyzeInput {
|
|
|
8
8
|
export interface AnalyzeOutput {
|
|
9
9
|
paths: ReturnType<typeof getRuleLabPaths>;
|
|
10
10
|
candidates: RuleLabCandidate[];
|
|
11
|
+
slice: RuleLabSlice;
|
|
11
12
|
}
|
|
12
13
|
export declare function analyzeRuleLabSlice(input: AnalyzeInput): Promise<AnalyzeOutput>;
|
package/dist/rule-lab/analyze.js
CHANGED
|
@@ -2,89 +2,124 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { getRuleLabPaths } from './paths.js';
|
|
5
|
+
import { buildCurationInput } from './curation-input-builder.js';
|
|
5
6
|
function buildCandidateId(slice, variant) {
|
|
6
7
|
return createHash('sha1')
|
|
7
8
|
.update(`${slice.id}:${slice.trigger_family}:${slice.resource_types.join('|')}:${slice.host_base_type.join('|')}:${variant}`)
|
|
8
9
|
.digest('hex')
|
|
9
10
|
.slice(0, 12);
|
|
10
11
|
}
|
|
11
|
-
function
|
|
12
|
-
return
|
|
12
|
+
function normalizeToken(value) {
|
|
13
|
+
return String(value || '')
|
|
14
|
+
.trim()
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
17
|
+
.replace(/^-+|-+$/g, '');
|
|
13
18
|
}
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
19
|
+
function inferRuleStem(slice, pair) {
|
|
20
|
+
const source = normalizeToken(pair.source_anchor.symbol || pair.source_anchor.file || `${slice.id}-source`);
|
|
21
|
+
const target = normalizeToken(pair.target_anchor.symbol || pair.target_anchor.file || `${slice.id}-target`);
|
|
22
|
+
const joined = [source, target].filter(Boolean).join('-');
|
|
23
|
+
return joined || normalizeToken(slice.id) || 'runtime-rule';
|
|
24
|
+
}
|
|
25
|
+
function buildProposalTopology(slice) {
|
|
26
|
+
const requiredHops = Array.isArray(slice.required_hops) && slice.required_hops.length > 0
|
|
27
|
+
? slice.required_hops
|
|
18
28
|
: ['resource', 'code_runtime'];
|
|
19
|
-
|
|
29
|
+
return requiredHops.map((hop) => ({
|
|
20
30
|
hop,
|
|
21
31
|
from: { entity: hop === 'resource' ? 'resource' : 'script' },
|
|
22
32
|
to: { entity: hop === 'code_runtime' ? 'runtime' : 'script' },
|
|
23
33
|
edge: { kind: hop === 'resource' ? 'binds_script' : 'calls' },
|
|
24
34
|
}));
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
35
|
+
}
|
|
36
|
+
function buildExactPairCandidates(slice) {
|
|
37
|
+
const pairs = Array.isArray(slice.exact_pairs) ? slice.exact_pairs : [];
|
|
38
|
+
if (pairs.length === 0) {
|
|
39
|
+
throw new Error('exact_pairs must be non-empty for reduced rule-lab analyze flow');
|
|
40
|
+
}
|
|
41
|
+
const seenPairIds = new Set();
|
|
42
|
+
for (const pair of pairs) {
|
|
43
|
+
const pairId = String(pair.id || '').trim();
|
|
44
|
+
if (!pairId)
|
|
45
|
+
continue;
|
|
46
|
+
if (seenPairIds.has(pairId)) {
|
|
47
|
+
throw new Error(`duplicate_exact_pair_id: ${pairId}`);
|
|
48
|
+
}
|
|
49
|
+
seenPairIds.add(pairId);
|
|
50
|
+
}
|
|
51
|
+
const topology = buildProposalTopology(slice);
|
|
52
|
+
return pairs.map((pair, index) => {
|
|
53
|
+
const pairKey = String(pair.id || `${index + 1}`).trim();
|
|
54
|
+
const sourceAnchor = `${String(pair.source_anchor.file || '').trim()}:${Number(pair.source_anchor.line || 1)}`;
|
|
55
|
+
const targetAnchor = `${String(pair.target_anchor.file || '').trim()}:${Number(pair.target_anchor.line || 1)}`;
|
|
56
|
+
const draftRuleId = String(pair.draft_rule_id || '').trim() || `unity.event.${inferRuleStem(slice, pair)}.v1`;
|
|
57
|
+
const bindingKind = pair.binding_kind || 'method_triggers_method';
|
|
58
|
+
return {
|
|
59
|
+
id: buildCandidateId(slice, `exact:${pairKey}`),
|
|
60
|
+
title: `${slice.trigger_family} exact pair ${pairKey}`,
|
|
61
|
+
rule_hint: `${slice.trigger_family}.${slice.id}.exact.${pairKey}`,
|
|
62
|
+
proposal_kind: 'per_anchor_rule',
|
|
63
|
+
aggregation_mode: 'per_anchor_rules',
|
|
64
|
+
binding_kind: bindingKind,
|
|
65
|
+
draft_rule_id: draftRuleId,
|
|
66
|
+
topology,
|
|
67
|
+
closure: {
|
|
68
|
+
required_hops: topology.map((hop) => hop.hop),
|
|
69
|
+
failure_map: {
|
|
70
|
+
missing_evidence: 'rule_matched_but_evidence_missing',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
claims: {
|
|
74
|
+
guarantees: [`exact pair linked: ${sourceAnchor} -> ${targetAnchor}`],
|
|
75
|
+
non_guarantees: ['sparse gap path only; no exhaustive discovery semantics'],
|
|
76
|
+
next_action: `gitnexus query "${slice.trigger_family}"`,
|
|
77
|
+
},
|
|
78
|
+
exact_pair: pair,
|
|
79
|
+
evidence: {
|
|
80
|
+
hops: [
|
|
81
|
+
{
|
|
82
|
+
hop_type: 'code_runtime',
|
|
83
|
+
anchor: sourceAnchor,
|
|
84
|
+
snippet: String(pair.source_anchor.symbol || 'source'),
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
hop_type: 'code_runtime',
|
|
88
|
+
anchor: targetAnchor,
|
|
89
|
+
snippet: String(pair.target_anchor.symbol || 'target'),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function assertNoPlaceholderIds(runId, sliceId) {
|
|
97
|
+
const placeholderRe = /<[^>]+>|placeholder|todo|tbd/i;
|
|
98
|
+
if (placeholderRe.test(runId) || placeholderRe.test(sliceId)) {
|
|
99
|
+
throw new Error('placeholder run/slice ids are not allowed');
|
|
100
|
+
}
|
|
75
101
|
}
|
|
76
102
|
export async function analyzeRuleLabSlice(input) {
|
|
103
|
+
assertNoPlaceholderIds(input.runId, input.sliceId);
|
|
77
104
|
const normalizedRepoPath = path.resolve(input.repoPath);
|
|
78
105
|
const paths = getRuleLabPaths(normalizedRepoPath, input.runId, input.sliceId);
|
|
79
106
|
const slicePath = path.join(paths.slicesRoot, input.sliceId, 'slice.json');
|
|
80
107
|
const raw = await fs.readFile(slicePath, 'utf-8');
|
|
81
108
|
const slice = JSON.parse(raw);
|
|
82
|
-
const
|
|
83
|
-
const
|
|
109
|
+
const candidates = buildExactPairCandidates(slice);
|
|
110
|
+
const curation = buildCurationInput({
|
|
111
|
+
runId: input.runId,
|
|
112
|
+
sliceId: input.sliceId,
|
|
113
|
+
slice,
|
|
114
|
+
candidates,
|
|
115
|
+
});
|
|
84
116
|
await fs.mkdir(path.dirname(paths.candidatesPath), { recursive: true });
|
|
85
117
|
await fs.writeFile(paths.candidatesPath, `${candidates.map((candidate) => JSON.stringify(candidate)).join('\n')}\n`, 'utf-8');
|
|
118
|
+
await fs.writeFile(slicePath, `${JSON.stringify(slice, null, 2)}\n`, 'utf-8');
|
|
119
|
+
await fs.writeFile(path.join(path.dirname(paths.candidatesPath), 'curation-input.json'), `${JSON.stringify(curation, null, 2)}\n`, 'utf-8');
|
|
86
120
|
return {
|
|
87
121
|
paths,
|
|
88
122
|
candidates,
|
|
123
|
+
slice,
|
|
89
124
|
};
|
|
90
125
|
}
|