archctx 0.5.7 → 0.5.9
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/assets/catalog.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "archcontext.practice-catalog-manifest/v1",
|
|
3
3
|
"catalogVersion": "2026.06.0",
|
|
4
|
-
"productVersion": "0.5.
|
|
4
|
+
"productVersion": "0.5.9",
|
|
5
5
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
6
6
|
"entries": [
|
|
7
7
|
{
|
|
@@ -389,5 +389,5 @@
|
|
|
389
389
|
"structurizr.dsl",
|
|
390
390
|
"twelve-factor"
|
|
391
391
|
],
|
|
392
|
-
"catalogDigest": "sha256:
|
|
392
|
+
"catalogDigest": "sha256:7838ef15b3da8f2c4528b7eadcbf9263adeee2e95ca2608c5819fd2b0b3708f9"
|
|
393
393
|
}
|
package/bin/archctx.mjs
CHANGED
|
@@ -897,6 +897,9 @@ function projectionResultInvariantIssues(input) {
|
|
|
897
897
|
issues.push(`${prefix} unchanged requires equal non-null digests`);
|
|
898
898
|
}
|
|
899
899
|
}
|
|
900
|
+
if (input.priorCommittedApplies) {
|
|
901
|
+
issues.push(...projectionPriorCommittedAppliesIssues(input.priorCommittedApplies, input.requestId));
|
|
902
|
+
}
|
|
900
903
|
const { receiptDigest, ...receiptPayload } = input;
|
|
901
904
|
if (projectionResultReceiptDigest(receiptPayload) !== receiptDigest)
|
|
902
905
|
issues.push("receiptDigest must match the canonical projection result payload");
|
|
@@ -915,6 +918,45 @@ function projectionResultInvariantIssues(input) {
|
|
|
915
918
|
}
|
|
916
919
|
return issues;
|
|
917
920
|
}
|
|
921
|
+
function projectionPriorCommittedAppliesIssues(input, requestId) {
|
|
922
|
+
const issues = sortedUniqueIssues("priorCommittedApplies.changeSetId", input.map((entry) => entry.changeSetId));
|
|
923
|
+
if (input.length === 0)
|
|
924
|
+
issues.push("priorCommittedApplies must be omitted instead of empty");
|
|
925
|
+
for (const [index, entry] of input.entries()) {
|
|
926
|
+
const prefix = `priorCommittedApplies[${index}]`;
|
|
927
|
+
issues.push(...sortedUniqueIssues(`${prefix}.files.path`, entry.files.map((file) => file.path)));
|
|
928
|
+
if (entry.requestId !== requestId)
|
|
929
|
+
issues.push(`${prefix}.requestId must match the projection result requestId`);
|
|
930
|
+
if (entry.changeSetId.trim() === "")
|
|
931
|
+
issues.push(`${prefix}.changeSetId must not be empty`);
|
|
932
|
+
if (!ISO_INSTANT.test(entry.committedAt))
|
|
933
|
+
issues.push(`${prefix}.committedAt must be an ISO-8601 UTC instant`);
|
|
934
|
+
if (entry.files.length === 0)
|
|
935
|
+
issues.push(`${prefix}.files must name at least one committed file`);
|
|
936
|
+
if (entry.applyId === undefined !== (entry.lookupKey === undefined)) {
|
|
937
|
+
issues.push(`${prefix}.applyId and lookupKey must be present together or both absent`);
|
|
938
|
+
}
|
|
939
|
+
for (const field of ["applyId", "lookupKey"]) {
|
|
940
|
+
const value = entry[field];
|
|
941
|
+
if (value !== undefined && !SHA256_DIGEST.test(value))
|
|
942
|
+
issues.push(`${prefix}.${field} must be a SHA-256 digest`);
|
|
943
|
+
}
|
|
944
|
+
for (const [fileIndex, file] of entry.files.entries()) {
|
|
945
|
+
const filePrefix = `${prefix}.files[${fileIndex}]`;
|
|
946
|
+
if (!isRepoRelativePosixPath(file.path))
|
|
947
|
+
issues.push(`${filePrefix}.path must be a repository-relative POSIX path`);
|
|
948
|
+
if (!PROJECTION_PRIOR_COMMITTED_APPLY_OPERATIONS.includes(file.operation)) {
|
|
949
|
+
issues.push(`${filePrefix}.operation must be a supported committed operation`);
|
|
950
|
+
}
|
|
951
|
+
const expectsMissing = file.operation === "delete";
|
|
952
|
+
if (expectsMissing && file.hash !== "missing")
|
|
953
|
+
issues.push(`${filePrefix}.hash must be "missing" for a delete`);
|
|
954
|
+
if (!expectsMissing && !SHA256_DIGEST.test(file.hash))
|
|
955
|
+
issues.push(`${filePrefix}.hash must be a SHA-256 body digest`);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return issues;
|
|
959
|
+
}
|
|
918
960
|
function projectionResultReceiptDigest(input) {
|
|
919
961
|
const refreshSignals = input.refreshSignals.map(({ projectionReceiptDigest: _projectionReceiptDigest, ...signal }) => signal);
|
|
920
962
|
return digestJson({ ...input, refreshSignals });
|
|
@@ -1126,10 +1168,11 @@ function sortedUniqueIssues(label, values) {
|
|
|
1126
1168
|
const expected = [...new Set(values)].sort();
|
|
1127
1169
|
return expected.length === values.length && expected.every((value, index) => value === values[index]) ? [] : [`${label} must be sorted and unique`];
|
|
1128
1170
|
}
|
|
1129
|
-
var PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request/v1", PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v2", PROJECTION_APPLY_IDENTITY_SCHEMA_VERSION = "archcontext.projection-apply-identity/v1", PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION = "archcontext.projection-apply-recovery-binding/v1", PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-intent/v1", PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION = "archcontext.projection-apply-recovery-proof/v1", PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-result/v1", ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1", ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1", ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v4", AGENT_CONTEXT_RENDERER_VERSION = "archcontext.agent-context-renderer/v1", PROJECTION_MODES, PROJECTION_TARGETS, ARCHITECTURE_MAJOR_CHANGE_REASON_CODES, ARCHCTX_FEATURES;
|
|
1171
|
+
var PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request/v1", PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v2", PROJECTION_APPLY_IDENTITY_SCHEMA_VERSION = "archcontext.projection-apply-identity/v1", PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION = "archcontext.projection-apply-recovery-binding/v1", PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-intent/v1", PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION = "archcontext.projection-apply-recovery-proof/v1", PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-result/v1", ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1", ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1", ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v4", AGENT_CONTEXT_RENDERER_VERSION = "archcontext.agent-context-renderer/v1", PROJECTION_MODES, PROJECTION_PRIOR_COMMITTED_APPLY_OPERATIONS, PROJECTION_TARGETS, ARCHITECTURE_MAJOR_CHANGE_REASON_CODES, ARCHCTX_FEATURES, SHA256_DIGEST, ISO_INSTANT;
|
|
1130
1172
|
var init_projection = __esm(() => {
|
|
1131
1173
|
init_schema();
|
|
1132
1174
|
PROJECTION_MODES = ["check", "plan", "apply", "adopt"];
|
|
1175
|
+
PROJECTION_PRIOR_COMMITTED_APPLY_OPERATIONS = ["delete", "write"];
|
|
1133
1176
|
PROJECTION_TARGETS = ["agent-context", "architecture-docs"];
|
|
1134
1177
|
ARCHITECTURE_MAJOR_CHANGE_REASON_CODES = [
|
|
1135
1178
|
"constraint-changed",
|
|
@@ -1152,11 +1195,14 @@ var init_projection = __esm(() => {
|
|
|
1152
1195
|
"module-statistics-v1",
|
|
1153
1196
|
"projection-apply-receipt-v1",
|
|
1154
1197
|
"projection-apply-recovery-v1",
|
|
1198
|
+
"projection-prior-committed-applies-v1",
|
|
1155
1199
|
"projection-protocol-v2",
|
|
1156
1200
|
"recommendation-v3",
|
|
1157
1201
|
"refactor-assessment-v1",
|
|
1158
1202
|
"refactor-resolution-v1"
|
|
1159
1203
|
];
|
|
1204
|
+
SHA256_DIGEST = /^sha256:[a-f0-9]{64}$/;
|
|
1205
|
+
ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/;
|
|
1160
1206
|
});
|
|
1161
1207
|
|
|
1162
1208
|
// packages/contracts/src/product-version.ts
|
|
@@ -1213,7 +1259,7 @@ function productVersionManifest() {
|
|
|
1213
1259
|
}
|
|
1214
1260
|
};
|
|
1215
1261
|
}
|
|
1216
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.5.
|
|
1262
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.5.9", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.0", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
1217
1263
|
|
|
1218
1264
|
// packages/contracts/src/refactor.ts
|
|
1219
1265
|
function refactorProposalDigest(proposal) {
|
|
@@ -2558,7 +2604,7 @@ var init_src2 = __esm(() => {
|
|
|
2558
2604
|
|
|
2559
2605
|
// node_modules/.bun/@colbymchenry+codegraph@1.5.0/node_modules/@colbymchenry/codegraph/npm-sdk.js
|
|
2560
2606
|
var require_npm_sdk = __commonJS(function(exports, module) {
|
|
2561
|
-
var __dirname = "/Users/ancienttwo/Projects/arch-context
|
|
2607
|
+
var __dirname = "/Users/ancienttwo/Projects/arch-context-wt-release-0.5.9/node_modules/.bun/@colbymchenry+codegraph@1.5.0/node_modules/@colbymchenry/codegraph";
|
|
2562
2608
|
var path = __require("path");
|
|
2563
2609
|
var os = __require("os");
|
|
2564
2610
|
var fs = __require("fs");
|
|
@@ -17517,11 +17563,14 @@ class ChangeSetEngine {
|
|
|
17517
17563
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
17518
17564
|
throw new Error("fault-injection");
|
|
17519
17565
|
}
|
|
17520
|
-
|
|
17521
|
-
|
|
17522
|
-
|
|
17523
|
-
|
|
17524
|
-
|
|
17566
|
+
const explicitProjectionOnly = draft.operations.length > 0 && draft.operations.every((operation) => (operation.op === "render_projection" || operation.op === "render_agent_context") && operation.projectionFiles !== undefined && operation.projectionFiles.length > 0);
|
|
17567
|
+
if (!explicitProjectionOnly) {
|
|
17568
|
+
for (const projection3 of deps.projection.planGeneratedProjection(root)) {
|
|
17569
|
+
await this.applyFileOperation(root, projection3.path, projection3.expectedHash, projection3.body, projection3.operation, backups, journalId, applied + 1, agentContextPaths);
|
|
17570
|
+
applied += 1;
|
|
17571
|
+
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
17572
|
+
throw new Error("fault-injection");
|
|
17573
|
+
}
|
|
17525
17574
|
}
|
|
17526
17575
|
await this.validateModel(root, draft, deps, "after");
|
|
17527
17576
|
const commit = await options.afterModelValidatedBeforeCommit?.({ root, draft, journalId });
|
|
@@ -17581,7 +17630,8 @@ class ChangeSetEngine {
|
|
|
17581
17630
|
tempPath,
|
|
17582
17631
|
backupPath,
|
|
17583
17632
|
existed,
|
|
17584
|
-
operation
|
|
17633
|
+
operation,
|
|
17634
|
+
bodyHash: operation === "delete_entity" ? "missing" : digestJson({ body })
|
|
17585
17635
|
});
|
|
17586
17636
|
}
|
|
17587
17637
|
backups.push(backup);
|
|
@@ -27222,6 +27272,32 @@ class SqliteLocalStore {
|
|
|
27222
27272
|
...recoveryProof ? { recoveryProof } : {}
|
|
27223
27273
|
};
|
|
27224
27274
|
}
|
|
27275
|
+
async listCommittedChangeSetsForTaskSession(root, taskSessionId) {
|
|
27276
|
+
const db = await this.database();
|
|
27277
|
+
const canonicalRoot = canonicalRepositoryRoot2(root);
|
|
27278
|
+
const rows = db.prepare(`SELECT journal.journal_id, journal.changeset_id, journal.root, journal.metadata_json, journal.files_json,
|
|
27279
|
+
journal.completed_at, journal.updated_at, receipt.apply_id, receipt.lookup_key
|
|
27280
|
+
FROM changeset_journal journal
|
|
27281
|
+
LEFT JOIN projection_apply_receipts receipt ON receipt.journal_id = journal.journal_id
|
|
27282
|
+
WHERE journal.status = 'committed'
|
|
27283
|
+
ORDER BY journal.completed_at ASC, journal.journal_id ASC`).all();
|
|
27284
|
+
const matched = [];
|
|
27285
|
+
for (const row of rows) {
|
|
27286
|
+
if (canonicalRepositoryRoot2(String(row.root)) !== canonicalRoot)
|
|
27287
|
+
continue;
|
|
27288
|
+
const journalId = String(row.journal_id);
|
|
27289
|
+
if (readChangeSetJournalTaskSessionId(String(row.metadata_json), journalId) !== taskSessionId)
|
|
27290
|
+
continue;
|
|
27291
|
+
matched.push({
|
|
27292
|
+
journalId,
|
|
27293
|
+
changeSetId: String(row.changeset_id),
|
|
27294
|
+
committedAt: String(row.completed_at ?? row.updated_at),
|
|
27295
|
+
...row.apply_id === null || row.apply_id === undefined ? {} : { applyId: String(row.apply_id), lookupKey: String(row.lookup_key) },
|
|
27296
|
+
files: committedChangeSetJournalFiles(String(row.files_json), journalId)
|
|
27297
|
+
});
|
|
27298
|
+
}
|
|
27299
|
+
return matched;
|
|
27300
|
+
}
|
|
27225
27301
|
async consumeProjectionApplyReceiptRecovery(proof) {
|
|
27226
27302
|
const db = await this.database();
|
|
27227
27303
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -30880,6 +30956,59 @@ function changeSetMetadata(draft) {
|
|
|
30880
30956
|
idempotencyKey: draft.idempotencyKey
|
|
30881
30957
|
};
|
|
30882
30958
|
}
|
|
30959
|
+
function readChangeSetJournalTaskSessionId(metadataJson, journalId) {
|
|
30960
|
+
let metadata;
|
|
30961
|
+
try {
|
|
30962
|
+
metadata = JSON.parse(metadataJson);
|
|
30963
|
+
} catch {
|
|
30964
|
+
throw new Error(`changeset-journal-metadata-malformed: ${journalId}`);
|
|
30965
|
+
}
|
|
30966
|
+
if (!isJsonRecord(metadata))
|
|
30967
|
+
throw new Error(`changeset-journal-metadata-malformed: ${journalId}`);
|
|
30968
|
+
const reason = metadata.reason;
|
|
30969
|
+
if (!isJsonRecord(reason) || typeof reason.taskSessionId !== "string" || reason.taskSessionId === "") {
|
|
30970
|
+
throw new Error(`changeset-journal-reason-malformed: ${journalId}`);
|
|
30971
|
+
}
|
|
30972
|
+
return reason.taskSessionId;
|
|
30973
|
+
}
|
|
30974
|
+
function committedChangeSetFileOperation(operation, journalId, path) {
|
|
30975
|
+
switch (operation) {
|
|
30976
|
+
case "delete_entity":
|
|
30977
|
+
return "delete";
|
|
30978
|
+
case "create_entity":
|
|
30979
|
+
case "update_entity_fields":
|
|
30980
|
+
case "write_policy":
|
|
30981
|
+
case "write_waiver":
|
|
30982
|
+
case "render_projection":
|
|
30983
|
+
case "render_agent_context":
|
|
30984
|
+
return "write";
|
|
30985
|
+
default:
|
|
30986
|
+
throw new Error(`changeset-journal-file-malformed: ${journalId}:${path}:${operation}`);
|
|
30987
|
+
}
|
|
30988
|
+
}
|
|
30989
|
+
function committedChangeSetJournalFiles(filesJson, journalId) {
|
|
30990
|
+
let parsed;
|
|
30991
|
+
try {
|
|
30992
|
+
parsed = JSON.parse(filesJson);
|
|
30993
|
+
} catch {
|
|
30994
|
+
throw new Error(`changeset-journal-files-malformed: ${journalId}`);
|
|
30995
|
+
}
|
|
30996
|
+
if (!Array.isArray(parsed))
|
|
30997
|
+
throw new Error(`changeset-journal-files-malformed: ${journalId}`);
|
|
30998
|
+
return parsed.map((entry) => {
|
|
30999
|
+
if (!isJsonRecord(entry) || typeof entry.path !== "string" || typeof entry.operation !== "string") {
|
|
31000
|
+
throw new Error(`changeset-journal-file-malformed: ${journalId}`);
|
|
31001
|
+
}
|
|
31002
|
+
if (typeof entry.bodyHash !== "string" || entry.bodyHash === "") {
|
|
31003
|
+
throw new Error(`changeset-journal-file-body-hash-missing: ${journalId}:${entry.path}`);
|
|
31004
|
+
}
|
|
31005
|
+
return {
|
|
31006
|
+
path: entry.path,
|
|
31007
|
+
operation: committedChangeSetFileOperation(entry.operation, journalId, entry.path),
|
|
31008
|
+
hash: entry.bodyHash
|
|
31009
|
+
};
|
|
31010
|
+
}).sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
31011
|
+
}
|
|
30883
31012
|
function readChangeSetJournalMetadata(db, journalId) {
|
|
30884
31013
|
const row = db.prepare("SELECT metadata_json FROM changeset_journal WHERE journal_id = ?").get(journalId);
|
|
30885
31014
|
if (!row)
|
|
@@ -34081,6 +34210,34 @@ class ArchctxDaemon {
|
|
|
34081
34210
|
...inspection ?? {}
|
|
34082
34211
|
});
|
|
34083
34212
|
}
|
|
34213
|
+
async listProjectionPriorCommittedApplies(root, requestId) {
|
|
34214
|
+
this.assertRunning();
|
|
34215
|
+
await this.openSession(root);
|
|
34216
|
+
let committed;
|
|
34217
|
+
try {
|
|
34218
|
+
committed = await this.localStore.listCommittedChangeSetsForTaskSession(root, requestId);
|
|
34219
|
+
} catch (error) {
|
|
34220
|
+
return errorEnvelope("projection.prior-committed-applies", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
34221
|
+
}
|
|
34222
|
+
const byChangeSetId = new Map;
|
|
34223
|
+
for (const entry of committed) {
|
|
34224
|
+
if (entry.files.length === 0)
|
|
34225
|
+
continue;
|
|
34226
|
+
byChangeSetId.set(entry.changeSetId, {
|
|
34227
|
+
...entry.applyId === undefined || entry.lookupKey === undefined ? {} : { applyId: entry.applyId, lookupKey: entry.lookupKey },
|
|
34228
|
+
requestId,
|
|
34229
|
+
changeSetId: entry.changeSetId,
|
|
34230
|
+
committedAt: entry.committedAt,
|
|
34231
|
+
files: entry.files
|
|
34232
|
+
});
|
|
34233
|
+
}
|
|
34234
|
+
const applies = [...byChangeSetId.values()].sort((left, right) => left.changeSetId < right.changeSetId ? -1 : left.changeSetId > right.changeSetId ? 1 : 0);
|
|
34235
|
+
const issues = applies.length === 0 ? [] : projectionPriorCommittedAppliesIssues(applies, requestId);
|
|
34236
|
+
if (issues.length > 0) {
|
|
34237
|
+
return errorEnvelope("projection.prior-committed-applies", "AC_SCHEMA_INVALID", `projection prior committed applies invariant failed: ${issues.join("; ")}`);
|
|
34238
|
+
}
|
|
34239
|
+
return okEnvelope("projection.prior-committed-applies", { applies });
|
|
34240
|
+
}
|
|
34084
34241
|
async recoverProjectionApply(root, intent) {
|
|
34085
34242
|
this.assertRunning();
|
|
34086
34243
|
const intentIssues = projectionApplyRecoveryIntentInvariantIssues(intent);
|
|
@@ -36900,6 +37057,9 @@ class RuntimeRpcClient {
|
|
|
36900
37057
|
inspectProjectionApplyReceipt(root, lookupKey) {
|
|
36901
37058
|
return this.call("inspectProjectionApplyReceipt", [root, lookupKey]);
|
|
36902
37059
|
}
|
|
37060
|
+
listProjectionPriorCommittedApplies(root, requestId) {
|
|
37061
|
+
return this.call("listProjectionPriorCommittedApplies", [root, requestId]);
|
|
37062
|
+
}
|
|
36903
37063
|
recoverProjectionApply(root, intent) {
|
|
36904
37064
|
return this.call("recoverProjectionApply", [root, intent]);
|
|
36905
37065
|
}
|
|
@@ -37258,6 +37418,8 @@ class ArchctxRuntimeRpcServer {
|
|
|
37258
37418
|
return this.daemon.applyUpdate(params[0], params[1]);
|
|
37259
37419
|
case "inspectProjectionApplyReceipt":
|
|
37260
37420
|
return this.daemon.inspectProjectionApplyReceipt(params[0], params[1]);
|
|
37421
|
+
case "listProjectionPriorCommittedApplies":
|
|
37422
|
+
return this.daemon.listProjectionPriorCommittedApplies(params[0], params[1]);
|
|
37261
37423
|
case "recoverProjectionApply":
|
|
37262
37424
|
return this.daemon.recoverProjectionApply(params[0], params[1]);
|
|
37263
37425
|
case "ledgerState":
|
|
@@ -39509,6 +39671,9 @@ class RuntimeRpcClient2 {
|
|
|
39509
39671
|
inspectProjectionApplyReceipt(root, lookupKey) {
|
|
39510
39672
|
return this.call("inspectProjectionApplyReceipt", [root, lookupKey]);
|
|
39511
39673
|
}
|
|
39674
|
+
listProjectionPriorCommittedApplies(root, requestId) {
|
|
39675
|
+
return this.call("listProjectionPriorCommittedApplies", [root, requestId]);
|
|
39676
|
+
}
|
|
39512
39677
|
recoverProjectionApply(root, intent) {
|
|
39513
39678
|
return this.call("recoverProjectionApply", [root, intent]);
|
|
39514
39679
|
}
|
|
@@ -40156,6 +40321,16 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
|
|
|
40156
40321
|
try {
|
|
40157
40322
|
switch (command2) {
|
|
40158
40323
|
case "init":
|
|
40324
|
+
if (args2.includes("--help") || args2.includes("-h")) {
|
|
40325
|
+
return okEnvelope("help", {
|
|
40326
|
+
usage: "archctx init [--name <product-name>]",
|
|
40327
|
+
description: "Initialize the repository architecture model and generated projection.",
|
|
40328
|
+
options: {
|
|
40329
|
+
"--name <product-name>": "Product name (default: ArchContext Project).",
|
|
40330
|
+
"--help, -h": "Show help without initializing the repository."
|
|
40331
|
+
}
|
|
40332
|
+
});
|
|
40333
|
+
}
|
|
40159
40334
|
return (await runtime()).init(cwd, readFlag(args2, "--name") ?? "ArchContext Project");
|
|
40160
40335
|
case "sync":
|
|
40161
40336
|
return (await runtime()).sync(cwd, readRepeatedFlag(args2, "--changed"));
|
|
@@ -41110,7 +41285,7 @@ function architectureProjectionProfile(args2) {
|
|
|
41110
41285
|
}
|
|
41111
41286
|
return profile;
|
|
41112
41287
|
}
|
|
41113
|
-
async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt, protocolRequest) {
|
|
41288
|
+
async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt, protocolRequest, priorCommittedApplies = []) {
|
|
41114
41289
|
if (profile !== REPO_HARNESS_PROJECTION_PROFILE) {
|
|
41115
41290
|
return errorEnvelope("docs.adopt", "AC_SCHEMA_INVALID", `docs adopt requires --profile ${REPO_HARNESS_PROJECTION_PROFILE}`);
|
|
41116
41291
|
}
|
|
@@ -41162,7 +41337,7 @@ async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projectio
|
|
|
41162
41337
|
return errorEnvelope("docs.adopt", "AC_PRECONDITION_FAILED", `projection-adoption-fixed-point-unproven: drift=${drift}; rejected=${reasons}; digest=${canonical.plan.projectionDigest === canonicalFirst.plan.projectionDigest ? "stable" : "changed"}`);
|
|
41163
41338
|
}
|
|
41164
41339
|
if (protocolRequest) {
|
|
41165
|
-
return applyProjectionProtocolFixedPoint(protocolRequest, projection3, canonical, adoption2.changeSetId, root, daemon);
|
|
41340
|
+
return applyProjectionProtocolFixedPoint(protocolRequest, projection3, canonical, adoption2.changeSetId, root, daemon, priorCommittedApplies);
|
|
41166
41341
|
}
|
|
41167
41342
|
const filesByPath = new Map;
|
|
41168
41343
|
for (const file of canonical.files)
|
|
@@ -41186,7 +41361,7 @@ async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projectio
|
|
|
41186
41361
|
apply: applied.data
|
|
41187
41362
|
});
|
|
41188
41363
|
}
|
|
41189
|
-
async function applyProjectionProtocolFixedPoint(request, input, fixedPoint, changeSetId, root, daemon) {
|
|
41364
|
+
async function applyProjectionProtocolFixedPoint(request, input, fixedPoint, changeSetId, root, daemon, priorCommittedApplies) {
|
|
41190
41365
|
const committedFiles = projectionProtocolFilesForExpectedOutput(root, fixedPoint);
|
|
41191
41366
|
const committedSignals = request.acceptedChange ? input.plan.refreshSignals.map((signal) => ({
|
|
41192
41367
|
...signal,
|
|
@@ -41204,7 +41379,7 @@ async function applyProjectionProtocolFixedPoint(request, input, fixedPoint, cha
|
|
|
41204
41379
|
const appliedResult = projectionProtocolResult(request, input, "applied", fixedPoint, applyIdentity, {
|
|
41205
41380
|
files: committedFiles,
|
|
41206
41381
|
refreshSignals: committedSignals
|
|
41207
|
-
});
|
|
41382
|
+
}, priorCommittedApplies);
|
|
41208
41383
|
let recoveryBinding;
|
|
41209
41384
|
if (applyIdentity) {
|
|
41210
41385
|
try {
|
|
@@ -41290,6 +41465,15 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
41290
41465
|
}
|
|
41291
41466
|
const root = findRepositoryRoot(cwd);
|
|
41292
41467
|
const generatedAt = new Date(0).toISOString();
|
|
41468
|
+
let priorCommittedApplies;
|
|
41469
|
+
try {
|
|
41470
|
+
const listed = await daemon.listProjectionPriorCommittedApplies(root, request.requestId);
|
|
41471
|
+
if (!listed.ok)
|
|
41472
|
+
return listed;
|
|
41473
|
+
priorCommittedApplies = parseProjectionPriorCommittedApplies(listed.data, request.requestId);
|
|
41474
|
+
} catch (error) {
|
|
41475
|
+
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", `projection prior committed apply lookup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
41476
|
+
}
|
|
41293
41477
|
if (request.mode === "apply" && request.acceptedChange) {
|
|
41294
41478
|
try {
|
|
41295
41479
|
assertProjectionExpectedSnapshotAgainstModel(request, root, loadNativeModelFromArchContext(root));
|
|
@@ -41316,7 +41500,7 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
41316
41500
|
}
|
|
41317
41501
|
const blocked = projectionProtocolHumanStatus(request, projection3);
|
|
41318
41502
|
if (blocked)
|
|
41319
|
-
return projectionProtocolEnvelope(request, projection3, blocked);
|
|
41503
|
+
return projectionProtocolEnvelope(request, projection3, blocked, projection3, priorCommittedApplies);
|
|
41320
41504
|
if (request.mode === "adopt") {
|
|
41321
41505
|
const expectedWorktreeDigest = computeWorktreeDigest(root);
|
|
41322
41506
|
const adopted = await runArchitectureDocsAdoptionCommand([
|
|
@@ -41330,7 +41514,7 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
41330
41514
|
expectedWorktreeDigest,
|
|
41331
41515
|
"--task-session-id",
|
|
41332
41516
|
request.requestId
|
|
41333
|
-
], root, daemon, projection3, REPO_HARNESS_PROJECTION_PROFILE, generatedAt, request);
|
|
41517
|
+
], root, daemon, projection3, REPO_HARNESS_PROJECTION_PROFILE, generatedAt, request, priorCommittedApplies);
|
|
41334
41518
|
if (!adopted.ok)
|
|
41335
41519
|
return adopted;
|
|
41336
41520
|
return adopted;
|
|
@@ -41346,10 +41530,23 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
41346
41530
|
} catch (error) {
|
|
41347
41531
|
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
41348
41532
|
}
|
|
41349
|
-
return applyProjectionProtocolFixedPoint(request, projection3, fixedPointProjection, changeSetId, root, daemon);
|
|
41533
|
+
return applyProjectionProtocolFixedPoint(request, projection3, fixedPointProjection, changeSetId, root, daemon, priorCommittedApplies);
|
|
41350
41534
|
}
|
|
41351
41535
|
const status = projection3.plan.drift.ok ? "noop" : "planned";
|
|
41352
|
-
return projectionProtocolEnvelope(request, projection3, status);
|
|
41536
|
+
return projectionProtocolEnvelope(request, projection3, status, projection3, priorCommittedApplies);
|
|
41537
|
+
}
|
|
41538
|
+
function parseProjectionPriorCommittedApplies(value, requestId) {
|
|
41539
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
41540
|
+
throw new Error("prior committed apply reply must be an object");
|
|
41541
|
+
const applies = value.applies;
|
|
41542
|
+
if (!Array.isArray(applies))
|
|
41543
|
+
throw new Error("prior committed apply reply must carry an applies array");
|
|
41544
|
+
if (applies.length === 0)
|
|
41545
|
+
return [];
|
|
41546
|
+
const issues = projectionPriorCommittedAppliesIssues(applies, requestId);
|
|
41547
|
+
if (issues.length > 0)
|
|
41548
|
+
throw new Error(`prior committed apply invariant failed: ${issues.join("; ")}`);
|
|
41549
|
+
return applies;
|
|
41353
41550
|
}
|
|
41354
41551
|
async function runProjectionApplyRecoveryCommand(args2, cwd, daemon) {
|
|
41355
41552
|
const raw = readFlag(args2, "--request-json");
|
|
@@ -41537,10 +41734,10 @@ function projectionProtocolHumanStatus(request, projection3) {
|
|
|
41537
41734
|
return "adoption-required";
|
|
41538
41735
|
return otherRejection || humanSignal ? "human-action-required" : null;
|
|
41539
41736
|
}
|
|
41540
|
-
function projectionProtocolEnvelope(request, input, status, output
|
|
41541
|
-
return projectionProtocolResultEnvelope(projectionProtocolResult(request, input, status, output));
|
|
41737
|
+
function projectionProtocolEnvelope(request, input, status, output, priorCommittedApplies) {
|
|
41738
|
+
return projectionProtocolResultEnvelope(projectionProtocolResult(request, input, status, output, undefined, undefined, priorCommittedApplies));
|
|
41542
41739
|
}
|
|
41543
|
-
function projectionProtocolResult(request, input, status, output = input, applyReceipt, overrides) {
|
|
41740
|
+
function projectionProtocolResult(request, input, status, output = input, applyReceipt, overrides, priorCommittedApplies = []) {
|
|
41544
41741
|
const inputSnapshot = projectionProtocolSnapshot(request, input.plan.provenance);
|
|
41545
41742
|
const outputSnapshot = projectionProtocolSnapshot(request, output.plan.provenance);
|
|
41546
41743
|
const files = overrides?.files ?? projectionProtocolFiles(input);
|
|
@@ -41567,7 +41764,8 @@ function projectionProtocolResult(request, input, status, output = input, applyR
|
|
|
41567
41764
|
files,
|
|
41568
41765
|
humanActions,
|
|
41569
41766
|
refreshSignals,
|
|
41570
|
-
...applyReceipt ? { applyReceipt } : {}
|
|
41767
|
+
...applyReceipt ? { applyReceipt } : {},
|
|
41768
|
+
...priorCommittedApplies.length > 0 ? { priorCommittedApplies } : {}
|
|
41571
41769
|
};
|
|
41572
41770
|
const receiptDigest = projectionResultReceiptDigest(withoutReceipt);
|
|
41573
41771
|
const result = {
|
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", "module-statistics-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-protocol-v2", "recommendation-v3", "refactor-assessment-v1", "refactor-resolution-v1"] }
|
|
42
|
+
"items": { "enum": ["architecture-docs-renderer-v2", "architecture-refresh-signal-v1", "module-statistics-v1", "projection-apply-receipt-v1", "projection-apply-recovery-v1", "projection-prior-committed-applies-v1", "projection-protocol-v2", "recommendation-v3", "refactor-assessment-v1", "refactor-resolution-v1"] }
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"humanActions": { "type": "array", "items": { "$ref": "#/$defs/humanAction" } },
|
|
17
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
18
|
"applyReceipt": { "$ref": "#/$defs/applyIdentity" },
|
|
19
|
+
"priorCommittedApplies": { "type": "array", "minItems": 1, "description": "Omitted, never empty. Canonical wire order is by changeSetId and is enforced by projectionResultInvariantIssues.", "items": { "$ref": "#/$defs/priorCommittedApply" } },
|
|
19
20
|
"receiptDigest": { "$ref": "#/$defs/digest" }
|
|
20
21
|
},
|
|
21
22
|
"allOf": [
|
|
@@ -166,6 +167,45 @@
|
|
|
166
167
|
"affectedNodeIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
167
168
|
}
|
|
168
169
|
},
|
|
170
|
+
"priorCommittedApply": {
|
|
171
|
+
"type": "object",
|
|
172
|
+
"additionalProperties": false,
|
|
173
|
+
"required": ["requestId", "changeSetId", "committedAt", "files"],
|
|
174
|
+
"properties": {
|
|
175
|
+
"applyId": { "$ref": "#/$defs/digest" },
|
|
176
|
+
"lookupKey": { "$ref": "#/$defs/digest" },
|
|
177
|
+
"requestId": { "type": "string", "pattern": "^[a-zA-Z0-9_.:-]+$", "minLength": 1 },
|
|
178
|
+
"changeSetId": { "type": "string", "minLength": 1 },
|
|
179
|
+
"committedAt": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$" },
|
|
180
|
+
"files": {
|
|
181
|
+
"type": "array",
|
|
182
|
+
"minItems": 1,
|
|
183
|
+
"description": "Canonical wire order is by path and is enforced by projectionResultInvariantIssues.",
|
|
184
|
+
"items": {
|
|
185
|
+
"type": "object",
|
|
186
|
+
"additionalProperties": false,
|
|
187
|
+
"required": ["path", "operation", "hash"],
|
|
188
|
+
"properties": {
|
|
189
|
+
"path": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"minLength": 1,
|
|
192
|
+
"not": { "anyOf": [{ "pattern": "^/" }, { "pattern": "\\\\" }, { "pattern": "(^|/)\\.\\.(/|$)" }] }
|
|
193
|
+
},
|
|
194
|
+
"operation": { "enum": ["delete", "write"] },
|
|
195
|
+
"hash": { "type": "string", "pattern": "^(?:sha256:[a-f0-9]{64}|missing)$" }
|
|
196
|
+
},
|
|
197
|
+
"allOf": [
|
|
198
|
+
{
|
|
199
|
+
"if": { "properties": { "operation": { "const": "delete" } }, "required": ["operation"] },
|
|
200
|
+
"then": { "properties": { "hash": { "const": "missing" } } },
|
|
201
|
+
"else": { "properties": { "hash": { "$ref": "#/$defs/digest" } } }
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"dependentRequired": { "applyId": ["lookupKey"], "lookupKey": ["applyId"] }
|
|
208
|
+
},
|
|
169
209
|
"applyIdentity": {
|
|
170
210
|
"type": "object",
|
|
171
211
|
"additionalProperties": false,
|