@ifc-lite/merge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,305 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { ATTR, IFCLITE_ATTR, canonicalStringify } from '@ifc-lite/ifcx';
5
+ import { stableHash } from '@ifc-lite/diff';
6
+ const PSET_RE = /(?:^|::)(Pset_[A-Za-z0-9_]+)(?:::|$)/;
7
+ const QSET_RE = /(?:^|::)(Qto_[A-Za-z0-9_]+)(?:::|$)/;
8
+ /**
9
+ * Map an IFCX attribute key onto the layer-op componentKey vocabulary.
10
+ * Diff keys and op keys are deliberately the same words (02 §2.2).
11
+ */
12
+ export function componentKeyForAttribute(attribute) {
13
+ if (attribute === ATTR.CLASS)
14
+ return 'attr:class';
15
+ if (attribute === ATTR.TRANSFORM)
16
+ return 'placement';
17
+ const pset = PSET_RE.exec(attribute);
18
+ if (pset)
19
+ return `pset:${pset[1]}`;
20
+ const qset = QSET_RE.exec(attribute);
21
+ if (qset)
22
+ return `qset:${qset[1]}`;
23
+ if (attribute.startsWith(ATTR.PROP_PREFIX)) {
24
+ return `attr:prop:${attribute.slice(ATTR.PROP_PREFIX.length)}`;
25
+ }
26
+ if (attribute.startsWith('usd::')) {
27
+ const tier = attribute.split('::').pop() ?? 'usd';
28
+ return `geometry:${tier}`;
29
+ }
30
+ return `attr:${attribute}`;
31
+ }
32
+ /**
33
+ * Flatten an ordered stack (weakest first) into entity component states.
34
+ * Later opinions shadow earlier ones per attribute; `null` child values
35
+ * remove slots; `ifclite::deleted` resolves to the strongest opinion.
36
+ */
37
+ export function extractStackState(layers) {
38
+ const state = new Map();
39
+ const entityFor = (path) => {
40
+ let entity = state.get(path);
41
+ if (!entity) {
42
+ entity = {
43
+ path,
44
+ components: new Map(),
45
+ children: new Map(),
46
+ inherits: new Map(),
47
+ deleted: false,
48
+ explicitDeleted: false,
49
+ };
50
+ state.set(path, entity);
51
+ }
52
+ return entity;
53
+ };
54
+ for (const layer of layers) {
55
+ for (const node of layer.data) {
56
+ applyNode(entityFor(node.path), node);
57
+ }
58
+ }
59
+ // Drop empty shells created purely by child references.
60
+ for (const [path, entity] of state) {
61
+ if (entity.components.size === 0 &&
62
+ entity.children.size === 0 &&
63
+ entity.inherits.size === 0 &&
64
+ !entity.deleted) {
65
+ state.delete(path);
66
+ }
67
+ }
68
+ // Entity tombstones shadow child paths: composition removes the whole
69
+ // subtree, so the merge state must see descendants as deleted too —
70
+ // otherwise a candidate deleting a parent while the target edits a
71
+ // descendant would silently miss the delete-vs-modify conflict.
72
+ const queue = [];
73
+ for (const entity of state.values()) {
74
+ if (entity.deleted)
75
+ queue.push(entity.path);
76
+ }
77
+ while (queue.length > 0) {
78
+ const path = queue.pop();
79
+ if (path === undefined)
80
+ break;
81
+ const entity = state.get(path);
82
+ if (!entity)
83
+ continue;
84
+ for (const childPath of entity.children.values()) {
85
+ const child = state.get(childPath);
86
+ if (child && !child.deleted) {
87
+ child.deleted = true;
88
+ queue.push(childPath);
89
+ }
90
+ }
91
+ }
92
+ return state;
93
+ }
94
+ function applyNode(entity, node) {
95
+ if (node.children) {
96
+ for (const [name, child] of Object.entries(node.children)) {
97
+ if (child === null)
98
+ entity.children.delete(name);
99
+ else
100
+ entity.children.set(name, child);
101
+ }
102
+ }
103
+ if (node.inherits) {
104
+ for (const [role, target] of Object.entries(node.inherits)) {
105
+ if (target === null)
106
+ entity.inherits.delete(role);
107
+ else
108
+ entity.inherits.set(role, target);
109
+ }
110
+ }
111
+ if (!node.attributes)
112
+ return;
113
+ for (const [key, value] of Object.entries(node.attributes)) {
114
+ if (key === IFCLITE_ATTR.DELETED) {
115
+ entity.deleted = value === true;
116
+ entity.explicitDeleted = value === true;
117
+ continue;
118
+ }
119
+ if (key.startsWith(IFCLITE_ATTR.DERIVED))
120
+ continue;
121
+ const componentKey = componentKeyForAttribute(key);
122
+ const component = entity.components.get(componentKey) ?? {};
123
+ if (value === null) {
124
+ delete component[key];
125
+ if (Object.keys(component).length === 0) {
126
+ entity.components.delete(componentKey);
127
+ continue;
128
+ }
129
+ }
130
+ else {
131
+ component[key] = value;
132
+ }
133
+ entity.components.set(componentKey, component);
134
+ }
135
+ }
136
+ /**
137
+ * Project the three stack states onto the paths actually touched by the
138
+ * ours/theirs suffixes — when `ours` and `theirs` share `ancestor` as a
139
+ * prefix, every other path is byte-identical across all three states and
140
+ * contributes nothing to the merge matrix. Untouched entities/components
141
+ * keep the SAME object references on every side, so the matrix can skip
142
+ * hashing them entirely.
143
+ *
144
+ * Returns null — caller must use full extraction — whenever any layer
145
+ * carries an `ifclite::deleted` opinion: tombstones shadow whole subtrees
146
+ * through the children graph, and that propagation is global, not
147
+ * per-path. Restricting the fast path to tombstone-free stacks keeps it
148
+ * provably equivalent to `extractStackState` (see the differential fuzz).
149
+ */
150
+ export function projectStackStates(ancestor, oursSuffix, theirsSuffix) {
151
+ const touched = new Set();
152
+ for (const suffix of [oursSuffix, theirsSuffix]) {
153
+ for (const layer of suffix) {
154
+ for (const node of layer.data) {
155
+ if (node.attributes?.[IFCLITE_ATTR.DELETED] !== undefined)
156
+ return null;
157
+ touched.add(node.path);
158
+ }
159
+ }
160
+ }
161
+ // Restricted ancestor fold: only touched paths get materialized. The
162
+ // tombstone scan rides the same pass so a delete-bearing history aborts
163
+ // before any per-side work.
164
+ const a = new Map();
165
+ for (const layer of ancestor) {
166
+ for (const node of layer.data) {
167
+ if (node.attributes?.[IFCLITE_ATTR.DELETED] !== undefined)
168
+ return null;
169
+ if (!touched.has(node.path))
170
+ continue;
171
+ applyNode(entityFor(a, node.path), node);
172
+ }
173
+ }
174
+ dropEmptyShells(a);
175
+ return {
176
+ a,
177
+ o: projectSide(a, oursSuffix),
178
+ t: projectSide(a, theirsSuffix),
179
+ };
180
+ }
181
+ /** Clone-on-write side state: ancestor refs shared until a suffix node hits the path. */
182
+ function projectSide(a, suffix) {
183
+ const state = new Map(a);
184
+ const cloned = new Set();
185
+ for (const layer of suffix) {
186
+ for (const node of layer.data) {
187
+ let entity = state.get(node.path);
188
+ if (entity && !cloned.has(node.path)) {
189
+ entity = {
190
+ path: entity.path,
191
+ components: new Map(entity.components),
192
+ children: new Map(entity.children),
193
+ inherits: new Map(entity.inherits),
194
+ deleted: entity.deleted,
195
+ explicitDeleted: entity.explicitDeleted,
196
+ };
197
+ state.set(node.path, entity);
198
+ }
199
+ else if (!entity) {
200
+ entity = entityFor(state, node.path);
201
+ }
202
+ cloned.add(node.path);
203
+ applyNodeCow(entity, node);
204
+ }
205
+ }
206
+ // Shell equivalence: a suffix that nulls every attribute away leaves an
207
+ // entity the reference extraction would drop — drop it here too. Only
208
+ // cloned entities can have changed, so only they need the check.
209
+ for (const path of cloned) {
210
+ const entity = state.get(path);
211
+ if (entity && isEmptyShell(entity))
212
+ state.delete(path);
213
+ }
214
+ return state;
215
+ }
216
+ function entityFor(state, path) {
217
+ let entity = state.get(path);
218
+ if (!entity) {
219
+ entity = {
220
+ path,
221
+ components: new Map(),
222
+ children: new Map(),
223
+ inherits: new Map(),
224
+ deleted: false,
225
+ explicitDeleted: false,
226
+ };
227
+ state.set(path, entity);
228
+ }
229
+ return entity;
230
+ }
231
+ function isEmptyShell(entity) {
232
+ return (entity.components.size === 0 &&
233
+ entity.children.size === 0 &&
234
+ entity.inherits.size === 0 &&
235
+ !entity.deleted);
236
+ }
237
+ function dropEmptyShells(state) {
238
+ for (const [path, entity] of state) {
239
+ if (isEmptyShell(entity))
240
+ state.delete(path);
241
+ }
242
+ }
243
+ /**
244
+ * `applyNode` for cloned side entities: component objects are copied
245
+ * before mutation so ancestor-shared references are never written through
246
+ * — reference equality stays a valid "unchanged" signal in the matrix.
247
+ */
248
+ function applyNodeCow(entity, node) {
249
+ if (node.children) {
250
+ for (const [name, child] of Object.entries(node.children)) {
251
+ if (child === null)
252
+ entity.children.delete(name);
253
+ else
254
+ entity.children.set(name, child);
255
+ }
256
+ }
257
+ if (node.inherits) {
258
+ for (const [role, target] of Object.entries(node.inherits)) {
259
+ if (target === null)
260
+ entity.inherits.delete(role);
261
+ else
262
+ entity.inherits.set(role, target);
263
+ }
264
+ }
265
+ if (!node.attributes)
266
+ return;
267
+ for (const [key, value] of Object.entries(node.attributes)) {
268
+ if (key.startsWith(IFCLITE_ATTR.DERIVED))
269
+ continue;
270
+ const componentKey = componentKeyForAttribute(key);
271
+ const component = { ...(entity.components.get(componentKey) ?? {}) };
272
+ if (value === null) {
273
+ delete component[key];
274
+ if (Object.keys(component).length === 0) {
275
+ entity.components.delete(componentKey);
276
+ continue;
277
+ }
278
+ }
279
+ else {
280
+ component[key] = value;
281
+ }
282
+ entity.components.set(componentKey, component);
283
+ }
284
+ }
285
+ /** Hash + value snapshot for conflict records and fold detection. */
286
+ export function snapshotOf(attributes) {
287
+ return { hash: stableHash(canonicalStringify(attributes)), attributes };
288
+ }
289
+ /**
290
+ * Unified view used by the matrix: real components plus `child:<name>` /
291
+ * `inherit:<role>` pseudo-components whose single attribute is the
292
+ * referenced path. Both are relation edges, so divergent edits surface
293
+ * as `hierarchy` conflicts.
294
+ */
295
+ export function componentEntries(entity) {
296
+ const entries = new Map(entity.components);
297
+ for (const [name, child] of entity.children) {
298
+ entries.set(`child:${name}`, { child });
299
+ }
300
+ for (const [role, target] of entity.inherits) {
301
+ entries.set(`inherit:${role}`, { inherit: target });
302
+ }
303
+ return entries;
304
+ }
305
+ //# sourceMappingURL=component-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-state.js","sourceRoot":"","sources":["../src/component-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `@ifc-lite/merge` — three-way merge engine for IFCX layers.
3
+ *
4
+ * Built on two runs of the two-way comparison joined on entity identity:
5
+ * emits a {@link MergePlan} (auto-merged ops + explicit conflict records),
6
+ * applies reviewer resolutions, publishes content-addressed merge layers
7
+ * with `manifest.merge` filled, and derives revert and rebase from the
8
+ * same state-based op model.
9
+ *
10
+ * Spec: docs/architecture/layer-prs/05-merge.md.
11
+ */
12
+ export type { ComponentAttributes, ComponentKey, ComponentSnapshot, MergeConflict, MergeConflictKind, MergeOp, MergePlan, MergePlanStats, ResolutionInput, } from './types.js';
13
+ export { componentKeyForAttribute, componentEntries, extractStackState, snapshotOf, type EntityState, type StackState, } from './component-state.js';
14
+ export { planThreeWayMerge, planFromStates, opsForComponentChange, type ThreeWayInputs, } from './three-way.js';
15
+ export { applyResolutions, buildMergeLayer, opsToNodes, type AppliedResolutions, type MergeLayerInit, type PublishedMergeLayer, } from './merge-layer.js';
16
+ export { buildInverseOps, buildRevertLayer, type RevertLayerInit, type RevertLayerResult, } from './inverse.js';
17
+ export { planRebase, type RebaseInputs, type RebaseResult } from './rebase.js';
18
+ export { diffLayerStacks, diffStackStates, type ModifiedEntity, type StackDiff, } from './state-diff.js';
19
+ export { checkRefPolicy, mergeIntoRef, resolveAncestor, type AncestorResolution, type LayerRefStore, type MergeInit, type MergeOutcome, type RefEntry, type RefPolicy, type Waiver, } from './ref-flow.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,SAAS,EACT,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,MAAM,GACZ,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ export { componentKeyForAttribute, componentEntries, extractStackState, snapshotOf, } from './component-state.js';
5
+ export { planThreeWayMerge, planFromStates, opsForComponentChange, } from './three-way.js';
6
+ export { applyResolutions, buildMergeLayer, opsToNodes, } from './merge-layer.js';
7
+ export { buildInverseOps, buildRevertLayer, } from './inverse.js';
8
+ export { planRebase } from './rebase.js';
9
+ export { diffLayerStacks, diffStackStates, } from './state-diff.js';
10
+ export { checkRefPolicy, mergeIntoRef, resolveAncestor, } from './ref-flow.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAyB/D,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,GAGX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,UAAU,GAIX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,gBAAgB,GAGjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAwC,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,eAAe,EACf,eAAe,GAGhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,eAAe,GAQhB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Revert: a layer of inverse ops. Composing `[base, L, revert(L)]`
3
+ * yields the same component state as `base` alone — additions are
4
+ * tombstoned, deletions resurrected, edited components restored to their
5
+ * base values. History stays append-only.
6
+ */
7
+ import type { IfcxFile, ProvenanceAuthor } from '@ifc-lite/ifcx';
8
+ import type { MergeOp } from './types.js';
9
+ import type { StackState } from './component-state.js';
10
+ /** Ops that transform `after` back into `before` (state-based, per component). */
11
+ export declare function buildInverseOps(before: StackState, after: StackState): MergeOp[];
12
+ export interface RevertLayerInit {
13
+ /** The layer to revert. */
14
+ layer: IfcxFile;
15
+ /** The stack the layer was applied on, ordered weakest first. */
16
+ base: readonly IfcxFile[];
17
+ author: ProvenanceAuthor;
18
+ intent?: string;
19
+ /** Layer id of the reverted layer (recorded as parent). */
20
+ layerId?: string;
21
+ created?: string;
22
+ }
23
+ export interface RevertLayerResult {
24
+ file: IfcxFile;
25
+ layerId: string;
26
+ ops: MergeOp[];
27
+ }
28
+ /** Emit an inverse-op layer that undoes `layer` on top of `base + layer`. */
29
+ export declare function buildRevertLayer(init: RevertLayerInit): RevertLayerResult;
30
+ //# sourceMappingURL=inverse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inverse.d.ts","sourceRoot":"","sources":["../src/inverse.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAuB,OAAO,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,EAAE,CAgDhF;AAED,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,KAAK,EAAE,QAAQ,CAAC;IAChB,iEAAiE;IACjE,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC1B,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,EAAE,CAAC;CAChB;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAgCzE"}
@@ -0,0 +1,87 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { computeLayerId, createProvenanceManifest, setProvenance } from '@ifc-lite/ifcx';
5
+ import { componentEntries, extractStackState, snapshotOf } from './component-state.js';
6
+ import { opsForComponentChange } from './three-way.js';
7
+ import { opsToNodes } from './merge-layer.js';
8
+ /** Ops that transform `after` back into `before` (state-based, per component). */
9
+ export function buildInverseOps(before, after) {
10
+ const ops = [];
11
+ const paths = new Set([...before.keys(), ...after.keys()]);
12
+ for (const path of paths) {
13
+ const beforeEntity = before.get(path);
14
+ const afterEntity = after.get(path);
15
+ const beforeAlive = beforeEntity !== undefined && !beforeEntity.deleted;
16
+ const afterAlive = afterEntity !== undefined && !afterEntity.deleted;
17
+ // Dead on both sides: invisible either way, nothing to undo.
18
+ if (!beforeAlive && !afterAlive)
19
+ continue;
20
+ if (!beforeAlive && afterAlive) {
21
+ // L added or resurrected the entity: re-tombstone it. When it was
22
+ // resurrected AND edited, the tombstone alone is not enough — L's
23
+ // component opinions stay in the stack and would shine through a
24
+ // later resurrect, so the component loop below also restores the
25
+ // before values (a dead entity's components stay visible to the
26
+ // merge matrix).
27
+ ops.push({ op: 'tombstone-entity', path });
28
+ }
29
+ if (beforeAlive && !afterAlive) {
30
+ // L deleted it: resurrect. Keys L added before (or while)
31
+ // tombstoning are still opinions in the stack — the component loop
32
+ // reads the after-state's under-tombstone components so those keys
33
+ // land in the union and get nulled, not just the pre-delete edits.
34
+ ops.push({ op: 'resurrect-entity', path });
35
+ }
36
+ const beforeComponents = beforeEntity
37
+ ? componentEntries(beforeEntity)
38
+ : new Map();
39
+ const afterComponents = afterEntity
40
+ ? componentEntries(afterEntity)
41
+ : new Map();
42
+ const keys = new Set([...beforeComponents.keys(), ...afterComponents.keys()]);
43
+ for (const key of keys) {
44
+ const beforeAttrs = beforeComponents.get(key);
45
+ const afterAttrs = afterComponents.get(key);
46
+ const beforeHash = beforeAttrs ? snapshotOf(beforeAttrs).hash : undefined;
47
+ const afterHash = afterAttrs ? snapshotOf(afterAttrs).hash : undefined;
48
+ if (beforeHash === afterHash)
49
+ continue;
50
+ ops.push(...opsForComponentChange(path, key, afterAttrs, beforeAttrs));
51
+ }
52
+ }
53
+ return ops;
54
+ }
55
+ /** Emit an inverse-op layer that undoes `layer` on top of `base + layer`. */
56
+ export function buildRevertLayer(init) {
57
+ const before = extractStackState(init.base);
58
+ const after = extractStackState([...init.base, init.layer]);
59
+ const ops = buildInverseOps(before, after);
60
+ const manifest = createProvenanceManifest({
61
+ author: init.author,
62
+ intent: init.intent ?? `Revert layer ${init.layerId ?? init.layer.header.id}`,
63
+ base: null,
64
+ created: init.created,
65
+ parents: init.layerId ? [init.layerId] : [],
66
+ });
67
+ const bare = {
68
+ header: {
69
+ id: '',
70
+ ifcxVersion: init.layer.header.ifcxVersion,
71
+ dataVersion: init.layer.header.dataVersion,
72
+ author: init.author.principal,
73
+ timestamp: manifest.created,
74
+ },
75
+ imports: [],
76
+ schemas: {},
77
+ data: opsToNodes(ops),
78
+ };
79
+ const withManifest = setProvenance(bare, manifest);
80
+ const layerId = computeLayerId(withManifest);
81
+ return {
82
+ file: { ...withManifest, header: { ...withManifest.header, id: layerId } },
83
+ layerId,
84
+ ops,
85
+ };
86
+ }
87
+ //# sourceMappingURL=inverse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inverse.js","sourceRoot":"","sources":["../src/inverse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Resolution application and merge-layer emission.
3
+ *
4
+ * Resolutions (ours/theirs/edited per conflict) append as ops; the result
5
+ * publishes as a merge layer with `manifest.merge` filled. The candidate
6
+ * layer is never mutated; history is append-only.
7
+ */
8
+ import type { IfcxFile, IfcxNode, MergeResolution, ProvenanceAuthor, ProvenanceBase, ProvenanceCheck, WaivedCheck } from '@ifc-lite/ifcx';
9
+ import type { MergeConflict, MergeOp, MergePlan, ResolutionInput } from './types.js';
10
+ export interface AppliedResolutions {
11
+ /** Ops produced by `theirs`/`edited` choices, in conflict order. */
12
+ ops: MergeOp[];
13
+ /** Resolution records for the merge manifest (includes `ours` picks). */
14
+ resolutions: MergeResolution[];
15
+ /** Conflicts no resolution addressed. */
16
+ unresolved: MergeConflict[];
17
+ }
18
+ /**
19
+ * Turn reviewer decisions into ops. `ours` keeps the target state (no op),
20
+ * `theirs` adopts the candidate value, `edited` takes the supplied
21
+ * replacement component value (component-scoped conflicts only).
22
+ */
23
+ export declare function applyResolutions(plan: MergePlan, inputs: readonly ResolutionInput[]): AppliedResolutions;
24
+ /** Serialize ops as ordinary IFCX node opinions, one node per path. */
25
+ export declare function opsToNodes(ops: readonly MergeOp[]): IfcxNode[];
26
+ export interface MergeLayerInit {
27
+ /** Auto ops plus resolution ops, in application order. */
28
+ ops: readonly MergeOp[];
29
+ author: ProvenanceAuthor;
30
+ intent: string;
31
+ /** The state the merge layer applies on top of (the target ref's stack). */
32
+ base: ProvenanceBase | null;
33
+ merge: {
34
+ /** Candidate layer id that was merged. */
35
+ candidate: string;
36
+ /** Target ref name or stack hash. */
37
+ into: string;
38
+ resolutions: MergeResolution[];
39
+ waived_checks?: WaivedCheck[];
40
+ /** Principal who resolved the merge. */
41
+ resolver: string;
42
+ };
43
+ parents?: string[];
44
+ checks?: ProvenanceCheck[];
45
+ created?: string;
46
+ ifcxVersion?: string;
47
+ dataVersion?: string;
48
+ }
49
+ export interface PublishedMergeLayer {
50
+ file: IfcxFile;
51
+ layerId: string;
52
+ }
53
+ /**
54
+ * Emit an immutable merge layer: ops as IFCX nodes plus a provenance
55
+ * manifest with `merge` filled, content-addressed by canonical blake3.
56
+ */
57
+ export declare function buildMergeLayer(init: MergeLayerInit): PublishedMergeLayer;
58
+ //# sourceMappingURL=merge-layer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-layer.d.ts","sourceRoot":"","sources":["../src/merge-layer.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAe,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEvJ,OAAO,KAAK,EAAuB,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG1G,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,GAAG,EAAE,OAAO,EAAE,CAAC;IACf,yEAAyE;IACzE,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,yCAAyC;IACzC,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAMD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,SAAS,eAAe,EAAE,GACjC,kBAAkB,CAiDpB;AAmED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG,QAAQ,EAAE,CAwC9D;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,GAAG,EAAE,SAAS,OAAO,EAAE,CAAC;IACxB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE;QACL,0CAA0C;QAC1C,SAAS,EAAE,MAAM,CAAC;QAClB,qCAAqC;QACrC,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,eAAe,EAAE,CAAC;QAC/B,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;QAC9B,wCAAwC;QACxC,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,mBAAmB,CAoCzE"}