@smartmemory/compose 0.3.5-beta → 0.3.6-beta

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.
Files changed (76) hide show
  1. package/bin/judgment-import.js +565 -0
  2. package/contracts/judgment-record.schema.json +400 -0
  3. package/dist/assets/{App-BG92y_CY.js → App-BG3ngu8H.js} +92 -92
  4. package/dist/assets/{abnfDiagram-VRR7QNED-Bip6cMjP.js → abnfDiagram-VRR7QNED-CjB_sD3D.js} +1 -1
  5. package/dist/assets/{arc-CyMTM07c.js → arc-_v4hR_uD.js} +1 -1
  6. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BukV0CJw.js → architectureDiagram-ZJ3FMSHR-DreJmzXQ.js} +1 -1
  7. package/dist/assets/{blockDiagram-677ZJIJ3-Bjb_MNB4.js → blockDiagram-677ZJIJ3-BG9-c0O1.js} +1 -1
  8. package/dist/assets/{c4Diagram-LMCZKHZV-CUmTCrMW.js → c4Diagram-LMCZKHZV-DZf45Fbz.js} +1 -1
  9. package/dist/assets/channel-B3U5wFAT.js +1 -0
  10. package/dist/assets/{chunk-2Q5K7J3B-Cyvi1AFH.js → chunk-2Q5K7J3B-Dn1spZYu.js} +1 -1
  11. package/dist/assets/{chunk-32BRIVSS-B1y5FpOd.js → chunk-32BRIVSS-pURGrJDk.js} +1 -1
  12. package/dist/assets/{chunk-5VM5RSS4-Qw-L7OoJ.js → chunk-5VM5RSS4-BY4_PV5H.js} +1 -1
  13. package/dist/assets/{chunk-EX3LRPZG-G_MZEji_.js → chunk-EX3LRPZG-DdELs1qP.js} +1 -1
  14. package/dist/assets/{chunk-JWPE2WC7-DQFs7gjy.js → chunk-JWPE2WC7-_7ujgd_Q.js} +1 -1
  15. package/dist/assets/{chunk-MOJQB5TN-CQZQYMcz.js → chunk-MOJQB5TN-D-ky35G-.js} +1 -1
  16. package/dist/assets/{chunk-RYQCIY6F-CmAda4sZ.js → chunk-RYQCIY6F-Dag_kVlO.js} +1 -1
  17. package/dist/assets/{chunk-V7JOEXUC-CbjBz-Ek.js → chunk-V7JOEXUC-BtewURat.js} +1 -1
  18. package/dist/assets/{chunk-VR4S4FIN-Dvhgnm7E.js → chunk-VR4S4FIN-Dt9NZ67m.js} +1 -1
  19. package/dist/assets/{chunk-XXDRQBXY-CSdt06Hp.js → chunk-XXDRQBXY-DfdVhbmA.js} +1 -1
  20. package/dist/assets/classDiagram-OUVF2IWQ-B6fCN-ht.js +1 -0
  21. package/dist/assets/classDiagram-v2-EOCWNBFH-B6fCN-ht.js +1 -0
  22. package/dist/assets/{cose-bilkent-JH36ORCC-G8l05tXy.js → cose-bilkent-JH36ORCC-BieYif4o.js} +1 -1
  23. package/dist/assets/{cynefin-VYW2F7L2-C3n1PNJC.js → cynefin-VYW2F7L2-CT2BA6KE.js} +1 -1
  24. package/dist/assets/{cynefinDiagram-TSTJHNR4-C8N_CvKJ.js → cynefinDiagram-TSTJHNR4-Bh6exbyg.js} +1 -1
  25. package/dist/assets/{dagre-VKFMJZFB-B2pkwDhN.js → dagre-VKFMJZFB-aXMLSmQL.js} +1 -1
  26. package/dist/assets/{diagram-FQU43EPY-DPHD_t-1.js → diagram-FQU43EPY-Dr7JAOuQ.js} +1 -1
  27. package/dist/assets/{diagram-G47NLZAW-DGmHIZRr.js → diagram-G47NLZAW-DUvA3FQK.js} +1 -1
  28. package/dist/assets/{diagram-NH7WQ7WH-BlLWwKVt.js → diagram-NH7WQ7WH-BQUARqcu.js} +1 -1
  29. package/dist/assets/{diagram-OA4YK3LP-DEv704Re.js → diagram-OA4YK3LP-dDUc1zHi.js} +1 -1
  30. package/dist/assets/{diagram-WEI45ONY-Bj6PGUCe.js → diagram-WEI45ONY-B2h5Qlb1.js} +1 -1
  31. package/dist/assets/{ebnfDiagram-CCIWWBDH-Ch-icksT.js → ebnfDiagram-CCIWWBDH-DThRGupB.js} +1 -1
  32. package/dist/assets/{erDiagram-Q63AITRT-CI3lwEFA.js → erDiagram-Q63AITRT-BUCsprO2.js} +1 -1
  33. package/dist/assets/{flowDiagram-23GEKE2U-DcUANpAz.js → flowDiagram-23GEKE2U-DXtNNi6r.js} +1 -1
  34. package/dist/assets/{ganttDiagram-NO4QXBWP-Cy0Ie8KS.js → ganttDiagram-NO4QXBWP-D4zbBHh_.js} +1 -1
  35. package/dist/assets/{gitGraphDiagram-IHSO6WYX-BswI52az.js → gitGraphDiagram-IHSO6WYX-DpoQws0W.js} +1 -1
  36. package/dist/assets/{index-B1H7-G2y.js → index-3ZH5eMcZ.js} +2 -2
  37. package/dist/assets/{infoDiagram-FWYZ7A6U-BBunqvr-.js → infoDiagram-FWYZ7A6U-Bbas2GAo.js} +1 -1
  38. package/dist/assets/{ishikawaDiagram-FXEZZL3T-Hm4zSDlM.js → ishikawaDiagram-FXEZZL3T-CzEB9fQS.js} +1 -1
  39. package/dist/assets/{journeyDiagram-5HDEW3XC-CIqcTFuO.js → journeyDiagram-5HDEW3XC-Bz8TCdz2.js} +1 -1
  40. package/dist/assets/{kanban-definition-HUTT4EX6-CB9jCXj_.js → kanban-definition-HUTT4EX6-tozrMoV_.js} +1 -1
  41. package/dist/assets/{linear-CsXqv70E.js → linear-Ck7gpa5N.js} +1 -1
  42. package/dist/assets/{mindmap-definition-LN4V7U3C-CpqH5F_P.js → mindmap-definition-LN4V7U3C-DTcHO0DJ.js} +1 -1
  43. package/dist/assets/{pegDiagram-2B236MQR-HpQyrDcm.js → pegDiagram-2B236MQR-CHiINrNy.js} +1 -1
  44. package/dist/assets/{pieDiagram-ENE6RG2P-xkcpHwnY.js → pieDiagram-ENE6RG2P-CfS4YFlR.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-ABIIQ3AL-kebZIOmu.js → quadrantDiagram-ABIIQ3AL-CadesS9w.js} +1 -1
  46. package/dist/assets/{railroadDiagram-RFXS5EU6-DNvGwWm9.js → railroadDiagram-RFXS5EU6-CgWEspBN.js} +1 -1
  47. package/dist/assets/{requirementDiagram-TGXJPOKE-D1lG1P7h.js → requirementDiagram-TGXJPOKE-bnI2zJeT.js} +1 -1
  48. package/dist/assets/{sankeyDiagram-HTMAVEWB-DOEEcn52.js → sankeyDiagram-HTMAVEWB-YWKFgOGw.js} +1 -1
  49. package/dist/assets/{sequenceDiagram-DBY2YBRQ-DynIVCk_.js → sequenceDiagram-DBY2YBRQ-BvkNOyF9.js} +1 -1
  50. package/dist/assets/{sizeCapture-X5ZJPWSS-DJXFjUUL.js → sizeCapture-X5ZJPWSS-DlFPA2yO.js} +1 -1
  51. package/dist/assets/{stateDiagram-2N3HPSRC-OZ7trFh5.js → stateDiagram-2N3HPSRC-h8NIx0kQ.js} +1 -1
  52. package/dist/assets/stateDiagram-v2-6OUMAXLB-DjPgZtJ9.js +1 -0
  53. package/dist/assets/{swimlanes-5IMT3BWC-DULYAFmB.js → swimlanes-5IMT3BWC-CT5n22kG.js} +2 -2
  54. package/dist/assets/swimlanesDiagram-G3AALYLV-Dn318Bhq.js +8 -0
  55. package/dist/assets/{timeline-definition-FHXFAJF6-CzqqUDvt.js → timeline-definition-FHXFAJF6-D267GQFF.js} +1 -1
  56. package/dist/assets/{vennDiagram-L72KCM5P-CdKmtcFL.js → vennDiagram-L72KCM5P-Dj-wWLYG.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-EHGQE667-DknGwjCA.js → wardleyDiagram-EHGQE667-BxCeYxkG.js} +1 -1
  58. package/dist/assets/{xychartDiagram-FW5EYKEG-DdYyKfQ3.js → xychartDiagram-FW5EYKEG-DMFqWn7z.js} +1 -1
  59. package/dist/index.html +1 -1
  60. package/lib/idempotency.js +33 -8
  61. package/lib/judgment/schema.js +23 -0
  62. package/lib/judgment/store/index.js +49 -0
  63. package/lib/judgment/store/records.js +246 -0
  64. package/lib/judgment-gen.js +342 -0
  65. package/lib/judgment-write-guard.js +230 -0
  66. package/lib/judgment-writer.js +877 -0
  67. package/lib/lifecycle-modes.js +42 -0
  68. package/package.json +1 -1
  69. package/server/compose-mcp-tools.js +34 -0
  70. package/server/compose-mcp.js +125 -0
  71. package/server/mcp-tool-policy.js +1 -0
  72. package/dist/assets/channel-BzkmtaLy.js +0 -1
  73. package/dist/assets/classDiagram-OUVF2IWQ-BIvLcbex.js +0 -1
  74. package/dist/assets/classDiagram-v2-EOCWNBFH-BIvLcbex.js +0 -1
  75. package/dist/assets/stateDiagram-v2-6OUMAXLB-GcPRHAJT.js +0 -1
  76. package/dist/assets/swimlanesDiagram-G3AALYLV-BB0gCy01.js +0 -8
@@ -0,0 +1,230 @@
1
+ /**
2
+ * lib/judgment-write-guard.js — write-time judgment-record validation (S03).
3
+ *
4
+ * Pure leaf validator in the feature-write-guard shape: schema conformance,
5
+ * grounding/elicitation rules, the design's edge→artifact table, and the
6
+ * method gates. The writer (lib/judgment-writer.js) and MCP surface call
7
+ * into this module; it never imports them — imports are restricted to the
8
+ * Ajv SchemaValidator and the judgment schema loader so the graph stays
9
+ * acyclic (the feature-write-guard.js:20-23 discipline).
10
+ *
11
+ * Rules enforced here (design.md rev 5):
12
+ * - every record validates against contracts/judgment-record.schema.json
13
+ * (MCP inputSchema is advisory, never the enforcement)
14
+ * - grounding: ASSERT requires a structured elicitation block
15
+ * - [owner-locked] is unrepresentable through tools — import or the epic's
16
+ * future override only
17
+ * - every transition edge carries its bound artifact or is refused; there
18
+ * is no free under_test→open edge; dissolution is its own artifact
19
+ * - EXT needs sharpened-or-judgment-dispatch before under_test; STRADDLE
20
+ * needs signal+kill-criteria; a SILENT ext result may only yield the
21
+ * joint outcome `inconclusive`
22
+ */
23
+ import { getJudgmentValidator } from './judgment/schema.js';
24
+
25
+ export class JudgmentWriteValidationError extends Error {
26
+ /**
27
+ * @param {'JUDGMENT_SCHEMA_VIOLATION'|'JUDGMENT_GROUNDING_VIOLATION'|'JUDGMENT_ILLEGAL_EDGE'|'JUDGMENT_METHOD_GATE'} kind
28
+ * @param {string[]} violations
29
+ */
30
+ constructor(kind, violations) {
31
+ super(`${kind}: ${violations.join('; ')}`);
32
+ this.name = 'JudgmentWriteValidationError';
33
+ this.code = kind;
34
+ this.kind = kind;
35
+ this.violations = violations;
36
+ }
37
+ }
38
+
39
+ function refuse(kind, violations) {
40
+ throw new JudgmentWriteValidationError(kind, violations);
41
+ }
42
+
43
+ /**
44
+ * Validate a record against its contract definition. Throws
45
+ * JUDGMENT_SCHEMA_VIOLATION with ajv error paths on mismatch.
46
+ *
47
+ * @param {'position_revision'|'joint'|'prediction'|'ledger_event'|'pending_intent'} defName
48
+ * @param {object} record
49
+ */
50
+ export function assertValidRecord(defName, record) {
51
+ const { valid, errors } = getJudgmentValidator().validate(defName, record);
52
+ if (valid) return;
53
+ refuse(
54
+ 'JUDGMENT_SCHEMA_VIOLATION',
55
+ (errors || []).map((e) => `${defName}${e.instancePath || ''}: ${e.message}`),
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Grounding rules over a record's claims (position revisions; any record
61
+ * carrying `claims[]`). `via: 'import'` — taken from opts or the record's own
62
+ * provenance — is the only sanctioned owner-tag path in v1.
63
+ *
64
+ * @param {object} record
65
+ * @param {{ via?: 'import' }} [opts]
66
+ */
67
+ export function assertGrounding(record, opts = {}) {
68
+ const via = opts.via ?? record?.provenance?.via;
69
+ const violations = [];
70
+ for (const claim of (Array.isArray(record?.claims) ? record.claims : [])) {
71
+ if (claim.grounding === 'ASSERT' && !claim.elicitation) {
72
+ violations.push(
73
+ `claim ${claim.id}: grounding ASSERT requires an elicitation block { asked, answered_at, answer_ref } (assert-elicitation-amendment)`,
74
+ );
75
+ }
76
+ if (claim.owner_locked === true && via !== 'import') {
77
+ violations.push(
78
+ `claim ${claim.id}: [owner-locked] is unrepresentable through tools — use the importer (via: 'import') or the epic's future override`,
79
+ );
80
+ }
81
+ }
82
+ if (violations.length > 0) refuse('JUDGMENT_GROUNDING_VIOLATION', violations);
83
+ }
84
+
85
+ /**
86
+ * The design's edge→artifact table, verbatim. Each legal edge names the
87
+ * exactly-one artifact the transition input must carry; anything else is
88
+ * refused. Keys are `${from}→${to}`.
89
+ *
90
+ * @type {Record<string, (input: object) => string|null>}
91
+ * returns a violation string or null when satisfied
92
+ */
93
+ const EDGE_TABLE = {
94
+ 'open→under_test': () => null, // method gate enforced by assertMethodGate
95
+ 'under_test→resolved': (input) =>
96
+ input?.resolution?.outcome === 'resolved'
97
+ ? null
98
+ : 'requires resolution { outcome: resolved, evidence }',
99
+ 'under_test→inconclusive': (input) =>
100
+ input?.resolution?.outcome === 'inconclusive'
101
+ ? null
102
+ : 'requires resolution { outcome: inconclusive, learned, would_have_settled }',
103
+ 'under_test→open': (input) =>
104
+ input?.resolution?.outcome === 'failed_to_run'
105
+ ? null
106
+ : 'a free under_test→open edge does not exist — requires resolution { outcome: failed_to_run, reason }',
107
+ 'open→superseded': (input) =>
108
+ input?.resolution?.outcome === 'superseded'
109
+ ? null
110
+ : 'requires resolution { outcome: superseded, why }',
111
+ 'under_test→superseded': (input) =>
112
+ input?.resolution?.outcome === 'superseded'
113
+ ? null
114
+ : 'requires resolution { outcome: superseded, why }',
115
+ 'open→dissolved': (input) =>
116
+ input?.dissolution && !input?.resolution
117
+ ? null
118
+ : 'requires dissolution { decomposed_into[] } — its own artifact, not a resolution',
119
+ 'under_test→dissolved': (input) =>
120
+ input?.dissolution && !input?.resolution
121
+ ? null
122
+ : 'requires dissolution { decomposed_into[] } — its own artifact, not a resolution',
123
+ 'resolved→open': (input) =>
124
+ input?.reopen?.shaken_evidence_ref
125
+ ? null
126
+ : 'reopen requires { shaken_evidence_ref } (P6)',
127
+ 'inconclusive→under_test': (input) => redisposeViolation(input),
128
+ 'inconclusive→open': (input) => redisposeViolation(input),
129
+ };
130
+
131
+ /**
132
+ * Re-dispose carries `{ new_resolve_by, new method package }` for BOTH target
133
+ * states (the table is explicit): a gated method may not be re-disposed
134
+ * without its package even when the joint returns to open.
135
+ */
136
+ function redisposeViolation(input) {
137
+ const redispose = input?.redispose;
138
+ if (!redispose?.new_resolve_by) {
139
+ return 're-dispose requires { new_resolve_by, new method package } (P3 retry-with-different-method)';
140
+ }
141
+ if (redispose.new_resolve_by === 'EXT' && !redispose.ext) {
142
+ return 're-dispose to EXT requires its ext package (sharpened or judgment-dispatch)';
143
+ }
144
+ if (redispose.new_resolve_by === 'STRADDLE' && !redispose.straddle) {
145
+ return 're-dispose to STRADDLE requires straddle { discriminating_signal, kill_criteria }';
146
+ }
147
+ return null;
148
+ }
149
+
150
+ /**
151
+ * The legal edge set, exported for the graph-parity contract test (the
152
+ * judgment lifecycle mode and this table must agree edge-for-edge).
153
+ */
154
+ export const LEGAL_EDGES = Object.freeze(Object.keys(EDGE_TABLE));
155
+
156
+ /**
157
+ * Assert a transition edge is legal and carries its bound artifact.
158
+ *
159
+ * @param {string} from current joint state
160
+ * @param {string} to target joint state
161
+ * @param {object} input transition input ({ resolution?, dissolution?, reopen?, redispose? })
162
+ */
163
+ export function assertEdgeArtifact(from, to, input = {}) {
164
+ const edge = `${from}→${to}`;
165
+ const rule = EDGE_TABLE[edge];
166
+ if (!rule) {
167
+ refuse('JUDGMENT_ILLEGAL_EDGE', [`edge ${edge} is not in the edge→artifact table — refused`]);
168
+ }
169
+ const violation = rule(input);
170
+ if (violation) refuse('JUDGMENT_ILLEGAL_EDGE', [`edge ${edge}: ${violation}`]);
171
+ }
172
+
173
+ /**
174
+ * Method gates (P3 / external-signal contract), applied to the joint as it
175
+ * would stand AFTER the transition (i.e. with any re-disposed method/package
176
+ * already merged by the caller):
177
+ * - EXT → under_test needs `ext` (sharpened package or judgment-dispatch)
178
+ * - STRADDLE → under_test needs `straddle { discriminating_signal, kill_criteria }`
179
+ * - an ext_result of SILENT may only accompany the joint outcome `inconclusive`
180
+ *
181
+ * @param {object} joint the joint record (post-merge view)
182
+ * @param {string} to target state
183
+ * @param {object} [input] transition input (for resolution inspection)
184
+ */
185
+ export function assertMethodGate(joint, to, input = {}) {
186
+ const violations = [];
187
+ if (to === 'under_test') {
188
+ if (joint.resolve_by === 'EXT' && !joint.ext) {
189
+ violations.push(
190
+ 'EXT joint cannot enter under_test without ext { sharpened_question, bar, falsifier } or ext { judgment_dispatch: true, reason } (BAR-OR-JUDGMENT)',
191
+ );
192
+ }
193
+ if (joint.resolve_by === 'STRADDLE' && !joint.straddle) {
194
+ violations.push(
195
+ 'STRADDLE joint cannot enter under_test without straddle { discriminating_signal, kill_criteria } (STRADDLE-NEEDS-SIGNAL, KILL-CRITERIA-FIRST)',
196
+ );
197
+ }
198
+ }
199
+ // EXT resolutions MUST carry the ruled result package. Since only the
200
+ // Answerer slice can produce evidence packages, this is also what makes
201
+ // "no EXT resolution can occur before the Answerer exists" structural.
202
+ if (joint.resolve_by === 'EXT' && (to === 'resolved' || to === 'inconclusive')) {
203
+ const extResult = input?.resolution?.ext_result;
204
+ if (!extResult) {
205
+ violations.push(
206
+ 'an EXT resolution requires the ruled ext_result package { outcome, sources, search_record, found_or_provoked, judgment_not_evidence }',
207
+ );
208
+ } else {
209
+ if (['FOUND', 'CONTRARY'].includes(extResult.outcome)) {
210
+ const sources = Array.isArray(extResult.sources) ? extResult.sources : [];
211
+ if (sources.length === 0) {
212
+ violations.push(`ext_result ${extResult.outcome} requires at least one source address`);
213
+ }
214
+ for (const source of sources) {
215
+ if (!String(source).startsWith('records/evidence/')) {
216
+ violations.push(`ext_result source "${source}" must address an immutable records/evidence/ package`);
217
+ }
218
+ }
219
+ }
220
+ if (joint.ext?.judgment_dispatch === true && extResult.judgment_dispatch !== true) {
221
+ violations.push('the judgment-dispatch stamp propagates permanently: ext_result.judgment_dispatch must be true on a BAR-OR-JUDGMENT joint');
222
+ }
223
+ }
224
+ }
225
+ const extOutcome = input?.resolution?.ext_result?.outcome;
226
+ if (extOutcome === 'SILENT' && to !== 'inconclusive') {
227
+ violations.push('a SILENT external-signal result may only yield the joint outcome inconclusive');
228
+ }
229
+ if (violations.length > 0) refuse('JUDGMENT_METHOD_GATE', violations);
230
+ }