@tiinex/core 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/package.json +5 -5
  2. package/src/tooling/portable/adapters/cli/cli.handoff-manufacture.js +47 -10
  3. package/src/tooling/portable/adapters/node/bootstrapCarrier.manufacture.js +18 -0
  4. package/src/tooling/portable/adapters/node/workspaceCarrier.manufacture.js +13 -3
  5. package/src/tooling/portable/bootstrap/tiinex.llm.bootstrap.md +2 -2
  6. package/src/tooling/portable/handoff/bootstrapCarrier.manufacture.js +56 -0
  7. package/src/tooling/portable/handoff/contracts/tiinex.handoff.package.v1.schema.md +340 -77
  8. package/src/tooling/portable/handoff/manufacture.js +3 -1
  9. package/src/tooling/portable/handoff/recipientV2.artifactFirst.build.js +73 -32
  10. package/src/tooling/portable/handoff/recipientV2.artifactFirst.closure.js +1 -1
  11. package/src/tooling/portable/handoff/recipientV2.artifactFirst.inspect.js +9 -1
  12. package/src/tooling/portable/handoff/recipientV2.artifactFirst.materials.js +28 -6
  13. package/src/tooling/portable/handoff/recipientV2.artifactFirst.shared.js +8 -0
  14. package/src/tooling/portable/handoff/recipientV2.coldProjection.js +11 -6
  15. package/src/tooling/portable/handoff/recipientV2.entryContract.js +12 -0
  16. package/src/tooling/portable/handoff/recipientV2.humanOutput.js +48 -6
  17. package/src/tooling/portable/handoff/recipientV2.packageV1.build.js +55 -43
  18. package/src/tooling/portable/handoff/recipientV2.packageV1.contract.js +57 -31
  19. package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.helpers.js +63 -10
  20. package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +55 -16
  21. package/src/tooling/portable/handoff/recipientV2.packageV1.workspaceProjection.js +14 -1
  22. package/src/tooling/portable/handoff/recipientV2.topology.js +3 -4
  23. package/src/tooling/portable/handoff/recipientV2.topology.materials.js +14 -0
  24. package/src/tooling/portable/handoff/workspaceCarrier.manufacture.js +42 -13
@@ -7,9 +7,9 @@ import { RECIPIENT_V2_EXTERNAL_PAYLOAD_SCHEMA_TARGET, renderRecipientV2ExternalP
7
7
  import { RECIPIENT_V2_READ_PATH } from './recipientV2.topology.js';
8
8
  import { RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY, RECIPIENT_V2_SIBLING_ROUTE_INFERENCE, recipientV2EntryCurrentRead } from './recipientV2.entryContract.js';
9
9
  import { recipientV2TransportFacts } from './recipientV2.transportManifest.js';
10
- import { buildRecipientV2BootstrapCarrier, recipientV2ParentAuthority } from './recipientV2.topology.workspaces.js';
10
+ import { buildRecipientV2BootstrapCarrier, buildRecipientV2WorkspaceCarriers, recipientV2ParentAuthority } from './recipientV2.topology.workspaces.js';
11
11
  import { buildEndpointRolePointerChain, buildParticipantRolePointerChain } from './recipientV2.endpointRolePointers.js';
12
- import { bindingForWorkspace, detachedMaterial, duplicates, finding, roleMaterialTarget, routeClaimsDetachedMaterial, safeToken, uniqueFileIndex } from './recipientV2.topology.materials.js';
12
+ import { bindingForWorkspace, boundedWorkspaceClaimsDetachedRecovery, detachedMaterial, duplicates, finding, roleMaterialTarget, routeClaimsDetachedMaterial, safeToken, uniqueFileIndex } from './recipientV2.topology.materials.js';
13
13
  import { RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, RECIPIENT_V2_PACKAGE_V1_ROOT_PATH, RECIPIENT_V2_PACKAGE_V1_SCHEMA_ID, RECIPIENT_V2_PACKAGE_V1_SCHEMA_TARGET } from './recipientV2.packageV1.constants.js';
14
14
  import { renderHandoffPackageV1 } from './recipientV2.packageV1.contract.js';
15
15
  import { inspectRecipientFacingV2PackageV1 } from './recipientV2.packageV1.inspect.js';
@@ -39,20 +39,33 @@ function buildRecipientFacingV2PackageV1Prepared(input = {}, sealedByWorkspaceId
39
39
  const route = selected[0];
40
40
  const sourceWorkspaceById = new Map((sourceSurface.topology?.workspaces || []).map((item) => [String(item.workspaceId || ''), item]));
41
41
  const sourceByPath = new Map((sourceSurface.files || []).map((file) => [String(file.path || ''), file]));
42
- // The package-v1 carrier preserves every complete Workspace source explicitly
43
- // selected for carriage. Route closure remains selected and minimal, but an
44
- // explicitly carried Workspace is not pruned merely because it is outside the
45
- // selected Handoff's pre-Handoff closure. Qualified package-parent Workspaces
46
- // used only as read-only requirement providers remain detached closure material.
47
- const workspaceIds = [...sourceWorkspaceById.keys()].filter(Boolean).sort();
42
+ const descriptorBindingById = new Map((descriptor.workspaceArchiveBindings || []).map((binding) => [String(binding.workspaceId || ''), binding]));
43
+ const forcedMaterialWorkspaceIds = new Set([...(input.materialRepresentationWorkspaceIds || []), ...(input.genericMaterialWorkspaceIds || [])].map((value) => String(value || '')));
44
+ for (const binding of descriptor.workspaceArchiveBindings || []) if (String(binding.coverage || '') === 'bounded' || String(binding.representation?.kind || '') === 'bounded-workspace-snapshot') forcedMaterialWorkspaceIds.add(String(binding.workspaceId || ''));
45
+ const workspaceIds = [...new Set([...sourceWorkspaceById.keys(), ...descriptorBindingById.keys()])].filter(Boolean).sort();
48
46
  const workspacePlans = workspaceIds.map((workspaceId, index) => Object.freeze({ workspaceId, ordinal: index + 3, prefix: `001-${index + 3}`, slug: safeToken(workspaceId) }));
49
47
  const files = [];
50
- const topology = { root: null, read: null, workspaces: [], caches: [], endpointRoles: [], participantRoles: [], routes: [], bootstrap: null };
48
+ const topology = { root: null, read: null, workspaces: [], materialRepresentations: [], caches: [], endpointRoles: [], participantRoles: [], routes: [], bootstrap: null };
51
49
  const workspaceById = new Map();
50
+ const directWorkspaceProjections = [];
51
+ const materialPlans = [];
52
52
 
53
53
  for (const plan of workspacePlans) {
54
54
  const source = sourceWorkspaceById.get(plan.workspaceId);
55
- if (!source || String(source.coverage || '') !== 'complete') { findings.push(finding('error', 'portable.handoff-package-v1.workspace.complete-required', 'Package-local direct Workspace binding requires one complete source snapshot.', { workspaceId: plan.workspaceId })); continue; }
55
+ const descriptorBinding = descriptorBindingById.get(plan.workspaceId);
56
+ const useMaterialRepresentation = forcedMaterialWorkspaceIds.has(plan.workspaceId);
57
+ if (useMaterialRepresentation) {
58
+ if (!descriptorBinding) { findings.push(finding('error', 'portable.handoff-package-v1.material.workspace-binding-missing', 'Generic Material Representation selection requires one qualified source Workspace representation binding.', { workspaceId: plan.workspaceId })); continue; }
59
+ materialPlans.push(Object.freeze({
60
+ ...plan, binding: descriptorBinding,
61
+ workspacePath: `${plan.prefix}-${plan.slug}.workspace.md`,
62
+ archivePath: `${plan.prefix}-${plan.slug}.workspace.zip`,
63
+ payloadArtifactPath: `${plan.prefix}-1-workspace-representation-payload.trace.md`,
64
+ representationArtifactPath: `${plan.prefix}-2-workspace-representation.trace.md`
65
+ }));
66
+ continue;
67
+ }
68
+ if (!source || String(source.coverage || '') !== 'complete') { findings.push(finding('error', 'portable.handoff-package-v1.workspace.complete-required', 'Package-local direct Workspace binding requires one complete source snapshot; bounded material must use Material Representation Bindings.', { workspaceId: plan.workspaceId })); continue; }
56
69
  const sourceArchive = sourceByPath.get(String(source.archivePath || ''));
57
70
  if (!sourceArchive) { findings.push(finding('error', 'portable.handoff-package-v1.workspace.archive-missing', 'Selected complete Workspace archive is unavailable.', { workspaceId: plan.workspaceId })); continue; }
58
71
  const archiveData = packageFileByteView(sourceArchive);
@@ -69,43 +82,37 @@ function buildRecipientFacingV2PackageV1Prepared(input = {}, sealedByWorkspaceId
69
82
  files.push(workspaceFile);
70
83
  const parent = recipientV2ParentAuthority(workspaceFile, 'tiinex.workspace.v1', workspaceSchemaTarget(targetQualification), createdAt);
71
84
  const sealedPrepared = sealedByWorkspaceId.get(plan.workspaceId) || null;
85
+ let projection;
72
86
  if (sealedPrepared) {
73
- const protectedPayloadPath = `${plan.prefix}-${plan.slug}.protected.bin`;
74
- const protectedPayloadDescriptorPath = `${plan.prefix}-${plan.slug}.protected-payload.trace.md`;
75
- const transportEnvelopePath = `${plan.prefix}-${plan.slug}.transport-envelope.trace.md`;
76
- const projection = Object.freeze({
77
- workspaceId: plan.workspaceId, ordinal: plan.ordinal, workspacePath, workspaceSha256: workspaceFile.sha256,
78
- snapshotKind: 'password-sealed-workspace-byte-tree', bindingState: 'sealed', protectedPayloadPath, protectedPayloadDescriptorPath, transportEnvelopePath,
79
- protectedPayloadBytes: sealedPrepared.protectedPayload.byteLength, sourceWorkspaceTargetSha256: workspaceFile.sha256, sourceWorkspaceTargetBytes: workspaceFile.bytes, coverage: 'complete'
80
- });
81
- topology.workspaces.push(projection);
82
- workspaceById.set(plan.workspaceId, { ...projection, file: workspaceFile, parent, sealed: true });
87
+ projection = Object.freeze({ workspaceId: plan.workspaceId, ordinal: plan.ordinal, workspacePath, workspaceSha256: workspaceFile.sha256, snapshotKind: 'password-sealed-workspace-byte-tree', bindingState: 'sealed', protectedPayloadPath: `${plan.prefix}-${plan.slug}.protected.bin`, protectedPayloadDescriptorPath: `${plan.prefix}-${plan.slug}.protected-payload.trace.md`, transportEnvelopePath: `${plan.prefix}-${plan.slug}.transport-envelope.trace.md`, protectedPayloadBytes: sealedPrepared.protectedPayload.byteLength, sourceWorkspaceTargetSha256: workspaceFile.sha256, sourceWorkspaceTargetBytes: workspaceFile.bytes, coverage: 'complete' });
83
88
  } else {
84
89
  const archivePath = `${plan.prefix}-${plan.slug}.workspace.zip`;
85
90
  const archiveFile = exactFile(archivePath, archiveData, 'recipient-v2-package-v1-complete-workspace-snapshot', 'application/zip');
86
91
  files.push(archiveFile);
87
- const projection = Object.freeze({
88
- workspaceId: plan.workspaceId, ordinal: plan.ordinal, workspacePath, workspaceSha256: workspaceFile.sha256,
89
- archivePath, archiveSha256: archiveFile.sha256, sourceWorkspaceTargetInnerPath: innerPath,
90
- sourceWorkspaceTargetSha256: workspaceFile.sha256, sourceWorkspaceTargetBytes: workspaceFile.bytes, coverage: 'complete'
91
- });
92
- topology.workspaces.push(projection);
93
- workspaceById.set(plan.workspaceId, { ...projection, file: workspaceFile, parent });
92
+ projection = Object.freeze({ workspaceId: plan.workspaceId, ordinal: plan.ordinal, workspacePath, workspaceSha256: workspaceFile.sha256, archivePath, archiveSha256: archiveFile.sha256, archiveBytes: archiveFile.bytes, sourceWorkspaceTargetInnerPath: innerPath, sourceWorkspaceTargetSha256: workspaceFile.sha256, sourceWorkspaceTargetBytes: workspaceFile.bytes, coverage: 'complete' });
94
93
  }
94
+ topology.workspaces.push(projection); directWorkspaceProjections.push(projection);
95
+ workspaceById.set(plan.workspaceId, { ...projection, file: workspaceFile, parent, sealed: Boolean(sealedPrepared) });
95
96
  }
96
97
 
97
98
  if (findings.some((item) => item.severity === 'error')) return blocked('workspace-binding-blocked', findings);
98
-
99
+ const materialBindingsForContract = materialPlans.map((plan) => Object.freeze({ materialId: `workspace-${plan.workspaceId}`, workspaceId: plan.workspaceId, representationArtifactPath: plan.representationArtifactPath, carriageState: 'verified' }));
99
100
  const packageFile = finalizeFile({
100
101
  path: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH,
101
102
  kind: 'tiinex-handoff-package-artifact',
102
103
  logicalKind: 'recipient-v2-package-v1-root',
103
104
  mediaType: 'text/markdown',
104
- content: renderHandoffPackageV1({ createdAt, workspaces: topology.workspaces, carrierLineage: carrier.lineage || {}, carrierProfile: input.carrierProfile || null, startPath: RECIPIENT_V2_READ_PATH, bootstrapPath: hasBootstrap(input.bundle) ? '001-2-bootstrap.trace.md' : '' })
105
+ content: renderHandoffPackageV1({ createdAt, packageRole: input.packageRole || undefined, workspaces: directWorkspaceProjections, materialRepresentations: materialBindingsForContract, carrierLineage: carrier.lineage || {}, carrierProfile: input.carrierProfile || null, startPath: RECIPIENT_V2_READ_PATH, bootstrapPath: hasBootstrap(input.bundle) ? '001-2-bootstrap.trace.md' : '' })
105
106
  });
106
107
  files.push(packageFile);
107
108
  topology.root = Object.freeze({ path: packageFile.path, sha256: packageFile.sha256 });
108
109
  const packageParent = recipientV2ParentAuthority(packageFile, RECIPIENT_V2_PACKAGE_V1_SCHEMA_ID, RECIPIENT_V2_PACKAGE_V1_SCHEMA_TARGET, createdAt);
110
+ if (materialPlans.length) {
111
+ const materialWorkspaceById = buildRecipientV2WorkspaceCarriers({ workspacePlans: materialPlans, byPath: uniqueFileIndex(input.bundle?.files || [], findings), findings, createdAt, rootParent: packageParent, files, topology });
112
+ for (const [workspaceId, workspace] of materialWorkspaceById) workspaceById.set(workspaceId, workspace);
113
+ topology.materialRepresentations.push(...materialBindingsForContract);
114
+ }
115
+
109
116
 
110
117
  for (const workspace of topology.workspaces.filter((item) => item.bindingState === 'sealed')) {
111
118
  const prepared = sealedByWorkspaceId.get(workspace.workspaceId);
@@ -124,28 +131,33 @@ function buildRecipientFacingV2PackageV1Prepared(input = {}, sealedByWorkspaceId
124
131
 
125
132
  const byPath = uniqueFileIndex(input.bundle?.files || [], findings);
126
133
  const detached = detachedMaterial(descriptor, byPath, findings);
127
- const selectedDetached = detached.filter((item) => routeClaimsDetachedMaterial(route, item));
128
- const owningWorkspace = workspaceById.get(String(route.workspaceId || ''));
129
- let cache = null;
130
- if (selectedDetached.length && owningWorkspace) {
131
- const plan = workspacePlans.find((item) => item.workspaceId === owningWorkspace.workspaceId);
134
+ const cachePlanByWorkspace = new Map();
135
+ for (const plan of workspacePlans) {
136
+ const workspace = workspaceById.get(plan.workspaceId);
137
+ if (!workspace) continue;
138
+ const binding = bindingForWorkspace(descriptor, workspace.workspaceId);
139
+ const materials = detached.filter((item) => (workspace.workspaceId === String(route.workspaceId || '') && routeClaimsDetachedMaterial(route, item)) || boundedWorkspaceClaimsDetachedRecovery(binding, item));
140
+ if (!materials.length) continue;
132
141
  const artifactPath = `${plan.prefix}-1-cache.trace.md`;
133
142
  const archivePath = `${plan.prefix}-1-cache.zip`;
134
- const cacheEntries = selectedDetached.map((item, index) => ({ path: `material/${index + 1}-${safeToken(item.requirementId || item.referenceTarget || 'material')}.bin`, data: item.data }));
143
+ const cacheEntries = materials.map((item, index) => ({ path: `material/${index + 1}-${safeToken(item.requirementId || item.referenceTarget || 'material')}.bin`, data: item.data }));
135
144
  const cacheBytes = exportFileMapZipUint8Array(cacheEntries, 'portable.handoff-package-v1.cache.path.invalid');
136
145
  const cacheFile = finalizeFile({ path: archivePath, kind: 'handoff-material-cache', logicalKind: 'recipient-v2-package-v1-workspace-dependency-cache', mediaType: 'application/zip', data: cacheBytes });
137
146
  const cacheFacts = {
138
- workspaceId: owningWorkspace.workspaceId, archivePath, archiveBytes: cacheFile.bytes, archiveSha256: cacheFile.sha256,
139
- materials: selectedDetached.map((item, index) => ({ requirementId: item.requirementId, classification: item.classification, referenceTarget: item.referenceTarget, routeWorkspaceId: item.routeWorkspaceId, routePath: item.routePath, sourceRequirementId: item.sourceRequirementId, sourceWorkspaceId: item.sourceWorkspaceId, sourcePath: item.sourcePath, targetWorkspaceId: item.targetWorkspaceId, targetPath: item.targetPath, originalPath: item.originalPath, archiveEntry: cacheEntries[index].path, bytes: item.bytes, sha256: item.sha256 }))
147
+ workspaceId: workspace.workspaceId, archivePath, archiveBytes: cacheFile.bytes, archiveSha256: cacheFile.sha256,
148
+ materials: materials.map((item, index) => ({ requirementId: item.requirementId, classification: item.classification, referenceTarget: item.referenceTarget, routeWorkspaceId: item.routeWorkspaceId, routePath: item.routePath, sourceRequirementId: item.sourceRequirementId, sourceWorkspaceId: item.sourceWorkspaceId, sourcePath: item.sourcePath, targetWorkspaceId: item.targetWorkspaceId, targetPath: item.targetPath, originalPath: item.originalPath, archiveEntry: cacheEntries[index].path, bytes: item.bytes, sha256: item.sha256 }))
140
149
  };
141
- const cacheArtifact = finalizeFile({ path: artifactPath, kind: 'tiinex-external-payload-artifact', logicalKind: 'recipient-v2-package-v1-workspace-dependency-cache-reference', mediaType: 'text/markdown', transportFacts: recipientV2TransportFacts('workspace-scoped Handoff dependency cache', cacheFacts), content: renderRecipientV2ExternalPayload({ createdAt, parent: owningWorkspace.parent, title: `Workspace Dependency Cache — ${owningWorkspace.workspaceId}`, summary: 'Exact route-bounded dependency bytes not satisfied by a complete carried Workspace snapshot.', label: `${owningWorkspace.workspaceId} Handoff dependency cache`, kind: 'zip export', role: 'workspace-scoped Handoff dependency cache', location: archivePath, bytes: cacheFile.bytes, sha256: cacheFile.sha256, materials: cacheFacts.materials }) });
150
+ const cacheArtifact = finalizeFile({ path: artifactPath, kind: 'tiinex-external-payload-artifact', logicalKind: 'recipient-v2-package-v1-workspace-dependency-cache-reference', mediaType: 'text/markdown', transportFacts: recipientV2TransportFacts('workspace-scoped Handoff dependency cache', cacheFacts), content: renderRecipientV2ExternalPayload({ createdAt, parent: workspace.parent, title: `Workspace Dependency Cache — ${workspace.workspaceId}`, summary: 'Exact route-bounded or bounded-Workspace recovery dependency bytes outside the carried Workspace representation.', label: `${workspace.workspaceId} Handoff dependency cache`, kind: 'zip export', role: 'workspace-scoped Handoff dependency cache', location: archivePath, bytes: cacheFile.bytes, sha256: cacheFile.sha256, materials: cacheFacts.materials }) });
142
151
  files.push(cacheArtifact, cacheFile);
143
- cache = { workspaceId: owningWorkspace.workspaceId, artifactPath, archivePath, materials: cacheFacts.materials, parent: recipientV2ParentAuthority(cacheArtifact, 'tiinex.external.payload.v1', RECIPIENT_V2_EXTERNAL_PAYLOAD_SCHEMA_TARGET, createdAt) };
152
+ const cache = { workspaceId: workspace.workspaceId, artifactPath, archivePath, materials: cacheFacts.materials, parent: recipientV2ParentAuthority(cacheArtifact, 'tiinex.external.payload.v1', RECIPIENT_V2_EXTERNAL_PAYLOAD_SCHEMA_TARGET, createdAt) };
144
153
  topology.caches.push(Object.freeze({ workspaceId: cache.workspaceId, artifactPath, archivePath, materials: cache.materials }));
154
+ cachePlanByWorkspace.set(workspace.workspaceId, cache);
145
155
  }
156
+ const owningWorkspace = workspaceById.get(String(route.workspaceId || ''));
157
+ const cache = owningWorkspace ? (cachePlanByWorkspace.get(owningWorkspace.workspaceId) || null) : null;
146
158
 
147
159
  if (!owningWorkspace) findings.push(finding('error', 'portable.handoff-package-v1.route.workspace-unresolved', 'Selected Handoff route owning Workspace is not carried.'));
148
- else if (owningWorkspace.sealed) findings.push(finding('error', 'portable.handoff-package-v1.route.workspace-sealed-forbidden', 'Selected authoritative Handoff route Workspace must remain a clear verified snapshot in Secure Transport V1.', { workspaceId: owningWorkspace.workspaceId }));
160
+ else if (owningWorkspace.sealed) findings.push(finding('error', 'portable.handoff-package-v1.route.workspace-sealed-forbidden', 'Selected authoritative Handoff route must remain inside clear qualified carried material in Secure Transport V1.', { workspaceId: owningWorkspace.workspaceId }));
149
161
  else {
150
162
  const plan = workspacePlans.find((item) => item.workspaceId === owningWorkspace.workspaceId);
151
163
  const binding = bindingForWorkspace(descriptor, owningWorkspace.workspaceId);
@@ -163,12 +175,12 @@ function buildRecipientFacingV2PackageV1Prepared(input = {}, sealedByWorkspaceId
163
175
  sourceWorkspaceTargetSha256: owningWorkspace.sourceWorkspaceTargetSha256, workspaceRelativeHandoffPath: String(route.workspaceRelativePath || ''), handoffBytes: Number(routeEntry?.bytes || 0), handoffSha256: String(route.sha256 || ''), routeId: String(route.id || ''), parties: route.parties || {}, cacheArtifactPath: cache?.artifactPath || '',
164
176
  requiredContextBindings: Object.freeze((route.requiredClosure?.requirements || []).filter((entry) => entry.state === 'qualified' && entry.resolution?.kind === 'workspace-archive-entry').map((entry) => Object.freeze({ requirementId: String(entry.requirementId || ''), name: String(entry.name || ''), referenceTarget: String(entry.referenceTarget || ''), workspaceId: String(entry.resolution?.workspaceId || ''), workspaceRelativePath: String(entry.resolution?.workspaceRelativePath || entry.resolution?.innerPath || ''), bytes: Number(entry.resolution?.bytes || 0), sha256: String(entry.resolution?.sha256 || '') })))
165
177
  };
166
- const pointer = finalizeFile({ path: pointerPath, kind: 'handoff-route-pointer', logicalKind: 'recipient-v2-package-v1-handoff-route-pointer', mediaType: 'text/markdown', transportFacts: recipientV2TransportFacts('handoff-route', pointerFacts), content: renderRecipientV2Pointer({ createdAt, parent: lineageParent, role: 'handoff-route', title: `Handoff Route Pointer — ${String(route.parties?.to || owningWorkspace.workspaceId || 'recipient')}`, summary: 'Qualified package-local Pointer to one authoritative Handoff inside one complete Workspace snapshot.', prose: 'Follow only this Pointer carrier-ancestor closure for pre-Handoff package grounding, then resolve the authoritative Handoff path against the exact bound Workspace snapshot.', currentRead: [{ label: 'Workspace Id', value: `\`${owningWorkspace.workspaceId}\`` }, { label: 'Workspace', value: `[${owningWorkspace.workspaceId}](${owningWorkspace.workspacePath})` }, { label: 'Route Id', value: `\`${String(route.id || '')}\`` }, ...(pointerFacts.cacheArtifactPath ? [{ label: 'Workspace Dependency Cache', value: `[cache](${pointerFacts.cacheArtifactPath})` }] : []), { label: 'Handoff Workspace Path', value: `\`${String(route.workspaceRelativePath || '')}\`` }], destinations: [{ label: 'Workspace snapshot containing the qualified Handoff route', display: `${owningWorkspace.archivePath} :: ${String(route.workspaceRelativePath || '')}`, target: owningWorkspace.archivePath }], facts: pointerFacts }) });
178
+ const pointer = finalizeFile({ path: pointerPath, kind: 'handoff-route-pointer', logicalKind: 'recipient-v2-package-v1-handoff-route-pointer', mediaType: 'text/markdown', transportFacts: recipientV2TransportFacts('handoff-route', pointerFacts), content: renderRecipientV2Pointer({ createdAt, parent: lineageParent, role: 'handoff-route', title: `Handoff Route Pointer — ${String(route.parties?.to || owningWorkspace.workspaceId || 'recipient')}`, summary: 'Qualified package-local Pointer to one authoritative Handoff inside one qualified carried Workspace representation.', prose: 'Follow only this Pointer carrier-ancestor closure for pre-Handoff package grounding, then resolve the authoritative Handoff path against the exact qualified carried Workspace representation.', currentRead: [{ label: 'Workspace Id', value: `\`${owningWorkspace.workspaceId}\`` }, { label: 'Workspace', value: `[${owningWorkspace.workspaceId}](${owningWorkspace.workspacePath})` }, { label: 'Route Id', value: `\`${String(route.id || '')}\`` }, ...(pointerFacts.cacheArtifactPath ? [{ label: 'Workspace Dependency Cache', value: `[cache](${pointerFacts.cacheArtifactPath})` }] : []), { label: 'Handoff Workspace Path', value: `\`${String(route.workspaceRelativePath || '')}\`` }], destinations: [{ label: 'Workspace representation containing the qualified Handoff route', display: `${owningWorkspace.archivePath} :: ${String(route.workspaceRelativePath || '')}`, target: owningWorkspace.archivePath }], facts: pointerFacts }) });
167
179
  files.push(pointer);
168
180
  topology.routes.push(Object.freeze({ pointerPath, workspaceId: owningWorkspace.workspaceId, workspaceRelativeHandoffPath: String(route.workspaceRelativePath || ''), routeId: String(route.id || ''), sha256: String(route.sha256 || '') }));
169
181
  }
170
182
 
171
- const readFacts = { format: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, packageRootPath: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH, entryArtifactPath: RECIPIENT_V2_READ_PATH, artifactSurface: 'tiinex.handoff.package.v1-plus-exact-complete-workspace-snapshots', routeAuthority: 'qualified-handoff-route-pointer-plus-exact-handoff-bytes', routeSelectionAuthority: RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY, siblingRouteInference: RECIPIENT_V2_SIBLING_ROUTE_INFERENCE, carrierLineage: carrier.lineage || null, pathParentProjection: true, pathAuthority: false };
183
+ const readFacts = { format: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, packageRootPath: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH, entryArtifactPath: RECIPIENT_V2_READ_PATH, artifactSurface: 'tiinex.handoff.package.v1-plus-qualified-carried-material', routeAuthority: 'qualified-handoff-route-pointer-plus-exact-qualified-carried-handoff-bytes', routeSelectionAuthority: RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY, siblingRouteInference: RECIPIENT_V2_SIBLING_ROUTE_INFERENCE, carrierLineage: carrier.lineage || null, pathParentProjection: true, pathAuthority: false };
172
184
  const readFile = finalizeFile({ path: RECIPIENT_V2_READ_PATH, kind: 'handoff-recovery-pointer', logicalKind: 'recipient-v2-package-v1-recovery-orientation', mediaType: 'text/markdown', transportFacts: recipientV2TransportFacts('recovery-orientation', readFacts), content: renderRecipientV2Pointer({ createdAt, parent: packageParent, role: 'recovery-orientation', title: 'READ BEFORE PROCEEDING — Tiinex Handoff Carrier', summary: 'Qualified recovery/orientation Pointer for the package-v1 recipient carrier.', prose: 'Read this Start artifact first, qualify the declared Tooling bootstrap, then continue from the exact supplied Handoff Pointer path. Do not infer sibling routes or derive semantic authority from package placement.', currentRead: [...recipientV2EntryCurrentRead(), { label: 'Package Artifact', value: `[Handoff Package](${RECIPIENT_V2_PACKAGE_V1_ROOT_PATH})` }, { label: 'Carrier Dimension', value: `\`${String(carrier.lineage?.dimension || '001')}\`` }, ...(carrier.lineage?.parentDimension ? [{ label: 'Parent Carrier Dimension', value: `\`${String(carrier.lineage.parentDimension)}\`` }] : []), { label: 'Carrier Checkpoint', value: String(carrier.lineage?.checkpointKind || 'progression') }], destinations: [{ label: 'Handoff Package contract', target: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH }, ...(topology.bootstrap ? [{ label: 'Portable Tooling bootstrap', target: topology.bootstrap.artifactPath }] : []), ...topology.workspaces.map((workspace) => ({ label: `Workspace ${workspace.workspaceId}`, target: workspace.workspacePath })), ...topology.routes.map((item) => ({ label: `Selected Handoff route ${item.routeId || item.workspaceRelativeHandoffPath}`, target: item.pointerPath }))], facts: readFacts }) });
173
185
  files.push(readFile); topology.read = Object.freeze({ path: readFile.path, sha256: readFile.sha256 });
174
186
 
@@ -177,7 +189,7 @@ function buildRecipientFacingV2PackageV1Prepared(input = {}, sealedByWorkspaceId
177
189
  const sortedFiles = [...files].sort((a, b) => String(a.path || '').localeCompare(String(b.path || '')));
178
190
  const bundle = { ...(input.bundle || {}), files: Object.freeze(sortedFiles), handoffClosure: null, transportFormat: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID };
179
191
  const inspection = inspectRecipientFacingV2PackageV1(bundle);
180
- return Object.freeze({ status: inspection.status === 'valid' && !findings.some((item) => item.severity === 'error') ? 'ready' : 'blocked', files: Object.freeze(sortedFiles), topology: deepFreeze(topology), inspection, findings: Object.freeze([...findings, ...(inspection.findings || [])]), boundary: 'Recipient-facing tiinex.handoff.package.v1 carrier with exact complete Workspace artifacts/snapshots, bootstrap/cache External Payload ownership retained, and no redundant Workspace External Payload or Workspace Representation companions.' });
192
+ return Object.freeze({ status: inspection.status === 'valid' && !findings.some((item) => item.severity === 'error') ? 'ready' : 'blocked', files: Object.freeze(sortedFiles), topology: deepFreeze(topology), inspection, findings: Object.freeze([...findings, ...(inspection.findings || [])]), boundary: 'Recipient-facing tiinex.handoff.package.v1 carrier with direct complete Workspace bindings and/or generic complete/bounded Workspace Representation bindings; bootstrap/cache ownership is explicit and transport projection creates no semantic authority.' });
181
193
  }
182
194
 
183
195
 
@@ -9,23 +9,26 @@ import { normalizeHandoffCarrierProfile, normalizeWorkspaceIds } from './carrier
9
9
 
10
10
  export const HANDOFF_PACKAGE_ROLE = 'recipient-facing-handoff-carrier';
11
11
  export const WORKSPACE_PACKAGE_ROLE = 'recipient-facing-workspace-carrier';
12
+ export const BOOTSTRAP_PACKAGE_ROLE = 'recipient-facing-bootstrap-carrier';
12
13
  export const WORKSPACE_CARRIER_CANONICAL_BLOCKER = 'portable.handoff-package-v1.workspace-carrier.canonical-follow-through-required';
13
14
 
14
- function routeProfileForRole(role = HANDOFF_PACKAGE_ROLE) {
15
- return role === WORKSPACE_PACKAGE_ROLE
16
- ? Object.freeze({ routePlacementRule: 'none', continueFromRule: 'none', preHandoffClosureRule: 'none' })
17
- : Object.freeze({ routePlacementRule: 'authoritative-workspace-descended', continueFromRule: 'exact-package-local-handoff-pointer', preHandoffClosureRule: 'selected-pointer-carrier-ancestors' });
15
+ const PACKAGE_ROLES = Object.freeze([HANDOFF_PACKAGE_ROLE, WORKSPACE_PACKAGE_ROLE, BOOTSTRAP_PACKAGE_ROLE]);
16
+
17
+ function roleProfileForRole(role = HANDOFF_PACKAGE_ROLE) {
18
+ return role === HANDOFF_PACKAGE_ROLE
19
+ ? Object.freeze({ routePlacementRule: 'authoritative-workspace-descended', continueFromRule: 'exact-package-local-handoff-pointer', preHandoffClosureRule: 'selected-pointer-carrier-ancestors', routeTransportRule: 'selected-handoff-route-instruction', recipientProjectionRule: 'qualified-handoff-to-endpoint-only' })
20
+ : Object.freeze({ routePlacementRule: 'none', continueFromRule: 'none', preHandoffClosureRule: 'none', routeTransportRule: 'none', recipientProjectionRule: 'none' });
18
21
  }
19
22
 
20
23
  export function renderHandoffPackageV1(input = {}) {
21
24
  const createdAt = normalizeCreatedAt(input.createdAt || '');
22
25
  const lineage = input.carrierLineage || {};
23
26
  const carrierProfile = normalizeHandoffCarrierProfile(input.carrierProfile || null);
24
- const packageRole = [HANDOFF_PACKAGE_ROLE, WORKSPACE_PACKAGE_ROLE].includes(String(input.packageRole || '')) ? String(input.packageRole) : HANDOFF_PACKAGE_ROLE;
25
- const routeProfile = routeProfileForRole(packageRole);
26
- const workspaces = input.workspaces || [];
27
- const workspaceBlocks = workspaces.map((workspace) => renderWorkspaceBinding(workspace)).join('\n');
28
- const unsigned = `# Continuity Context\n\n- Envelope Schema: [tiinex.root.v1](${RECIPIENT_V2_ROOT_SCHEMA_TARGET})\n- Current\n - Current Schema: [tiinex.handoff.package.v1](${RECIPIENT_V2_PACKAGE_V1_SCHEMA_TARGET})\n - Created At: ${createdAt}\n - Summary: Recipient-facing self-contained Handoff carrier identity, discovery, exact complete Workspace snapshot bindings, and fail-closed qualification boundary.\n\n---\n\n# Handoff Package\n\n## Package Identity\n\n- Package Role: ${packageRole}\n- Carrier Kind: self-contained\n\n## Bootstrap Exposure\n\n- Start Artifact: [Start](${input.startPath || RECIPIENT_V2_READ_PATH})\n${input.bootstrapPath ? `- Tooling Bootstrap Descriptor: [Bootstrap](${input.bootstrapPath})\n` : '- Tooling Bootstrap Descriptor: [Bootstrap](001-2-bootstrap.trace.md)\n'}- Bootstrap Rule: start-then-qualified-bootstrap\n\n## Workspace Snapshot Bindings\n\n${workspaceBlocks || '- none'}\n\n## Route Discovery\n\n- Route Placement Rule: ${routeProfile.routePlacementRule}\n- Continue-From Rule: ${routeProfile.continueFromRule}\n- Pre-Handoff Closure Rule: ${routeProfile.preHandoffClosureRule}\n\n## Carrier Continuity\n\n- Carrier Dimension: ${String(lineage.dimension || '001')}\n${lineage.parentDimension ? `- Parent Carrier Dimension: ${String(lineage.parentDimension)}\n` : ''}- Carrier Checkpoint: ${String(lineage.checkpointKind || 'progression')}\n${lineage.majorReason ? `- Major Reason: ${String(lineage.majorReason)}\n` : ''}- Carrier Profile Id: ${carrierProfile.id || 'none'}\n- Required Major Workspace Ids: ${carrierProfile.requiredMajorWorkspaceIds.length ? carrierProfile.requiredMajorWorkspaceIds.join(', ') : 'none'}\n\n## Qualification Boundary\n\n- Receiver Qualification: reverify-carried-authority-and-bytes\n- Failure Policy: fail-closed\n- Derived Inventory Authority: none\n\n## Interpretation Limits\n\n- Does Not Mean: package placement, discovery ancestry, or byte integrity creates Handoff, Workspace, Role, participation, acceptance, provenance, or Parent authority\n- Must Not Be Used To Claim: carrier convenience metadata overrides the authoritative contained artifacts or exact qualified source bytes\n- Generic Payload Boundary: bootstrap/cache payloads retain explicit External Payload ownership when required; complete Workspace snapshot binding is package-local only\n- Generic Representation Boundary: bounded, partial, independently selectable, multi-representation, or external-lifecycle Workspace representations require the generic Workspace Representation contract\n- Carrier Profile Boundary: required Workspace identifiers come only from the explicit carrier profile; literal project Workspace names have no generic semantic meaning\n\n---\n\n# Continuity Integrity\n\n- [sha256-base64url-c14n-v2](${C14N_V2_VALIDATOR_TARGET})\n - Towards: self\n - Value: pending\n`;
27
+ const packageRole = PACKAGE_ROLES.includes(String(input.packageRole || '')) ? String(input.packageRole) : HANDOFF_PACKAGE_ROLE;
28
+ const roleProfile = roleProfileForRole(packageRole);
29
+ const workspaceBlocks = (input.workspaces || []).map((workspace) => renderWorkspaceBinding(workspace)).join('\n');
30
+ const materialBlocks = (input.materialRepresentations || []).map((material) => renderMaterialRepresentationBinding(material)).join('\n');
31
+ const unsigned = `# Continuity Context\n\n- Envelope Schema: [tiinex.root.v1](${RECIPIENT_V2_ROOT_SCHEMA_TARGET})\n- Current\n - Current Schema: [tiinex.handoff.package.v1](${RECIPIENT_V2_PACKAGE_V1_SCHEMA_TARGET})\n - Created At: ${createdAt}\n - Summary: Recipient-facing self-contained carrier identity, Start/bootstrap exposure, qualified source-material bindings, route discovery when declared, and transport projection boundaries.\n\n---\n\n# Handoff Package\n\n## Package Identity\n\n- Package Role: ${packageRole}\n- Carrier Kind: self-contained\n\n## Bootstrap Exposure\n\n- Start Artifact: [Start](${input.startPath || RECIPIENT_V2_READ_PATH})\n${input.bootstrapPath ? `- Tooling Bootstrap Descriptor: [Bootstrap](${input.bootstrapPath})\n` : '- Tooling Bootstrap Descriptor: [Bootstrap](001-2-bootstrap.trace.md)\n'}- Bootstrap Rule: start-then-qualified-bootstrap\n\n## Workspace Snapshot Bindings\n\n${workspaceBlocks || '- none'}\n\n## Material Representation Bindings\n\n${materialBlocks || '- none'}\n\n## Route Discovery\n\n- Route Placement Rule: ${roleProfile.routePlacementRule}\n- Continue-From Rule: ${roleProfile.continueFromRule}\n- Pre-Handoff Closure Rule: ${roleProfile.preHandoffClosureRule}\n\n## Transport Projection\n\n- Generic Transport Rule: start-artifact-instruction\n- Route Transport Rule: ${roleProfile.routeTransportRule}\n- Recipient Projection Rule: ${roleProfile.recipientProjectionRule}\n\n## Carrier Continuity\n\n- Carrier Dimension: ${String(lineage.dimension || '001')}\n${lineage.parentDimension ? `- Parent Carrier Dimension: ${String(lineage.parentDimension)}\n` : ''}- Carrier Checkpoint: ${String(lineage.checkpointKind || 'progression')}\n${lineage.majorReason ? `- Major Reason: ${String(lineage.majorReason)}\n` : ''}- Carrier Profile Id: ${carrierProfile.id || 'none'}\n- Required Major Workspace Ids: ${carrierProfile.requiredMajorWorkspaceIds.length ? carrierProfile.requiredMajorWorkspaceIds.join(', ') : 'none'}\n\n## Qualification Boundary\n\n- Receiver Qualification: reverify-carried-authority-and-bytes\n- Failure Policy: fail-closed\n- Derived Inventory Authority: none\n\n## Interpretation Limits\n\n- Does Not Mean: package placement, discovery ancestry, byte integrity, Role presence, Workspace identity, or transport destination creates Handoff, recipient, holder, participation, acceptance, provenance, Parent, project membership, or work authority\n- Must Not Be Used To Claim: carrier convenience metadata overrides authoritative contained artifacts, exact qualified source bytes, or the selected Handoff To endpoint when recipient projection is permitted\n- Generic Payload Boundary: bootstrap/cache payloads retain explicit External Payload ownership when required; direct complete Workspace snapshot binding is package-local only\n- Generic Representation Boundary: independently selectable complete/bounded Workspace representation semantics remain owned by qualified tiinex.workspace.representation.v1 bindings\n- Carrier Profile Boundary: required Workspace identifiers come only from the explicit carrier profile; literal project Workspace names have no generic semantic meaning\n\n---\n\n# Continuity Integrity\n\n- [sha256-base64url-c14n-v2](${C14N_V2_VALIDATOR_TARGET})\n - Towards: self\n - Value: pending\n`;
29
32
  const sealed = sealC14nV2Self(unsigned);
30
33
  if (sealed.state !== 'sealed') throw new Error(`portable.handoff-package-v1.integrity.seal-failed:${sealed.reason || sealed.state}`);
31
34
  return `${sealed.markdown}\n`;
@@ -33,15 +36,14 @@ export function renderHandoffPackageV1(input = {}) {
33
36
 
34
37
  export function parseHandoffPackageV1(markdown = '') {
35
38
  const body = String(markdown || '');
36
- const workspaceHeading = '## Workspace Snapshot Bindings';
37
- const workspaceStart = body.indexOf(workspaceHeading);
38
- const workspaceEnd = workspaceStart >= 0 ? body.indexOf('## Route Discovery', workspaceStart + workspaceHeading.length) : -1;
39
- const workspacesSection = workspaceStart >= 0 ? body.slice(workspaceStart + workspaceHeading.length, workspaceEnd >= 0 ? workspaceEnd : undefined).trim() : '';
40
- const workspaces = parseWorkspaceBindings(workspacesSection);
39
+ const workspaces = parseWorkspaceBindings(sectionText(body, 'Workspace Snapshot Bindings'));
40
+ const materialRepresentations = parseMaterialRepresentationBindings(sectionText(body, 'Material Representation Bindings'));
41
41
  return Object.freeze({
42
42
  packageRole: field(sectionText(body, 'Package Identity'), 'Package Role'), carrierKind: field(sectionText(body, 'Package Identity'), 'Carrier Kind'),
43
43
  startPath: markdownTarget(field(sectionText(body, 'Bootstrap Exposure'), 'Start Artifact')), bootstrapPath: markdownTarget(field(sectionText(body, 'Bootstrap Exposure'), 'Tooling Bootstrap Descriptor')), bootstrapRule: field(sectionText(body, 'Bootstrap Exposure'), 'Bootstrap Rule'),
44
- workspaces: Object.freeze(workspaces), routePlacementRule: field(sectionText(body, 'Route Discovery'), 'Route Placement Rule'), continueFromRule: field(sectionText(body, 'Route Discovery'), 'Continue-From Rule'), preHandoffClosureRule: field(sectionText(body, 'Route Discovery'), 'Pre-Handoff Closure Rule'),
44
+ workspaces: Object.freeze(workspaces), materialRepresentations: Object.freeze(materialRepresentations),
45
+ routePlacementRule: field(sectionText(body, 'Route Discovery'), 'Route Placement Rule'), continueFromRule: field(sectionText(body, 'Route Discovery'), 'Continue-From Rule'), preHandoffClosureRule: field(sectionText(body, 'Route Discovery'), 'Pre-Handoff Closure Rule'),
46
+ genericTransportRule: field(sectionText(body, 'Transport Projection'), 'Generic Transport Rule'), routeTransportRule: field(sectionText(body, 'Transport Projection'), 'Route Transport Rule'), recipientProjectionRule: field(sectionText(body, 'Transport Projection'), 'Recipient Projection Rule'),
45
47
  carrierDimension: field(sectionText(body, 'Carrier Continuity'), 'Carrier Dimension'), parentCarrierDimension: field(sectionText(body, 'Carrier Continuity'), 'Parent Carrier Dimension'), carrierCheckpoint: field(sectionText(body, 'Carrier Continuity'), 'Carrier Checkpoint'), majorReason: field(sectionText(body, 'Carrier Continuity'), 'Major Reason'), carrierProfileId: normalizeProfileId(field(sectionText(body, 'Carrier Continuity'), 'Carrier Profile Id')), requiredMajorWorkspaceIds: normalizeWorkspaceIds(field(sectionText(body, 'Carrier Continuity'), 'Required Major Workspace Ids')),
46
48
  receiverQualification: field(sectionText(body, 'Qualification Boundary'), 'Receiver Qualification'), failurePolicy: field(sectionText(body, 'Qualification Boundary'), 'Failure Policy'), derivedInventoryAuthority: field(sectionText(body, 'Qualification Boundary'), 'Derived Inventory Authority')
47
49
  });
@@ -49,36 +51,35 @@ export function parseHandoffPackageV1(markdown = '') {
49
51
 
50
52
  export function validatePackageFields(value, findings) {
51
53
  const packageRole = String(value?.packageRole || '');
52
- const roleKnown = [HANDOFF_PACKAGE_ROLE, WORKSPACE_PACKAGE_ROLE].includes(packageRole);
53
- if (!roleKnown) findings.push(finding('error', 'portable.handoff-package-v1.field.packageRole.invalid', 'Handoff package v1 Package Role is missing or invalid.', { field: 'packageRole', expected: `${HANDOFF_PACKAGE_ROLE}|${WORKSPACE_PACKAGE_ROLE}`, observed: packageRole }));
54
- const routeProfile = routeProfileForRole(roleKnown ? packageRole : HANDOFF_PACKAGE_ROLE);
54
+ const roleKnown = PACKAGE_ROLES.includes(packageRole);
55
+ if (!roleKnown) findings.push(finding('error', 'portable.handoff-package-v1.field.packageRole.invalid', 'Handoff package v1 Package Role is missing or invalid.', { field: 'packageRole', expected: PACKAGE_ROLES.join('|'), observed: packageRole }));
56
+ const roleProfile = roleProfileForRole(roleKnown ? packageRole : HANDOFF_PACKAGE_ROLE);
55
57
  const exact = [
56
- ['carrierKind', 'self-contained'], ['bootstrapRule', 'start-then-qualified-bootstrap'], ['routePlacementRule', routeProfile.routePlacementRule], ['continueFromRule', routeProfile.continueFromRule], ['preHandoffClosureRule', routeProfile.preHandoffClosureRule], ['receiverQualification', 'reverify-carried-authority-and-bytes'], ['failurePolicy', 'fail-closed'], ['derivedInventoryAuthority', 'none']
58
+ ['carrierKind', 'self-contained'], ['bootstrapRule', 'start-then-qualified-bootstrap'], ['routePlacementRule', roleProfile.routePlacementRule], ['continueFromRule', roleProfile.continueFromRule], ['preHandoffClosureRule', roleProfile.preHandoffClosureRule], ['genericTransportRule', 'start-artifact-instruction'], ['routeTransportRule', roleProfile.routeTransportRule], ['recipientProjectionRule', roleProfile.recipientProjectionRule], ['receiverQualification', 'reverify-carried-authority-and-bytes'], ['failurePolicy', 'fail-closed'], ['derivedInventoryAuthority', 'none']
57
59
  ];
58
60
  for (const [key, expected] of exact) if (String(value?.[key] || '') !== expected) findings.push(finding('error', `portable.handoff-package-v1.field.${key}.invalid`, 'Handoff package v1 required closed-domain field is missing or invalid.', { field: key, expected, observed: String(value?.[key] || '') }));
59
61
  if (!value?.startPath || !value?.bootstrapPath) findings.push(finding('error', 'portable.handoff-package-v1.bootstrap-exposure-invalid', 'Start Artifact and Tooling Bootstrap Descriptor must be package-local links.'));
60
- if (!Array.isArray(value?.workspaces) || !value.workspaces.length) findings.push(finding('error', 'portable.handoff-package-v1.workspace-bindings-missing', 'Handoff package v1 requires at least one complete Workspace snapshot binding.'));
61
62
  for (const binding of value?.workspaces || []) validateWorkspaceBinding(binding, findings);
63
+ for (const binding of value?.materialRepresentations || []) validateMaterialRepresentationBinding(binding, findings);
64
+ const directCount = Array.isArray(value?.workspaces) ? value.workspaces.length : 0;
65
+ const materialCount = Array.isArray(value?.materialRepresentations) ? value.materialRepresentations.length : 0;
66
+ if (packageRole === BOOTSTRAP_PACKAGE_ROLE && (directCount || materialCount)) findings.push(finding('error', 'portable.handoff-package-v1.bootstrap-carrier.material-forbidden', 'Bootstrap-only carrier must declare no Workspace Snapshot Bindings and no Material Representation Bindings.', { directCount, materialCount }));
67
+ if ([WORKSPACE_PACKAGE_ROLE, HANDOFF_PACKAGE_ROLE].includes(packageRole) && !(directCount + materialCount)) findings.push(finding('error', 'portable.handoff-package-v1.source-material-bindings-missing', 'Workspace/Handoff carrier requires at least one qualified source-material binding across Workspace Snapshot Bindings and Material Representation Bindings.'));
62
68
  if (!validCarrierDimension(value?.carrierDimension)) findings.push(finding('error', 'portable.handoff-package-v1.carrier-dimension-invalid', 'Carrier Dimension must be a canonical numeric hyphen path.', { value: value?.carrierDimension || '' }));
63
69
  if (value?.parentCarrierDimension && !validCarrierDimension(value.parentCarrierDimension)) findings.push(finding('error', 'portable.handoff-package-v1.parent-carrier-dimension-invalid', 'Parent Carrier Dimension must be a canonical numeric hyphen path.', { value: value.parentCarrierDimension || '' }));
64
70
  if (!['progression', 'major'].includes(String(value?.carrierCheckpoint || ''))) findings.push(finding('error', 'portable.handoff-package-v1.carrier-checkpoint-invalid', 'Carrier Checkpoint must be progression or major.'));
65
71
  if (value?.carrierCheckpoint === 'major' && !String(value.majorReason || '').trim()) findings.push(finding('error', 'portable.handoff-package-v1.major-reason-missing', 'Major carrier requires one meaningful Major Reason.'));
66
- if (value?.carrierCheckpoint === 'major') {
67
- if ((value.requiredMajorWorkspaceIds || []).length && !String(value.carrierProfileId || '').trim()) findings.push(finding('error', 'portable.handoff-package-v1.major-carrier-profile-missing', 'Named Major Workspace requirements require one explicit carrier profile id.'));
68
- const carried = new Set((value?.workspaces || []).map((item) => String(item.workspaceId || '').trim().toLowerCase()).filter(Boolean));
69
- const missing = normalizeWorkspaceIds(value.requiredMajorWorkspaceIds || []).filter((workspaceId) => !carried.has(workspaceId));
70
- if (missing.length) findings.push(finding('error', 'portable.handoff-package-v1.major-source-closure-incomplete', 'Major package-v1 carrier is missing one or more Workspace snapshot bindings required by its explicit carrier profile.', { carrierProfileId: String(value.carrierProfileId || ''), missingWorkspaceIds: missing }));
71
- }
72
+ if (value?.carrierCheckpoint === 'major' && (value.requiredMajorWorkspaceIds || []).length && !String(value.carrierProfileId || '').trim()) findings.push(finding('error', 'portable.handoff-package-v1.major-carrier-profile-missing', 'Named Major Workspace requirements require one explicit carrier profile id.'));
72
73
  }
73
74
 
74
75
  function parseWorkspaceBindings(text = '') {
75
76
  const out = [];
76
77
  const re = /^-\s+([^\n]+)\n((?:\s{2}-\s+[^\n]+\n?)*)/gm;
77
78
  for (const match of String(text || '').matchAll(re)) {
79
+ if (String(match[1] || '').trim().toLowerCase() === 'none') continue;
78
80
  const current = { label: String(match[1] || '').trim() };
79
81
  for (const line of String(match[2] || '').split('\n')) {
80
- const fieldMatch = line.match(/^\s{2}-\s+([^:]+):\s*(.*)$/);
81
- if (!fieldMatch) continue;
82
+ const fieldMatch = line.match(/^\s{2}-\s+([^:]+):\s*(.*)$/); if (!fieldMatch) continue;
82
83
  const key = fieldMatch[1].trim(); const value = fieldMatch[2].trim();
83
84
  if (key === 'Workspace Id') current.workspaceId = value;
84
85
  else if (key === 'Workspace Artifact') current.workspaceArtifactPath = markdownTarget(value);
@@ -100,6 +101,24 @@ function parseWorkspaceBindings(text = '') {
100
101
  return out.map((item) => Object.freeze({ ...item, byteSize: item.byteSize ?? null }));
101
102
  }
102
103
 
104
+ function parseMaterialRepresentationBindings(text = '') {
105
+ const out = [];
106
+ const re = /^-\s+([^\n]+)\n((?:\s{2}-\s+[^\n]+\n?)*)/gm;
107
+ for (const match of String(text || '').matchAll(re)) {
108
+ if (String(match[1] || '').trim().toLowerCase() === 'none') continue;
109
+ const current = { label: String(match[1] || '').trim() };
110
+ for (const line of String(match[2] || '').split('\n')) {
111
+ const fieldMatch = line.match(/^\s{2}-\s+([^:]+):\s*(.*)$/); if (!fieldMatch) continue;
112
+ const key = fieldMatch[1].trim(); const value = fieldMatch[2].trim();
113
+ if (key === 'Material Id') current.materialId = value;
114
+ else if (key === 'Workspace Representation') current.workspaceRepresentationPath = markdownTarget(value);
115
+ else if (key === 'Carriage State') current.carriageState = value;
116
+ else if (key === 'Notes') current.notes = value;
117
+ }
118
+ out.push(current);
119
+ }
120
+ return out.map((item) => Object.freeze({ ...item }));
121
+ }
103
122
 
104
123
  function renderWorkspaceBinding(workspace = {}) {
105
124
  const sealed = String(workspace.snapshotKind || '') === 'password-sealed-workspace-byte-tree' || String(workspace.bindingState || '') === 'sealed';
@@ -107,6 +126,12 @@ function renderWorkspaceBinding(workspace = {}) {
107
126
  return `- ${workspace.workspaceId}\n - Workspace Id: ${workspace.workspaceId}\n - Workspace Artifact: [${workspace.workspaceId} Workspace](${workspace.workspacePath})\n - Snapshot Path: [${workspace.workspaceId} Snapshot](${workspace.archivePath})\n - Workspace Artifact Inner Path: \`${workspace.sourceWorkspaceTargetInnerPath}\`\n - Snapshot Kind: exact-workspace-byte-tree-archive\n - Coverage: complete\n - Binding State: verified\n - Integrity Method: sha256\n - Integrity Value: ${workspace.archiveSha256}\n - Byte Size: ${workspace.archiveBytes || ''}`.replace(/\n - Byte Size: $/, '');
108
127
  }
109
128
 
129
+ function renderMaterialRepresentationBinding(material = {}) {
130
+ const id = String(material.materialId || material.workspaceId || 'material');
131
+ const path = String(material.workspaceRepresentationPath || material.representationArtifactPath || '');
132
+ return `- ${id}\n - Material Id: ${id}\n - Workspace Representation: [${id} Workspace Representation](${path})\n - Carriage State: ${String(material.carriageState || 'verified')}${material.notes ? `\n - Notes: ${String(material.notes)}` : ''}`;
133
+ }
134
+
110
135
  function validateWorkspaceBinding(binding = {}, findings = []) {
111
136
  const workspaceId = String(binding.workspaceId || '');
112
137
  if (!workspaceId || !binding.workspaceArtifactPath || String(binding.coverage || '') !== 'complete') findings.push(finding('error', 'portable.handoff-package-v1.workspace-binding-common-invalid', 'Workspace binding requires Workspace Id, Workspace Artifact, and complete coverage.', { workspaceId }));
@@ -124,7 +149,8 @@ function validateWorkspaceBinding(binding = {}, findings = []) {
124
149
  findings.push(finding('error', 'portable.handoff-package-v1.workspace-binding-kind-invalid', 'Workspace binding Snapshot Kind is unsupported.', { workspaceId, snapshotKind: kind }));
125
150
  }
126
151
 
127
- function normalizeProfileId(value = '') {
128
- const text = String(value || '').trim();
129
- return text.toLowerCase() === 'none' ? '' : text;
152
+ function validateMaterialRepresentationBinding(binding = {}, findings = []) {
153
+ if (!String(binding.materialId || '').trim() || !String(binding.workspaceRepresentationPath || '').trim() || !['verified', 'unresolved'].includes(String(binding.carriageState || ''))) findings.push(finding('error', 'portable.handoff-package-v1.material-representation-binding-invalid', 'Material Representation binding requires Material Id, Workspace Representation link, and closed-domain Carriage State.', { materialId: String(binding.materialId || ''), carriageState: String(binding.carriageState || '') }));
130
154
  }
155
+
156
+ function normalizeProfileId(value = '') { const text = String(value || '').trim(); return text.toLowerCase() === 'none' ? '' : text; }
@@ -1,8 +1,9 @@
1
1
  import { packageFileBytes, sha256Hex } from '../../../export/package.bytes.js';
2
- import { parseRecipientV2ExternalPayload, parseRecipientV2Pointer } from './recipientV2.artifacts.js';
2
+ import { parseRecipientV2ExternalPayload, parseRecipientV2Pointer, parseRecipientV2WorkspaceRepresentation } from './recipientV2.artifacts.js';
3
3
  import { RECIPIENT_V2_READ_PATH } from './recipientV2.topology.js';
4
4
  import { RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY, RECIPIENT_V2_SIBLING_ROUTE_INFERENCE } from './recipientV2.entryContract.js';
5
5
  import { inspectStoredWorkspaceArchive } from './workspaceByteProvider.js';
6
+ import { recipientEntriesFingerprint } from './recipientV2.topology.helpers.js';
6
7
  import { parentTrace } from './recipientV2.lineage.js';
7
8
  import { finding } from './recipientV2.topology.materials.js';
8
9
  import { RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, RECIPIENT_V2_PACKAGE_V1_ROOT_PATH } from './recipientV2.packageV1.constants.js';
@@ -62,16 +63,15 @@ export function deriveVisibleFacts({ file = null, markdown = '', schemaId = '',
62
63
  const role = String(visible.role || '');
63
64
  if (!role) return null;
64
65
  const base = { factsFormat: 'portable-recipient-v2', factsVersion: 1, role };
65
- if (role === 'recovery-orientation') { const workspaceMode = String(packageContract?.packageRole || '') === 'recipient-facing-workspace-carrier'; return { ...base, format: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, packageRole: String(packageContract?.packageRole || ''), packageRootPath: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH, entryArtifactPath: RECIPIENT_V2_READ_PATH, routeAuthority: workspaceMode ? 'none' : 'qualified-handoff-route-pointer-plus-exact-handoff-bytes', routeSelectionAuthority: workspaceMode ? 'none' : RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY, siblingRouteInference: workspaceMode ? false : RECIPIENT_V2_SIBLING_ROUTE_INFERENCE }; }
66
+ if (role === 'recovery-orientation') { const routed = String(packageContract?.packageRole || '') === 'recipient-facing-handoff-carrier'; return { ...base, format: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID, packageRole: String(packageContract?.packageRole || ''), packageRootPath: RECIPIENT_V2_PACKAGE_V1_ROOT_PATH, entryArtifactPath: RECIPIENT_V2_READ_PATH, routeAuthority: routed ? 'qualified-handoff-route-pointer-plus-exact-handoff-bytes' : 'none', routeSelectionAuthority: routed ? RECIPIENT_V2_ROUTE_SELECTION_AUTHORITY : 'none', siblingRouteInference: routed ? RECIPIENT_V2_SIBLING_ROUTE_INFERENCE : false }; }
66
67
  if (role === 'handoff-route') {
67
68
  const workspaceId = String(visible.workspaceId || '');
68
- const binding = (packageContract?.workspaces || []).find((item) => item.workspaceId === workspaceId) || null;
69
- const archiveFile = binding ? oneFile(index, binding.snapshotPath) : null;
70
- const workspaceFile = binding ? oneFile(index, binding.workspaceArtifactPath) : null;
71
- const parsed = archiveFile ? inspectStoredWorkspaceArchive(packageFileBytes(archiveFile), { ownedBytes: true }) : null;
72
- const handoffEntry = (parsed?.entries || []).find((entry) => entry.path === visible.handoffWorkspacePath) || null;
69
+ const direct = directWorkspaceClosure(index, packageContract, workspaceId);
70
+ const generic = direct ? null : genericWorkspaceClosure(index, packageContract, { workspaceId });
71
+ const closure = direct || generic;
72
+ const handoffEntry = (closure?.parsed?.entries || []).find((entry) => entry.path === visible.handoffWorkspacePath) || null;
73
73
  const current = sectionText(markdown, 'Current Read');
74
- return { ...base, workspaceId, workspaceArtifactPath: binding?.workspaceArtifactPath || '', workspaceArtifactSha256: workspaceFile ? sha256Hex(packageFileBytes(workspaceFile)) : '', archivePath: binding?.snapshotPath || '', archiveSha256: archiveFile ? sha256Hex(packageFileBytes(archiveFile)) : '', sourceWorkspaceTargetInnerPath: binding?.workspaceArtifactInnerPath || '', sourceWorkspaceTargetSha256: workspaceFile ? sha256Hex(packageFileBytes(workspaceFile)) : '', workspaceRelativeHandoffPath: visible.handoffWorkspacePath, handoffBytes: Number(handoffEntry?.bytes || 0), handoffSha256: String(handoffEntry?.sha256 || ''), routeId: visible.routeId || unquote(field(current, 'Route Id')), cacheArtifactPath: markdownTarget(field(current, 'Workspace Dependency Cache')), requiredContextBindings: Object.freeze([]) };
74
+ return { ...base, workspaceId, workspaceArtifactPath: closure?.workspaceFile?.path || '', workspaceArtifactSha256: closure?.workspaceFile ? sha256Hex(packageFileBytes(closure.workspaceFile)) : '', archivePath: closure?.archiveFile?.path || '', archiveSha256: closure?.archiveFile ? sha256Hex(packageFileBytes(closure.archiveFile)) : '', sourceWorkspaceTargetInnerPath: closure?.workspaceArtifactInnerPath || '', sourceWorkspaceTargetSha256: closure?.sourceWorkspaceTargetSha256 || '', workspaceRelativeHandoffPath: visible.handoffWorkspacePath, handoffBytes: Number(handoffEntry?.bytes || 0), handoffSha256: String(handoffEntry?.sha256 || ''), routeId: visible.routeId || unquote(field(current, 'Route Id')), cacheArtifactPath: markdownTarget(field(current, 'Workspace Dependency Cache')), requiredContextBindings: Object.freeze([]) };
75
75
  }
76
76
  if (role === 'endpoint-role' || role === 'participant-role') {
77
77
  const targetPayload = visible.targetPayload || '';
@@ -90,17 +90,70 @@ export function deriveVisibleFacts({ file = null, markdown = '', schemaId = '',
90
90
  const workspaceId = (packageContract?.workspaces || []).find((item) => item.transportEnvelopePath === file?.path)?.workspaceId || '';
91
91
  return { factsFormat: 'portable-recipient-v2', factsVersion: 1, role: TRANSPORT_ENVELOPE_V1_ROLE, workspaceId: String(workspaceId || ''), workspaceArtifactPath: visible.workspaceArtifactPath, protectedPayloadDescriptorPath: visible.protectedPayloadDescriptorPath, workspaceBindingValue: visible.workspaceBindingValue, profileId: visible.profile?.profileId || '', profileVersion: Number(visible.profile?.profileVersion || 0) };
92
92
  }
93
+ if (schemaId === 'tiinex.workspace.v1') {
94
+ const generic = genericWorkspaceClosure(index, packageContract, { workspaceArtifactPath: file?.path });
95
+ if (!generic) return null;
96
+ const entries = generic.parsed?.entries || [];
97
+ const totalBytes = entries.reduce((sum, entry) => sum + Number(entry.bytes || 0), 0);
98
+ return { factsFormat: 'portable-recipient-v2', factsVersion: 1, role: 'workspace-node', workspaceId: generic.workspaceId, archivePath: generic.archiveFile?.path || '', archiveBytes: generic.archiveFile ? packageFileBytes(generic.archiveFile).byteLength : 0, archiveSha256: generic.archiveFile ? sha256Hex(packageFileBytes(generic.archiveFile)) : '', representationArtifactPath: generic.representationFile?.path || '', payloadArtifactPath: generic.payloadFile?.path || '', sourceWorkspaceTargetInnerPath: generic.workspaceArtifactInnerPath || '', sourceWorkspaceTargetBytes: Number(generic.sourceWorkspaceTargetBytes || 0), sourceWorkspaceTargetSha256: generic.sourceWorkspaceTargetSha256 || '', entryCount: entries.length, totalBytes, entriesFingerprint: recipientEntriesFingerprint(entries), coverage: generic.representation?.coverage || '', coverageState: generic.representation?.bindingState === 'verified' ? 'qualified' : 'unresolved', completenessState: generic.representation?.coverage === 'complete' && generic.representation?.bindingState === 'verified' ? 'qualified' : '', archiveCodec: 'deterministic-stored-zip', providerKind: 'package-local-stored-zip-v1' };
99
+ }
100
+ if (schemaId === 'tiinex.workspace.representation.v1') {
101
+ const generic = genericWorkspaceClosure(index, packageContract, { representationArtifactPath: file?.path });
102
+ if (!generic) return null;
103
+ const entries = generic.parsed?.entries || [];
104
+ return { factsFormat: 'portable-recipient-v2', factsVersion: 1, role: 'workspace-representation', workspaceId: generic.workspaceId, workspaceArtifactPath: generic.workspaceFile?.path || '', payloadArtifactPath: generic.payloadFile?.path || '', sourceWorkspaceTargetInnerPath: generic.workspaceArtifactInnerPath || '', archivePath: generic.archiveFile?.path || '', archiveSha256: generic.archiveFile ? sha256Hex(packageFileBytes(generic.archiveFile)) : '', entryCount: entries.length, entriesFingerprint: recipientEntriesFingerprint(entries), coverage: generic.representation?.coverage || '', coverageState: generic.representation?.bindingState === 'verified' ? 'qualified' : 'unresolved', completenessState: generic.representation?.coverage === 'complete' && generic.representation?.bindingState === 'verified' ? 'qualified' : '' };
105
+ }
93
106
  if (schemaId === 'tiinex.external.payload.v1') {
94
107
  const visible = parseRecipientV2ExternalPayload(markdown);
95
- const role = String(visible.payloadRole || '');
108
+ const rawRole = String(visible.payloadRole || '');
109
+ const role = /workspace archive representation payload$/i.test(rawRole) ? 'workspace-representation-payload' : rawRole;
96
110
  const parent = parentTraceFromMarkdown(markdown);
97
- const workspaceId = String(visible.workspaceId || '') || (packageContract?.workspaces || []).find((item) => item.workspaceArtifactPath === parent)?.workspaceId || '';
111
+ const genericParent = genericWorkspaceClosure(index, packageContract, { workspaceArtifactPath: parent });
112
+ const workspaceId = String(visible.workspaceId || '') || (packageContract?.workspaces || []).find((item) => item.workspaceArtifactPath === parent)?.workspaceId || genericParent?.workspaceId || '';
98
113
  const materials = parsePayloadMaterials(sectionText(markdown, 'Payload Material Bindings'));
99
114
  return { factsFormat: 'portable-recipient-v2', factsVersion: 1, role, workspaceId, archivePath: visible.location, archiveBytes: visible.bytes, archiveSha256: visible.integrityValue, materials };
100
115
  }
101
116
  return null;
102
117
  }
103
118
 
119
+ function directWorkspaceClosure(index, packageContract, workspaceId) {
120
+ const binding = (packageContract?.workspaces || []).find((item) => String(item.workspaceId || '') === String(workspaceId || '')) || null;
121
+ if (!binding || String(binding.snapshotKind || '') !== 'exact-workspace-byte-tree-archive') return null;
122
+ const archiveFile = oneFile(index, binding.snapshotPath);
123
+ const workspaceFile = oneFile(index, binding.workspaceArtifactPath);
124
+ const parsed = archiveFile ? inspectStoredWorkspaceArchive(packageFileBytes(archiveFile), { ownedBytes: true }) : null;
125
+ return archiveFile && workspaceFile && parsed ? { workspaceId: String(binding.workspaceId || ''), workspaceFile, archiveFile, parsed, workspaceArtifactInnerPath: String(binding.workspaceArtifactInnerPath || ''), sourceWorkspaceTargetSha256: sha256Hex(packageFileBytes(workspaceFile)) } : null;
126
+ }
127
+
128
+ function genericWorkspaceClosure(index, packageContract, selector = {}) {
129
+ for (const binding of packageContract?.materialRepresentations || []) {
130
+ const representationFile = oneFile(index, binding.workspaceRepresentationPath);
131
+ if (!representationFile) continue;
132
+ const representation = parseRecipientV2WorkspaceRepresentation(decodeUtf8(packageFileBytes(representationFile)));
133
+ if (selector.representationArtifactPath && String(representationFile.path || '') !== String(selector.representationArtifactPath)) continue;
134
+ const workspaceFile = oneFile(index, representation.workspaceArtifactPath);
135
+ const payloadFile = oneFile(index, representation.payloadArtifactPath);
136
+ if (!workspaceFile || !payloadFile) continue;
137
+ if (selector.workspaceArtifactPath && String(workspaceFile.path || '') !== String(selector.workspaceArtifactPath)) continue;
138
+ const workspaceMarkdown = decodeUtf8(packageFileBytes(workspaceFile));
139
+ const workspaceId = workspaceIdFromCarrierWorkspaceMarkdown(workspaceMarkdown);
140
+ if (selector.workspaceId && workspaceId !== String(selector.workspaceId || '')) continue;
141
+ const payload = parseRecipientV2ExternalPayload(decodeUtf8(packageFileBytes(payloadFile)));
142
+ const archiveFile = oneFile(index, payload.location);
143
+ const parsed = archiveFile ? inspectStoredWorkspaceArchive(packageFileBytes(archiveFile), { ownedBytes: true }) : null;
144
+ if (!archiveFile || !parsed) continue;
145
+ const target = (parsed.entries || []).find((entry) => String(entry.path || '') === String(representation.workspaceArtifactInnerPath || '')) || null;
146
+ return { binding, workspaceId, representationFile, representation, workspaceFile, payloadFile, payload, archiveFile, parsed, workspaceArtifactInnerPath: String(representation.workspaceArtifactInnerPath || ''), sourceWorkspaceTargetBytes: Number(target?.bytes || 0), sourceWorkspaceTargetSha256: String(target?.sha256 || '') };
147
+ }
148
+ return null;
149
+ }
150
+
151
+ function workspaceIdFromCarrierWorkspaceMarkdown(markdown = '') {
152
+ const summary = String(markdown).match(/^\s*-\s+Summary:\s+Package-local Workspace node for\s+(.+?);/mi)?.[1]?.trim();
153
+ if (summary) return summary;
154
+ return String(markdown).match(/^#\s+(.+?)\s+—\s+Handoff Workspace\s*$/m)?.[1]?.trim() || '';
155
+ }
156
+
104
157
  function workspaceIdForRoute(index = new Map(), routeId = '') {
105
158
  const targetRouteId = String(routeId || '');
106
159
  if (!targetRouteId) return '';