archctx-contracts 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fixtures/boundary/architecture-node-extension.json +1 -1
- package/fixtures/invalid/node-unknown-field.json +1 -1
- package/fixtures/valid/archctx-capabilities.json +14 -0
- package/fixtures/valid/architecture-flow.json +53 -0
- package/fixtures/valid/architecture-node.json +19 -2
- package/fixtures/valid/architecture-refresh-signal.json +35 -0
- package/fixtures/valid/product-version-manifest.json +6 -6
- package/fixtures/valid/projection-request.json +14 -0
- package/fixtures/valid/projection-result.json +47 -0
- package/package.json +1 -1
- package/schemas/repo/architecture-flow.schema.json +97 -0
- package/schemas/repo/architecture-node.schema.json +39 -2
- package/schemas/runtime/archctx-capabilities.schema.json +45 -0
- package/schemas/runtime/architecture-refresh-signal.schema.json +88 -0
- package/schemas/runtime/changeset.schema.json +1 -1
- package/schemas/runtime/projection-request.schema.json +61 -0
- package/schemas/runtime/projection-result.schema.json +162 -0
- package/src/architecture.ts +73 -0
- package/src/index.ts +2 -0
- package/src/product-version.ts +3 -3
- package/src/projection.ts +301 -0
- package/src/validator.ts +18 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.capabilities/v1",
|
|
3
|
+
"package": { "name": "archctx", "version": "0.4.0" },
|
|
4
|
+
"protocols": {
|
|
5
|
+
"projectionRequest": "archcontext.projection-request/v1",
|
|
6
|
+
"projectionResult": "archcontext.projection-result/v1",
|
|
7
|
+
"architectureRefreshSignal": "archcontext.architecture-refresh-signal/v1"
|
|
8
|
+
},
|
|
9
|
+
"renderers": {
|
|
10
|
+
"architectureDocs": "archcontext.docs-renderer/v2",
|
|
11
|
+
"agentContext": "archcontext.agent-context-renderer/v1"
|
|
12
|
+
},
|
|
13
|
+
"features": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-protocol-v1"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.flow/v1",
|
|
3
|
+
"id": "flow.subscriptions.create",
|
|
4
|
+
"capabilityId": "capability.subscriptions",
|
|
5
|
+
"name": "Create subscription",
|
|
6
|
+
"applicability": "required",
|
|
7
|
+
"participants": [
|
|
8
|
+
{ "id": "client", "nodeId": "external.client" },
|
|
9
|
+
{ "id": "api", "nodeId": "module.subscription" },
|
|
10
|
+
{ "id": "store", "nodeId": "datastore.subscription" }
|
|
11
|
+
],
|
|
12
|
+
"steps": [
|
|
13
|
+
{
|
|
14
|
+
"id": "request",
|
|
15
|
+
"from": "client",
|
|
16
|
+
"to": "api",
|
|
17
|
+
"label": "Create subscription",
|
|
18
|
+
"evidence": { "entrypointId": "entrypoint.subscription.create", "sourceSymbol": "createSubscription", "sinkId": "sink.subscription.persist" }
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"outcomes": [
|
|
22
|
+
{
|
|
23
|
+
"id": "accepted",
|
|
24
|
+
"kind": "success",
|
|
25
|
+
"label": "Subscription accepted",
|
|
26
|
+
"steps": [
|
|
27
|
+
{
|
|
28
|
+
"id": "persist",
|
|
29
|
+
"from": "api",
|
|
30
|
+
"to": "store",
|
|
31
|
+
"label": "Persist subscription",
|
|
32
|
+
"evidence": { "entrypointId": "entrypoint.subscription.create", "sourceSymbol": "createSubscription", "sinkId": "sink.subscription.persist" }
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"terminal": { "participant": "api", "label": "Return subscription ID" }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "rejected",
|
|
39
|
+
"kind": "error",
|
|
40
|
+
"label": "Subscription rejected",
|
|
41
|
+
"steps": [
|
|
42
|
+
{
|
|
43
|
+
"id": "reject",
|
|
44
|
+
"from": "api",
|
|
45
|
+
"to": "client",
|
|
46
|
+
"label": "Return validation error",
|
|
47
|
+
"evidence": { "entrypointId": "entrypoint.subscription.create", "sourceSymbol": "createSubscription", "sinkId": "sink.subscription.persist" }
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"terminal": { "participant": "client", "label": "Handle validation error" }
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion": "archcontext.node/
|
|
2
|
+
"schemaVersion": "archcontext.node/v2",
|
|
3
3
|
"id": "module.subscription",
|
|
4
4
|
"kind": "module",
|
|
5
5
|
"name": "Subscription",
|
|
@@ -10,7 +10,24 @@
|
|
|
10
10
|
"source": {
|
|
11
11
|
"include": ["src/subscription/**"],
|
|
12
12
|
"exclude": ["src/subscription/generated/**"],
|
|
13
|
-
"entrypoints": [
|
|
13
|
+
"entrypoints": [
|
|
14
|
+
{
|
|
15
|
+
"id": "entrypoint.subscription.create",
|
|
16
|
+
"path": "src/subscription/index.ts",
|
|
17
|
+
"symbols": [
|
|
18
|
+
{
|
|
19
|
+
"name": "createSubscription",
|
|
20
|
+
"sinks": [
|
|
21
|
+
{
|
|
22
|
+
"id": "sink.subscription.persist",
|
|
23
|
+
"path": "src/subscription/store.ts",
|
|
24
|
+
"symbol": "saveSubscription"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
14
31
|
},
|
|
15
32
|
"ownership": {
|
|
16
33
|
"lifecycle": ["subscription"],
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.architecture-refresh-signal/v1",
|
|
3
|
+
"signalId": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
|
4
|
+
"idempotencyKey": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
|
|
5
|
+
"mode": "refresh-required",
|
|
6
|
+
"repository": { "repositoryId": "repo.example" },
|
|
7
|
+
"worktree": {
|
|
8
|
+
"workspaceId": "ws.example",
|
|
9
|
+
"headSha": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
10
|
+
"worktreeDigest": "sha256:3333333333333333333333333333333333333333333333333333333333333333"
|
|
11
|
+
},
|
|
12
|
+
"cause": "accepted-semantic-delta",
|
|
13
|
+
"acceptedChange": {
|
|
14
|
+
"changeSetId": "changeset.architecture-api-v2",
|
|
15
|
+
"eventId": "architecture_event.changeset_apply.api-v2",
|
|
16
|
+
"reasonCodes": ["entrypoint-changed", "responsibility-changed"],
|
|
17
|
+
"affectedNodeIds": ["capability.api", "capability.runtime"]
|
|
18
|
+
},
|
|
19
|
+
"reasonCodes": ["entrypoint-changed", "responsibility-changed"],
|
|
20
|
+
"affectedNodeIds": ["capability.api", "capability.runtime"],
|
|
21
|
+
"refreshTargets": ["architecture-contract-context", "architecture-readiness", "capability-context", "capability-index"],
|
|
22
|
+
"baseDigests": {
|
|
23
|
+
"modelDigest": "sha256:4444444444444444444444444444444444444444444444444444444444444444",
|
|
24
|
+
"sourceTreeDigest": "sha256:5555555555555555555555555555555555555555555555555555555555555555",
|
|
25
|
+
"flowProofDigest": "sha256:6666666666666666666666666666666666666666666666666666666666666666",
|
|
26
|
+
"projectionDigest": "sha256:7777777777777777777777777777777777777777777777777777777777777777"
|
|
27
|
+
},
|
|
28
|
+
"resultingDigests": {
|
|
29
|
+
"modelDigest": "sha256:8888888888888888888888888888888888888888888888888888888888888888",
|
|
30
|
+
"sourceTreeDigest": "sha256:9999999999999999999999999999999999999999999999999999999999999999",
|
|
31
|
+
"flowProofDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
32
|
+
"projectionDigest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
33
|
+
},
|
|
34
|
+
"projectionReceiptDigest": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": "archcontext.product-version-manifest/v1",
|
|
3
3
|
"product": {
|
|
4
4
|
"name": "archctx",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"distribution": "one-package"
|
|
7
7
|
},
|
|
8
8
|
"packageManager": "bun@1.3.10",
|
|
@@ -12,25 +12,25 @@
|
|
|
12
12
|
"surfaces": {
|
|
13
13
|
"cli": {
|
|
14
14
|
"packageName": "@archcontext/surfaces",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.4.0",
|
|
16
16
|
"entrypoint": "archctx"
|
|
17
17
|
},
|
|
18
18
|
"daemon": {
|
|
19
19
|
"packageName": "@archcontext/local-runtime",
|
|
20
|
-
"version": "0.
|
|
20
|
+
"version": "0.4.0",
|
|
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.
|
|
26
|
+
"version": "0.4.0",
|
|
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.
|
|
33
|
+
"contractsPackageVersion": "0.4.0",
|
|
34
34
|
"reviewChallenge": "archcontext.review-challenge/v2",
|
|
35
35
|
"attestation": "archcontext.attestation/v2",
|
|
36
36
|
"deviceIdentity": "archcontext.device-identity/v1",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"sqliteMigrations": "0001_runtime_state..0012_explorer_projection_index",
|
|
45
45
|
"codeGraph": {
|
|
46
46
|
"packageName": "@colbymchenry/codegraph",
|
|
47
|
-
"requiredVersion": "1.
|
|
47
|
+
"requiredVersion": "1.5.0",
|
|
48
48
|
"adapter": "codegraph-cli"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.projection-request/v1",
|
|
3
|
+
"requestId": "projection_request.repo_main",
|
|
4
|
+
"profile": "repo-harness/v1",
|
|
5
|
+
"mode": "apply",
|
|
6
|
+
"targets": ["agent-context", "architecture-docs"],
|
|
7
|
+
"changedPaths": ["packages/core/src/index.ts", "src/cli/main.ts"],
|
|
8
|
+
"expected": {
|
|
9
|
+
"repositoryId": "repo.example",
|
|
10
|
+
"workspaceId": "ws.example",
|
|
11
|
+
"headSha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
12
|
+
"worktreeDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.projection-result/v1",
|
|
3
|
+
"requestId": "projection_request.repo_main",
|
|
4
|
+
"status": "applied",
|
|
5
|
+
"inputSnapshot": {
|
|
6
|
+
"repositoryId": "repo.example",
|
|
7
|
+
"workspaceId": "ws.example",
|
|
8
|
+
"headSha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
9
|
+
"baseHeadSha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
10
|
+
"worktreeDigest": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
|
11
|
+
"sourceTreeDigest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
|
|
12
|
+
"modelDigest": "sha256:3333333333333333333333333333333333333333333333333333333333333333",
|
|
13
|
+
"codeGraphDigest": "sha256:4444444444444444444444444444444444444444444444444444444444444444",
|
|
14
|
+
"indexedWorktreeDigest": "sha256:4545454545454545454545454545454545454545454545454545454545454545",
|
|
15
|
+
"projectionInputDigest": "sha256:5555555555555555555555555555555555555555555555555555555555555555",
|
|
16
|
+
"rendererVersion": "archcontext.docs-renderer/v2",
|
|
17
|
+
"layoutVersion": "archcontext.docs-layout/v1",
|
|
18
|
+
"generatedFrom": { "codeGraphPackage": "@colbymchenry/codegraph", "codeGraphVersion": "1.5.0", "codeGraphBinaryDigest": "sha256:4646464646464646464646464646464646464646464646464646464646464646", "codeGraphStatus": "ready" }
|
|
19
|
+
},
|
|
20
|
+
"outputSnapshot": {
|
|
21
|
+
"repositoryId": "repo.example",
|
|
22
|
+
"workspaceId": "ws.example",
|
|
23
|
+
"headSha": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
24
|
+
"baseHeadSha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
25
|
+
"worktreeDigest": "sha256:6666666666666666666666666666666666666666666666666666666666666666",
|
|
26
|
+
"sourceTreeDigest": "sha256:7777777777777777777777777777777777777777777777777777777777777777",
|
|
27
|
+
"modelDigest": "sha256:8888888888888888888888888888888888888888888888888888888888888888",
|
|
28
|
+
"codeGraphDigest": "sha256:9999999999999999999999999999999999999999999999999999999999999999",
|
|
29
|
+
"indexedWorktreeDigest": "sha256:9898989898989898989898989898989898989898989898989898989898989898",
|
|
30
|
+
"projectionInputDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
31
|
+
"rendererVersion": "archcontext.docs-renderer/v2",
|
|
32
|
+
"layoutVersion": "archcontext.docs-layout/v1",
|
|
33
|
+
"generatedFrom": { "codeGraphPackage": "@colbymchenry/codegraph", "codeGraphVersion": "1.5.0", "codeGraphBinaryDigest": "sha256:9797979797979797979797979797979797979797979797979797979797979797", "codeGraphStatus": "ready" }
|
|
34
|
+
},
|
|
35
|
+
"affectedNodeIds": ["capability.api"],
|
|
36
|
+
"files": [
|
|
37
|
+
{
|
|
38
|
+
"path": "docs/architecture/modules/api.md",
|
|
39
|
+
"action": "update",
|
|
40
|
+
"preimageDigest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
41
|
+
"outputDigest": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"humanActions": [],
|
|
45
|
+
"refreshSignals": [],
|
|
46
|
+
"receiptDigest": "sha256:e41599eb1613796b64b03290c170076af2aa542de043b91672f327475e9d1cad"
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archctx.repoharness.com/schemas/repo/architecture-flow.schema.json",
|
|
4
|
+
"title": "ArchitectureFlowV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "id", "capabilityId", "name", "applicability"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "archcontext.flow/v1" },
|
|
10
|
+
"id": { "type": "string", "pattern": "^flow\\.[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)*$" },
|
|
11
|
+
"capabilityId": { "type": "string", "pattern": "^capability\\.[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)*$" },
|
|
12
|
+
"name": { "type": "string", "minLength": 1 },
|
|
13
|
+
"applicability": { "type": "string", "enum": ["required", "not-applicable"] },
|
|
14
|
+
"rationale": { "type": "string", "minLength": 1 },
|
|
15
|
+
"participants": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"minItems": 1,
|
|
18
|
+
"items": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["id", "nodeId"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)*$" },
|
|
24
|
+
"nodeId": { "type": "string", "minLength": 1 }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"steps": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"minItems": 1,
|
|
31
|
+
"items": { "$ref": "#/$defs/step" }
|
|
32
|
+
},
|
|
33
|
+
"outcomes": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"minItems": 2,
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"required": ["id", "kind", "label", "steps", "terminal"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)*$" },
|
|
42
|
+
"kind": { "type": "string", "enum": ["success", "error"] },
|
|
43
|
+
"label": { "type": "string", "minLength": 1 },
|
|
44
|
+
"steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/step" } },
|
|
45
|
+
"terminal": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["participant", "label"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"participant": { "type": "string", "minLength": 1 },
|
|
51
|
+
"label": { "type": "string", "minLength": 1 }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"allOf": [
|
|
57
|
+
{ "contains": { "type": "object", "properties": { "kind": { "const": "success" } }, "required": ["kind"] }, "minContains": 1 },
|
|
58
|
+
{ "contains": { "type": "object", "properties": { "kind": { "const": "error" } }, "required": ["kind"] }, "minContains": 1 }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"$defs": {
|
|
63
|
+
"evidenceSelector": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": ["entrypointId", "sourceSymbol", "sinkId"],
|
|
67
|
+
"properties": {
|
|
68
|
+
"entrypointId": { "type": "string", "minLength": 1 },
|
|
69
|
+
"sourceSymbol": { "type": "string", "minLength": 1 },
|
|
70
|
+
"sinkId": { "type": "string", "minLength": 1 }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"step": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"required": ["id", "from", "to", "label", "evidence"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)*$" },
|
|
79
|
+
"from": { "type": "string", "minLength": 1 },
|
|
80
|
+
"to": { "type": "string", "minLength": 1 },
|
|
81
|
+
"label": { "type": "string", "minLength": 1 },
|
|
82
|
+
"evidence": { "$ref": "#/$defs/evidenceSelector" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"oneOf": [
|
|
87
|
+
{
|
|
88
|
+
"properties": { "applicability": { "const": "required" } },
|
|
89
|
+
"required": ["participants", "steps", "outcomes"]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"properties": { "applicability": { "const": "not-applicable" } },
|
|
93
|
+
"required": ["rationale"],
|
|
94
|
+
"not": { "anyOf": [{ "required": ["participants"] }, { "required": ["steps"] }, { "required": ["outcomes"] }] }
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"additionalProperties": false,
|
|
7
7
|
"required": ["schemaVersion", "id", "kind", "name", "status", "summary"],
|
|
8
8
|
"properties": {
|
|
9
|
-
"schemaVersion": { "const": "archcontext.node/
|
|
9
|
+
"schemaVersion": { "const": "archcontext.node/v2" },
|
|
10
10
|
"id": { "type": "string", "pattern": "^([a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)*::)?[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
11
11
|
"kind": {
|
|
12
12
|
"type": "string",
|
|
@@ -23,7 +23,44 @@
|
|
|
23
23
|
"properties": {
|
|
24
24
|
"include": { "type": "array", "items": { "type": "string" } },
|
|
25
25
|
"exclude": { "type": "array", "items": { "type": "string" } },
|
|
26
|
-
"entrypoints": {
|
|
26
|
+
"entrypoints": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"required": ["id", "path", "symbols"],
|
|
32
|
+
"properties": {
|
|
33
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
34
|
+
"path": { "type": "string", "minLength": 1 },
|
|
35
|
+
"symbols": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"minItems": 1,
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": ["name", "sinks"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"name": { "type": "string", "minLength": 1 },
|
|
44
|
+
"sinks": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"minItems": 1,
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"required": ["id", "path", "symbol"],
|
|
51
|
+
"properties": {
|
|
52
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
53
|
+
"path": { "type": "string", "minLength": 1 },
|
|
54
|
+
"symbol": { "type": "string", "minLength": 1 }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
27
64
|
}
|
|
28
65
|
},
|
|
29
66
|
"ownership": {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/archctx-capabilities.schema.json",
|
|
4
|
+
"title": "ArchctxCapabilitiesV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "package", "protocols", "renderers", "features"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "archcontext.capabilities/v1" },
|
|
10
|
+
"package": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"required": ["name", "version"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": { "const": "archctx" },
|
|
16
|
+
"version": { "type": "string", "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$" }
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"protocols": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"required": ["projectionRequest", "projectionResult", "architectureRefreshSignal"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"projectionRequest": { "const": "archcontext.projection-request/v1" },
|
|
25
|
+
"projectionResult": { "const": "archcontext.projection-result/v1" },
|
|
26
|
+
"architectureRefreshSignal": { "const": "archcontext.architecture-refresh-signal/v1" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"renderers": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": ["architectureDocs", "agentContext"],
|
|
33
|
+
"properties": {
|
|
34
|
+
"architectureDocs": { "const": "archcontext.docs-renderer/v2" },
|
|
35
|
+
"agentContext": { "const": "archcontext.agent-context-renderer/v1" }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"features": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"minItems": 3,
|
|
41
|
+
"uniqueItems": true,
|
|
42
|
+
"items": { "enum": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-protocol-v1"] }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/architecture-refresh-signal.schema.json",
|
|
4
|
+
"title": "ArchitectureRefreshSignalV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "signalId", "idempotencyKey", "mode", "repository", "worktree", "cause", "reasonCodes", "affectedNodeIds", "refreshTargets", "baseDigests", "resultingDigests", "projectionReceiptDigest"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "archcontext.architecture-refresh-signal/v1" },
|
|
10
|
+
"signalId": { "$ref": "#/$defs/digest" },
|
|
11
|
+
"idempotencyKey": { "$ref": "#/$defs/digest" },
|
|
12
|
+
"mode": { "enum": ["human-action-required", "refresh-required"] },
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"required": ["repositoryId"],
|
|
17
|
+
"properties": { "repositoryId": { "type": "string", "minLength": 1 } }
|
|
18
|
+
},
|
|
19
|
+
"worktree": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"required": ["workspaceId", "headSha", "worktreeDigest"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"workspaceId": { "type": "string", "minLength": 1 },
|
|
25
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
26
|
+
"worktreeDigest": { "$ref": "#/$defs/digest" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"cause": { "enum": ["accepted-semantic-delta", "unresolved-major-candidate", "verified-flow-proof-delta"] },
|
|
30
|
+
"acceptedChange": { "$ref": "#/$defs/acceptedChange" },
|
|
31
|
+
"reasonCodes": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"minItems": 1,
|
|
34
|
+
"uniqueItems": true,
|
|
35
|
+
"items": { "$ref": "#/$defs/reasonCode" }
|
|
36
|
+
},
|
|
37
|
+
"affectedNodeIds": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"minItems": 1,
|
|
40
|
+
"uniqueItems": true,
|
|
41
|
+
"items": { "type": "string", "minLength": 1 }
|
|
42
|
+
},
|
|
43
|
+
"refreshTargets": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"minItems": 1,
|
|
46
|
+
"uniqueItems": true,
|
|
47
|
+
"items": { "enum": ["architecture-contract-context", "architecture-readiness", "architecture-request-index", "capability-context", "capability-index"] }
|
|
48
|
+
},
|
|
49
|
+
"baseDigests": { "$ref": "#/$defs/digestSet" },
|
|
50
|
+
"resultingDigests": { "$ref": "#/$defs/digestSet" },
|
|
51
|
+
"projectionReceiptDigest": { "$ref": "#/$defs/digest" }
|
|
52
|
+
},
|
|
53
|
+
"allOf": [
|
|
54
|
+
{
|
|
55
|
+
"if": { "properties": { "cause": { "const": "unresolved-major-candidate" } }, "required": ["cause"] },
|
|
56
|
+
"then": { "properties": { "mode": { "const": "human-action-required" } }, "not": { "required": ["acceptedChange"] } },
|
|
57
|
+
"else": { "properties": { "mode": { "const": "refresh-required" } }, "required": ["acceptedChange"] }
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"$defs": {
|
|
61
|
+
"digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
62
|
+
"reasonCode": {
|
|
63
|
+
"enum": ["constraint-changed", "entrypoint-changed", "interface-changed", "lifecycle-changed", "node-added", "node-moved", "node-removed", "node-renamed", "ownership-changed", "relation-changed", "responsibility-changed", "risk-boundary-changed", "verified-flow-proof-changed"]
|
|
64
|
+
},
|
|
65
|
+
"acceptedChange": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": ["changeSetId", "eventId", "reasonCodes", "affectedNodeIds"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"changeSetId": { "type": "string", "minLength": 1 },
|
|
71
|
+
"eventId": { "type": "string", "minLength": 1 },
|
|
72
|
+
"reasonCodes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/reasonCode" } },
|
|
73
|
+
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"digestSet": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"required": ["modelDigest", "sourceTreeDigest", "flowProofDigest", "projectionDigest"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"modelDigest": { "$ref": "#/$defs/digest" },
|
|
82
|
+
"sourceTreeDigest": { "$ref": "#/$defs/digest" },
|
|
83
|
+
"flowProofDigest": { "$ref": "#/$defs/digest" },
|
|
84
|
+
"projectionDigest": { "$ref": "#/$defs/digest" }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"additionalProperties": true,
|
|
37
37
|
"required": ["op", "expectedHash"],
|
|
38
38
|
"properties": {
|
|
39
|
-
"op": { "type": "string", "enum": ["create_entity", "update_entity_fields", "delete_entity", "write_policy", "write_waiver", "render_projection"] },
|
|
39
|
+
"op": { "type": "string", "enum": ["create_entity", "update_entity_fields", "delete_entity", "write_policy", "write_waiver", "render_projection", "render_agent_context"] },
|
|
40
40
|
"entityId": { "type": "string" },
|
|
41
41
|
"path": { "type": "string" },
|
|
42
42
|
"expectedHash": { "type": "string" },
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/projection-request.schema.json",
|
|
4
|
+
"title": "ProjectionRequestV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "requestId", "profile", "mode", "targets", "changedPaths", "expected"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "archcontext.projection-request/v1" },
|
|
10
|
+
"requestId": { "type": "string", "pattern": "^[a-zA-Z0-9_.:-]+$", "minLength": 1 },
|
|
11
|
+
"profile": { "const": "repo-harness/v1" },
|
|
12
|
+
"mode": { "enum": ["check", "plan", "apply", "adopt"] },
|
|
13
|
+
"targets": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"minItems": 1,
|
|
16
|
+
"uniqueItems": true,
|
|
17
|
+
"description": "Canonical wire order is lexicographic and is enforced by projectionRequestInvariantIssues.",
|
|
18
|
+
"items": { "enum": ["agent-context", "architecture-docs"] }
|
|
19
|
+
},
|
|
20
|
+
"changedPaths": {
|
|
21
|
+
"type": "array",
|
|
22
|
+
"uniqueItems": true,
|
|
23
|
+
"description": "Canonical wire order is lexicographic and is enforced by projectionRequestInvariantIssues.",
|
|
24
|
+
"items": { "$ref": "#/$defs/repoPath" }
|
|
25
|
+
},
|
|
26
|
+
"expected": { "$ref": "#/$defs/expectedSnapshot" },
|
|
27
|
+
"adoptionPlanId": { "type": "string", "pattern": "^adoption_plan\\.[a-zA-Z0-9_.-]+$" }
|
|
28
|
+
},
|
|
29
|
+
"allOf": [
|
|
30
|
+
{
|
|
31
|
+
"if": { "properties": { "mode": { "const": "adopt" } }, "required": ["mode"] },
|
|
32
|
+
"then": { "required": ["adoptionPlanId"] },
|
|
33
|
+
"else": { "not": { "required": ["adoptionPlanId"] } }
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"$defs": {
|
|
37
|
+
"digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
38
|
+
"repoPath": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1,
|
|
41
|
+
"not": {
|
|
42
|
+
"anyOf": [
|
|
43
|
+
{ "pattern": "^/" },
|
|
44
|
+
{ "pattern": "\\\\" },
|
|
45
|
+
{ "pattern": "(^|/)\\.\\.(/|$)" }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"expectedSnapshot": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": ["repositoryId", "workspaceId", "headSha", "worktreeDigest"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"repositoryId": { "type": "string", "minLength": 1 },
|
|
55
|
+
"workspaceId": { "type": "string", "minLength": 1 },
|
|
56
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
57
|
+
"worktreeDigest": { "$ref": "#/$defs/digest" }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/projection-result.schema.json",
|
|
4
|
+
"title": "ProjectionResultV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "requestId", "status", "inputSnapshot", "outputSnapshot", "affectedNodeIds", "files", "humanActions", "refreshSignals", "receiptDigest"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": "archcontext.projection-result/v1" },
|
|
10
|
+
"requestId": { "type": "string", "pattern": "^[a-zA-Z0-9_.:-]+$", "minLength": 1 },
|
|
11
|
+
"status": { "enum": ["adoption-required", "applied", "blocked", "human-action-required", "noop", "permanent-failure", "planned", "retryable-failure"] },
|
|
12
|
+
"inputSnapshot": { "$ref": "#/$defs/snapshot" },
|
|
13
|
+
"outputSnapshot": { "$ref": "#/$defs/snapshot" },
|
|
14
|
+
"affectedNodeIds": { "type": "array", "uniqueItems": true, "description": "Canonical wire order is lexicographic and is enforced by projectionResultInvariantIssues.", "items": { "type": "string", "minLength": 1 } },
|
|
15
|
+
"files": { "type": "array", "description": "Canonical wire order is by path and is enforced by projectionResultInvariantIssues.", "items": { "$ref": "#/$defs/file" } },
|
|
16
|
+
"humanActions": { "type": "array", "items": { "$ref": "#/$defs/humanAction" } },
|
|
17
|
+
"refreshSignals": { "type": "array", "description": "Canonical wire order is by signalId and cross-object receipt/snapshot bindings are enforced by projectionResultInvariantIssues.", "items": { "$ref": "#/$defs/refreshSignal" } },
|
|
18
|
+
"receiptDigest": { "$ref": "#/$defs/digest" }
|
|
19
|
+
},
|
|
20
|
+
"allOf": [
|
|
21
|
+
{
|
|
22
|
+
"if": { "properties": { "status": { "enum": ["adoption-required", "human-action-required"] } }, "required": ["status"] },
|
|
23
|
+
"then": { "properties": { "humanActions": { "minItems": 1 } } },
|
|
24
|
+
"else": { "properties": { "humanActions": { "maxItems": 0 } } }
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"$defs": {
|
|
28
|
+
"digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
29
|
+
"nullableDigest": { "type": ["string", "null"], "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
30
|
+
"snapshot": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"required": ["repositoryId", "workspaceId", "headSha", "baseHeadSha", "worktreeDigest", "sourceTreeDigest", "modelDigest", "codeGraphDigest", "indexedWorktreeDigest", "projectionInputDigest", "rendererVersion", "layoutVersion", "generatedFrom"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"repositoryId": { "type": "string", "minLength": 1 },
|
|
36
|
+
"workspaceId": { "type": "string", "minLength": 1 },
|
|
37
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
38
|
+
"baseHeadSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
39
|
+
"worktreeDigest": { "$ref": "#/$defs/digest" },
|
|
40
|
+
"sourceTreeDigest": { "$ref": "#/$defs/digest" },
|
|
41
|
+
"modelDigest": { "$ref": "#/$defs/digest" },
|
|
42
|
+
"codeGraphDigest": { "$ref": "#/$defs/digest" },
|
|
43
|
+
"indexedWorktreeDigest": { "$ref": "#/$defs/nullableDigest" },
|
|
44
|
+
"projectionInputDigest": { "$ref": "#/$defs/digest" },
|
|
45
|
+
"rendererVersion": { "const": "archcontext.docs-renderer/v2" },
|
|
46
|
+
"layoutVersion": { "const": "archcontext.docs-layout/v1" },
|
|
47
|
+
"generatedFrom": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"required": ["codeGraphPackage", "codeGraphVersion", "codeGraphBinaryDigest", "codeGraphStatus"],
|
|
51
|
+
"properties": {
|
|
52
|
+
"codeGraphPackage": { "const": "@colbymchenry/codegraph" },
|
|
53
|
+
"codeGraphVersion": { "const": "1.5.0" },
|
|
54
|
+
"codeGraphBinaryDigest": { "$ref": "#/$defs/digest" },
|
|
55
|
+
"codeGraphStatus": { "enum": ["ready", "unavailable"] }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"file": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"additionalProperties": false,
|
|
63
|
+
"required": ["path", "action", "preimageDigest", "outputDigest"],
|
|
64
|
+
"properties": {
|
|
65
|
+
"path": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"minLength": 1,
|
|
68
|
+
"not": { "anyOf": [{ "pattern": "^/" }, { "pattern": "\\\\" }, { "pattern": "(^|/)\\.\\.(/|$)" }] }
|
|
69
|
+
},
|
|
70
|
+
"action": { "enum": ["create", "delete", "unchanged", "update"] },
|
|
71
|
+
"preimageDigest": { "$ref": "#/$defs/nullableDigest" },
|
|
72
|
+
"outputDigest": { "$ref": "#/$defs/nullableDigest" }
|
|
73
|
+
},
|
|
74
|
+
"allOf": [
|
|
75
|
+
{
|
|
76
|
+
"if": { "properties": { "action": { "const": "create" } }, "required": ["action"] },
|
|
77
|
+
"then": { "properties": { "preimageDigest": { "const": null }, "outputDigest": { "$ref": "#/$defs/digest" } } }
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"if": { "properties": { "action": { "const": "delete" } }, "required": ["action"] },
|
|
81
|
+
"then": { "properties": { "preimageDigest": { "$ref": "#/$defs/digest" }, "outputDigest": { "const": null } } }
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"if": { "properties": { "action": { "enum": ["unchanged", "update"] } }, "required": ["action"] },
|
|
85
|
+
"then": { "properties": { "preimageDigest": { "$ref": "#/$defs/digest" }, "outputDigest": { "$ref": "#/$defs/digest" } } }
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"humanAction": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"additionalProperties": false,
|
|
92
|
+
"required": ["reasonCode", "affectedNodeIds", "requestPayloadDigest"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"reasonCode": { "enum": ["adoption-required", "manual-region-conflict", "target-collision", "unprovable-required-flow", "unresolved-major-change"] },
|
|
95
|
+
"affectedNodeIds": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
96
|
+
"requestPayloadDigest": { "$ref": "#/$defs/digest" }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"digestSet": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"additionalProperties": false,
|
|
102
|
+
"required": ["modelDigest", "sourceTreeDigest", "flowProofDigest", "projectionDigest"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"modelDigest": { "$ref": "#/$defs/digest" },
|
|
105
|
+
"sourceTreeDigest": { "$ref": "#/$defs/digest" },
|
|
106
|
+
"flowProofDigest": { "$ref": "#/$defs/digest" },
|
|
107
|
+
"projectionDigest": { "$ref": "#/$defs/digest" }
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"reasonCode": {
|
|
111
|
+
"enum": ["constraint-changed", "entrypoint-changed", "interface-changed", "lifecycle-changed", "node-added", "node-moved", "node-removed", "node-renamed", "ownership-changed", "relation-changed", "responsibility-changed", "risk-boundary-changed", "verified-flow-proof-changed"]
|
|
112
|
+
},
|
|
113
|
+
"refreshSignal": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"additionalProperties": false,
|
|
116
|
+
"required": ["schemaVersion", "signalId", "idempotencyKey", "mode", "repository", "worktree", "cause", "reasonCodes", "affectedNodeIds", "refreshTargets", "baseDigests", "resultingDigests", "projectionReceiptDigest"],
|
|
117
|
+
"properties": {
|
|
118
|
+
"schemaVersion": { "const": "archcontext.architecture-refresh-signal/v1" },
|
|
119
|
+
"signalId": { "$ref": "#/$defs/digest" },
|
|
120
|
+
"idempotencyKey": { "$ref": "#/$defs/digest" },
|
|
121
|
+
"mode": { "enum": ["human-action-required", "refresh-required"] },
|
|
122
|
+
"repository": { "type": "object", "additionalProperties": false, "required": ["repositoryId"], "properties": { "repositoryId": { "type": "string", "minLength": 1 } } },
|
|
123
|
+
"worktree": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"additionalProperties": false,
|
|
126
|
+
"required": ["workspaceId", "headSha", "worktreeDigest"],
|
|
127
|
+
"properties": {
|
|
128
|
+
"workspaceId": { "type": "string", "minLength": 1 },
|
|
129
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
130
|
+
"worktreeDigest": { "$ref": "#/$defs/digest" }
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"cause": { "enum": ["accepted-semantic-delta", "unresolved-major-candidate", "verified-flow-proof-delta"] },
|
|
134
|
+
"acceptedChange": { "$ref": "#/$defs/acceptedChange" },
|
|
135
|
+
"reasonCodes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/reasonCode" } },
|
|
136
|
+
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
137
|
+
"refreshTargets": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["architecture-contract-context", "architecture-readiness", "architecture-request-index", "capability-context", "capability-index"] } },
|
|
138
|
+
"baseDigests": { "$ref": "#/$defs/digestSet" },
|
|
139
|
+
"resultingDigests": { "$ref": "#/$defs/digestSet" },
|
|
140
|
+
"projectionReceiptDigest": { "$ref": "#/$defs/digest" }
|
|
141
|
+
},
|
|
142
|
+
"allOf": [
|
|
143
|
+
{
|
|
144
|
+
"if": { "properties": { "cause": { "const": "unresolved-major-candidate" } }, "required": ["cause"] },
|
|
145
|
+
"then": { "properties": { "mode": { "const": "human-action-required" } }, "not": { "required": ["acceptedChange"] } },
|
|
146
|
+
"else": { "properties": { "mode": { "const": "refresh-required" } }, "required": ["acceptedChange"] }
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
"acceptedChange": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"additionalProperties": false,
|
|
153
|
+
"required": ["changeSetId", "eventId", "reasonCodes", "affectedNodeIds"],
|
|
154
|
+
"properties": {
|
|
155
|
+
"changeSetId": { "type": "string", "minLength": 1 },
|
|
156
|
+
"eventId": { "type": "string", "minLength": 1 },
|
|
157
|
+
"reasonCodes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/reasonCode" } },
|
|
158
|
+
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface ArchitectureSinkSelectorV2 {
|
|
2
|
+
id: string;
|
|
3
|
+
path: string;
|
|
4
|
+
symbol: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ArchitectureEntrypointSymbolV2 {
|
|
8
|
+
name: string;
|
|
9
|
+
sinks: ArchitectureSinkSelectorV2[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ArchitectureEntrypointV2 {
|
|
13
|
+
id: string;
|
|
14
|
+
path: string;
|
|
15
|
+
symbols: ArchitectureEntrypointSymbolV2[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ArchitectureNodeSourceV2 {
|
|
19
|
+
include?: string[];
|
|
20
|
+
exclude?: string[];
|
|
21
|
+
entrypoints?: ArchitectureEntrypointV2[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ArchitectureFlowEvidenceSelectorV1 {
|
|
25
|
+
entrypointId: string;
|
|
26
|
+
sourceSymbol: string;
|
|
27
|
+
sinkId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ArchitectureFlowParticipantV1 {
|
|
31
|
+
id: string;
|
|
32
|
+
nodeId: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ArchitectureFlowStepV1 {
|
|
36
|
+
id: string;
|
|
37
|
+
from: string;
|
|
38
|
+
to: string;
|
|
39
|
+
label: string;
|
|
40
|
+
evidence: ArchitectureFlowEvidenceSelectorV1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ArchitectureFlowOutcomeV1 {
|
|
44
|
+
id: string;
|
|
45
|
+
kind: "success" | "error";
|
|
46
|
+
label: string;
|
|
47
|
+
steps: ArchitectureFlowStepV1[];
|
|
48
|
+
terminal: {
|
|
49
|
+
participant: string;
|
|
50
|
+
label: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type ArchitectureFlowV1 = ArchitectureRequiredFlowV1 | ArchitectureNotApplicableFlowV1;
|
|
55
|
+
|
|
56
|
+
interface ArchitectureFlowBaseV1 {
|
|
57
|
+
schemaVersion: "archcontext.flow/v1";
|
|
58
|
+
id: string;
|
|
59
|
+
capabilityId: string;
|
|
60
|
+
name: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ArchitectureRequiredFlowV1 extends ArchitectureFlowBaseV1 {
|
|
64
|
+
applicability: "required";
|
|
65
|
+
participants: ArchitectureFlowParticipantV1[];
|
|
66
|
+
steps: ArchitectureFlowStepV1[];
|
|
67
|
+
outcomes: ArchitectureFlowOutcomeV1[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ArchitectureNotApplicableFlowV1 extends ArchitectureFlowBaseV1 {
|
|
71
|
+
applicability: "not-applicable";
|
|
72
|
+
rationale: string;
|
|
73
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export * from "./control-plane-routes";
|
|
2
|
+
export * from "./architecture";
|
|
2
3
|
export * from "./external-docs";
|
|
3
4
|
export * from "./github-governance";
|
|
4
5
|
export * from "./ledger";
|
|
5
6
|
export * from "./ports";
|
|
6
7
|
export * from "./practices";
|
|
8
|
+
export * from "./projection";
|
|
7
9
|
export * from "./product-version";
|
|
8
10
|
export * from "./schema";
|
|
9
11
|
export * from "./validator";
|
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.
|
|
2
|
+
export const ARCHCONTEXT_PRODUCT_VERSION = "0.4.0";
|
|
3
3
|
export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.3.10";
|
|
4
4
|
export const ARCHCONTEXT_NODE_RANGE = ">=24 <26";
|
|
5
5
|
export const LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1";
|
|
@@ -41,7 +41,7 @@ export interface ProductVersionManifest {
|
|
|
41
41
|
sqliteMigrations: string;
|
|
42
42
|
codeGraph: {
|
|
43
43
|
packageName: "@colbymchenry/codegraph";
|
|
44
|
-
requiredVersion: "1.
|
|
44
|
+
requiredVersion: "1.5.0";
|
|
45
45
|
adapter: "codegraph-cli";
|
|
46
46
|
};
|
|
47
47
|
};
|
|
@@ -100,7 +100,7 @@ export function productVersionManifest(): ProductVersionManifest {
|
|
|
100
100
|
sqliteMigrations: "0001_runtime_state..0012_explorer_projection_index",
|
|
101
101
|
codeGraph: {
|
|
102
102
|
packageName: "@colbymchenry/codegraph",
|
|
103
|
-
requiredVersion: "1.
|
|
103
|
+
requiredVersion: "1.5.0",
|
|
104
104
|
adapter: "codegraph-cli"
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { digestJson, type Json } from "./schema";
|
|
2
|
+
|
|
3
|
+
export const PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request/v1" as const;
|
|
4
|
+
export const PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v1" as const;
|
|
5
|
+
export const ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1" as const;
|
|
6
|
+
export const ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1" as const;
|
|
7
|
+
export const ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v2" as const;
|
|
8
|
+
export const AGENT_CONTEXT_RENDERER_VERSION = "archcontext.agent-context-renderer/v1" as const;
|
|
9
|
+
|
|
10
|
+
export const PROJECTION_MODES = ["check", "plan", "apply", "adopt"] as const;
|
|
11
|
+
export const PROJECTION_TARGETS = ["agent-context", "architecture-docs"] as const;
|
|
12
|
+
export const PROJECTION_RESULT_STATUSES = [
|
|
13
|
+
"adoption-required",
|
|
14
|
+
"applied",
|
|
15
|
+
"blocked",
|
|
16
|
+
"human-action-required",
|
|
17
|
+
"noop",
|
|
18
|
+
"permanent-failure",
|
|
19
|
+
"planned",
|
|
20
|
+
"retryable-failure"
|
|
21
|
+
] as const;
|
|
22
|
+
export const PROJECTION_HUMAN_ACTION_REASON_CODES = [
|
|
23
|
+
"adoption-required",
|
|
24
|
+
"manual-region-conflict",
|
|
25
|
+
"target-collision",
|
|
26
|
+
"unprovable-required-flow",
|
|
27
|
+
"unresolved-major-change"
|
|
28
|
+
] as const;
|
|
29
|
+
export const ARCHITECTURE_MAJOR_CHANGE_REASON_CODES = [
|
|
30
|
+
"constraint-changed",
|
|
31
|
+
"entrypoint-changed",
|
|
32
|
+
"interface-changed",
|
|
33
|
+
"lifecycle-changed",
|
|
34
|
+
"node-added",
|
|
35
|
+
"node-moved",
|
|
36
|
+
"node-removed",
|
|
37
|
+
"node-renamed",
|
|
38
|
+
"ownership-changed",
|
|
39
|
+
"relation-changed",
|
|
40
|
+
"responsibility-changed",
|
|
41
|
+
"risk-boundary-changed",
|
|
42
|
+
"verified-flow-proof-changed"
|
|
43
|
+
] as const;
|
|
44
|
+
export const ARCHITECTURE_REFRESH_TARGETS = [
|
|
45
|
+
"architecture-contract-context",
|
|
46
|
+
"architecture-readiness",
|
|
47
|
+
"architecture-request-index",
|
|
48
|
+
"capability-context",
|
|
49
|
+
"capability-index"
|
|
50
|
+
] as const;
|
|
51
|
+
export const ARCHCTX_FEATURES = [
|
|
52
|
+
"architecture-docs-renderer-v2",
|
|
53
|
+
"architecture-refresh-signal-v1",
|
|
54
|
+
"projection-protocol-v1"
|
|
55
|
+
] as const;
|
|
56
|
+
|
|
57
|
+
export type ProjectionMode = (typeof PROJECTION_MODES)[number];
|
|
58
|
+
export type ProjectionTarget = (typeof PROJECTION_TARGETS)[number];
|
|
59
|
+
export type ProjectionResultStatus = (typeof PROJECTION_RESULT_STATUSES)[number];
|
|
60
|
+
export type ProjectionHumanActionReasonCode = (typeof PROJECTION_HUMAN_ACTION_REASON_CODES)[number];
|
|
61
|
+
export type ArchitectureMajorChangeReasonCode = (typeof ARCHITECTURE_MAJOR_CHANGE_REASON_CODES)[number];
|
|
62
|
+
export type ArchitectureRefreshTarget = (typeof ARCHITECTURE_REFRESH_TARGETS)[number];
|
|
63
|
+
export type ArchctxFeature = (typeof ARCHCTX_FEATURES)[number];
|
|
64
|
+
export type Sha256Digest = `sha256:${string}`;
|
|
65
|
+
|
|
66
|
+
export interface ProjectionExpectedSnapshotV1 {
|
|
67
|
+
repositoryId: string;
|
|
68
|
+
workspaceId: string;
|
|
69
|
+
headSha: string;
|
|
70
|
+
worktreeDigest: Sha256Digest;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ProjectionRequestV1 {
|
|
74
|
+
schemaVersion: typeof PROJECTION_REQUEST_SCHEMA_VERSION;
|
|
75
|
+
requestId: string;
|
|
76
|
+
profile: "repo-harness/v1";
|
|
77
|
+
mode: ProjectionMode;
|
|
78
|
+
targets: ProjectionTarget[];
|
|
79
|
+
changedPaths: string[];
|
|
80
|
+
expected: ProjectionExpectedSnapshotV1;
|
|
81
|
+
adoptionPlanId?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ProjectionSnapshotV1 extends ProjectionExpectedSnapshotV1 {
|
|
85
|
+
baseHeadSha: string;
|
|
86
|
+
sourceTreeDigest: Sha256Digest;
|
|
87
|
+
modelDigest: Sha256Digest;
|
|
88
|
+
codeGraphDigest: Sha256Digest;
|
|
89
|
+
indexedWorktreeDigest: Sha256Digest | null;
|
|
90
|
+
projectionInputDigest: Sha256Digest;
|
|
91
|
+
rendererVersion: typeof ARCHITECTURE_DOCS_RENDERER_VERSION;
|
|
92
|
+
layoutVersion: "archcontext.docs-layout/v1";
|
|
93
|
+
generatedFrom: {
|
|
94
|
+
codeGraphPackage: "@colbymchenry/codegraph";
|
|
95
|
+
codeGraphVersion: "1.5.0";
|
|
96
|
+
codeGraphBinaryDigest: Sha256Digest;
|
|
97
|
+
codeGraphStatus: "ready" | "unavailable";
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ProjectionFileResultV1 {
|
|
102
|
+
path: string;
|
|
103
|
+
action: "create" | "delete" | "unchanged" | "update";
|
|
104
|
+
preimageDigest: Sha256Digest | null;
|
|
105
|
+
outputDigest: Sha256Digest | null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ProjectionHumanActionV1 {
|
|
109
|
+
reasonCode: ProjectionHumanActionReasonCode;
|
|
110
|
+
affectedNodeIds: string[];
|
|
111
|
+
requestPayloadDigest: Sha256Digest;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface ArchitectureDigestSetV1 {
|
|
115
|
+
modelDigest: Sha256Digest;
|
|
116
|
+
sourceTreeDigest: Sha256Digest;
|
|
117
|
+
flowProofDigest: Sha256Digest;
|
|
118
|
+
projectionDigest: Sha256Digest;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface AcceptedArchitectureChangeReferenceV1 {
|
|
122
|
+
changeSetId: string;
|
|
123
|
+
eventId: string;
|
|
124
|
+
reasonCodes: ArchitectureMajorChangeReasonCode[];
|
|
125
|
+
affectedNodeIds: string[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface ArchitectureRefreshSignalV1 {
|
|
129
|
+
schemaVersion: typeof ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION;
|
|
130
|
+
signalId: Sha256Digest;
|
|
131
|
+
idempotencyKey: Sha256Digest;
|
|
132
|
+
mode: "human-action-required" | "refresh-required";
|
|
133
|
+
repository: { repositoryId: string };
|
|
134
|
+
worktree: { workspaceId: string; headSha: string; worktreeDigest: Sha256Digest };
|
|
135
|
+
cause: "accepted-semantic-delta" | "unresolved-major-candidate" | "verified-flow-proof-delta";
|
|
136
|
+
acceptedChange?: AcceptedArchitectureChangeReferenceV1;
|
|
137
|
+
reasonCodes: ArchitectureMajorChangeReasonCode[];
|
|
138
|
+
affectedNodeIds: string[];
|
|
139
|
+
refreshTargets: ArchitectureRefreshTarget[];
|
|
140
|
+
baseDigests: ArchitectureDigestSetV1;
|
|
141
|
+
resultingDigests: ArchitectureDigestSetV1;
|
|
142
|
+
projectionReceiptDigest: Sha256Digest;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface ProjectionResultV1 {
|
|
146
|
+
schemaVersion: typeof PROJECTION_RESULT_SCHEMA_VERSION;
|
|
147
|
+
requestId: string;
|
|
148
|
+
status: ProjectionResultStatus;
|
|
149
|
+
inputSnapshot: ProjectionSnapshotV1;
|
|
150
|
+
outputSnapshot: ProjectionSnapshotV1;
|
|
151
|
+
affectedNodeIds: string[];
|
|
152
|
+
files: ProjectionFileResultV1[];
|
|
153
|
+
humanActions: ProjectionHumanActionV1[];
|
|
154
|
+
refreshSignals: ArchitectureRefreshSignalV1[];
|
|
155
|
+
receiptDigest: Sha256Digest;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface ArchctxCapabilitiesV1 {
|
|
159
|
+
schemaVersion: typeof ARCHCTX_CAPABILITIES_SCHEMA_VERSION;
|
|
160
|
+
package: {
|
|
161
|
+
name: "archctx";
|
|
162
|
+
version: string;
|
|
163
|
+
};
|
|
164
|
+
protocols: {
|
|
165
|
+
projectionRequest: typeof PROJECTION_REQUEST_SCHEMA_VERSION;
|
|
166
|
+
projectionResult: typeof PROJECTION_RESULT_SCHEMA_VERSION;
|
|
167
|
+
architectureRefreshSignal: typeof ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION;
|
|
168
|
+
};
|
|
169
|
+
renderers: {
|
|
170
|
+
architectureDocs: typeof ARCHITECTURE_DOCS_RENDERER_VERSION;
|
|
171
|
+
agentContext: typeof AGENT_CONTEXT_RENDERER_VERSION;
|
|
172
|
+
};
|
|
173
|
+
features: ArchctxFeature[];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function archctxCapabilities(packageVersion: string): ArchctxCapabilitiesV1 {
|
|
177
|
+
return {
|
|
178
|
+
schemaVersion: ARCHCTX_CAPABILITIES_SCHEMA_VERSION,
|
|
179
|
+
package: { name: "archctx", version: packageVersion },
|
|
180
|
+
protocols: {
|
|
181
|
+
projectionRequest: PROJECTION_REQUEST_SCHEMA_VERSION,
|
|
182
|
+
projectionResult: PROJECTION_RESULT_SCHEMA_VERSION,
|
|
183
|
+
architectureRefreshSignal: ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION
|
|
184
|
+
},
|
|
185
|
+
renderers: {
|
|
186
|
+
architectureDocs: ARCHITECTURE_DOCS_RENDERER_VERSION,
|
|
187
|
+
agentContext: AGENT_CONTEXT_RENDERER_VERSION
|
|
188
|
+
},
|
|
189
|
+
features: [...ARCHCTX_FEATURES]
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function projectionRequestInvariantIssues(input: ProjectionRequestV1): string[] {
|
|
194
|
+
const issues = [
|
|
195
|
+
...sortedUniqueIssues("targets", input.targets),
|
|
196
|
+
...sortedUniqueIssues("changedPaths", input.changedPaths)
|
|
197
|
+
];
|
|
198
|
+
if (input.targets.length === 0) issues.push("targets must contain at least one projection target");
|
|
199
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId)) issues.push("requestId must use the stable identifier character set");
|
|
200
|
+
if (input.mode === "adopt" && !input.adoptionPlanId) issues.push("adoptionPlanId is required when mode=adopt");
|
|
201
|
+
if (input.mode !== "adopt" && input.adoptionPlanId !== undefined) issues.push("adoptionPlanId is only allowed when mode=adopt");
|
|
202
|
+
return issues;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function projectionResultInvariantIssues(input: ProjectionResultV1): string[] {
|
|
206
|
+
const issues = [
|
|
207
|
+
...sortedUniqueIssues("affectedNodeIds", input.affectedNodeIds),
|
|
208
|
+
...sortedUniqueIssues("files.path", input.files.map((file) => file.path)),
|
|
209
|
+
...sortedUniqueIssues("refreshSignals.signalId", input.refreshSignals.map((signal) => signal.signalId)),
|
|
210
|
+
...input.humanActions.flatMap((action, index) => sortedUniqueIssues(`humanActions[${index}].affectedNodeIds`, action.affectedNodeIds)),
|
|
211
|
+
...input.refreshSignals.flatMap((signal, index) => architectureRefreshSignalInvariantIssues(signal, `refreshSignals[${index}]`))
|
|
212
|
+
];
|
|
213
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId)) issues.push("requestId must use the stable identifier character set");
|
|
214
|
+
if (input.inputSnapshot.repositoryId !== input.outputSnapshot.repositoryId) issues.push("outputSnapshot.repositoryId must match inputSnapshot.repositoryId");
|
|
215
|
+
if (input.inputSnapshot.workspaceId !== input.outputSnapshot.workspaceId) issues.push("outputSnapshot.workspaceId must match inputSnapshot.workspaceId");
|
|
216
|
+
if (input.inputSnapshot.baseHeadSha !== input.outputSnapshot.baseHeadSha) issues.push("outputSnapshot.baseHeadSha must match inputSnapshot.baseHeadSha");
|
|
217
|
+
const statusRequiresHumanAction = input.status === "adoption-required" || input.status === "human-action-required";
|
|
218
|
+
if (statusRequiresHumanAction && input.humanActions.length === 0) issues.push(`${input.status} status requires at least one human action`);
|
|
219
|
+
if (!statusRequiresHumanAction && input.humanActions.length > 0) issues.push(`human actions are not allowed when status=${input.status}`);
|
|
220
|
+
for (const [index, file] of input.files.entries()) {
|
|
221
|
+
const prefix = `files[${index}]`;
|
|
222
|
+
if (file.action === "create" && (file.preimageDigest !== null || file.outputDigest === null)) {
|
|
223
|
+
issues.push(`${prefix} create requires null preimageDigest and non-null outputDigest`);
|
|
224
|
+
}
|
|
225
|
+
if (file.action === "delete" && (file.preimageDigest === null || file.outputDigest !== null)) {
|
|
226
|
+
issues.push(`${prefix} delete requires non-null preimageDigest and null outputDigest`);
|
|
227
|
+
}
|
|
228
|
+
if (file.action === "update" && (file.preimageDigest === null || file.outputDigest === null || file.preimageDigest === file.outputDigest)) {
|
|
229
|
+
issues.push(`${prefix} update requires two different non-null digests`);
|
|
230
|
+
}
|
|
231
|
+
if (file.action === "unchanged" && (file.preimageDigest === null || file.outputDigest === null || file.preimageDigest !== file.outputDigest)) {
|
|
232
|
+
issues.push(`${prefix} unchanged requires equal non-null digests`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const { receiptDigest, ...receiptPayload } = input;
|
|
236
|
+
if (projectionResultReceiptDigest(receiptPayload) !== receiptDigest) issues.push("receiptDigest must match the canonical projection result payload");
|
|
237
|
+
for (const [index, signal] of input.refreshSignals.entries()) {
|
|
238
|
+
const prefix = `refreshSignals[${index}]`;
|
|
239
|
+
if (signal.projectionReceiptDigest !== receiptDigest) issues.push(`${prefix}.projectionReceiptDigest must match receiptDigest`);
|
|
240
|
+
if (signal.repository.repositoryId !== input.outputSnapshot.repositoryId) issues.push(`${prefix}.repositoryId must match outputSnapshot.repositoryId`);
|
|
241
|
+
if (signal.worktree.workspaceId !== input.outputSnapshot.workspaceId) issues.push(`${prefix}.workspaceId must match outputSnapshot.workspaceId`);
|
|
242
|
+
if (signal.worktree.headSha !== input.outputSnapshot.headSha) issues.push(`${prefix}.headSha must match outputSnapshot.headSha`);
|
|
243
|
+
if (signal.worktree.worktreeDigest !== input.outputSnapshot.worktreeDigest) issues.push(`${prefix}.worktreeDigest must match outputSnapshot.worktreeDigest`);
|
|
244
|
+
}
|
|
245
|
+
return issues;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Computes the accepted projection receipt. Signal back-references are omitted from the
|
|
250
|
+
* receipt payload to avoid a circular hash; every signal must then bind that receipt via
|
|
251
|
+
* projectionReceiptDigest, which projectionResultInvariantIssues verifies.
|
|
252
|
+
*/
|
|
253
|
+
export function projectionResultReceiptDigest(input: Omit<ProjectionResultV1, "receiptDigest">): Sha256Digest {
|
|
254
|
+
const refreshSignals = input.refreshSignals.map(({ projectionReceiptDigest: _projectionReceiptDigest, ...signal }) => signal);
|
|
255
|
+
return digestJson({ ...input, refreshSignals } as unknown as Json) as Sha256Digest;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function architectureRefreshSignalInvariantIssues(input: ArchitectureRefreshSignalV1, prefix = "signal"): string[] {
|
|
259
|
+
const issues = [
|
|
260
|
+
...sortedUniqueIssues(`${prefix}.reasonCodes`, input.reasonCodes),
|
|
261
|
+
...sortedUniqueIssues(`${prefix}.affectedNodeIds`, input.affectedNodeIds),
|
|
262
|
+
...sortedUniqueIssues(`${prefix}.refreshTargets`, input.refreshTargets)
|
|
263
|
+
];
|
|
264
|
+
if (input.acceptedChange) {
|
|
265
|
+
issues.push(
|
|
266
|
+
...sortedUniqueIssues(`${prefix}.acceptedChange.reasonCodes`, input.acceptedChange.reasonCodes),
|
|
267
|
+
...sortedUniqueIssues(`${prefix}.acceptedChange.affectedNodeIds`, input.acceptedChange.affectedNodeIds)
|
|
268
|
+
);
|
|
269
|
+
if (input.acceptedChange.changeSetId.trim() === "") issues.push(`${prefix}.acceptedChange.changeSetId must not be empty`);
|
|
270
|
+
if (input.acceptedChange.eventId.trim() === "") issues.push(`${prefix}.acceptedChange.eventId must not be empty`);
|
|
271
|
+
if (input.acceptedChange.reasonCodes.join("\u0000") !== input.reasonCodes.join("\u0000")) {
|
|
272
|
+
issues.push(`${prefix}.acceptedChange.reasonCodes must match signal reasonCodes`);
|
|
273
|
+
}
|
|
274
|
+
if (input.acceptedChange.affectedNodeIds.join("\u0000") !== input.affectedNodeIds.join("\u0000")) {
|
|
275
|
+
issues.push(`${prefix}.acceptedChange.affectedNodeIds must match signal affectedNodeIds`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (input.reasonCodes.length === 0) issues.push(`${prefix}.reasonCodes must contain at least one reason`);
|
|
279
|
+
if (input.affectedNodeIds.length === 0) issues.push(`${prefix}.affectedNodeIds must contain at least one node`);
|
|
280
|
+
if (input.refreshTargets.length === 0) issues.push(`${prefix}.refreshTargets must contain at least one target`);
|
|
281
|
+
if (input.cause === "unresolved-major-candidate" && input.mode !== "human-action-required") {
|
|
282
|
+
issues.push(`${prefix}.unresolved-major-candidate requires human-action-required mode`);
|
|
283
|
+
}
|
|
284
|
+
if (input.cause !== "unresolved-major-candidate" && input.mode !== "refresh-required") {
|
|
285
|
+
issues.push(`${prefix}.${input.cause} requires refresh-required mode`);
|
|
286
|
+
}
|
|
287
|
+
if (input.mode === "refresh-required" && !input.acceptedChange) {
|
|
288
|
+
issues.push(`${prefix}.refresh-required requires acceptedChange`);
|
|
289
|
+
}
|
|
290
|
+
if (input.mode === "human-action-required" && input.acceptedChange) {
|
|
291
|
+
issues.push(`${prefix}.human-action-required forbids acceptedChange`);
|
|
292
|
+
}
|
|
293
|
+
return issues;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function sortedUniqueIssues(label: string, values: readonly string[]): string[] {
|
|
297
|
+
const expected = [...new Set(values)].sort();
|
|
298
|
+
return expected.length === values.length && expected.every((value, index) => value === values[index])
|
|
299
|
+
? []
|
|
300
|
+
: [`${label} must be sorted and unique`];
|
|
301
|
+
}
|
package/src/validator.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { canonicalize, type Json } from "./schema";
|
|
2
2
|
|
|
3
3
|
export interface ValidationIssue {
|
|
4
4
|
path: string;
|
|
@@ -23,9 +23,14 @@ type JsonSchema = {
|
|
|
23
23
|
oneOf?: JsonSchema[];
|
|
24
24
|
anyOf?: JsonSchema[];
|
|
25
25
|
allOf?: JsonSchema[];
|
|
26
|
+
if?: JsonSchema;
|
|
27
|
+
then?: JsonSchema;
|
|
28
|
+
else?: JsonSchema;
|
|
26
29
|
not?: JsonSchema;
|
|
27
30
|
additionalProperties?: boolean | JsonSchema;
|
|
28
31
|
minItems?: number;
|
|
32
|
+
maxItems?: number;
|
|
33
|
+
uniqueItems?: boolean;
|
|
29
34
|
minLength?: number;
|
|
30
35
|
maxLength?: number;
|
|
31
36
|
minimum?: number;
|
|
@@ -68,6 +73,12 @@ function visit(schema: JsonSchema, value: Json, path: string, issues: Validation
|
|
|
68
73
|
if (!matched) issues.push({ path, message: "expected at least one matching schema" });
|
|
69
74
|
}
|
|
70
75
|
for (const candidate of schema.allOf ?? []) visit(candidate, value, path, issues, root);
|
|
76
|
+
if (schema.if) {
|
|
77
|
+
const conditionIssues: ValidationIssue[] = [];
|
|
78
|
+
visit(schema.if, value, path, conditionIssues, root);
|
|
79
|
+
const branch = conditionIssues.length === 0 ? schema.then : schema.else;
|
|
80
|
+
if (branch) visit(branch, value, path, issues, root);
|
|
81
|
+
}
|
|
71
82
|
if (schema.not) {
|
|
72
83
|
const candidateIssues: ValidationIssue[] = [];
|
|
73
84
|
visit(schema.not, value, path, candidateIssues, root);
|
|
@@ -101,6 +112,12 @@ function visit(schema: JsonSchema, value: Json, path: string, issues: Validation
|
|
|
101
112
|
if (schema.minItems !== undefined && value.length < schema.minItems) {
|
|
102
113
|
issues.push({ path, message: `expected at least ${schema.minItems} items` });
|
|
103
114
|
}
|
|
115
|
+
if (schema.maxItems !== undefined && value.length > schema.maxItems) {
|
|
116
|
+
issues.push({ path, message: `expected at most ${schema.maxItems} items` });
|
|
117
|
+
}
|
|
118
|
+
if (schema.uniqueItems && new Set(value.map(canonicalize)).size !== value.length) {
|
|
119
|
+
issues.push({ path, message: "expected unique items" });
|
|
120
|
+
}
|
|
104
121
|
if (schema.items) value.forEach((item, index) => visit(schema.items!, item, `${path}[${index}]`, issues, root));
|
|
105
122
|
}
|
|
106
123
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|