@neocompose/cli 0.89.12 → 0.89.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.89.13
4
+
5
+ ### Patch Changes
6
+
7
+ - ca52724: Keep named aggregate values and their descendants at the same identities when owning collections are edited before the first push. Local exports no longer give an inserted value the identity of a different named value, and push retains the exported identities. Aliases share their terminal declaration; scalar locals keep independent owning occurrences. Constructor-backed owners preserve these identities through computed arguments, nested named values, and unordered collections without changing constructor execution.
8
+
9
+ Unpushed named values from earlier local exports receive new identity reservations. Saves tied to the earlier provisional IDs may need to be recreated.
10
+
3
11
  ## 0.89.12
4
12
 
5
13
  ### Patch Changes
@@ -19377,7 +19377,7 @@ var init_registry = __esm({
19377
19377
  "../packages/manifest/schema-contract/registry.mjs"() {
19378
19378
  "use strict";
19379
19379
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
19380
- cliVersion: "0.89.12",
19380
+ cliVersion: "0.89.13",
19381
19381
  projectFileUploadBatchSize: 32,
19382
19382
  documentRecords: {
19383
19383
  member: {
@@ -25194,6 +25194,10 @@ function* staticMembersInitializedByName(analysis, syntax) {
25194
25194
  }
25195
25195
  }
25196
25196
  }
25197
+ function pendingLocalValueId(global) {
25198
+ const source = global.source;
25199
+ return `__pending__:value:${encodeURIComponent(source.uri)}:${source.range.start.line}:${source.range.start.character}:${encodeURIComponent(global.name)}`;
25200
+ }
25197
25201
  function typeText(type2) {
25198
25202
  return type2.name + (type2.arguments.length === 0 ? "" : `<${type2.arguments.map(typeText).join(", ")}>`) + (type2.nullable ? "?" : "");
25199
25203
  }
@@ -25243,6 +25247,7 @@ var init_local_values = __esm({
25243
25247
  resolve(expression, source, valueId) {
25244
25248
  if (expression.kind !== "ident") return { expression, source };
25245
25249
  let text;
25250
+ let pendingIdentity;
25246
25251
  for (const step of this.chain(expression.name)) {
25247
25252
  const global = step.global;
25248
25253
  if (valueId !== void 0) {
@@ -25264,8 +25269,9 @@ var init_local_values = __esm({
25264
25269
  source: global.source,
25265
25270
  label: global.name
25266
25271
  };
25272
+ pendingIdentity = this.scalarTypes.has(global.type.name) ? void 0 : pendingLocalValueId(global);
25267
25273
  }
25268
- return { expression, source, text };
25274
+ return { expression, source, text, pendingIdentity };
25269
25275
  }
25270
25276
  /**
25271
25277
  * The expression and text a bare local name stands for, through any alias
@@ -25303,7 +25309,7 @@ var init_local_values = __esm({
25303
25309
  * Compile authoring locals without introducing runtime globals. The splices
25304
25310
  * are the uses of `code` this replaced.
25305
25311
  */
25306
- executable(code, runtimeIdentifiers = /* @__PURE__ */ new Set(), materializationRoot, identity3, storedValueAtPath) {
25312
+ executable(code, runtimeIdentifiers = /* @__PURE__ */ new Set(), materializationRoot, identity3) {
25307
25313
  if (this.definitions.size === 0 || !mayUseLocalInitializer(code, this.definitions))
25308
25314
  return { code, splices: [] };
25309
25315
  const terminalName = (name) => {
@@ -25380,23 +25386,40 @@ var init_local_values = __esm({
25380
25386
  const annotation2 = terminal2.expression.kind === "annotated" ? terminal2.expression.annotations.find(
25381
25387
  (entry) => entry.name === "id"
25382
25388
  )?.args[0] : void 0;
25383
- const existingId = storedValueAtPath?.(
25384
- materializationRoot,
25385
- placementPath
25386
- );
25387
- if (annotation2?.kind === "litString" && existingId !== annotation2.value) {
25388
- throw new Error(
25389
- `Local initializer ${terminal2.global.name} has an @id that does not identify its existing row inside this constructor-backed owner. Remove that @id and let preparation assign the owning tree, or place the value directly in its own static member.`
25390
- );
25391
- }
25392
25389
  const source = terminal2.global.source;
25393
25390
  const suffix = this.scalarTypes.has(terminal2.global.type.name) ? `:${encodeURIComponent(JSON.stringify([materializationRoot, placementPath]))}` : "";
25394
- const id2 = annotation2?.kind === "litString" ? annotation2.value : `__pending__:value:${encodeURIComponent(source.uri)}:${source.range.start.line}:${source.range.start.character}:${encodeURIComponent(terminal2.global.name)}${suffix}`;
25391
+ const id2 = annotation2?.kind === "litString" ? annotation2.value : `${pendingLocalValueId(terminal2.global)}${suffix}`;
25392
+ if (annotation2?.kind === "litString")
25393
+ identity3?.validateAuthoredId?.(id2);
25395
25394
  for (const { global } of steps) {
25396
25395
  const owners = this.owners.get(global.name) ?? /* @__PURE__ */ new Map();
25397
- owners.set(existingId ?? id2, global.name);
25396
+ owners.set(id2, global.name);
25398
25397
  this.owners.set(global.name, owners);
25399
25398
  }
25399
+ const normalizeLocation = (rootId, path2) => {
25400
+ const seen = /* @__PURE__ */ new Set();
25401
+ let location4 = { rootId, path: path2 };
25402
+ while (!seen.has(location4.rootId)) {
25403
+ seen.add(location4.rootId);
25404
+ const parent = identity3?.sites.get(location4.rootId)?.materializedLocation ?? identity3?.storedParent?.(location4.rootId);
25405
+ if (parent === void 0) break;
25406
+ location4 = {
25407
+ rootId: parent.rootId,
25408
+ path: [...parent.path, ...location4.path]
25409
+ };
25410
+ }
25411
+ return location4;
25412
+ };
25413
+ const location3 = normalizeLocation(
25414
+ materializationRoot,
25415
+ placementPath
25416
+ );
25417
+ const prior = identity3?.sites.get(id2)?.materializedLocation;
25418
+ const priorLocation = prior === void 0 ? void 0 : normalizeLocation(prior.rootId, prior.path);
25419
+ if (priorLocation !== void 0 && (priorLocation.rootId !== location3.rootId || JSON.stringify(priorLocation.path) !== JSON.stringify(location3.path)))
25420
+ throw new Error(
25421
+ `Local value ${terminal2.global.name} has two owning assignments. Use Reference(${terminal2.global.name}) for a reference, or duplicate its initializer.`
25422
+ );
25400
25423
  identity3?.sites.set(id2, {
25401
25424
  id: id2,
25402
25425
  uri: source.uri,
@@ -25406,8 +25429,10 @@ var init_local_values = __esm({
25406
25429
  stampForm: 0 /* Prefix */,
25407
25430
  nestedListEntries: identity3.localListEntries(terminal2.global),
25408
25431
  materializedLocation: {
25409
- rootId: materializationRoot,
25410
- path: placementPath
25432
+ preserveIdentity: !this.scalarTypes.has(
25433
+ terminal2.global.type.name
25434
+ ),
25435
+ ...location3
25411
25436
  },
25412
25437
  stampIdentity: annotation2 === void 0 && !this.scalarTypes.has(terminal2.global.type.name)
25413
25438
  });
@@ -51098,6 +51123,13 @@ function applyConstructorFields(args) {
51098
51123
  let kept = 0;
51099
51124
  for (const row of createdValues) {
51100
51125
  if (row.id === keptId || row.containerId === keptId) {
51126
+ if (row.containerId === keptId) {
51127
+ if (ctx.__indexes !== void 0)
51128
+ unindexEvaluatorRow(ctx.__indexes, row);
51129
+ delete row.containerId;
51130
+ if (ctx.__indexes !== void 0)
51131
+ indexEvaluatorRow(ctx.__indexes, row);
51132
+ }
51101
51133
  createdById.delete(row.id);
51102
51134
  continue;
51103
51135
  }
@@ -54309,6 +54341,9 @@ function materializeConstructorArgumentValue(args) {
54309
54341
  for (const entry of rows) sourceEntries.push(entry.value);
54310
54342
  }
54311
54343
  const ids = [];
54344
+ const authoredEntries = args.ctx.__constructionEntryIds === void 0 ? void 0 : [];
54345
+ if (authoredEntries !== void 0)
54346
+ args.ctx.__constructionEntryIds?.set(row.id, authoredEntries);
54312
54347
  const references = recordedReferenceEntries(sourceEntries, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(sourceEntries, args.ctx));
54313
54348
  for (const [index, rawEntry] of sourceEntries.entries()) {
54314
54349
  if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, index) && typeof rawEntry === "string" && evalValueById(
@@ -54318,6 +54353,7 @@ function materializeConstructorArgumentValue(args) {
54318
54353
  args.ctx.__valueOverlay
54319
54354
  ) !== null) {
54320
54355
  ids.push(rawEntry);
54356
+ authoredEntries?.push(rawEntry);
54321
54357
  continue;
54322
54358
  }
54323
54359
  const entryValue = constructorCollectionEntryValue(
@@ -54339,6 +54375,7 @@ function materializeConstructorArgumentValue(args) {
54339
54375
  },
54340
54376
  destinationName: `${args.member.name}[${index}]`
54341
54377
  });
54378
+ authoredEntries?.push(child2.id);
54342
54379
  if (listKindOf(args.member) === 1 /* Unordered */) {
54343
54380
  child2.containerId = row.id;
54344
54381
  } else {
@@ -57427,7 +57464,16 @@ var init_constructor_argument_ownership = __esm({
57427
57464
  ownershipFacts() {
57428
57465
  if (this.ownership !== void 0) return this.ownership;
57429
57466
  const targetValueIds = new Set(this.valuesById.keys());
57430
- const owners = resolveOwnerMembersForValues(this.document, targetValueIds);
57467
+ const owners = resolveOwnerMembersForValues(
57468
+ this.document,
57469
+ targetValueIds,
57470
+ [...this.contextualRootMembersByValueId ?? []].map(
57471
+ ([valueId, member]) => ({
57472
+ valueId,
57473
+ member: resolveMember(member, this.document.members)
57474
+ })
57475
+ )
57476
+ );
57431
57477
  this.ownership = {
57432
57478
  owners,
57433
57479
  independentlyOwnedValueIds: new Set(owners.keys())
@@ -57750,6 +57796,7 @@ function evaluateInitializerMaterialization(args) {
57750
57796
  const createdValues = [];
57751
57797
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
57752
57798
  const evaluated = args.evaluateInitializer({
57799
+ constructionEntryIds: args.constructionEntryIds,
57753
57800
  randomSource: args.randomSource,
57754
57801
  genericEnv: args.genericEnv,
57755
57802
  init: args.init,
@@ -57829,7 +57876,9 @@ function finalizeMaterializedRoot(args) {
57829
57876
  });
57830
57877
  }
57831
57878
  function materializeInitializerValue(args) {
57879
+ const constructionEntryIds = args.captureConstructionEntries ? /* @__PURE__ */ new Map() : void 0;
57832
57880
  const { evaluated, createdValues, storageKeyDeclarations } = evaluateInitializerMaterialization({
57881
+ constructionEntryIds,
57833
57882
  randomSource: args.randomSource,
57834
57883
  evaluateInitializer: args.evaluateInitializer,
57835
57884
  init: args.row.init,
@@ -57881,6 +57930,7 @@ function materializeInitializerValue(args) {
57881
57930
  return {
57882
57931
  root,
57883
57932
  createdValues,
57933
+ constructionEntryIds,
57884
57934
  snapshot: evaluated.snapshot,
57885
57935
  pinnedRootSchemaKeys: evaluated.pinnedRootSchemaKeys ?? /* @__PURE__ */ new Set(),
57886
57936
  pinnedSchemaKeysByValueId: evaluated.pinnedSchemaKeysByValueId ?? /* @__PURE__ */ new Map()
@@ -58598,7 +58648,7 @@ function buildVirtualInstanceMaterializedIndex(args) {
58598
58648
  return {
58599
58649
  rows,
58600
58650
  rowsById,
58601
- graph: new MaterializedValueGraphContext(
58651
+ graph: args.materializedGraph ?? new MaterializedValueGraphContext(
58602
58652
  { ...args.document, values: rows },
58603
58653
  rowsById
58604
58654
  ),
@@ -59081,7 +59131,9 @@ function resolveVirtualInstanceGraph(args) {
59081
59131
  if (parent !== void 0 && isMemberEntryCollectionBase(parent.member) && listKindOf(parent.member) === 1 /* Unordered */)
59082
59132
  effective.containerId = parentId;
59083
59133
  }
59084
- if (isClassSlotMember(indexed.member) && effective.value !== null) {
59134
+ if (args.opaquePaths?.has(pathKey)) {
59135
+ effective.value = materialized?.value ?? indexed.expandedRow.value;
59136
+ } else if (isClassSlotMember(indexed.member) && effective.value !== null) {
59085
59137
  const storedRecord = stringRecord(materialized?.value);
59086
59138
  const classId = rowClassId(indexed.member, effective);
59087
59139
  const constructedChildren = materialized === null ? /* @__PURE__ */ new Map() : settledAggregateChildren(materialized, classId, pathKey);
@@ -60671,6 +60723,16 @@ function keptRowReason(facts) {
60671
60723
  if (!facts.defaultEqual) return "provenanceOnly";
60672
60724
  return "pinnedOrReference";
60673
60725
  }
60726
+ function indexAuthoredConstructionIdentities(locations) {
60727
+ const byRoot = /* @__PURE__ */ new Map();
60728
+ for (const [id2, location3] of locations) {
60729
+ if (!location3.preserveIdentity) continue;
60730
+ const entries = byRoot.get(location3.rootId) ?? [];
60731
+ entries.push({ id: id2, path: location3.path });
60732
+ byRoot.set(location3.rootId, entries);
60733
+ }
60734
+ return byRoot;
60735
+ }
60674
60736
  function sparsifyConstructedInstance(args) {
60675
60737
  const materializedRows = [
60676
60738
  args.constructed.root,
@@ -60685,18 +60747,107 @@ function sparsifyConstructedInstance(args) {
60685
60747
  new Map(materializedRows.map((row) => [row.id, row])),
60686
60748
  /* @__PURE__ */ new Map([[args.constructed.root.id, args.rootMember]])
60687
60749
  );
60750
+ const anchors = /* @__PURE__ */ new Map();
60751
+ const authoredIds = /* @__PURE__ */ new Set();
60752
+ for (const identity3 of args.authoredIdentities ?? []) {
60753
+ let row = args.constructed.root;
60754
+ for (const segment of identity3.path) {
60755
+ const payload = row.value;
60756
+ let childId;
60757
+ if (Array.isArray(payload) && typeof segment === "number")
60758
+ childId = args.constructionEntryIds?.get(row.id)?.[segment] ?? payload[segment];
60759
+ else if (isObjectRecord(payload)) childId = payload[String(segment)];
60760
+ if (typeof childId !== "string")
60761
+ throw new Error(
60762
+ `Named construction ${identity3.id} has no value at ${JSON.stringify(identity3.path)}.`
60763
+ );
60764
+ const child2 = materializedGraph.valuesById.get(childId);
60765
+ if (child2 === void 0)
60766
+ throw new Error(
60767
+ `Named construction ${identity3.id} points to missing child ${childId}.`
60768
+ );
60769
+ row = child2;
60770
+ }
60771
+ if (anchors.has(row.id))
60772
+ throw new Error(`Constructed row ${row.id} has multiple named owners.`);
60773
+ if (authoredIds.has(identity3.id))
60774
+ throw new Error(
60775
+ `Named construction identity ${identity3.id} has multiple owning placements.`
60776
+ );
60777
+ if (identity3.id !== row.id && materializedGraph.valuesById.has(identity3.id))
60778
+ throw new Error(
60779
+ `Named construction identity ${identity3.id} collides with another constructed row.`
60780
+ );
60781
+ anchors.set(row.id, identity3.id);
60782
+ authoredIds.add(identity3.id);
60783
+ }
60784
+ const rootId = args.constructed.root.id;
60785
+ const boundaries = /* @__PURE__ */ new Map();
60786
+ const namedPaths = namedConstructionPaths(
60787
+ materializedGraph,
60788
+ new Map([[rootId, rootId], ...anchors]),
60789
+ args.constructionEntryIds,
60790
+ boundaries
60791
+ );
60792
+ const materializedIndex = buildVirtualInstanceMaterializedIndex({
60793
+ document: args.document,
60794
+ materializedRows,
60795
+ materializedGraph
60796
+ });
60688
60797
  const graph = resolveVirtualInstanceGraph({
60689
60798
  document: args.document,
60690
60799
  instanceRoot: args.constructed.root,
60691
60800
  rootMember: args.rootMember,
60692
60801
  expandedRoot: args.baseline.root,
60693
60802
  expandedRows: [args.baseline.root, ...args.baseline.createdChildren],
60694
- materializedRows,
60695
- materializedGraph
60696
- });
60697
- const protectedValueIds = /* @__PURE__ */ new Set();
60803
+ materializedIndex,
60804
+ materializedGraph,
60805
+ opaquePaths: boundaries.get(rootId)
60806
+ });
60807
+ const namedClaims = /* @__PURE__ */ new Map();
60808
+ const namedIds2 = /* @__PURE__ */ new Map();
60809
+ const scopedId = (rowId) => {
60810
+ const anchor = anchors.get(rowId);
60811
+ if (anchor !== void 0) return anchor;
60812
+ const cached = namedIds2.get(rowId);
60813
+ if (cached !== void 0) return cached;
60814
+ const scope = namedPaths.get(rowId);
60815
+ if (scope === void 0 || scope.id === rootId) return void 0;
60816
+ const relativePath = scope.path;
60817
+ const claims = namedClaims.get(scope.id) ?? /* @__PURE__ */ new Map();
60818
+ namedClaims.set(scope.id, claims);
60819
+ const claimed = claimVirtualIdentity({
60820
+ claimedVirtualIds: claims,
60821
+ instanceRootId: scope.id,
60822
+ rawSourceIdentity: `materialized:${relativePath}`,
60823
+ pathKey: relativePath
60824
+ });
60825
+ const id2 = args.virtualValueIdForSource?.(scope.id, claimed.sourceIdentity) ?? claimed.virtualId;
60826
+ namedIds2.set(rowId, id2);
60827
+ return id2;
60828
+ };
60829
+ const namedRootIds = new Set(anchors.keys());
60830
+ const protectedValueIds = new Set(namedRootIds);
60698
60831
  if (args.snapshot)
60699
60832
  for (const row of materializedRows) protectedValueIds.add(row.id);
60833
+ const pinNamedTarget = (id2) => {
60834
+ const scope = namedPaths.get(id2);
60835
+ if (scope !== void 0 && scope.id !== rootId) protectedValueIds.add(id2);
60836
+ };
60837
+ if (anchors.size > 0) {
60838
+ for (const row of materializedRows) {
60839
+ const owner = materializedGraph.ownerForValue(row.id);
60840
+ if (owner?.kind === 9 /* Lookup */)
60841
+ for (const id2 of materializedGraph.referencedValueIds(row))
60842
+ pinNamedTarget(id2);
60843
+ if (owner?.kind === 25 /* NSDelegate */ && isMemberDelegateTarget(row.value)) {
60844
+ if (typeof row.value.valueId === "string")
60845
+ pinNamedTarget(row.value.valueId);
60846
+ }
60847
+ for (const id2 of materializedGraph.referenceArgumentIds(row))
60848
+ pinNamedTarget(id2);
60849
+ }
60850
+ }
60700
60851
  const localizedTextIds = args.localizedTextIds ?? new Set(args.document.localizedTexts?.map((text) => text.id));
60701
60852
  for (const location3 of graph.locationsByPath.values()) {
60702
60853
  const row = location3.materializedRow;
@@ -60738,11 +60889,13 @@ function sparsifyConstructedInstance(args) {
60738
60889
  for (const childId of materializedGraph.referencedValueIds(row))
60739
60890
  pinArgumentFields(childId);
60740
60891
  };
60741
- for (const edge of materializedGraph.constructorEdges(
60742
- args.constructed.root
60743
- )) {
60744
- protectArgument(edge.targetValueId, edge.typeInfo);
60745
- pinArgumentFields(edge.targetValueId);
60892
+ for (const id2 of [args.constructed.root.id, ...anchors.keys()]) {
60893
+ for (const edge of materializedGraph.constructorEdges(
60894
+ materializedGraph.valuesById.get(id2)
60895
+ )) {
60896
+ protectArgument(edge.targetValueId, edge.typeInfo);
60897
+ pinArgumentFields(edge.targetValueId);
60898
+ }
60746
60899
  }
60747
60900
  for (const schemaKey of args.pinnedRootSchemaKeys ?? []) {
60748
60901
  const location3 = graph.locationsByPath.get(
@@ -60752,8 +60905,30 @@ function sparsifyConstructedInstance(args) {
60752
60905
  protectedValueIds.add(location3.materializedRow.id);
60753
60906
  }
60754
60907
  }
60755
- const rootId = args.constructed.root.id;
60756
- const locationValueId = (location3) => args.virtualValueIdForSource?.(rootId, location3.sourceIdentity) ?? location3.virtualRow.id;
60908
+ const pinnedNamedCalls = /* @__PURE__ */ new Set();
60909
+ const pinNamedCallFields = (id2) => {
60910
+ if (pinnedNamedCalls.has(id2)) return;
60911
+ pinnedNamedCalls.add(id2);
60912
+ const row = materializedGraph.valuesById.get(id2);
60913
+ if (row === void 0) return;
60914
+ const member = materializedGraph.ownerForValue(id2);
60915
+ if (member !== void 0 && (isMemberEntryCollectionBase(member) || isMemberDictionaryBase(member) || isMemberTupleBase(member))) {
60916
+ for (const child2 of materializedGraph.referencedValueIds(row))
60917
+ pinNamedCallFields(child2);
60918
+ for (const child2 of materializedGraph.childrenByContainerId.get(id2) ?? [])
60919
+ pinNamedCallFields(child2.id);
60920
+ return;
60921
+ }
60922
+ if (!isObjectRecord(row.value)) return;
60923
+ for (const key of args.pinnedSchemaKeysByValueId?.get(id2) ?? []) {
60924
+ const child2 = row.value[key];
60925
+ if (typeof child2 !== "string") continue;
60926
+ protectedValueIds.add(child2);
60927
+ pinNamedCallFields(child2);
60928
+ }
60929
+ };
60930
+ for (const id2 of anchors.keys()) pinNamedCallFields(id2);
60931
+ const locationValueId = (location3) => (location3.materializedRow === null ? void 0 : scopedId(location3.materializedRow.id)) ?? args.virtualValueIdForSource?.(rootId, location3.sourceIdentity) ?? location3.virtualRow.id;
60757
60932
  if (args.bindingTargets !== void 0)
60758
60933
  pinReferencedSlots(
60759
60934
  graph,
@@ -60766,7 +60941,8 @@ function sparsifyConstructedInstance(args) {
60766
60941
  try {
60767
60942
  plan = planCollapseVirtualInstance({
60768
60943
  graph,
60769
- pinnedValueIds: protectedValueIds
60944
+ pinnedValueIds: protectedValueIds,
60945
+ nestedRootValueIds: namedRootIds
60770
60946
  });
60771
60947
  } catch (error) {
60772
60948
  if (!(error instanceof OpenGenericComparisonError)) throw error;
@@ -60776,6 +60952,59 @@ function sparsifyConstructedInstance(args) {
60776
60952
  const updatedValueById = new Map(
60777
60953
  plan.updates.map((update) => [update.valueId, update.value])
60778
60954
  );
60955
+ if (!args.snapshot) {
60956
+ for (const [rowId, authoredId] of anchors) {
60957
+ const root2 = materializedGraph.valuesById.get(rowId);
60958
+ const placement = materializedGraph.ownerForValue(rowId);
60959
+ if (placement === void 0)
60960
+ throw new Error(
60961
+ `Named construction ${authoredId} has no typed owning placement.`
60962
+ );
60963
+ const member = storedClassResolutionMember(
60964
+ placement,
60965
+ root2,
60966
+ args.document.members
60967
+ );
60968
+ if (member === null) continue;
60969
+ if (args.expandNamedRoot === void 0)
60970
+ throw new Error(
60971
+ "Named Class preparation requires its own construction expansion."
60972
+ );
60973
+ const baseline = args.expandNamedRoot(root2, member, materializedRows);
60974
+ const ownGraph = resolveVirtualInstanceGraph({
60975
+ document: args.document,
60976
+ instanceRoot: root2,
60977
+ rootMember: member,
60978
+ expandedRoot: baseline.root,
60979
+ expandedRows: baseline.rows,
60980
+ pinnedRootSchemaKeys: args.pinnedSchemaKeysByValueId?.get(rowId),
60981
+ materializedIndex,
60982
+ materializedGraph,
60983
+ opaquePaths: boundaries.get(authoredId)
60984
+ });
60985
+ for (const location3 of ownGraph.locationsByPath.values()) {
60986
+ const row = location3.materializedRow;
60987
+ if (row !== null && isMemberStringBase(location3.member) && isLocalizedStringMember(location3.member) && typeof row.value === "string" && row.value !== "" && !localizedTextIds.has(row.value))
60988
+ protectedValueIds.add(row.id);
60989
+ }
60990
+ if (args.bindingTargets !== void 0)
60991
+ pinReferencedSlots(
60992
+ ownGraph,
60993
+ authoredId,
60994
+ args.bindingTargets,
60995
+ locationValueId,
60996
+ protectedValueIds
60997
+ );
60998
+ const ownPlan = planCollapseVirtualInstance({
60999
+ graph: ownGraph,
61000
+ pinnedValueIds: protectedValueIds,
61001
+ nestedRootValueIds: namedRootIds
61002
+ });
61003
+ for (const id2 of ownPlan.deletes) deletedIds.add(id2);
61004
+ for (const update of ownPlan.updates)
61005
+ updatedValueById.set(update.valueId, update.value);
61006
+ }
61007
+ }
60779
61008
  restoreRowsRetainedRowsName(
60780
61009
  materializedGraph,
60781
61010
  materializedRows,
@@ -60797,6 +61026,10 @@ function sparsifyConstructedInstance(args) {
60797
61026
  );
60798
61027
  }
60799
61028
  nextIdById.set(args.constructed.root.id, args.constructed.root.id);
61029
+ for (const row of retainedRows) {
61030
+ const id2 = scopedId(row.id);
61031
+ if (id2 !== void 0) nextIdById.set(row.id, id2);
61032
+ }
60800
61033
  const unmappedRows = retainedRows.filter((row) => !nextIdById.has(row.id));
60801
61034
  const fallbackRows = (unmappedRows.length === 0 ? [] : (() => {
60802
61035
  const fallbackPaths = materializedFallbackPaths(
@@ -60812,6 +61045,11 @@ function sparsifyConstructedInstance(args) {
60812
61045
  (left, right) => left.path.localeCompare(right.path) || left.row.id.localeCompare(right.row.id)
60813
61046
  );
60814
61047
  for (const { row, path } of fallbackRows) {
61048
+ const namedId = scopedId(row.id);
61049
+ if (namedId !== void 0) {
61050
+ nextIdById.set(row.id, namedId);
61051
+ continue;
61052
+ }
60815
61053
  const rawSourceIdentity = typeof row.sourceValueId === "string" && row.sourceValueId.length > 0 ? row.sourceValueId : `materialized:${path}`;
60816
61054
  const { sourceIdentity: sourceIdentity3, virtualId } = claimVirtualIdentity({
60817
61055
  claimedVirtualIds,
@@ -60832,6 +61070,8 @@ function sparsifyConstructedInstance(args) {
60832
61070
  if (retainedId !== void 0) return retainedId;
60833
61071
  const receiver = graph.locationsById.get(id2);
60834
61072
  if (receiver === void 0) return id2;
61073
+ const named = scopedId(id2);
61074
+ if (named !== void 0) return named;
60835
61075
  return args.virtualValueIdForSource?.(
60836
61076
  args.constructed.root.id,
60837
61077
  receiver.sourceIdentity
@@ -60899,6 +61139,54 @@ function restoreRowsRetainedRowsName(materializedGraph, rows, updatedValueById,
60899
61139
  restore(valueId);
60900
61140
  }
60901
61141
  }
61142
+ function namedConstructionPaths(graph, anchors, entries, boundaries) {
61143
+ const paths = /* @__PURE__ */ new Map();
61144
+ const queue = [];
61145
+ for (const [rowId, id2] of anchors) {
61146
+ paths.set(rowId, { id: id2, path: ROOT_PATH });
61147
+ queue.push(rowId);
61148
+ }
61149
+ if (queue.length === 0) return paths;
61150
+ const add = (childId, scope, segment) => {
61151
+ if (typeof childId !== "string" || !graph.valuesById.has(childId)) return;
61152
+ const path = appendVirtualValuePath(scope.path, segment);
61153
+ if (anchors.has(childId)) {
61154
+ const paths2 = boundaries.get(scope.id) ?? /* @__PURE__ */ new Set();
61155
+ paths2.add(path);
61156
+ boundaries.set(scope.id, paths2);
61157
+ return;
61158
+ }
61159
+ if (paths.has(childId)) return;
61160
+ paths.set(childId, { id: scope.id, path });
61161
+ queue.push(childId);
61162
+ };
61163
+ for (let index = 0; index < queue.length; index++) {
61164
+ const rowId = queue[index];
61165
+ const row = graph.valuesById.get(rowId);
61166
+ const scope = paths.get(rowId);
61167
+ if (row === void 0) continue;
61168
+ const member = graph.ownerForValue(rowId);
61169
+ if (Array.isArray(row.value) && member !== void 0 && (isMemberEntryCollectionBase(member) || isMemberTupleBase(member))) {
61170
+ const children3 = entries?.get(rowId) ?? (row.value.length > 0 ? row.value : graph.childrenByContainerId.get(rowId)?.map((child2) => child2.id) ?? []);
61171
+ children3.forEach((id2, index2) => add(id2, scope, { kind: "list", index: index2 }));
61172
+ } else if (isObjectRecord(row.value) && (typeof row.classId === "string" || member !== void 0 && (isClassSlotMember(member) || isMemberDictionaryBase(member)))) {
61173
+ for (const [schemaKey, id2] of Object.entries(row.value))
61174
+ add(
61175
+ id2,
61176
+ scope,
61177
+ member !== void 0 && isMemberDictionaryBase(member) ? { kind: "dictionary", key: schemaKey } : { kind: "class", schemaKey }
61178
+ );
61179
+ }
61180
+ for (const edge of graph.edgesByOwnerValueId.get(rowId) ?? []) {
61181
+ if (graph.independentlyOwnedValueIds.has(edge.targetValueId)) continue;
61182
+ add(edge.targetValueId, scope, {
61183
+ kind: "class",
61184
+ schemaKey: `@constructor:${edge.parameterId}`
61185
+ });
61186
+ }
61187
+ }
61188
+ return paths;
61189
+ }
60902
61190
  function materializedFallbackPaths(rows, graph, materializedGraph) {
60903
61191
  const rowsById = new Map(rows.map((row) => [row.id, row]));
60904
61192
  const unorderedEntriesByContainerId = buildUnorderedListMembershipIndex(rows);
@@ -61082,6 +61370,7 @@ function indexExpansion(args) {
61082
61370
  discoveredNodes?.push(node);
61083
61371
  nodesByPath.set(pathKey, node);
61084
61372
  appendChildPath(parentPath, pathKey);
61373
+ if (args.opaquePaths?.has(pathKey)) return;
61085
61374
  if (isClassTypedMember(member)) {
61086
61375
  const record7 = stringRecord(row.value);
61087
61376
  const classId = row.classId ?? member.classId;
@@ -64044,6 +64333,7 @@ function evaluateMemberInitializer(args) {
64044
64333
  );
64045
64334
  const compiled = compileMemberInitializer(args, databaseVM);
64046
64335
  const ctx = {
64336
+ __constructionEntryIds: args.constructionEntryIds,
64047
64337
  randomSource: args.randomSource,
64048
64338
  randomIdentity,
64049
64339
  ...args.sessionValues === void 0 ? {} : { __runtimeSessionValues: args.sessionValues },
@@ -118624,6 +118914,43 @@ function storedValueAtPathV4(rows, rootId, path) {
118624
118914
  }
118625
118915
  return id2;
118626
118916
  }
118917
+ function storedValueOwnsPathV4(records3, rows, ownerForValue) {
118918
+ const placements = buildStoredValuePlacementIndexV4(records3, rows);
118919
+ const parents = /* @__PURE__ */ new Map();
118920
+ for (const [id2, edge] of placements.placementByChildValueId)
118921
+ parents.set(id2, { id: edge.parentValueId, key: edge.schemaKey });
118922
+ for (const [id2, row] of rows) {
118923
+ if (typeof row.containerId === "string")
118924
+ parents.set(id2, { id: row.containerId, key: null });
118925
+ }
118926
+ for (const [id2, row] of rows) {
118927
+ if (!Array.isArray(row.value)) continue;
118928
+ const owner = ownerForValue(id2);
118929
+ if (owner === void 0) continue;
118930
+ if (!isMemberEntryCollectionBase(owner) && !isMemberTupleBase(owner))
118931
+ continue;
118932
+ row.value.forEach((child2, index) => {
118933
+ if (typeof child2 !== "string") return;
118934
+ const container = rows.get(child2)?.containerId;
118935
+ if (container !== void 0 && container !== id2) return;
118936
+ if (container === void 0 && parents.has(child2)) return;
118937
+ parents.set(child2, { id: id2, key: index });
118938
+ });
118939
+ }
118940
+ return (rootId, path, valueId) => {
118941
+ let id2 = valueId;
118942
+ for (let index = path.length - 1; index >= 0; index--) {
118943
+ const parent = parents.get(id2);
118944
+ if (parent === void 0) return false;
118945
+ const key = path[index];
118946
+ if (parent.key === null) {
118947
+ if (typeof key !== "number") return false;
118948
+ } else if (parent.key !== key) return false;
118949
+ id2 = parent.id;
118950
+ }
118951
+ return id2 === rootId;
118952
+ };
118953
+ }
118627
118954
  function buildStoredValuePlacementIndexV4(records3, logicalValues) {
118628
118955
  const live = [...records3].filter((record7) => record7.deleted !== true);
118629
118956
  const values = logicalValues ?? storedValueRowsByIdV4(live);
@@ -123566,6 +123893,14 @@ var init_project_migration_member_listeners = __esm({
123566
123893
  });
123567
123894
 
123568
123895
  // ../packages/neoscript-runtime/src/virtual-instance-values.ts
123896
+ function expandStoredClassValue2(args) {
123897
+ return expandStoredClassValue({
123898
+ ...args,
123899
+ evaluateInitializer: evaluateMemberInitializer,
123900
+ materializeInitializerValue,
123901
+ materializeMemberDefaultValue: materializeMemberDefaultValue2
123902
+ });
123903
+ }
123569
123904
  function expandStoredInstance2(args) {
123570
123905
  return expandStoredInstance({
123571
123906
  ...args,
@@ -123599,9 +123934,52 @@ function resolveStoredClassValue2(args) {
123599
123934
  materializeMemberDefaultValue: materializeMemberDefaultValue2
123600
123935
  });
123601
123936
  }
123937
+ function sparsifyConstructedInstance2(args) {
123938
+ let document;
123939
+ return sparsifyConstructedInstance({
123940
+ ...args,
123941
+ expandNamedRoot: (instanceRoot, rootMember, materializedRows) => {
123942
+ if (document === void 0) {
123943
+ if (!("project" in args.document))
123944
+ throw new Error(
123945
+ "Named Class preparation requires the project evaluation context."
123946
+ );
123947
+ const base = args.document;
123948
+ const baseRows = initializerEvaluatorLookups(base).evaluatorIndexes?.valueById ?? new Map(base.values.map((row) => [row.id, row]));
123949
+ const rows = new Map(materializedRows.map((row) => [row.id, row]));
123950
+ const valuesById = new OverlayReadonlyMap(baseRows, rows, /* @__PURE__ */ new Set());
123951
+ const values = lazyArray(() => valuesById.values());
123952
+ const changedContainerIds = new Set(rows.keys());
123953
+ for (const row of rows.values())
123954
+ if (row.containerId) changedContainerIds.add(row.containerId);
123955
+ document = {
123956
+ ...base,
123957
+ databaseVM: void 0,
123958
+ indexedView: void 0,
123959
+ evaluatorCache: void 0,
123960
+ worldQueryCache: void 0,
123961
+ values,
123962
+ valueById: (id2) => valuesById.get(id2) ?? null,
123963
+ evaluatorOverlay: {
123964
+ base,
123965
+ rows,
123966
+ hiddenIds: /* @__PURE__ */ new Set(),
123967
+ changedContainerIds,
123968
+ values,
123969
+ valuesById,
123970
+ containerMembership: "merge"
123971
+ }
123972
+ };
123973
+ }
123974
+ return expandStoredClassValue2({ document, instanceRoot, rootMember });
123975
+ }
123976
+ });
123977
+ }
123602
123978
  var init_virtual_instance_values = __esm({
123603
123979
  "../packages/neoscript-runtime/src/virtual-instance-values.ts"() {
123604
123980
  "use strict";
123981
+ init_overlay_readonly_map();
123982
+ init_lazy_array();
123605
123983
  init_initializer_materialization();
123606
123984
  init_evaluateInitializer();
123607
123985
  init_virtual_instance_graph();
@@ -148047,6 +148425,7 @@ function* prepareServerOwnedSchemaCommitPasses(args) {
148047
148425
  });
148048
148426
  materializePreparedInstanceInitializers({
148049
148427
  referenceOwners: args.initializerReferenceOwners,
148428
+ constructionIdentities: args.constructionIdentities,
148050
148429
  document: args.document,
148051
148430
  physicalValues: args.document.physicalValues,
148052
148431
  prepared,
@@ -148422,6 +148801,7 @@ function materializePreparedInstanceInitializers(args) {
148422
148801
  }
148423
148802
  const materialized = replay(
148424
148803
  (readTracking) => materializeInitializerValue2({
148804
+ captureConstructionEntries: args.constructionIdentities?.has(valueId),
148425
148805
  readTracking,
148426
148806
  // Every site that survives the declaration-default guard is source for
148427
148807
  // a persisted instance construction. The trusted replay mode both
@@ -148485,9 +148865,12 @@ function materializePreparedInstanceInitializers(args) {
148485
148865
  constructionBaselineReplay: true,
148486
148866
  storedConstructionReplay: true
148487
148867
  });
148488
- const sparse2 = sparsifyConstructedInstance({
148868
+ const authoredIdentities = args.constructionIdentities?.get(valueId);
148869
+ const sparse2 = sparsifyConstructedInstance2({
148870
+ authoredIdentities,
148871
+ constructionEntryIds: materialized.constructionEntryIds,
148489
148872
  localizedTextIds,
148490
- document: currentDocument,
148873
+ document: authoredIdentities?.length ? batch.comparisonDocument() : currentDocument,
148491
148874
  rootMember: member,
148492
148875
  constructed: {
148493
148876
  root: materialized.root,
@@ -160240,6 +160623,7 @@ function preparationArgs(context) {
160240
160623
  return {
160241
160624
  document: context.document,
160242
160625
  initializerReferenceOwners: args.initializerReferenceOwners,
160626
+ constructionIdentities: args.constructionIdentities,
160243
160627
  contentHashHeads: context.contentHashHeads,
160244
160628
  changes: args.changes,
160245
160629
  authoredValueSeeds: args.authoredValueSeeds,
@@ -160814,8 +161198,14 @@ function verifyProjectSourceCommitAgainstStateV4(args) {
160814
161198
  ${blockingErrors.map((error) => error.message).join("\n")}` : `Trusted source lowering found conflict markers in ${status.conflictedFiles.join(", ")}.`
160815
161199
  );
160816
161200
  }
161201
+ const identitySeeds = new Map(status.authoredValueSeeds);
161202
+ identitySeeds.set("source-owned constructions", {
161203
+ values: [...status.pendingValueIdentitySites ?? []].flatMap(
161204
+ ([id2, site]) => site.materializedLocation?.preserveIdentity === true ? [{ id: id2, value: null }] : []
161205
+ )
161206
+ });
160817
161207
  auditAuthoredSeedRowIdentities(
160818
- status.authoredValueSeeds,
161208
+ identitySeeds,
160819
161209
  args.stateRecords,
160820
161210
  assignments,
160821
161211
  derivedSeedRowIds
@@ -160852,6 +161242,18 @@ ${blockingErrors.map((error) => error.message).join("\n")}` : `Trusted source lo
160852
161242
  ...rewrite(seed)
160853
161243
  })
160854
161244
  );
161245
+ const constructionIdentities = indexAuthoredConstructionIdentities(
161246
+ [...status.pendingValueIdentitySites ?? []].flatMap(([id2, site]) => {
161247
+ const location3 = site.materializedLocation;
161248
+ if (location3?.preserveIdentity !== true) return [];
161249
+ return [
161250
+ [
161251
+ rewrite(id2),
161252
+ { ...location3, rootId: rewrite(location3.rootId) }
161253
+ ]
161254
+ ];
161255
+ })
161256
+ );
160855
161257
  for (const pendingId2 of assignments.keys()) {
160856
161258
  if (!usedAssignments.has(pendingId2)) {
160857
161259
  const message = `Pending id assignment ${pendingId2} is not present in the verified source manifest.`;
@@ -160872,6 +161274,7 @@ ${blockingErrors.map((error) => error.message).join("\n")}` : `Trusted source lo
160872
161274
  });
160873
161275
  compareChanges(expectedChanges, verifiableChanges);
160874
161276
  compareSeeds(expectedSeeds, args.authoredValueSeeds);
161277
+ return constructionIdentities;
160875
161278
  }
160876
161279
  function isDerivedOnlyRefresh(change, stateRecords) {
160877
161280
  if (change.operation !== "update") return false;
@@ -161412,6 +161815,7 @@ var ProjectSourceCommitVerificationError, ABSENT_DIFFERENCE_VALUE;
161412
161815
  var init_trusted_commit_verification = __esm({
161413
161816
  "src/project-source/trusted-commit-verification.ts"() {
161414
161817
  "use strict";
161818
+ init_virtual_instance_values();
161415
161819
  init_animation_child_binding_id();
161416
161820
  init_world_system_classes();
161417
161821
  init_tuple_element_member_id();
@@ -161500,6 +161904,7 @@ function sourceCommitPreparation(args) {
161500
161904
  }),
161501
161905
  authoredValueSeeds: args.authoredValueSeeds,
161502
161906
  initializerReferenceOwners: args.initializerReferenceOwners,
161907
+ constructionIdentities: args.constructionIdentities,
161503
161908
  forceRecompile: args.forceRecompile,
161504
161909
  scriptSources: args.scriptSources,
161505
161910
  serverTimestamp: args.serverTimestamp
@@ -161783,6 +162188,7 @@ function replayStoredConstructionV4(args) {
161783
162188
  // explicit typed descriptor for evaluation that compiled the replay.
161784
162189
  member: compileMember,
161785
162190
  row: evaluationRow,
162191
+ captureConstructionEntries: args.captureConstructionEntries,
161786
162192
  storedConstructionReplay: true,
161787
162193
  ...args.omitConstructionFields === true ? { constructionBaselineReplay: true } : {},
161788
162194
  ...args.initializerArgumentValues === void 0 ? {} : { argumentValues: args.initializerArgumentValues }
@@ -166874,9 +167280,18 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
166874
167280
  valueId,
166875
167281
  {
166876
167282
  sites: context.pendingValueIdentitySites,
167283
+ storedParent: (id2) => {
167284
+ const edge = context.readStoredValuePlacements().placementByChildValueId.get(id2);
167285
+ return edge === void 0 ? void 0 : { rootId: edge.parentValueId, path: [edge.schemaKey] };
167286
+ },
167287
+ validateAuthoredId: (id2) => {
167288
+ if (!isPendingId(id2) && context.state[`value:${id2}`] === void 0 && !isUuidV4Id(id2))
167289
+ throw new Error(
167290
+ `New local value @id(${JSON.stringify(id2)}) requires a UUID v4.`
167291
+ );
167292
+ },
166877
167293
  localListEntries: (local2) => localNestedListEntries(context, local2)
166878
- },
166879
- context.storedValueAtPath
167294
+ }
166880
167295
  );
166881
167296
  const settled = settleInitializerReferenceSpellings(
166882
167297
  executable.code,
@@ -167618,7 +168033,7 @@ function lowerSeedChild(context, member, expression, source, path, rows, localiz
167618
168033
  )
167619
168034
  });
167620
168035
  }
167621
- const valueId = annotatedId2 ?? context.structuralStoredIds.get(path) ?? pendingNestedValueId(source, path);
168036
+ const valueId = annotatedId2 ?? context.structuralStoredIds.get(path) ?? local.pendingIdentity ?? pendingNestedValueId(source, path);
167622
168037
  if (!context.structuralConstruction && annotatedId2 !== null && context.state[`value:${annotatedId2}`] !== void 0) {
167623
168038
  const failure = storedClassMoveFailure(
167624
168039
  context,
@@ -167668,7 +168083,7 @@ function lowerSeedChild(context, member, expression, source, path, rows, localiz
167668
168083
  expression,
167669
168084
  source,
167670
168085
  valueId,
167671
- unorderedRowSubtreePath(valueId, path, containerId),
168086
+ local.pendingIdentity === void 0 ? unorderedRowSubtreePath(valueId, path, containerId) : valueId,
167672
168087
  rows,
167673
168088
  localizedTexts,
167674
168089
  containerId,
@@ -167847,9 +168262,18 @@ function lowerAuthoredValueRow(context, member, sourceExpression, expectedValueI
167847
168262
  expectedValueId,
167848
168263
  {
167849
168264
  sites: context.pendingValueIdentitySites,
168265
+ storedParent: (id3) => {
168266
+ const edge = context.readStoredValuePlacements().placementByChildValueId.get(id3);
168267
+ return edge === void 0 ? void 0 : { rootId: edge.parentValueId, path: [edge.schemaKey] };
168268
+ },
168269
+ validateAuthoredId: (id3) => {
168270
+ if (!isPendingId(id3) && context.state[`value:${id3}`] === void 0 && !isUuidV4Id(id3))
168271
+ throw new Error(
168272
+ `New local value @id(${JSON.stringify(id3)}) requires a UUID v4.`
168273
+ );
168274
+ },
167850
168275
  localListEntries: (local2) => localNestedListEntries(context, local2)
167851
- },
167852
- context.storedValueAtPath
168276
+ }
167853
168277
  );
167854
168278
  const settled = settleInitializerReferenceSpellings(
167855
168279
  executable.code,
@@ -169441,9 +169865,10 @@ function recordRepeatedRow(context, rowId, collection, site, placedIds = context
169441
169865
  function lowerPendingListItem(context, member, expression, source, path, containerId, environment, authoredSlice) {
169442
169866
  const rows = /* @__PURE__ */ new Map();
169443
169867
  const localizedTexts = /* @__PURE__ */ new Map();
169444
- const annotatedId2 = authoredRowId(context, expression, source);
169445
- const valueId = annotatedId2 ?? pendingNestedValueId(source, path);
169446
- const stablePath = isPendingId(valueId) ? valueId : unorderedRowSubtreePath(valueId, path, containerId);
169868
+ const local = context.localValues.resolve(expression, source);
169869
+ const annotatedId2 = annotatedValue(local.expression).id;
169870
+ const valueId = annotatedId2 ?? local.pendingIdentity ?? pendingNestedValueId(source, path);
169871
+ const stablePath = isPendingId(valueId) || local.pendingIdentity !== void 0 ? valueId : unorderedRowSubtreePath(valueId, path, containerId);
169447
169872
  lowerSeedRow(
169448
169873
  context,
169449
169874
  member,
@@ -171426,6 +171851,14 @@ function emitValue(context, member, valueId, options) {
171426
171851
  context.localizedTextIds = /* @__PURE__ */ new Set();
171427
171852
  const expression2 = emitValue(context, member, valueId, {
171428
171853
  ...options,
171854
+ writeIdentity: options.writeIdentity || !context.symbolsByValueId.has(valueId) && member.valueId !== valueId && (typeof member.id !== "string" || memberValueId(member.id) !== valueId) && (!isObjectRecord(member.defaultValue) || member.defaultValue.id !== valueId) && [
171855
+ 7 /* Class */,
171856
+ 22 /* Interface */,
171857
+ 6 /* List */,
171858
+ 28 /* Set */,
171859
+ 5 /* Dictionary */,
171860
+ 30 /* Tuple */
171861
+ ].includes(numberField(member, "kind")),
171429
171862
  localDefinition: true,
171430
171863
  visited,
171431
171864
  decorateLocal: void 0
@@ -175763,6 +176196,9 @@ function reconciliationRecords(workspace, changes, seeds = /* @__PURE__ */ new M
175763
176196
  });
175764
176197
  }
175765
176198
  function materializeInitializersLocallyV4(args) {
176199
+ const constructionIdentities = indexAuthoredConstructionIdentities(
176200
+ args.localReferenceLocations ?? []
176201
+ );
175766
176202
  const records3 = prospectiveInitializerRecordsV4(args);
175767
176203
  const sourceRoots = initializerSourceRootIds(
175768
176204
  args.changes,
@@ -175995,7 +176431,7 @@ function materializeInitializersLocallyV4(args) {
175995
176431
  throw new PendingInitializerDependency(location3.rootId);
175996
176432
  if (pendingRoots.has(location3.rootId))
175997
176433
  throw new PendingInitializerDependency(location3.rootId);
175998
- const target = resolvedLocalIds.get(id2) ?? storedValueAtPathV4(
176434
+ const target = resolvedLocalIds.get(id2) ?? (location3.preserveIdentity && batch.valuesById.has(id2) ? id2 : null) ?? storedValueAtPathV4(
175999
176435
  batch.valuesById,
176000
176436
  location3.rootId,
176001
176437
  location3.path
@@ -176038,6 +176474,7 @@ function materializeInitializersLocallyV4(args) {
176038
176474
  pinnedSchemaKeysByValueId: /* @__PURE__ */ new Map()
176039
176475
  };
176040
176476
  const evaluated2 = replayStoredConstructionV4({
176477
+ captureConstructionEntries: constructionIdentities.has(sourceValueId),
176041
176478
  readTracking,
176042
176479
  records: records3,
176043
176480
  document,
@@ -176117,9 +176554,12 @@ function materializeInitializersLocallyV4(args) {
176117
176554
  }
176118
176555
  return [row];
176119
176556
  });
176120
- const sparse2 = sparsifyConstructedInstance({
176557
+ const authoredIdentities = constructionIdentities.get(sourceValueId);
176558
+ const sparse2 = sparsifyConstructedInstance2({
176559
+ authoredIdentities,
176560
+ constructionEntryIds: pinned.constructionEntryIds,
176121
176561
  localizedTextIds,
176122
- document,
176562
+ document: authoredIdentities?.length ? comparisonDocument() : document,
176123
176563
  rootMember: rootOwner,
176124
176564
  constructed: {
176125
176565
  root: evaluatedRoot,
@@ -176177,11 +176617,7 @@ function materializeInitializersLocallyV4(args) {
176177
176617
  for (const [id2, location3] of args.localReferenceLocations ?? []) {
176178
176618
  if (resolvedLocalIds.has(id2)) continue;
176179
176619
  if (unavailableRootIds.has(location3.rootId)) continue;
176180
- const target = storedValueAtPathV4(
176181
- batch.valuesById,
176182
- location3.rootId,
176183
- location3.path
176184
- );
176620
+ const target = location3.preserveIdentity && batch.valuesById.has(id2) ? id2 : storedValueAtPathV4(batch.valuesById, location3.rootId, location3.path);
176185
176621
  if (target !== null) resolvedLocalIds.set(id2, target);
176186
176622
  }
176187
176623
  return { roots, resolvedLocalIds, failures, unavailableRootIds };
@@ -188867,6 +189303,48 @@ function preserveProjectFileRegistrySource(existing, emitted, records3 = /* @__P
188867
189303
  if (registryOnly) emitted = existing;
188868
189304
  return applySourceEdits(emitted, replacements);
188869
189305
  }
189306
+ function augmentAuthoredProjectFileRegistries(existing, emitted) {
189307
+ const authored = parseNeoProjectSource(existing, "definition");
189308
+ const generated = parseNeoProjectSource(emitted, "definition");
189309
+ const declarations = new Map(
189310
+ authored.declarations.flatMap(
189311
+ (declaration) => declaration.kind === "global" ? [[declaration.name, declaration]] : []
189312
+ )
189313
+ );
189314
+ const edits = [];
189315
+ const additions = [];
189316
+ for (const declaration of generated.declarations) {
189317
+ if (declaration.kind !== "global") continue;
189318
+ if (!["ImageRegistry", "AudioClipRegistry"].includes(declaration.type.name))
189319
+ continue;
189320
+ const content = emitted.slice(
189321
+ generated.syntax.source.offsetAt(declaration.range.start),
189322
+ generated.syntax.source.offsetAt(declaration.range.end)
189323
+ );
189324
+ const prior = declarations.get(declaration.name);
189325
+ if (prior === void 0) {
189326
+ additions.push(content);
189327
+ continue;
189328
+ }
189329
+ const start = authored.syntax.source.offsetAt(prior.range.start);
189330
+ const end = authored.syntax.source.offsetAt(prior.range.end);
189331
+ edits.push({
189332
+ start,
189333
+ end,
189334
+ text: preserveProjectFileRegistrySource(
189335
+ existing.slice(start, end),
189336
+ content
189337
+ )
189338
+ });
189339
+ }
189340
+ if (additions.length > 0)
189341
+ edits.push({
189342
+ start: existing.length,
189343
+ end: existing.length,
189344
+ text: "\n" + additions.join("\n\n") + "\n"
189345
+ });
189346
+ return applySourceEdits(existing, edits);
189347
+ }
188870
189348
  function registries(document, source, templateIds) {
188871
189349
  if (document.diagnostics.some((diagnostic) => diagnostic.severity === "error"))
188872
189350
  return [];
@@ -224398,7 +224876,7 @@ import {
224398
224876
  statSync as statSync7
224399
224877
  } from "node:fs";
224400
224878
  import { join as join22, relative as relative8, sep as sep9 } from "node:path";
224401
- function assignPendingIds(changes, authoredValueSeeds, reconstructed3, previousLedger = {}, codePendingIdCandidates = []) {
224879
+ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, previousLedger = {}, codePendingIdCandidates = [], authoredPendingIds = []) {
224402
224880
  const assigned = /* @__PURE__ */ new Map();
224403
224881
  const minted = /* @__PURE__ */ new Map();
224404
224882
  let mint = (pendingId2) => {
@@ -224543,6 +225021,7 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, previousL
224543
225021
  for (const change of changes) collectCodeIds(change.nextData);
224544
225022
  for (const seed of authoredValueSeeds.values()) collectCodeIds(seed);
224545
225023
  }
225024
+ for (const id2 of authoredPendingIds) collect(id2);
224546
225025
  for (const root of roots) assign(root);
224547
225026
  const keys = identityLedgerKeys(minted.keys());
224548
225027
  const ledger = {};
@@ -225459,7 +225938,7 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
225459
225938
  } : void 0;
225460
225939
  onPhase("Hashing project source\u2026");
225461
225940
  const source = projectSourceIdentityForStatus(status);
225462
- const verificationSource = options.fullValidation ? locatedPendingProjectSourceIdentity(workspace, status) : null;
225941
+ const verificationSource = options.fullValidation ? authoredVerificationSource(workspace, status, source) : null;
225463
225942
  onPhase("Assigning pending value identities\u2026");
225464
225943
  const release = options.purpose === "evaluation" /* Evaluation */ ? await acquireWorkspaceLock(
225465
225944
  workspace.root,
@@ -225475,6 +225954,9 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
225475
225954
  { ...options.identityLedger, ...latestLedger },
225476
225955
  [...status.pendingValueIdentitySites ?? []].flatMap(
225477
225956
  ([id2, site]) => site.materializedLocation !== void 0 && pendingVirtualValueIdentity(id2) !== null ? [id2] : []
225957
+ ),
225958
+ [...status.pendingValueIdentitySites ?? []].flatMap(
225959
+ ([id2, site]) => site.materializedLocation?.preserveIdentity === true ? [id2] : []
225478
225960
  )
225479
225961
  );
225480
225962
  if (!mergeReservedIdentities(workspace.root, pendingAssignment.ledger)) {
@@ -225501,6 +225983,7 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
225501
225983
  status.changes,
225502
225984
  localizedTextCreateEnvelopeConfig2(workspace, status.changes)
225503
225985
  );
225986
+ let verifiedConstructionIdentities;
225504
225987
  try {
225505
225988
  if (verificationSource !== null) {
225506
225989
  onPhase("Verifying the assigned value-id stamps\u2026");
@@ -225510,8 +225993,8 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
225510
225993
  status.pendingValueIdentitySites,
225511
225994
  { sourceSnapshot: status.sourceSnapshot, validateResult: true }
225512
225995
  );
225513
- onPhase("Verifying the complete source round trip\u2026");
225514
- verifyProjectSourceCommitAgainstStateV4({
225996
+ onPhase("Verifying the authored source and ownership\u2026");
225997
+ verifiedConstructionIdentities = verifyProjectSourceCommitAgainstStateV4({
225515
225998
  projectId: workspace.config.projectId,
225516
225999
  versionId: workspace.config.versionId,
225517
226000
  stateRecords: workspace.state.records,
@@ -225533,6 +226016,23 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
225533
226016
  let prepared;
225534
226017
  try {
225535
226018
  const preparationArgs2 = {
226019
+ constructionIdentities: verifiedConstructionIdentities ?? indexAuthoredConstructionIdentities(
226020
+ [...status.pendingValueIdentitySites ?? []].flatMap(
226021
+ ([id2, site]) => {
226022
+ const location3 = site.materializedLocation;
226023
+ if (location3 === void 0) return [];
226024
+ return [
226025
+ [
226026
+ pendingAssignment.assigned.get(id2) ?? id2,
226027
+ {
226028
+ ...location3,
226029
+ rootId: pendingAssignment.assigned.get(location3.rootId) ?? location3.rootId
226030
+ }
226031
+ ]
226032
+ ];
226033
+ }
226034
+ )
226035
+ ),
225536
226036
  initializerReferenceOwners: new Map(
225537
226037
  [...status.pendingValueIdentitySites ?? []].flatMap(
225538
226038
  ([id2, site]) => site.materializedLocation === void 0 ? [] : [
@@ -225621,17 +226121,6 @@ function locatePreparationError(error, status, assigned) {
225621
226121
  if (source === void 0) return error;
225622
226122
  return new Error(`${source.file}:${source.line} \u2014 ${error.message}`);
225623
226123
  }
225624
- function locatedPendingProjectSourceIdentity(workspace, status) {
225625
- try {
225626
- return createPendingProjectSourceIdentityV4(
225627
- workspace,
225628
- status,
225629
- status.authoredValueSeeds
225630
- );
225631
- } catch (error) {
225632
- throw locatePreparationError(error, status, /* @__PURE__ */ new Map());
225633
- }
225634
- }
225635
226124
  async function prepareLocalCandidateV4(workspace, options = {}) {
225636
226125
  const pushOptions = {
225637
226126
  dryRun: options.dryRun ?? true,
@@ -225869,6 +226358,30 @@ function reportDryRunFailure(error, json) {
225869
226358
  }
225870
226359
  console.error(`Dry run failed: ${message}`);
225871
226360
  }
226361
+ function authoredVerificationSource(workspace, status, source) {
226362
+ let canonical;
226363
+ try {
226364
+ canonical = createPendingProjectSourceIdentityV4(
226365
+ workspace,
226366
+ status,
226367
+ status.authoredValueSeeds
226368
+ );
226369
+ } catch (error) {
226370
+ throw locatePreparationError(error, status, /* @__PURE__ */ new Map());
226371
+ }
226372
+ const files = new Map(source.files.map((file) => [file.path, file]));
226373
+ for (const file of canonical.files) {
226374
+ const prior = files.get(file.path);
226375
+ const content = augmentAuthoredProjectFileRegistries(
226376
+ prior?.content ?? "",
226377
+ file.content
226378
+ );
226379
+ if (content === (prior?.content ?? "")) continue;
226380
+ files.set(file.path, { ...file, content });
226381
+ }
226382
+ const result = [...files.values()];
226383
+ return { files: result, sourceHash: hashProjectSourceFiles(result) };
226384
+ }
225872
226385
  function projectSourceIdentityForStatus(status) {
225873
226386
  if (status.sourceSnapshot === void 0) {
225874
226387
  throw new Error(
@@ -226219,11 +226732,46 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
226219
226732
  replacements.exact
226220
226733
  );
226221
226734
  const ownedLocalReplacements = new Map(replacements.exact);
226735
+ let committedNamedRows;
226736
+ let ownsCommittedPath;
226222
226737
  for (const [locator, site] of localStatus.pendingValueIdentitySites ?? []) {
226223
226738
  const location3 = site.materializedLocation;
226224
226739
  if (location3 === void 0) continue;
226225
226740
  const rootId = rewritePlacementValueId(location3.rootId, replacements);
226226
- const id2 = committedValueAtPath(rootId, location3.path);
226741
+ const expectedId = rewritePlacementValueId(locator, replacements);
226742
+ let id2 = committedValueAtPath(rootId, location3.path);
226743
+ if (location3.preserveIdentity === true) {
226744
+ committedNamedRows ??= storedValueRowsByIdV4(Object.values(nextRecords));
226745
+ const row = committedNamedRows.get(expectedId);
226746
+ if (row === void 0)
226747
+ throw new Error(
226748
+ `Committed named value ${locator} is missing its assigned identity ${expectedId}.`
226749
+ );
226750
+ if (id2 !== expectedId) {
226751
+ if (ownsCommittedPath === void 0) {
226752
+ const document = readProjectDocument(
226753
+ pulledProjectDocumentRaw({
226754
+ ...workspace,
226755
+ state: { ...workspace.state, records: nextRecords }
226756
+ })
226757
+ );
226758
+ const graph = new MaterializedValueGraphContext(document);
226759
+ ownsCommittedPath = storedValueOwnsPathV4(
226760
+ Object.values(nextRecords),
226761
+ committedNamedRows,
226762
+ (id3) => graph.ownerForValue(id3)
226763
+ );
226764
+ }
226765
+ const path = location3.path.map(
226766
+ (key) => typeof key === "string" ? replacements.exact.get(key) ?? key : key
226767
+ );
226768
+ if (!ownsCommittedPath(rootId, path, expectedId))
226769
+ throw new Error(
226770
+ `Committed named value ${locator} is absent from its owning path.`
226771
+ );
226772
+ }
226773
+ id2 = expectedId;
226774
+ }
226227
226775
  if (id2 === null)
226228
226776
  throw new Error(
226229
226777
  `Committed local value ${locator} has no row at its owning path.`
@@ -226778,8 +227326,13 @@ function materializeAssignedValueIdsInAuthoredSource(workspace, replacements, pe
226778
227326
  assignedId,
226779
227327
  options.committedValueAtPath
226780
227328
  );
226781
- if (entryStamps === null) continue;
226782
- if (site.stampIdentity !== false) {
227329
+ if (entryStamps === null && !site.materializedLocation?.preserveIdentity)
227330
+ continue;
227331
+ if (site.stampIdentity !== false && site.materializedLocation?.preserveIdentity) {
227332
+ file.edits.push(
227333
+ idStamp(file, sourceOffset2(file, site.declarationStart), assignedId)
227334
+ );
227335
+ } else if (site.stampIdentity !== false) {
226783
227336
  const row = rowAt(file, expressionOffset);
226784
227337
  if (row === null) continue;
226785
227338
  if (row.slot === 0 /* Entry */) {
@@ -226793,7 +227346,7 @@ function materializeAssignedValueIdsInAuthoredSource(workspace, replacements, pe
226793
227346
  file.edits.push(...stamp);
226794
227347
  }
226795
227348
  }
226796
- file.edits.push(...entryStamps);
227349
+ file.edits.push(...entryStamps ?? []);
226797
227350
  }
226798
227351
  const preserved = /* @__PURE__ */ new Map();
226799
227352
  for (const [uri, file] of files)
@@ -227610,6 +228163,8 @@ var compileNSVoidBody2, compileNSFunction2, compileNSGetter2, compileNSSetter2,
227610
228163
  var init_push = __esm({
227611
228164
  "src/commands/push.ts"() {
227612
228165
  "use strict";
228166
+ init_constructor_argument_ownership();
228167
+ init_virtual_instance_values();
227613
228168
  init_animation_child_binding_id();
227614
228169
  init_world_system_classes();
227615
228170
  init_local_project_file_storage();
@@ -243158,7 +243713,7 @@ var releaseWorkspaceLock = () => void 0;
243158
243713
  async function main() {
243159
243714
  const args = parseArgs(process.argv.slice(2));
243160
243715
  if (args.command === "--version") {
243161
- console.log("0.89.12");
243716
+ console.log("0.89.13");
243162
243717
  return;
243163
243718
  }
243164
243719
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -37246,6 +37246,13 @@ function applyConstructorFields(args) {
37246
37246
  let kept = 0;
37247
37247
  for (const row of createdValues) {
37248
37248
  if (row.id === keptId || row.containerId === keptId) {
37249
+ if (row.containerId === keptId) {
37250
+ if (ctx.__indexes !== void 0)
37251
+ unindexEvaluatorRow(ctx.__indexes, row);
37252
+ delete row.containerId;
37253
+ if (ctx.__indexes !== void 0)
37254
+ indexEvaluatorRow(ctx.__indexes, row);
37255
+ }
37249
37256
  createdById.delete(row.id);
37250
37257
  continue;
37251
37258
  }
@@ -40459,6 +40466,9 @@ function materializeConstructorArgumentValue(args) {
40459
40466
  for (const entry of rows) sourceEntries.push(entry.value);
40460
40467
  }
40461
40468
  const ids = [];
40469
+ const authoredEntries = args.ctx.__constructionEntryIds === void 0 ? void 0 : [];
40470
+ if (authoredEntries !== void 0)
40471
+ args.ctx.__constructionEntryIds?.set(row.id, authoredEntries);
40462
40472
  const references = recordedReferenceEntries(sourceEntries, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(sourceEntries, args.ctx));
40463
40473
  for (const [index, rawEntry] of sourceEntries.entries()) {
40464
40474
  if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, index) && typeof rawEntry === "string" && evalValueById(
@@ -40468,6 +40478,7 @@ function materializeConstructorArgumentValue(args) {
40468
40478
  args.ctx.__valueOverlay
40469
40479
  ) !== null) {
40470
40480
  ids.push(rawEntry);
40481
+ authoredEntries?.push(rawEntry);
40471
40482
  continue;
40472
40483
  }
40473
40484
  const entryValue = constructorCollectionEntryValue(
@@ -40489,6 +40500,7 @@ function materializeConstructorArgumentValue(args) {
40489
40500
  },
40490
40501
  destinationName: `${args.member.name}[${index}]`
40491
40502
  });
40503
+ authoredEntries?.push(child.id);
40492
40504
  if (listKindOf(args.member) === 1 /* Unordered */) {
40493
40505
  child.containerId = row.id;
40494
40506
  } else {
@@ -43306,7 +43318,16 @@ var MaterializedValueGraphContext = class _MaterializedValueGraphContext {
43306
43318
  ownershipFacts() {
43307
43319
  if (this.ownership !== void 0) return this.ownership;
43308
43320
  const targetValueIds = new Set(this.valuesById.keys());
43309
- const owners = resolveOwnerMembersForValues(this.document, targetValueIds);
43321
+ const owners = resolveOwnerMembersForValues(
43322
+ this.document,
43323
+ targetValueIds,
43324
+ [...this.contextualRootMembersByValueId ?? []].map(
43325
+ ([valueId, member]) => ({
43326
+ valueId,
43327
+ member: resolveMember(member, this.document.members)
43328
+ })
43329
+ )
43330
+ );
43310
43331
  this.ownership = {
43311
43332
  owners,
43312
43333
  independentlyOwnedValueIds: new Set(owners.keys())
@@ -46238,6 +46259,7 @@ function evaluateInitializerMaterialization(args) {
46238
46259
  const createdValues = [];
46239
46260
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
46240
46261
  const evaluated = args.evaluateInitializer({
46262
+ constructionEntryIds: args.constructionEntryIds,
46241
46263
  randomSource: args.randomSource,
46242
46264
  genericEnv: args.genericEnv,
46243
46265
  init: args.init,
@@ -46317,7 +46339,9 @@ function finalizeMaterializedRoot(args) {
46317
46339
  });
46318
46340
  }
46319
46341
  function materializeInitializerValue(args) {
46342
+ const constructionEntryIds = args.captureConstructionEntries ? /* @__PURE__ */ new Map() : void 0;
46320
46343
  const { evaluated, createdValues, storageKeyDeclarations } = evaluateInitializerMaterialization({
46344
+ constructionEntryIds,
46321
46345
  randomSource: args.randomSource,
46322
46346
  evaluateInitializer: args.evaluateInitializer,
46323
46347
  init: args.row.init,
@@ -46369,6 +46393,7 @@ function materializeInitializerValue(args) {
46369
46393
  return {
46370
46394
  root,
46371
46395
  createdValues,
46396
+ constructionEntryIds,
46372
46397
  snapshot: evaluated.snapshot,
46373
46398
  pinnedRootSchemaKeys: evaluated.pinnedRootSchemaKeys ?? /* @__PURE__ */ new Set(),
46374
46399
  pinnedSchemaKeysByValueId: evaluated.pinnedSchemaKeysByValueId ?? /* @__PURE__ */ new Map()
@@ -46838,7 +46863,7 @@ function buildVirtualInstanceMaterializedIndex(args) {
46838
46863
  return {
46839
46864
  rows,
46840
46865
  rowsById,
46841
- graph: new MaterializedValueGraphContext(
46866
+ graph: args.materializedGraph ?? new MaterializedValueGraphContext(
46842
46867
  { ...args.document, values: rows },
46843
46868
  rowsById
46844
46869
  ),
@@ -47314,7 +47339,9 @@ function resolveVirtualInstanceGraph(args) {
47314
47339
  if (parent !== void 0 && isMemberEntryCollectionBase(parent.member) && listKindOf(parent.member) === 1 /* Unordered */)
47315
47340
  effective.containerId = parentId;
47316
47341
  }
47317
- if (isClassSlotMember(indexed.member) && effective.value !== null) {
47342
+ if (args.opaquePaths?.has(pathKey)) {
47343
+ effective.value = materialized?.value ?? indexed.expandedRow.value;
47344
+ } else if (isClassSlotMember(indexed.member) && effective.value !== null) {
47318
47345
  const storedRecord = stringRecord(materialized?.value);
47319
47346
  const classId = rowClassId(indexed.member, effective);
47320
47347
  const constructedChildren = materialized === null ? /* @__PURE__ */ new Map() : settledAggregateChildren(materialized, classId, pathKey);
@@ -48648,6 +48675,7 @@ function indexExpansion(args) {
48648
48675
  discoveredNodes?.push(node);
48649
48676
  nodesByPath.set(pathKey, node);
48650
48677
  appendChildPath(parentPath, pathKey);
48678
+ if (args.opaquePaths?.has(pathKey)) return;
48651
48679
  if (isClassTypedMember(member)) {
48652
48680
  const record4 = stringRecord(row.value);
48653
48681
  const classId = row.classId ?? member.classId;
@@ -51152,6 +51180,7 @@ function evaluateMemberInitializer(args) {
51152
51180
  );
51153
51181
  const compiled = compileMemberInitializer(args, databaseVM);
51154
51182
  const ctx = {
51183
+ __constructionEntryIds: args.constructionEntryIds,
51155
51184
  randomSource: args.randomSource,
51156
51185
  randomIdentity,
51157
51186
  ...args.sessionValues === void 0 ? {} : { __runtimeSessionValues: args.sessionValues },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.89.12",
3
+ "version": "0.89.13",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.89.12 -->
12
+ <!-- reviewed-through-cli: 0.89.13 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -143,7 +143,7 @@ The marker near the top of `SKILL.md` must exactly match the package version,
143
143
  and this quoted copy is checked too:
144
144
 
145
145
  ```html
146
- <!-- reviewed-through-cli: 0.89.12 -->
146
+ <!-- reviewed-through-cli: 0.89.13 -->
147
147
  ```
148
148
 
149
149
  Keep this skill on current behavior. Upgrade steps, rollout prerequisites,
@@ -63,6 +63,13 @@ Quest HardAsStone = new Quest() { Name = "Hard as stone" };
63
63
  form above. Never put an ID in both places. A local keeps its concrete type
64
64
  when a base-typed member consumes it.
65
65
 
66
+ Before its first push, a named aggregate in an owning graph reserves its
67
+ identity by its terminal local declaration. Inserting or reordering other list
68
+ entries keeps that value and its descendants stable across local exports.
69
+ Aliases share the terminal declaration's identity. Scalar locals remain reusable
70
+ values, so each owning occurrence gets its own identity. Keep the assigned
71
+ `@id` when renaming or moving a declaration after push.
72
+
66
73
  ## Locals as constructor arguments
67
74
 
68
75
  In constructor arguments and executable operands, a class local names its one