@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.
- package/package.json +8 -6
- package/src/schemas/creation.contracts.js +1 -1
- package/src/schemas/party/role/tiinex.party.role.v1.schema.js +5 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.json +2 -2
- package/src/schemas/party/role/tiinex.party.role.v1.schema.md +313 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.runtime.json +18 -6
- package/src/schemas/party/role/tiinex.party.role.v1.validate.js +36 -0
- package/src/schemas/schema.reference.js +29 -0
- package/src/tooling/portable/adapters/cli/cli.command-input.js +8 -1
- package/src/tooling/portable/adapters/cli/cli.common-author.js +117 -6
- package/src/tooling/portable/adapters/cli/cli.common-output.js +26 -0
- package/src/tooling/portable/adapters/cli/cli.handoff-manufacture.js +33 -17
- package/src/tooling/portable/adapters/cli/cli.handoff-sibling-allocation.js +139 -2
- package/src/tooling/portable/adapters/cli/cli.help.js +1 -1
- package/src/tooling/portable/adapters/node/handoff.manufacture.js +30 -5
- package/src/tooling/portable/adapters/node/handoff.manufacture.packageParent.js +123 -0
- package/src/tooling/portable/audit/audit.capability.js +10 -4
- package/src/tooling/portable/grounding/grounding.capsule.js +33 -2
- package/src/tooling/portable/grounding/grounding.delegationArtifactAuthority.js +220 -0
- package/src/tooling/portable/grounding/grounding.delegationReadiness.js +241 -0
- package/src/tooling/portable/grounding/grounding.holderAssignmentModes.js +125 -0
- package/src/tooling/portable/grounding/grounding.holderBindingAuthorization.js +80 -0
- package/src/tooling/portable/grounding/grounding.implementationSourceAuthority.js +109 -0
- package/src/tooling/portable/grounding/grounding.participantAuthority.js +1 -1
- package/src/tooling/portable/grounding/grounding.readiness.authority.js +15 -0
- package/src/tooling/portable/grounding/grounding.readiness.js +86 -13
- package/src/tooling/portable/grounding/grounding.readiness.support.js +2 -2
- package/src/tooling/portable/handoff/carrierProjection.routeQualification.js +20 -4
- package/src/tooling/portable/handoff/coldStartQualification.grounding.js +116 -5
- package/src/tooling/portable/handoff/coldStartQualification.materials.js +92 -10
- package/src/tooling/portable/handoff/delegationReturnReservation.js +4 -2
- package/src/tooling/portable/handoff/manufacture.js +1 -0
- package/src/tooling/portable/handoff/recipientV2.endpointRolePointers.js +1 -1
- package/src/tooling/portable/handoff/recipientV2.inspect.projection.js +7 -1
- package/src/tooling/portable/handoff/recipientV2.packageV1.build.js +2 -2
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +1 -1
- package/src/tooling/portable/handoff/recipientV2.topology.js +5 -3
- 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
|
|
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
|
-
|
|
140
|
-
|
|
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
|
|
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
|
|
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
|
|
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 || '')
|
|
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)
|
|
75
|
-
|
|
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
|
|
194
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|