mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
perf(artifacts)!: name each edge's child through its occurrence (#1493)
Every inventory edge is created from one occurrence and copied that occurrence's artifact_id and logical_path as child_artifact_id and logical_path. Edges now keep the occurrence_id reference alone. Edge IDs still hash the same child and path, read from the occurrence, so they are unchanged; validation and artifact comparison read the occurrence too. inspect_artifact output: Transmission.app 1.10 MB to 0.97 MB, Visual Studio Code.app 15.37 MB to 13.48 MB. BREAKING CHANGE: Artifact inventory edges no longer include child_artifact_id or logical_path; read them from the occurrence named by occurrence_id. The graph commitment changes, so inventory Evidence recorded by earlier versions no longer validates. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f692c83e2
commit
a0e5e9db2b
8 files changed
+45
-39
No files matched your search
@@ -249,16 +249,14 @@ export const createArtifactEdges = (
|
||||
rootArtifactId;
|
||||
const semantic = {
|
||||
parent_artifact_id: parentArtifactId,
|
||||
child_artifact_id: occurrence.artifact_id,
|
||||
relation:
|
||||
occurrence.entry_kind === "slice"
|
||||
? ("slice-of" as const)
|
||||
: relationFor(occurrence.logical_path),
|
||||
occurrence_id: occurrence.occurrence_id,
|
||||
logical_path: occurrence.logical_path,
|
||||
};
|
||||
edges.push({
|
||||
edge_id: artifactEdgeId(semantic),
|
||||
edge_id: artifactEdgeId(semantic, occurrence),
|
||||
...semantic,
|
||||
producer: occurrence.entry_kind === "slice" ? (producer ?? null) : null,
|
||||
ordinal: edges.length,
|
||||
|
||||
@@ -350,19 +350,20 @@ const relationsByPath = (
|
||||
inventory.occurrences.map((item) => [item.occurrence_id, item]),
|
||||
);
|
||||
for (const edge of inventory.edges) {
|
||||
const path = edge.logical_path ?? ".";
|
||||
const values = output.get(path);
|
||||
const occurrence = occurrences.get(edge.occurrence_id);
|
||||
// An incomplete inventory can omit the occurrence that names the child.
|
||||
if (occurrence?.artifact_id === null || occurrence === undefined) continue;
|
||||
const path = occurrence.logical_path;
|
||||
const values = output.get(path);
|
||||
const projection: RelationProjection = {
|
||||
parent_logical_path:
|
||||
occurrence?.parent_occurrence_id === null ||
|
||||
occurrence?.parent_occurrence_id === undefined
|
||||
occurrence.parent_occurrence_id === null
|
||||
? null
|
||||
: (occurrences.get(occurrence.parent_occurrence_id)?.logical_path ??
|
||||
null),
|
||||
child_artifact_id: edge.child_artifact_id,
|
||||
child_artifact_id: occurrence.artifact_id,
|
||||
relation: edge.relation,
|
||||
logical_path: edge.logical_path,
|
||||
logical_path: occurrence.logical_path,
|
||||
producer: edge.producer,
|
||||
};
|
||||
if (values === undefined) output.set(path, [projection]);
|
||||
|
||||
@@ -151,12 +151,14 @@ export const integrityContradictionSchema = z.object({
|
||||
limitations: z.array(z.string()).min(1),
|
||||
});
|
||||
|
||||
/** Parent-child derivation relation between two content-addressed artifacts. */
|
||||
/**
|
||||
* Parent-child derivation relation between two content-addressed artifacts.
|
||||
* The child artifact and its logical path are those of the edge's occurrence.
|
||||
*/
|
||||
const artifactEdgeSchema = z.object({
|
||||
edge_id: edgeIdSchema,
|
||||
ordinal: z.number().int().min(0),
|
||||
parent_artifact_id: artifactIdSchema,
|
||||
child_artifact_id: artifactIdSchema,
|
||||
relation: z.enum([
|
||||
"contains",
|
||||
"extracts",
|
||||
@@ -167,7 +169,6 @@ const artifactEdgeSchema = z.object({
|
||||
"derived-from",
|
||||
]),
|
||||
occurrence_id: occurrenceIdSchema,
|
||||
logical_path: boundedRelativePathSchema.nullable(),
|
||||
producer: artifactCommandSchema.nullable(),
|
||||
});
|
||||
|
||||
|
||||
@@ -71,14 +71,21 @@ export const artifactContradictionId = (input: {
|
||||
"Artifact",
|
||||
)}`;
|
||||
|
||||
/** Identify an edge by its semantic relationship and exact occurrence. */
|
||||
/**
|
||||
* Identify an edge by its semantic relationship and exact occurrence. The
|
||||
* child artifact and logical path come from that occurrence.
|
||||
*/
|
||||
export const artifactEdgeId = (
|
||||
semantic: Pick<
|
||||
ArtifactEdge,
|
||||
| "parent_artifact_id"
|
||||
| "child_artifact_id"
|
||||
| "relation"
|
||||
| "occurrence_id"
|
||||
| "logical_path"
|
||||
>,
|
||||
): string => `edge_${digestCanonicalValue(semantic, "Artifact")}`;
|
||||
edge: Pick<ArtifactEdge, "parent_artifact_id" | "relation" | "occurrence_id">,
|
||||
occurrence: Pick<ArtifactOccurrence, "artifact_id" | "logical_path">,
|
||||
): string =>
|
||||
`edge_${digestCanonicalValue(
|
||||
{
|
||||
parent_artifact_id: edge.parent_artifact_id,
|
||||
child_artifact_id: occurrence.artifact_id,
|
||||
relation: edge.relation,
|
||||
occurrence_id: edge.occurrence_id,
|
||||
logical_path: occurrence.logical_path,
|
||||
},
|
||||
"Artifact",
|
||||
)}`;
|
||||
@@ -211,8 +211,14 @@ const validateCompleteInventory = (inventory: InventorySet): void => {
|
||||
);
|
||||
for (const occurrence of inventory.occurrences)
|
||||
validateOccurrence(occurrence, inventory, nodeIds, occurrenceIds);
|
||||
const occurrencesById = new Map(
|
||||
inventory.occurrences.map((occurrence) => [
|
||||
occurrence.occurrence_id,
|
||||
occurrence,
|
||||
]),
|
||||
);
|
||||
for (const edge of inventory.edges)
|
||||
validateEdge(edge, nodeIds, occurrenceIds);
|
||||
validateEdge(edge, nodeIds, occurrencesById);
|
||||
for (const contradiction of inventory.integrityContradictions) {
|
||||
if (
|
||||
!nodeIds.has(contradiction.parent_artifact_id) ||
|
||||
@@ -273,22 +279,17 @@ const validateOccurrence = (
|
||||
const validateEdge = (
|
||||
edge: ArtifactInventoryResult["edges"][number],
|
||||
nodeIds: ReadonlySet<string>,
|
||||
occurrenceIds: ReadonlySet<string>,
|
||||
occurrences: ReadonlyMap<string, ArtifactOccurrence>,
|
||||
): void => {
|
||||
const occurrence = occurrences.get(edge.occurrence_id);
|
||||
if (
|
||||
!nodeIds.has(edge.parent_artifact_id) ||
|
||||
!nodeIds.has(edge.child_artifact_id) ||
|
||||
!occurrenceIds.has(edge.occurrence_id)
|
||||
occurrence?.artifact_id === null ||
|
||||
occurrence === undefined ||
|
||||
!nodeIds.has(occurrence.artifact_id)
|
||||
)
|
||||
throw new TypeError("Artifact edge references a missing graph member");
|
||||
const semantic = {
|
||||
parent_artifact_id: edge.parent_artifact_id,
|
||||
child_artifact_id: edge.child_artifact_id,
|
||||
relation: edge.relation,
|
||||
occurrence_id: edge.occurrence_id,
|
||||
logical_path: edge.logical_path,
|
||||
};
|
||||
if (edge.edge_id !== artifactEdgeId(semantic))
|
||||
if (edge.edge_id !== artifactEdgeId(edge, occurrence))
|
||||
throw new TypeError("Artifact edge ID does not match its identity");
|
||||
};
|
||||
|
||||
|
||||
@@ -50,10 +50,9 @@ describe("artifact inventory entry order", () => {
|
||||
const parent = artifactOccurrenceAt(observed, parentPath);
|
||||
expect(observed.edges).toContainEqual(
|
||||
expect.objectContaining({
|
||||
logical_path: path,
|
||||
occurrence_id: occurrence.occurrence_id,
|
||||
relation: "contains",
|
||||
parent_artifact_id: parent.artifact_id,
|
||||
child_artifact_id: occurrence.artifact_id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,10 +75,9 @@ describe("expanded ASAR inventory containment", () => {
|
||||
const child = artifactOccurrenceAt(nested, path);
|
||||
expect(nested.edges).toContainEqual(
|
||||
expect.objectContaining({
|
||||
logical_path: path,
|
||||
occurrence_id: child.occurrence_id,
|
||||
relation: "contains",
|
||||
parent_artifact_id: artifactOccurrenceAt(nested, parent).artifact_id,
|
||||
child_artifact_id: child.artifact_id,
|
||||
}),
|
||||
);
|
||||
if (path.startsWith("resources/app.asar/"))
|
||||
|
||||
@@ -65,7 +65,7 @@ describe("artifact directory inventory", () => {
|
||||
expect.objectContaining({
|
||||
relation: "maps-source",
|
||||
parent_artifact_id: script?.artifact_id,
|
||||
child_artifact_id: sourceMap?.artifact_id,
|
||||
occurrence_id: sourceMap?.occurrence_id,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user