@tiinex/core 0.8.0 → 0.9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiinex/core",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Shared host-neutral Tiinex implementation core for artifacts, schemas, validation, lineage, grounding, Handoffs, provenance and deterministic workflows.",
5
5
  "type": "module",
6
6
  "sideEffects": true,
@@ -167,12 +167,12 @@
167
167
  "type": "git",
168
168
  "url": "git+https://github.com/Tiinex/core.git"
169
169
  },
170
- "gitHead": "6a139559c7cb3d809b2ecf0482d0ae42243aa609",
170
+ "gitHead": "0239fd8a9fdcefe608decd5e37819e138c0c103c",
171
171
  "tiinexRelease": {
172
172
  "policy": "tiinex.master-npm-release.v1",
173
- "sourceCommit": "6a139559c7cb3d809b2ecf0482d0ae42243aa609",
174
- "sourceTree": "ec876301e7b78eaf85e8cbf9aba91dba873c2b3b",
173
+ "sourceCommit": "0239fd8a9fdcefe608decd5e37819e138c0c103c",
174
+ "sourceTree": "c66d279c1d39367f1fdc838e45963544d2cf898f",
175
175
  "repository": "Tiinex/core",
176
- "previousVersion": "0.7.0"
176
+ "previousVersion": "0.8.0"
177
177
  }
178
178
  }
@@ -0,0 +1,49 @@
1
+ export function parseWorkspaceQualifiedRecoveryReference(value = '') {
2
+ const rawValue = normalizedReferenceText(value);
3
+ const match = rawValue.match(/^([A-Za-z0-9._-]+)::(.+)$/);
4
+ if (!match) return null;
5
+ const rawPath = referencePathPart(match[2]);
6
+ if (!rawPath || rawPath.startsWith('/') || rawPath.startsWith('\\') || /^[A-Za-z]:[\\/]/.test(rawPath)) return null;
7
+ const parts = rawPath.replace(/\\/g, '/').split('/');
8
+ if (parts.some((part) => !part || part === '..' || hasControlCharacters(part))) return null;
9
+ const path = parts.filter((part) => part !== '.').join('/');
10
+ return path ? Object.freeze({ workspaceId: match[1], path, reference: `${match[1]}::${path}` }) : null;
11
+ }
12
+
13
+ export function classifyParentRecoveryReference(value = '') {
14
+ const raw = normalizedReferenceText(value);
15
+ if (!raw) return Object.freeze({ kind: 'empty', raw: '', workspaceQualified: null });
16
+ const workspaceQualified = parseWorkspaceQualifiedRecoveryReference(raw);
17
+ if (workspaceQualified) return Object.freeze({ kind: 'workspace-qualified', raw, workspaceQualified });
18
+ if (isNetworkOrSchemeReference(raw)) return Object.freeze({ kind: 'external', raw, workspaceQualified: null });
19
+ if (raw.includes('::')) return Object.freeze({ kind: 'malformed-workspace-qualified', raw, workspaceQualified: null });
20
+ return Object.freeze({ kind: 'local-relative', raw, workspaceQualified: null });
21
+ }
22
+
23
+ export function isMalformedWorkspaceQualifiedRecoveryReference(value = '') {
24
+ return classifyParentRecoveryReference(value).kind === 'malformed-workspace-qualified';
25
+ }
26
+
27
+ export function isExternalRecoveryReference(value = '') {
28
+ return classifyParentRecoveryReference(value).kind === 'external';
29
+ }
30
+
31
+ function normalizedReferenceText(value = '') {
32
+ return String(value || '').trim();
33
+ }
34
+
35
+ function referencePathPart(value = '') {
36
+ let decoded;
37
+ try { decoded = decodeURIComponent(String(value || '').split('#')[0].split('?')[0]); }
38
+ catch { return ''; }
39
+ return decoded;
40
+ }
41
+
42
+ function isNetworkOrSchemeReference(value = '') {
43
+ const text = String(value || '');
44
+ return /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(text) || text.startsWith('//') || (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(text) && !text.includes('::'));
45
+ }
46
+
47
+ function hasControlCharacters(value = '') {
48
+ return /[\u0000-\u001f]/.test(String(value || ''));
49
+ }
@@ -3,6 +3,7 @@ import { schemaIdForRecord } from './schema.identity.js';
3
3
  import { canonicalRootCreatedAt } from './creation.rootMetadata.js';
4
4
  import { renderSchemaReference } from './schema.reference.js';
5
5
  import { C14N_V2_METHOD_ID, renderIntegrityMethodReference } from '../integrity/integrity.methodReference.js';
6
+ import { parseWorkspaceQualifiedRecoveryReference } from '../lineage/parentRecoveryReference.js';
6
7
 
7
8
  export const GENERIC_ARTIFACT_CREATION_RENDERER_ID = 'tiinex.site.generic-artifact-creation-renderer.v1';
8
9
 
@@ -194,11 +195,16 @@ function parentEnvelope(record = {}, childPath = '') {
194
195
  const recoveryMode = normalizeParentRecoveryMode(record.recoveryMode || record.parentRecoveryMode || 'local-relative');
195
196
  const published = normalizePublishedReference(record.publishedReference || record.browseGitReference || record.browseGit || '');
196
197
  const publishedReference = published.state === 'qualified' ? published.target : '';
197
- const relativeReference = recoveryMode === 'external-versioned' ? '' : String(record.relativeReference || relativePath(dirname(child), parentPath)).trim();
198
+ const relativeReference = recoveryMode === 'external-versioned'
199
+ ? ''
200
+ : recoveryMode === 'workspace-qualified'
201
+ ? String(record.relativeReference || parentPath).trim()
202
+ : String(record.relativeReference || relativePath(dirname(child), parentPath)).trim();
198
203
  const traceReference = recoveryMode === 'external-versioned' ? publishedReference : relativeReference;
199
204
  const schemaReferenceAuthority = normalizeParentSchemaReferenceAuthority(record.schemaReferenceAuthority || record.parentSchemaReferenceAuthority, schemaId);
200
205
  if (!schemaId || !parentPath || !child || !traceReference) throw new Error('creation-parent-identity-incomplete');
201
206
  if (recoveryMode === 'external-versioned' && !publishedReference) throw new Error('creation-parent-external-versioned-reference-required');
207
+ if (recoveryMode === 'workspace-qualified' && !parseWorkspaceQualifiedRecoveryReference(relativeReference)) throw new Error('creation-parent-workspace-qualified-reference-invalid');
202
208
  const parentSelf = validatedC14nV2PrimarySelfDigest(record.markdown || '');
203
209
  if (parentSelf.state !== 'verified') throw new Error(`creation-parent-primary-self-${parentSelf.reason || parentSelf.state}`);
204
210
  const integrityTarget = publishedReference || relativeReference;
@@ -217,7 +223,12 @@ function parentEnvelope(record = {}, childPath = '') {
217
223
  });
218
224
  }
219
225
 
220
- function normalizeParentRecoveryMode(value = '') { return String(value || '').trim() === 'external-versioned' ? 'external-versioned' : 'local-relative'; }
226
+ function normalizeParentRecoveryMode(value = '') {
227
+ const mode = String(value || '').trim();
228
+ if (mode === 'external-versioned') return 'external-versioned';
229
+ if (mode === 'workspace-qualified') return 'workspace-qualified';
230
+ return 'local-relative';
231
+ }
221
232
  function normalizePublishedReference(value) {
222
233
  if (typeof value === 'string') return Object.freeze({ target: value, state: value ? 'unresolved' : 'unavailable' });
223
234
  return Object.freeze({ target: String(value?.target || value?.url || ''), state: String(value?.state || value?.resolutionState || 'unresolved') });
@@ -1,3 +1,5 @@
1
+ import { isMalformedWorkspaceQualifiedRecoveryReference } from '../lineage/parentRecoveryReference.js';
2
+
1
3
  export function rootValidate(artifact) {
2
4
  const findings = [];
3
5
  const envelope = artifact?.envelope || {};
@@ -20,6 +22,13 @@ export function rootValidate(artifact) {
20
22
  const labels = originEntries.map((entry) => String(entry?.label || '').trim()).filter(Boolean);
21
23
  const duplicateLabels = [...new Set(labels.filter((label, index) => labels.indexOf(label) !== index))];
22
24
  for (const label of duplicateLabels) findings.push(error('root.parent.origin.label.duplicate', `Parent Origin recovery label is duplicated: ${label}.`));
25
+ const recoveryReferences = [
26
+ Object.freeze({ field: 'Trace', target: String(parent.trace || '').trim() }),
27
+ ...originEntries.map((entry) => Object.freeze({ field: `Origin:${String(entry?.label || '').trim() || 'unlabelled'}`, target: String(entry?.target || '').trim() }))
28
+ ].filter((entry) => entry.target);
29
+ for (const reference of recoveryReferences) {
30
+ if (isMalformedWorkspaceQualifiedRecoveryReference(reference.target)) findings.push(error('root.parent.recovery.workspace-qualified.malformed', `Parent ${reference.field} contains a malformed Workspace-qualified recovery locator: ${reference.target}.`));
31
+ }
23
32
  }
24
33
  if (envelope.repairsDeclared) findings.push(info('root.repairs.declared', 'Envelope declares repair notes; validators should preserve unknown repair fields.'));
25
34
  if (!findings.some((finding) => finding.severity === 'error')) findings.push(info('root.envelope.readable', 'Root envelope is readable at current validation depth.'));
@@ -9,6 +9,7 @@ import { resolveSchemaModule } from '../../../../schemas/resolver.js';
9
9
  import { loadNodePortableInput } from '../../input/node.input.js';
10
10
  import { runPortableOperation } from '../../operation.catalog.js';
11
11
  import { allocateContinuationPath, allocateDirectoryArtifactPath } from '../../../../transitions/record.transitions.js';
12
+ import { classifyParentRecoveryReference } from '../../../../lineage/parentRecoveryReference.js';
12
13
 
13
14
  const STATE_RELATIVE_PATH = '.tiinex/continuation.json';
14
15
 
@@ -137,11 +138,18 @@ async function parentRecordFromArtifact(parentPath, parentRelativePath, context
137
138
  currentCreatedAt: String(current.createdAt || ''),
138
139
  createdAt: String(current.createdAt || ''),
139
140
  markdown,
140
- recoveryMode: 'local-relative',
141
+ recoveryMode: parentRecoveryMode(parentRelativePath),
141
142
  schemaReferenceAuthority
142
143
  });
143
144
  }
144
145
 
146
+ export function parentRecoveryMode(reference = '') {
147
+ const classification = classifyParentRecoveryReference(reference);
148
+ if (classification.kind === 'workspace-qualified') return 'workspace-qualified';
149
+ if (classification.kind === 'malformed-workspace-qualified') throw new Error('portable.cli.author.parent.workspace-qualified.malformed');
150
+ return 'local-relative';
151
+ }
152
+
145
153
  function exactDeclaredSchemaReferenceAuthority(schemaId, schemaTarget) {
146
154
  return Object.freeze({
147
155
  schemaId,
@@ -85,7 +85,8 @@ export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime =
85
85
  parentPackagePath: resolvedParent,
86
86
  parentPackageSha256: provisionalLineage.parentPackageSha256,
87
87
  parentDimension: provisionalLineage.parentDimension,
88
- enabled: !flags['package-major'] && Boolean(flags.output || flags['output-dir'])
88
+ enabled: !flags['package-major'] && Boolean(flags.output || flags['output-dir']),
89
+ siblingIndex: flags['package-sibling-index']
89
90
  });
90
91
  carrierLineage = flags['package-major'] ? provisionalLineage : carrierLineageFromCliParent({
91
92
  bundle: parentBundle,
@@ -1,10 +1,12 @@
1
- import { mkdir, open } from 'node:fs/promises';
1
+ import { mkdir, open, readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
 
4
4
  const MAX_SIBLING_INDEX = 9999;
5
5
 
6
- export async function reserveHandoffSiblingIndex({ parentPackagePath = '', parentPackageSha256 = '', parentDimension = '', enabled = true } = {}) {
7
- if (!enabled) return Object.freeze({ state: 'not-reserved', siblingIndex: 1, allocationPath: '' });
6
+ export async function reserveHandoffSiblingIndex({ parentPackagePath = '', parentPackageSha256 = '', parentDimension = '', enabled = true, siblingIndex = null } = {}) {
7
+ const requestedSiblingIndex = normalizeSiblingIndex(siblingIndex);
8
+ if (!enabled) return Object.freeze({ state: 'not-reserved', siblingIndex: requestedSiblingIndex || 1, allocationPath: '', coordinationRequired: Boolean(requestedSiblingIndex) });
9
+ if (!requestedSiblingIndex) throw new Error('portable.cli.handoff-carrier.sibling-allocation.explicit-index-required');
8
10
  const parentPath = path.resolve(String(parentPackagePath || ''));
9
11
  const digest = String(parentPackageSha256 || '').trim().toLowerCase();
10
12
  const dimension = String(parentDimension || '').trim();
@@ -12,20 +14,42 @@ export async function reserveHandoffSiblingIndex({ parentPackagePath = '', paren
12
14
  const allocationDir = path.join(path.dirname(parentPath), '.tiinex-handoff-sibling-allocations');
13
15
  await mkdir(allocationDir, { recursive: true });
14
16
  const key = `${digest.slice(0, 24)}-${dimension.replace(/[^0-9-]/g, '')}`;
15
- for (let siblingIndex = 1; siblingIndex <= MAX_SIBLING_INDEX; siblingIndex += 1) {
16
- const allocationPath = path.join(allocationDir, `${key}-${siblingIndex}.allocation`);
17
- try {
18
- const handle = await open(allocationPath, 'wx');
19
- try {
20
- await handle.writeFile(`${JSON.stringify({ parentPackageSha256: digest, parentDimension: dimension, siblingIndex, childDimension: `${dimension}-${siblingIndex}` })}\n`, 'utf8');
21
- } finally {
22
- await handle.close();
23
- }
24
- return Object.freeze({ state: 'reserved', siblingIndex, allocationPath });
25
- } catch (error) {
26
- if (error?.code === 'EEXIST') continue;
27
- throw error;
28
- }
17
+ const allocationPath = path.join(allocationDir, `${key}-${requestedSiblingIndex}.allocation`);
18
+ const record = Object.freeze({
19
+ parentPackageSha256: digest,
20
+ parentDimension: dimension,
21
+ siblingIndex: requestedSiblingIndex,
22
+ childDimension: `${dimension}-${requestedSiblingIndex}`,
23
+ allocationAuthority: 'explicit-caller-coordination'
24
+ });
25
+ try {
26
+ const handle = await open(allocationPath, 'wx');
27
+ try { await handle.writeFile(`${JSON.stringify(record)}\n`, 'utf8'); }
28
+ finally { await handle.close(); }
29
+ return Object.freeze({ state: 'reserved-explicit', siblingIndex: requestedSiblingIndex, allocationPath, coordinationRequired: true });
30
+ } catch (error) {
31
+ if (error?.code !== 'EEXIST') throw error;
32
+ const prior = await readAllocation(allocationPath);
33
+ if (!sameAllocation(prior, record)) throw new Error('portable.cli.handoff-carrier.sibling-allocation.existing-reservation-conflict');
34
+ return Object.freeze({ state: 'reused-explicit', siblingIndex: requestedSiblingIndex, allocationPath, coordinationRequired: true });
29
35
  }
30
- throw new Error('portable.cli.handoff-carrier.sibling-allocation.exhausted');
36
+ }
37
+
38
+ function normalizeSiblingIndex(value) {
39
+ if (value === null || value === undefined || value === '') return 0;
40
+ const parsed = Number(value);
41
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_SIBLING_INDEX) throw new Error('portable.cli.handoff-carrier.sibling-allocation.index-invalid');
42
+ return parsed;
43
+ }
44
+
45
+ async function readAllocation(allocationPath) {
46
+ try { return JSON.parse(await readFile(allocationPath, 'utf8')); }
47
+ catch { throw new Error('portable.cli.handoff-carrier.sibling-allocation.existing-reservation-invalid'); }
48
+ }
49
+
50
+ function sameAllocation(left = {}, right = {}) {
51
+ return String(left.parentPackageSha256 || '') === String(right.parentPackageSha256 || '')
52
+ && String(left.parentDimension || '') === String(right.parentDimension || '')
53
+ && Number(left.siblingIndex || 0) === Number(right.siblingIndex || 0)
54
+ && String(left.childDimension || '') === String(right.childDimension || '');
31
55
  }
@@ -70,7 +70,7 @@ function commonCommandHelp(command, surfaceCommand) {
70
70
  '',
71
71
  `${command} handoff <workspace-dir>`,
72
72
  '',
73
- 'Infers the latest qualified authored Handoff, selected Workspace identity/target, received package parent as carrier-lineage evidence, canonical projected filename, and return output directory. It does not implicitly carry sibling Workspaces from the received package; advanced manufacture must select exact reusable parent snapshots with `--package-parent-workspaces <id,...|all>`. The default receipt keeps output identity, routing text, closure/workspace qualification, verification, and actionable findings compact; add `--full` for the complete manufacture receipt. Normal operator completion is exactly one Handoff package plus the adjacent exact routing text. In markdown-capable hosts render that routing in a fenced code block; do not emit canonical Workspace Evidence/Handoff markdown as additional loose transport files. Runtime-only `.tiinex` state is excluded from canonical manufacture.',
73
+ 'Infers the latest qualified authored Handoff, selected Workspace identity/target, received package parent as carrier-lineage evidence, canonical projected filename, and return output directory. A non-major continuation that writes a carrier must supply an explicitly coordinated `--package-sibling-index <1..9999>`; Tooling will not silently discover the next sibling because isolated runtimes cannot prove a globally unique reservation. Distinct explicit sibling indexes preserve same-Major parallelism, while byte-identical duplicate transport at one exact output path is idempotent and divergent bytes fail closed. It does not implicitly carry sibling Workspaces from the received package; advanced manufacture must select exact reusable parent snapshots with `--package-parent-workspaces <id,...|all>`. The default receipt keeps output identity, routing text, closure/workspace qualification, verification, and actionable findings compact; add `--full` for the complete manufacture receipt. Normal operator completion is exactly one Handoff package plus the adjacent exact routing text. In markdown-capable hosts render that routing in a fenced code block; do not emit canonical Workspace Evidence/Handoff markdown as additional loose transport files. Runtime-only `.tiinex` state is excluded from canonical manufacture.',
74
74
  '',
75
75
  `Advanced/internal catalog: ${command} operations`
76
76
  ];
@@ -273,7 +273,7 @@ function resolveCarriedWorkspaceQualifiedReference(target = '', workspaceRuntime
273
273
 
274
274
  export function resolveRelativeWorkspaceTarget(sourcePath = '', target = '') {
275
275
  const raw = safeDecodeURIComponent(String(target || '').split('#')[0].split('?')[0]);
276
- if (!raw || path.posix.isAbsolute(raw) || raw.startsWith('\\')) return '';
276
+ if (!raw || path.posix.isAbsolute(raw) || raw.startsWith('\\') || raw.includes('::')) return '';
277
277
  const base = normalizeRelativePath(sourcePath).split('/').slice(0, -1);
278
278
  for (const part of raw.replace(/\\/g, '/').split('/')) {
279
279
  if (!part || part === '.') continue;
@@ -4,6 +4,7 @@ import { projectHandoffMaterialRequirements, projectParticipantRoleRequirements
4
4
  import { qualifySelectedHandoffArtifact } from './routeArtifactConformance.js';
5
5
  import { listHandoffWorkspaceEntries, resolveHandoffWorkspaceEntry } from './workspaceByteProvider.js';
6
6
  import { parseWorkspaceQualifiedReference, SHARED_ROUTE_REQUIRED_CONTEXT_BOUNDARY } from './workspaceQualifiedReference.js';
7
+ import { classifyParentRecoveryReference } from '../../../lineage/parentRecoveryReference.js';
7
8
  import { decodeUtf8, deepFreeze, findFile, normalizeWorkspacePath } from './carrierProjection.shared.js';
8
9
 
9
10
  export function qualifyRoute(bundle, descriptor, byteProvider, workspace, spec = {}, options = {}) {
@@ -132,13 +133,27 @@ function resolveDescriptorMaterial(bundle, descriptor, byteProvider, target = ''
132
133
  }
133
134
 
134
135
  function resolveRouteParent(bundle, descriptor, byteProvider, workspace, routePath, parent = {}, targetEntry = {}) {
135
- const localTargets = [];
136
- if (parent.trace && !isExternalReference(parent.trace)) localTargets.push(String(parent.trace));
136
+ const recoveryTargets = [];
137
+ if (parent.trace) recoveryTargets.push(String(parent.trace));
137
138
  for (const entry of parent.originEntries || []) {
138
- if (String(entry?.label || '').trim() === 'relative' && entry?.target && !isExternalReference(entry.target)) localTargets.push(String(entry.target));
139
+ if (String(entry?.label || '').trim() === 'relative' && entry?.target) recoveryTargets.push(String(entry.target));
139
140
  }
140
141
  const candidates = new Map();
141
- for (const target of localTargets) {
142
+ for (const target of [...new Set(recoveryTargets)]) {
143
+ const classification = classifyParentRecoveryReference(target);
144
+ if (classification.kind === 'malformed-workspace-qualified') return Object.freeze({ state: 'unavailable', reason: 'parent-workspace-qualified-reference-malformed' });
145
+ if (classification.kind === 'external' || classification.kind === 'empty') continue;
146
+ if (classification.kind === 'workspace-qualified') {
147
+ const qualified = classification.workspaceQualified;
148
+ const resolved = resolveHandoffWorkspaceEntry(byteProvider, qualified.workspaceId, qualified.path);
149
+ if (resolved.state !== 'qualified') continue;
150
+ const data = packageFileBytes({ data: resolved.data });
151
+ if (Number(resolved.bytes || 0) !== data.byteLength || String(resolved.sha256 || '') !== sha256Hex(data)) continue;
152
+ const markdown = decodeUtf8(data);
153
+ if (!markdown) continue;
154
+ candidates.set(`${qualified.workspaceId}\u0000${qualified.path}`, Object.freeze({ state: 'qualified', markdown, basis: 'parent-workspace-qualified-reference', workspaceId: qualified.workspaceId, workspaceRelativePath: qualified.path, packagePath: String(resolved.packagePath || ''), sha256: sha256Hex(data) }));
155
+ continue;
156
+ }
142
157
  const resolvedPath = resolveWorkspaceReference(routePath, target);
143
158
  if (!resolvedPath) continue;
144
159
  const resolved = resolveHandoffWorkspaceEntry(byteProvider, workspace.id, resolvedPath);
@@ -192,7 +207,7 @@ function packageParentCandidates(bundle = {}, descriptor = {}, byteProvider = {}
192
207
 
193
208
  function resolveWorkspaceReference(routePath, target) {
194
209
  const raw = safeDecodeURIComponent(String(target || '').split('#')[0].split('?')[0]);
195
- if (!raw || raw.startsWith('/') || raw.startsWith('\\')) return '';
210
+ if (!raw || raw.startsWith('/') || raw.startsWith('\\') || raw.includes('::')) return '';
196
211
  const base = normalizeWorkspacePath(routePath).split('/').slice(0, -1);
197
212
  for (const part of raw.replace(/\\/g, '/').split('/')) {
198
213
  if (!part || part === '.') continue;
@@ -3,6 +3,7 @@ import { validatedC14nV2PrimarySelfDigest } from '../../../integrity/integrity.c
3
3
  import { projectHandoffMaterialRequirements } from './materialClosure.requirements.js';
4
4
  import { deepFreeze, finding, normalizeRoutePath, sectionText, fieldValue, decodeUtf8 } from './recipientV2.artifactFirst.shared.js';
5
5
  import { parseWorkspaceQualifiedReference } from './workspaceQualifiedReference.js';
6
+ import { classifyParentRecoveryReference } from '../../../lineage/parentRecoveryReference.js';
6
7
 
7
8
  export function qualifyRecipientV2ArtifactFirstPhase1RequiredContextClosure(input = {}) {
8
9
  return qualifyPhase1RequiredContextClosure(input);
@@ -71,7 +72,23 @@ export function qualifyPhase1RequiredContextClosure({ markdown = '', routePath =
71
72
  export function resolveArchiveParent(routePath = '', entries = [], parent = {}, targetEntry = {}, parentCandidates = []) {
72
73
  const refs = [String(parent.trace || ''), ...(parent.originEntries || []).map((item) => String(item.target || '')), String(targetEntry.towards || '')].filter(Boolean);
73
74
  for (const ref of refs) {
74
- if (/^[a-z][a-z0-9+.-]*:\/\//i.test(ref)) continue;
75
+ const classification = classifyParentRecoveryReference(ref);
76
+ if (classification.kind === 'malformed-workspace-qualified') return Object.freeze({ state: 'unresolved', reason: 'parent-workspace-qualified-reference-malformed' });
77
+ if (classification.kind === 'external' || classification.kind === 'empty') continue;
78
+ if (classification.kind === 'workspace-qualified') {
79
+ const qualified = classification.workspaceQualified;
80
+ const matches = (parentCandidates || []).filter((candidate) => String(candidate.workspaceId || '') === qualified.workspaceId && String(candidate.workspaceRelativePath || '') === qualified.path);
81
+ if (matches.length > 1) return Object.freeze({ state: 'ambiguous', reason: 'multiple-parent-workspace-qualified-reference-candidates' });
82
+ if (matches.length === 1) {
83
+ const candidate = matches[0];
84
+ const data = packageFileBytes({ data: candidate.data });
85
+ if (data.byteLength && Number(candidate.bytes || data.byteLength) === data.byteLength && (!candidate.sha256 || String(candidate.sha256) === sha256Hex(data))) {
86
+ const markdown = decodeUtf8(data);
87
+ if (markdown) return Object.freeze({ state: 'qualified', markdown, basis: 'artifact-first-workspace-qualified-reference', workspaceId: qualified.workspaceId, workspaceRelativePath: qualified.path, archiveEntry: String(candidate.archiveEntry || ''), sha256: sha256Hex(data) });
88
+ }
89
+ }
90
+ continue;
91
+ }
75
92
  const resolved = resolveRelativeWorkspacePath(routePath, ref);
76
93
  if (!resolved) continue;
77
94
  const matches = entries.filter((entry) => String(entry.path || '') === resolved);
@@ -115,7 +132,7 @@ export function phase1CacheParentCandidates(cacheQualifications = []) {
115
132
 
116
133
  export function resolveRelativeWorkspacePath(fromPath = '', ref = '') {
117
134
  const value = String(ref || '').split('#')[0].replace(/\\/g, '/');
118
- if (!value || value.startsWith('/') || /^[A-Za-z]:\//.test(value)) return '';
135
+ if (!value || value.startsWith('/') || /^[A-Za-z]:\//.test(value) || value.includes('::')) return '';
119
136
  const base = String(fromPath || '').replace(/\\/g, '/').split('/'); base.pop();
120
137
  const parts = value.startsWith('./') || value.startsWith('../') ? [...base, ...value.split('/')] : [...base, ...value.split('/')];
121
138
  const out = [];
@@ -284,7 +284,7 @@ function qualifyParentBoundaryCacheRequirementIds(caches = [], workspaceByteProv
284
284
  function resolveRelativeWorkspacePath(sourcePath = '', target = '') {
285
285
  let raw;
286
286
  try { raw = decodeURIComponent(String(target || '').split('#')[0].split('?')[0]); } catch { return ''; }
287
- if (!raw || raw.startsWith('/') || raw.startsWith('\\') || /^[a-z][a-z0-9+.-]*:/i.test(raw) || raw.startsWith('//')) return '';
287
+ if (!raw || raw.startsWith('/') || raw.startsWith('\\') || raw.includes('::') || /^[a-z][a-z0-9+.-]*:/i.test(raw) || raw.startsWith('//')) return '';
288
288
  const parts = normalizeWorkspacePath(sourcePath).split('/').slice(0, -1);
289
289
  for (const part of raw.replace(/\\/g, '/').split('/')) {
290
290
  if (!part || part === '.') continue;
@@ -1,10 +1,8 @@
1
+ import { parseWorkspaceQualifiedRecoveryReference } from '../../../lineage/parentRecoveryReference.js';
2
+
1
3
  export const SHARED_ROUTE_REQUIRED_CONTEXT_BOUNDARY = 'Shared-route recipient grounding proof only. Every Required Context item must resolve to exact carried package bytes; Reference Context is intentionally excluded from this blocking projection.';
2
4
 
3
5
  export function parseWorkspaceQualifiedReference(value = '') {
4
- const match = String(value || '').trim().match(/^([a-zA-Z0-9._-]+)::(.+)$/);
5
- if (!match) return null;
6
- const raw = String(match[2] || '').split('#')[0].split('?')[0].replace(/\\/g, '/');
7
- if (!raw || raw.startsWith('/') || raw.split('/').some((part) => part === '..')) return null;
8
- const path = raw.split('/').filter((part) => part && part !== '.').join('/');
9
- return path ? Object.freeze({ workspaceId: match[1], path }) : null;
6
+ const parsed = parseWorkspaceQualifiedRecoveryReference(value);
7
+ return parsed ? Object.freeze({ workspaceId: parsed.workspaceId, path: parsed.path }) : null;
10
8
  }
@@ -1,5 +1,6 @@
1
1
  import { validatedC14nV2PrimarySelfDigest } from '../../../integrity/integrity.c14nV2.js';
2
2
  import { qualifyTiinexRouteArtifact } from './routeArtifactConformance.js';
3
+ import { classifyParentRecoveryReference } from '../../../lineage/parentRecoveryReference.js';
3
4
 
4
5
  export const HANDOFF_WORKSPACE_TARGET_CONFORMANCE_SCHEMA_ID = 'tiinex.portable.handoff-workspace-target-conformance.v1';
5
6
 
@@ -48,7 +49,10 @@ function resolveWorkspaceParent({ entries = [], parentCandidates = [], targetPat
48
49
  const indexed = indexEntries(entries);
49
50
  const recoveryIndexed = indexEntries(parentCandidates);
50
51
  const localCandidates = new Map();
51
- for (const reference of parentLocalReferences(parent)) {
52
+ for (const reference of parentRecoveryReferences(parent)) {
53
+ const classification = classifyParentRecoveryReference(reference);
54
+ if (classification.kind === 'malformed-workspace-qualified') return Object.freeze({ state: 'unavailable', reason: 'parent-workspace-qualified-reference-malformed' });
55
+ if (classification.kind !== 'local-relative') continue;
52
56
  const resolvedPath = resolveRelativeReference(targetPath, reference);
53
57
  if (!resolvedPath) continue;
54
58
  const entry = indexed.get(resolvedPath);
@@ -87,18 +91,18 @@ function indexEntries(entries = []) {
87
91
  return out;
88
92
  }
89
93
 
90
- function parentLocalReferences(parent = {}) {
94
+ function parentRecoveryReferences(parent = {}) {
91
95
  const out = [];
92
- if (parent.trace && !isExternalReference(parent.trace)) out.push(String(parent.trace));
96
+ if (parent.trace) out.push(String(parent.trace));
93
97
  for (const entry of parent.originEntries || []) {
94
- if (String(entry?.label || '').trim() === 'relative' && entry?.target && !isExternalReference(entry.target)) out.push(String(entry.target));
98
+ if (String(entry?.label || '').trim() === 'relative' && entry?.target) out.push(String(entry.target));
95
99
  }
96
100
  return [...new Set(out)];
97
101
  }
98
102
 
99
103
  function resolveRelativeReference(fromPath = '', reference = '') {
100
104
  const base = normalizeInnerPath(fromPath);
101
- if (!base || !reference || isExternalReference(reference)) return '';
105
+ if (!base || !reference || isExternalReference(reference) || String(reference).includes('::')) return '';
102
106
  let clean;
103
107
  try { clean = decodeURIComponent(String(reference).split('#')[0].split('?')[0]); } catch { return ''; }
104
108
  if (!clean || clean.startsWith('/') || clean.startsWith('\\') || /^[A-Za-z]:[\\/]/.test(clean)) return '';
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { packageFileBytes } from '../../../export/package.bytes.js';
5
5
  import { inspectRecipientFacingV2Topology } from '../handoff/recipientV2.inspect.js';
@@ -38,10 +38,10 @@ export async function writeRecipientFacingV2PackageZip(bundle = {}, outputPath =
38
38
  if (!target.toLowerCase().endsWith('.zip')) throw new Error('portable.recipient-v2.zip.output.extension');
39
39
  await mkdir(path.dirname(target), { recursive: true });
40
40
  const buffer = recipientFacingV2PackageZipBuffer(bundle, options);
41
- await writeFile(target, buffer);
41
+ const exactWrite = await writeExactRecipientTransportBytes(target, buffer);
42
42
  return Object.freeze({
43
43
  schema: 'tiinex.portable.recipient-facing-v2.zip-write.v1',
44
- status: 'written',
44
+ status: exactWrite.status,
45
45
  path: target,
46
46
  bytes: buffer.length,
47
47
  transportFormat: RECIPIENT_V2_FORMAT_ID,
@@ -49,6 +49,20 @@ export async function writeRecipientFacingV2PackageZip(bundle = {}, outputPath =
49
49
  });
50
50
  }
51
51
 
52
+ export async function writeExactRecipientTransportBytes(outputPath = '', data = new Uint8Array()) {
53
+ const target = path.resolve(String(outputPath || '').trim());
54
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
55
+ try {
56
+ await writeFile(target, buffer, { flag: 'wx' });
57
+ return Object.freeze({ status: 'written', path: target, bytes: buffer.length });
58
+ } catch (error) {
59
+ if (error?.code !== 'EEXIST') throw error;
60
+ const existing = await readFile(target);
61
+ if (!existing.equals(buffer)) throw new Error('portable.recipient-v2.zip.output-collision-divergent');
62
+ return Object.freeze({ status: 'reused-identical', path: target, bytes: buffer.length });
63
+ }
64
+ }
65
+
52
66
  function bufferViewOfPackageFile(file = {}) {
53
67
  const value = file.data;
54
68
  if (Buffer.isBuffer(value)) return value;