@tiinex/core 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package.json +8 -6
  2. package/src/schemas/creation.contracts.js +1 -1
  3. package/src/schemas/party/role/tiinex.party.role.v1.schema.js +5 -0
  4. package/src/schemas/party/role/tiinex.party.role.v1.schema.json +2 -2
  5. package/src/schemas/party/role/tiinex.party.role.v1.schema.md +313 -0
  6. package/src/schemas/party/role/tiinex.party.role.v1.schema.runtime.json +18 -6
  7. package/src/schemas/party/role/tiinex.party.role.v1.validate.js +36 -0
  8. package/src/schemas/schema.reference.js +29 -0
  9. package/src/tooling/portable/adapters/cli/cli.command-input.js +8 -1
  10. package/src/tooling/portable/adapters/cli/cli.common-author.js +117 -6
  11. package/src/tooling/portable/adapters/cli/cli.common-output.js +26 -0
  12. package/src/tooling/portable/adapters/cli/cli.handoff-manufacture.js +33 -17
  13. package/src/tooling/portable/adapters/cli/cli.handoff-sibling-allocation.js +139 -2
  14. package/src/tooling/portable/adapters/cli/cli.help.js +1 -1
  15. package/src/tooling/portable/adapters/node/handoff.manufacture.js +30 -5
  16. package/src/tooling/portable/adapters/node/handoff.manufacture.packageParent.js +123 -0
  17. package/src/tooling/portable/audit/audit.capability.js +10 -4
  18. package/src/tooling/portable/grounding/grounding.capsule.js +33 -2
  19. package/src/tooling/portable/grounding/grounding.delegationArtifactAuthority.js +220 -0
  20. package/src/tooling/portable/grounding/grounding.delegationReadiness.js +241 -0
  21. package/src/tooling/portable/grounding/grounding.holderAssignmentModes.js +125 -0
  22. package/src/tooling/portable/grounding/grounding.holderBindingAuthorization.js +80 -0
  23. package/src/tooling/portable/grounding/grounding.implementationSourceAuthority.js +109 -0
  24. package/src/tooling/portable/grounding/grounding.participantAuthority.js +1 -1
  25. package/src/tooling/portable/grounding/grounding.readiness.authority.js +15 -0
  26. package/src/tooling/portable/grounding/grounding.readiness.js +86 -13
  27. package/src/tooling/portable/grounding/grounding.readiness.support.js +2 -2
  28. package/src/tooling/portable/handoff/carrierProjection.routeQualification.js +20 -4
  29. package/src/tooling/portable/handoff/coldStartQualification.grounding.js +116 -5
  30. package/src/tooling/portable/handoff/coldStartQualification.materials.js +92 -10
  31. package/src/tooling/portable/handoff/delegationReturnReservation.js +4 -2
  32. package/src/tooling/portable/handoff/manufacture.js +1 -0
  33. package/src/tooling/portable/handoff/recipientV2.endpointRolePointers.js +1 -1
  34. package/src/tooling/portable/handoff/recipientV2.inspect.projection.js +7 -1
  35. package/src/tooling/portable/handoff/recipientV2.packageV1.build.js +2 -2
  36. package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +1 -1
  37. package/src/tooling/portable/handoff/recipientV2.topology.js +5 -3
  38. package/src/tooling/portable/handoff/recipientV2.topology.materials.js +0 -0
@@ -41,6 +41,7 @@ export function projectPortableGroundingReadiness(input = {}, options = {}) {
41
41
  route,
42
42
  toolingAvailable: true
43
43
  }, { ...options, coldStartMaterialContext: materialContext });
44
+ const authority = withExplicitGroundingAuthorityInputs(grounding, input);
44
45
  const continuation = projectGroundedContinuation({
45
46
  bundle,
46
47
  route,
@@ -62,7 +63,7 @@ export function projectPortableGroundingReadiness(input = {}, options = {}) {
62
63
  });
63
64
  return composeGroundingReadiness({
64
65
  mode: 'routed-handoff-package',
65
- authority: grounding,
66
+ authority,
66
67
  continuation,
67
68
  contextAudit,
68
69
  material,
@@ -113,6 +114,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
113
114
  const route = authority?.selectedRoute || null;
114
115
  const roleState = String(authority?.role?.state || 'unresolved');
115
116
  const holderState = String(authority?.holderBinding?.state || 'unresolved');
117
+ const holderAuthorizationState = String(authority?.holderBinding?.authorization?.state || (holderState === 'not-applicable' ? 'not-applicable' : 'unresolved'));
116
118
  if (!route || String(authority?.status || '') === 'blocked') missing(missingEvidence, unresolved, 'authority-route-unqualified', 'The selected Handoff route is not qualified for this grounding result.');
117
119
  else known.push(evidence('qualified-handoff-route', 'qualified', route.id || route.pointerPath || 'selected-route'));
118
120
  if (roleState === 'qualified' || roleState === 'not-applicable') known.push(evidence('recipient-role-boundary', roleState, authority?.role?.endpoint?.label || 'recipient'));
@@ -120,7 +122,6 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
120
122
  else missing(missingEvidence, unresolved, 'recipient-role-unresolved', 'The Handoff recipient Role boundary is not qualified for act-ready grounding.');
121
123
 
122
124
  if (holderState === 'qualified' || holderState === 'not-applicable') {
123
- holderBindingActReady = true;
124
125
  known.push(evidence('session-holder-role-binding', holderState, authority?.holderBinding?.roleLabel || authority?.role?.endpoint?.label || 'recipient'));
125
126
  } else if (holderState === 'blocked') {
126
127
  holderBindingActReady = false;
@@ -131,13 +132,28 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
131
132
  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
133
  }
133
134
 
135
+ if (holderState === 'not-applicable') {
136
+ holderBindingActReady = true;
137
+ known.push(evidence('session-holder-role-binding-authorization', 'not-applicable', 'selected Handoff recipient is not a Role endpoint'));
138
+ } else if (holderState === 'qualified') {
139
+ if (holderAuthorizationState === 'qualified') {
140
+ holderBindingActReady = true;
141
+ known.push(evidence('session-holder-role-binding-authorization', 'qualified', authority?.holderBinding?.authorization?.provenance?.roleArtifactPath || authority?.role?.endpoint?.label || 'recipient Role material'));
142
+ } else {
143
+ holderBindingActReady = false;
144
+ unresolved.push(evidence('session-holder-role-binding-authorization', holderAuthorizationState || 'unresolved', authority?.holderBinding?.authorization?.reasonCode || 'exact qualified canonical assignment-mode authority does not authorize the asserted binding mechanism'));
145
+ reasons.push(reason('session-holder-role-binding-authorization-unresolved', 'The explicit consuming-session Role assertion matches the selected recipient Role, but exact qualified canonical assignment-mode authority does not authorize the asserted mechanism. Matching session input alone cannot make the route act-ready.'));
146
+ }
147
+ }
148
+
134
149
  const required = Array.isArray(requiredContext) ? requiredContext : [];
135
150
  const unresolvedRequired = required.filter((entry) => entry.state !== 'qualified');
136
151
  if (unresolvedRequired.length) missing(missingEvidence, unresolved, 'required-context-unqualified', `${unresolvedRequired.length} declared Required Context item(s) are not exact-qualified.`);
137
152
  else known.push(evidence('required-context-closure', 'qualified', `${required.length} item(s)`));
138
153
  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)`));
154
+ const workspaceCoverage = projectWorkspaceActionCoverage(contextAudit);
155
+ if (!workspaceCoverage.qualified) missing(missingEvidence, unresolved, 'workspace-snapshot-coverage-unqualified', workspaceCoverage.message);
156
+ else known.push(evidence('workspace-snapshot-coverage', 'qualified', `${workspaceCoverage.count} workspace representation(s): ${workspaceCoverage.completeCount} complete, ${workspaceCoverage.boundedCount} bounded`));
141
157
  for (const item of requiredRecordResolution.missing) missing(missingEvidence, unresolved, 'required-context-not-in-snapshot', item);
142
158
  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
159
  } else {
@@ -148,7 +164,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
148
164
  if (!records.length) missing(missingEvidence, unresolved, 'no-artifact-records', 'No readable Tiinex artifact records were loaded for grounding.');
149
165
  else known.push(evidence('loaded-artifact-records', 'known', `${records.length} record(s)`));
150
166
 
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'));
167
+ 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
168
  inferred.push(evidence('lineage-leaf-role', 'bounded-inference', 'derived only from declared Parent edges in the shared resolver'));
153
169
 
154
170
  if (handoffMode) {
@@ -157,7 +173,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
157
173
  } else if (topology.routeLeaves.length) {
158
174
  known.push(evidence('selected-route-parent-lineage-leaf', 'resolved', `${topology.routeLeaves.length} selected-route leaf/leaves`));
159
175
  } 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.');
176
+ 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
177
  }
162
178
  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
179
  } else if (lineageIssues.length) {
@@ -190,7 +206,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
190
206
  let state = 'grounded-to-act';
191
207
  if (missingEvidence.length) state = 'insufficient-grounding';
192
208
  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.'));
209
+ 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
210
  const orchestrationReadiness = projectGroundingOrchestrationReadiness({ readinessState: state, participantContext: capsule.participantContext, processApplicability: capsule.processApplicability, sourceEvidence: capsule.sourceEvidence, topology });
195
211
 
196
212
  return Object.freeze({
@@ -218,11 +234,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
218
234
  requestedSelectors: requiredContextProjection.requestedSelectors,
219
235
  unmatchedSelectors: requiredContextProjection.unmatchedSelectors
220
236
  }),
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 })
237
+ 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
238
  }),
227
239
  lineage: Object.freeze({
228
240
  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'),
@@ -243,6 +255,7 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
243
255
  }),
244
256
  continuity,
245
257
  orchestrationReadiness,
258
+ delegationReadiness: capsule.delegationReadiness,
246
259
  capsule,
247
260
  currentWork: Object.freeze({
248
261
  state: topology.currentFrontier.length ? 'current-frontier-resolved' : topology.currentTasks.length ? 'current-candidates-without-frontier' : 'unresolved',
@@ -277,6 +290,61 @@ export function composeGroundingReadiness({ mode = 'loaded-material', authority
277
290
  });
278
291
  }
279
292
 
293
+
294
+ function withExplicitGroundingAuthorityInputs(grounding = {}, input = {}) {
295
+ const context = input.delegationContext && typeof input.delegationContext === 'object' ? input.delegationContext : {};
296
+ const selected = {
297
+ delegateCapabilityAuthority: input.delegateCapabilityAuthority || context.delegateCapabilityAuthority || null,
298
+ processApplicability: input.processApplicability || context.processApplicability || null,
299
+ delegationTargetAuthority: input.delegationTargetAuthority || context.delegationTargetAuthority || context.targetAuthority || null,
300
+ implementationSourceAuthority: input.implementationSourceAuthority || context.implementationSourceAuthority || context.sourceAuthority || null,
301
+ delegationReturnReconciliationExpectation: input.delegationReturnReconciliationExpectation || context.delegationReturnReconciliationExpectation || context.returnReconciliationExpectation || null
302
+ };
303
+ const additions = Object.fromEntries(Object.entries(selected).filter(([, value]) => value && typeof value === 'object'));
304
+ return Object.freeze({ ...(grounding || {}), ...additions, ...(Object.keys(context).length ? { delegationContext: Object.freeze({ ...context }) } : {}) });
305
+ }
306
+
307
+ function projectWorkspaceActionCoverage(contextAudit = {}) {
308
+ const workspaces = Array.isArray(contextAudit?.workspaceMaterializations) ? contextAudit.workspaceMaterializations : [];
309
+ const summaries = workspaces.map((workspace) => {
310
+ const coverage = workspaceCoverageState(workspace);
311
+ const qualification = String(workspace?.qualification || '').trim().toLowerCase();
312
+ const qualified = ['complete', 'bounded'].includes(coverage) && qualification === 'qualified';
313
+ return Object.freeze({ workspaceId: String(workspace?.workspaceId || ''), coverage, qualification: qualification || 'unresolved', qualified });
314
+ });
315
+ const aggregateReady = String(contextAudit?.status || '') === 'ready' && String(contextAudit?.coverage?.state || '') === 'qualified';
316
+ const qualified = aggregateReady && summaries.length > 0 && summaries.every((item) => item.qualified);
317
+ const completeCount = summaries.filter((item) => item.coverage === 'complete').length;
318
+ const boundedCount = summaries.filter((item) => item.coverage === 'bounded').length;
319
+ const unqualified = summaries.filter((item) => !item.qualified);
320
+ const message = qualified
321
+ ? `Qualified carried Workspace coverage is established for ${summaries.length} representation(s): ${completeCount} complete, ${boundedCount} bounded.`
322
+ : !aggregateReady
323
+ ? 'Carried Workspace context audit is not qualified for bounded action readiness.'
324
+ : !summaries.length
325
+ ? 'No qualified carried Workspace representation is available for the selected Handoff route.'
326
+ : `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.`;
327
+ return Object.freeze({
328
+ state: qualified ? 'qualified' : 'unqualified',
329
+ qualified,
330
+ count: summaries.length,
331
+ completeCount,
332
+ boundedCount,
333
+ unqualified: Object.freeze(unqualified),
334
+ message,
335
+ 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.'
336
+ });
337
+ }
338
+
339
+ function workspaceCoverageState(workspace = {}) {
340
+ const explicit = String(workspace?.coverage || workspace?.materialization || '').trim().toLowerCase();
341
+ if (explicit === 'complete' || explicit === 'bounded') return explicit;
342
+ const reason = String(workspace?.reason || '').trim().toLowerCase();
343
+ if (reason.includes('bounded') || reason.includes('partial')) return 'bounded';
344
+ if (reason.includes('complete')) return 'complete';
345
+ return 'unresolved';
346
+ }
347
+
280
348
  function projectCurrentWork(topology = {}, records = [], includeCurrentWork = false) {
281
349
  const recordById = new Map((records || []).map((record) => [String(record.id || ''), record]));
282
350
  const frontier = (topology.currentFrontier || []).slice(0, MAX_ITEMS).map((item) => {
@@ -300,8 +368,13 @@ function projectCurrentWork(topology = {}, records = [], includeCurrentWork = fa
300
368
  }
301
369
 
302
370
  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' });
371
+ 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
372
  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' });
373
+ if (state === 'grounded-to-discuss' && String(authority?.holderBinding?.state || '') === 'qualified' && String(authority?.holderBinding?.authorization?.state || 'unresolved') !== 'qualified') return Object.freeze({
374
+ kind: 'resolve-session-holder-binding-authorization',
375
+ target: authority?.holderBinding?.authorization?.provenance?.roleArtifactPath || authority?.role?.endpoint?.label || authority?.handoff?.to || '',
376
+ basis: 'a matching explicit session Role assertion is not semantic authorization; exact qualified recipient Role Holder Relationship authority must establish the assignment mode'
377
+ });
305
378
  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
379
  if (continuity?.state === 'unproven') return Object.freeze({
307
380
  kind: continuity.recovery?.state === 'host-action-available' ? 'recover-required-parent-with-host-action' : 'request-exact-required-parent-material',
@@ -168,13 +168,13 @@ 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
  }
175
175
 
176
176
  function isExactHydratedWorkspaceContext(entry = {}) {
177
- if (String(entry.providerMode || '') !== 'archive') return false;
177
+ if (!['archive', 'cache'].includes(String(entry.providerMode || ''))) return false;
178
178
  if (!['hydrated-text', 'qualified-locator-only'].includes(String(entry.contentState || ''))) return false;
179
179
  const expectedBytes = Number(entry.bytes || 0);
180
180
  const actualBytes = Number(entry.actualBytes || 0);
@@ -71,8 +71,22 @@ function qualifyRequiredRequirement(bundle, descriptor, byteProvider, workspace,
71
71
  let resolution=null;
72
72
  if (!target||target.startsWith('#')) { resolution=resolveDescriptorMaterial(bundle,descriptor,byteProvider,target,requirementId,workspace.id,routePath); if(!resolution) reasons.push('exact-required-material-reference-or-binding-unresolved'); }
73
73
  const qualified=parseWorkspaceQualifiedReference(target);
74
- if (!resolution&&!reasons.length&&qualified) resolution=resolveWorkspaceRequiredMaterial(byteProvider,{id:qualified.workspaceId},qualified.path);
75
- if (!resolution&&!reasons.length&&!qualified&&!isExternalReference(target)) { const resolvedPath=resolveWorkspaceReference(routePath,target); if(!resolvedPath) reasons.push('workspace-reference-outside-or-invalid'); else resolution=resolveWorkspaceRequiredMaterial(byteProvider,workspace,resolvedPath); }
74
+ if (!resolution&&!reasons.length&&qualified) {
75
+ const workspaceResolution=resolveWorkspaceRequiredMaterial(byteProvider,{id:qualified.workspaceId},qualified.path);
76
+ resolution=workspaceResolution.state==='qualified'
77
+ ? workspaceResolution
78
+ : (resolveDescriptorMaterial(bundle,descriptor,byteProvider,target,requirementId,workspace.id,routePath)||workspaceResolution);
79
+ }
80
+ if (!resolution&&!reasons.length&&!qualified&&!isExternalReference(target)) {
81
+ const resolvedPath=resolveWorkspaceReference(routePath,target);
82
+ if(!resolvedPath) reasons.push('workspace-reference-outside-or-invalid');
83
+ else {
84
+ const workspaceResolution=resolveWorkspaceRequiredMaterial(byteProvider,workspace,resolvedPath);
85
+ resolution=workspaceResolution.state==='qualified'
86
+ ? workspaceResolution
87
+ : (resolveDescriptorMaterial(bundle,descriptor,byteProvider,target,requirementId,workspace.id,routePath)||workspaceResolution);
88
+ }
89
+ }
76
90
  if (!resolution&&!reasons.length) resolution=resolveDescriptorMaterial(bundle,descriptor,byteProvider,target,requirementId,workspace.id,routePath);
77
91
  if (!resolution&&!reasons.length) reasons.push('required-material-not-carried');
78
92
  if (resolution?.state!=='qualified'&&resolution?.reason) reasons.push(resolution.reason);
@@ -190,8 +204,10 @@ function resolveRouteParent(bundle, descriptor, byteProvider, workspace, routePa
190
204
  if (!markdown) continue;
191
205
  const self = validatedC14nV2PrimarySelfDigest(markdown);
192
206
  if (self.state !== 'verified' || self.value !== digest) continue;
193
- const key = `${candidate.workspaceId || ''}\u0000${candidate.workspaceRelativePath || ''}\u0000${candidate.packagePath || ''}`;
194
- digestMatches.set(key, Object.freeze({ state: 'qualified', markdown, basis: 'parent-target-digest-candidate', workspaceRelativePath: normalizeWorkspacePath(candidate.workspaceRelativePath || ''), packagePath: String(candidate.packagePath || ''), sha256: sha256Hex(data) }));
207
+ const candidatePath = normalizeWorkspacePath(candidate.workspaceRelativePath || '');
208
+ const candidateSha256 = sha256Hex(data);
209
+ const key = `${candidate.workspaceId || ''}\u0000${candidatePath}\u0000${candidateSha256}`;
210
+ if (!digestMatches.has(key)) digestMatches.set(key, Object.freeze({ state: 'qualified', markdown, basis: 'parent-target-digest-candidate', workspaceRelativePath: candidatePath, packagePath: String(candidate.packagePath || ''), sha256: candidateSha256 }));
195
211
  }
196
212
  if (digestMatches.size === 1) return [...digestMatches.values()][0];
197
213
  if (digestMatches.size > 1) return Object.freeze({ state: 'ambiguous', reason: 'multiple-parent-target-digest-candidates' });
@@ -19,6 +19,7 @@ import {
19
19
  resolveGroundingRouteMarkdown,
20
20
  recipientFactsIndexForColdStart,
21
21
  resolveReferencedRoleMaterial,
22
+ resolveReferencedEndpointRoleMaterial,
22
23
  selectGroundingRoute
23
24
  } from './coldStartQualification.materials.js';
24
25
  import {
@@ -31,6 +32,7 @@ import {
31
32
  normalizeStringList,
32
33
  normalizeToken
33
34
  } from './coldStartQualification.shared.js';
35
+ import { projectHolderBindingAuthorization } from '../grounding/grounding.holderBindingAuthorization.js';
34
36
 
35
37
  export function groundPortableColdConsumer(input = {}, options = {}) {
36
38
  const ingressKind = normalizeIngressKind(input.ingressKind || input.kind || (input.toolingAvailable === false ? COLD_START_INGRESS_KINDS.DEGRADED_CAPTURE : COLD_START_INGRESS_KINDS.HANDOFF));
@@ -59,7 +61,8 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
59
61
 
60
62
  const bundle = input.bundle || input.package || input;
61
63
  const role = groundRecipientRole(input, handoff, bundle, orientation, selectedRoute, findings, materialContext);
62
- const holderBinding = groundHolderBinding(input, handoff, findings);
64
+ const senderRole = groundSenderRole(handoff, bundle, orientation, selectedRoute, materialContext);
65
+ const holderBinding = groundHolderBinding(input, handoff, role, findings);
63
66
  const participation = groundParticipation(input, handoff, bundle, orientation, selectedRoute, findings, materialContext);
64
67
  const interaction = groundInteraction(input, handoff);
65
68
 
@@ -68,7 +71,12 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
68
71
  }
69
72
 
70
73
  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';
74
+ const degraded = degradedCapture.active
75
+ || role.state === 'degraded'
76
+ || holderBinding.state === 'unresolved'
77
+ || holderBinding.authorization?.state === 'unresolved'
78
+ || interaction.modeState === 'unresolved'
79
+ || participation.participantState === 'unresolved';
72
80
  return deepFreeze({
73
81
  schema: PORTABLE_COLD_CONSUMER_GROUNDING_SCHEMA_ID,
74
82
  version: 1,
@@ -78,6 +86,7 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
78
86
  selectedRoute,
79
87
  handoff,
80
88
  role,
89
+ senderRole,
81
90
  holderBinding,
82
91
  participation,
83
92
  interaction,
@@ -114,6 +123,50 @@ export function groundPortableColdConsumer(input = {}, options = {}) {
114
123
  });
115
124
  }
116
125
 
126
+ function groundSenderRole(handoff, bundle, orientation, selectedRoute, materialContext) {
127
+ const fromKind = normalizeToken(handoff.fromKind);
128
+ if (fromKind && fromKind !== 'role') return deepFreeze({
129
+ state: 'not-applicable',
130
+ endpoint: Object.freeze({ label: handoff.from || '', kind: handoff.fromKind || '', bounded: Boolean(handoff.from) }),
131
+ material: Object.freeze({ state: 'not-required', artifact: null }),
132
+ exactBoundaryLoaded: null,
133
+ authorityBoundaryLoaded: null,
134
+ boundary: 'Sender endpoint is not declared as Role; no sender Role authority is invented.'
135
+ });
136
+ if (!handoff.fromReference) return deepFreeze({
137
+ state: 'unresolved',
138
+ endpoint: Object.freeze({ label: handoff.from || '', kind: handoff.fromKind || (handoff.from ? 'role' : ''), bounded: Boolean(handoff.from) }),
139
+ material: Object.freeze({ state: 'missing-exact-reference', artifact: null }),
140
+ exactBoundaryLoaded: null,
141
+ authorityBoundaryLoaded: null,
142
+ boundary: 'Delegation projection requires an exact Handoff From Reference; Role inventory and endpoint labels are not substituted.'
143
+ });
144
+ const localFindings = [];
145
+ const material = resolveReferencedEndpointRoleMaterial(bundle, handoff, orientation, selectedRoute, localFindings, materialContext, 'from');
146
+ const parsed = material ? parseRoleMaterial(material) : null;
147
+ const target = normalizeComparable(handoff.from || '');
148
+ if (!parsed || (target && normalizeComparable(parsed.label) !== target)) return deepFreeze({
149
+ state: 'unresolved',
150
+ endpoint: Object.freeze({ label: handoff.from || '', kind: handoff.fromKind || (handoff.from ? 'role' : ''), bounded: Boolean(handoff.from) }),
151
+ material: Object.freeze({ state: localFindings.length ? 'unresolved-exact-reference' : 'missing', artifact: null }),
152
+ exactBoundaryLoaded: null,
153
+ authorityBoundaryLoaded: null,
154
+ boundary: 'Exact sender Role material did not qualify; sender authority is not inferred from carried Role inventory.'
155
+ });
156
+ return deepFreeze({
157
+ state: 'qualified',
158
+ endpoint: Object.freeze({ label: handoff.from || parsed.label || '', kind: handoff.fromKind || 'role', bounded: Boolean(handoff.from) }),
159
+ material: Object.freeze({
160
+ state: 'qualified',
161
+ artifact: Object.freeze({ path: parsed.path, sha256: parsed.sha256, schemaId: parsed.schemaId, title: parsed.title, roleLabel: parsed.label, roleKind: parsed.roleKind, reference: handoff.fromReference || '' })
162
+ }),
163
+ exactBoundaryLoaded: parsed.boundary,
164
+ authorityBoundaryLoaded: parsed.authorityBoundary,
165
+ interpretationLimitsLoaded: parsed.interpretationLimits,
166
+ boundary: 'Exact Handoff From Reference Role material only. Sender Role authority remains separate from Handoff transfer and is never inferred from endpoint naming or cache inventory.'
167
+ });
168
+ }
169
+
117
170
  function groundRecipientRole(input, handoff, bundle, orientation, selectedRoute, findings, materialContext) {
118
171
  const toKind = normalizeToken(handoff.toKind);
119
172
  if (toKind && toKind !== 'role') return deepFreeze({
@@ -178,13 +231,14 @@ function groundRecipientRole(input, handoff, bundle, orientation, selectedRoute,
178
231
  compatibility,
179
232
  exactBoundaryLoaded: selected ? selected.boundary : null,
180
233
  authorityBoundaryLoaded: selected ? selected.authorityBoundary : null,
234
+ holderRelationshipLoaded: selected ? selected.holderRelationship : null,
181
235
  interpretationLimitsLoaded: selected ? selected.interpretationLimits : null,
182
236
  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
237
  });
184
238
  }
185
239
 
186
240
 
187
- function groundHolderBinding(input, handoff, findings) {
241
+ function groundHolderBinding(input, handoff, role, findings) {
188
242
  const raw = input.holderBinding || input.sessionHolderBinding || input.sessionRoleBinding || {};
189
243
  const explicit = typeof raw === 'string' ? { roleLabel: raw } : (raw && typeof raw === 'object' ? raw : {});
190
244
  const roleLabel = String(explicit.roleLabel || explicit.role || input.holderRole || input.sessionRole || '').trim();
@@ -193,14 +247,22 @@ function groundHolderBinding(input, handoff, findings) {
193
247
  const recipientRoleKind = normalizeToken(handoff.toKind || (recipientRoleLabel ? 'role' : ''));
194
248
  const roleRecipient = recipientRoleKind === 'role';
195
249
  const explicitlySupplied = Boolean(roleLabel || holderId);
250
+ const sourceDetail = holderBindingSourceDetail(input, explicit, explicitlySupplied);
251
+ const assertionMode = String(explicit.assignmentMode || explicit.bindingMode || explicit.mechanism || input.holderAssignmentMode || input.sessionAssignmentMode || 'explicit-session').trim();
252
+ const authorization = projectHolderBindingAuthorization(role, { assertionMode });
253
+ const durableIdentity = holderDurableIdentityProjection(holderId);
196
254
 
197
255
  if (!roleRecipient) return deepFreeze({
198
256
  state: 'not-applicable',
199
257
  holderId,
258
+ assertionMode,
200
259
  roleLabel,
201
260
  recipientRoleLabel,
202
261
  recipientCompatibility: 'not-applicable',
203
262
  source: explicitlySupplied ? 'explicit-input' : 'none',
263
+ sourceDetail,
264
+ authorization,
265
+ durableIdentity,
204
266
  explicit: explicitlySupplied,
205
267
  inferredFromTransport: false,
206
268
  boundary: 'The selected Handoff recipient is not a Role endpoint, so no consuming-session Role holder binding is required or inferred.'
@@ -211,10 +273,14 @@ function groundHolderBinding(input, handoff, findings) {
211
273
  return deepFreeze({
212
274
  state: 'unresolved',
213
275
  holderId,
276
+ assertionMode,
214
277
  roleLabel: '',
215
278
  recipientRoleLabel,
216
279
  recipientCompatibility: 'unresolved',
217
280
  source: explicitlySupplied ? 'explicit-input' : 'none',
281
+ sourceDetail,
282
+ authorization,
283
+ durableIdentity,
218
284
  explicit: explicitlySupplied,
219
285
  inferredFromTransport: false,
220
286
  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.'
@@ -226,10 +292,14 @@ function groundHolderBinding(input, handoff, findings) {
226
292
  return deepFreeze({
227
293
  state: 'blocked',
228
294
  holderId,
295
+ assertionMode,
229
296
  roleLabel,
230
297
  recipientRoleLabel,
231
298
  recipientCompatibility: 'mismatch',
232
299
  source: 'explicit-input',
300
+ sourceDetail,
301
+ authorization,
302
+ durableIdentity,
233
303
  explicit: true,
234
304
  inferredFromTransport: false,
235
305
  boundary: 'An explicit holder Role mismatch is contradictory and blocks act-ready grounding. Tooling does not relabel the session to make the route fit.'
@@ -239,19 +309,60 @@ function groundHolderBinding(input, handoff, findings) {
239
309
  return deepFreeze({
240
310
  state: 'qualified',
241
311
  holderId,
312
+ assertionMode,
242
313
  roleLabel,
243
314
  recipientRoleLabel,
244
315
  recipientCompatibility: 'matched',
245
316
  source: 'explicit-input',
317
+ sourceDetail,
318
+ authorization,
319
+ durableIdentity,
246
320
  explicit: true,
247
321
  inferredFromTransport: false,
248
322
  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
323
  });
250
324
  }
251
325
 
326
+ function holderDurableIdentityProjection(holderId = '') {
327
+ return deepFreeze({
328
+ state: 'not-established',
329
+ declaredHolderId: String(holderId || ''),
330
+ 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.'
331
+ });
332
+ }
333
+
334
+ function holderBindingSourceDetail(input = {}, explicit = {}, explicitlySupplied = false) {
335
+ if (!explicitlySupplied) return deepFreeze({
336
+ kind: 'none',
337
+ locator: '',
338
+ authorityClass: 'none',
339
+ semanticAuthorityState: 'not-established',
340
+ qualifiedMaterialSource: false,
341
+ boundary: 'No consuming-session holder declaration was supplied.'
342
+ });
343
+ const declaredLocator = String(explicit.sourceLocator || explicit.source || '').trim();
344
+ let locator = declaredLocator;
345
+ if (!locator) {
346
+ if (input.holderBinding) locator = 'input.holderBinding';
347
+ else if (input.sessionHolderBinding) locator = 'input.sessionHolderBinding';
348
+ else if (input.sessionRoleBinding) locator = 'input.sessionRoleBinding';
349
+ else if (input.holderRole || input.holderId) locator = 'input.holderRole/input.holderId';
350
+ else if (input.sessionRole) locator = 'input.sessionRole';
351
+ else locator = 'explicit-session-input';
352
+ }
353
+ return deepFreeze({
354
+ kind: 'operator-session-input',
355
+ locator,
356
+ authorityClass: 'session-binding-input-only',
357
+ semanticAuthorityState: 'not-established',
358
+ qualifiedMaterialSource: false,
359
+ 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.'
360
+ });
361
+ }
362
+
252
363
  function groundParticipation(input, handoff, bundle, orientation, selectedRoute, findings, materialContext) {
253
364
  const explicitParticipants = normalizeParticipants(input.participants || input.interaction?.participants || []);
254
- const packageRoleGrounding = resolvePackageParticipantRoles(bundle, orientation, selectedRoute, findings);
365
+ const packageRoleGrounding = resolvePackageParticipantRoles(bundle, orientation, selectedRoute, findings, materialContext);
255
366
  const participants = dedupeGroundedParticipants(explicitParticipants);
256
367
  const contributions = normalizeContributions(input.contributions || input.interaction?.contributions || []);
257
368
  const currentContributionId = String(input.currentContributionId || input.interaction?.currentContributionId || '').trim();
@@ -286,7 +397,7 @@ function resolvePackageParticipantRoles(bundle = {}, orientation = null, selecte
286
397
  const pointerPath = String(pointerPaths[index] || '');
287
398
  const pointerFile = findFile(bundle, pointerPath);
288
399
  if (!pointerFile) { findings.push(portableFinding('error', 'portable.cold-start.participant-role.pointer.missing', 'Selected Handoff route declares Role grounding Pointer ancestry that is not carried.', { pointerPath })); continue; }
289
- const compatibilityFacts = recipientV2FactsIndex(bundle).map.get(pointerPath) || null;
400
+ const compatibilityFacts = recipientFactsIndexForColdStart(bundle, materialContext).map.get(pointerPath) || null;
290
401
  const projectedFacts = (orientation?.participantRoles || []).find((item) => String(item.pointerPath || '') === pointerPath) || null;
291
402
  const facts = compatibilityFacts?.role === 'participant-role'
292
403
  ? compatibilityFacts