@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 +6 -5
- package/src/tooling/portable/adapters/cli/cli.command-input.js +8 -1
- package/src/tooling/portable/adapters/cli/cli.common-output.js +7 -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 +4 -1
- package/src/tooling/portable/grounding/grounding.capsule.js +8 -1
- package/src/tooling/portable/grounding/grounding.holderBindingAuthorization.js +81 -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 +69 -12
- package/src/tooling/portable/grounding/grounding.readiness.support.js +1 -1
- package/src/tooling/portable/handoff/coldStartQualification.grounding.js +62 -3
- package/src/tooling/portable/handoff/coldStartQualification.materials.js +8 -0
- package/src/tooling/portable/handoff/delegationReturnReservation.js +4 -2
- package/src/tooling/portable/handoff/manufacture.js +1 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.projection.js +3 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiinex/core",
|
|
3
|
-
"version": "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": "
|
|
174
|
+
"gitHead": "fe01706aecacbf28c66e2ac052e4f639170dfe73",
|
|
174
175
|
"tiinexRelease": {
|
|
175
176
|
"policy": "tiinex.master-npm-release.v1",
|
|
176
|
-
"sourceCommit": "
|
|
177
|
-
"sourceTree": "
|
|
177
|
+
"sourceCommit": "fe01706aecacbf28c66e2ac052e4f639170dfe73",
|
|
178
|
+
"sourceTree": "b4e5dbb825a1504fef53f1e5281d4bd6fd3c87ff",
|
|
178
179
|
"repository": "Tiinex/core",
|
|
179
|
-
"previousVersion": "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 {
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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,
|