From 6d1faae1b877b8768afe0604cf03a4c2844da9a9 Mon Sep 17 00:00:00 2001 From: Dave Richardson Date: Mon, 31 Aug 2026 17:51:50 -0700 Subject: [PATCH] weave: move initial mesh progression into metadata - keep only settled mesh-support history membership in MeshInventory - record current/latest/next progression for every versioned mesh support artifact in MeshMetadata - teach ResourcePage history and raw-source readers to combine inventory structure with metadata progression - cover versioned and current-only support policies plus the regenerated sidecar execution surface --- src/core/weave/mesh_support_pages.ts | 62 ++++++------ src/core/weave/mesh_support_pages_test.ts | 116 +++++++++++++++++++++- src/core/weave/weave_test.ts | 38 ++++++- src/runtime/weave/page_model_assembly.ts | 4 +- src/runtime/weave/raw_source_panels.ts | 8 +- tests/integration/weave_test.ts | 23 ++++- 6 files changed, 210 insertions(+), 41 deletions(-) diff --git a/src/core/weave/mesh_support_pages.ts b/src/core/weave/mesh_support_pages.ts index 662f0f7..f72b9b8 100644 --- a/src/core/weave/mesh_support_pages.ts +++ b/src/core/weave/mesh_support_pages.ts @@ -432,11 +432,11 @@ function planInitialMeshSupportResourcePageWeave(input: { const versionedInventory = versionedSupportResources.find((support) => support.path === "_mesh/_inventory" ); - const updatedMeshMetadataTurtle = versionedInventory === undefined + const updatedMeshMetadataTurtle = versionedSupportResources.length === 0 ? input.currentMeshMetadataTurtle - : renderInitialMeshMetadataWithMeshInventoryProgression( + : renderInitialMeshMetadataWithSupportProgression( input.currentMeshMetadataTurtle, - versionedInventory, + versionedSupportResources, ); return { @@ -457,7 +457,7 @@ function planInitialMeshSupportResourcePageWeave(input: { }]), ], updatedFiles: [ - ...(versionedInventory === undefined ? [] : [{ + ...(versionedSupportResources.length === 0 ? [] : [{ path: "_mesh/_meta/meta.ttl", contents: updatedMeshMetadataTurtle, }]), @@ -469,41 +469,45 @@ function planInitialMeshSupportResourcePageWeave(input: { }; } -function renderInitialMeshMetadataWithMeshInventoryProgression( +function renderInitialMeshMetadataWithSupportProgression( currentMeshMetadataTurtle: string, - versionedInventory: MeshSupportResource, + versionedSupportResources: readonly MeshSupportResource[], ): string { const metadataWithPrefixes = ensureXsdPrefix(currentMeshMetadataTurtle); let blocks = splitTurtleBlocks(metadataWithPrefixes); - blocks = upsertSubjectBlockAfter( - blocks, - "_mesh", - "_mesh/_inventory", - renderInitialMeshInventoryMetaProgressionBlock(versionedInventory), - ); - blocks = upsertSubjectBlockAfter( - blocks, - "_mesh/_inventory", - versionedInventory.historyPath!, - renderInitialMeshInventoryHistoryMetaProgressionBlock(versionedInventory), - ); + let anchorPath = "_mesh"; + for (const support of versionedSupportResources) { + blocks = upsertSubjectBlockAfter( + blocks, + anchorPath, + support.path, + renderInitialMeshSupportMetaProgressionBlock(support), + ); + blocks = upsertSubjectBlockAfter( + blocks, + support.path, + support.historyPath!, + renderInitialMeshSupportHistoryMetaProgressionBlock(support), + ); + anchorPath = support.historyPath!; + } return `${blocks.join("\n\n")}\n`; } -function renderInitialMeshInventoryMetaProgressionBlock( - versionedInventory: MeshSupportResource, +function renderInitialMeshSupportMetaProgressionBlock( + support: MeshSupportResource, ): string { - return `<_mesh/_inventory> a sflo:MeshInventory, sflo:DigitalArtifact, sflo:RdfDocument ; - sflo:currentArtifactHistory <${versionedInventory.historyPath!}> ; + return `<${support.path}> + sflo:currentArtifactHistory <${support.historyPath!}> ; sflo:nextHistoryOrdinal "2"^^xsd:nonNegativeInteger .`; } -function renderInitialMeshInventoryHistoryMetaProgressionBlock( - versionedInventory: MeshSupportResource, +function renderInitialMeshSupportHistoryMetaProgressionBlock( + support: MeshSupportResource, ): string { - return `<${versionedInventory.historyPath!}> a sflo:ArtifactHistory ; - sflo:latestHistoricalState <${versionedInventory.statePath!}> ; + return `<${support.historyPath!}> + sflo:latestHistoricalState <${support.statePath!}> ; sflo:nextStateOrdinal "2"^^xsd:nonNegativeInteger .`; } @@ -720,7 +724,7 @@ function appendInitialSupportHistoryFactsToBlock( block: string, historyPath: string, ): string { - if (block.includes("sflo:currentArtifactHistory")) { + if (block.includes("sflo:hasArtifactHistory")) { return block; } if (!block.endsWith(" .")) { @@ -730,7 +734,7 @@ function appendInitialSupportHistoryFactsToBlock( } return `${ block.slice(0, -2) - } ;\n sflo:hasArtifactHistory <${historyPath}> ;\n sflo:currentArtifactHistory <${historyPath}> ;\n sflo:nextHistoryOrdinal "2"^^xsd:nonNegativeInteger .`; + } ;\n sflo:hasArtifactHistory <${historyPath}> .`; } function renderInitialSupportHistoryBlock( @@ -740,8 +744,6 @@ function renderInitialSupportHistoryBlock( return `<${historyPath}> a sflo:ArtifactHistory ; sflo:historyOrdinal "1"^^xsd:nonNegativeInteger ; sflo:hasHistoricalState <${statePath}> ; - sflo:latestHistoricalState <${statePath}> ; - sflo:nextStateOrdinal "2"^^xsd:nonNegativeInteger ; sflo:hasResourcePage <${historyPath}/index.html> .`; } diff --git a/src/core/weave/mesh_support_pages_test.ts b/src/core/weave/mesh_support_pages_test.ts index 02c764c..b68dc67 100644 --- a/src/core/weave/mesh_support_pages_test.ts +++ b/src/core/weave/mesh_support_pages_test.ts @@ -1,4 +1,10 @@ -import { assert, assertEquals, assertThrows } from "@std/assert"; +import { + assert, + assertEquals, + assertFalse, + assertStringIncludes, + assertThrows, +} from "@std/assert"; import { compareRdfContent } from "../../../dependencies/github.com/spectacular-voyage/accord/src/checker/compare_rdf.ts"; import { planMeshSupportResourcePages } from "./mesh_support_pages.ts"; import { WeaveInputError } from "./errors.ts"; @@ -51,6 +57,77 @@ Deno.test("mesh-support page-only append rejects a missing support subject", () ); }); +Deno.test("initial mesh-support history keeps mutable progression in MeshMetadata only", () => { + const plan = planMeshSupportResourcePages({ + meshBase, + currentMeshInventoryTurtle: initialSupportInventoryTurtle(), + currentMeshMetadataTurtle: initialMeshMetadataTurtle(), + currentMeshConfigTurtle: "# current config bytes\n", + supportHistoryPolicies: { + meshMetadata: "versioned", + meshInventory: "versioned", + config: "versioned", + }, + }); + const updatedInventory = + plan.updatedFiles.find((file) => + file.path === "_mesh/_inventory/inventory.ttl" + )?.contents ?? ""; + const updatedMetadata = + plan.updatedFiles.find((file) => file.path === "_mesh/_meta/meta.ttl") + ?.contents ?? ""; + + for ( + const mutablePredicate of [ + "sflo:currentArtifactHistory", + "sflo:nextHistoryOrdinal", + "sflo:latestHistoricalState", + "sflo:nextStateOrdinal", + ] + ) { + assertFalse( + updatedInventory.includes(mutablePredicate), + "MeshInventory retained mutable predicate " + mutablePredicate, + ); + } + for ( + const supportPath of [ + "_mesh/_meta", + "_mesh/_inventory", + "_mesh/_config", + ] + ) { + const historyPath = supportPath + "/_history001"; + assertStringIncludes( + updatedInventory, + "sflo:hasArtifactHistory <" + historyPath + ">", + ); + assertStringIncludes( + updatedInventory, + "sflo:hasHistoricalState <" + historyPath + "/_s0001>", + ); + assertStringIncludes(updatedMetadata, "<" + supportPath + ">"); + assertStringIncludes( + updatedMetadata, + "sflo:currentArtifactHistory <" + historyPath + ">", + ); + assertStringIncludes( + updatedMetadata, + "<" + historyPath + ">", + ); + assertStringIncludes( + updatedMetadata, + "sflo:latestHistoricalState <" + historyPath + "/_s0001>", + ); + } + assertEquals( + plan.createdFiles.find((file) => + file.path === "_mesh/_meta/_history001/_s0001/ttl/meta.ttl" + )?.contents, + updatedMetadata, + ); +}); + function planCurrentOnlyMeshSupportPages( currentMeshInventoryTurtle: string, ) { @@ -110,6 +187,43 @@ function requestedSupportPageFactsTurtle(): string { `; } +function initialSupportInventoryTurtle(): string { + return [ + "@base <" + meshBase + "> .", + "@prefix sflo: .", + "", + "<_mesh> a sflo:SemanticMesh .", + "", + "<_mesh/_meta> a sflo:MeshMetadata, sflo:DigitalArtifact, sflo:RdfDocument ;", + " sflo:hasWorkingLocatedFile <_mesh/_meta/meta.ttl> .", + "", + "<_mesh/_inventory> a sflo:MeshInventory, sflo:DigitalArtifact, sflo:RdfDocument ;", + " sflo:hasWorkingLocatedFile <_mesh/_inventory/inventory.ttl> .", + "", + "<_mesh/_config> a sflo:DigitalArtifact, sflo:RdfDocument ;", + " sflo:hasWorkingLocatedFile <_mesh/_config/config.ttl> .", + "", + "<_mesh/_meta/meta.ttl> a sflo:LocatedFile, sflo:RdfDocument .", + "", + "<_mesh/_inventory/inventory.ttl> a sflo:LocatedFile, sflo:RdfDocument .", + "", + "<_mesh/_config/config.ttl> a sflo:LocatedFile, sflo:RdfDocument .", + "", + ].join("\n"); +} + +function initialMeshMetadataTurtle(): string { + return [ + "@base <" + meshBase + "> .", + "@prefix sflo: .", + "", + "<_mesh> a sflo:SemanticMesh .", + "", + "<_mesh/_meta> a sflo:MeshMetadata, sflo:DigitalArtifact, sflo:RdfDocument .", + "", + ].join("\n"); +} + function encode(value: string): Uint8Array { return new TextEncoder().encode(value); } diff --git a/src/core/weave/weave_test.ts b/src/core/weave/weave_test.ts index a3a2bca..f78314a 100644 --- a/src/core/weave/weave_test.ts +++ b/src/core/weave/weave_test.ts @@ -212,16 +212,22 @@ Deno.test("planMeshSupportResourcePages adds current support ResourcePages inclu ); assertEquals( plan.updatedFiles.map((file) => file.path), - ["_mesh/_inventory/inventory.ttl"], + ["_mesh/_meta/meta.ttl", "_mesh/_inventory/inventory.ttl"], ); - const inventory = plan.updatedFiles[0]?.contents ?? ""; + const inventory = + plan.updatedFiles.find((file) => + file.path === "_mesh/_inventory/inventory.ttl" + )?.contents ?? ""; + const metadata = + plan.updatedFiles.find((file) => file.path === "_mesh/_meta/meta.ttl") + ?.contents ?? ""; assertStringIncludes( inventory, "sfcfg:hasConfig <_mesh/_config> ;\n sflo:hasResourcePage <_mesh/index.html> .", ); assertStringIncludes( inventory, - "sflo:hasWorkingLocatedFile <_mesh/_config/config.ttl> ;\n sflo:hasResourcePage <_mesh/_config/index.html> ;\n sflo:hasArtifactHistory <_mesh/_config/_history001> ;", + "sflo:hasWorkingLocatedFile <_mesh/_config/config.ttl> ;\n sflo:hasResourcePage <_mesh/_config/index.html> ;\n sflo:hasArtifactHistory <_mesh/_config/_history001> .", ); assertStringIncludes( inventory, @@ -245,6 +251,19 @@ Deno.test("planMeshSupportResourcePages adds current support ResourcePages inclu "sflo:currentArtifactHistory <_mesh/_meta/_history001>", ), ); + assertFalse( + inventory.includes( + "sflo:currentArtifactHistory <_mesh/_config/_history001>", + ), + ); + assertStringIncludes( + metadata, + "sflo:currentArtifactHistory <_mesh/_config/_history001> ;", + ); + assertStringIncludes( + metadata, + "sflo:latestHistoricalState <_mesh/_config/_history001/_s0001> ;", + ); assertStringIncludes( inventory, "<_mesh/_config/_history001/_s0001/ttl> a sflo:ArtifactManifestation, sflo:RdfDocument ;", @@ -321,7 +340,10 @@ Deno.test("planMeshSupportResourcePages keeps support ResourcePage facts when pa }, }); - const inventory = plan.updatedFiles[0]?.contents ?? ""; + const inventory = + plan.updatedFiles.find((file) => + file.path === "_mesh/_inventory/inventory.ttl" + )?.contents ?? ""; assertStringIncludes( inventory, "sflo:hasResourcePage <_mesh/_config/index.html>", @@ -340,7 +362,7 @@ Deno.test("planMeshSupportResourcePages keeps support ResourcePage facts when pa ); assertStringIncludes( inventory, - "sflo:hasArtifactHistory <_mesh/_config/_history001> ;", + "sflo:hasArtifactHistory <_mesh/_config/_history001> .", ); assertStringIncludes( inventory, @@ -4215,6 +4237,12 @@ Deno.test("planWeave renders an extracted term from a nested source without a ro const input = await createExtractedBobWeaveInput(); input.currentMeshInventoryTurtle = input.currentMeshInventoryTurtle .replace(" sflo:hasKnop ;\n", "") + .replace( + `<_mesh> sflo:hasKnop . + +`, + "", + ) .replace( ` a sflo:Knop ; sflo:hasWorkingKnopInventoryFile ; diff --git a/src/runtime/weave/page_model_assembly.ts b/src/runtime/weave/page_model_assembly.ts index ad55df8..16e226a 100644 --- a/src/runtime/weave/page_model_assembly.ts +++ b/src/runtime/weave/page_model_assembly.ts @@ -127,8 +127,8 @@ export async function visitResourcePageModels( () => collectHistoryGroupsByResourcePath( meshState.meshBase, - meshState.currentMeshInventoryTurtle, - "Could not parse the current MeshInventory while collecting ResourcePage histories.", + `${meshState.currentMeshInventoryTurtle}\n${meshState.currentMeshMetadataTurtle}`, + "Could not parse the current MeshInventory and MeshMetadata while collecting ResourcePage histories.", ), ); const meshInventoryPagePaths = await timeOptional( diff --git a/src/runtime/weave/raw_source_panels.ts b/src/runtime/weave/raw_source_panels.ts index e37e4d9..17c102c 100644 --- a/src/runtime/weave/raw_source_panels.ts +++ b/src/runtime/weave/raw_source_panels.ts @@ -70,11 +70,17 @@ export async function collectMeshSupportRawSourcePanels( string, readonly ResourcePageRawSourcePanelModel[] >(); - const quads = parseInventoryQuads( + const inventoryQuads = parseInventoryQuads( meshState.meshBase, meshState.currentMeshInventoryTurtle, "Could not parse the current MeshInventory while collecting mesh support source panels.", ); + const metadataQuads = parseInventoryQuads( + meshState.meshBase, + meshState.currentMeshMetadataTurtle, + "Could not parse the current MeshMetadata while collecting mesh support source panels.", + ); + const quads = [...inventoryQuads, ...metadataQuads]; if ( !(await addLatestHistoricalRawSourcePanelForCurrentArtifact( diff --git a/tests/integration/weave_test.ts b/tests/integration/weave_test.ts index 5d9ef5c..57eb4a8 100644 --- a/tests/integration/weave_test.ts +++ b/tests/integration/weave_test.ts @@ -148,7 +148,10 @@ Deno.test("executeWeave materializes current support ResourcePages for a docs-ro "docs/_mesh/index.html", ].sort(), ); - assertEquals(result.updatedPaths, ["docs/_mesh/_inventory/inventory.ttl"]); + assertEquals(result.updatedPaths, [ + "docs/_mesh/_meta/meta.ttl", + "docs/_mesh/_inventory/inventory.ttl", + ]); const inventory = await Deno.readTextFile( join(workspaceRoot, "docs/_mesh/_inventory/inventory.ttl"), ); @@ -158,7 +161,7 @@ Deno.test("executeWeave materializes current support ResourcePages for a docs-ro ); assertStringIncludes( inventory, - "sflo:hasWorkingLocatedFile <_mesh/_config/config.ttl> ;\n sflo:hasResourcePage <_mesh/_config/index.html> ;\n sflo:hasArtifactHistory <_mesh/_config/_history001> ;", + "sflo:hasWorkingLocatedFile <_mesh/_config/config.ttl> ;\n sflo:hasResourcePage <_mesh/_config/index.html> ;\n sflo:hasArtifactHistory <_mesh/_config/_history001> .", ); assertStringIncludes( inventory, @@ -178,6 +181,22 @@ Deno.test("executeWeave materializes current support ResourcePages for a docs-ro "sflo:currentArtifactHistory <_mesh/_meta/_history001>", ), ); + assertFalse( + inventory.includes( + "sflo:currentArtifactHistory <_mesh/_config/_history001>", + ), + ); + const metadata = await Deno.readTextFile( + join(workspaceRoot, "docs/_mesh/_meta/meta.ttl"), + ); + assertStringIncludes( + metadata, + "sflo:currentArtifactHistory <_mesh/_config/_history001> ;", + ); + assertStringIncludes( + metadata, + "sflo:latestHistoricalState <_mesh/_config/_history001/_s0001> ;", + ); const configPage = await Deno.readTextFile( join(workspaceRoot, "docs/_mesh/_config/index.html"), );