archctx-contracts 0.4.6 → 0.4.8
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/product-version-manifest.json +7 -7
- package/fixtures/valid/projection-apply-recovery.json +9 -0
- package/package.json +1 -1
- package/schemas/runtime/archctx-capabilities.schema.json +1 -1
- package/schemas/runtime/product-version-manifest.schema.json +1 -1
- package/schemas/runtime/projection-apply-recovery.schema.json +188 -0
- package/src/product-version.ts +3 -3
- package/src/projection.ts +205 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "archcontext.capabilities/v1",
|
|
3
|
-
"package": { "name": "archctx", "version": "0.4.
|
|
3
|
+
"package": { "name": "archctx", "version": "0.4.8" },
|
|
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/v4",
|
|
11
11
|
"agentContext": "archcontext.agent-context-renderer/v1"
|
|
12
12
|
},
|
|
13
|
-
"features": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-apply-receipt-v1", "projection-protocol-v2"]
|
|
13
|
+
"features": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-protocol-v2"]
|
|
14
14
|
}
|
|
@@ -2,35 +2,35 @@
|
|
|
2
2
|
"schemaVersion": "archcontext.product-version-manifest/v1",
|
|
3
3
|
"product": {
|
|
4
4
|
"name": "archctx",
|
|
5
|
-
"version": "0.4.
|
|
5
|
+
"version": "0.4.8",
|
|
6
6
|
"distribution": "one-package"
|
|
7
7
|
},
|
|
8
|
-
"packageManager": "bun@1.
|
|
8
|
+
"packageManager": "bun@1.4.0",
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
10
|
+
"node": ">=22.22 <26"
|
|
11
11
|
},
|
|
12
12
|
"surfaces": {
|
|
13
13
|
"cli": {
|
|
14
14
|
"packageName": "@archcontext/surfaces",
|
|
15
|
-
"version": "0.4.
|
|
15
|
+
"version": "0.4.8",
|
|
16
16
|
"entrypoint": "archctx"
|
|
17
17
|
},
|
|
18
18
|
"daemon": {
|
|
19
19
|
"packageName": "@archcontext/local-runtime",
|
|
20
|
-
"version": "0.4.
|
|
20
|
+
"version": "0.4.8",
|
|
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.4.
|
|
26
|
+
"version": "0.4.8",
|
|
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.4.
|
|
33
|
+
"contractsPackageVersion": "0.4.8",
|
|
34
34
|
"reviewChallenge": "archcontext.review-challenge/v2",
|
|
35
35
|
"attestation": "archcontext.attestation/v2",
|
|
36
36
|
"deviceIdentity": "archcontext.device-identity/v1",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "archcontext.projection-apply-recovery-intent/v1",
|
|
3
|
+
"requestId": "projection_request.recovery_fixture",
|
|
4
|
+
"profile": "repo-harness/v1",
|
|
5
|
+
"receipt": {
|
|
6
|
+
"lookupKey": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
7
|
+
"applyId": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
|
8
|
+
}
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"type": "array",
|
|
40
40
|
"minItems": 3,
|
|
41
41
|
"uniqueItems": true,
|
|
42
|
-
"items": { "enum": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-apply-receipt-v1", "projection-protocol-v2"] }
|
|
42
|
+
"items": { "enum": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-protocol-v2"] }
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archcontext.dev/schemas/runtime/projection-apply-recovery.schema.json",
|
|
4
|
+
"title": "ProjectionApplyRecoveryV1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "enum": ["archcontext.projection-apply-recovery-intent/v1", "archcontext.projection-apply-recovery-proof/v1", "archcontext.projection-apply-recovery-result/v1"] },
|
|
10
|
+
"requestId": {},
|
|
11
|
+
"profile": {},
|
|
12
|
+
"acceptedChange": {},
|
|
13
|
+
"receipt": {},
|
|
14
|
+
"requestDigest": {},
|
|
15
|
+
"proofDigest": {},
|
|
16
|
+
"deliveryStatus": {},
|
|
17
|
+
"expectedResultingDigests": {},
|
|
18
|
+
"current": {},
|
|
19
|
+
"proof": {},
|
|
20
|
+
"refreshSignals": {}
|
|
21
|
+
},
|
|
22
|
+
"allOf": [
|
|
23
|
+
{
|
|
24
|
+
"if": { "properties": { "schemaVersion": { "const": "archcontext.projection-apply-recovery-intent/v1" } }, "required": ["schemaVersion"] },
|
|
25
|
+
"then": { "$ref": "#/$defs/intent" }
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"if": { "properties": { "schemaVersion": { "const": "archcontext.projection-apply-recovery-proof/v1" } }, "required": ["schemaVersion"] },
|
|
29
|
+
"then": { "$ref": "#/$defs/proof" }
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"if": { "properties": { "schemaVersion": { "const": "archcontext.projection-apply-recovery-result/v1" } }, "required": ["schemaVersion"] },
|
|
33
|
+
"then": { "$ref": "#/$defs/result" }
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"$defs": {
|
|
37
|
+
"digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
38
|
+
"generatedFrom": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": ["codeGraphPackage", "codeGraphVersion", "codeGraphBinaryDigest", "codeGraphStatus"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"codeGraphPackage": { "const": "@colbymchenry/codegraph" },
|
|
44
|
+
"codeGraphVersion": { "const": "1.5.0" },
|
|
45
|
+
"codeGraphBinaryDigest": { "$ref": "#/$defs/digest" },
|
|
46
|
+
"codeGraphStatus": { "enum": ["ready", "unavailable"] }
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"readyGeneratedFrom": {
|
|
50
|
+
"allOf": [
|
|
51
|
+
{ "$ref": "#/$defs/generatedFrom" },
|
|
52
|
+
{ "properties": { "codeGraphStatus": { "const": "ready" } }, "required": ["codeGraphStatus"] }
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"digestSet": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": ["modelDigest", "sourceTreeDigest", "flowProofDigest", "projectionDigest"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"modelDigest": { "$ref": "#/$defs/digest" },
|
|
61
|
+
"sourceTreeDigest": { "$ref": "#/$defs/digest" },
|
|
62
|
+
"flowProofDigest": { "$ref": "#/$defs/digest" },
|
|
63
|
+
"projectionDigest": { "$ref": "#/$defs/digest" }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"reasonCode": {
|
|
67
|
+
"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"]
|
|
68
|
+
},
|
|
69
|
+
"acceptedChange": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"required": ["changeSetId", "eventId", "reasonCodes", "affectedNodeIds"],
|
|
73
|
+
"properties": {
|
|
74
|
+
"changeSetId": { "type": "string", "minLength": 1 },
|
|
75
|
+
"eventId": { "type": "string", "minLength": 1 },
|
|
76
|
+
"reasonCodes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/reasonCode" } },
|
|
77
|
+
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"intentReceipt": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"additionalProperties": false,
|
|
83
|
+
"required": ["lookupKey", "applyId"],
|
|
84
|
+
"properties": {
|
|
85
|
+
"lookupKey": { "$ref": "#/$defs/digest" },
|
|
86
|
+
"applyId": { "$ref": "#/$defs/digest" }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"intent": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"additionalProperties": false,
|
|
92
|
+
"required": ["schemaVersion", "requestId", "profile", "receipt"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"schemaVersion": { "const": "archcontext.projection-apply-recovery-intent/v1" },
|
|
95
|
+
"requestId": { "type": "string", "pattern": "^[a-zA-Z0-9_.:-]+$", "minLength": 1 },
|
|
96
|
+
"profile": { "const": "repo-harness/v1" },
|
|
97
|
+
"receipt": { "$ref": "#/$defs/intentReceipt" }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"snapshot": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"additionalProperties": false,
|
|
103
|
+
"required": ["repositoryId", "workspaceId", "headSha", "baseHeadSha", "worktreeDigest", "sourceTreeDigest", "modelDigest", "codeGraphDigest", "indexedWorktreeDigest", "projectionInputDigest", "rendererVersion", "layoutVersion", "generatedFrom"],
|
|
104
|
+
"properties": {
|
|
105
|
+
"repositoryId": { "type": "string", "minLength": 1 },
|
|
106
|
+
"workspaceId": { "type": "string", "minLength": 1 },
|
|
107
|
+
"headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
108
|
+
"baseHeadSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
109
|
+
"worktreeDigest": { "$ref": "#/$defs/digest" },
|
|
110
|
+
"sourceTreeDigest": { "$ref": "#/$defs/digest" },
|
|
111
|
+
"modelDigest": { "$ref": "#/$defs/digest" },
|
|
112
|
+
"codeGraphDigest": { "$ref": "#/$defs/digest" },
|
|
113
|
+
"indexedWorktreeDigest": { "type": ["string", "null"], "pattern": "^sha256:[a-f0-9]{64}$" },
|
|
114
|
+
"projectionInputDigest": { "$ref": "#/$defs/digest" },
|
|
115
|
+
"rendererVersion": { "const": "archcontext.docs-renderer/v4" },
|
|
116
|
+
"layoutVersion": { "const": "archcontext.docs-layout/v1" },
|
|
117
|
+
"generatedFrom": { "$ref": "#/$defs/readyGeneratedFrom" }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"proofReceipt": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"additionalProperties": false,
|
|
123
|
+
"required": ["lookupKey", "applyId", "receiptDigest"],
|
|
124
|
+
"properties": {
|
|
125
|
+
"lookupKey": { "$ref": "#/$defs/digest" },
|
|
126
|
+
"applyId": { "$ref": "#/$defs/digest" },
|
|
127
|
+
"receiptDigest": { "$ref": "#/$defs/digest" }
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"proof": {
|
|
131
|
+
"type": "object",
|
|
132
|
+
"additionalProperties": false,
|
|
133
|
+
"required": ["schemaVersion", "requestId", "requestDigest", "proofDigest", "deliveryStatus", "receipt", "acceptedChange", "expectedResultingDigests", "current"],
|
|
134
|
+
"properties": {
|
|
135
|
+
"schemaVersion": { "const": "archcontext.projection-apply-recovery-proof/v1" },
|
|
136
|
+
"requestId": { "type": "string", "pattern": "^[a-zA-Z0-9_.:-]+$", "minLength": 1 },
|
|
137
|
+
"requestDigest": { "$ref": "#/$defs/digest" },
|
|
138
|
+
"proofDigest": { "$ref": "#/$defs/digest" },
|
|
139
|
+
"deliveryStatus": { "enum": ["delivered", "already-delivered"] },
|
|
140
|
+
"receipt": { "$ref": "#/$defs/proofReceipt" },
|
|
141
|
+
"acceptedChange": { "$ref": "#/$defs/acceptedChange" },
|
|
142
|
+
"expectedResultingDigests": { "$ref": "#/$defs/digestSet" },
|
|
143
|
+
"current": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"required": ["snapshot", "resultingDigests", "ownedOutputDigest", "fixedPointDigest"],
|
|
147
|
+
"properties": {
|
|
148
|
+
"snapshot": { "$ref": "#/$defs/snapshot" },
|
|
149
|
+
"resultingDigests": { "$ref": "#/$defs/digestSet" },
|
|
150
|
+
"ownedOutputDigest": { "$ref": "#/$defs/digest" },
|
|
151
|
+
"fixedPointDigest": { "$ref": "#/$defs/digest" }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"refreshSignal": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"additionalProperties": false,
|
|
159
|
+
"required": ["schemaVersion", "signalId", "idempotencyKey", "mode", "repository", "worktree", "cause", "reasonCodes", "affectedNodeIds", "refreshTargets", "baseDigests", "resultingDigests", "projectionReceiptDigest"],
|
|
160
|
+
"properties": {
|
|
161
|
+
"schemaVersion": { "const": "archcontext.architecture-refresh-signal/v1" },
|
|
162
|
+
"signalId": { "$ref": "#/$defs/digest" },
|
|
163
|
+
"idempotencyKey": { "$ref": "#/$defs/digest" },
|
|
164
|
+
"mode": { "enum": ["human-action-required", "refresh-required"] },
|
|
165
|
+
"repository": { "type": "object", "additionalProperties": false, "required": ["repositoryId"], "properties": { "repositoryId": { "type": "string", "minLength": 1 } } },
|
|
166
|
+
"worktree": { "type": "object", "additionalProperties": false, "required": ["workspaceId", "headSha", "worktreeDigest"], "properties": { "workspaceId": { "type": "string", "minLength": 1 }, "headSha": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "worktreeDigest": { "$ref": "#/$defs/digest" } } },
|
|
167
|
+
"cause": { "enum": ["accepted-semantic-delta", "unresolved-major-candidate", "verified-flow-proof-delta"] },
|
|
168
|
+
"acceptedChange": { "$ref": "#/$defs/acceptedChange" },
|
|
169
|
+
"reasonCodes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/reasonCode" } },
|
|
170
|
+
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
171
|
+
"refreshTargets": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["architecture-contract-context", "architecture-readiness", "architecture-request-index", "capability-context", "capability-index"] } },
|
|
172
|
+
"baseDigests": { "$ref": "#/$defs/digestSet" },
|
|
173
|
+
"resultingDigests": { "$ref": "#/$defs/digestSet" },
|
|
174
|
+
"projectionReceiptDigest": { "$ref": "#/$defs/digest" }
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"result": {
|
|
178
|
+
"type": "object",
|
|
179
|
+
"additionalProperties": false,
|
|
180
|
+
"required": ["schemaVersion", "proof", "refreshSignals"],
|
|
181
|
+
"properties": {
|
|
182
|
+
"schemaVersion": { "const": "archcontext.projection-apply-recovery-result/v1" },
|
|
183
|
+
"proof": { "$ref": "#/$defs/proof" },
|
|
184
|
+
"refreshSignals": { "type": "array", "items": { "$ref": "#/$defs/refreshSignal" } }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
package/src/product-version.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const ARCHCONTEXT_PRODUCT_NAME = "archctx";
|
|
2
|
-
export const ARCHCONTEXT_PRODUCT_VERSION = "0.4.
|
|
3
|
-
export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.
|
|
4
|
-
export const ARCHCONTEXT_NODE_RANGE = ">=
|
|
2
|
+
export const ARCHCONTEXT_PRODUCT_VERSION = "0.4.8";
|
|
3
|
+
export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.0";
|
|
4
|
+
export const ARCHCONTEXT_NODE_RANGE = ">=22.22 <26";
|
|
5
5
|
export const LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1";
|
|
6
6
|
export const ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
7
7
|
|
package/src/projection.ts
CHANGED
|
@@ -4,6 +4,10 @@ export const PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request
|
|
|
4
4
|
export const PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v2" as const;
|
|
5
5
|
export const PROJECTION_APPLY_IDENTITY_SCHEMA_VERSION = "archcontext.projection-apply-identity/v1" as const;
|
|
6
6
|
export const PROJECTION_APPLY_RECEIPT_SCHEMA_VERSION = "archcontext.projection-apply-receipt/v1" as const;
|
|
7
|
+
export const PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION = "archcontext.projection-apply-recovery-binding/v1" as const;
|
|
8
|
+
export const PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-intent/v1" as const;
|
|
9
|
+
export const PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION = "archcontext.projection-apply-recovery-proof/v1" as const;
|
|
10
|
+
export const PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-result/v1" as const;
|
|
7
11
|
export const ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1" as const;
|
|
8
12
|
export const ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1" as const;
|
|
9
13
|
export const ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v4" as const;
|
|
@@ -55,6 +59,7 @@ export const ARCHCTX_FEATURES = [
|
|
|
55
59
|
"architecture-docs-renderer-v2",
|
|
56
60
|
"architecture-refresh-signal-v1",
|
|
57
61
|
"projection-apply-receipt-v1",
|
|
62
|
+
"projection-apply-recovery-v1",
|
|
58
63
|
"projection-protocol-v2"
|
|
59
64
|
] as const;
|
|
60
65
|
|
|
@@ -180,6 +185,74 @@ export interface ProjectionApplyReceiptV1 {
|
|
|
180
185
|
schemaVersion: typeof PROJECTION_APPLY_RECEIPT_SCHEMA_VERSION;
|
|
181
186
|
identity: ProjectionApplyIdentityV1;
|
|
182
187
|
result: ProjectionResultV2;
|
|
188
|
+
/**
|
|
189
|
+
* Present only on receipts written after recovery protocol v1 shipped. Receipts created by
|
|
190
|
+
* v0.4.7 remain inspectable, but cannot be recovered because they never recorded this exact
|
|
191
|
+
* approval binding.
|
|
192
|
+
*/
|
|
193
|
+
recovery?: ProjectionApplyRecoveryBindingV1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Immutable approval metadata recorded with a new committed apply receipt, never inferred later. */
|
|
197
|
+
export interface ProjectionApplyRecoveryBindingV1 {
|
|
198
|
+
schemaVersion: typeof PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION;
|
|
199
|
+
targets: ProjectionTarget[];
|
|
200
|
+
changedPaths: string[];
|
|
201
|
+
originalExpectedSnapshot: ProjectionExpectedSnapshotV1;
|
|
202
|
+
expectedResultingDigests: ArchitectureDigestSetV1;
|
|
203
|
+
rendererVersion: typeof ARCHITECTURE_DOCS_RENDERER_VERSION;
|
|
204
|
+
layoutVersion: "archcontext.docs-layout/v1";
|
|
205
|
+
generatedFrom: ProjectionSnapshotV1["generatedFrom"];
|
|
206
|
+
ownedOutputDigest: Sha256Digest;
|
|
207
|
+
receiptDigest: Sha256Digest;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The only client-supplied recovery input. The daemon resolves every semantic field from the
|
|
212
|
+
* committed receipt and repository authority while it holds the writer boundary.
|
|
213
|
+
*/
|
|
214
|
+
export interface ProjectionApplyRecoveryIntentV1 {
|
|
215
|
+
schemaVersion: typeof PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION;
|
|
216
|
+
requestId: string;
|
|
217
|
+
profile: "repo-harness/v1";
|
|
218
|
+
receipt: {
|
|
219
|
+
lookupKey: Sha256Digest;
|
|
220
|
+
applyId: Sha256Digest;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export type ProjectionApplyRecoveryDeliveryStatus = "delivered" | "already-delivered";
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* A semantic proof created only after the CLI has rebuilt the current projection fixed point.
|
|
228
|
+
* `proofDigest` intentionally excludes deliveryStatus so an idempotent repeat can change only
|
|
229
|
+
* that explicitly declared field.
|
|
230
|
+
*/
|
|
231
|
+
export interface ProjectionApplyRecoveryProofV1 {
|
|
232
|
+
schemaVersion: typeof PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION;
|
|
233
|
+
requestId: string;
|
|
234
|
+
requestDigest: Sha256Digest;
|
|
235
|
+
proofDigest: Sha256Digest;
|
|
236
|
+
deliveryStatus: ProjectionApplyRecoveryDeliveryStatus;
|
|
237
|
+
receipt: {
|
|
238
|
+
lookupKey: Sha256Digest;
|
|
239
|
+
applyId: Sha256Digest;
|
|
240
|
+
receiptDigest: Sha256Digest;
|
|
241
|
+
};
|
|
242
|
+
acceptedChange: AcceptedArchitectureChangeReferenceV1;
|
|
243
|
+
expectedResultingDigests: ArchitectureDigestSetV1;
|
|
244
|
+
current: {
|
|
245
|
+
snapshot: ProjectionSnapshotV1;
|
|
246
|
+
resultingDigests: ArchitectureDigestSetV1;
|
|
247
|
+
ownedOutputDigest: Sha256Digest;
|
|
248
|
+
fixedPointDigest: Sha256Digest;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface ProjectionApplyRecoveryResultV1 {
|
|
253
|
+
schemaVersion: typeof PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION;
|
|
254
|
+
proof: ProjectionApplyRecoveryProofV1;
|
|
255
|
+
refreshSignals: ArchitectureRefreshSignalV1[];
|
|
183
256
|
}
|
|
184
257
|
|
|
185
258
|
export interface ArchctxCapabilitiesV1 {
|
|
@@ -365,9 +438,141 @@ export function projectionApplyReceiptInvariantIssues(input: ProjectionApplyRece
|
|
|
365
438
|
if (digestJson(input.result.applyReceipt as unknown as Json) !== digestJson(input.identity as unknown as Json)) {
|
|
366
439
|
issues.push("projection apply receipt result must carry the same apply identity");
|
|
367
440
|
}
|
|
441
|
+
if (input.recovery) issues.push(...projectionApplyRecoveryBindingInvariantIssues(input.recovery, input));
|
|
442
|
+
return issues;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export function projectionApplyRecoveryBindingInvariantIssues(
|
|
446
|
+
binding: ProjectionApplyRecoveryBindingV1,
|
|
447
|
+
receipt?: ProjectionApplyReceiptV1
|
|
448
|
+
): string[] {
|
|
449
|
+
const issues = [
|
|
450
|
+
...sortedUniqueIssues("recovery.targets", binding.targets),
|
|
451
|
+
...sortedUniqueIssues("recovery.changedPaths", binding.changedPaths)
|
|
452
|
+
];
|
|
453
|
+
if (binding.schemaVersion !== PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION) {
|
|
454
|
+
issues.push("recovery schemaVersion is invalid");
|
|
455
|
+
}
|
|
456
|
+
if (binding.targets.length === 0) issues.push("recovery targets must contain at least one projection target");
|
|
457
|
+
if (receipt) {
|
|
458
|
+
if (binding.receiptDigest !== receipt.result.receiptDigest) {
|
|
459
|
+
issues.push("recovery receiptDigest must match the committed result receiptDigest");
|
|
460
|
+
}
|
|
461
|
+
if (binding.originalExpectedSnapshot.repositoryId !== receipt.result.inputSnapshot.repositoryId
|
|
462
|
+
|| binding.originalExpectedSnapshot.workspaceId !== receipt.result.inputSnapshot.workspaceId
|
|
463
|
+
|| binding.originalExpectedSnapshot.headSha !== receipt.result.inputSnapshot.headSha
|
|
464
|
+
|| binding.originalExpectedSnapshot.worktreeDigest !== receipt.result.inputSnapshot.worktreeDigest) {
|
|
465
|
+
issues.push("recovery originalExpectedSnapshot must match the committed input snapshot");
|
|
466
|
+
}
|
|
467
|
+
if (binding.rendererVersion !== receipt.result.outputSnapshot.rendererVersion
|
|
468
|
+
|| binding.layoutVersion !== receipt.result.outputSnapshot.layoutVersion
|
|
469
|
+
|| digestJson(binding.generatedFrom as unknown as Json) !== digestJson(receipt.result.outputSnapshot.generatedFrom as unknown as Json)) {
|
|
470
|
+
issues.push("recovery renderer, layout, and CodeGraph provenance must match the committed output snapshot");
|
|
471
|
+
}
|
|
472
|
+
const expectedDigests = projectionApplyReceiptResultingDigests(receipt);
|
|
473
|
+
if (!expectedDigests || digestJson(binding.expectedResultingDigests as unknown as Json) !== digestJson(expectedDigests as unknown as Json)) {
|
|
474
|
+
issues.push("recovery expectedResultingDigests must match committed refresh signals");
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return issues;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export function projectionApplyRecoveryIntentInvariantIssues(input: ProjectionApplyRecoveryIntentV1): string[] {
|
|
481
|
+
const issues: string[] = [];
|
|
482
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION) issues.push("recovery intent schemaVersion is invalid");
|
|
483
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId)) issues.push("recovery intent requestId must use the stable identifier character set");
|
|
484
|
+
if (input.profile !== "repo-harness/v1") issues.push("recovery intent profile is invalid");
|
|
485
|
+
for (const field of ["lookupKey", "applyId"] as const) {
|
|
486
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(input.receipt[field])) issues.push(`recovery intent receipt.${field} must be a SHA-256 digest`);
|
|
487
|
+
}
|
|
488
|
+
return issues;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export function projectionApplyRecoveryProofDigest(input: Omit<ProjectionApplyRecoveryProofV1, "proofDigest" | "deliveryStatus">): Sha256Digest {
|
|
492
|
+
return digestJson(input as unknown as Json) as Sha256Digest;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export function projectionApplyRecoveryProofInvariantIssues(input: ProjectionApplyRecoveryProofV1): string[] {
|
|
496
|
+
const issues = [
|
|
497
|
+
...sortedUniqueIssues("acceptedChange.reasonCodes", input.acceptedChange.reasonCodes),
|
|
498
|
+
...sortedUniqueIssues("acceptedChange.affectedNodeIds", input.acceptedChange.affectedNodeIds)
|
|
499
|
+
];
|
|
500
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION) issues.push("recovery proof schemaVersion is invalid");
|
|
501
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId)) issues.push("recovery proof requestId must use the stable identifier character set");
|
|
502
|
+
if (input.current.snapshot.generatedFrom.codeGraphStatus !== "ready") issues.push("recovery proof requires a ready current CodeGraph snapshot");
|
|
503
|
+
const { proofDigest: _proofDigest, deliveryStatus: _deliveryStatus, ...payload } = input;
|
|
504
|
+
if (projectionApplyRecoveryProofDigest(payload) !== input.proofDigest) {
|
|
505
|
+
issues.push("recovery proofDigest must bind the semantic proof payload");
|
|
506
|
+
}
|
|
507
|
+
return issues;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export function projectionApplyRecoveryResultInvariantIssues(input: ProjectionApplyRecoveryResultV1): string[] {
|
|
511
|
+
const issues = [
|
|
512
|
+
...projectionApplyRecoveryProofInvariantIssues(input.proof),
|
|
513
|
+
...input.refreshSignals.flatMap((signal, index) => architectureRefreshSignalInvariantIssues(signal, `refreshSignals[${index}]`)),
|
|
514
|
+
...sortedUniqueIssues("refreshSignals.signalId", input.refreshSignals.map((signal) => signal.signalId))
|
|
515
|
+
];
|
|
516
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION) {
|
|
517
|
+
issues.push("recovery result schemaVersion is invalid");
|
|
518
|
+
}
|
|
519
|
+
if (input.proof.deliveryStatus === "already-delivered" && input.refreshSignals.length > 0) {
|
|
520
|
+
issues.push("already-delivered recovery result cannot repeat refreshSignals");
|
|
521
|
+
}
|
|
522
|
+
for (const [index, signal] of input.refreshSignals.entries()) {
|
|
523
|
+
const prefix = `refreshSignals[${index}]`;
|
|
524
|
+
if (signal.projectionReceiptDigest !== input.proof.receipt.receiptDigest) {
|
|
525
|
+
issues.push(`${prefix}.projectionReceiptDigest must match recovery proof receiptDigest`);
|
|
526
|
+
}
|
|
527
|
+
if (digestJson(signal.acceptedChange as unknown as Json) !== digestJson(input.proof.acceptedChange as unknown as Json)) {
|
|
528
|
+
issues.push(`${prefix}.acceptedChange must match recovery proof approval`);
|
|
529
|
+
}
|
|
530
|
+
if (digestJson(signal.resultingDigests as unknown as Json) !== digestJson(input.proof.expectedResultingDigests as unknown as Json)) {
|
|
531
|
+
issues.push(`${prefix}.resultingDigests must match recovery proof`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return issues;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/** The durable store uses this before delivery; it can validate immutable bindings but not re-render the current projection. */
|
|
538
|
+
export function projectionApplyRecoveryProofReceiptInvariantIssues(
|
|
539
|
+
proof: ProjectionApplyRecoveryProofV1,
|
|
540
|
+
receipt: ProjectionApplyReceiptV1
|
|
541
|
+
): string[] {
|
|
542
|
+
const issues = [
|
|
543
|
+
...projectionApplyRecoveryProofInvariantIssues(proof),
|
|
544
|
+
...projectionApplyReceiptInvariantIssues(receipt)
|
|
545
|
+
];
|
|
546
|
+
const binding = receipt.recovery;
|
|
547
|
+
if (!binding) return [...issues, "committed projection receipt does not support semantic recovery"];
|
|
548
|
+
if (proof.receipt.lookupKey !== receipt.identity.lookupKey
|
|
549
|
+
|| proof.receipt.applyId !== receipt.identity.applyId
|
|
550
|
+
|| proof.receipt.receiptDigest !== receipt.result.receiptDigest) {
|
|
551
|
+
issues.push("recovery proof receipt identity must match the committed receipt");
|
|
552
|
+
}
|
|
553
|
+
if (digestJson(proof.acceptedChange as unknown as Json) !== digestJson(receipt.identity.acceptedChange as unknown as Json)
|
|
554
|
+
|| digestJson(proof.expectedResultingDigests as unknown as Json) !== digestJson(binding.expectedResultingDigests as unknown as Json)) {
|
|
555
|
+
issues.push("recovery proof approval binding must match the committed receipt");
|
|
556
|
+
}
|
|
557
|
+
if (digestJson(proof.current.resultingDigests as unknown as Json) !== digestJson(binding.expectedResultingDigests as unknown as Json)
|
|
558
|
+
|| proof.current.ownedOutputDigest !== binding.ownedOutputDigest
|
|
559
|
+
|| proof.current.snapshot.rendererVersion !== binding.rendererVersion
|
|
560
|
+
|| proof.current.snapshot.layoutVersion !== binding.layoutVersion
|
|
561
|
+
|| digestJson(proof.current.snapshot.generatedFrom as unknown as Json) !== digestJson(binding.generatedFrom as unknown as Json)) {
|
|
562
|
+
issues.push("recovery proof current state must match the committed recovery binding");
|
|
563
|
+
}
|
|
368
564
|
return issues;
|
|
369
565
|
}
|
|
370
566
|
|
|
567
|
+
function projectionApplyReceiptResultingDigests(receipt: ProjectionApplyReceiptV1): ArchitectureDigestSetV1 | undefined {
|
|
568
|
+
const signals = receipt.result.refreshSignals;
|
|
569
|
+
if (signals.length === 0) return undefined;
|
|
570
|
+
const [first] = signals;
|
|
571
|
+
return signals.every((signal) => digestJson(signal.resultingDigests as unknown as Json) === digestJson(first.resultingDigests as unknown as Json))
|
|
572
|
+
? first.resultingDigests
|
|
573
|
+
: undefined;
|
|
574
|
+
}
|
|
575
|
+
|
|
371
576
|
export function architectureRefreshSignalInvariantIssues(input: ArchitectureRefreshSignalV1, prefix = "signal"): string[] {
|
|
372
577
|
const issues = [
|
|
373
578
|
...sortedUniqueIssues(`${prefix}.reasonCodes`, input.reasonCodes),
|