@lwelliott/cortex-cli 1.0.5 → 1.0.6

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/dist/cli/index.js CHANGED
@@ -111,9 +111,11 @@ try {
111
111
  program.parse(process.argv);
112
112
  }
113
113
  catch (err) {
114
- // CommanderError is already output via writeErr interceptor — don't double-output
114
+ // CommanderError is already output via writeErr interceptor — don't double-output.
115
+ // commander.version: --version was requested — output already printed, exit cleanly.
115
116
  if (err instanceof Error && 'code' in err && typeof err.code === 'string' && err.code.startsWith('commander.')) {
116
- process.exit(1);
117
+ const exitCode = err.exitCode;
118
+ process.exit(exitCode && exitCode !== 0 ? exitCode : err.code === 'commander.version' ? 0 : 1);
117
119
  }
118
120
  if (err instanceof errors_1.CortexError) {
119
121
  const msg = err.message.replace(/^ERR-[A-Z]+-[0-9]+:\s*/, '');
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -89,7 +89,7 @@ export declare const RELATION_TYPES: readonly [{
89
89
  readonly description: "A requirement fulfills a user story (inverse of fulfilled_by)";
90
90
  }, {
91
91
  readonly name: "implemented_by";
92
- readonly from_types: readonly ["SAD", "AD", "QA"];
92
+ readonly from_types: readonly ["SAD", "AD", "QA", "TC"];
93
93
  readonly to_types: readonly ["SRC"];
94
94
  readonly cardinality: "many_to_many";
95
95
  readonly inverse_of: "implements";
@@ -97,7 +97,7 @@ export declare const RELATION_TYPES: readonly [{
97
97
  }, {
98
98
  readonly name: "implements";
99
99
  readonly from_types: readonly ["SRC"];
100
- readonly to_types: readonly ["SAD", "AD", "QA"];
100
+ readonly to_types: readonly ["SAD", "AD", "QA", "TC"];
101
101
  readonly cardinality: "many_to_many";
102
102
  readonly inverse_of: "implemented_by";
103
103
  readonly description: "Source code implements a design or QA artifact (inverse of implemented_by)";
@@ -21,8 +21,8 @@ exports.RELATION_TYPES = [
21
21
  { name: 'divided_into', from_types: ["TS"], to_types: ["TC"], cardinality: "one_to_many", inverse_of: "divided_from", description: "A test suite is divided into test cases (inverse of divided_from)" },
22
22
  { name: 'fulfilled_by', from_types: ["US"], to_types: ["FR", "NFR"], cardinality: "many_to_many", inverse_of: "fulfills", description: "A user story is fulfilled by functional or non-functional requirements (e.g., US-001 fulfilled by FR-001)" },
23
23
  { name: 'fulfills', from_types: ["FR", "NFR"], to_types: ["US"], cardinality: "many_to_many", inverse_of: "fulfilled_by", description: "A requirement fulfills a user story (inverse of fulfilled_by)" },
24
- { name: 'implemented_by', from_types: ["SAD", "AD", "QA"], to_types: ["SRC"], cardinality: "many_to_many", inverse_of: "implements", description: "A design or QA artifact is implemented by source code (e.g., SAD-0035 implemented by SRC-auth)" },
25
- { name: 'implements', from_types: ["SRC"], to_types: ["SAD", "AD", "QA"], cardinality: "many_to_many", inverse_of: "implemented_by", description: "Source code implements a design or QA artifact (inverse of implemented_by)" },
24
+ { name: 'implemented_by', from_types: ["SAD", "AD", "QA", "TC"], to_types: ["SRC"], cardinality: "many_to_many", inverse_of: "implements", description: "A design or QA artifact is implemented by source code (e.g., SAD-0035 implemented by SRC-auth)" },
25
+ { name: 'implements', from_types: ["SRC"], to_types: ["SAD", "AD", "QA", "TC"], cardinality: "many_to_many", inverse_of: "implemented_by", description: "Source code implements a design or QA artifact (inverse of implemented_by)" },
26
26
  { name: 'realized_by', from_types: ["FR", "NFR"], to_types: ["FS", "NFS"], cardinality: "many_to_many", inverse_of: "realizes", description: "A functional or non-functional requirement is realized by a functional or non-functional specification (e.g., FR-001 realized by FS-001, NFR-001 realized by NFS-001)" },
27
27
  { name: 'realizes', from_types: ["FS", "NFS"], to_types: ["FR", "NFR"], cardinality: "many_to_many", inverse_of: "realized_by", description: "A functional or non-functional specification realizes a functional or non-functional requirement (inverse of realized_by; e.g., FS-001 realizes FR-001, NFS-001 realizes NFR-001)" },
28
28
  { name: 'verified_by', from_types: ["FS", "NFS"], to_types: ["TS"], cardinality: "many_to_many", inverse_of: "verifies", description: "A specification is verified by a test suite (e.g., FS-001 verified by TS-033)" },
@@ -1 +1 @@
1
- {"version":3,"file":"schema-types.js","sourceRoot":"","sources":["../../../src/db/generated/schema-types.ts"],"names":[],"mappings":";AAAA,qDAAqD;AACrD,kGAAkG;;;AAElG;;;;GAIG;AACU,QAAA,cAAc,GAAG;IAC5B,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,sFAAsF,EAAE;IACnO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,sEAAsE,EAAE;IACnN,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAC,IAAI,EAAC,IAAI,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,4FAA4F,EAAE;IAC3O,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,KAAK,EAAC,IAAI,EAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,wEAAwE,EAAE;IACvN,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,IAAI,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,+FAA+F,EAAE;IACzO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,uEAAuE,EAAE;IACjN,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,mEAAmE,EAAE;IAC3M,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,yEAAyE,EAAE;IACjN,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,8EAA8E,EAAE;IACnN,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,mEAAmE,EAAE;IACxM,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,2GAA2G,EAAE;IACnP,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,+DAA+D,EAAE;IACvM,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,KAAK,EAAC,IAAI,EAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,gGAAgG,EAAE;IAClP,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAC,IAAI,EAAC,IAAI,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,4EAA4E,EAAE;IAC9N,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,uKAAuK,EAAE;IACpT,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,mLAAmL,EAAE;IAChU,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,+EAA+E,EAAE;IACtN,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAC,KAAK,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,gEAAgE,EAAE;CAC/L,CAAC"}
1
+ {"version":3,"file":"schema-types.js","sourceRoot":"","sources":["../../../src/db/generated/schema-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAe,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmB1F;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAM7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,QAAQ,CA6EV;AAsDD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAe9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,oBAAoB,GAAG,QAAQ,EAAE,CA+B/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,YAAY,EAAE,CAEvE"}
1
+ {"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAe,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAoB1F;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAM7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,QAAQ,CAgFV;AAsDD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAkB9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,oBAAoB,GAAG,QAAQ,EAAE,CA+B/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,YAAY,EAAE,CAEvE"}
@@ -2,6 +2,7 @@
2
2
  // Relation model: CRUD operations for graph relations
3
3
  // MOD-010: Relations with constraint enforcement (AD-0017)
4
4
  // + MOD-008: Schema dependency
5
+ // AD-0006: Advisory lock wrapping for write operations
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
7
  exports.getRelationType = getRelationType;
7
8
  exports.createRelation = createRelation;
@@ -9,6 +10,7 @@ exports.removeRelation = removeRelation;
9
10
  exports.queryRelations = queryRelations;
10
11
  exports.listRelationTypes = listRelationTypes;
11
12
  const retry_1 = require("../db/retry");
13
+ const locks_1 = require("../db/locks");
12
14
  const errors_1 = require("../utils/errors");
13
15
  /** Parse JSON field safely */
14
16
  function parseJson(raw, fallback) {
@@ -46,69 +48,72 @@ function getRelationType(db, name) {
46
48
  * 8. Insert inverse
47
49
  */
48
50
  function createRelation(db, fromId, relType, toId, properties) {
49
- return (0, retry_1.withTransaction)(db, () => {
50
- // 1. Self-relation check
51
- if (fromId === toId) {
52
- throw new errors_1.GraphSelfRelationError(fromId, relType);
53
- }
54
- // 2. Document existence (SAD-0035: entities table dropped, use documents)
55
- const fromDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(fromId);
56
- if (!fromDoc)
57
- throw new errors_1.GraphEntityNotFoundError(fromId);
58
- const toDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(toId);
59
- if (!toDoc)
60
- throw new errors_1.GraphEntityNotFoundError(toId);
61
- // 3. Relation type existence
62
- const rt = getRelationType(db, relType);
63
- if (!rt)
64
- throw new errors_1.GraphRelationTypeNotFoundError(relType);
65
- // 4. Type constraint check
66
- const fromTypes = parseJson(rt.from_types, []);
67
- const toTypes = parseJson(rt.to_types, []);
68
- if (fromTypes.length > 0 && !fromTypes.includes(fromDoc.type_name)) {
69
- throw new errors_1.GraphTypeConstraintError(relType, 'from', fromDoc.type_name, fromTypes);
70
- }
71
- if (toTypes.length > 0 && !toTypes.includes(toDoc.type_name)) {
72
- throw new errors_1.GraphTypeConstraintError(relType, 'to', toDoc.type_name, toTypes);
73
- }
74
- // 5. Cardinality constraint check
75
- enforceCardinality(db, rt, fromId, toId, relType);
76
- // 6. Duplicate check
77
- const existing = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(fromId, relType, toId);
78
- if (existing)
79
- throw new errors_1.GraphDuplicateRelationError(fromId, relType, toId);
80
- const now = new Date().toISOString();
81
- const propsJson = JSON.stringify(properties ?? {});
82
- // 7. Insert primary relation
83
- const result = db.prepare(`
84
- INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
85
- VALUES (?, ?, ?, ?, ?, ?)
86
- `).run(fromId, relType, toId, propsJson, now, now);
87
- const relation = {
88
- id: Number(result.lastInsertRowid),
89
- from_id: fromId,
90
- rel_type: relType,
91
- to_id: toId,
92
- properties: propsJson,
93
- created_at: now,
94
- updated_at: now,
95
- };
96
- // 8. Insert inverse relation if defined
97
- if (rt.inverse_of) {
98
- const inverseRt = getRelationType(db, rt.inverse_of);
99
- if (inverseRt) {
100
- // Check cardinality for inverse too
101
- enforceCardinality(db, inverseRt, toId, fromId, rt.inverse_of);
102
- const existingInverse = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(toId, rt.inverse_of, fromId);
103
- if (!existingInverse) {
104
- db.prepare(`
105
- INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
106
- VALUES (?, ?, ?, ?, ?, ?)
107
- `).run(toId, rt.inverse_of, fromId, propsJson, now, now);
51
+ const owner = (0, locks_1.generateLockOwner)();
52
+ return (0, locks_1.withLock)(db, { name: 'graph:mutations', owner }, () => {
53
+ return (0, retry_1.withTransaction)(db, () => {
54
+ // 1. Self-relation check
55
+ if (fromId === toId) {
56
+ throw new errors_1.GraphSelfRelationError(fromId, relType);
57
+ }
58
+ // 2. Document existence (SAD-0035: entities table dropped, use documents)
59
+ const fromDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(fromId);
60
+ if (!fromDoc)
61
+ throw new errors_1.GraphEntityNotFoundError(fromId);
62
+ const toDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(toId);
63
+ if (!toDoc)
64
+ throw new errors_1.GraphEntityNotFoundError(toId);
65
+ // 3. Relation type existence
66
+ const rt = getRelationType(db, relType);
67
+ if (!rt)
68
+ throw new errors_1.GraphRelationTypeNotFoundError(relType);
69
+ // 4. Type constraint check
70
+ const fromTypes = parseJson(rt.from_types, []);
71
+ const toTypes = parseJson(rt.to_types, []);
72
+ if (fromTypes.length > 0 && !fromTypes.includes(fromDoc.type_name)) {
73
+ throw new errors_1.GraphTypeConstraintError(relType, 'from', fromDoc.type_name, fromTypes);
74
+ }
75
+ if (toTypes.length > 0 && !toTypes.includes(toDoc.type_name)) {
76
+ throw new errors_1.GraphTypeConstraintError(relType, 'to', toDoc.type_name, toTypes);
77
+ }
78
+ // 5. Cardinality constraint check
79
+ enforceCardinality(db, rt, fromId, toId, relType);
80
+ // 6. Duplicate check
81
+ const existing = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(fromId, relType, toId);
82
+ if (existing)
83
+ throw new errors_1.GraphDuplicateRelationError(fromId, relType, toId);
84
+ const now = new Date().toISOString();
85
+ const propsJson = JSON.stringify(properties ?? {});
86
+ // 7. Insert primary relation
87
+ const result = db.prepare(`
88
+ INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
89
+ VALUES (?, ?, ?, ?, ?, ?)
90
+ `).run(fromId, relType, toId, propsJson, now, now);
91
+ const relation = {
92
+ id: Number(result.lastInsertRowid),
93
+ from_id: fromId,
94
+ rel_type: relType,
95
+ to_id: toId,
96
+ properties: propsJson,
97
+ created_at: now,
98
+ updated_at: now,
99
+ };
100
+ // 8. Insert inverse relation if defined
101
+ if (rt.inverse_of) {
102
+ const inverseRt = getRelationType(db, rt.inverse_of);
103
+ if (inverseRt) {
104
+ // Check cardinality for inverse too
105
+ enforceCardinality(db, inverseRt, toId, fromId, rt.inverse_of);
106
+ const existingInverse = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(toId, rt.inverse_of, fromId);
107
+ if (!existingInverse) {
108
+ db.prepare(`
109
+ INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
110
+ VALUES (?, ?, ?, ?, ?, ?)
111
+ `).run(toId, rt.inverse_of, fromId, propsJson, now, now);
112
+ }
108
113
  }
109
114
  }
110
- }
111
- return relation;
115
+ return relation;
116
+ });
112
117
  });
113
118
  }
114
119
  /**
@@ -152,18 +157,21 @@ function enforceCardinality(db, rt, fromId, toId, relType) {
152
157
  * Also removes any inverse relation.
153
158
  */
154
159
  function removeRelation(db, relationId) {
155
- (0, retry_1.withTransaction)(db, () => {
156
- const rel = db.prepare('SELECT from_id, rel_type, to_id FROM relations WHERE id = ?')
157
- .get(relationId);
158
- if (!rel)
159
- throw new errors_1.GraphRelationNotFoundError(relationId);
160
- db.prepare('DELETE FROM relations WHERE id = ?').run(relationId);
161
- // Remove inverse if defined
162
- const rt = getRelationType(db, rel.rel_type);
163
- if (rt?.inverse_of) {
164
- db.prepare('DELETE FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?')
165
- .run(rel.to_id, rt.inverse_of, rel.from_id);
166
- }
160
+ const owner = (0, locks_1.generateLockOwner)();
161
+ (0, locks_1.withLock)(db, { name: 'graph:mutations', owner }, () => {
162
+ (0, retry_1.withTransaction)(db, () => {
163
+ const rel = db.prepare('SELECT from_id, rel_type, to_id FROM relations WHERE id = ?')
164
+ .get(relationId);
165
+ if (!rel)
166
+ throw new errors_1.GraphRelationNotFoundError(relationId);
167
+ db.prepare('DELETE FROM relations WHERE id = ?').run(relationId);
168
+ // Remove inverse if defined
169
+ const rt = getRelationType(db, rel.rel_type);
170
+ if (rt?.inverse_of) {
171
+ db.prepare('DELETE FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?')
172
+ .run(rel.to_id, rt.inverse_of, rel.from_id);
173
+ }
174
+ });
167
175
  });
168
176
  }
169
177
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type Database from 'better-sqlite3';
2
2
  import type { Document, DocumentDetail, DocumentRegisterOptions, DocumentUpdateFields, SearchResult, ListOptions, SearchOptions } from '../models/document';
3
3
  /**
4
4
  * Register a new document.
5
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
5
6
  */
6
7
  export declare function registerDocument(db: Database.Database, id: string, type: string, title: string, opts?: DocumentRegisterOptions): Document;
7
8
  /**
@@ -25,6 +26,7 @@ export declare function getDocument(db: Database.Database, id: string): Document
25
26
  export declare function showDocument(db: Database.Database, id: string): DocumentDetail;
26
27
  /**
27
28
  * Update document metadata.
29
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
28
30
  * --meta replaces entirely (not merge), per spec.
29
31
  *
30
32
  * MOD-021: When fields.type changes the document type, the old entity is deleted
@@ -35,6 +37,7 @@ export declare function showDocument(db: Database.Database, id: string): Documen
35
37
  export declare function updateDocument(db: Database.Database, id: string, fields: DocumentUpdateFields): Document;
36
38
  /**
37
39
  * Remove a document registration.
40
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
38
41
  *
39
42
  * Deletion ordering per SAD-0035 (3-step sequence after entities table drop):
40
43
  * Step 1: Delete relations (outgoing and incoming) referencing the document
@@ -1 +1 @@
1
- {"version":3,"file":"document-service.d.ts","sourceRoot":"","sources":["../../src/services/document-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAmC5J;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,uBAAuB,GAC7B,QAAQ,CAmEV;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,CAAC,EAAE,WAAW,GACjB,QAAQ,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAkDhC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,CAkB9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,oBAAoB,GAC3B,QAAQ,CAmEV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAetE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,GACnB,YAAY,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgIpC"}
1
+ {"version":3,"file":"document-service.d.ts","sourceRoot":"","sources":["../../src/services/document-service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAoC5J;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,uBAAuB,GAC7B,QAAQ,CA8DV;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,CAAC,EAAE,WAAW,GACjB,QAAQ,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAkDhC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,CAkB9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,oBAAoB,GAC3B,QAAQ,CAiEV;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAgBtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,GACnB,YAAY,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgIpC"}
@@ -3,6 +3,7 @@
3
3
  // SAD-0003: MOD-012 Document Registry & Content
4
4
  // AD-0018: FTS5 with trigger-based index
5
5
  // AD-0019: Dual-mode document storage
6
+ // AD-0006: Advisory lock wrapping for multi-step write operations
6
7
  // SAD-0035: Entity auto-sync removed — entities table dropped
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  exports.registerDocument = registerDocument;
@@ -16,6 +17,7 @@ const crypto_1 = require("crypto");
16
17
  const fs_1 = require("fs");
17
18
  const errors_1 = require("../utils/errors");
18
19
  const retry_1 = require("../db/retry");
20
+ const locks_1 = require("../db/locks");
19
21
  // ─── Order-by validation ───
20
22
  const VALID_ORDER_FIELDS = ['id', 'type', 'title', 'created', 'updated'];
21
23
  function parseOrderBy(raw) {
@@ -41,6 +43,7 @@ function sha256(content) {
41
43
  // ─── Public API ───
42
44
  /**
43
45
  * Register a new document.
46
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
44
47
  */
45
48
  function registerDocument(db, id, type, title, opts) {
46
49
  if (!id || !id.trim())
@@ -49,25 +52,13 @@ function registerDocument(db, id, type, title, opts) {
49
52
  throw new errors_1.DocumentMissingFieldError('type');
50
53
  if (!title || !title.trim())
51
54
  throw new errors_1.DocumentMissingFieldError('title');
52
- // Check duplicate
53
- const existing = db.prepare('SELECT id FROM documents WHERE id = ?').get(id);
54
- if (existing)
55
- throw new errors_1.DocumentDuplicateError(id);
56
- // Pre-transaction doc type validation gate (FS-SS-012-0011, SAD-0027 §5)
57
- // builtin:3.0: doc type IS entity type name (no mapping needed)
58
55
  // Pre-transaction SRC storage enforcement (FS-SS-029-0001 v2 VR-001/VR-002)
59
56
  // SRC documents must use filesystem storage; DB storage via --content-file is rejected
60
57
  if (type === 'SRC' && (opts?.content || opts?.contentFile)) {
61
58
  throw new errors_1.DocSrcStorageError();
62
59
  }
63
- // FS-SS-012-0001 v4 VR-004: When content is provided (via --content-file),
64
- // content_storage defaults to 'db'. Otherwise defaults to 'filesystem'.
65
- const storage = opts?.contentStorage ?? ((opts?.content || opts?.contentFile) ? 'db' : 'filesystem');
66
- const metadata = opts?.metadata ? JSON.stringify(opts.metadata) : '{}';
67
- const now = new Date().toISOString();
60
+ // Pre-transaction file read (fail fast before lock acquisition)
68
61
  // Handle content: compute hash and load content from file or direct input
69
- // Content is ALWAYS stored in document_contents to enable FTS5 indexing,
70
- // regardless of whether content_storage is 'db' or 'filesystem'.
71
62
  let contentHash = null;
72
63
  let contentValue = null;
73
64
  let contentFilePath = null;
@@ -87,19 +78,27 @@ function registerDocument(db, id, type, title, opts) {
87
78
  throw new errors_1.DocumentFileError(opts.contentFile, msg);
88
79
  }
89
80
  }
90
- // Determine the filesystem path to store in the documents table.
91
- // Prefer the explicit --path option; fall back to --content-file path.
81
+ const storage = opts?.contentStorage ?? ((opts?.content || opts?.contentFile) ? 'db' : 'filesystem');
82
+ const metadata = opts?.metadata ? JSON.stringify(opts.metadata) : '{}';
92
83
  const storedPath = opts?.path ?? contentFilePath ?? null;
93
- // Insert document and content (FK: document_contents → documents)
94
- // SAD-0035: Entity auto-creation removed entities table dropped
95
- (0, retry_1.withTransaction)(db, () => {
96
- db.prepare(`INSERT INTO documents (id, type, title, path, content_hash, content_storage, metadata, created_at, updated_at)
97
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, type, title, storedPath, contentHash, storage, metadata, now, now);
98
- if (contentValue !== null) {
99
- db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at) VALUES (?, ?, ?, ?)`).run(id, contentValue, contentHash, now);
100
- }
84
+ const owner = (0, locks_1.generateLockOwner)();
85
+ return (0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
86
+ // Check duplicate inside lock to prevent TOCTOU races
87
+ const existing = db.prepare('SELECT id FROM documents WHERE id = ?').get(id);
88
+ if (existing)
89
+ throw new errors_1.DocumentDuplicateError(id);
90
+ const now = new Date().toISOString();
91
+ // Insert document and content (FK: document_contents → documents)
92
+ // SAD-0035: Entity auto-creation removed — entities table dropped
93
+ (0, retry_1.withTransaction)(db, () => {
94
+ db.prepare(`INSERT INTO documents (id, type, title, path, content_hash, content_storage, metadata, created_at, updated_at)
95
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, type, title, storedPath, contentHash, storage, metadata, now, now);
96
+ if (contentValue !== null) {
97
+ db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at) VALUES (?, ?, ?, ?)`).run(id, contentValue, contentHash, now);
98
+ }
99
+ });
100
+ return getDocument(db, id);
101
101
  });
102
- return getDocument(db, id);
103
102
  }
104
103
  /**
105
104
  * List documents with optional filters, pagination, sorting, and count-only support.
@@ -190,6 +189,7 @@ function showDocument(db, id) {
190
189
  }
191
190
  /**
192
191
  * Update document metadata.
192
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
193
193
  * --meta replaces entirely (not merge), per spec.
194
194
  *
195
195
  * MOD-021: When fields.type changes the document type, the old entity is deleted
@@ -198,29 +198,10 @@ function showDocument(db, id) {
198
198
  * atomic transaction per FS-SS-021-0004.
199
199
  */
200
200
  function updateDocument(db, id, fields) {
201
+ // Pre-lock validation
201
202
  const doc = getDocument(db, id);
202
- const now = new Date().toISOString();
203
- const sets = ['updated_at = ?'];
204
- const params = [now];
205
- if (fields.title !== undefined) {
206
- sets.push('title = ?');
207
- params.push(fields.title);
208
- }
209
- if (fields.type !== undefined) {
210
- sets.push('type = ?');
211
- params.push(fields.type);
212
- }
213
- if (fields.metadata !== undefined) {
214
- sets.push('metadata = ?');
215
- params.push(JSON.stringify(fields.metadata));
216
- }
217
- if (fields.content_storage !== undefined) {
218
- sets.push('content_storage = ?');
219
- params.push(fields.content_storage);
220
- }
221
- // Handle content update
203
+ // Handle content file read before lock acquisition (fail fast)
222
204
  let newContent;
223
- let contentHash;
224
205
  if (fields.contentFile) {
225
206
  try {
226
207
  newContent = (0, fs_1.readFileSync)(fields.contentFile, 'utf-8');
@@ -233,39 +214,58 @@ function updateDocument(db, id, fields) {
233
214
  else if (fields.content !== undefined) {
234
215
  newContent = fields.content;
235
216
  }
236
- if (newContent !== undefined) {
237
- contentHash = sha256(newContent);
238
- sets.push('content_hash = ?');
239
- params.push(contentHash);
240
- }
241
- // SAD-0035: Entity sync on type change removed — entities table dropped
242
217
  // content_storage switch validation (FR-URD-G001-0001 M6)
243
- // Switching from filesystem to db without providing content creates an
244
- // inconsistency: the document_contents table has no authoritative copy.
245
218
  if (fields.content_storage !== undefined && fields.content_storage !== doc.content_storage) {
246
219
  if (fields.content_storage === 'db' && doc.content_storage === 'filesystem' && newContent === undefined && !fields.contentFile) {
247
220
  throw new errors_1.DocumentMissingFieldError('content');
248
221
  }
249
222
  }
250
- params.push(id);
251
- // Single atomic transaction: content upsert + document update
252
- // SAD-0035: Entity sync removed — entities table dropped
253
- (0, retry_1.withTransaction)(db, () => {
254
- // Step 1: Content upsert
255
- // Content is ALWAYS written to document_contents to enable FTS5 indexing
256
- // and maintain content_hash consistency, regardless of storage type.
223
+ const owner = (0, locks_1.generateLockOwner)();
224
+ return (0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
225
+ const now = new Date().toISOString();
226
+ const sets = ['updated_at = ?'];
227
+ const params = [now];
228
+ if (fields.title !== undefined) {
229
+ sets.push('title = ?');
230
+ params.push(fields.title);
231
+ }
232
+ if (fields.type !== undefined) {
233
+ sets.push('type = ?');
234
+ params.push(fields.type);
235
+ }
236
+ if (fields.metadata !== undefined) {
237
+ sets.push('metadata = ?');
238
+ params.push(JSON.stringify(fields.metadata));
239
+ }
240
+ if (fields.content_storage !== undefined) {
241
+ sets.push('content_storage = ?');
242
+ params.push(fields.content_storage);
243
+ }
244
+ let contentHash;
257
245
  if (newContent !== undefined) {
258
- db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at)
259
- VALUES (?, ?, ?, ?)
260
- ON CONFLICT(document_id) DO UPDATE SET content = excluded.content, content_hash = excluded.content_hash, updated_at = excluded.updated_at`).run(id, newContent, contentHash, now);
246
+ contentHash = sha256(newContent);
247
+ sets.push('content_hash = ?');
248
+ params.push(contentHash);
261
249
  }
262
- // Step 2: Document row UPDATE
263
- db.prepare(`UPDATE documents SET ${sets.join(', ')} WHERE id = ?`).run(...params);
250
+ params.push(id);
251
+ // Single atomic transaction: content upsert + document update
252
+ // SAD-0035: Entity sync removed — entities table dropped
253
+ (0, retry_1.withTransaction)(db, () => {
254
+ // Step 1: Content upsert
255
+ if (newContent !== undefined) {
256
+ db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at)
257
+ VALUES (?, ?, ?, ?)
258
+ ON CONFLICT(document_id) DO UPDATE SET content = excluded.content, content_hash = excluded.content_hash, updated_at = excluded.updated_at`).run(id, newContent, contentHash, now);
259
+ }
260
+ // Step 2: Document row UPDATE
261
+ db.prepare(`UPDATE documents SET ${sets.join(', ')} WHERE id = ?`).run(...params);
262
+ });
263
+ return getDocument(db, id);
264
264
  });
265
- return getDocument(db, id);
266
265
  }
267
266
  /**
268
267
  * Remove a document registration.
268
+ * Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
269
269
  *
270
270
  * Deletion ordering per SAD-0035 (3-step sequence after entities table drop):
271
271
  * Step 1: Delete relations (outgoing and incoming) referencing the document
@@ -276,16 +276,17 @@ function updateDocument(db, id, fields) {
276
276
  * Content is always deleted unconditionally per AD-0028 — there is no soft-delete option.
277
277
  */
278
278
  function removeDocument(db, id) {
279
- getDocument(db, id); // verify exists
280
- (0, retry_1.withTransaction)(db, () => {
281
- // Step 1: Delete all relations referencing this document (from_id OR to_id)
282
- db.prepare('DELETE FROM relations WHERE from_id = ? OR to_id = ?').run(id, id);
283
- // Step 2: Delete document_contents unconditionally per AD-0028
284
- // FK constraint (document_contents.document_id documents.id) requires
285
- // content deletion before the document row is removed.
286
- db.prepare('DELETE FROM document_contents WHERE document_id = ?').run(id);
287
- // Step 3: Delete document row
288
- db.prepare('DELETE FROM documents WHERE id = ?').run(id);
279
+ getDocument(db, id); // verify exists before lock
280
+ const owner = (0, locks_1.generateLockOwner)();
281
+ (0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
282
+ (0, retry_1.withTransaction)(db, () => {
283
+ // Step 1: Delete all relations referencing this document (from_id OR to_id)
284
+ db.prepare('DELETE FROM relations WHERE from_id = ? OR to_id = ?').run(id, id);
285
+ // Step 2: Delete document_contents unconditionally per AD-0028
286
+ db.prepare('DELETE FROM document_contents WHERE document_id = ?').run(id);
287
+ // Step 3: Delete document row
288
+ db.prepare('DELETE FROM documents WHERE id = ?').run(id);
289
+ });
289
290
  });
290
291
  }
291
292
  /**