@quolu/lattice 0.52.2 → 0.52.4
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/package.json +1 -1
- package/src/artifact-contracts-v2.mjs +325 -325
- package/src/artifact-contracts.mjs +895 -895
- package/src/boundary-compiler.mjs +712 -712
- package/src/boundary-observation-compiler-v2.mjs +344 -344
- package/src/bounded-seam.mjs +230 -230
- package/src/bridge-address.mjs +107 -107
- package/src/bridge-cli.mjs +297 -297
- package/src/bridge-config.mjs +346 -346
- package/src/bridge-daemon.mjs +378 -378
- package/src/bridge-hub-protocol.mjs +198 -0
- package/src/bridge-launch-agent.mjs +323 -323
- package/src/bridge-registrar.mjs +102 -102
- package/src/bridge-server.mjs +376 -376
- package/src/cli-help.mjs +308 -308
- package/src/cli-stdio.mjs +40 -40
- package/src/control-compiler.mjs +532 -532
- package/src/dag-chain.mjs +261 -261
- package/src/factory-diagnostics.mjs +188 -188
- package/src/git-process.mjs +72 -0
- package/src/hash-chain.mjs +76 -76
- package/src/hooks-cli.mjs +1057 -1057
- package/src/isolation-runner.mjs +409 -409
- package/src/node-version-guard.mjs +44 -44
- package/src/project-cli.mjs +699 -697
- package/src/project-identity.mjs +130 -130
- package/src/rc1-black-box-oracle.mjs +906 -906
- package/src/rc1-comparison.mjs +154 -154
- package/src/rc1-evidence-bundle.mjs +456 -456
- package/src/rc1-v4-campaign.mjs +708 -708
- package/src/rc1-v4-transform.mjs +467 -467
- package/src/rc1-v5-artifact-set.mjs +855 -855
- package/src/rc1-v5-behavior-evidence.mjs +594 -594
- package/src/rc1-v5-campaign.mjs +797 -797
- package/src/rc1-v5-transform.mjs +421 -421
- package/src/rc1-v6-artifact-set.mjs +807 -807
- package/src/rc1-v6-behavior-evidence.mjs +273 -273
- package/src/rc1-v6-campaign.mjs +623 -623
- package/src/rc1-v6-causal-binding.mjs +473 -473
- package/src/rc1-v6-measurement.mjs +313 -313
- package/src/rc2-artifact-set.mjs +1584 -1584
- package/src/rc2-campaign.mjs +1506 -1506
- package/src/rc2-delivery-policy-front-end.mjs +1079 -1079
- package/src/rc2-delivery-policy-oracle.mjs +134 -134
- package/src/rc2-delivery-policy-transform.mjs +1127 -1127
- package/src/rc2-rc1-transfer-front-end.mjs +511 -511
- package/src/rc3-actual-dogfood.mjs +652 -652
- package/src/rc3-dogfood-scaffold.mjs +315 -315
- package/src/rc3-scripted-campaign.mjs +1383 -1383
- package/src/rc4-stage1-dogfood.mjs +673 -673
- package/src/runtime-adapter-registry.mjs +524 -524
- package/src/runtime-cli.mjs +4588 -4588
- package/src/runtime-contracts.mjs +824 -824
- package/src/runtime-control-store.mjs +604 -604
- package/src/runtime-controller-protocol.mjs +587 -587
- package/src/runtime-decision-verifier.mjs +701 -701
- package/src/runtime-diff-observer.mjs +361 -361
- package/src/runtime-direct-os-observer.mjs +301 -301
- package/src/runtime-driver-state.mjs +166 -166
- package/src/runtime-engine.mjs +779 -779
- package/src/runtime-errors.mjs +356 -356
- package/src/runtime-event-store.mjs +189 -189
- package/src/runtime-front-end.mjs +925 -925
- package/src/runtime-gate-store.mjs +481 -481
- package/src/runtime-hold-recompile.mjs +916 -916
- package/src/runtime-io-sentinel.mjs +391 -391
- package/src/runtime-lifecycle-lock.mjs +294 -294
- package/src/runtime-managed-supervisor.mjs +1490 -1490
- package/src/runtime-multi-epoch-store.mjs +838 -838
- package/src/runtime-projection.mjs +269 -269
- package/src/runtime-pull-intake.mjs +1192 -1192
- package/src/runtime-scripted-adapter-controller.mjs +1160 -1160
- package/src/runtime-scripted-executor.mjs +163 -163
- package/src/runtime-scripted-worktree.mjs +104 -104
- package/src/runtime-seam-resolve.mjs +428 -428
- package/src/runtime-seam-treatment.mjs +173 -173
- package/src/runtime-socket-owner.mjs +125 -125
- package/src/runtime-work-order-contracts.mjs +91 -91
- package/src/runtime-work-order-controller.mjs +1171 -1171
- package/src/runtime-worktree-executor.mjs +199 -199
- package/src/schedulability-compiler-v2.mjs +303 -303
- package/src/schedulability-verifier-v2.mjs +317 -317
- package/src/seam-apply.mjs +549 -549
- package/src/seam-commit-shared.mjs +22 -22
- package/src/seam-commit-transform.mjs +81 -81
- package/src/seam-commit.mjs +18 -18
- package/src/seam-cost.mjs +322 -322
- package/src/seam-derivation.mjs +188 -188
- package/src/seam-gate.mjs +146 -146
- package/src/seam-proposal-contracts.mjs +446 -446
- package/src/seam-proposal-queries.mjs +521 -521
- package/src/seam-proposal.mjs +2011 -2011
- package/src/seam-ref.mjs +33 -33
- package/src/seam-rewrite.mjs +286 -286
- package/src/seam-transform.mjs +554 -554
- package/src/seam-verification.mjs +260 -260
- package/src/sensor-adapter.mjs +432 -432
- package/src/sensor-cli.mjs +139 -139
- package/src/sensor-diff.mjs +661 -661
- package/src/sensor-node-runtime.mjs +53 -53
- package/src/sensor-runtime.mjs +52 -52
- package/src/timestamp-contract.mjs +8 -8
- package/src/todo-audit-pending.mjs +91 -91
- package/src/todo-chain.mjs +178 -178
- package/src/todo-cli.mjs +3143 -3141
- package/src/todo-contracts.mjs +728 -728
- package/src/todo-dashboard-registry.mjs +573 -573
- package/src/todo-dispatch-shape.mjs +190 -190
- package/src/todo-gantt-html-independence.mjs +239 -239
- package/src/todo-gantt-html-shared.mjs +226 -226
- package/src/todo-gantt-html-style.mjs +131 -131
- package/src/todo-gantt-html.mjs +248 -248
- package/src/todo-gantt-layout.mjs +974 -974
- package/src/todo-gantt-live.mjs +361 -361
- package/src/todo-gantt-nested.mjs +263 -263
- package/src/todo-gantt-presentation.mjs +217 -217
- package/src/todo-gantt-scope.mjs +123 -123
- package/src/todo-gantt-svg.mjs +353 -353
- package/src/todo-independence-contracts.mjs +595 -595
- package/src/todo-independence-guidance.mjs +322 -322
- package/src/todo-independence.mjs +640 -640
- package/src/todo-markdown-renderer.mjs +260 -260
- package/src/todo-migration.mjs +448 -448
- package/src/todo-narrative-anchor.mjs +130 -130
- package/src/todo-note-store.mjs +629 -629
- package/src/todo-parallel-candidates.mjs +114 -114
- package/src/todo-revision.mjs +995 -995
- package/src/todo-split.mjs +472 -472
- package/src/todo-status.mjs +690 -690
- package/src/todo-store-git-transaction.mjs +418 -418
- package/src/todo-store.mjs +4360 -4322
- package/src/treatment-compiler.mjs +728 -728
- package/src/treatment-runner.mjs +656 -656
- package/src/witness-scaffold.mjs +180 -180
|
@@ -1,130 +1,130 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
import { parseTodoMarkdownDocument } from './todo-markdown-renderer.mjs';
|
|
4
|
-
|
|
5
|
-
const REASONS = Object.freeze({
|
|
6
|
-
ANCHOR_MISSING: 'anchor_missing',
|
|
7
|
-
PATH_MISMATCH: 'path_mismatch',
|
|
8
|
-
LINE_MISSING: 'line_missing',
|
|
9
|
-
DIGEST_MISMATCH: 'digest_mismatch',
|
|
10
|
-
NOT_CHECKBOX: 'not_checkbox',
|
|
11
|
-
DUPLICATE_CLAIM: 'duplicate_claim',
|
|
12
|
-
AST_LOCATION_MISSING: 'ast_location_missing',
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
function refKey(ref) {
|
|
16
|
-
return JSON.stringify([ref.project_id, ref.plan_key, ref.task_id]);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function compareText(left, right) {
|
|
20
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function compareRefs(left, right) {
|
|
24
|
-
return compareText(left.project_id, right.project_id)
|
|
25
|
-
|| compareText(left.plan_key, right.plan_key)
|
|
26
|
-
|| compareText(left.task_id, right.task_id);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function listItems(tree) {
|
|
30
|
-
const result = [];
|
|
31
|
-
const visit = (node) => {
|
|
32
|
-
if (node === null || typeof node !== 'object') return;
|
|
33
|
-
if (node.type === 'listItem') result.push(node);
|
|
34
|
-
if (Array.isArray(node.children)) for (const child of node.children) visit(child);
|
|
35
|
-
};
|
|
36
|
-
visit(tree);
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function outcome(ref, narrativeRef, anchor, reason) {
|
|
41
|
-
return {
|
|
42
|
-
ref,
|
|
43
|
-
narrative_ref: narrativeRef,
|
|
44
|
-
anchored: reason === null,
|
|
45
|
-
reason,
|
|
46
|
-
origin_line: anchor?.origin_line ?? null,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function verifyNarrativeAnchors({
|
|
51
|
-
readModel,
|
|
52
|
-
narratives,
|
|
53
|
-
parseMarkdown = parseTodoMarkdownDocument,
|
|
54
|
-
}) {
|
|
55
|
-
if (readModel?.schema !== 'lattice.todo_store_read.v1' || !Array.isArray(readModel.members)) {
|
|
56
|
-
throw new TypeError('readModel must be lattice.todo_store_read.v1');
|
|
57
|
-
}
|
|
58
|
-
if (!Array.isArray(narratives)) throw new TypeError('narratives must be an array');
|
|
59
|
-
if (typeof parseMarkdown !== 'function') throw new TypeError('parseMarkdown must be a function');
|
|
60
|
-
|
|
61
|
-
const supplied = new Map(narratives.map((entry) => [refKey(entry.ref), entry]));
|
|
62
|
-
const candidates = [];
|
|
63
|
-
for (const member of readModel.members) for (const task of member.plan.tasks) {
|
|
64
|
-
const ref = {
|
|
65
|
-
project_id: member.plan.project_id,
|
|
66
|
-
plan_key: member.plan.plan_key,
|
|
67
|
-
task_id: task.task_id,
|
|
68
|
-
};
|
|
69
|
-
const anchor = task.narrative_anchor ?? null;
|
|
70
|
-
const narrative = supplied.get(refKey(ref));
|
|
71
|
-
candidates.push({ ref, task, anchor, narrative });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const duplicateClaims = new Set();
|
|
75
|
-
const claims = new Map();
|
|
76
|
-
for (const candidate of candidates) {
|
|
77
|
-
const { anchor, narrative, task } = candidate;
|
|
78
|
-
if (anchor === null || task.narrative_ref !== anchor.origin_plan_ref
|
|
79
|
-
|| narrative?.narrative_ref !== task.narrative_ref || typeof narrative?.markdown !== 'string') continue;
|
|
80
|
-
const claimKey = JSON.stringify([anchor.origin_plan_ref, anchor.origin_line]);
|
|
81
|
-
const claimed = claims.get(claimKey) ?? [];
|
|
82
|
-
claimed.push(candidate);
|
|
83
|
-
claims.set(claimKey, claimed);
|
|
84
|
-
}
|
|
85
|
-
for (const claimed of claims.values()) {
|
|
86
|
-
if (claimed.length > 1) for (const candidate of claimed) duplicateClaims.add(refKey(candidate.ref));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const parsedDocuments = new Map();
|
|
90
|
-
const outcomes = candidates.map(({ ref, task, anchor, narrative }) => {
|
|
91
|
-
if (anchor === null) return outcome(ref, task.narrative_ref, anchor, REASONS.ANCHOR_MISSING);
|
|
92
|
-
if (task.narrative_ref !== anchor.origin_plan_ref
|
|
93
|
-
|| narrative?.narrative_ref !== task.narrative_ref || typeof narrative?.markdown !== 'string') {
|
|
94
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.PATH_MISMATCH);
|
|
95
|
-
}
|
|
96
|
-
if (duplicateClaims.has(refKey(ref))) {
|
|
97
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.DUPLICATE_CLAIM);
|
|
98
|
-
}
|
|
99
|
-
const lines = narrative.markdown.split('\n');
|
|
100
|
-
if (!Number.isSafeInteger(anchor.origin_line) || anchor.origin_line < 1
|
|
101
|
-
|| anchor.origin_line > lines.length) {
|
|
102
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.LINE_MISSING);
|
|
103
|
-
}
|
|
104
|
-
const line = lines[anchor.origin_line - 1];
|
|
105
|
-
const lineDigest = createHash('sha256').update(Buffer.from(line, 'utf8')).digest('hex');
|
|
106
|
-
if (lineDigest !== anchor.source_line_digest) {
|
|
107
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.DIGEST_MISMATCH);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const documentKey = JSON.stringify([task.narrative_ref, narrative.markdown]);
|
|
111
|
-
let items = parsedDocuments.get(documentKey);
|
|
112
|
-
if (items === undefined) {
|
|
113
|
-
items = listItems(parseMarkdown(narrative.markdown));
|
|
114
|
-
parsedDocuments.set(documentKey, items);
|
|
115
|
-
}
|
|
116
|
-
const matched = items.find((item) => item.position?.start?.line === anchor.origin_line);
|
|
117
|
-
if (matched !== undefined && typeof matched.checked === 'boolean') {
|
|
118
|
-
return outcome(ref, task.narrative_ref, anchor, null);
|
|
119
|
-
}
|
|
120
|
-
if (matched === undefined && items.some((item) => !Number.isSafeInteger(item.position?.start?.line))) {
|
|
121
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.AST_LOCATION_MISSING);
|
|
122
|
-
}
|
|
123
|
-
return outcome(ref, task.narrative_ref, anchor, REASONS.NOT_CHECKBOX);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
outcomes.sort((left, right) => compareRefs(left.ref, right.ref));
|
|
127
|
-
return outcomes;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export const TODO_NARRATIVE_ANCHOR_REASONS = REASONS;
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
import { parseTodoMarkdownDocument } from './todo-markdown-renderer.mjs';
|
|
4
|
+
|
|
5
|
+
const REASONS = Object.freeze({
|
|
6
|
+
ANCHOR_MISSING: 'anchor_missing',
|
|
7
|
+
PATH_MISMATCH: 'path_mismatch',
|
|
8
|
+
LINE_MISSING: 'line_missing',
|
|
9
|
+
DIGEST_MISMATCH: 'digest_mismatch',
|
|
10
|
+
NOT_CHECKBOX: 'not_checkbox',
|
|
11
|
+
DUPLICATE_CLAIM: 'duplicate_claim',
|
|
12
|
+
AST_LOCATION_MISSING: 'ast_location_missing',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function refKey(ref) {
|
|
16
|
+
return JSON.stringify([ref.project_id, ref.plan_key, ref.task_id]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function compareText(left, right) {
|
|
20
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function compareRefs(left, right) {
|
|
24
|
+
return compareText(left.project_id, right.project_id)
|
|
25
|
+
|| compareText(left.plan_key, right.plan_key)
|
|
26
|
+
|| compareText(left.task_id, right.task_id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function listItems(tree) {
|
|
30
|
+
const result = [];
|
|
31
|
+
const visit = (node) => {
|
|
32
|
+
if (node === null || typeof node !== 'object') return;
|
|
33
|
+
if (node.type === 'listItem') result.push(node);
|
|
34
|
+
if (Array.isArray(node.children)) for (const child of node.children) visit(child);
|
|
35
|
+
};
|
|
36
|
+
visit(tree);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function outcome(ref, narrativeRef, anchor, reason) {
|
|
41
|
+
return {
|
|
42
|
+
ref,
|
|
43
|
+
narrative_ref: narrativeRef,
|
|
44
|
+
anchored: reason === null,
|
|
45
|
+
reason,
|
|
46
|
+
origin_line: anchor?.origin_line ?? null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function verifyNarrativeAnchors({
|
|
51
|
+
readModel,
|
|
52
|
+
narratives,
|
|
53
|
+
parseMarkdown = parseTodoMarkdownDocument,
|
|
54
|
+
}) {
|
|
55
|
+
if (readModel?.schema !== 'lattice.todo_store_read.v1' || !Array.isArray(readModel.members)) {
|
|
56
|
+
throw new TypeError('readModel must be lattice.todo_store_read.v1');
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(narratives)) throw new TypeError('narratives must be an array');
|
|
59
|
+
if (typeof parseMarkdown !== 'function') throw new TypeError('parseMarkdown must be a function');
|
|
60
|
+
|
|
61
|
+
const supplied = new Map(narratives.map((entry) => [refKey(entry.ref), entry]));
|
|
62
|
+
const candidates = [];
|
|
63
|
+
for (const member of readModel.members) for (const task of member.plan.tasks) {
|
|
64
|
+
const ref = {
|
|
65
|
+
project_id: member.plan.project_id,
|
|
66
|
+
plan_key: member.plan.plan_key,
|
|
67
|
+
task_id: task.task_id,
|
|
68
|
+
};
|
|
69
|
+
const anchor = task.narrative_anchor ?? null;
|
|
70
|
+
const narrative = supplied.get(refKey(ref));
|
|
71
|
+
candidates.push({ ref, task, anchor, narrative });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const duplicateClaims = new Set();
|
|
75
|
+
const claims = new Map();
|
|
76
|
+
for (const candidate of candidates) {
|
|
77
|
+
const { anchor, narrative, task } = candidate;
|
|
78
|
+
if (anchor === null || task.narrative_ref !== anchor.origin_plan_ref
|
|
79
|
+
|| narrative?.narrative_ref !== task.narrative_ref || typeof narrative?.markdown !== 'string') continue;
|
|
80
|
+
const claimKey = JSON.stringify([anchor.origin_plan_ref, anchor.origin_line]);
|
|
81
|
+
const claimed = claims.get(claimKey) ?? [];
|
|
82
|
+
claimed.push(candidate);
|
|
83
|
+
claims.set(claimKey, claimed);
|
|
84
|
+
}
|
|
85
|
+
for (const claimed of claims.values()) {
|
|
86
|
+
if (claimed.length > 1) for (const candidate of claimed) duplicateClaims.add(refKey(candidate.ref));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const parsedDocuments = new Map();
|
|
90
|
+
const outcomes = candidates.map(({ ref, task, anchor, narrative }) => {
|
|
91
|
+
if (anchor === null) return outcome(ref, task.narrative_ref, anchor, REASONS.ANCHOR_MISSING);
|
|
92
|
+
if (task.narrative_ref !== anchor.origin_plan_ref
|
|
93
|
+
|| narrative?.narrative_ref !== task.narrative_ref || typeof narrative?.markdown !== 'string') {
|
|
94
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.PATH_MISMATCH);
|
|
95
|
+
}
|
|
96
|
+
if (duplicateClaims.has(refKey(ref))) {
|
|
97
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.DUPLICATE_CLAIM);
|
|
98
|
+
}
|
|
99
|
+
const lines = narrative.markdown.split('\n');
|
|
100
|
+
if (!Number.isSafeInteger(anchor.origin_line) || anchor.origin_line < 1
|
|
101
|
+
|| anchor.origin_line > lines.length) {
|
|
102
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.LINE_MISSING);
|
|
103
|
+
}
|
|
104
|
+
const line = lines[anchor.origin_line - 1];
|
|
105
|
+
const lineDigest = createHash('sha256').update(Buffer.from(line, 'utf8')).digest('hex');
|
|
106
|
+
if (lineDigest !== anchor.source_line_digest) {
|
|
107
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.DIGEST_MISMATCH);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const documentKey = JSON.stringify([task.narrative_ref, narrative.markdown]);
|
|
111
|
+
let items = parsedDocuments.get(documentKey);
|
|
112
|
+
if (items === undefined) {
|
|
113
|
+
items = listItems(parseMarkdown(narrative.markdown));
|
|
114
|
+
parsedDocuments.set(documentKey, items);
|
|
115
|
+
}
|
|
116
|
+
const matched = items.find((item) => item.position?.start?.line === anchor.origin_line);
|
|
117
|
+
if (matched !== undefined && typeof matched.checked === 'boolean') {
|
|
118
|
+
return outcome(ref, task.narrative_ref, anchor, null);
|
|
119
|
+
}
|
|
120
|
+
if (matched === undefined && items.some((item) => !Number.isSafeInteger(item.position?.start?.line))) {
|
|
121
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.AST_LOCATION_MISSING);
|
|
122
|
+
}
|
|
123
|
+
return outcome(ref, task.narrative_ref, anchor, REASONS.NOT_CHECKBOX);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
outcomes.sort((left, right) => compareRefs(left.ref, right.ref));
|
|
127
|
+
return outcomes;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const TODO_NARRATIVE_ANCHOR_REASONS = REASONS;
|