@tiinex/core 0.18.0 → 0.19.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.18.0",
3
+ "version": "0.19.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,
@@ -79,6 +79,7 @@
79
79
  "./tooling/portable/grounding/grounding.capsule.js": "./src/tooling/portable/grounding/grounding.capsule.js",
80
80
  "./tooling/portable/grounding/grounding.participantAuthority.js": "./src/tooling/portable/grounding/grounding.participantAuthority.js",
81
81
  "./tooling/portable/grounding/grounding.processApplicability.js": "./src/tooling/portable/grounding/grounding.processApplicability.js",
82
+ "./tooling/portable/grounding/grounding.implementationSourceAuthority.js": "./src/tooling/portable/grounding/grounding.implementationSourceAuthority.js",
82
83
  "./tooling/portable/grounding/grounding.readiness.js": "./src/tooling/portable/grounding/grounding.readiness.js",
83
84
  "./tooling/portable/grounding/grounding.workProvenance.js": "./src/tooling/portable/grounding/grounding.workProvenance.js",
84
85
  "./tooling/portable/handoff/carrierLineage.js": "./src/tooling/portable/handoff/carrierLineage.js",
@@ -170,12 +171,12 @@
170
171
  "type": "git",
171
172
  "url": "git+https://github.com/Tiinex/core.git"
172
173
  },
173
- "gitHead": "12321ec2a8d09722b464ef7977afa2dcdc924718",
174
+ "gitHead": "fe01706aecacbf28c66e2ac052e4f639170dfe73",
174
175
  "tiinexRelease": {
175
176
  "policy": "tiinex.master-npm-release.v1",
176
- "sourceCommit": "12321ec2a8d09722b464ef7977afa2dcdc924718",
177
- "sourceTree": "eba0d10ad8f5fc20cc1c98ee88c328fbd4dafa4c",
177
+ "sourceCommit": "fe01706aecacbf28c66e2ac052e4f639170dfe73",
178
+ "sourceTree": "b4e5dbb825a1504fef53f1e5281d4bd6fd3c87ff",
178
179
  "repository": "Tiinex/core",
179
- "previousVersion": "0.17.0"
180
+ "previousVersion": "0.18.0"
180
181
  }
181
182
  }
@@ -117,7 +117,7 @@ export async function commandInput(parsed, runtime = {}) {
117
117
  packageSourcePath: packagePath,
118
118
  includeLegacyTopics: Boolean(flags['include-legacy-topics']),
119
119
  includeRequiredContext: flags['include-required-context'] || '',
120
- holderBinding: { roleLabel: flags['holder-role'] || '', holderId: flags['holder-id'] || '' },
120
+ holderBinding: { roleLabel: flags['holder-role'] || '', holderId: flags['holder-id'] || '', sourceLocator: holderBindingCliSource(flags) },
121
121
  host,
122
122
  recoveryAcceptance
123
123
  },
@@ -471,4 +471,11 @@ function mergeLoadedMaterial(primary = {}, secondary = {}) {
471
471
  }
472
472
 
473
473
  function normalizeRuntimePaths(value) { const paths = Array.isArray(value) ? value : value ? [value] : []; return paths.map((entry) => String(entry || '').trim()).filter(Boolean); }
474
+ function holderBindingCliSource(flags = {}) {
475
+ const fields = [];
476
+ if (Object.prototype.hasOwnProperty.call(flags, 'holder-role')) fields.push('--holder-role');
477
+ if (Object.prototype.hasOwnProperty.call(flags, 'holder-id')) fields.push('--holder-id');
478
+ return fields.length ? `cli:${fields.join(',')}` : '';
479
+ }
480
+
474
481
  function splitFlag(value) { return !value || value === true ? [] : String(value).split(',').map((item) => item.trim()).filter(Boolean); }
@@ -163,6 +163,7 @@ function projectHandoffDefault(result = {}, parsed = {}) {
163
163
  status: String(carrier.status || ''),
164
164
  mode: String(carrier.mode || ''),
165
165
  lineage: carrier.lineage ? compactCarrierLineage(carrier.lineage) : null,
166
+ allocation: result.carrierAllocation ? Object.freeze({ ...result.carrierAllocation }) : null,
166
167
  route: Object.freeze({
167
168
  id: String(route.id || ''),
168
169
  state: String(route.state || ''),
@@ -275,11 +276,17 @@ function compactGroundAuthority(authority = {}) {
275
276
  }),
276
277
  holderBinding: Object.freeze({
277
278
  state: String(holderBinding.state || ''),
279
+ bindingPresent: Boolean(holderBinding.bindingPresent),
280
+ declarationPresent: Boolean(holderBinding.declarationPresent),
278
281
  holderId: String(holderBinding.holderId || ''),
279
282
  roleLabel: String(holderBinding.roleLabel || ''),
280
283
  recipientRoleLabel: String(holderBinding.recipientRoleLabel || ''),
281
284
  recipientCompatibility: String(holderBinding.recipientCompatibility || ''),
282
285
  source: String(holderBinding.source || ''),
286
+ sourceDetail: holderBinding.sourceDetail ? Object.freeze({ ...holderBinding.sourceDetail }) : null,
287
+ authorization: holderBinding.authorization ? Object.freeze({ ...holderBinding.authorization, provenance: holderBinding.authorization.provenance ? Object.freeze({ ...holderBinding.authorization.provenance }) : null }) : null,
288
+ durableIdentity: holderBinding.durableIdentity ? Object.freeze({ ...holderBinding.durableIdentity }) : Object.freeze({ state: 'not-established' }),
289
+ semanticAuthorityState: String(holderBinding.semanticAuthorityState || 'not-established'),
283
290
  explicit: Boolean(holderBinding.explicit),
284
291
  inferredFromTransport: Boolean(holderBinding.inferredFromTransport),
285
292
  provenance: holderBinding.provenance ? Object.freeze({ ...holderBinding.provenance }) : null
@@ -10,7 +10,7 @@ import { projectRecipientV2HumanOutput } from '../../handoff/recipientV2.humanOu
10
10
  import { inspectRecipientFacingV2Topology } from '../../handoff/recipientV2.inspect.js';
11
11
  import { carrierLineageFromCliParent, initialHandoffCarrierLineage, parentHandoffCarrierLineageFromBundle, parentHandoffCarrierProfileFromBundle } from '../../handoff/carrierLineage.js';
12
12
  import { loadNodePortableInput } from '../../input/node.input.js';
13
- import { reserveHandoffSiblingIndex } from './cli.handoff-sibling-allocation.js';
13
+ import { resolveHandoffSiblingAllocation } from './cli.handoff-sibling-allocation.js';
14
14
  import { normalizeHandoffCarrierProfile } from '../../handoff/carrierProfile.js';
15
15
 
16
16
  export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime = {}) {
@@ -26,7 +26,6 @@ export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime =
26
26
  const handoffPath = flags.handoff || parsed.positionals?.[1] || continuationState.returnHandoffPath || '';
27
27
  if (!flags['workspace-id'] && continuationState.workspaceId) flags['workspace-id'] = continuationState.workspaceId;
28
28
  if (!flags['workspace-target'] && continuationState.workspaceTarget) flags['workspace-target'] = continuationState.workspaceTarget;
29
- if (!flags['package-sibling-index'] && continuationState.returnPackageSiblingIndex) flags['package-sibling-index'] = continuationState.returnPackageSiblingIndex;
30
29
  if (!flags['package-parent'] && continuationState.packageParentPath) flags['package-parent'] = continuationState.packageParentPath;
31
30
  if (!flags.route && handoffPath) flags.route = handoffPath;
32
31
  if (!flags.output && !flags['output-dir'] && parsed.surfaceCommand === 'handoff' && continuationState.returnOutputDir) flags['output-dir'] = continuationState.returnOutputDir;
@@ -55,6 +54,7 @@ export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime =
55
54
  let packageParentSha256 = '';
56
55
  let carrierLineage = initialHandoffCarrierLineage();
57
56
  let inheritedCarrierProfile = normalizeHandoffCarrierProfile(null);
57
+ let carrierAllocation = Object.freeze({ state: 'root', allocationMode: 'initial-root', siblingIndex: null, provenance: Object.freeze({ basis: 'initial-carrier-root' }) });
58
58
  if (parentPackagePath) {
59
59
  const resolvedParent = path.resolve(parentPackagePath);
60
60
  const parentBytes = new Uint8Array(await readFile(resolvedParent));
@@ -86,21 +86,35 @@ export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime =
86
86
  major: Boolean(flags['package-major']),
87
87
  majorReason: flags['major-reason'] || ''
88
88
  });
89
- const siblingAllocation = await reserveHandoffSiblingIndex({
90
- parentPackagePath: resolvedParent,
91
- parentPackageSha256: provisionalLineage.parentPackageSha256,
92
- parentDimension: provisionalLineage.parentDimension,
93
- enabled: !flags['package-major'] && Boolean(flags.output || flags['output-dir']),
94
- siblingIndex: flags['package-sibling-index']
95
- });
96
- carrierLineage = flags['package-major'] ? provisionalLineage : carrierLineageFromCliParent({
97
- bundle: parentBundle,
98
- parentPath: resolvedParent,
99
- parentBytes,
100
- routeDimensions,
101
- qualifiedParentLineage: parentLineage,
102
- siblingIndex: siblingAllocation.siblingIndex
103
- });
89
+ if (flags['package-major']) {
90
+ carrierLineage = provisionalLineage;
91
+ carrierAllocation = Object.freeze({
92
+ state: 'qualified', allocationMode: 'explicit-major', siblingIndex: null,
93
+ provenance: Object.freeze({ basis: 'explicit-major-request', parentPackagePath: resolvedParent, parentPackageSha256: provisionalLineage.parentPackageSha256, parentDimension: provisionalLineage.parentDimension }),
94
+ boundary: 'Carrier Major creation remains explicit and separate from non-Major pointer-order allocation.'
95
+ });
96
+ } else {
97
+ const parentInspection = inspectRecipientFacingV2Topology(parentBundle);
98
+ const siblingAllocation = await resolveHandoffSiblingAllocation({
99
+ parentInspection,
100
+ parentPackagePath: resolvedParent,
101
+ parentPackageSha256: provisionalLineage.parentPackageSha256,
102
+ parentDimension: provisionalLineage.parentDimension,
103
+ selectedRoutePointer: continuationState.selectedRoutePointer || flags['package-parent-route-pointer'] || '',
104
+ selectedRouteId: continuationState.selectedRouteId || flags['package-parent-route-id'] || '',
105
+ explicitSiblingIndex: flags['package-sibling-index'],
106
+ enabled: Boolean(flags.output || flags['output-dir'])
107
+ });
108
+ carrierAllocation = siblingAllocation;
109
+ carrierLineage = carrierLineageFromCliParent({
110
+ bundle: parentBundle,
111
+ parentPath: resolvedParent,
112
+ parentBytes,
113
+ routeDimensions,
114
+ qualifiedParentLineage: parentLineage,
115
+ siblingIndex: siblingAllocation.siblingIndex
116
+ });
117
+ }
104
118
  packageParentSha256 = String(carrierLineage.parentPackageSha256 || '');
105
119
  } else if (flags['package-major']) {
106
120
  throw new Error('portable.cli.handoff-carrier.package-major.parent-required');
@@ -129,6 +143,7 @@ export async function prepareHandoffManufactureCliCommand(parsed = {}, runtime =
129
143
  verifyRoundtrip,
130
144
  recipientRouteSelector: flags.route || '',
131
145
  carrierLineage,
146
+ carrierAllocation,
132
147
  carrierProfile,
133
148
  packageParentBundle,
134
149
  packageParentPath: parentPackagePath ? path.resolve(parentPackagePath) : '',
@@ -329,6 +344,7 @@ export function summarizeHandoffManufactureCliOutput(result = {}, writeReceipt =
329
344
  }) : null,
330
345
  toolingBootstrap: result.toolingBootstrap || null,
331
346
  carrierLineage: result.carrierLineage || projection.lineage || null,
347
+ carrierAllocation: result.carrierAllocation || result.manufacturingEvidence?.carrierAllocation || null,
332
348
  majorReadiness: result.majorReadiness || null,
333
349
  operationBoundary: result.operationBoundary ? Object.freeze({ ...result.operationBoundary }) : null,
334
350
  manufacturingEvidence: result.manufacturingEvidence || null,
@@ -2,6 +2,125 @@ 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
+ const POINTER_PATH_RE = /^(\d{3}(?:-\d+)*)-handoff-pointer\.trace\.md$/;
6
+
7
+ export function deriveHandoffSiblingAllocation({ parentInspection = null, selectedRoutePointer = '', selectedRouteId = '', explicitSiblingIndex = null, parentPackagePath = '', parentPackageSha256 = '', parentDimension = '' } = {}) {
8
+ const explicit = normalizeSiblingIndex(explicitSiblingIndex);
9
+ const inspection = parentInspection && typeof parentInspection === 'object' ? parentInspection : null;
10
+ if (!inspection || inspection.detected === false) return freeze({
11
+ state: 'unavailable',
12
+ siblingIndex: explicit || null,
13
+ allocationMode: explicit ? 'explicit-override-only' : 'unavailable',
14
+ reasonCode: 'qualified-parent-route-topology-unavailable',
15
+ provenance: provenanceBase({ parentPackagePath, parentPackageSha256, parentDimension, explicitSiblingIndex: explicit }),
16
+ boundary: allocationBoundary()
17
+ });
18
+ if (String(inspection.status || '') !== 'valid') return freeze({
19
+ state: 'blocked',
20
+ siblingIndex: null,
21
+ allocationMode: 'blocked',
22
+ reasonCode: 'qualified-parent-route-topology-invalid',
23
+ provenance: provenanceBase({ parentPackagePath, parentPackageSha256, parentDimension, explicitSiblingIndex: explicit }),
24
+ boundary: allocationBoundary()
25
+ });
26
+
27
+ const routes = [...(inspection.routes || [])].map((route) => ({
28
+ pointerPath: String(route.pointerPath || '').trim(),
29
+ routeId: String(route.routeId || '').trim(),
30
+ workspaceId: String(route.workspaceId || '').trim(),
31
+ workspaceRelativeHandoffPath: String(route.workspaceRelativeHandoffPath || '').trim()
32
+ }));
33
+ if (!routes.length) return blocked('qualified-parent-route-topology-empty');
34
+
35
+ const qualified = [];
36
+ const seenDimensions = new Set();
37
+ for (const route of routes) {
38
+ const match = route.pointerPath.match(POINTER_PATH_RE);
39
+ if (!match) return blocked('qualified-parent-route-pointer-order-unresolved');
40
+ const dimension = match[1];
41
+ if (seenDimensions.has(dimension)) return blocked('qualified-parent-route-pointer-order-ambiguous');
42
+ seenDimensions.add(dimension);
43
+ qualified.push({ ...route, pointerDimension: dimension, pointerSegments: dimension.split('-').map((value) => Number.parseInt(value, 10)) });
44
+ }
45
+ qualified.sort(comparePointerOrder);
46
+
47
+ const pointerSelector = String(selectedRoutePointer || '').trim();
48
+ const routeIdSelector = String(selectedRouteId || '').trim();
49
+ let selected = null;
50
+ if (pointerSelector) {
51
+ const matches = qualified.filter((route) => route.pointerPath === pointerSelector);
52
+ if (matches.length !== 1) return blocked(matches.length ? 'selected-parent-route-pointer-ambiguous' : 'selected-parent-route-pointer-unqualified');
53
+ selected = matches[0];
54
+ }
55
+ if (routeIdSelector) {
56
+ const matches = qualified.filter((route) => route.routeId === routeIdSelector);
57
+ if (matches.length !== 1) return blocked(matches.length ? 'selected-parent-route-id-ambiguous' : 'selected-parent-route-id-unqualified');
58
+ if (selected && selected.pointerPath !== matches[0].pointerPath) return blocked('selected-parent-route-selector-conflict');
59
+ selected = matches[0];
60
+ }
61
+ if (!selected) {
62
+ if (qualified.length !== 1) return blocked('selected-parent-route-required-for-parallel-topology');
63
+ selected = qualified[0];
64
+ }
65
+
66
+ const siblingIndex = qualified.findIndex((route) => route.pointerPath === selected.pointerPath) + 1;
67
+ if (!Number.isInteger(siblingIndex) || siblingIndex < 1 || siblingIndex > MAX_SIBLING_INDEX) return blocked('derived-sibling-index-out-of-range');
68
+ if (explicit && explicit !== siblingIndex) return blocked('explicit-sibling-index-conflicts-with-qualified-topology', { expectedSiblingIndex: siblingIndex });
69
+
70
+ return freeze({
71
+ state: 'qualified',
72
+ siblingIndex,
73
+ childDimension: parentDimension ? `${String(parentDimension).trim()}-${siblingIndex}` : '',
74
+ allocationMode: 'qualified-parent-route-pointer-ordinal',
75
+ explicitOverride: explicit ? 'matched-derived-value' : 'not-supplied',
76
+ reasonCode: '',
77
+ provenance: {
78
+ ...provenanceBase({ parentPackagePath, parentPackageSha256, parentDimension, explicitSiblingIndex: explicit }),
79
+ basis: 'qualified-parent-route-pointer-ordinal',
80
+ selectedRoutePointer: selected.pointerPath,
81
+ selectedRouteId: selected.routeId,
82
+ selectedWorkspaceId: selected.workspaceId,
83
+ selectedWorkspaceRelativeHandoffPath: selected.workspaceRelativeHandoffPath,
84
+ routeOrdinal: siblingIndex,
85
+ qualifiedRouteCount: qualified.length,
86
+ pointerOrder: qualified.map((route, index) => Object.freeze({ ordinal: index + 1, pointerPath: route.pointerPath, routeId: route.routeId }))
87
+ },
88
+ boundary: allocationBoundary()
89
+ });
90
+
91
+ function blocked(reasonCode, extra = {}) {
92
+ return freeze({
93
+ state: 'blocked', siblingIndex: null, allocationMode: 'blocked', reasonCode, ...extra,
94
+ provenance: provenanceBase({ parentPackagePath, parentPackageSha256, parentDimension, explicitSiblingIndex: explicit }),
95
+ boundary: allocationBoundary()
96
+ });
97
+ }
98
+ }
99
+
100
+ export async function resolveHandoffSiblingAllocation(input = {}) {
101
+ const derived = deriveHandoffSiblingAllocation(input);
102
+ if (derived.state === 'qualified') return derived;
103
+ if (derived.state === 'blocked') throw new Error(`portable.cli.handoff-carrier.sibling-allocation.${derived.reasonCode}`);
104
+ const explicit = normalizeSiblingIndex(input.explicitSiblingIndex ?? input.siblingIndex);
105
+ if (!explicit) throw new Error('portable.cli.handoff-carrier.sibling-allocation.explicit-index-required-when-topology-unavailable');
106
+ const legacy = await reserveHandoffSiblingIndex({
107
+ parentPackagePath: input.parentPackagePath,
108
+ parentPackageSha256: input.parentPackageSha256,
109
+ parentDimension: input.parentDimension,
110
+ enabled: input.enabled !== false,
111
+ siblingIndex: explicit
112
+ });
113
+ return freeze({
114
+ ...legacy,
115
+ allocationMode: 'explicit-advanced-override',
116
+ explicitOverride: 'required-because-qualified-topology-unavailable',
117
+ provenance: {
118
+ ...provenanceBase({ ...input, explicitSiblingIndex: explicit }),
119
+ basis: 'explicit-advanced-override-without-qualified-route-topology'
120
+ },
121
+ boundary: allocationBoundary()
122
+ });
123
+ }
5
124
 
6
125
  export async function reserveHandoffSiblingIndex({ parentPackagePath = '', parentPackageSha256 = '', parentDimension = '', enabled = true, siblingIndex = null } = {}) {
7
126
  const requestedSiblingIndex = normalizeSiblingIndex(siblingIndex);
@@ -35,21 +154,39 @@ export async function reserveHandoffSiblingIndex({ parentPackagePath = '', paren
35
154
  }
36
155
  }
37
156
 
157
+ function comparePointerOrder(left, right) {
158
+ const a = left.pointerSegments || [], b = right.pointerSegments || [];
159
+ for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
160
+ if (a[index] === undefined) return -1;
161
+ if (b[index] === undefined) return 1;
162
+ if (a[index] !== b[index]) return a[index] - b[index];
163
+ }
164
+ return left.pointerPath.localeCompare(right.pointerPath);
165
+ }
166
+
167
+ function provenanceBase({ parentPackagePath = '', parentPackageSha256 = '', parentDimension = '', explicitSiblingIndex = null } = {}) {
168
+ return {
169
+ parentPackagePath: String(parentPackagePath || ''),
170
+ parentPackageSha256: String(parentPackageSha256 || '').trim().toLowerCase(),
171
+ parentDimension: String(parentDimension || '').trim(),
172
+ explicitSiblingIndex: explicitSiblingIndex ? normalizeSiblingIndex(explicitSiblingIndex) : null
173
+ };
174
+ }
175
+ function allocationBoundary() { return 'Transport-only carrier allocation. A non-Major sibling ordinal may come only from exact qualified package-local Handoff Pointer order for the selected parent route, or from an explicit advanced override when such topology is unavailable. Allocation never creates semantic Parent, Workspace, Role, acceptance, completion, participant, process, or source authority; different carrier prefixes are not coordinated.'; }
38
176
  function normalizeSiblingIndex(value) {
39
177
  if (value === null || value === undefined || value === '') return 0;
40
178
  const parsed = Number(value);
41
179
  if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_SIBLING_INDEX) throw new Error('portable.cli.handoff-carrier.sibling-allocation.index-invalid');
42
180
  return parsed;
43
181
  }
44
-
45
182
  async function readAllocation(allocationPath) {
46
183
  try { return JSON.parse(await readFile(allocationPath, 'utf8')); }
47
184
  catch { throw new Error('portable.cli.handoff-carrier.sibling-allocation.existing-reservation-invalid'); }
48
185
  }
49
-
50
186
  function sameAllocation(left = {}, right = {}) {
51
187
  return String(left.parentPackageSha256 || '') === String(right.parentPackageSha256 || '')
52
188
  && String(left.parentDimension || '') === String(right.parentDimension || '')
53
189
  && Number(left.siblingIndex || 0) === Number(right.siblingIndex || 0)
54
190
  && String(left.childDimension || '') === String(right.childDimension || '');
55
191
  }
192
+ function freeze(value) { if (Array.isArray(value)) return Object.freeze(value.map(freeze)); if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value; return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, freeze(item)]))); }
@@ -83,7 +83,7 @@ function commonCommandHelp(command, surfaceCommand) {
83
83
  '',
84
84
  `${command} handoff <workspace-dir>`,
85
85
  '',
86
- 'Infers the latest qualified authored Handoff, selected Workspace identity/target, received package parent as carrier-lineage evidence, canonical projected filename, and return output directory. When the outgoing Handoff declares `Signal Kind: return`, delegation manufacture is transport-not-ready unless the delegator supplies `--return-package-sibling-index <1..9999>` for the expected non-Major return, or explicitly declares `--return-package-major`; the qualified reservation is carried in the route pointer and later continuation state. 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>`. Recovery/integration manufacture can bind the reconciled byte proof with `--require-reconciliation-proof --reconciliation-proof <full-reconcile-receipt.json>`; missing, non-ready, edited, or source-stale proof blocks package output. 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.',
86
+ 'Infers the latest qualified authored Handoff, selected Workspace identity/target, received package parent as carrier-lineage evidence, canonical projected filename, and return output directory. Ordinary non-Major continuation derives its sibling ordinal from the exact qualified selected Handoff Pointer order in the received parent carrier, so common-path `handoff` does not require `--package-sibling-index` or `--return-package-sibling-index`. A single selected Pointer derives `-1`; parallel qualified Pointers derive dense local ordinals in Pointer order, and each returned branch continues from its own carrier. `--package-sibling-index` remains an advanced compatibility override only when qualified route topology is unavailable, and must match when topology already proves the value; conflicting or ambiguous topology fails closed. `--return-package-major` remains the explicit Major-return declaration. Different carrier prefixes are never globally coordinated. 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>`. Recovery/integration manufacture can bind the reconciled byte proof with `--require-reconciliation-proof --reconciliation-proof <full-reconcile-receipt.json>`; missing, non-ready, edited, or source-stale proof blocks package output. 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.',
87
87
  '',
88
88
  `Advanced/internal catalog: ${command} operations`
89
89
  ];
@@ -140,7 +140,8 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
140
140
  }
141
141
  const suppliedTransportRoutes = [...(input.transportRoutes || input.handoffRoutes || [])].map((route) => normalizeTransportRoute(route, workspaceId)).filter(Boolean);
142
142
  const reservationProjection = returnCarrierReservationPreflight.state === 'qualified' && returnCarrierReservationPreflight.returnExpected
143
- ? Object.freeze({ carrierKind: returnCarrierReservationPreflight.carrierKind, siblingIndex: returnCarrierReservationPreflight.siblingIndex })
143
+ && (returnCarrierReservationPreflight.carrierKind === 'major' || Number.isInteger(returnCarrierReservationPreflight.siblingIndex))
144
+ ? Object.freeze({ carrierKind: returnCarrierReservationPreflight.carrierKind, ...(Number.isInteger(returnCarrierReservationPreflight.siblingIndex) ? { siblingIndex: returnCarrierReservationPreflight.siblingIndex } : {}) })
144
145
  : null;
145
146
  const transportRoutes = Object.freeze((suppliedTransportRoutes.length ? suppliedTransportRoutes : [Object.freeze({ workspaceId, path: handoffPath })]).map((route) => Object.freeze({ ...route, ...(route.path === handoffPath && String(route.workspaceId || '') === workspaceId && reservationProjection ? { returnCarrierReservation: reservationProjection } : {}) })));
146
147
  const workspaceTargets = mergeWorkspaceTargetBindings(normalizeWorkspaceTargetBindings({
@@ -205,6 +206,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
205
206
  transportRoutes,
206
207
  workspaceTargets,
207
208
  carrierLineage: normalizeHandoffCarrierLineage(input.carrierLineage || null),
209
+ carrierAllocation: input.carrierAllocation ? Object.freeze({ ...input.carrierAllocation }) : null,
208
210
  carrierProfile: normalizeHandoffCarrierProfile(input.carrierProfile || null),
209
211
  toolingBootstrap: toolingBootstrap.summary,
210
212
  reconciliationProofQualification,
@@ -218,6 +220,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
218
220
  reconciliationProof: reconciliationProofQualification,
219
221
  schemaReferencePreflight,
220
222
  returnCarrierReservationPreflight,
223
+ carrierAllocation: input.carrierAllocation ? Object.freeze({ ...input.carrierAllocation }) : null,
221
224
  packageParentWorkspaceReuse: Object.freeze({
222
225
  state: String(packageParentReuse.state || ''),
223
226
  providerState: String(packageParentReuse.providerState || ''),
@@ -4,6 +4,7 @@ import { projectGroundingSourceEvidence } from './grounding.sourceEvidence.js';
4
4
  import { projectGroundingPlanningContext } from './grounding.planningContext.js';
5
5
  import { projectGroundingParticipantContext } from './grounding.participantContext.js';
6
6
  import { projectGroundingProcessApplicability } from './grounding.processApplicability.js';
7
+ import { projectGroundingImplementationSourceAuthority } from './grounding.implementationSourceAuthority.js';
7
8
 
8
9
  export const PORTABLE_GROUNDING_CAPSULE_SCHEMA_ID = 'tiinex.portable.grounding-capsule.v1';
9
10
 
@@ -16,6 +17,7 @@ export function projectGroundingCapsule({ authority = null, continuation = null,
16
17
  const participantAuthority = projectParticipantAuthority(authority);
17
18
  const participantContext = projectGroundingParticipantContext(authority);
18
19
  const processApplicability = projectGroundingProcessApplicability(authority);
20
+ const implementationSourceAuthority = projectGroundingImplementationSourceAuthority({ authority, records, contextAudit, requiredContext });
19
21
  const sourceEvidence = projectGroundingSourceEvidence({ records, contextAudit, continuation, requiredContext });
20
22
  return Object.freeze({
21
23
  schema: PORTABLE_GROUNDING_CAPSULE_SCHEMA_ID,
@@ -29,16 +31,21 @@ export function projectGroundingCapsule({ authority = null, continuation = null,
29
31
  recipientState: String(authority?.role?.state || 'unresolved'),
30
32
  holder: String(authority?.holderBinding?.roleLabel || ''),
31
33
  holderState: String(authority?.holderBinding?.state || 'unresolved'),
32
- compatibility: String(authority?.holderBinding?.recipientCompatibility || 'unresolved')
34
+ compatibility: String(authority?.holderBinding?.recipientCompatibility || 'unresolved'),
35
+ authorizationState: String(authority?.holderBinding?.authorization?.state || (String(authority?.holderBinding?.state || '') === 'not-applicable' ? 'not-applicable' : 'unresolved')),
36
+ authorizationSource: String(authority?.holderBinding?.authorization?.source || ''),
37
+ durableIdentityState: String(authority?.holderBinding?.durableIdentity?.state || 'not-established')
33
38
  }),
34
39
  participantAuthority,
35
40
  participantContext,
36
41
  processApplicability,
42
+ implementationSourceAuthority,
37
43
  workProvenance,
38
44
  unresolved: Object.freeze([
39
45
  ...workProvenance.unresolved,
40
46
  ...participantContext.unresolved,
41
47
  ...processApplicability.unresolved,
48
+ ...implementationSourceAuthority.unresolved,
42
49
  ...sourceEvidence.blockers.map((item) => ({ code: item.code, detail: item.request }))
43
50
  ]),
44
51
  boundary: 'Full Required Context bodies remain selector-gated.'
@@ -0,0 +1,81 @@
1
+ import { deepFreeze, normalizeComparable, normalizeToken } from '../handoff/coldStartQualification.shared.js';
2
+
3
+ export const EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE = 'assignable per explicit session or Handoff';
4
+ export const CURRENT_ROLE_EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE = 'assignable per explicit session, role invocation, or Handoff; no permanent holder asserted';
5
+ export const ANCHOR_EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE = 'assignable per explicit session or Handoff; no permanent holder asserted';
6
+
7
+ const AUTHORIZED_EXPLICIT_SESSION_OR_HANDOFF_STATES = new Set([
8
+ normalizeComparable(EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE),
9
+ normalizeComparable(CURRENT_ROLE_EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE),
10
+ normalizeComparable(ANCHOR_EXPLICIT_SESSION_OR_HANDOFF_HOLDER_STATE)
11
+ ]);
12
+
13
+ export function projectHolderBindingAuthorization(role = {}) {
14
+ const endpointKind = normalizeToken(role?.endpoint?.kind || '');
15
+ if (endpointKind !== 'role') return deepFreeze({
16
+ state: 'not-applicable',
17
+ assignmentMode: '',
18
+ holderState: '',
19
+ source: 'none',
20
+ reasonCode: 'recipient-not-role',
21
+ provenance: {
22
+ basis: 'recipient-not-role',
23
+ roleArtifactPath: '',
24
+ roleArtifactSha256: '',
25
+ section: 'Holder Relationship',
26
+ field: 'Holder State',
27
+ boundary: 'Holder-assignment authorization is only applicable when the selected Handoff recipient is a Role endpoint.'
28
+ },
29
+ boundary: 'No Role assignment authorization is required for a non-Role recipient.'
30
+ });
31
+
32
+ const material = role?.material?.artifact || null;
33
+ const relationship = role?.holderRelationshipLoaded || {};
34
+ const holderState = String(relationship.holderState || '').trim();
35
+ const qualifiedMaterial = String(role?.state || '') === 'qualified'
36
+ && String(role?.material?.state || '') === 'qualified'
37
+ && Boolean(material?.path)
38
+ && Boolean(material?.sha256);
39
+ const provenance = {
40
+ basis: qualifiedMaterial ? 'exact-qualified-role-holder-relationship' : 'exact-qualified-role-holder-relationship-not-established',
41
+ roleArtifactPath: String(material?.path || ''),
42
+ roleArtifactSha256: String(material?.sha256 || ''),
43
+ roleSchemaId: String(material?.schemaId || ''),
44
+ roleLabel: String(material?.roleLabel || role?.endpoint?.label || ''),
45
+ section: 'Holder Relationship',
46
+ field: 'Holder State',
47
+ exactValue: holderState,
48
+ boundary: 'Only exact qualified recipient Role material may authorize the bounded session assignment mode. Handoff endpoints, transport identity, explicit session input, filenames, and package placement do not provide this authority.'
49
+ };
50
+
51
+ if (!qualifiedMaterial) return deepFreeze({
52
+ state: 'unresolved',
53
+ assignmentMode: '',
54
+ holderState,
55
+ source: 'none',
56
+ reasonCode: 'qualified-role-holder-authority-not-established',
57
+ provenance,
58
+ boundary: 'A matching session Role assertion remains unauthorized until exact qualified Role material establishes the assignment mode.'
59
+ });
60
+
61
+ const assignmentAuthorized = AUTHORIZED_EXPLICIT_SESSION_OR_HANDOFF_STATES.has(normalizeComparable(holderState));
62
+ if (!assignmentAuthorized) return deepFreeze({
63
+ state: 'unresolved',
64
+ assignmentMode: '',
65
+ holderState,
66
+ source: 'qualified-recipient-role-material',
67
+ reasonCode: holderState ? 'holder-assignment-mode-not-authorized' : 'holder-assignment-mode-unresolved',
68
+ provenance,
69
+ boundary: 'The exact qualified Role does not establish authorization for explicit-session/Handoff assignment. Core preserves this as unresolved and does not reinterpret other Holder State wording.'
70
+ });
71
+
72
+ return deepFreeze({
73
+ state: 'qualified',
74
+ assignmentMode: 'explicit-session-or-handoff',
75
+ holderState,
76
+ source: 'qualified-recipient-role-material',
77
+ reasonCode: 'holder-assignment-mode-authorized',
78
+ provenance,
79
+ boundary: 'Exact qualified Role Holder Relationship authorizes this assignment mode for the bounded current session only; it does not establish durable holder identity or broader participant/process/source authority.'
80
+ });
81
+ }
@@ -0,0 +1,109 @@
1
+ const MAX_FACTS = 12;
2
+ const MAX_WORKSPACE_FACTS = 12;
3
+
4
+ export function projectGroundingImplementationSourceAuthority({ authority = null, records = [], contextAudit = null, requiredContext = [] } = {}) {
5
+ const supplied = authority?.implementationSourceAuthority || null;
6
+ const exactUpstream = qualifiesExactUpstreamProjection(supplied);
7
+ const descriptiveFacts = projectDescriptiveWorkspaceFacts({ records, contextAudit, requiredContext });
8
+
9
+ if (!exactUpstream) return Object.freeze({
10
+ state: 'unresolved',
11
+ facts: Object.freeze([]),
12
+ descriptiveFacts,
13
+ provenance: Object.freeze({
14
+ basis: 'no-exact-upstream-qualified-implementation-source-authority-projection',
15
+ sourceArtifact: null,
16
+ boundary: 'Core does not derive implementation-source creation authority from Workspace carriage, completeness, boundedness, writability language, path adjacency, repository identity, or current Task wording.'
17
+ }),
18
+ unresolved: Object.freeze([Object.freeze({
19
+ code: 'implementation-source-authority-not-established',
20
+ detail: 'No exact upstream-qualified implementation-source authority projection is present. Workspace purpose/boundary facts remain descriptive only; do not infer permission to create or select implementation source from carriage, writability, repository identity, path adjacency, or executable Task presence.'
21
+ })]),
22
+ boundary: 'Semantics-neutral diagnostic only. Core exposes exact upstream authority projections when independently qualified, but does not define allow/deny meaning or manufacture source-creation permission.'
23
+ });
24
+
25
+ const facts = Array.isArray(supplied.facts) ? supplied.facts : Array.isArray(supplied.items) ? supplied.items : [];
26
+ return Object.freeze({
27
+ state: 'explicit-qualified-upstream-projection',
28
+ facts: Object.freeze(facts.slice(0, MAX_FACTS).map((item) => Object.freeze({ ...(item || {}) }))),
29
+ descriptiveFacts,
30
+ provenance: Object.freeze({
31
+ basis: 'exact-upstream-qualified-implementation-source-authority-projection',
32
+ sourceArtifact: Object.freeze(projectSourceArtifact(supplied)),
33
+ upstreamProvenance: supplied.provenance ? Object.freeze({ ...(supplied.provenance || {}) }) : null,
34
+ boundary: 'Core passes through the already-qualified upstream projection and exact source-artifact identity without interpreting its semantic allow/deny meaning.'
35
+ }),
36
+ unresolved: Object.freeze([]),
37
+ boundary: 'Semantics-neutral pass-through only. The upstream semantic owner defines the meaning of projected facts; Core neither broadens nor converts them into generic source authority.'
38
+ });
39
+ }
40
+
41
+ function qualifiesExactUpstreamProjection(value = null) {
42
+ if (!value || typeof value !== 'object' || value.explicit !== true) return false;
43
+ if (String(value.qualification || value.state || '').trim().toLowerCase() !== 'qualified') return false;
44
+ const source = projectSourceArtifact(value);
45
+ return Boolean(source.path && /^[0-9a-f]{64}$/i.test(source.sha256));
46
+ }
47
+
48
+ function projectSourceArtifact(value = {}) {
49
+ const source = value.sourceArtifact || value.provenance?.sourceArtifact || {};
50
+ return {
51
+ workspaceId: String(source.workspaceId || source.workspace || ''),
52
+ path: String(source.path || source.workspaceRelativePath || value.provenance?.sourceArtifactPath || ''),
53
+ sha256: String(source.sha256 || value.provenance?.sourceArtifactSha256 || '').trim().toLowerCase(),
54
+ schemaId: String(source.schemaId || '')
55
+ };
56
+ }
57
+
58
+ function projectDescriptiveWorkspaceFacts({ records = [], contextAudit = null, requiredContext = [] } = {}) {
59
+ const byPath = new Map((records || []).map((record) => [String(record.path || ''), record]));
60
+ const out = [];
61
+ for (const workspace of contextAudit?.workspaceMaterializations || []) {
62
+ if (out.length >= MAX_WORKSPACE_FACTS) break;
63
+ if (String(workspace.qualification || '') !== 'qualified') continue;
64
+ const workspaceId = String(workspace.workspaceId || '');
65
+ const innerPath = normalizePath(workspace.sourceWorkspaceTargetInnerPath || '');
66
+ const exactPath = workspaceId && innerPath ? `${workspaceId}/${innerPath}` : '';
67
+ const record = exactPath ? byPath.get(exactPath) : null;
68
+ if (!record || !record.hasContinuityContext || !record.hasIntegrity) continue;
69
+ const boundary = section(record.markdown || '', 'Workspace Boundary');
70
+ if (!boundary) continue;
71
+ out.push(Object.freeze({
72
+ kind: 'workspace-boundary',
73
+ workspace: workspaceId,
74
+ text: compact(boundary, 500),
75
+ authorityEffect: 'descriptive-only',
76
+ provenance: Object.freeze({
77
+ basis: 'exact-qualified-workspace-artifact-section',
78
+ sourceArtifactPath: exactPath,
79
+ sourceArtifactSha256: String(workspace.sourceWorkspaceTargetSha256 || ''),
80
+ section: 'Workspace Boundary',
81
+ boundary: 'Exact carried Workspace metadata is exposed as a fact only; Core does not reinterpret boundary prose as implementation-source creation permission.'
82
+ })
83
+ }));
84
+ }
85
+ for (const entry of requiredContext || []) {
86
+ if (out.length >= MAX_WORKSPACE_FACTS) break;
87
+ if (String(entry.state || '') !== 'qualified' || !String(entry.purpose || '').trim()) continue;
88
+ out.push(Object.freeze({
89
+ kind: 'required-context-purpose',
90
+ workspace: String(entry.workspaceId || ''),
91
+ text: compact(entry.purpose, 500),
92
+ authorityEffect: 'descriptive-only',
93
+ provenance: Object.freeze({
94
+ basis: String(entry.provenance?.basis || 'selected-handoff-required-context-declaration'),
95
+ declarationSource: entry.provenance?.declarationSource ? Object.freeze({ ...(entry.provenance.declarationSource || {}) }) : null,
96
+ requirementId: String(entry.requirementId || ''),
97
+ boundary: 'Selected-Handoff purpose text is exposed verbatim as route context; it is not converted into implementation-source creation authority.'
98
+ })
99
+ }));
100
+ }
101
+ return Object.freeze(out);
102
+ }
103
+
104
+ function section(markdown = '', heading = '') {
105
+ const escaped = String(heading || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
106
+ return String(markdown || '').match(new RegExp(`(?:^|\\n)##\\s+${escaped}\\s*\\r?\\n([\\s\\S]*?)(?=\\n##\\s+|\\n#\\s+Continuity Integrity|$)`, 'i'))?.[1]?.trim() || '';
107
+ }
108
+ function compact(value = '', limit = 500) { const text = String(value || '').replace(/\s+/g, ' ').trim(); return text.length > limit ? `${text.slice(0, limit - 1).trimEnd()}…` : text; }
109
+ function normalizePath(value = '') { return String(value || '').replace(/\\/g, '/').replace(/^\/+/, ''); }
@@ -10,7 +10,7 @@ export function projectParticipantAuthority(authority = null) {
10
10
  recipientRole: String(role.endpoint?.label || authority?.handoff?.to || ''),
11
11
  roleMaterial: Object.freeze({ path: String(material.path || ''), schemaId: String(material.schemaId || ''), roleLabel: String(material.roleLabel || '') }),
12
12
  authorityBoundary: Object.freeze({ mayDo: compact(declared.mayDo), doesNotAuthorize: compact(declared.doesNotAuthorize), reviewBoundary: compact(declared.reviewBoundary) }),
13
- holderBinding: Object.freeze({ state: String(holder.state || 'unresolved'), roleLabel: String(holder.roleLabel || ''), source: String(holder.source || 'none'), explicit: Boolean(holder.explicit), inferredFromTransport: Boolean(holder.inferredFromTransport) }),
13
+ holderBinding: Object.freeze({ state: String(holder.state || 'unresolved'), bindingPresent: String(holder.state || '') === 'qualified', declarationPresent: Boolean(holder.explicit), roleLabel: String(holder.roleLabel || ''), source: String(holder.source || 'none'), sourceDetail: holder.sourceDetail ? Object.freeze({ ...(holder.sourceDetail || {}) }) : null, authorization: holder.authorization ? Object.freeze({ ...holder.authorization, provenance: holder.authorization.provenance ? Object.freeze({ ...holder.authorization.provenance }) : null }) : null, durableIdentity: holder.durableIdentity ? Object.freeze({ ...holder.durableIdentity }) : Object.freeze({ state: 'not-established' }), semanticAuthorityState: String(holder.sourceDetail?.semanticAuthorityState || 'not-established'), explicit: Boolean(holder.explicit), inferredFromTransport: Boolean(holder.inferredFromTransport) }),
14
14
  participantIdentityCreatesAuthority: false,
15
15
  conversationPositionCreatesAuthority: false,
16
16
  universalHumanFeedbackRule: false,
@@ -38,16 +38,31 @@ export function projectGroundingAuthority(authority, mode) {
38
38
  role: authority.role ? Object.freeze({ state: authority.role.state || '', label: authority.role.endpoint?.label || '', kind: authority.role.endpoint?.kind || '' }) : null,
39
39
  holderBinding: authority.holderBinding ? Object.freeze({
40
40
  state: authority.holderBinding.state || '',
41
+ bindingPresent: String(authority.holderBinding.state || '') === 'qualified',
42
+ declarationPresent: Boolean(authority.holderBinding.explicit),
41
43
  holderId: authority.holderBinding.holderId || '',
42
44
  roleLabel: authority.holderBinding.roleLabel || '',
43
45
  recipientRoleLabel: authority.holderBinding.recipientRoleLabel || '',
44
46
  recipientCompatibility: authority.holderBinding.recipientCompatibility || '',
45
47
  source: authority.holderBinding.source || '',
48
+ sourceDetail: authority.holderBinding.sourceDetail ? Object.freeze({ ...(authority.holderBinding.sourceDetail || {}) }) : null,
49
+ authorization: authority.holderBinding.authorization ? Object.freeze({
50
+ ...(authority.holderBinding.authorization || {}),
51
+ provenance: authority.holderBinding.authorization.provenance ? Object.freeze({ ...(authority.holderBinding.authorization.provenance || {}) }) : null
52
+ }) : null,
53
+ durableIdentity: authority.holderBinding.durableIdentity ? Object.freeze({ ...(authority.holderBinding.durableIdentity || {}) }) : Object.freeze({ state: 'not-established' }),
54
+ semanticAuthorityState: authority.holderBinding.sourceDetail?.semanticAuthorityState || 'not-established',
46
55
  explicit: Boolean(authority.holderBinding.explicit),
47
56
  inferredFromTransport: Boolean(authority.holderBinding.inferredFromTransport),
48
57
  provenance: Object.freeze({
49
58
  basis: authority.holderBinding.explicit ? 'explicit-consuming-session-holder-binding' : 'unresolved-or-non-explicit-holder-binding',
50
59
  source: authority.holderBinding.source || '',
60
+ sourceKind: authority.holderBinding.sourceDetail?.kind || '',
61
+ sourceLocator: authority.holderBinding.sourceDetail?.locator || '',
62
+ semanticAuthorityState: authority.holderBinding.sourceDetail?.semanticAuthorityState || 'not-established',
63
+ qualifiedMaterialSource: Boolean(authority.holderBinding.sourceDetail?.qualifiedMaterialSource),
64
+ authorizationState: authority.holderBinding.authorization?.state || 'unresolved',
65
+ authorizationBasis: authority.holderBinding.authorization?.provenance?.basis || '',
51
66
  boundary: authority.holderBinding.boundary || 'Consuming-session holder identity is never inferred from route transport or recipient position.'
52
67
  }),
53
68
  boundary: authority.holderBinding.boundary || ''
@@ -113,6 +113,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
113
113
  const route = authority?.selectedRoute || null;
114
114
  const roleState = String(authority?.role?.state || 'unresolved');
115
115
  const holderState = String(authority?.holderBinding?.state || 'unresolved');
116
+ const holderAuthorizationState = String(authority?.holderBinding?.authorization?.state || (holderState === 'not-applicable' ? 'not-applicable' : 'unresolved'));
116
117
  if (!route || String(authority?.status || '') === 'blocked') missing(missingEvidence, unresolved, 'authority-route-unqualified', 'The selected Handoff route is not qualified for this grounding result.');
117
118
  else known.push(evidence('qualified-handoff-route', 'qualified', route.id || route.pointerPath || 'selected-route'));
118
119
  if (roleState === 'qualified' || roleState === 'not-applicable') known.push(evidence('recipient-role-boundary', roleState, authority?.role?.endpoint?.label || 'recipient'));
@@ -120,7 +121,6 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
120
121
  else missing(missingEvidence, unresolved, 'recipient-role-unresolved', 'The Handoff recipient Role boundary is not qualified for act-ready grounding.');
121
122
 
122
123
  if (holderState === 'qualified' || holderState === 'not-applicable') {
123
- holderBindingActReady = true;
124
124
  known.push(evidence('session-holder-role-binding', holderState, authority?.holderBinding?.roleLabel || authority?.role?.endpoint?.label || 'recipient'));
125
125
  } else if (holderState === 'blocked') {
126
126
  holderBindingActReady = false;
@@ -131,13 +131,28 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
131
131
  reasons.push(reason('session-holder-role-binding-unresolved', 'The selected recipient Role does not assign itself to this consuming session. Supply an explicit matching session holder Role binding before act-ready continuation.'));
132
132
  }
133
133
 
134
+ if (holderState === 'not-applicable') {
135
+ holderBindingActReady = true;
136
+ known.push(evidence('session-holder-role-binding-authorization', 'not-applicable', 'selected Handoff recipient is not a Role endpoint'));
137
+ } else if (holderState === 'qualified') {
138
+ if (holderAuthorizationState === 'qualified') {
139
+ holderBindingActReady = true;
140
+ known.push(evidence('session-holder-role-binding-authorization', 'qualified', authority?.holderBinding?.authorization?.provenance?.roleArtifactPath || authority?.role?.endpoint?.label || 'recipient Role material'));
141
+ } else {
142
+ holderBindingActReady = false;
143
+ unresolved.push(evidence('session-holder-role-binding-authorization', holderAuthorizationState || 'unresolved', authority?.holderBinding?.authorization?.holderState || 'exact qualified Role Holder Relationship does not establish the explicit-session/Handoff assignment mode'));
144
+ reasons.push(reason('session-holder-role-binding-authorization-unresolved', 'The explicit consuming-session Role assertion matches the selected recipient Role, but exact qualified Role holder-assignment authority does not establish that assignment mode. Matching session input alone cannot make the route act-ready.'));
145
+ }
146
+ }
147
+
134
148
  const required = Array.isArray(requiredContext) ? requiredContext : [];
135
149
  const unresolvedRequired = required.filter((entry) => entry.state !== 'qualified');
136
150
  if (unresolvedRequired.length) missing(missingEvidence, unresolved, 'required-context-unqualified', `${unresolvedRequired.length} declared Required Context item(s) are not exact-qualified.`);
137
151
  else known.push(evidence('required-context-closure', 'qualified', `${required.length} item(s)`));
138
152
  if (String(continuation?.state || '') !== 'ready') missing(missingEvidence, unresolved, 'continuation-not-ready', 'The grounded continuation is not ready for substantive work.');
139
- if (String(contextAudit?.status || '') !== 'ready' || String(contextAudit?.coverage?.state || '') !== 'qualified') missing(missingEvidence, unresolved, 'workspace-snapshot-coverage-unqualified', 'Complete carried Workspace snapshot coverage is not qualified.');
140
- else known.push(evidence('workspace-snapshot-coverage', 'qualified', `${contextAudit.workspaceMaterializations?.length || 0} workspace(s)`));
153
+ const workspaceCoverage = projectWorkspaceActionCoverage(contextAudit);
154
+ if (!workspaceCoverage.qualified) missing(missingEvidence, unresolved, 'workspace-snapshot-coverage-unqualified', workspaceCoverage.message);
155
+ else known.push(evidence('workspace-snapshot-coverage', 'qualified', `${workspaceCoverage.count} workspace representation(s): ${workspaceCoverage.completeCount} complete, ${workspaceCoverage.boundedCount} bounded`));
141
156
  for (const item of requiredRecordResolution.missing) missing(missingEvidence, unresolved, 'required-context-not-in-snapshot', item);
142
157
  if (!routeRecordIds.size) missing(missingEvidence, unresolved, 'selected-route-not-in-snapshot', 'The qualified selected Handoff route was not found at its exact carried Workspace path.');
143
158
  } else {
@@ -148,7 +163,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
148
163
  if (!records.length) missing(missingEvidence, unresolved, 'no-artifact-records', 'No readable Tiinex artifact records were loaded for grounding.');
149
164
  else known.push(evidence('loaded-artifact-records', 'known', `${records.length} record(s)`));
150
165
 
151
- inferred.push(evidence('relevant-lineage-scope', 'bounded-inference', handoffMode ? 'directed declared-Parent cone around the exact selected Handoff route within complete carried Workspace snapshots plus independently qualified exact detached Parent-boundary cache records' : 'all loaded records'));
166
+ inferred.push(evidence('relevant-lineage-scope', 'bounded-inference', handoffMode ? 'directed declared-Parent cone around the exact selected Handoff route within qualified carried Workspace representations (complete or bounded as declared) plus independently qualified exact detached Parent-boundary cache records' : 'all loaded records'));
152
167
  inferred.push(evidence('lineage-leaf-role', 'bounded-inference', 'derived only from declared Parent edges in the shared resolver'));
153
168
 
154
169
  if (handoffMode) {
@@ -157,7 +172,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
157
172
  } else if (topology.routeLeaves.length) {
158
173
  known.push(evidence('selected-route-parent-lineage-leaf', 'resolved', `${topology.routeLeaves.length} selected-route leaf/leaves`));
159
174
  } else {
160
- missing(missingEvidence, unresolved, 'selected-route-lineage-leaf-missing', 'The selected Handoff route is not a resolved Parent-lineage leaf in the complete carried Workspace snapshots.');
175
+ missing(missingEvidence, unresolved, 'selected-route-lineage-leaf-missing', 'The selected Handoff route is not a resolved Parent-lineage leaf in the qualified carried Workspace material.');
161
176
  }
162
177
  if (lineageIssues.length > routeBlockingLineageIssues.length) unresolved.push(evidence('upstream-lineage-diagnostics', continuity.state === 'qualified' ? 'degraded-nonblocking' : 'blocking-for-cold-start-continuity', `${lineageIssues.length - routeBlockingLineageIssues.length} upstream Parent-lineage issue(s) remain outside the selected-route edge boundary.`));
163
178
  } else if (lineageIssues.length) {
@@ -190,7 +205,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
190
205
  let state = 'grounded-to-act';
191
206
  if (missingEvidence.length) state = 'insufficient-grounding';
192
207
  else if (!handoffMode || !holderBindingActReady || !topology.currentFrontier.length || humanOnly.length) state = 'grounded-to-discuss';
193
- if (state === 'grounded-to-act') reasons.push(reason('bounded-act-ready', 'Selected Handoff authority, explicit consuming-session holder Role binding, Required Context, carried Workspace coverage, cold-start continuity to a qualified semantic root, the selected-route Parent-lineage leaf, and declared current-work frontier evidence are all resolved enough for the next bounded action.'));
208
+ if (state === 'grounded-to-act') reasons.push(reason('bounded-act-ready', 'Selected Handoff authority, explicit consuming-session holder Role binding, exact qualified holder-assignment authorization where the recipient is a Role, exact Required Context, qualified carried Workspace coverage (complete or bounded as declared), cold-start continuity to a qualified semantic root, the selected-route Parent-lineage leaf, and declared current-work frontier evidence are all resolved enough for the next bounded action.'));
194
209
  const orchestrationReadiness = projectGroundingOrchestrationReadiness({ readinessState: state, participantContext: capsule.participantContext, processApplicability: capsule.processApplicability, sourceEvidence: capsule.sourceEvidence, topology });
195
210
 
196
211
  return Object.freeze({
@@ -218,11 +233,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
218
233
  requestedSelectors: requiredContextProjection.requestedSelectors,
219
234
  unmatchedSelectors: requiredContextProjection.unmatchedSelectors
220
235
  }),
221
- workspaceSnapshots: contextAudit ? Object.freeze({
222
- state: String(contextAudit.coverage?.state || contextAudit.status || 'unresolved'),
223
- qualified: String(contextAudit.status || '') === 'ready',
224
- count: contextAudit.workspaceMaterializations?.length || 0
225
- }) : Object.freeze({ state: 'not-supplied', qualified: false, count: 0 })
236
+ workspaceSnapshots: contextAudit ? projectWorkspaceActionCoverage(contextAudit) : Object.freeze({ state: 'not-supplied', qualified: false, count: 0, completeCount: 0, boundedCount: 0, unqualified: Object.freeze([]), message: 'No carried Workspace context audit was supplied.' })
226
237
  }),
227
238
  lineage: Object.freeze({
228
239
  state: handoffMode ? (routeBlockingLineageIssues.length ? 'unresolved' : topology.routeLeaves.length ? (lineageIssues.length ? 'resolved-with-upstream-degradation' : 'resolved') : 'missing-leaf') : (lineageIssues.length ? 'unresolved' : topology.leaves.length ? 'resolved' : 'missing-leaf'),
@@ -277,6 +288,47 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
277
288
  });
278
289
  }
279
290
 
291
+ function projectWorkspaceActionCoverage(contextAudit = {}) {
292
+ const workspaces = Array.isArray(contextAudit?.workspaceMaterializations) ? contextAudit.workspaceMaterializations : [];
293
+ const summaries = workspaces.map((workspace) => {
294
+ const coverage = workspaceCoverageState(workspace);
295
+ const qualification = String(workspace?.qualification || '').trim().toLowerCase();
296
+ const qualified = ['complete', 'bounded'].includes(coverage) && qualification === 'qualified';
297
+ return Object.freeze({ workspaceId: String(workspace?.workspaceId || ''), coverage, qualification: qualification || 'unresolved', qualified });
298
+ });
299
+ const aggregateReady = String(contextAudit?.status || '') === 'ready' && String(contextAudit?.coverage?.state || '') === 'qualified';
300
+ const qualified = aggregateReady && summaries.length > 0 && summaries.every((item) => item.qualified);
301
+ const completeCount = summaries.filter((item) => item.coverage === 'complete').length;
302
+ const boundedCount = summaries.filter((item) => item.coverage === 'bounded').length;
303
+ const unqualified = summaries.filter((item) => !item.qualified);
304
+ const message = qualified
305
+ ? `Qualified carried Workspace coverage is established for ${summaries.length} representation(s): ${completeCount} complete, ${boundedCount} bounded.`
306
+ : !aggregateReady
307
+ ? 'Carried Workspace context audit is not qualified for bounded action readiness.'
308
+ : !summaries.length
309
+ ? 'No qualified carried Workspace representation is available for the selected Handoff route.'
310
+ : `Carried Workspace representation qualification is incomplete for ${unqualified.length} workspace(s); bounded carriage is actionable only when each carried representation is independently qualified as complete or bounded.`;
311
+ return Object.freeze({
312
+ state: qualified ? 'qualified' : 'unqualified',
313
+ qualified,
314
+ count: summaries.length,
315
+ completeCount,
316
+ boundedCount,
317
+ unqualified: Object.freeze(unqualified),
318
+ message,
319
+ boundary: 'Complete and bounded carriage remain distinct. Bounded coverage can satisfy current-route action readiness only when the carried representation itself is qualified; it never implies whole-Workspace or whole-program authority.'
320
+ });
321
+ }
322
+
323
+ function workspaceCoverageState(workspace = {}) {
324
+ const explicit = String(workspace?.coverage || workspace?.materialization || '').trim().toLowerCase();
325
+ if (explicit === 'complete' || explicit === 'bounded') return explicit;
326
+ const reason = String(workspace?.reason || '').trim().toLowerCase();
327
+ if (reason.includes('bounded') || reason.includes('partial')) return 'bounded';
328
+ if (reason.includes('complete')) return 'complete';
329
+ return 'unresolved';
330
+ }
331
+
280
332
  function projectCurrentWork(topology = {}, records = [], includeCurrentWork = false) {
281
333
  const recordById = new Map((records || []).map((record) => [String(record.id || ''), record]));
282
334
  const frontier = (topology.currentFrontier || []).slice(0, MAX_ITEMS).map((item) => {
@@ -300,8 +352,13 @@ function projectCurrentWork(topology = {}, records = [], includeCurrentWork = fa
300
352
  }
301
353
 
302
354
  function nextActionFor(state, topology, continuity = {}, authority = null) {
303
- if (state === 'grounded-to-act') return Object.freeze({ kind: 'continue-bounded-handoff-work', target: topology.currentFrontier[0]?.path || '', basis: 'qualified authority + explicit session holder Role binding + required context + cold-start root continuity + selected-route Parent leaf + declared current-work frontier' });
355
+ if (state === 'grounded-to-act') return Object.freeze({ kind: 'continue-bounded-handoff-work', target: topology.currentFrontier[0]?.path || '', basis: 'qualified authority + explicit session holder Role binding + exact qualified holder-assignment authorization when Role-recipient + required context + cold-start root continuity + selected-route Parent leaf + declared current-work frontier' });
304
356
  if (state === 'grounded-to-discuss' && String(authority?.holderBinding?.state || 'unresolved') === 'unresolved') return Object.freeze({ kind: 'declare-explicit-session-holder-role-binding', target: authority?.role?.endpoint?.label || authority?.handoff?.to || '', basis: 'recipient Role qualification is separate from consuming-session holder binding; no transport/provider/assistant-user identity inference is permitted' });
357
+ if (state === 'grounded-to-discuss' && String(authority?.holderBinding?.state || '') === 'qualified' && String(authority?.holderBinding?.authorization?.state || 'unresolved') !== 'qualified') return Object.freeze({
358
+ kind: 'resolve-session-holder-binding-authorization',
359
+ target: authority?.holderBinding?.authorization?.provenance?.roleArtifactPath || authority?.role?.endpoint?.label || authority?.handoff?.to || '',
360
+ basis: 'a matching explicit session Role assertion is not semantic authorization; exact qualified recipient Role Holder Relationship authority must establish the assignment mode'
361
+ });
305
362
  if (state === 'grounded-to-discuss') return Object.freeze({ kind: topology.currentFrontier.length ? 'obtain-bounded-action-authority-or-human-gate' : 'resolve-current-work-frontier', target: topology.currentTasks[0]?.path || '', basis: 'discussion-ready but act-readiness condition is unresolved' });
306
363
  if (continuity?.state === 'unproven') return Object.freeze({
307
364
  kind: continuity.recovery?.state === 'host-action-available' ? 'recover-required-parent-with-host-action' : 'request-exact-required-parent-material',
@@ -168,7 +168,7 @@ export function resolveRequiredContextRecords(requiredContext = [], records = []
168
168
  const record = byPath.get(expectedPath);
169
169
  if (record) { ids.add(record.id); matched += 1; continue; }
170
170
  if (isExactHydratedWorkspaceContext(entry)) { matched += 1; continue; }
171
- missing.push(`${entry.requirementId || entry.name || expectedPath}: exact qualified context was not found at ${expectedPath} inside the complete carried Workspace snapshots.`);
171
+ missing.push(`${entry.requirementId || entry.name || expectedPath}: exact qualified context was not found at ${expectedPath} inside the qualified carried Workspace material.`);
172
172
  }
173
173
  return Object.freeze({ ids, matched, missing: Object.freeze(missing) });
174
174
  }
@@ -31,6 +31,7 @@ import {
31
31
  normalizeStringList,
32
32
  normalizeToken
33
33
  } from './coldStartQualification.shared.js';
34
+ import { projectHolderBindingAuthorization } from '../grounding/grounding.holderBindingAuthorization.js';
34
35
 
35
36
  export function groundPortableColdConsumer(input = {}, options = {}) {
36
37
  const ingressKind = normalizeIngressKind(input.ingressKind || input.kind || (input.toolingAvailable === false ? COLD_START_INGRESS_KINDS.DEGRADED_CAPTURE : COLD_START_INGRESS_KINDS.HANDOFF));
@@ -59,7 +60,7 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
59
60
 
60
61
  const bundle = input.bundle || input.package || input;
61
62
  const role = groundRecipientRole(input, handoff, bundle, orientation, selectedRoute, findings, materialContext);
62
- const holderBinding = groundHolderBinding(input, handoff, findings);
63
+ const holderBinding = groundHolderBinding(input, handoff, role, findings);
63
64
  const participation = groundParticipation(input, handoff, bundle, orientation, selectedRoute, findings, materialContext);
64
65
  const interaction = groundInteraction(input, handoff);
65
66
 
@@ -68,7 +69,12 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
68
69
  }
69
70
 
70
71
  const blocked = findings.some((finding) => finding.severity === 'error');
71
- const degraded = degradedCapture.active || role.state === 'degraded' || holderBinding.state === 'unresolved' || interaction.modeState === 'unresolved' || participation.participantState === 'unresolved';
72
+ const degraded = degradedCapture.active
73
+ || role.state === 'degraded'
74
+ || holderBinding.state === 'unresolved'
75
+ || holderBinding.authorization?.state === 'unresolved'
76
+ || interaction.modeState === 'unresolved'
77
+ || participation.participantState === 'unresolved';
72
78
  return deepFreeze({
73
79
  schema: PORTABLE_COLD_CONSUMER_GROUNDING_SCHEMA_ID,
74
80
  version: 1,
@@ -178,13 +184,14 @@ function groundRecipientRole(input, handoff, bundle, orientation, selectedRoute,
178
184
  compatibility,
179
185
  exactBoundaryLoaded: selected ? selected.boundary : null,
180
186
  authorityBoundaryLoaded: selected ? selected.authorityBoundary : null,
187
+ holderRelationshipLoaded: selected ? selected.holderRelationship : null,
181
188
  interpretationLimitsLoaded: selected ? selected.interpretationLimits : null,
182
189
  boundary: 'A Handoff `To Kind: role` endpoint remains bounded even when current Role material is missing. Matching Role material qualifies the loaded boundary but does not prove a human holder, consent, or authority beyond the Role artifact itself.'
183
190
  });
184
191
  }
185
192
 
186
193
 
187
- function groundHolderBinding(input, handoff, findings) {
194
+ function groundHolderBinding(input, handoff, role, findings) {
188
195
  const raw = input.holderBinding || input.sessionHolderBinding || input.sessionRoleBinding || {};
189
196
  const explicit = typeof raw === 'string' ? { roleLabel: raw } : (raw && typeof raw === 'object' ? raw : {});
190
197
  const roleLabel = String(explicit.roleLabel || explicit.role || input.holderRole || input.sessionRole || '').trim();
@@ -193,6 +200,9 @@ function groundHolderBinding(input, handoff, findings) {
193
200
  const recipientRoleKind = normalizeToken(handoff.toKind || (recipientRoleLabel ? 'role' : ''));
194
201
  const roleRecipient = recipientRoleKind === 'role';
195
202
  const explicitlySupplied = Boolean(roleLabel || holderId);
203
+ const sourceDetail = holderBindingSourceDetail(input, explicit, explicitlySupplied);
204
+ const authorization = projectHolderBindingAuthorization(role);
205
+ const durableIdentity = holderDurableIdentityProjection(holderId);
196
206
 
197
207
  if (!roleRecipient) return deepFreeze({
198
208
  state: 'not-applicable',
@@ -201,6 +211,9 @@ function groundHolderBinding(input, handoff, findings) {
201
211
  recipientRoleLabel,
202
212
  recipientCompatibility: 'not-applicable',
203
213
  source: explicitlySupplied ? 'explicit-input' : 'none',
214
+ sourceDetail,
215
+ authorization,
216
+ durableIdentity,
204
217
  explicit: explicitlySupplied,
205
218
  inferredFromTransport: false,
206
219
  boundary: 'The selected Handoff recipient is not a Role endpoint, so no consuming-session Role holder binding is required or inferred.'
@@ -215,6 +228,9 @@ function groundHolderBinding(input, handoff, findings) {
215
228
  recipientRoleLabel,
216
229
  recipientCompatibility: 'unresolved',
217
230
  source: explicitlySupplied ? 'explicit-input' : 'none',
231
+ sourceDetail,
232
+ authorization,
233
+ durableIdentity,
218
234
  explicit: explicitlySupplied,
219
235
  inferredFromTransport: false,
220
236
  boundary: 'Recipient Role and consuming-session holder are separate. No holder Role is inferred from route selection, transport identity, provider identity, assistant/user position, or participant declarations.'
@@ -230,6 +246,9 @@ function groundHolderBinding(input, handoff, findings) {
230
246
  recipientRoleLabel,
231
247
  recipientCompatibility: 'mismatch',
232
248
  source: 'explicit-input',
249
+ sourceDetail,
250
+ authorization,
251
+ durableIdentity,
233
252
  explicit: true,
234
253
  inferredFromTransport: false,
235
254
  boundary: 'An explicit holder Role mismatch is contradictory and blocks act-ready grounding. Tooling does not relabel the session to make the route fit.'
@@ -243,12 +262,52 @@ function groundHolderBinding(input, handoff, findings) {
243
262
  recipientRoleLabel,
244
263
  recipientCompatibility: 'matched',
245
264
  source: 'explicit-input',
265
+ sourceDetail,
266
+ authorization,
267
+ durableIdentity,
246
268
  explicit: true,
247
269
  inferredFromTransport: false,
248
270
  boundary: 'Explicit consuming-session Role-capacity binding only. This binds the current Tooling invocation/session to the selected recipient Role capacity; it does not prove a human identity, consent, or authority beyond the qualified Handoff/Role/Task boundaries.'
249
271
  });
250
272
  }
251
273
 
274
+ function holderDurableIdentityProjection(holderId = '') {
275
+ return deepFreeze({
276
+ state: 'not-established',
277
+ declaredHolderId: String(holderId || ''),
278
+ boundary: 'A bounded session Role assertion and its assignment authorization do not establish durable Party/person/model holder identity. Exact holder/Party authority would be required separately.'
279
+ });
280
+ }
281
+
282
+ function holderBindingSourceDetail(input = {}, explicit = {}, explicitlySupplied = false) {
283
+ if (!explicitlySupplied) return deepFreeze({
284
+ kind: 'none',
285
+ locator: '',
286
+ authorityClass: 'none',
287
+ semanticAuthorityState: 'not-established',
288
+ qualifiedMaterialSource: false,
289
+ boundary: 'No consuming-session holder declaration was supplied.'
290
+ });
291
+ const declaredLocator = String(explicit.sourceLocator || explicit.source || '').trim();
292
+ let locator = declaredLocator;
293
+ if (!locator) {
294
+ if (input.holderBinding) locator = 'input.holderBinding';
295
+ else if (input.sessionHolderBinding) locator = 'input.sessionHolderBinding';
296
+ else if (input.sessionRoleBinding) locator = 'input.sessionRoleBinding';
297
+ else if (input.holderRole || input.holderId) locator = 'input.holderRole/input.holderId';
298
+ else if (input.sessionRole) locator = 'input.sessionRole';
299
+ else locator = 'explicit-session-input';
300
+ }
301
+ return deepFreeze({
302
+ kind: 'operator-session-input',
303
+ locator,
304
+ authorityClass: 'session-binding-input-only',
305
+ semanticAuthorityState: 'not-established',
306
+ qualifiedMaterialSource: false,
307
+ boundary: 'This source proves only the explicit consuming-session Role-capacity declaration supplied to Tooling. It is not semantic holder-assignment authority carried by qualified material.'
308
+ });
309
+ }
310
+
252
311
  function groundParticipation(input, handoff, bundle, orientation, selectedRoute, findings, materialContext) {
253
312
  const explicitParticipants = normalizeParticipants(input.participants || input.interaction?.participants || []);
254
313
  const packageRoleGrounding = resolvePackageParticipantRoles(bundle, orientation, selectedRoute, findings);
@@ -160,6 +160,7 @@ export function parseRoleMaterial(entry) {
160
160
  const roleSection = sectionText(parsed.body?.text || '', 'Role Identity');
161
161
  const boundarySection = sectionText(parsed.body?.text || '', 'Role Boundary');
162
162
  const authoritySection = sectionText(parsed.body?.text || '', 'Authority And Responsibility Boundary');
163
+ const holderSection = sectionText(parsed.body?.text || '', 'Holder Relationship');
163
164
  const limitsSection = sectionText(parsed.body?.text || '', 'Interpretation Limits');
164
165
  const label = sectionField(roleSection, 'Role Label');
165
166
  return deepFreeze({
@@ -172,6 +173,13 @@ export function parseRoleMaterial(entry) {
172
173
  roleKind: sectionField(roleSection, 'Role Kind'),
173
174
  boundary: Object.freeze({ inScope: sectionField(boundarySection, 'In Scope'), outOfScope: sectionField(boundarySection, 'Out Of Scope'), context: sectionField(boundarySection, 'Context') }),
174
175
  authorityBoundary: Object.freeze({ mayDo: sectionField(authoritySection, 'May Do'), doesNotAuthorize: sectionField(authoritySection, 'Does Not Authorize'), reviewBoundary: sectionField(authoritySection, 'Review Boundary') }),
176
+ holderRelationship: Object.freeze({
177
+ holderState: sectionField(holderSection, 'Holder State'),
178
+ currentHolder: sectionField(holderSection, 'Current Holder'),
179
+ possibleHolder: sectionField(holderSection, 'Possible Holder'),
180
+ unknownHolder: sectionField(holderSection, 'Unknown Holder'),
181
+ relationArtifact: sectionReferenceTarget(holderSection, 'Relation Artifact')
182
+ }),
175
183
  interpretationLimits: Object.freeze({ doesNotProve: sectionField(limitsSection, 'Does Not Prove'), mustNotBeTreatedAs: sectionField(limitsSection, 'Must Not Be Treated As') }),
176
184
  parentTrace: String(parsed.envelope?.parent?.trace || ''),
177
185
  parentSchemaId: String(parsed.envelope?.parent?.schema?.id || '')
@@ -32,14 +32,16 @@ export function qualifyDelegationReturnReservation(input = {}) {
32
32
  });
33
33
  }
34
34
 
35
+ const rawSupplied = rawIndex !== undefined && rawIndex !== null && String(rawIndex).trim() !== '';
35
36
  const siblingIndex = parseSiblingIndex(rawIndex);
36
- if (siblingIndex === null) findings.push(finding('error', 'portable.delegation-return-reservation.sibling-index.required', 'A return Handoff is transport-not-ready until the delegator supplies one explicit non-Major return package sibling index in the supported range 1..9999.'));
37
+ if (rawSupplied && siblingIndex === null) findings.push(finding('error', 'portable.delegation-return-reservation.sibling-index.invalid', 'Explicit return package sibling override must be an integer in the supported range 1..9999.'));
37
38
  return freeze({
38
39
  schema: PORTABLE_DELEGATION_RETURN_RESERVATION_SCHEMA_ID,
39
40
  state: findings.length ? 'blocked' : 'qualified',
40
41
  returnExpected: true,
41
42
  carrierKind: 'non-major',
42
43
  siblingIndex,
44
+ allocationMode: siblingIndex === null ? 'derive-from-qualified-recipient-selected-pointer' : 'explicit-advanced-override',
43
45
  findings,
44
46
  boundary: boundary()
45
47
  });
@@ -95,7 +97,7 @@ function field(section = '', name = '') {
95
97
  const match = String(section || '').match(new RegExp(`^\\s*-\\s+${escapeRegExp(name)}\\s*:\\s*(.+?)\\s*$`, 'mi'));
96
98
  return String(match?.[1] || '').trim();
97
99
  }
98
- function boundary() { return 'Transport preflight only. It validates an explicit delegator-coordinated return reservation and never allocates, discovers, increments, guesses, recycles, or promotes a sibling index into semantic Parent, Workspace, Role, acceptance, or completion authority.'; }
100
+ function boundary() { return 'Transport preflight only. Ordinary non-Major return allocation is derived later from the exact qualified selected parent Handoff Pointer ordinal; an explicit return sibling index is an advanced compatibility override only. This projection never promotes transport allocation into semantic Parent, Workspace, Role, acceptance, completion, participant, process, or source authority.'; }
99
101
  function finding(severity, code, message) { return Object.freeze({ severity, code, message }); }
100
102
  function escapeRegExp(value = '') { return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
101
103
  function freeze(value) { if (Array.isArray(value)) return Object.freeze(value.map(freeze)); if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value; return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, freeze(item)]))); }
@@ -77,6 +77,7 @@ export function manufactureRecipientRelativeHandoffPackage(input = {}, options =
77
77
  roundtrip: upgraded.roundtrip || null,
78
78
  toolingBootstrap: input.toolingBootstrap || null,
79
79
  manufacturingEvidence: input.manufacturingEvidence || null,
80
+ carrierAllocation: input.carrierAllocation || input.manufacturingEvidence?.carrierAllocation || null,
80
81
  schemaReferencePreflight,
81
82
  returnCarrierReservationPreflight,
82
83
  reconciliationProofQualification,
@@ -5,6 +5,7 @@ export function projectRecipientV2Routes(routePointers = [], endpointPointers =
5
5
  const qualified = (qualifiedRoutes || []).find((route) => String(route.workspaceId || '') === String(item.facts?.workspaceId || '') && String(route.workspaceRelativePath || '') === String(item.facts?.workspaceRelativeHandoffPath || '')) || null;
6
6
  return Object.freeze({
7
7
  pointerPath: item.path,
8
+ routeId: String(item.facts?.routeId || qualified?.id || ''),
8
9
  workspaceId: String(item.facts?.workspaceId || ''),
9
10
  workspaceRelativeHandoffPath: String(item.facts?.workspaceRelativeHandoffPath || ''),
10
11
  returnCarrierReservation: item.facts?.returnCarrierReservation || qualified?.returnCarrierReservation || null,
@@ -17,6 +18,7 @@ export function projectRecipientV2Routes(routePointers = [], endpointPointers =
17
18
  export function projectRecipientV2EndpointRoles(pointers = []) {
18
19
  return Object.freeze(pointers.map((item) => Object.freeze({
19
20
  pointerPath: item.path,
21
+ routeId: String(item.facts?.routeId || qualified?.id || ''),
20
22
  workspaceId: String(item.facts?.workspaceId || ''),
21
23
  routeId: String(item.facts?.routeId || ''),
22
24
  requirementId: String(item.facts?.endpointRequirementId || ''),
@@ -36,6 +38,7 @@ export function projectRecipientV2EndpointRoles(pointers = []) {
36
38
  export function projectRecipientV2ParticipantRoles(pointers = []) {
37
39
  return Object.freeze(pointers.map((item) => Object.freeze({
38
40
  pointerPath: item.path,
41
+ routeId: String(item.facts?.routeId || qualified?.id || ''),
39
42
  workspaceId: String(item.facts?.workspaceId || ''),
40
43
  routeId: String(item.facts?.routeId || ''),
41
44
  roleLabelHint: String(item.facts?.roleLabelHint || ''),
@@ -256,7 +256,7 @@ export function inspectRecipientFacingV2PackageV1(bundle = {}, options = {}) {
256
256
  return deepFreeze({
257
257
  schema: 'tiinex.portable.recipient-facing-handoff-package-v1.inspection.v1', detected: Boolean(packageFile), status, format: RECIPIENT_V2_PACKAGE_V1_FORMAT_ID,
258
258
  rootArtifact: packageFile ? Object.freeze({ path: packageFile.path, schemaId: RECIPIENT_V2_PACKAGE_V1_SCHEMA_ID, sha256: sha256Hex(packageFileBytes(packageFile)), carrierLineage: lineage }) : null,
259
- readArtifact, workspaces: Object.freeze(workspaceParts.map((item) => Object.freeze({ workspaceId: item.workspaceId, coverage: String(item.representation?.coverage || item.facts?.coverage || 'complete'), bindingState: item.bindingState || String(item.representation?.bindingState || 'verified'), workspaceArtifactPath: item.artifact.path, workspaceArchivePath: item.archiveFile?.path || '', sourceWorkspaceTargetInnerPath: item.facts.sourceWorkspaceTargetInnerPath, sourceWorkspaceTargetSha256: item.facts.sourceWorkspaceTargetSha256 }))), sealedWorkspaces: Object.freeze(sealedWorkspaceBindings),
259
+ readArtifact, workspaces: Object.freeze(workspaceParts.map((item) => Object.freeze({ workspaceId: item.workspaceId, coverage: String(item.representation?.coverage || item.facts?.coverage || 'complete'), bindingState: item.bindingState || String(item.representation?.bindingState || 'verified'), workspaceArtifactPath: item.artifact.path, workspaceRepresentationArtifactPath: String(item.representationArtifact?.path || ''), workspacePayloadArtifactPath: String(item.payloadArtifact?.path || item.protectedPayloadArtifact?.path || ''), workspaceArchivePath: item.archiveFile?.path || '', sourceWorkspaceTargetInnerPath: item.facts.sourceWorkspaceTargetInnerPath, sourceWorkspaceTargetSha256: item.facts.sourceWorkspaceTargetSha256 }))), sealedWorkspaces: Object.freeze(sealedWorkspaceBindings),
260
260
  routes: projectRecipientV2Routes(routePointers, endpointRolePointers, participantRolePointers, carrierProjection?.routes || []), endpointRoles: projectRecipientV2EndpointRoles(endpointRolePointers), participantRoles: projectRecipientV2ParticipantRoles(participantRolePointers),
261
261
  caches: Object.freeze(caches.map((cache) => Object.freeze({ workspaceId: String(cache.facts?.workspaceId || ''), artifactPath: cache.artifact.path, archivePath: cache.file.path, materials: cache.facts.materials || [] }))),
262
262
  bootstrapInspection, transportManifest: null, artifactFacts: Object.freeze(generatedArtifacts.map((item) => Object.freeze({ path: item.path, facts: item.facts }))), descriptor, workspaceByteProvider, carrierProjection, coldConsumerProjection,