@davidorex/pi-context 0.29.0 → 0.30.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.
@@ -473,9 +473,100 @@ export declare function appendRelationByRef(cwd: string, rel: {
473
473
  child: string;
474
474
  relation_type: string;
475
475
  ordinal?: number;
476
- }, ctx?: DispatchContext): {
476
+ }, ctx?: DispatchContext, opts?: {
477
+ dryRun?: boolean;
478
+ }): {
477
479
  appended: boolean;
478
480
  edge: Edge;
481
+ dryRun?: boolean;
482
+ };
483
+ /**
484
+ * Friendly-selector relation removal — the porcelain twin of
485
+ * {@link appendRelationByRef}. Resolves `parent` / `child` STRING selectors to
486
+ * structured `EdgeEndpoint`s via the SAME `resolveRelationSelector` the append
487
+ * porcelain uses, then delegates to the raw `removeRelation` plumbing, which
488
+ * matches on the `identityKey` dedup identity (so a `removeRelationByRef` of the
489
+ * selectors an `appendRelationByRef` wrote removes exactly that edge — the
490
+ * porcelain layers stay symmetric). Returns `{ removed, edge }` where `edge` is
491
+ * the RESOLVED structured edge that was matched against (so callers can report /
492
+ * dry-run-validate the structured form), and `removed` is false on the
493
+ * idempotent no-match no-op.
494
+ */
495
+ export declare function removeRelationByRef(cwd: string, rel: {
496
+ parent: string;
497
+ child: string;
498
+ relation_type: string;
499
+ }, ctx?: DispatchContext, opts?: {
500
+ dryRun?: boolean;
501
+ }): {
502
+ removed: boolean;
503
+ edge: Edge;
504
+ dryRun?: boolean;
505
+ };
506
+ /**
507
+ * Friendly-selector ATOMIC relation replace — a single load → filter-out-old →
508
+ * push-new → write cycle (no half-state: the old edge and the new edge never
509
+ * coexist on disk, and the file is rewritten exactly ONCE). Resolves the `old`
510
+ * and `new` selector triples via the SAME `resolveRelationSelector` the append /
511
+ * remove porcelain use. The old edge is matched on the `identityKey` dedup
512
+ * identity (parent, child, relation_type — `ordinal`-insensitive, symmetric with
513
+ * append-dedup / remove); the new edge is pushed verbatim (carrying its optional
514
+ * `ordinal`). If the resolved new edge collides on identity with a surviving edge
515
+ * it is de-duplicated against the post-filter set so the write stays
516
+ * exact-duplicate-free, matching `appendRelations` semantics.
517
+ *
518
+ * Returns `{ replaced, removed, oldEdge, newEdge }`: `removed` reflects whether
519
+ * the old edge was actually present (false → the old edge was absent, so this is
520
+ * effectively an append of `newEdge`); `replaced` is true when the resolved new
521
+ * edge was written (false only when it collided with an already-present surviving
522
+ * edge → a no-op add). `ctx` threads to `writeRelations` for attestation parity.
523
+ */
524
+ export declare function replaceRelationByRef(cwd: string, rels: {
525
+ old: {
526
+ parent: string;
527
+ child: string;
528
+ relation_type: string;
529
+ };
530
+ new: {
531
+ parent: string;
532
+ child: string;
533
+ relation_type: string;
534
+ ordinal?: number;
535
+ };
536
+ }, ctx?: DispatchContext, opts?: {
537
+ dryRun?: boolean;
538
+ }): {
539
+ replaced: boolean;
540
+ removed: boolean;
541
+ oldEdge: Edge;
542
+ newEdge: Edge;
543
+ dryRun?: boolean;
544
+ };
545
+ /**
546
+ * Friendly-selector BULK relation append over the raw {@link appendRelations}
547
+ * (whole-file additive write with per-(parent, child, relation_type) dedup,
548
+ * skipping edges already on disk OR earlier in the same batch). Resolves each
549
+ * `edges[]` selector triple via the SAME `resolveRelationSelector` the
550
+ * single-edge porcelain uses, then hands the resolved `Edge[]` to
551
+ * `appendRelations`. Returns `{ appended, skipped, edges }` — `edges` being the
552
+ * resolved structured edges handed to the raw layer (so callers can report /
553
+ * dry-run-validate the structured form). Same deferred-integrity semantics as
554
+ * `appendRelations` (AJV-shape + duplicate-no-op only; relation_type
555
+ * registration / endpoint resolution / cycle checks deferred to
556
+ * `validateContext`).
557
+ */
558
+ export declare function appendRelationsByRef(cwd: string, edges: {
559
+ parent: string;
560
+ child: string;
561
+ relation_type: string;
562
+ ordinal?: number;
563
+ }[], ctx?: DispatchContext, opts?: {
564
+ dryRun?: boolean;
565
+ }): {
566
+ appended: number;
567
+ skipped: number;
568
+ edges: Edge[];
569
+ dryRun?: boolean;
479
570
  };
480
571
  /**
481
572
  * Classification of an endpoint by {@link resolveRef}:
@@ -596,8 +687,12 @@ export interface CompleteTaskResult {
596
687
  }
597
688
  /**
598
689
  * Gate task completion on verification. Reads the verification block to confirm
599
- * a passing verification entry exists targeting this task, then atomically
600
- * updates the task status to "completed" with the verification cross-reference.
690
+ * a passing verification entry exists, asserts a `verification_verifies_item`
691
+ * closure-table edge links that verification (parent) to this task (child), then
692
+ * atomically updates the task status to "completed". The edge IS the linkage —
693
+ * no `verification` field is embedded on the task (the verification → task
694
+ * `verification.target`/`target_type` fields were removed from the verification
695
+ * schema in favor of the edge; this gate reads the edge, not the removed fields).
601
696
  */
602
- export declare function completeTask(cwd: string, taskId: string, verificationId: string): CompleteTaskResult;
697
+ export declare function completeTask(cwd: string, taskId: string, verificationId: string, ctx?: DispatchContext): CompleteTaskResult;
603
698
  //# sourceMappingURL=context-sdk.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-sdk.d.ts","sourceRoot":"","sources":["../src/context-sdk.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context-sdk.d.ts","sourceRoot":"","sources":["../src/context-sdk.ts"],"names":[],"mappings":"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"}
@@ -6,13 +6,16 @@
6
6
  import { execSync } from "node:child_process";
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
9
10
  import { readBlock, readBlockForDir, updateItemInBlock } from "./block-api.js";
10
- import { appendRelation, endpointKey, findUnmaterializedAssets, isSkeletonConfig, loadConfig, loadRelations, validateRelations, } from "./context.js";
11
+ import { appendRelation, appendRelations, endpointIdentity, endpointKey, findUnmaterializedAssets, isSkeletonConfig, loadConfig, loadRelations, removeRelation, validateRelations, writeRelations, } from "./context.js";
11
12
  import { resolveContextDir, SCHEMAS_DIR, schemaPath, schemasDir, tryResolveContextDir } from "./context-dir.js";
12
13
  import { loadRegistry, resolveAlias, resolveSubstrateDir } from "./context-registry.js";
13
14
  import { cleanGitEnv } from "./git-env.js";
14
15
  import { getLensValidators } from "./lens-validator.js";
16
+ import { findReferencesInRepo } from "./lens-view.js";
15
17
  import { addressInto, discoverArrayKey, pageArray } from "./read-element.js";
18
+ import { validateFromFile } from "./schema-validator.js";
16
19
  import { findNestedIdBearingArrays } from "./schema-write.js";
17
20
  import { resolveStatusVocabulary } from "./status-vocab.js";
18
21
  import { topoSort } from "./topo.js";
@@ -1111,6 +1114,25 @@ export function resolveRelationSelector(cwd, selector) {
1111
1114
  const oid = loc && typeof loc.item.oid === "string" ? loc.item.oid : selector;
1112
1115
  return { kind: "item", oid, refname: selector };
1113
1116
  }
1117
+ /**
1118
+ * Resolve the bundled relations schema file (top-level `Edge[]` array schema)
1119
+ * — the SAME schema `loadRelations` / `writeRelations` validate against (see
1120
+ * `context.ts` `bundledSchemaPath("relations")`). Resolved relative to this
1121
+ * module so it works from both `src/` (tsx --test) and `dist/` (after tsc) —
1122
+ * the `schemas/` dir lives one directory up in either case. Used by the
1123
+ * `dryRun` preview branch of the relation porcelain to apply the write path's
1124
+ * validation WITHOUT writing (TASK-010: the shared library preview the
1125
+ * orchestrator scripts and the `--dryRun` ops both call).
1126
+ */
1127
+ function relationsSchemaPath() {
1128
+ const here = path.dirname(fileURLToPath(import.meta.url));
1129
+ return path.resolve(here, "..", "schemas", "relations.schema.json");
1130
+ }
1131
+ /** Dedup identity key for an edge — the SAME (parent, child, relation_type)
1132
+ * identity the raw append/remove plumbing matches on (ordinal-insensitive). */
1133
+ function edgeIdentityKey(edge) {
1134
+ return `${endpointIdentity(edge.parent)} ${endpointIdentity(edge.child)} ${edge.relation_type}`;
1135
+ }
1114
1136
  /**
1115
1137
  * Friendly-selector relation append (Cycle 5 porcelain). Resolves `parent` /
1116
1138
  * `child` STRING selectors to structured `EdgeEndpoint`s via
@@ -1123,16 +1145,157 @@ export function resolveRelationSelector(cwd, selector) {
1123
1145
  * actually written (so callers can report / dry-run-validate the structured
1124
1146
  * form).
1125
1147
  */
1126
- export function appendRelationByRef(cwd, rel, ctx) {
1148
+ export function appendRelationByRef(cwd, rel, ctx, opts) {
1127
1149
  const edge = {
1128
1150
  parent: resolveRelationSelector(cwd, rel.parent),
1129
1151
  child: resolveRelationSelector(cwd, rel.child),
1130
1152
  relation_type: rel.relation_type,
1131
1153
  ...(rel.ordinal !== undefined ? { ordinal: rel.ordinal } : {}),
1132
1154
  };
1155
+ if (opts?.dryRun) {
1156
+ // Preview parity: run the SAME validation the write path applies (the
1157
+ // prospective Edge[] against the whole relations schema — what
1158
+ // loadRelations/writeRelations validate) but write nothing. The
1159
+ // would-decision uses the SAME dedup identity the raw append matches on.
1160
+ const existing = loadRelations(cwd);
1161
+ const prospective = [...existing, edge];
1162
+ validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
1163
+ const newId = edgeIdentityKey(edge);
1164
+ const duplicate = existing.some((e) => edgeIdentityKey(e) === newId);
1165
+ return { appended: !duplicate, edge, dryRun: true };
1166
+ }
1133
1167
  const { appended } = appendRelation(cwd, edge, ctx);
1134
1168
  return { appended, edge };
1135
1169
  }
1170
+ /**
1171
+ * Friendly-selector relation removal — the porcelain twin of
1172
+ * {@link appendRelationByRef}. Resolves `parent` / `child` STRING selectors to
1173
+ * structured `EdgeEndpoint`s via the SAME `resolveRelationSelector` the append
1174
+ * porcelain uses, then delegates to the raw `removeRelation` plumbing, which
1175
+ * matches on the `identityKey` dedup identity (so a `removeRelationByRef` of the
1176
+ * selectors an `appendRelationByRef` wrote removes exactly that edge — the
1177
+ * porcelain layers stay symmetric). Returns `{ removed, edge }` where `edge` is
1178
+ * the RESOLVED structured edge that was matched against (so callers can report /
1179
+ * dry-run-validate the structured form), and `removed` is false on the
1180
+ * idempotent no-match no-op.
1181
+ */
1182
+ export function removeRelationByRef(cwd, rel, ctx, opts) {
1183
+ const edge = {
1184
+ parent: resolveRelationSelector(cwd, rel.parent),
1185
+ child: resolveRelationSelector(cwd, rel.child),
1186
+ relation_type: rel.relation_type,
1187
+ };
1188
+ if (opts?.dryRun) {
1189
+ // Preview parity: compute the prospective post-removal Edge[] and validate
1190
+ // it against the whole relations schema (write-path validation), write
1191
+ // nothing. `removed` reflects whether a matching edge is present on the
1192
+ // SAME dedup identity the raw remove matches on.
1193
+ const existing = loadRelations(cwd);
1194
+ const targetId = edgeIdentityKey(edge);
1195
+ const matches = existing.some((e) => edgeIdentityKey(e) === targetId);
1196
+ const prospective = existing.filter((e) => edgeIdentityKey(e) !== targetId);
1197
+ validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
1198
+ return { removed: matches, edge, dryRun: true };
1199
+ }
1200
+ const { removed } = removeRelation(cwd, edge, ctx);
1201
+ return { removed, edge };
1202
+ }
1203
+ /**
1204
+ * Friendly-selector ATOMIC relation replace — a single load → filter-out-old →
1205
+ * push-new → write cycle (no half-state: the old edge and the new edge never
1206
+ * coexist on disk, and the file is rewritten exactly ONCE). Resolves the `old`
1207
+ * and `new` selector triples via the SAME `resolveRelationSelector` the append /
1208
+ * remove porcelain use. The old edge is matched on the `identityKey` dedup
1209
+ * identity (parent, child, relation_type — `ordinal`-insensitive, symmetric with
1210
+ * append-dedup / remove); the new edge is pushed verbatim (carrying its optional
1211
+ * `ordinal`). If the resolved new edge collides on identity with a surviving edge
1212
+ * it is de-duplicated against the post-filter set so the write stays
1213
+ * exact-duplicate-free, matching `appendRelations` semantics.
1214
+ *
1215
+ * Returns `{ replaced, removed, oldEdge, newEdge }`: `removed` reflects whether
1216
+ * the old edge was actually present (false → the old edge was absent, so this is
1217
+ * effectively an append of `newEdge`); `replaced` is true when the resolved new
1218
+ * edge was written (false only when it collided with an already-present surviving
1219
+ * edge → a no-op add). `ctx` threads to `writeRelations` for attestation parity.
1220
+ */
1221
+ export function replaceRelationByRef(cwd, rels, ctx, opts) {
1222
+ const oldEdge = {
1223
+ parent: resolveRelationSelector(cwd, rels.old.parent),
1224
+ child: resolveRelationSelector(cwd, rels.old.child),
1225
+ relation_type: rels.old.relation_type,
1226
+ };
1227
+ const newEdge = {
1228
+ parent: resolveRelationSelector(cwd, rels.new.parent),
1229
+ child: resolveRelationSelector(cwd, rels.new.child),
1230
+ relation_type: rels.new.relation_type,
1231
+ ...(rels.new.ordinal !== undefined ? { ordinal: rels.new.ordinal } : {}),
1232
+ };
1233
+ const existing = loadRelations(cwd);
1234
+ const oldKey = edgeIdentityKey(oldEdge);
1235
+ const newKey = edgeIdentityKey(newEdge);
1236
+ const filtered = existing.filter((e) => edgeIdentityKey(e) !== oldKey);
1237
+ const removed = filtered.length !== existing.length;
1238
+ const collides = filtered.some((e) => edgeIdentityKey(e) === newKey);
1239
+ const next = collides ? filtered : [...filtered, newEdge];
1240
+ if (opts?.dryRun) {
1241
+ // Preview parity: validate the prospective post-replace Edge[] against the
1242
+ // whole relations schema (write-path validation), write nothing. The
1243
+ // would-decisions (`removed`/`replaced`) are the SAME values the write
1244
+ // path computes.
1245
+ validateFromFile(relationsSchemaPath(), next, "relations[edge]");
1246
+ return { replaced: !collides, removed, oldEdge, newEdge, dryRun: true };
1247
+ }
1248
+ writeRelations(cwd, next, ctx);
1249
+ return { replaced: !collides, removed, oldEdge, newEdge };
1250
+ }
1251
+ /**
1252
+ * Friendly-selector BULK relation append over the raw {@link appendRelations}
1253
+ * (whole-file additive write with per-(parent, child, relation_type) dedup,
1254
+ * skipping edges already on disk OR earlier in the same batch). Resolves each
1255
+ * `edges[]` selector triple via the SAME `resolveRelationSelector` the
1256
+ * single-edge porcelain uses, then hands the resolved `Edge[]` to
1257
+ * `appendRelations`. Returns `{ appended, skipped, edges }` — `edges` being the
1258
+ * resolved structured edges handed to the raw layer (so callers can report /
1259
+ * dry-run-validate the structured form). Same deferred-integrity semantics as
1260
+ * `appendRelations` (AJV-shape + duplicate-no-op only; relation_type
1261
+ * registration / endpoint resolution / cycle checks deferred to
1262
+ * `validateContext`).
1263
+ */
1264
+ export function appendRelationsByRef(cwd, edges, ctx, opts) {
1265
+ const resolved = edges.map((rel) => ({
1266
+ parent: resolveRelationSelector(cwd, rel.parent),
1267
+ child: resolveRelationSelector(cwd, rel.child),
1268
+ relation_type: rel.relation_type,
1269
+ ...(rel.ordinal !== undefined ? { ordinal: rel.ordinal } : {}),
1270
+ }));
1271
+ if (opts?.dryRun) {
1272
+ // Preview parity: replay the bulk dedup the raw appendRelations applies —
1273
+ // skip an edge whose identity is already on disk OR earlier in THIS batch
1274
+ // (a `seen` Set seeded from the existing on-disk identities) — accumulate
1275
+ // the non-dup prospective Edge[], validate it against the whole relations
1276
+ // schema (write-path validation), write nothing.
1277
+ const existing = loadRelations(cwd);
1278
+ const seen = new Set(existing.map((e) => edgeIdentityKey(e)));
1279
+ let appended = 0;
1280
+ let skipped = 0;
1281
+ const prospective = [...existing];
1282
+ for (const edge of resolved) {
1283
+ const key = edgeIdentityKey(edge);
1284
+ if (seen.has(key)) {
1285
+ skipped++;
1286
+ }
1287
+ else {
1288
+ seen.add(key);
1289
+ prospective.push(edge);
1290
+ appended++;
1291
+ }
1292
+ }
1293
+ validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
1294
+ return { appended, skipped, edges: resolved, dryRun: true };
1295
+ }
1296
+ const { appended, skipped } = appendRelations(cwd, resolved, ctx);
1297
+ return { appended, skipped, edges: resolved };
1298
+ }
1136
1299
  /**
1137
1300
  * Build (or fetch from the per-pass cache) the {@link SubstrateIndex} for a
1138
1301
  * REGISTERED foreign substrate. Resolves the substrate dir from the registry,
@@ -1710,10 +1873,14 @@ export function validateContext(cwd) {
1710
1873
  }
1711
1874
  /**
1712
1875
  * Gate task completion on verification. Reads the verification block to confirm
1713
- * a passing verification entry exists targeting this task, then atomically
1714
- * updates the task status to "completed" with the verification cross-reference.
1876
+ * a passing verification entry exists, asserts a `verification_verifies_item`
1877
+ * closure-table edge links that verification (parent) to this task (child), then
1878
+ * atomically updates the task status to "completed". The edge IS the linkage —
1879
+ * no `verification` field is embedded on the task (the verification → task
1880
+ * `verification.target`/`target_type` fields were removed from the verification
1881
+ * schema in favor of the edge; this gate reads the edge, not the removed fields).
1715
1882
  */
1716
- export function completeTask(cwd, taskId, verificationId) {
1883
+ export function completeTask(cwd, taskId, verificationId, ctx) {
1717
1884
  // 1. Read and validate verification entry
1718
1885
  let verData;
1719
1886
  try {
@@ -1727,9 +1894,6 @@ export function completeTask(cwd, taskId, verificationId) {
1727
1894
  if (!verification) {
1728
1895
  throw new Error(`Verification '${verificationId}' not found in verification block`);
1729
1896
  }
1730
- if (verification.target !== taskId || verification.target_type !== "task") {
1731
- throw new Error(`Verification '${verificationId}' targets '${verification.target}' (${verification.target_type}), not task '${taskId}'`);
1732
- }
1733
1897
  if (verification.status !== "passed") {
1734
1898
  throw new Error(`Verification '${verificationId}' status is '${verification.status}', not 'passed' — cannot complete task`);
1735
1899
  }
@@ -1753,11 +1917,17 @@ export function completeTask(cwd, taskId, verificationId) {
1753
1917
  if (currentStatus === "cancelled") {
1754
1918
  throw new Error(`Task '${taskId}' is already cancelled`);
1755
1919
  }
1756
- // 3. Update task status with verification cross-reference
1757
- updateItemInBlock(cwd, "tasks", "tasks", (t) => t.id === taskId, {
1758
- status: "completed",
1759
- verification: verificationId,
1760
- });
1920
+ // 3. Assert the verification_verifies_item edge: verification (parent) →
1921
+ // task (child). The closure-table edge not a verification field — is the
1922
+ // canonical linkage. Inbound edges point AT the task; compare the parent
1923
+ // endpoint via endpointKey (the codebase's endpoint-comparison idiom).
1924
+ const verifiesEdge = findReferencesInRepo(cwd, taskId, "inbound").find((e) => e.relation_type === "verification_verifies_item" && endpointKey(e.parent) === verificationId);
1925
+ if (!verifiesEdge) {
1926
+ throw new Error(`verification '${verificationId}' does not verify task '${taskId}' — no verification_verifies_item edge; file the link (append-relation parent=${verificationId} child=${taskId} relation_type=verification_verifies_item) before completing`);
1927
+ }
1928
+ // 4. Update task status. The edge is the linkage — no `verification` field is
1929
+ // embedded (a populated additionalProperties:false tasks schema would reject it).
1930
+ updateItemInBlock(cwd, "tasks", "tasks", (t) => t.id === taskId, { status: "completed" }, ctx);
1761
1931
  return {
1762
1932
  taskId,
1763
1933
  verificationId,