archctx-contracts 0.7.0 → 0.7.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/fixtures/valid/archctx-capabilities.json +2 -2
- package/fixtures/valid/capability-dependencies.json +35 -0
- package/fixtures/valid/docs-anchors.json +105 -0
- package/fixtures/valid/flow-selector-check.json +50 -0
- package/fixtures/valid/product-version-manifest.json +5 -5
- package/fixtures/valid/runtime-refactor-scan.json +1 -0
- package/package.json +1 -1
- package/schemas/runtime/archctx-capabilities.schema.json +1 -1
- package/schemas/runtime/capability-dependencies.schema.json +116 -0
- package/schemas/runtime/docs-anchors.schema.json +143 -0
- package/schemas/runtime/flow-selector-check.schema.json +109 -0
- package/schemas/runtime/recommendation-v3.schema.json +1 -0
- package/schemas/runtime/runtime-recommendation-show.schema.json +14 -0
- package/schemas/runtime/runtime-refactor-scan.schema.json +19 -0
- package/schemas/runtime/structural-observation-payload.schema.json +1 -0
- package/src/architecture.ts +6 -3
- package/src/docs-anchors.ts +126 -0
- package/src/index.ts +2 -0
- package/src/ownership-dependencies.ts +129 -0
- package/src/product-version.ts +1 -1
- package/src/projection.ts +69 -1
- package/src/refactor.ts +37 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "archcontext.capabilities/v1",
|
|
3
|
-
"package": { "name": "archctx", "version": "0.7.
|
|
3
|
+
"package": { "name": "archctx", "version": "0.7.2" },
|
|
4
4
|
"protocols": {
|
|
5
5
|
"projectionRequest": "archcontext.projection-request/v1",
|
|
6
6
|
"projectionResult": "archcontext.projection-result/v2",
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
"architectureDocs": "archcontext.docs-renderer/v5",
|
|
11
11
|
"agentContext": "archcontext.agent-context-renderer/v1"
|
|
12
12
|
},
|
|
13
|
-
"features": ["architecture-change-capabilities-v1", "architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "changeset-entity-operations-v1", "code-facts-unavailable-error-v1", "module-statistics-v1", "projection-apply-readback-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-apply-replay-v1", "projection-check-freshness-v1", "projection-manifest-contract-v2", "projection-observed-major-change-acceptance-v1", "projection-orphan-review-v1", "projection-preview-v1", "projection-prior-committed-applies-v1", "projection-protocol-v2", "recommendation-scan-decision-v1", "recommendation-v3", "refactor-assessment-v1", "refactor-observation-evidence-v1", "refactor-resolution-v1", "refactor-scan-limits-v1"]
|
|
13
|
+
"features": ["architecture-change-capabilities-v1", "architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "capability-dependencies-v1", "changeset-entity-operations-v1", "changeset-ownership-delta-v1", "code-facts-unavailable-error-v1", "docs-anchors-v1", "flow-selector-check-v1", "module-statistics-v1", "projection-apply-readback-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-apply-replay-v1", "projection-check-freshness-v1", "projection-manifest-contract-v2", "projection-observed-major-change-acceptance-v1", "projection-orphan-review-v1", "projection-preview-v1", "projection-prior-committed-applies-v1", "projection-protocol-v2", "recommendation-scan-decision-v1", "recommendation-v3", "refactor-assessment-v1", "refactor-observation-evidence-v1", "refactor-resolution-v1", "refactor-scan-limits-v1", "refactor-scan-untracked-count-v1"]
|
|
14
14
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.capability-dependencies/v1",
|
|
3
|
+
"ownershipRule": "parent-chain",
|
|
4
|
+
"filter": { "from": null, "into": "capability.billing" },
|
|
5
|
+
"capabilities": ["capability.billing", "capability.checkout"],
|
|
6
|
+
"matrix": [
|
|
7
|
+
{ "from": "capability.checkout", "to": "capability.billing", "imports": 2, "calls": null }
|
|
8
|
+
],
|
|
9
|
+
"imports": {
|
|
10
|
+
"coverage": "complete",
|
|
11
|
+
"reasonCodes": [],
|
|
12
|
+
"truncated": false,
|
|
13
|
+
"importNodeCount": 14,
|
|
14
|
+
"importNodeLimit": 50000,
|
|
15
|
+
"importNodeLimitExceeded": false,
|
|
16
|
+
"edgeCount": 3,
|
|
17
|
+
"unresolvedCount": 0,
|
|
18
|
+
"unattributed": { "unownedEndpoint": 1, "contestedEndpoint": 0, "noCapabilityEndpoint": 0 }
|
|
19
|
+
},
|
|
20
|
+
"calls": { "coverage": "unknown", "reasonCodes": ["call-edges-not-exposed"] },
|
|
21
|
+
"edges": {
|
|
22
|
+
"limit": 200,
|
|
23
|
+
"count": 2,
|
|
24
|
+
"omittedCount": 0,
|
|
25
|
+
"items": [
|
|
26
|
+
{ "fromPath": "src/checkout/cart.ts", "toPath": "src/billing/invoice.ts", "fromCapability": "capability.checkout", "toCapability": "capability.billing" },
|
|
27
|
+
{ "fromPath": "src/checkout/pay.ts", "toPath": "src/billing/invoice.ts", "fromCapability": "capability.checkout", "toCapability": "capability.billing" }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"worktree": {
|
|
31
|
+
"headSha": "0123456789abcdef0123456789abcdef01234567",
|
|
32
|
+
"worktreeDigest": "sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
|
33
|
+
},
|
|
34
|
+
"privacy": { "writes": "none" }
|
|
35
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.docs-anchors/v1",
|
|
3
|
+
"profile": "repo-harness/v1",
|
|
4
|
+
"codeGraph": {
|
|
5
|
+
"availability": "ready"
|
|
6
|
+
},
|
|
7
|
+
"summary": {
|
|
8
|
+
"nodes": 3,
|
|
9
|
+
"documents": 2,
|
|
10
|
+
"citations": 6,
|
|
11
|
+
"findings": 4,
|
|
12
|
+
"unchecked": 1,
|
|
13
|
+
"byKind": {
|
|
14
|
+
"line-moved": 1,
|
|
15
|
+
"line-out-of-range": 1,
|
|
16
|
+
"missing-path": 1,
|
|
17
|
+
"missing-symbol": 1
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"nodes": [
|
|
21
|
+
{
|
|
22
|
+
"nodeId": "capability.runtime-harness.evals-checks",
|
|
23
|
+
"documentPath": "docs/architecture/modules/runtime-harness/evals-checks.md",
|
|
24
|
+
"citationCount": 2,
|
|
25
|
+
"findings": [
|
|
26
|
+
{
|
|
27
|
+
"kind": "missing-symbol",
|
|
28
|
+
"origin": {
|
|
29
|
+
"kind": "node-responsibility",
|
|
30
|
+
"index": 0
|
|
31
|
+
},
|
|
32
|
+
"citation": {
|
|
33
|
+
"text": "is_evidence_producer_command()",
|
|
34
|
+
"symbol": "is_evidence_producer_command"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"unchecked": []
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"nodeId": "capability.runtime-harness.hook-adapters",
|
|
42
|
+
"documentPath": "docs/architecture/modules/runtime-harness/hook-adapters.md",
|
|
43
|
+
"citationCount": 4,
|
|
44
|
+
"findings": [
|
|
45
|
+
{
|
|
46
|
+
"kind": "line-moved",
|
|
47
|
+
"origin": {
|
|
48
|
+
"kind": "document",
|
|
49
|
+
"path": "docs/architecture/modules/runtime-harness/hook-adapters.md",
|
|
50
|
+
"line": 41
|
|
51
|
+
},
|
|
52
|
+
"citation": {
|
|
53
|
+
"text": "route-registry.ts:52",
|
|
54
|
+
"path": "route-registry.ts",
|
|
55
|
+
"resolvedPath": "src/hooks/route-registry.ts",
|
|
56
|
+
"line": 52,
|
|
57
|
+
"symbol": "registerRoute"
|
|
58
|
+
},
|
|
59
|
+
"currentLines": [
|
|
60
|
+
54
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"kind": "line-out-of-range",
|
|
65
|
+
"origin": {
|
|
66
|
+
"kind": "document",
|
|
67
|
+
"path": "docs/architecture/modules/runtime-harness/hook-adapters.md",
|
|
68
|
+
"line": 44
|
|
69
|
+
},
|
|
70
|
+
"citation": {
|
|
71
|
+
"text": "src/hooks/runtime.ts:410",
|
|
72
|
+
"path": "src/hooks/runtime.ts",
|
|
73
|
+
"line": 410
|
|
74
|
+
},
|
|
75
|
+
"lineCount": 362
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"kind": "missing-path",
|
|
79
|
+
"origin": {
|
|
80
|
+
"kind": "node-summary"
|
|
81
|
+
},
|
|
82
|
+
"citation": {
|
|
83
|
+
"text": "src/hooks/legacy-adapter.ts",
|
|
84
|
+
"path": "src/hooks/legacy-adapter.ts"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"unchecked": [
|
|
89
|
+
{
|
|
90
|
+
"reasonCode": "path-ambiguous",
|
|
91
|
+
"origin": {
|
|
92
|
+
"kind": "document",
|
|
93
|
+
"path": "docs/architecture/modules/runtime-harness/hook-adapters.md",
|
|
94
|
+
"line": 50
|
|
95
|
+
},
|
|
96
|
+
"citation": {
|
|
97
|
+
"text": "index.ts:12",
|
|
98
|
+
"path": "index.ts",
|
|
99
|
+
"line": 12
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.flow-selector-check/v1",
|
|
3
|
+
"ok": false,
|
|
4
|
+
"codeGraph": { "availability": "ready", "version": "1.6.1" },
|
|
5
|
+
"summary": { "selectors": 2, "proven": 1, "unproven": 1, "usedUnproven": 1 },
|
|
6
|
+
"selectors": [
|
|
7
|
+
{
|
|
8
|
+
"nodeId": "capability.runtime.hooks",
|
|
9
|
+
"entrypointId": "entrypoint.hook.stop",
|
|
10
|
+
"sourcePath": "src/hook.ts",
|
|
11
|
+
"sourceSymbol": "runHook",
|
|
12
|
+
"sinkId": "sink.hook.journal",
|
|
13
|
+
"sinkPath": "src/journal.ts",
|
|
14
|
+
"sinkSymbol": "writeEvent",
|
|
15
|
+
"status": "proven",
|
|
16
|
+
"callSites": [{ "path": "src/hook.ts", "line": 12 }],
|
|
17
|
+
"referenceSites": [],
|
|
18
|
+
"rejectedBuiltinCallSites": [],
|
|
19
|
+
"flowSteps": [{ "flowId": "flow.runtime.hooks.stop", "stepId": "persist" }]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"nodeId": "capability.runtime.hooks",
|
|
23
|
+
"entrypointId": "entrypoint.hook.stop",
|
|
24
|
+
"sourcePath": "src/hook.ts",
|
|
25
|
+
"sourceSymbol": "runHook",
|
|
26
|
+
"sinkId": "sink.hook.resolve",
|
|
27
|
+
"sinkPath": "src/paths.ts",
|
|
28
|
+
"sinkSymbol": "resolve",
|
|
29
|
+
"status": "false-builtin-call",
|
|
30
|
+
"callSites": [],
|
|
31
|
+
"referenceSites": [],
|
|
32
|
+
"rejectedBuiltinCallSites": [{ "path": "src/hook.ts", "line": 7 }],
|
|
33
|
+
"flowSteps": [{ "flowId": "flow.runtime.hooks.stop", "stepId": "resolve" }]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"capabilities": [
|
|
37
|
+
{
|
|
38
|
+
"capabilityId": "capability.runtime.hooks",
|
|
39
|
+
"p2Status": "unprovable",
|
|
40
|
+
"diagnostics": [
|
|
41
|
+
{
|
|
42
|
+
"code": "selector-evidence-unmatched",
|
|
43
|
+
"flowId": "flow.runtime.hooks.stop",
|
|
44
|
+
"stepId": "resolve",
|
|
45
|
+
"detail": "entrypoint.hook.stop runHook sink.hook.resolve"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": "archcontext.product-version-manifest/v1",
|
|
3
3
|
"product": {
|
|
4
4
|
"name": "archctx",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.2",
|
|
6
6
|
"distribution": "one-package"
|
|
7
7
|
},
|
|
8
8
|
"packageManager": "bun@1.4.3",
|
|
@@ -12,25 +12,25 @@
|
|
|
12
12
|
"surfaces": {
|
|
13
13
|
"cli": {
|
|
14
14
|
"packageName": "@archcontext/surfaces",
|
|
15
|
-
"version": "0.7.
|
|
15
|
+
"version": "0.7.2",
|
|
16
16
|
"entrypoint": "archctx"
|
|
17
17
|
},
|
|
18
18
|
"daemon": {
|
|
19
19
|
"packageName": "@archcontext/local-runtime",
|
|
20
|
-
"version": "0.7.
|
|
20
|
+
"version": "0.7.2",
|
|
21
21
|
"entrypoint": "archctx daemon start",
|
|
22
22
|
"rpcSchemaVersion": "archcontext.runtime-rpc/v1"
|
|
23
23
|
},
|
|
24
24
|
"mcp": {
|
|
25
25
|
"packageName": "@archcontext/surfaces",
|
|
26
|
-
"version": "0.7.
|
|
26
|
+
"version": "0.7.2",
|
|
27
27
|
"entrypoint": "archctx mcp",
|
|
28
28
|
"transport": "stdio"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"schemas": {
|
|
32
32
|
"schemaSetVersion": "2026-06-25.al0-ledger",
|
|
33
|
-
"contractsPackageVersion": "0.7.
|
|
33
|
+
"contractsPackageVersion": "0.7.2",
|
|
34
34
|
"reviewChallenge": "archcontext.review-challenge/v2",
|
|
35
35
|
"attestation": "archcontext.attestation/v2",
|
|
36
36
|
"deviceIdentity": "archcontext.device-identity/v1",
|
package/package.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"type": "string",
|
|
44
44
|
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*-v[0-9]+$",
|
|
45
45
|
"description": "One feature flag: a lowercase kebab-case name that ends in a version suffix (-v1, -v2, ...). The pattern is open, so a validator built from this schema accepts flags that a later archctx adds. A consumer must ignore a flag it does not know. examples lists the flags this schema version knows.",
|
|
46
|
-
"examples": ["architecture-change-capabilities-v1", "architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "changeset-entity-operations-v1", "code-facts-unavailable-error-v1", "module-statistics-v1", "projection-apply-readback-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-apply-replay-v1", "projection-check-freshness-v1", "projection-manifest-contract-v2", "projection-observed-major-change-acceptance-v1", "projection-orphan-review-v1", "projection-preview-v1", "projection-prior-committed-applies-v1", "projection-protocol-v2", "recommendation-scan-decision-v1", "recommendation-v3", "refactor-assessment-v1", "refactor-observation-evidence-v1", "refactor-resolution-v1", "refactor-scan-limits-v1"]
|
|
46
|
+
"examples": ["architecture-change-capabilities-v1", "architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "capability-dependencies-v1", "changeset-entity-operations-v1", "changeset-ownership-delta-v1", "code-facts-unavailable-error-v1", "docs-anchors-v1", "flow-selector-check-v1", "module-statistics-v1", "projection-apply-readback-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-apply-replay-v1", "projection-check-freshness-v1", "projection-manifest-contract-v2", "projection-observed-major-change-acceptance-v1", "projection-orphan-review-v1", "projection-preview-v1", "projection-prior-committed-applies-v1", "projection-protocol-v2", "recommendation-scan-decision-v1", "recommendation-v3", "refactor-assessment-v1", "refactor-observation-evidence-v1", "refactor-resolution-v1", "refactor-scan-limits-v1", "refactor-scan-untracked-count-v1"]
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/capability-dependencies.schema.json",
|
|
4
|
+
"title": "CapabilityDependenciesV1",
|
|
5
|
+
"description": "The data of `archctx deps`: a read-only capability x capability import matrix. Owners come from the parent-chain rule `refactor scan` uses, rolled up to the nearest capability. Call counts are not available in v1.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "ownershipRule", "filter", "capabilities", "matrix", "imports", "calls", "edges", "worktree", "privacy"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "archcontext.capability-dependencies/v1" },
|
|
11
|
+
"ownershipRule": { "const": "parent-chain" },
|
|
12
|
+
"filter": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"required": ["from", "into"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"from": { "type": ["string", "null"] },
|
|
18
|
+
"into": { "type": ["string", "null"] }
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"capabilities": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
22
|
+
"matrix": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"items": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"required": ["from", "to", "imports", "calls"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"from": { "type": "string", "minLength": 1 },
|
|
30
|
+
"to": { "type": "string", "minLength": 1 },
|
|
31
|
+
"imports": { "type": "integer", "minimum": 1 },
|
|
32
|
+
"calls": { "type": "null" }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"imports": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"required": ["coverage", "reasonCodes", "truncated", "importNodeCount", "importNodeLimit", "importNodeLimitExceeded", "edgeCount", "unresolvedCount", "unattributed"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"coverage": { "enum": ["complete", "partial", "unknown"] },
|
|
42
|
+
"reasonCodes": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"uniqueItems": true,
|
|
45
|
+
"items": { "enum": ["code-facts-import-limit", "code-facts-stale", "code-facts-truncated", "code-facts-unavailable"] }
|
|
46
|
+
},
|
|
47
|
+
"truncated": { "type": "boolean" },
|
|
48
|
+
"importNodeCount": { "type": ["integer", "null"], "minimum": 0 },
|
|
49
|
+
"importNodeLimit": { "type": "integer", "minimum": 1 },
|
|
50
|
+
"importNodeLimitExceeded": { "type": "boolean" },
|
|
51
|
+
"edgeCount": { "type": "integer", "minimum": 0 },
|
|
52
|
+
"unresolvedCount": { "type": "integer", "minimum": 0 },
|
|
53
|
+
"unattributed": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": false,
|
|
56
|
+
"required": ["unownedEndpoint", "contestedEndpoint", "noCapabilityEndpoint"],
|
|
57
|
+
"properties": {
|
|
58
|
+
"unownedEndpoint": { "type": "integer", "minimum": 0 },
|
|
59
|
+
"contestedEndpoint": { "type": "integer", "minimum": 0 },
|
|
60
|
+
"noCapabilityEndpoint": { "type": "integer", "minimum": 0 }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"calls": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": ["coverage", "reasonCodes"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"coverage": { "const": "unknown" },
|
|
71
|
+
"reasonCodes": { "type": "array", "minItems": 1, "maxItems": 1, "items": { "const": "call-edges-not-exposed" } }
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"edges": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"required": ["limit", "count", "omittedCount", "items"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"limit": { "type": "integer", "minimum": 0 },
|
|
80
|
+
"count": { "type": "integer", "minimum": 0 },
|
|
81
|
+
"omittedCount": { "type": "integer", "minimum": 0 },
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "array",
|
|
84
|
+
"items": {
|
|
85
|
+
"type": "object",
|
|
86
|
+
"additionalProperties": false,
|
|
87
|
+
"required": ["fromPath", "toPath", "fromCapability", "toCapability"],
|
|
88
|
+
"properties": {
|
|
89
|
+
"fromPath": { "type": "string", "minLength": 1 },
|
|
90
|
+
"toPath": { "type": "string", "minLength": 1 },
|
|
91
|
+
"fromCapability": { "type": "string", "minLength": 1 },
|
|
92
|
+
"toCapability": { "type": "string", "minLength": 1 }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"worktree": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"required": ["headSha", "worktreeDigest"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
104
|
+
"worktreeDigest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"privacy": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"additionalProperties": false,
|
|
110
|
+
"required": ["writes"],
|
|
111
|
+
"properties": {
|
|
112
|
+
"writes": { "const": "none" }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/docs-anchors.schema.json",
|
|
4
|
+
"title": "DocsAnchorsReportV1",
|
|
5
|
+
"description": "Read-only result of `archctx docs anchors`: stale citations in human-owned module document regions and node prose. A signal, not a gate.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "profile", "codeGraph", "summary", "nodes"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "archcontext.docs-anchors/v1" },
|
|
11
|
+
"profile": { "enum": ["default", "repo-harness/v1"] },
|
|
12
|
+
"codeGraph": {
|
|
13
|
+
"oneOf": [
|
|
14
|
+
{
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"required": ["availability"],
|
|
18
|
+
"properties": { "availability": { "const": "ready" } }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["availability", "reasonCode"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"availability": { "const": "unavailable" },
|
|
26
|
+
"reasonCode": { "enum": ["index-missing", "index-open-failed"] }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"summary": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"required": ["nodes", "documents", "citations", "findings", "unchecked", "byKind"],
|
|
35
|
+
"properties": {
|
|
36
|
+
"nodes": { "$ref": "#/$defs/count" },
|
|
37
|
+
"documents": { "$ref": "#/$defs/count" },
|
|
38
|
+
"citations": { "$ref": "#/$defs/count" },
|
|
39
|
+
"findings": { "$ref": "#/$defs/count" },
|
|
40
|
+
"unchecked": { "$ref": "#/$defs/count" },
|
|
41
|
+
"byKind": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["line-moved", "line-out-of-range", "missing-path", "missing-symbol"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"line-moved": { "$ref": "#/$defs/count" },
|
|
47
|
+
"line-out-of-range": { "$ref": "#/$defs/count" },
|
|
48
|
+
"missing-path": { "$ref": "#/$defs/count" },
|
|
49
|
+
"missing-symbol": { "$ref": "#/$defs/count" }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"nodes": {
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"additionalProperties": false,
|
|
59
|
+
"required": ["nodeId", "citationCount", "findings", "unchecked"],
|
|
60
|
+
"properties": {
|
|
61
|
+
"nodeId": { "type": "string", "minLength": 1 },
|
|
62
|
+
"documentPath": { "$ref": "#/$defs/repoPath" },
|
|
63
|
+
"citationCount": { "type": "integer", "minimum": 1 },
|
|
64
|
+
"findings": { "type": "array", "items": { "$ref": "#/$defs/finding" } },
|
|
65
|
+
"unchecked": { "type": "array", "items": { "$ref": "#/$defs/unchecked" } }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"$defs": {
|
|
71
|
+
"count": { "type": "integer", "minimum": 0 },
|
|
72
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
73
|
+
"repoPath": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"minLength": 1,
|
|
76
|
+
"not": { "anyOf": [{ "pattern": "^/" }, { "pattern": "\\\\" }, { "pattern": "(^|/)\\.\\.(/|$)" }] }
|
|
77
|
+
},
|
|
78
|
+
"origin": {
|
|
79
|
+
"oneOf": [
|
|
80
|
+
{
|
|
81
|
+
"type": "object",
|
|
82
|
+
"additionalProperties": false,
|
|
83
|
+
"required": ["kind", "path", "line"],
|
|
84
|
+
"properties": {
|
|
85
|
+
"kind": { "const": "document" },
|
|
86
|
+
"path": { "$ref": "#/$defs/repoPath" },
|
|
87
|
+
"line": { "$ref": "#/$defs/line" }
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"required": ["kind"],
|
|
94
|
+
"properties": { "kind": { "const": "node-summary" } }
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "object",
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": ["kind", "index"],
|
|
100
|
+
"properties": {
|
|
101
|
+
"kind": { "const": "node-responsibility" },
|
|
102
|
+
"index": { "type": "integer", "minimum": 0 }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"citation": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"additionalProperties": false,
|
|
110
|
+
"required": ["text"],
|
|
111
|
+
"properties": {
|
|
112
|
+
"text": { "type": "string", "minLength": 1 },
|
|
113
|
+
"path": { "type": "string", "minLength": 1 },
|
|
114
|
+
"resolvedPath": { "$ref": "#/$defs/repoPath" },
|
|
115
|
+
"line": { "$ref": "#/$defs/line" },
|
|
116
|
+
"endLine": { "$ref": "#/$defs/line" },
|
|
117
|
+
"symbol": { "type": "string", "minLength": 1 }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"finding": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"additionalProperties": false,
|
|
123
|
+
"required": ["kind", "origin", "citation"],
|
|
124
|
+
"properties": {
|
|
125
|
+
"kind": { "enum": ["line-moved", "line-out-of-range", "missing-path", "missing-symbol"] },
|
|
126
|
+
"origin": { "$ref": "#/$defs/origin" },
|
|
127
|
+
"citation": { "$ref": "#/$defs/citation" },
|
|
128
|
+
"lineCount": { "$ref": "#/$defs/count" },
|
|
129
|
+
"currentLines": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/line" } }
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"unchecked": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"additionalProperties": false,
|
|
135
|
+
"required": ["reasonCode", "origin", "citation"],
|
|
136
|
+
"properties": {
|
|
137
|
+
"reasonCode": { "enum": ["codegraph-unavailable", "language-unsupported", "path-ambiguous"] },
|
|
138
|
+
"origin": { "$ref": "#/$defs/origin" },
|
|
139
|
+
"citation": { "$ref": "#/$defs/citation" }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/flow-selector-check.schema.json",
|
|
4
|
+
"title": "ArchitectureFlowSelectorCheckV1",
|
|
5
|
+
"description": "The data of `archctx flows check`: the P2 flow proof of every capability that declares a flow, and the proof status of every declared entrypoint-to-sink selector, computed without rendering. Consumers detect it through the flow-selector-check-v1 capability.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "ok", "codeGraph", "summary", "selectors", "capabilities"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "archcontext.flow-selector-check/v1" },
|
|
11
|
+
"ok": { "type": "boolean", "description": "True when no capability that declares a flow has an unprovable P2 proof." },
|
|
12
|
+
"codeGraph": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"required": ["availability", "version"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"availability": { "enum": ["ready", "unavailable"] },
|
|
18
|
+
"version": { "type": "string", "minLength": 1 }
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"summary": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"additionalProperties": false,
|
|
24
|
+
"required": ["selectors", "proven", "unproven", "usedUnproven"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"selectors": { "type": "integer", "minimum": 0 },
|
|
27
|
+
"proven": { "type": "integer", "minimum": 0 },
|
|
28
|
+
"unproven": { "type": "integer", "minimum": 0 },
|
|
29
|
+
"usedUnproven": { "type": "integer", "minimum": 0, "description": "Unproven selectors that a required-flow step names." }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"selectors": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": ["nodeId", "entrypointId", "sourcePath", "sourceSymbol", "sinkId", "sinkPath", "sinkSymbol", "status", "callSites", "referenceSites", "rejectedBuiltinCallSites", "flowSteps"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"nodeId": { "type": "string", "minLength": 1 },
|
|
40
|
+
"entrypointId": { "type": "string", "minLength": 1 },
|
|
41
|
+
"sourcePath": { "type": "string", "minLength": 1 },
|
|
42
|
+
"sourceSymbol": { "type": "string", "minLength": 1 },
|
|
43
|
+
"sinkId": { "type": "string", "minLength": 1 },
|
|
44
|
+
"sinkPath": { "type": "string", "minLength": 1 },
|
|
45
|
+
"sinkSymbol": { "type": "string", "minLength": 1 },
|
|
46
|
+
"status": {
|
|
47
|
+
"enum": ["ambiguous-symbol", "evidence-missing", "evidence-truncated", "false-builtin-call", "no-direct-call", "only-references", "proven"],
|
|
48
|
+
"description": "Only proven binds a flow step."
|
|
49
|
+
},
|
|
50
|
+
"callSites": { "$ref": "#/$defs/sites" },
|
|
51
|
+
"referenceSites": { "$ref": "#/$defs/sites" },
|
|
52
|
+
"rejectedBuiltinCallSites": { "$ref": "#/$defs/sites" },
|
|
53
|
+
"flowSteps": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"items": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": ["flowId", "stepId"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"flowId": { "type": "string", "minLength": 1 },
|
|
61
|
+
"stepId": { "type": "string", "minLength": 1 }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"capabilities": {
|
|
69
|
+
"type": "array",
|
|
70
|
+
"items": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"additionalProperties": false,
|
|
73
|
+
"required": ["capabilityId", "p2Status", "diagnostics"],
|
|
74
|
+
"properties": {
|
|
75
|
+
"capabilityId": { "type": "string", "minLength": 1 },
|
|
76
|
+
"p2Status": { "enum": ["not-applicable", "proven", "unprovable"] },
|
|
77
|
+
"diagnostics": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"items": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"additionalProperties": false,
|
|
82
|
+
"required": ["code", "detail"],
|
|
83
|
+
"properties": {
|
|
84
|
+
"code": { "type": "string", "minLength": 1 },
|
|
85
|
+
"flowId": { "type": "string", "minLength": 1 },
|
|
86
|
+
"stepId": { "type": "string", "minLength": 1 },
|
|
87
|
+
"detail": { "type": "string" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"$defs": {
|
|
96
|
+
"sites": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"required": ["path"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"path": { "type": "string", "minLength": 1 },
|
|
104
|
+
"line": { "type": "integer", "minimum": 1 }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -470,6 +470,7 @@
|
|
|
470
470
|
"items": {
|
|
471
471
|
"enum": [
|
|
472
472
|
"caller-coverage-unknown",
|
|
473
|
+
"code-facts-import-limit",
|
|
473
474
|
"code-facts-missing",
|
|
474
475
|
"code-facts-truncated",
|
|
475
476
|
"major-change-detected",
|
|
@@ -1740,12 +1741,20 @@
|
|
|
1740
1741
|
],
|
|
1741
1742
|
"minimum": 0
|
|
1742
1743
|
},
|
|
1744
|
+
"importNodeCount": {
|
|
1745
|
+
"type": [
|
|
1746
|
+
"integer",
|
|
1747
|
+
"null"
|
|
1748
|
+
],
|
|
1749
|
+
"minimum": 0
|
|
1750
|
+
},
|
|
1743
1751
|
"reasonCodes": {
|
|
1744
1752
|
"type": "array",
|
|
1745
1753
|
"uniqueItems": true,
|
|
1746
1754
|
"items": {
|
|
1747
1755
|
"enum": [
|
|
1748
1756
|
"caller-coverage-unknown",
|
|
1757
|
+
"code-facts-import-limit",
|
|
1749
1758
|
"code-facts-missing",
|
|
1750
1759
|
"code-facts-truncated",
|
|
1751
1760
|
"major-change-detected",
|
|
@@ -2028,6 +2037,10 @@
|
|
|
2028
2037
|
},
|
|
2029
2038
|
"task": {
|
|
2030
2039
|
"type": "string"
|
|
2040
|
+
},
|
|
2041
|
+
"importNodeLimit": {
|
|
2042
|
+
"type": "integer",
|
|
2043
|
+
"minimum": 1
|
|
2031
2044
|
}
|
|
2032
2045
|
}
|
|
2033
2046
|
},
|
|
@@ -2272,6 +2285,7 @@
|
|
|
2272
2285
|
"items": {
|
|
2273
2286
|
"enum": [
|
|
2274
2287
|
"caller-coverage-unknown",
|
|
2288
|
+
"code-facts-import-limit",
|
|
2275
2289
|
"code-facts-missing",
|
|
2276
2290
|
"code-facts-truncated",
|
|
2277
2291
|
"major-change-detected",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"type": "integer",
|
|
43
43
|
"minimum": 0
|
|
44
44
|
},
|
|
45
|
+
"untrackedExcludedCount": {
|
|
46
|
+
"type": "integer",
|
|
47
|
+
"minimum": 0,
|
|
48
|
+
"description": "Worktree files that Git does not ignore and that the HEAD tree does not carry (untracked and newly staged files). The scan measures HEAD only, so it excludes them. Optional: a scan from an older archctx does not report it."
|
|
49
|
+
},
|
|
45
50
|
"snapshot": {
|
|
46
51
|
"$ref": "#/$defs/moduleStatisticsSnapshot"
|
|
47
52
|
},
|
|
@@ -510,6 +515,7 @@
|
|
|
510
515
|
"items": {
|
|
511
516
|
"enum": [
|
|
512
517
|
"caller-coverage-unknown",
|
|
518
|
+
"code-facts-import-limit",
|
|
513
519
|
"code-facts-missing",
|
|
514
520
|
"code-facts-truncated",
|
|
515
521
|
"major-change-detected",
|
|
@@ -1780,12 +1786,20 @@
|
|
|
1780
1786
|
],
|
|
1781
1787
|
"minimum": 0
|
|
1782
1788
|
},
|
|
1789
|
+
"importNodeCount": {
|
|
1790
|
+
"type": [
|
|
1791
|
+
"integer",
|
|
1792
|
+
"null"
|
|
1793
|
+
],
|
|
1794
|
+
"minimum": 0
|
|
1795
|
+
},
|
|
1783
1796
|
"reasonCodes": {
|
|
1784
1797
|
"type": "array",
|
|
1785
1798
|
"uniqueItems": true,
|
|
1786
1799
|
"items": {
|
|
1787
1800
|
"enum": [
|
|
1788
1801
|
"caller-coverage-unknown",
|
|
1802
|
+
"code-facts-import-limit",
|
|
1789
1803
|
"code-facts-missing",
|
|
1790
1804
|
"code-facts-truncated",
|
|
1791
1805
|
"major-change-detected",
|
|
@@ -2068,6 +2082,10 @@
|
|
|
2068
2082
|
},
|
|
2069
2083
|
"task": {
|
|
2070
2084
|
"type": "string"
|
|
2085
|
+
},
|
|
2086
|
+
"importNodeLimit": {
|
|
2087
|
+
"type": "integer",
|
|
2088
|
+
"minimum": 1
|
|
2071
2089
|
}
|
|
2072
2090
|
}
|
|
2073
2091
|
},
|
|
@@ -2312,6 +2330,7 @@
|
|
|
2312
2330
|
"items": {
|
|
2313
2331
|
"enum": [
|
|
2314
2332
|
"caller-coverage-unknown",
|
|
2333
|
+
"code-facts-import-limit",
|
|
2315
2334
|
"code-facts-missing",
|
|
2316
2335
|
"code-facts-truncated",
|
|
2317
2336
|
"major-change-detected",
|
package/src/architecture.ts
CHANGED
|
@@ -90,11 +90,14 @@ export type DependencyConstraintStatus = (typeof DEPENDENCY_CONSTRAINT_STATUSES)
|
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Why a dependency result is not a complete observation: no index answered, the index attested
|
|
93
|
-
* to a different worktree, the
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* to a different worktree, the index holds more import nodes than the configured read limit
|
|
94
|
+
* (`code-facts-import-limit`), the read came back shorter than the population the index reported
|
|
95
|
+
* (`code-facts-truncated`), a constrained file carries a repository-local import that resolved to
|
|
96
|
+
* no file, or the workspace package map could not be read, so no bare workspace specifier could
|
|
97
|
+
* be resolved.
|
|
96
98
|
*/
|
|
97
99
|
export const DEPENDENCY_CONSTRAINT_REASON_CODES = [
|
|
100
|
+
"code-facts-import-limit",
|
|
98
101
|
"code-facts-stale",
|
|
99
102
|
"code-facts-truncated",
|
|
100
103
|
"code-facts-unavailable",
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `archctx docs anchors` (#298): a read-only signal for stale citations in human-owned text. It
|
|
3
|
+
* reads the human-owned regions of module documents and node prose (`summary`,
|
|
4
|
+
* `responsibilities`), and resolves each citation against the Git-visible tree and CodeGraph. It is
|
|
5
|
+
* a signal, not a gate: findings never change `ok`, freshness or the projection result.
|
|
6
|
+
*/
|
|
7
|
+
export const DOCS_ANCHORS_REPORT_SCHEMA_VERSION = "archcontext.docs-anchors/v1" as const;
|
|
8
|
+
|
|
9
|
+
export const DOCS_ANCHOR_FINDING_KINDS = ["line-moved", "line-out-of-range", "missing-path", "missing-symbol"] as const;
|
|
10
|
+
export type DocsAnchorFindingKind = (typeof DOCS_ANCHOR_FINDING_KINDS)[number];
|
|
11
|
+
|
|
12
|
+
/** Why a citation was found but one of its checks could not run. */
|
|
13
|
+
export const DOCS_ANCHOR_UNCHECKED_REASON_CODES = ["codegraph-unavailable", "language-unsupported", "path-ambiguous"] as const;
|
|
14
|
+
export type DocsAnchorUncheckedReasonCode = (typeof DOCS_ANCHOR_UNCHECKED_REASON_CODES)[number];
|
|
15
|
+
|
|
16
|
+
export const DOCS_ANCHOR_CODEGRAPH_UNAVAILABLE_REASON_CODES = ["index-missing", "index-open-failed"] as const;
|
|
17
|
+
export type DocsAnchorCodeGraphUnavailableReasonCode = (typeof DOCS_ANCHOR_CODEGRAPH_UNAVAILABLE_REASON_CODES)[number];
|
|
18
|
+
|
|
19
|
+
/** Where the citation is written: a human-owned document line, or a field of the node. */
|
|
20
|
+
export type DocsAnchorOriginV1 =
|
|
21
|
+
| { kind: "document"; path: string; line: number }
|
|
22
|
+
| { kind: "node-summary" }
|
|
23
|
+
| { kind: "node-responsibility"; index: number };
|
|
24
|
+
|
|
25
|
+
export interface DocsAnchorCitationV1 {
|
|
26
|
+
/** The inline code span as written, without the backticks. */
|
|
27
|
+
text: string;
|
|
28
|
+
/** The cited path as written. */
|
|
29
|
+
path?: string;
|
|
30
|
+
/** The Git-visible file or directory the path resolved to, when it differs from `path`. */
|
|
31
|
+
resolvedPath?: string;
|
|
32
|
+
line?: number;
|
|
33
|
+
endLine?: number;
|
|
34
|
+
symbol?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DocsAnchorFindingV1 {
|
|
38
|
+
kind: DocsAnchorFindingKind;
|
|
39
|
+
origin: DocsAnchorOriginV1;
|
|
40
|
+
citation: DocsAnchorCitationV1;
|
|
41
|
+
/** `line-out-of-range` only: the current line count of the cited file. */
|
|
42
|
+
lineCount?: number;
|
|
43
|
+
/** `line-moved` only: the current start lines of the cited symbol, sorted. */
|
|
44
|
+
currentLines?: number[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface DocsAnchorUncheckedV1 {
|
|
48
|
+
reasonCode: DocsAnchorUncheckedReasonCode;
|
|
49
|
+
origin: DocsAnchorOriginV1;
|
|
50
|
+
citation: DocsAnchorCitationV1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface DocsAnchorsNodeV1 {
|
|
54
|
+
nodeId: string;
|
|
55
|
+
/** The node's module document, when the active layout has one and it exists. */
|
|
56
|
+
documentPath?: string;
|
|
57
|
+
citationCount: number;
|
|
58
|
+
findings: DocsAnchorFindingV1[];
|
|
59
|
+
unchecked: DocsAnchorUncheckedV1[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type DocsAnchorsCodeGraphV1 =
|
|
63
|
+
| { availability: "ready" }
|
|
64
|
+
| { availability: "unavailable"; reasonCode: DocsAnchorCodeGraphUnavailableReasonCode };
|
|
65
|
+
|
|
66
|
+
export interface DocsAnchorsReportV1 {
|
|
67
|
+
schemaVersion: typeof DOCS_ANCHORS_REPORT_SCHEMA_VERSION;
|
|
68
|
+
profile: "default" | "repo-harness/v1";
|
|
69
|
+
codeGraph: DocsAnchorsCodeGraphV1;
|
|
70
|
+
summary: {
|
|
71
|
+
/** Model nodes whose prose and module document were read. */
|
|
72
|
+
nodes: number;
|
|
73
|
+
/** Module documents read. */
|
|
74
|
+
documents: number;
|
|
75
|
+
citations: number;
|
|
76
|
+
findings: number;
|
|
77
|
+
unchecked: number;
|
|
78
|
+
byKind: Record<DocsAnchorFindingKind, number>;
|
|
79
|
+
};
|
|
80
|
+
/** Nodes with at least one citation, sorted by `nodeId`. */
|
|
81
|
+
nodes: DocsAnchorsNodeV1[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function docsAnchorsReportIssues(report: DocsAnchorsReportV1): string[] {
|
|
85
|
+
const issues: string[] = [];
|
|
86
|
+
const ids = report.nodes.map((node) => node.nodeId);
|
|
87
|
+
const sorted = [...new Set(ids)].sort();
|
|
88
|
+
if (sorted.length !== ids.length || sorted.some((id, index) => id !== ids[index])) issues.push("nodes.nodeId must be sorted and unique");
|
|
89
|
+
const findings = report.nodes.flatMap((node) => node.findings);
|
|
90
|
+
const unchecked = report.nodes.flatMap((node) => node.unchecked);
|
|
91
|
+
if (report.summary.citations !== report.nodes.reduce((total, node) => total + node.citationCount, 0)) issues.push("summary.citations must equal the sum of nodes[].citationCount");
|
|
92
|
+
if (report.summary.findings !== findings.length) issues.push("summary.findings must equal the number of findings");
|
|
93
|
+
if (report.summary.unchecked !== unchecked.length) issues.push("summary.unchecked must equal the number of unchecked citations");
|
|
94
|
+
for (const kind of DOCS_ANCHOR_FINDING_KINDS) {
|
|
95
|
+
if (report.summary.byKind[kind] !== findings.filter((finding) => finding.kind === kind).length) issues.push(`summary.byKind.${kind} must equal the number of ${kind} findings`);
|
|
96
|
+
}
|
|
97
|
+
for (const [index, node] of report.nodes.entries()) {
|
|
98
|
+
if (node.citationCount === 0) issues.push(`nodes[${index}] must have at least one citation`);
|
|
99
|
+
for (const [findingIndex, finding] of node.findings.entries()) {
|
|
100
|
+
issues.push(...docsAnchorFindingIssues(finding, `nodes[${index}].findings[${findingIndex}]`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (report.codeGraph.availability === "ready" && unchecked.some((entry) => entry.reasonCode === "codegraph-unavailable")) {
|
|
104
|
+
issues.push("codegraph-unavailable is reported only when codeGraph.availability is unavailable");
|
|
105
|
+
}
|
|
106
|
+
return issues;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function docsAnchorFindingIssues(finding: DocsAnchorFindingV1, prefix: string): string[] {
|
|
110
|
+
const issues: string[] = [];
|
|
111
|
+
const { citation } = finding;
|
|
112
|
+
if (finding.kind === "missing-path" && citation.path === undefined) issues.push(`${prefix} missing-path must name citation.path`);
|
|
113
|
+
if (finding.kind === "missing-symbol" && citation.symbol === undefined) issues.push(`${prefix} missing-symbol must name citation.symbol`);
|
|
114
|
+
if (finding.kind === "line-out-of-range" && (citation.line === undefined || finding.lineCount === undefined)) {
|
|
115
|
+
issues.push(`${prefix} line-out-of-range must name citation.line and lineCount`);
|
|
116
|
+
}
|
|
117
|
+
if ((finding.lineCount !== undefined) !== (finding.kind === "line-out-of-range")) issues.push(`${prefix}.lineCount is present only on line-out-of-range`);
|
|
118
|
+
if (finding.kind === "line-moved") {
|
|
119
|
+
const lines = finding.currentLines ?? [];
|
|
120
|
+
if (citation.line === undefined || citation.symbol === undefined) issues.push(`${prefix} line-moved must name citation.line and citation.symbol`);
|
|
121
|
+
if (lines.length === 0 || lines.some((line, index) => index > 0 && line <= lines[index - 1]!)) issues.push(`${prefix}.currentLines must be non-empty, sorted and unique`);
|
|
122
|
+
} else if (finding.currentLines !== undefined) {
|
|
123
|
+
issues.push(`${prefix}.currentLines is present only on line-moved`);
|
|
124
|
+
}
|
|
125
|
+
return issues;
|
|
126
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./control-plane-routes";
|
|
2
2
|
export * from "./architecture";
|
|
3
|
+
export * from "./docs-anchors";
|
|
3
4
|
export * from "./external-docs";
|
|
4
5
|
export * from "./github-governance";
|
|
5
6
|
export * from "./ledger";
|
|
7
|
+
export * from "./ownership-dependencies";
|
|
6
8
|
export * from "./ports";
|
|
7
9
|
export * from "./practices";
|
|
8
10
|
export * from "./projection";
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { EvidenceCoverageLevelV2 } from "./ledger";
|
|
2
|
+
|
|
3
|
+
// --- ChangeSet ownership delta (plan preview) ---
|
|
4
|
+
//
|
|
5
|
+
// `archctx plan` and `archcontext_plan_update` add `preview.ownershipDelta` when a planned
|
|
6
|
+
// ChangeSet writes a node file. It compares file ownership before and after the planned model over
|
|
7
|
+
// the files the HEAD tree carries, with the parent-chain rule `refactor scan` uses
|
|
8
|
+
// (module-statistics `resolveOwnership`). It is read-only: nothing is written to compute it.
|
|
9
|
+
|
|
10
|
+
export const CHANGESET_OWNERSHIP_DELTA_SCHEMA_VERSION = "archcontext.changeset-ownership-delta/v1" as const;
|
|
11
|
+
/** Upper bound on the paths one ownership delta category lists. `count` always holds the full total. */
|
|
12
|
+
export const CHANGESET_OWNERSHIP_DELTA_PATH_LIMIT = 50;
|
|
13
|
+
|
|
14
|
+
export interface OwnershipDeltaSummaryV1 {
|
|
15
|
+
ownedFileCount: number;
|
|
16
|
+
/** Owned files whose claimants do not sit on one `parent` chain. */
|
|
17
|
+
multiplyOwnedFileCount: number;
|
|
18
|
+
/** Unclaimed files under a declared source root that no node excludes. */
|
|
19
|
+
unownedFileCount: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface OwnershipDeltaFileV1 {
|
|
23
|
+
path: string;
|
|
24
|
+
/** Owning node ids before the plan, sorted. More than one id means the claim is contested. */
|
|
25
|
+
before: string[];
|
|
26
|
+
/** Owning node ids after the plan, sorted. */
|
|
27
|
+
after: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface OwnershipDeltaCategoryV1 {
|
|
31
|
+
/** Every file in this category. */
|
|
32
|
+
count: number;
|
|
33
|
+
/** The first `pathLimit` files, sorted by path. */
|
|
34
|
+
files: OwnershipDeltaFileV1[];
|
|
35
|
+
/** `count - files.length`. */
|
|
36
|
+
omittedCount: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ChangeSetOwnershipDeltaComputedV1 {
|
|
40
|
+
schemaVersion: typeof CHANGESET_OWNERSHIP_DELTA_SCHEMA_VERSION;
|
|
41
|
+
status: "computed";
|
|
42
|
+
ownershipRule: "parent-chain";
|
|
43
|
+
fileUniverse: "head-tracked-files";
|
|
44
|
+
trackedFileCount: number;
|
|
45
|
+
/** Node ids whose `source.include`, `source.exclude` or `parent` differ, or that the plan creates or deletes. */
|
|
46
|
+
changedNodeIds: string[];
|
|
47
|
+
pathLimit: number;
|
|
48
|
+
before: OwnershipDeltaSummaryV1;
|
|
49
|
+
after: OwnershipDeltaSummaryV1;
|
|
50
|
+
/** Unowned before, owned by exactly one node after. */
|
|
51
|
+
becameOwned: OwnershipDeltaCategoryV1;
|
|
52
|
+
/** Not contested before, contested (multiply owned) after. */
|
|
53
|
+
becameContested: OwnershipDeltaCategoryV1;
|
|
54
|
+
/** Owned before, owned by a different node set after, and not newly contested. */
|
|
55
|
+
ownerChanged: OwnershipDeltaCategoryV1;
|
|
56
|
+
/** Owned before, unowned after. */
|
|
57
|
+
becameUnowned: OwnershipDeltaCategoryV1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ChangeSetOwnershipDeltaUnavailableV1 {
|
|
61
|
+
schemaVersion: typeof CHANGESET_OWNERSHIP_DELTA_SCHEMA_VERSION;
|
|
62
|
+
status: "unavailable";
|
|
63
|
+
/** Why no delta was computed, for example a planned node body that does not parse. */
|
|
64
|
+
reason: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ChangeSetOwnershipDeltaV1 = ChangeSetOwnershipDeltaComputedV1 | ChangeSetOwnershipDeltaUnavailableV1;
|
|
68
|
+
|
|
69
|
+
// --- Capability dependency matrix (`archctx deps`) ---
|
|
70
|
+
|
|
71
|
+
export const CAPABILITY_DEPENDENCIES_SCHEMA_VERSION = "archcontext.capability-dependencies/v1" as const;
|
|
72
|
+
/** Default number of file-level edges `archctx deps` lists. `edges.count` always holds the full total. */
|
|
73
|
+
export const CAPABILITY_DEPENDENCIES_EDGE_LIMIT = 200;
|
|
74
|
+
/** The CodeGraph adapter has no bounded repository-wide call-edge read, so calls are not counted. */
|
|
75
|
+
export const CAPABILITY_DEPENDENCIES_CALLS_UNAVAILABLE_REASON = "call-edges-not-exposed" as const;
|
|
76
|
+
|
|
77
|
+
export interface CapabilityDependencyCellV1 {
|
|
78
|
+
/** Owning capability of the importing file. */
|
|
79
|
+
from: string;
|
|
80
|
+
/** Owning capability of the imported file. */
|
|
81
|
+
to: string;
|
|
82
|
+
/** Distinct file-to-file import edges from `from` into `to`. */
|
|
83
|
+
imports: number;
|
|
84
|
+
/** Always `null` in v1: call edges are not read (see `calls`). */
|
|
85
|
+
calls: null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface CapabilityDependencyEdgeV1 {
|
|
89
|
+
fromPath: string;
|
|
90
|
+
toPath: string;
|
|
91
|
+
fromCapability: string;
|
|
92
|
+
toCapability: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface CapabilityDependenciesV1 {
|
|
96
|
+
schemaVersion: typeof CAPABILITY_DEPENDENCIES_SCHEMA_VERSION;
|
|
97
|
+
ownershipRule: "parent-chain";
|
|
98
|
+
/** `--from` / `--into` node ids, or `null`. A node matches a file when it or a descendant owns it. */
|
|
99
|
+
filter: { from: string | null; into: string | null };
|
|
100
|
+
/** Every `kind: capability` node id in the model, sorted. */
|
|
101
|
+
capabilities: string[];
|
|
102
|
+
/** Non-zero cells only, sorted by `from` then `to`. A cell with `from === to` counts edges inside one capability. */
|
|
103
|
+
matrix: CapabilityDependencyCellV1[];
|
|
104
|
+
imports: {
|
|
105
|
+
coverage: EvidenceCoverageLevelV2;
|
|
106
|
+
/** `code-facts-unavailable`, `code-facts-stale`, `code-facts-import-limit`, `code-facts-truncated`. */
|
|
107
|
+
reasonCodes: string[];
|
|
108
|
+
/** True when the index read is not the whole population for a reason other than the limit. */
|
|
109
|
+
truncated: boolean;
|
|
110
|
+
importNodeCount: number | null;
|
|
111
|
+
importNodeLimit: number;
|
|
112
|
+
importNodeLimitExceeded: boolean;
|
|
113
|
+
/** Distinct file-to-file edges that passed the filters, attributed or not. */
|
|
114
|
+
edgeCount: number;
|
|
115
|
+
/**
|
|
116
|
+
* Repository-local import specifiers (relative, or naming a workspace package) from filtered
|
|
117
|
+
* files that resolved to no repository file. Always 0 with `--into`: such an edge has no target.
|
|
118
|
+
*/
|
|
119
|
+
unresolvedCount: number;
|
|
120
|
+
/** Edges left out of `matrix` because one endpoint has no single owning capability. */
|
|
121
|
+
unattributed: { unownedEndpoint: number; contestedEndpoint: number; noCapabilityEndpoint: number };
|
|
122
|
+
};
|
|
123
|
+
calls: {
|
|
124
|
+
coverage: "unknown";
|
|
125
|
+
reasonCodes: [typeof CAPABILITY_DEPENDENCIES_CALLS_UNAVAILABLE_REASON];
|
|
126
|
+
};
|
|
127
|
+
/** Attributed file-level edges behind `matrix`, sorted by path. */
|
|
128
|
+
edges: { limit: number; count: number; omittedCount: number; items: CapabilityDependencyEdgeV1[] };
|
|
129
|
+
}
|
package/src/product-version.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const ARCHCONTEXT_PRODUCT_NAME = "archctx";
|
|
2
|
-
export const ARCHCONTEXT_PRODUCT_VERSION = "0.7.
|
|
2
|
+
export const ARCHCONTEXT_PRODUCT_VERSION = "0.7.2";
|
|
3
3
|
export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3";
|
|
4
4
|
export const ARCHCONTEXT_NODE_RANGE = ">=22.22 <26";
|
|
5
5
|
export const LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1";
|
package/src/projection.ts
CHANGED
|
@@ -62,8 +62,12 @@ export const ARCHCTX_FEATURES = [
|
|
|
62
62
|
"architecture-change-capabilities-v1",
|
|
63
63
|
"architecture-docs-renderer-v2",
|
|
64
64
|
"architecture-refresh-signal-v1",
|
|
65
|
+
"capability-dependencies-v1",
|
|
65
66
|
"changeset-entity-operations-v1",
|
|
67
|
+
"changeset-ownership-delta-v1",
|
|
66
68
|
"code-facts-unavailable-error-v1",
|
|
69
|
+
"docs-anchors-v1",
|
|
70
|
+
"flow-selector-check-v1",
|
|
67
71
|
"module-statistics-v1",
|
|
68
72
|
"projection-apply-readback-v1",
|
|
69
73
|
"projection-apply-receipt-v1",
|
|
@@ -81,7 +85,8 @@ export const ARCHCTX_FEATURES = [
|
|
|
81
85
|
"refactor-assessment-v1",
|
|
82
86
|
"refactor-observation-evidence-v1",
|
|
83
87
|
"refactor-resolution-v1",
|
|
84
|
-
"refactor-scan-limits-v1"
|
|
88
|
+
"refactor-scan-limits-v1",
|
|
89
|
+
"refactor-scan-untracked-count-v1"
|
|
85
90
|
] as const;
|
|
86
91
|
|
|
87
92
|
/**
|
|
@@ -103,6 +108,69 @@ export const ARCHITECTURE_SEMANTIC_FACETS = [
|
|
|
103
108
|
export const ARCHITECTURE_PROOF_P1_STATUSES = ["proven", "unprovable"] as const;
|
|
104
109
|
export const ARCHITECTURE_PROOF_P2_STATUSES = ["not-applicable", "proven", "unprovable"] as const;
|
|
105
110
|
|
|
111
|
+
export const ARCHITECTURE_FLOW_SELECTOR_CHECK_SCHEMA_VERSION = "archcontext.flow-selector-check/v1" as const;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The proof status of one declared entrypoint→sink selector, as the P2 flow proof reads its
|
|
115
|
+
* evidence. Only `proven` can bind a flow step. `no-direct-call`: no `calls` edge from the source
|
|
116
|
+
* to the sink. `only-references`: no proving call, but the source references the sink by value.
|
|
117
|
+
* `false-builtin-call`: the only calls carry a runtime built-in name and the source file does not
|
|
118
|
+
* import the sink file. `ambiguous-symbol`: the source or the sink matches more than one indexed
|
|
119
|
+
* symbol. `evidence-missing`: no evidence was measured (for example, no CodeGraph index).
|
|
120
|
+
* `evidence-truncated`: the evidence producer could not enumerate every edge.
|
|
121
|
+
*/
|
|
122
|
+
export const ARCHITECTURE_FLOW_SELECTOR_PROOF_STATUSES = [
|
|
123
|
+
"ambiguous-symbol",
|
|
124
|
+
"evidence-missing",
|
|
125
|
+
"evidence-truncated",
|
|
126
|
+
"false-builtin-call",
|
|
127
|
+
"no-direct-call",
|
|
128
|
+
"only-references",
|
|
129
|
+
"proven"
|
|
130
|
+
] as const;
|
|
131
|
+
export type ArchitectureFlowSelectorProofStatus = typeof ARCHITECTURE_FLOW_SELECTOR_PROOF_STATUSES[number];
|
|
132
|
+
|
|
133
|
+
export interface ArchitectureFlowSelectorSiteV1 {
|
|
134
|
+
path: string;
|
|
135
|
+
line?: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ArchitectureFlowSelectorCheckEntryV1 {
|
|
139
|
+
nodeId: string;
|
|
140
|
+
entrypointId: string;
|
|
141
|
+
sourcePath: string;
|
|
142
|
+
sourceSymbol: string;
|
|
143
|
+
sinkId: string;
|
|
144
|
+
sinkPath: string;
|
|
145
|
+
sinkSymbol: string;
|
|
146
|
+
status: ArchitectureFlowSelectorProofStatus;
|
|
147
|
+
callSites: ArchitectureFlowSelectorSiteV1[];
|
|
148
|
+
referenceSites: ArchitectureFlowSelectorSiteV1[];
|
|
149
|
+
rejectedBuiltinCallSites: ArchitectureFlowSelectorSiteV1[];
|
|
150
|
+
/** The required-flow steps that name this selector as evidence. Empty for an unused selector. */
|
|
151
|
+
flowSteps: Array<{ flowId: string; stepId: string }>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface ArchitectureFlowSelectorCheckCapabilityV1 {
|
|
155
|
+
capabilityId: string;
|
|
156
|
+
/** The same P2 status a projection records for this capability. */
|
|
157
|
+
p2Status: typeof ARCHITECTURE_PROOF_P2_STATUSES[number];
|
|
158
|
+
diagnostics: Array<{ code: string; flowId?: string; stepId?: string; detail: string }>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* `archctx flows check`: the P2 flow proof without rendering. Read-only. `ok` is true when no
|
|
163
|
+
* capability that declares a flow has an unprovable P2 proof.
|
|
164
|
+
*/
|
|
165
|
+
export interface ArchitectureFlowSelectorCheckV1 {
|
|
166
|
+
schemaVersion: typeof ARCHITECTURE_FLOW_SELECTOR_CHECK_SCHEMA_VERSION;
|
|
167
|
+
ok: boolean;
|
|
168
|
+
codeGraph: { availability: "ready" | "unavailable"; version: string };
|
|
169
|
+
summary: { selectors: number; proven: number; unproven: number; usedUnproven: number };
|
|
170
|
+
selectors: ArchitectureFlowSelectorCheckEntryV1[];
|
|
171
|
+
capabilities: ArchitectureFlowSelectorCheckCapabilityV1[];
|
|
172
|
+
}
|
|
173
|
+
|
|
106
174
|
/** `files[].preview.format`: a `create` carries the rendered body, an `update` or `delete` a unified diff. */
|
|
107
175
|
export const PROJECTION_FILE_PREVIEW_FORMATS = ["body", "unified-diff"] as const;
|
|
108
176
|
/** Upper bound, in UTF-8 bytes, on one `files[].preview.content`. */
|
package/src/refactor.ts
CHANGED
|
@@ -42,6 +42,7 @@ export const REFACTOR_VERIFICATION_REQUEST_KEYS = [
|
|
|
42
42
|
"executionEvidenceRefs",
|
|
43
43
|
"expectedHeadSha",
|
|
44
44
|
"expectedWorktreeDigest",
|
|
45
|
+
"importNodeLimit",
|
|
45
46
|
"recommendationId",
|
|
46
47
|
"schemaVersion"
|
|
47
48
|
] as const;
|
|
@@ -62,6 +63,7 @@ export const REFACTOR_SCALES = [
|
|
|
62
63
|
] as const;
|
|
63
64
|
export const REFACTOR_SCALE_REASON_CODES = [
|
|
64
65
|
"caller-coverage-unknown",
|
|
66
|
+
"code-facts-import-limit",
|
|
65
67
|
"code-facts-missing",
|
|
66
68
|
"code-facts-truncated",
|
|
67
69
|
"major-change-detected",
|
|
@@ -198,6 +200,11 @@ export interface RefactorRequestV1 {
|
|
|
198
200
|
expectedHeadSha?: string;
|
|
199
201
|
expectedWorktreeDigest?: string;
|
|
200
202
|
task?: string;
|
|
203
|
+
/**
|
|
204
|
+
* The most CodeGraph import nodes the scan reads. Omitted means the runtime default. A larger
|
|
205
|
+
* index gives partial coverage with `code-facts-import-limit`, never `code-facts-truncated`.
|
|
206
|
+
*/
|
|
207
|
+
importNodeLimit?: number;
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
/**
|
|
@@ -216,6 +223,11 @@ export interface RefactorVerificationRequestV1 {
|
|
|
216
223
|
expectedHeadSha?: string;
|
|
217
224
|
expectedWorktreeDigest?: string;
|
|
218
225
|
executionEvidenceRefs?: RefactorExecutionEvidenceRefV1[];
|
|
226
|
+
/**
|
|
227
|
+
* The most CodeGraph import nodes the re-measure reads. Omitted means the limit the recorded
|
|
228
|
+
* baseline snapshot was measured with, so BEFORE and AFTER read the same import population.
|
|
229
|
+
*/
|
|
230
|
+
importNodeLimit?: number;
|
|
219
231
|
}
|
|
220
232
|
|
|
221
233
|
export interface ModuleStatisticsV1 {
|
|
@@ -281,8 +293,18 @@ export interface ModuleStatisticsSnapshotV1 {
|
|
|
281
293
|
binaryDigest: string;
|
|
282
294
|
indexedWorktreeDigest: string | null;
|
|
283
295
|
coverage: EvidenceCoverageLevelV2;
|
|
296
|
+
/**
|
|
297
|
+
* True only when the read is shorter than the population the index reported. A read cut by
|
|
298
|
+
* `edgeLimit` is not truncated: it reports `code-facts-import-limit` instead.
|
|
299
|
+
*/
|
|
284
300
|
truncated: boolean;
|
|
301
|
+
/** The import-node read limit the scan applied. */
|
|
285
302
|
edgeLimit: number | null;
|
|
303
|
+
/**
|
|
304
|
+
* Import nodes the index reported, or `null` when no index gave a count. Absent on snapshots
|
|
305
|
+
* recorded before the field existed.
|
|
306
|
+
*/
|
|
307
|
+
importNodeCount?: number | null;
|
|
286
308
|
reasonCodes: RefactorScaleReasonCode[];
|
|
287
309
|
};
|
|
288
310
|
modules: ModuleStatisticsV1[];
|
|
@@ -594,6 +616,9 @@ export function refactorRequestInvariantIssues(request: RefactorRequestV1, prefi
|
|
|
594
616
|
}
|
|
595
617
|
}
|
|
596
618
|
if (request.proposal) issues.push(...refactorProposalInvariantIssues(request.proposal, `${prefix}.proposal`));
|
|
619
|
+
if (request.importNodeLimit !== undefined && !(Number.isInteger(request.importNodeLimit) && request.importNodeLimit >= 1)) {
|
|
620
|
+
issues.push(`${prefix}.importNodeLimit must be a positive integer`);
|
|
621
|
+
}
|
|
597
622
|
return issues;
|
|
598
623
|
}
|
|
599
624
|
|
|
@@ -630,6 +655,9 @@ export function refactorVerificationRequestInvariantIssues(
|
|
|
630
655
|
if (request.expectedWorktreeDigest !== undefined) {
|
|
631
656
|
issues.push(...digestIssues(`${prefix}.expectedWorktreeDigest`, request.expectedWorktreeDigest));
|
|
632
657
|
}
|
|
658
|
+
if (request.importNodeLimit !== undefined && !(Number.isInteger(request.importNodeLimit) && request.importNodeLimit >= 1)) {
|
|
659
|
+
issues.push(`${prefix}.importNodeLimit must be a positive integer`);
|
|
660
|
+
}
|
|
633
661
|
if (request.executionEvidenceRefs !== undefined) {
|
|
634
662
|
if (!Array.isArray(request.executionEvidenceRefs)) {
|
|
635
663
|
issues.push(`${prefix}.executionEvidenceRefs must be an array`);
|
|
@@ -722,6 +750,15 @@ export function moduleStatisticsSnapshotInvariantIssues(snapshot: ModuleStatisti
|
|
|
722
750
|
}
|
|
723
751
|
}
|
|
724
752
|
issues.push(...nonNegativeIntegerIssues(`${prefix}.codeFacts.edgeLimit`, snapshot.codeFacts.edgeLimit));
|
|
753
|
+
const importNodeCount = snapshot.codeFacts.importNodeCount ?? null;
|
|
754
|
+
issues.push(...nonNegativeIntegerIssues(`${prefix}.codeFacts.importNodeCount`, importNodeCount));
|
|
755
|
+
if (snapshot.codeFacts.reasonCodes.includes("code-facts-import-limit")) {
|
|
756
|
+
const { edgeLimit } = snapshot.codeFacts;
|
|
757
|
+
if (snapshot.codeFacts.coverage !== "partial") issues.push(`${prefix}.codeFacts.coverage must be partial when the import limit was reached`);
|
|
758
|
+
if (edgeLimit === null || (importNodeCount !== null && importNodeCount <= edgeLimit)) {
|
|
759
|
+
issues.push(`${prefix}.codeFacts.importNodeCount must exceed edgeLimit when the import limit was reached`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
725
762
|
for (const [field, value] of Object.entries(snapshot.repositorySummary)) {
|
|
726
763
|
issues.push(...nonNegativeIntegerIssues(`${prefix}.repositorySummary.${field}`, value));
|
|
727
764
|
}
|