@sentropic/focus 0.5.0-rc.3 → 0.5.0-rc.7

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 (86) hide show
  1. package/dist/editing/anchors.d.ts +14 -0
  2. package/dist/editing/anchors.d.ts.map +1 -0
  3. package/dist/editing/anchors.js +113 -0
  4. package/dist/editing/anchors.js.map +1 -0
  5. package/dist/editing/codec.d.ts +24 -0
  6. package/dist/editing/codec.d.ts.map +1 -0
  7. package/dist/editing/codec.js +143 -0
  8. package/dist/editing/codec.js.map +1 -0
  9. package/dist/editing/contract.d.ts +129 -0
  10. package/dist/editing/contract.d.ts.map +1 -0
  11. package/dist/editing/contract.js +76 -0
  12. package/dist/editing/contract.js.map +1 -0
  13. package/dist/editing/diff.d.ts +12 -0
  14. package/dist/editing/diff.d.ts.map +1 -0
  15. package/dist/editing/diff.js +125 -0
  16. package/dist/editing/diff.js.map +1 -0
  17. package/dist/editing/digest.d.ts +6 -0
  18. package/dist/editing/digest.d.ts.map +1 -0
  19. package/dist/editing/digest.js +56 -0
  20. package/dist/editing/digest.js.map +1 -0
  21. package/dist/editing/index.d.ts +7 -0
  22. package/dist/editing/index.d.ts.map +1 -0
  23. package/dist/editing/index.js +7 -0
  24. package/dist/editing/index.js.map +1 -0
  25. package/dist/editing/reconcile.d.ts +66 -0
  26. package/dist/editing/reconcile.d.ts.map +1 -0
  27. package/dist/editing/reconcile.js +167 -0
  28. package/dist/editing/reconcile.js.map +1 -0
  29. package/dist/editing/structure.d.ts +24 -0
  30. package/dist/editing/structure.d.ts.map +1 -0
  31. package/dist/editing/structure.js +71 -0
  32. package/dist/editing/structure.js.map +1 -0
  33. package/dist/index.d.ts +4 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/model.d.ts +71 -1
  38. package/dist/model.d.ts.map +1 -1
  39. package/dist/model.js +1 -1
  40. package/dist/model.js.map +1 -1
  41. package/dist/registry/definitions.d.ts +1 -1
  42. package/dist/registry/definitions.d.ts.map +1 -1
  43. package/dist/registry/definitions.js +40 -32
  44. package/dist/registry/definitions.js.map +1 -1
  45. package/dist/render/evidence.d.ts +10 -0
  46. package/dist/render/evidence.d.ts.map +1 -0
  47. package/dist/render/evidence.js +37 -0
  48. package/dist/render/evidence.js.map +1 -0
  49. package/dist/render/html.d.ts.map +1 -1
  50. package/dist/render/html.js +2 -0
  51. package/dist/render/html.js.map +1 -1
  52. package/dist/render/md.d.ts.map +1 -1
  53. package/dist/render/md.js +3 -0
  54. package/dist/render/md.js.map +1 -1
  55. package/dist/render/terminal.d.ts.map +1 -1
  56. package/dist/render/terminal.js +3 -0
  57. package/dist/render/terminal.js.map +1 -1
  58. package/dist/validation/evidence-bytes.d.ts +5 -0
  59. package/dist/validation/evidence-bytes.d.ts.map +1 -0
  60. package/dist/validation/evidence-bytes.js +57 -0
  61. package/dist/validation/evidence-bytes.js.map +1 -0
  62. package/dist/validation/evidence-shape.d.ts +12 -0
  63. package/dist/validation/evidence-shape.d.ts.map +1 -0
  64. package/dist/validation/evidence-shape.js +54 -0
  65. package/dist/validation/evidence-shape.js.map +1 -0
  66. package/dist/validation/evidence-sources.d.ts +7 -0
  67. package/dist/validation/evidence-sources.d.ts.map +1 -0
  68. package/dist/validation/evidence-sources.js +56 -0
  69. package/dist/validation/evidence-sources.js.map +1 -0
  70. package/dist/validation/evidence.d.ts +5 -0
  71. package/dist/validation/evidence.d.ts.map +1 -0
  72. package/dist/validation/evidence.js +131 -0
  73. package/dist/validation/evidence.js.map +1 -0
  74. package/dist/validation/index.d.ts +1 -1
  75. package/dist/validation/index.d.ts.map +1 -1
  76. package/dist/validation/index.js +11 -1
  77. package/dist/validation/index.js.map +1 -1
  78. package/dist/validation/readability.d.ts.map +1 -1
  79. package/dist/validation/readability.js +21 -0
  80. package/dist/validation/readability.js.map +1 -1
  81. package/package.json +14 -3
  82. package/registry/entries.v1.json +17 -4
  83. package/schemas/decision-dossier-document.v2.schema.json +925 -0
  84. package/schemas/focus-edit-return.v1.schema.json +950 -0
  85. package/schemas/focus-editing-manifest.v1.schema.json +167 -0
  86. package/skills/focus/SKILL.md +50 -1
@@ -0,0 +1,14 @@
1
+ import type { DecisionDossierDocument } from '../model.js';
2
+ import type { Address, EditingField, FocusEditingManifest, Paragraph, ParagraphValue, Validation } from './contract.js';
3
+ export declare const fieldKey: (a: Address) => string;
4
+ export declare function sourceNodes(doc: DecisionDossierDocument): Record<string, any>[];
5
+ export declare function sourceNode(doc: DecisionDossierDocument, address: Address): Record<string, any>;
6
+ export declare function editableFields(doc: DecisionDossierDocument): EditingField[];
7
+ export declare function sealManifest(value: Omit<FocusEditingManifest, 'manifestBaseHash'>): FocusEditingManifest;
8
+ /** Legacy seed only. A revised source MUST carry an explicit mapping instead of reseeding. */
9
+ export declare function seedManifest(doc: DecisionDossierDocument): FocusEditingManifest;
10
+ export declare function validateManifest(value: unknown, doc: DecisionDossierDocument): Validation<FocusEditingManifest>;
11
+ /** Explicit producer correspondence, including retirements. Never matches by text similarity. */
12
+ export declare function carryManifest(doc: DecisionDossierDocument, previous: FocusEditingManifest, paragraphs: Paragraph[]): FocusEditingManifest;
13
+ export declare function readParagraphs(doc: DecisionDossierDocument, manifest: FocusEditingManifest): ParagraphValue[];
14
+ //# sourceMappingURL=anchors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../src/editing/anchors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKxH,eAAO,MAAM,QAAQ,GAAI,GAAG,OAAO,KAAG,MAAyD,CAAC;AAQhG,wBAAgB,WAAW,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAE/E;AACD,wBAAgB,UAAU,CAAC,GAAG,EAAE,uBAAuB,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAG9F;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,uBAAuB,GAAG,YAAY,EAAE,CAK3E;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,GAAG,oBAAoB,CAExG;AACD,8FAA8F;AAC9F,wBAAgB,YAAY,CAAC,GAAG,EAAE,uBAAuB,GAAG,oBAAoB,CAU/E;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,uBAAuB,GAAG,UAAU,CAAC,oBAAoB,CAAC,CA2C/G;AACD,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,GAAG,EAAE,uBAAuB,EAAE,QAAQ,EAAE,oBAAoB,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,oBAAoB,CAKzI;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,uBAAuB,EAAE,QAAQ,EAAE,oBAAoB,GAAG,cAAc,EAAE,CAM7G"}
@@ -0,0 +1,113 @@
1
+ import { baseDigest, canonicalJson, manifestDigest } from './digest.js';
2
+ import { manifestSchema, matchesSchema } from './structure.js';
3
+ import { isRepresentablePlainText, segmentMarkdown, segmentText } from './codec.js';
4
+ export const fieldKey = (a) => canonicalJson([a.nodeId, a.targetRef, a.field]);
5
+ /** Exactly one soft line break (LF, CRLF or CR): the only allowed overhang
6
+ * of a text/plain paragraph range beyond its source block. */
7
+ const singleLineBreak = /^(?:\r\n|\n|\r)$/;
8
+ /** An emptied narrative field keeps one empty unit: `""` is content (D14), so an
9
+ * empty source still carries its paragraph identity instead of zero units. */
10
+ const textSegments = (source) => source === '' ? [{ start: 0, end: 0, editable: true }] : segmentText(source);
11
+ export function sourceNodes(doc) {
12
+ return doc.sections.flatMap(s => s.kind === 'optionSet' ? [s, ...s.options] : [s]);
13
+ }
14
+ export function sourceNode(doc, address) {
15
+ const found = sourceNodes(doc).filter(n => n.id === address.nodeId && n.targetRef === address.targetRef);
16
+ if (found.length !== 1)
17
+ throw new Error('missing-or-ambiguous-node');
18
+ return found[0];
19
+ }
20
+ export function editableFields(doc) {
21
+ const allowed = { prose: ['markdown'], question: ['question', 'recommendedAnswer', 'context'], option: ['label', 'body', 'consequence'] };
22
+ return sourceNodes(doc).flatMap(n => (allowed[n.kind] ?? []).filter(field => typeof n[field] === 'string').map(field => ({
23
+ nodeId: n.id, targetRef: n.targetRef, field: field, contentFormat: field === 'markdown' ? 'focus.markdown.p0@1' : 'text/plain', blockKind: n.kind,
24
+ })));
25
+ }
26
+ export function sealManifest(value) {
27
+ return { ...value, manifestBaseHash: manifestDigest(value) };
28
+ }
29
+ /** Legacy seed only. A revised source MUST carry an explicit mapping instead of reseeding. */
30
+ export function seedManifest(doc) {
31
+ const baseHash = baseDigest(doc), fields = editableFields(doc);
32
+ const paragraphs = fields.flatMap(f => {
33
+ const source = sourceNode(doc, f)[f.field];
34
+ const segments = f.contentFormat === 'text/plain' ? textSegments(source) : segmentMarkdown(source);
35
+ return segments.filter(s => s.editable).map((s, order) => ({ nodeId: f.nodeId, targetRef: f.targetRef, field: f.field,
36
+ paragraphId: `paragraph:${baseDigest([baseHash, fieldKey(f), order]).slice(7)}`, blockKind: 'paragraph', parentId: null, order,
37
+ range: { start: s.start, end: s.end, unit: 'utf16' } }));
38
+ });
39
+ return sealManifest({ schemaVersion: 1, manifestId: `manifest:${baseHash.slice(7)}`, documentRef: doc.ref, baseHash, fields, paragraphs, retiredParagraphIds: [] });
40
+ }
41
+ export function validateManifest(value, doc) {
42
+ if (!matchesSchema(manifestSchema, value))
43
+ return { ok: false, issues: ['manifest-structure'] };
44
+ const m = value, issues = [];
45
+ try {
46
+ if (m.documentRef !== doc.ref || m.baseHash !== baseDigest(doc) || m.manifestBaseHash !== manifestDigest(m))
47
+ issues.push('manifest-digest-or-base');
48
+ const allowed = editableFields(doc), fieldIds = new Set(), ids = new Set();
49
+ for (const f of m.fields) {
50
+ const key = fieldKey(f);
51
+ if (fieldIds.has(key) || !allowed.some(a => canonicalJson(a) === canonicalJson(f)))
52
+ issues.push('unsupported-or-duplicate-field');
53
+ fieldIds.add(key);
54
+ const source = sourceNode(doc, f)[f.field];
55
+ const ps = m.paragraphs.filter(p => fieldKey(p) === key).sort((a, b) => a.order - b.order);
56
+ const segments = f.contentFormat === 'text/plain' ? textSegments(source) : segmentMarkdown(source);
57
+ let end = 0;
58
+ ps.forEach((p, index) => {
59
+ if (p.order !== index || p.range.start < end || p.range.end < p.range.start || p.range.end > source.length)
60
+ issues.push('ambiguous-range');
61
+ // An empty text/plain paragraph holds no characters, so it never matches a
62
+ // text block: it is a zero-length unit owned by a structural gap (D14).
63
+ // It is representable outside any block (source edge, block boundary or
64
+ // blank gap), never strictly inside one.
65
+ const emptyGapUnit = f.contentFormat === 'text/plain' && p.range.start === p.range.end &&
66
+ !segments.some(s => s.start < p.range.start && p.range.start < s.end);
67
+ // Case 3: a text/plain paragraph may keep at most one soft break at
68
+ // each edge ("A\n", "\nB"). Its range then extends one break beyond
69
+ // its block; the sliced text still round-trips via stored ranges.
70
+ // The extension must stay anchored on a whole source block: an
71
+ // internal fragment that merely round-trips (e.g. "B" of "ABC")
72
+ // is never a paragraph.
73
+ const edgeBreakUnit = f.contentFormat === 'text/plain' && p.range.start < p.range.end &&
74
+ isRepresentablePlainText(source.slice(p.range.start, p.range.end)) &&
75
+ segments.some(s => s.editable && p.range.start <= s.start && p.range.end >= s.end &&
76
+ (p.range.start === s.start || singleLineBreak.test(source.slice(p.range.start, s.start))) &&
77
+ (p.range.end === s.end || singleLineBreak.test(source.slice(s.end, p.range.end))));
78
+ if (!segments.some(s => s.editable && s.start === p.range.start && s.end === p.range.end) && !emptyGapUnit && !edgeBreakUnit && !(p.range.start === p.range.end && f.contentFormat !== 'text/plain'))
79
+ issues.push('unsupported-range');
80
+ end = p.range.end;
81
+ });
82
+ }
83
+ for (const p of m.paragraphs) {
84
+ if (ids.has(p.paragraphId) || m.retiredParagraphIds.includes(p.paragraphId) || !fieldIds.has(fieldKey(p)))
85
+ issues.push('ambiguous-paragraph');
86
+ ids.add(p.paragraphId);
87
+ }
88
+ }
89
+ catch {
90
+ issues.push('invalid-manifest');
91
+ }
92
+ return issues.length ? { ok: false, issues } : { ok: true, value: m };
93
+ }
94
+ /** Explicit producer correspondence, including retirements. Never matches by text similarity. */
95
+ export function carryManifest(doc, previous, paragraphs) {
96
+ const active = new Set(paragraphs.map(p => p.paragraphId));
97
+ const m = sealManifest({ schemaVersion: 1, manifestId: previous.manifestId, documentRef: doc.ref, baseHash: baseDigest(doc), fields: editableFields(doc),
98
+ paragraphs: structuredClone(paragraphs), retiredParagraphIds: [...new Set([...previous.retiredParagraphIds, ...previous.paragraphs.filter(p => !active.has(p.paragraphId)).map(p => p.paragraphId)])] });
99
+ const result = validateManifest(m, doc);
100
+ if (!result.ok)
101
+ throw new Error(result.issues.join(', '));
102
+ return m;
103
+ }
104
+ export function readParagraphs(doc, manifest) {
105
+ const check = validateManifest(manifest, doc);
106
+ if (!check.ok)
107
+ throw new Error(check.issues.join(', '));
108
+ return manifest.fields.flatMap(f => manifest.paragraphs.filter(p => fieldKey(p) === fieldKey(f)).sort((a, b) => a.order - b.order).map(p => ({
109
+ documentRef: doc.ref, nodeId: p.nodeId, targetRef: p.targetRef, field: p.field, paragraphId: p.paragraphId, blockKind: 'paragraph',
110
+ format: f.contentFormat, text: sourceNode(doc, p)[p.field].slice(p.range.start, p.range.end),
111
+ })));
112
+ }
113
+ //# sourceMappingURL=anchors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchors.js","sourceRoot":"","sources":["../../src/editing/anchors.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAChG;8DAC8D;AAC9D,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAC3C;8EAC8E;AAC9E,MAAM,YAAY,GAAG,CAAC,MAAc,EAAuD,EAAE,CAC3F,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC/E,MAAM,UAAU,WAAW,CAAC,GAA4B;IACtD,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1G,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,GAA4B,EAAE,OAAgB;IACvE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,GAA4B;IACzD,MAAM,OAAO,GAA6B,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC;IACpK,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACvH,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,KAA8B,EAAE,aAAa,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,qBAA8B,CAAC,CAAC,CAAC,YAAqB,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI;KAC7L,CAAC,CAAC,CAAC,CAAC;AACP,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,KAAqD;IAChF,OAAO,EAAE,GAAG,KAAK,EAAE,gBAAgB,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;AAC/D,CAAC;AACD,8FAA8F;AAC9F,MAAM,UAAU,YAAY,CAAC,GAA4B;IACvD,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAgB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QACjD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAW,CAAC;QACrD,MAAM,QAAQ,GAAG,CAAC,CAAC,aAAa,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACnG,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK;YACnH,WAAW,EAAE,aAAa,UAAU,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,WAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK;YACvI,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,OAAgB,EAAE,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IACH,OAAO,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU,EAAE,YAAY,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,CAAC;AACtK,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,GAA4B;IAC3E,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC;IAChG,MAAM,CAAC,GAAG,KAA6B,EAAE,MAAM,GAAa,EAAE,CAAC;IAC/D,IAAI,CAAC;QACH,IAAI,CAAC,CAAC,WAAW,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,gBAAgB,KAAK,cAAc,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACpJ,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,EAAU,EAAE,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3F,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;YAClI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAW,CAAC;YACrD,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3F,MAAM,QAAQ,GAAG,CAAC,CAAC,aAAa,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YACnG,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;gBACtB,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM;oBAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAC3I,2EAA2E;gBAC3E,wEAAwE;gBACxE,wEAAwE;gBACxE,yCAAyC;gBACzC,MAAM,YAAY,GAAG,CAAC,CAAC,aAAa,KAAK,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG;oBACpF,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBACxE,oEAAoE;gBACpE,oEAAoE;gBACpE,kEAAkE;gBAClE,+DAA+D;gBAC/D,gEAAgE;gBAChE,wBAAwB;gBACxB,MAAM,aAAa,GAAG,CAAC,CAAC,aAAa,KAAK,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG;oBACnF,wBAAwB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG;wBAC/E,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;wBACzF,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,aAAa,KAAK,YAAY,CAAC;oBAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBACvO,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;YACpB,CAAC,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC9I,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AACxE,CAAC;AACD,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,GAA4B,EAAE,QAA8B,EAAE,UAAuB;IACjH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,GAAG,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC;QACtJ,UAAU,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,mBAAmB,EAAE,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3M,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAAC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAAC,OAAO,CAAC,CAAC;AAC/G,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,GAA4B,EAAE,QAA8B;IACzF,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACvG,OAAO,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3I,WAAW,EAAE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,WAAoB;QAC3I,MAAM,EAAE,CAAC,CAAC,aAAa,EAAE,IAAI,EAAG,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAY,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;KACzG,CAAC,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { FocusReturn } from './contract.js';
2
+ export interface SourceSegment {
3
+ start: number;
4
+ end: number;
5
+ text: string;
6
+ editable: boolean;
7
+ }
8
+ /** Source-preserving CommonMark + GFM tables. No Markdown reserialization. */
9
+ export declare function segmentMarkdown(source: string): SourceSegment[];
10
+ /** Plain narrative fields: one unit per block of non-blank lines. Exact source
11
+ * offsets, CRLF/CR aware, no trimming and no normalization: blank lines stay
12
+ * structural gaps owned by the manifest, never paragraph content. */
13
+ export declare function segmentText(source: string): SourceSegment[];
14
+ /** A text/plain paragraph is one block of non-blank lines (segmentText) with
15
+ * at most one soft line break kept at each edge (case 3: "A\n", "\nB",
16
+ * "\nA\n", CRLF/CR included). Blank lines stay structural gaps owned by the
17
+ * manifest, never paragraph content: stripping more than one edge break still
18
+ * leaves an edge break behind, so "A\n\n" or "\n\nB" keep failing. A lone
19
+ * single break ("\n", "\r\n", "\r") is representable as its own unit. */
20
+ export declare function isRepresentablePlainText(text: string): boolean;
21
+ export declare function assertParagraphText(text: string, format: string): void;
22
+ export declare function encodeReturn(value: FocusReturn, format?: 'json' | 'yaml'): string;
23
+ export declare function decodeReturn(raw: string, format?: 'json' | 'yaml'): FocusReturn;
24
+ //# sourceMappingURL=codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/editing/codec.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,aAAa;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE;AAG9F,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAoB/D;AACD;;qEAEqE;AACrE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAsB3D;AAKD;;;;;yEAKyE;AACzE,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAW9D;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAQtE;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,GAAE,MAAM,GAAG,MAAe,GAAG,MAAM,CAIzF;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,MAAe,GAAG,WAAW,CAevF"}
@@ -0,0 +1,143 @@
1
+ import { parser, GFM } from '@lezer/markdown';
2
+ import { parseDocument, isAlias, isMap, isSeq, isScalar, stringify } from 'yaml';
3
+ import { canonicalJson } from './digest.js';
4
+ import { validateReturnStructure } from './contract.js';
5
+ const sourceParser = parser.configure(GFM);
6
+ /** Source-preserving CommonMark + GFM tables. No Markdown reserialization. */
7
+ export function segmentMarkdown(source) {
8
+ // Lezer consumes LF. Preserve an exact offset map into the original CRLF/CR source.
9
+ const chars = [], offsets = [0];
10
+ for (let i = 0; i < source.length; i++) {
11
+ if (source[i] === '\r') {
12
+ chars.push('\n');
13
+ if (source[i + 1] === '\n')
14
+ i++;
15
+ }
16
+ else
17
+ chars.push(source[i]);
18
+ offsets.push(i + 1);
19
+ }
20
+ const tree = sourceParser.parse(chars.join(''));
21
+ const safe = (node) => {
22
+ if (!['Paragraph', 'Emphasis', 'StrongEmphasis', 'InlineCode', 'HardBreak', 'CodeMark', 'EmphasisMark', 'Escape', 'Entity'].includes(node.name))
23
+ return false;
24
+ for (let child = node.firstChild; child; child = child.nextSibling)
25
+ if (!safe(child))
26
+ return false;
27
+ return true;
28
+ };
29
+ const segments = [];
30
+ for (let node = tree.topNode.firstChild; node; node = node.nextSibling) {
31
+ const start = offsets[node.from], end = offsets[node.to];
32
+ segments.push({ start, end, text: source.slice(start, end), editable: node.name === 'Paragraph' && safe(node) });
33
+ }
34
+ return segments;
35
+ }
36
+ /** Plain narrative fields: one unit per block of non-blank lines. Exact source
37
+ * offsets, CRLF/CR aware, no trimming and no normalization: blank lines stay
38
+ * structural gaps owned by the manifest, never paragraph content. */
39
+ export function segmentText(source) {
40
+ if (source === '')
41
+ return [];
42
+ const parts = source.split(/(\r\n|\n|\r)/);
43
+ const lines = [];
44
+ let offset = 0;
45
+ for (let i = 0; i < parts.length; i += 2) {
46
+ const text = parts[i];
47
+ lines.push({ start: offset, end: offset + text.length, text });
48
+ offset += text.length + (parts[i + 1] ?? '').length;
49
+ }
50
+ const segments = [];
51
+ let open = null;
52
+ const close = (last) => {
53
+ segments.push({ start: lines[open].start, end: lines[last].end, text: source.slice(lines[open].start, lines[last].end), editable: true });
54
+ open = null;
55
+ };
56
+ lines.forEach((line, index) => {
57
+ if (/^[ \t]*$/.test(line.text)) {
58
+ if (open !== null)
59
+ close(index - 1);
60
+ }
61
+ else if (open === null)
62
+ open = index;
63
+ });
64
+ if (open !== null)
65
+ close(lines.length - 1);
66
+ return segments;
67
+ }
68
+ const lineBreak = String.raw `(?:\r\n|\n|\r)`;
69
+ const singleBreak = new RegExp(`^${lineBreak}$`);
70
+ const leadingBreak = new RegExp(`^${lineBreak}`);
71
+ const trailingBreak = new RegExp(`${lineBreak}$`);
72
+ /** A text/plain paragraph is one block of non-blank lines (segmentText) with
73
+ * at most one soft line break kept at each edge (case 3: "A\n", "\nB",
74
+ * "\nA\n", CRLF/CR included). Blank lines stay structural gaps owned by the
75
+ * manifest, never paragraph content: stripping more than one edge break still
76
+ * leaves an edge break behind, so "A\n\n" or "\n\nB" keep failing. A lone
77
+ * single break ("\n", "\r\n", "\r") is representable as its own unit. */
78
+ export function isRepresentablePlainText(text) {
79
+ if (text === '')
80
+ return true;
81
+ if (singleBreak.test(text))
82
+ return true;
83
+ let core = text;
84
+ const lead = core.match(leadingBreak);
85
+ if (lead)
86
+ core = core.slice(lead[0].length);
87
+ const trail = core.match(trailingBreak);
88
+ if (trail)
89
+ core = core.slice(0, -trail[0].length);
90
+ if (core === '')
91
+ return false;
92
+ const parts = segmentText(core);
93
+ return parts.length === 1 && parts[0].start === 0 && parts[0].end === core.length;
94
+ }
95
+ export function assertParagraphText(text, format) {
96
+ if (text === '')
97
+ return;
98
+ if (format === 'text/plain') {
99
+ if (isRepresentablePlainText(text))
100
+ return;
101
+ throw new Error('unsupported-paragraph-format');
102
+ }
103
+ const parts = segmentMarkdown(text);
104
+ if (parts.length !== 1 || !parts[0].editable || parts[0].start !== 0 || parts[0].end !== text.length)
105
+ throw new Error('unsupported-paragraph-format');
106
+ }
107
+ export function encodeReturn(value, format = 'json') {
108
+ if (!validateReturnStructure(value))
109
+ throw new Error('unsupported-version-or-structure');
110
+ canonicalJson(value);
111
+ return format === 'json' ? JSON.stringify(value, null, 2) + '\n' : stringify(value, { lineWidth: 0, aliasDuplicateObjects: false });
112
+ }
113
+ export function decodeReturn(raw, format = 'json') {
114
+ if (format !== 'json' && format !== 'yaml')
115
+ throw new Error('unsupported-format');
116
+ if (format === 'json')
117
+ JSON.parse(raw); // Strict JSON syntax; YAML below also checks duplicate keys.
118
+ const parsed = parseDocument(raw, { uniqueKeys: true, strict: true, schema: 'core' });
119
+ if (parsed.errors.length || parsed.warnings.length)
120
+ throw new Error('Invalid serialized return');
121
+ const visit = (node) => {
122
+ if (!node)
123
+ return;
124
+ if (isAlias(node) || node.tag)
125
+ throw new Error('Aliases and explicit tags are unsupported');
126
+ if (isMap(node))
127
+ for (const pair of node.items) {
128
+ if (!isScalar(pair.key) || typeof pair.key.value !== 'string')
129
+ throw new Error('JSON keys must be strings');
130
+ visit(pair.key);
131
+ visit(pair.value);
132
+ }
133
+ if (isSeq(node))
134
+ node.items.forEach(visit);
135
+ };
136
+ visit(parsed.contents);
137
+ const value = parsed.toJS({ maxAliasCount: 0 });
138
+ canonicalJson(value);
139
+ if (!validateReturnStructure(value))
140
+ throw new Error('unsupported-version-or-structure');
141
+ return value;
142
+ }
143
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/editing/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import type { DecisionDossierDocument } from '../model.js';
2
+ export type Format = 'text/plain' | 'focus.markdown.p0@1';
3
+ export interface Address {
4
+ nodeId: string;
5
+ targetRef: string;
6
+ field: 'markdown' | 'question' | 'recommendedAnswer' | 'context' | 'label' | 'body' | 'consequence';
7
+ }
8
+ export interface EditingField extends Address {
9
+ contentFormat: Format;
10
+ blockKind: 'prose' | 'question' | 'option';
11
+ }
12
+ export interface Paragraph extends Address {
13
+ paragraphId: string;
14
+ blockKind: 'paragraph';
15
+ parentId: null;
16
+ order: number;
17
+ range: {
18
+ start: number;
19
+ end: number;
20
+ unit: 'utf16';
21
+ };
22
+ }
23
+ export interface FocusEditingManifest {
24
+ schemaVersion: 1;
25
+ manifestId: string;
26
+ documentRef: string;
27
+ baseHash: string;
28
+ manifestBaseHash: string;
29
+ fields: EditingField[];
30
+ paragraphs: Paragraph[];
31
+ retiredParagraphIds: string[];
32
+ }
33
+ export interface Anchors {
34
+ parentId: null;
35
+ previousParagraphId: string | null;
36
+ nextParagraphId: string | null;
37
+ }
38
+ export interface ParagraphValue extends Address {
39
+ documentRef: string;
40
+ paragraphId: string;
41
+ blockKind: 'paragraph';
42
+ format: Format;
43
+ text: string;
44
+ }
45
+ export interface ParagraphChange extends Address {
46
+ documentRef: string;
47
+ paragraphId: string;
48
+ blockKind: 'paragraph';
49
+ format: Format;
50
+ changeId: string;
51
+ operation: 'replace' | 'insert' | 'delete' | 'move';
52
+ before: string | null;
53
+ after: string | null;
54
+ beforeAnchors: Anchors | null;
55
+ anchors: Anchors;
56
+ }
57
+ export interface EditTransaction {
58
+ transactionId: string;
59
+ changes: ParagraphChange[];
60
+ }
61
+ export interface Production {
62
+ producerId: string;
63
+ generationId: string;
64
+ requestId: string;
65
+ }
66
+ export interface FocusReturn {
67
+ kind: 'focus.return';
68
+ schemaVersion: 1;
69
+ returnId: string;
70
+ digest: string;
71
+ capture: {
72
+ at: string;
73
+ };
74
+ scope: {
75
+ workspaceId: string;
76
+ } | null;
77
+ source: {
78
+ documentRef: string;
79
+ hash: string;
80
+ cursor: string;
81
+ baseHash: string;
82
+ manifestId: string;
83
+ manifestBaseHash: string;
84
+ };
85
+ production: Production | null;
86
+ manifest: FocusEditingManifest;
87
+ answers: {
88
+ questionId: string;
89
+ targetRef: string;
90
+ optionIds: string[];
91
+ text: string | null;
92
+ }[];
93
+ notes: {
94
+ targetRef: string;
95
+ text: string | null;
96
+ }[];
97
+ editReturn: {
98
+ schemaVersion: 1;
99
+ mode: 'cumulative';
100
+ transactions: EditTransaction[];
101
+ supersedesReturnId?: string;
102
+ supersededReturnIds: string[];
103
+ };
104
+ }
105
+ export type Validation<T> = {
106
+ ok: true;
107
+ value: T;
108
+ } | {
109
+ ok: false;
110
+ issues: string[];
111
+ };
112
+ export declare const validateManifestStructure: (v: unknown) => v is FocusEditingManifest;
113
+ export declare const validateReturnStructure: (v: unknown) => v is FocusReturn;
114
+ export declare function validateReturn(value: unknown, doc: DecisionDossierDocument, manifest: FocusEditingManifest): Validation<FocusReturn>;
115
+ export interface FreezeInput {
116
+ document: DecisionDossierDocument;
117
+ manifest: FocusEditingManifest;
118
+ production: Production | null;
119
+ scope: FocusReturn['scope'];
120
+ answers: FocusReturn['answers'];
121
+ notes: FocusReturn['notes'];
122
+ transactions: EditTransaction[];
123
+ previous?: FocusReturn;
124
+ returnId: string;
125
+ capturedAt: string;
126
+ }
127
+ /** Capture metadata/identity is supplied by the host, never invented by the pure core. */
128
+ export declare function freezeReturn(input: FreezeInput): FocusReturn;
129
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/editing/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { baseDigest, canonicalJson, returnDigest } from './digest.js';
2
+ import { validateManifest, fieldKey, sourceNodes } from './anchors.js';
3
+ import { matchesSchema, manifestSchema, returnSchema } from './structure.js';
4
+ export const validateManifestStructure = (v) => matchesSchema(manifestSchema, v);
5
+ export const validateReturnStructure = (v) => matchesSchema(returnSchema, v);
6
+ export function validateReturn(value, doc, manifest) {
7
+ const issues = [];
8
+ if (!validateReturnStructure(value))
9
+ return { ok: false, issues: ['unsupported-version-or-structure'] };
10
+ try {
11
+ if (value.digest !== returnDigest(value))
12
+ issues.push('return-digest');
13
+ if (!validateManifest(manifest, doc).ok || !validateManifest(value.manifest, doc).ok || canonicalJson(value.manifest) !== canonicalJson(manifest))
14
+ issues.push('manifest-mismatch');
15
+ if (value.source.documentRef !== doc.ref || value.source.hash !== doc.hash || value.source.cursor !== doc.cursor || value.source.baseHash !== baseDigest(doc) || value.source.manifestId !== manifest.manifestId || value.source.manifestBaseHash !== manifest.manifestBaseHash)
16
+ issues.push('source-mismatch');
17
+ const ancestry = value.editReturn.supersededReturnIds;
18
+ if (ancestry.includes(value.returnId) || (ancestry.length === 0) !== (value.editReturn.supersedesReturnId === undefined) || (ancestry.length && ancestry[0] !== value.editReturn.supersedesReturnId))
19
+ issues.push('ancestry');
20
+ const nodes = sourceNodes(doc), targets = new Set([doc.ref, ...nodes.map(n => n.targetRef)]);
21
+ for (const note of value.notes)
22
+ if (!targets.has(note.targetRef))
23
+ issues.push('note-target');
24
+ const answerIds = new Set();
25
+ for (const answer of value.answers) {
26
+ if (answerIds.has(answer.questionId))
27
+ issues.push('duplicate-answer');
28
+ answerIds.add(answer.questionId);
29
+ const question = nodes.find(n => n.kind === 'question' && n.id === answer.questionId && n.targetRef === answer.targetRef);
30
+ const options = doc.sections.flatMap(n => n.kind === 'optionSet' && n.questionId === answer.questionId ? n.options : []);
31
+ if (!question || answer.optionIds.some(id => !options.some(o => o.id === id)))
32
+ issues.push('answer-target');
33
+ }
34
+ const txIds = new Set(), changeIds = new Set();
35
+ for (const tx of value.editReturn.transactions) {
36
+ if (txIds.has(tx.transactionId))
37
+ issues.push('duplicate-transaction-id');
38
+ txIds.add(tx.transactionId);
39
+ for (const change of tx.changes) {
40
+ if (changeIds.has(change.changeId))
41
+ issues.push('duplicate-change-id');
42
+ changeIds.add(change.changeId);
43
+ const f = manifest.fields.find(f => fieldKey(f) === fieldKey(change));
44
+ if (!f || f.contentFormat !== change.format || change.documentRef !== doc.ref)
45
+ issues.push('address');
46
+ if (change.operation === 'move' && change.before !== change.after)
47
+ issues.push('move-content');
48
+ if (change.operation === 'insert' && (manifest.paragraphs.some(p => p.paragraphId === change.paragraphId) || manifest.retiredParagraphIds.includes(change.paragraphId)))
49
+ issues.push('reused-paragraph-id');
50
+ }
51
+ }
52
+ }
53
+ catch {
54
+ issues.push('invalid-json-value');
55
+ }
56
+ return issues.length ? { ok: false, issues } : { ok: true, value };
57
+ }
58
+ /** Capture metadata/identity is supplied by the host, never invented by the pure core. */
59
+ export function freezeReturn(input) {
60
+ const { document: doc, manifest, previous } = input;
61
+ if (previous && !validateReturn(previous, doc, manifest).ok)
62
+ throw new Error('Invalid previous frozen return: recover complete ancestry');
63
+ const value = { kind: 'focus.return', schemaVersion: 1, returnId: input.returnId, digest: '', capture: { at: input.capturedAt },
64
+ scope: input.scope, source: { documentRef: doc.ref, hash: doc.hash, cursor: doc.cursor, baseHash: manifest.baseHash, manifestId: manifest.manifestId, manifestBaseHash: manifest.manifestBaseHash },
65
+ production: input.production, manifest, answers: input.answers, notes: input.notes,
66
+ editReturn: { schemaVersion: 1, mode: 'cumulative', transactions: input.transactions.filter(t => t.changes.length), supersededReturnIds: previous ? [previous.returnId, ...previous.editReturn.supersededReturnIds] : [], ...(previous ? { supersedesReturnId: previous.returnId } : {}) } };
67
+ // Re-copy/download the same completed revision without allocating a new identity.
68
+ if (previous && canonicalJson([value.answers, value.notes, value.editReturn.transactions, value.production, value.scope]) === canonicalJson([previous.answers, previous.notes, previous.editReturn.transactions, previous.production, previous.scope]))
69
+ return structuredClone(previous);
70
+ value.digest = returnDigest(value);
71
+ const check = validateReturn(value, doc, manifest);
72
+ if (!check.ok)
73
+ throw new Error(check.issues.join(', '));
74
+ return structuredClone(value);
75
+ }
76
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/editing/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { DecisionDossierDocument } from '../model.js';
2
+ import type { Anchors, EditTransaction, FocusEditingManifest, ParagraphValue } from './contract.js';
3
+ export declare const paragraphAnchors: (values: ParagraphValue[], index: number) => Anchors;
4
+ export declare function diffParagraphs(baseline: ParagraphValue[], draft: ParagraphValue[], transactionId: string): EditTransaction;
5
+ /** Applies one atomic batch to source tokens. Opaque gaps are never reserialized.
6
+ * A retired identity is restored only when explicitly listed in `restoreIds`:
7
+ * reviving any other retired identity silently reassigns it (D13). */
8
+ export declare function applyParagraphChanges(document: DecisionDossierDocument, manifest: FocusEditingManifest, transactions: EditTransaction[], restoreIds?: ReadonlySet<string> | null): {
9
+ document: DecisionDossierDocument;
10
+ manifest: FocusEditingManifest;
11
+ };
12
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/editing/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAmB,cAAc,EAAa,MAAM,eAAe,CAAC;AAKhI,eAAO,MAAM,gBAAgB,GAAI,QAAQ,cAAc,EAAE,EAAE,OAAO,MAAM,KAAG,OAAqJ,CAAC;AACjO,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,eAAe,CA2B1H;AAED;;sEAEsE;AACtE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,uBAAuB,EAAE,QAAQ,EAAE,oBAAoB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,UAAU,GAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAW,GAAG;IAAE,QAAQ,EAAE,uBAAuB,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,CA8C9P"}