@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
|
@@ -11,6 +11,8 @@ import { runPortableOperation } from '../../operation.catalog.js';
|
|
|
11
11
|
import { markPortableBootstrapCanonicalSource } from '../../providers/schema.bootstrap.provenance.js';
|
|
12
12
|
import { allocateContinuationPath, allocateDirectoryArtifactPath } from '../../../../transitions/record.transitions.js';
|
|
13
13
|
import { classifyParentRecoveryReference } from '../../../../lineage/parentRecoveryReference.js';
|
|
14
|
+
import { creationSchemaReferenceValidationContext } from '../../draft/draft.validation-context.js';
|
|
15
|
+
import { isQualifiedIdentifierOnlyHistoricalSchemaReferenceAuthority, qualifiedIdentifierOnlyHistoricalSchemaReferenceAuthority } from '../../../../schemas/schema.reference.js';
|
|
14
16
|
|
|
15
17
|
const STATE_RELATIVE_PATH = '.tiinex/continuation.json';
|
|
16
18
|
|
|
@@ -66,16 +68,21 @@ export async function runCommonAuthorCli(parsed = {}, runtime = {}) {
|
|
|
66
68
|
await writeFile(artifactPath, markdown, { encoding: 'utf8', flag: flags.overwrite ? 'w' : 'wx' });
|
|
67
69
|
wrote = true;
|
|
68
70
|
const auditMaterial = await loadNodePortableInput(
|
|
69
|
-
[artifactPath
|
|
71
|
+
[artifactPath],
|
|
70
72
|
{ maxFiles: flags['max-files'], maxTextBytes: flags['max-text-bytes'] }
|
|
71
73
|
);
|
|
72
|
-
const
|
|
74
|
+
const candidateAudit = await runPortableOperation('audit', auditMaterial, {});
|
|
75
|
+
const parentAudit = parentPath
|
|
76
|
+
? await runHistoricalParentAudit(parentPath, parentRecord, contract, flags)
|
|
77
|
+
: null;
|
|
78
|
+
const audit = mergeAuthorAuditResults(candidateAudit, parentAudit);
|
|
73
79
|
const stageMaterial = await loadNodePortableInput(
|
|
74
80
|
normalizeRuntimePaths(runtime.defaultSchemaMaterialPaths),
|
|
75
81
|
{ maxFiles: flags['max-files'], maxTextBytes: flags['max-text-bytes'] }
|
|
76
82
|
);
|
|
77
83
|
const stage = await runPortableOperation('stage-draft', {
|
|
78
84
|
...stageMaterial,
|
|
85
|
+
schemaReferenceAuthorities: creationSchemaReferenceValidationContext(contract, parentRecord),
|
|
79
86
|
draft: { path: artifactRelativePath, markdown, schemaId, sourceMode: 'local-common-author', source: null }
|
|
80
87
|
}, {});
|
|
81
88
|
const blocking = Number(audit?.findingSummary?.counts?.error || 0) + Number(stage?.findingSummary?.counts?.error || 0);
|
|
@@ -87,7 +94,7 @@ export async function runCommonAuthorCli(parsed = {}, runtime = {}) {
|
|
|
87
94
|
schema: 'tiinex.portable.common-author.result.v1',
|
|
88
95
|
operation: 'author',
|
|
89
96
|
status: 'blocked',
|
|
90
|
-
artifact: Object.freeze({ path: artifactRelativePath, schemaId, written: false }),
|
|
97
|
+
artifact: Object.freeze({ path: artifactRelativePath, schemaId, written: false, parentPath: parentReference, parentSource: parentSource || '', parentSchemaReferenceAuthority: projectHistoricalParentReferenceAuthority(parentRecord) }),
|
|
91
98
|
audit,
|
|
92
99
|
stage,
|
|
93
100
|
findingSummary: mergeFindingSummaries(audit?.findingSummary, stage?.findingSummary),
|
|
@@ -105,7 +112,7 @@ export async function runCommonAuthorCli(parsed = {}, runtime = {}) {
|
|
|
105
112
|
schema: 'tiinex.portable.common-author.result.v1',
|
|
106
113
|
operation: 'author',
|
|
107
114
|
status: 'qualified',
|
|
108
|
-
artifact: Object.freeze({ path: artifactRelativePath, absolutePath: artifactPath, schemaId, parentPath: parentReference, parentSource: parentSource || '', selfIntegrity: selfIntegrity.state, written: true }),
|
|
115
|
+
artifact: Object.freeze({ path: artifactRelativePath, absolutePath: artifactPath, schemaId, parentPath: parentReference, parentSource: parentSource || '', parentSchemaReferenceAuthority: projectHistoricalParentReferenceAuthority(parentRecord), selfIntegrity: selfIntegrity.state, written: true }),
|
|
109
116
|
qualification: Object.freeze({ audit: audit.status, stage: stage.status, exportReady: Boolean(stage?.stagedArtifact?.qualification?.exportReady) }),
|
|
110
117
|
findingSummary: mergeFindingSummaries(audit?.findingSummary, stage?.findingSummary),
|
|
111
118
|
nextAction: schemaId === 'tiinex.handoff.v1'
|
|
@@ -120,6 +127,88 @@ export async function runCommonAuthorCli(parsed = {}, runtime = {}) {
|
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
129
|
|
|
130
|
+
async function runHistoricalParentAudit(parentPath, parentRecord = {}, contract = {}, flags = {}) {
|
|
131
|
+
const material = await loadNodePortableInput(
|
|
132
|
+
[parentPath],
|
|
133
|
+
{ maxFiles: flags['max-files'], maxTextBytes: flags['max-text-bytes'] }
|
|
134
|
+
);
|
|
135
|
+
const exactCurrentMatch = sameExactSchemaReferenceAuthority(
|
|
136
|
+
parentRecord.schemaReferenceAuthority || null,
|
|
137
|
+
contract?.schemaReferences?.current || null,
|
|
138
|
+
parentRecord.schemaId || parentRecord.currentSchemaId || ''
|
|
139
|
+
);
|
|
140
|
+
return runPortableOperation('audit', material, {
|
|
141
|
+
schemaReferenceContext: 'historical',
|
|
142
|
+
schemaReferenceAuthorities: Object.freeze({ current: parentRecord.schemaReferenceAuthority || null }),
|
|
143
|
+
...(exactCurrentMatch ? {} : {
|
|
144
|
+
schemaValidationAuthority: historicalParentSchemaValidationAuthority(parentRecord)
|
|
145
|
+
})
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function sameExactSchemaReferenceAuthority(parentAuthority = null, currentAuthority = null, schemaId = '') {
|
|
150
|
+
if (!parentAuthority || !currentAuthority) return false;
|
|
151
|
+
const expectedSchemaId = String(schemaId || '').trim();
|
|
152
|
+
const parentSchemaId = String(parentAuthority.schemaId || '').trim();
|
|
153
|
+
const currentSchemaId = String(currentAuthority.schemaId || '').trim();
|
|
154
|
+
if (!expectedSchemaId || parentSchemaId !== expectedSchemaId || currentSchemaId !== expectedSchemaId) return false;
|
|
155
|
+
if (String(parentAuthority.resolutionState || parentAuthority.state || '') !== 'qualified') return false;
|
|
156
|
+
if (String(currentAuthority.resolutionState || currentAuthority.state || '') !== 'qualified') return false;
|
|
157
|
+
const parentTargets = exactSchemaReferenceTargets(parentAuthority);
|
|
158
|
+
const currentTargets = new Set(exactSchemaReferenceTargets(currentAuthority));
|
|
159
|
+
return parentTargets.length > 0 && parentTargets.some((target) => currentTargets.has(target));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function exactSchemaReferenceTargets(authority = {}) {
|
|
163
|
+
return [...new Set([
|
|
164
|
+
...(Array.isArray(authority.exactTargets) ? authority.exactTargets : []),
|
|
165
|
+
authority.preferredTarget || authority.target || ''
|
|
166
|
+
].map((item) => String(item || '').trim()).filter(Boolean))];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function historicalParentSchemaValidationAuthority(parentRecord = {}) {
|
|
170
|
+
const schemaId = String(parentRecord.schemaId || parentRecord.currentSchemaId || '').trim();
|
|
171
|
+
const target = String(parentRecord.schemaReferenceAuthority?.preferredTarget || parentRecord.schemaReferenceAuthority?.target || '').trim();
|
|
172
|
+
const identifierOnly = isQualifiedIdentifierOnlyHistoricalSchemaReferenceAuthority(parentRecord.schemaReferenceAuthority || {});
|
|
173
|
+
return Object.freeze({
|
|
174
|
+
schema: 'tiinex.portable.historical-parent-schema-validation-authority.v1',
|
|
175
|
+
state: 'unavailable',
|
|
176
|
+
reason: identifierOnly ? 'historical-parent-schema-revision-unresolved-identifier-only' : 'historical-parent-schema-revision-not-qualified-as-current-candidate-authority',
|
|
177
|
+
schemaId,
|
|
178
|
+
currentReference: Object.freeze({
|
|
179
|
+
state: identifierOnly ? 'historical-identifier-only-preserved' : target ? 'historical-exact-reference-preserved' : 'unavailable',
|
|
180
|
+
basis: identifierOnly ? 'historical-parent-declared-schema-identifier-only' : 'historical-parent-declared-schema-reference',
|
|
181
|
+
raw: '',
|
|
182
|
+
target,
|
|
183
|
+
exactRevisionState: identifierOnly ? 'unresolved' : target ? 'declared-exact-reference' : 'unavailable'
|
|
184
|
+
}),
|
|
185
|
+
lineage: Object.freeze([]),
|
|
186
|
+
findings: Object.freeze([
|
|
187
|
+
identifierOnly
|
|
188
|
+
? `Historical Parent ${parentRecord.path || parentRecord.id || '(parent)'} preserves only the declared ${schemaId || 'Current Schema'} identifier; exact historical schema revision remains unresolved and current candidate schema validation is withheld for the Parent.`
|
|
189
|
+
: `Historical Parent ${parentRecord.path || parentRecord.id || '(parent)'} is preserved under its exact declared ${schemaId || 'Current Schema'} reference${target ? ` ${target}` : ''}; current candidate schema validation is withheld because exact same-revision current authority is not qualified.`
|
|
190
|
+
]),
|
|
191
|
+
compiledContract: null,
|
|
192
|
+
boundary: 'Historical Parent validation still runs Root readability, exact declared schema-identifier/reference-shape checks, recovery and integrity. Identifier-only authority never becomes exact historical schema-revision authority; current schema-specific machine/companion validation is applied only when the Parent and current creation contract share exact qualified schema-revision authority.'
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function mergeAuthorAuditResults(candidateAudit = {}, parentAudit = null) {
|
|
197
|
+
if (!parentAudit) return candidateAudit;
|
|
198
|
+
const audits = Object.freeze([...(candidateAudit.audits || []), ...(parentAudit.audits || [])]);
|
|
199
|
+
const findings = Object.freeze([...(candidateAudit.findings || []), ...(parentAudit.findings || [])]);
|
|
200
|
+
return Object.freeze({
|
|
201
|
+
...candidateAudit,
|
|
202
|
+
audits,
|
|
203
|
+
findings,
|
|
204
|
+
findingSummary: mergeFindingSummaries(candidateAudit.findingSummary, parentAudit.findingSummary),
|
|
205
|
+
boundary: Object.freeze({
|
|
206
|
+
...(candidateAudit.boundary || {}),
|
|
207
|
+
historicalParentAudit: 'separate exact-byte historical audit; current schema-specific validation only when exact same-revision authority is qualified'
|
|
208
|
+
})
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
123
212
|
async function parentRecordFromArtifact(parentPath, parentRelativePath, context = {}) {
|
|
124
213
|
const markdown = await readFile(parentPath, 'utf8');
|
|
125
214
|
const parsed = parseArtifactMarkdown(markdown);
|
|
@@ -131,8 +220,11 @@ async function parentRecordFromArtifact(parentPath, parentRelativePath, context
|
|
|
131
220
|
if (self.state !== 'verified') throw new Error(`portable.cli.author.parent.integrity.${self.reason || self.state}`);
|
|
132
221
|
const schemaReferenceAuthority = schemaTarget
|
|
133
222
|
? exactDeclaredSchemaReferenceAuthority(schemaId, schemaTarget)
|
|
134
|
-
:
|
|
135
|
-
|
|
223
|
+
: qualifiedIdentifierOnlyHistoricalSchemaReferenceAuthority(schemaId, {
|
|
224
|
+
basis: 'exact-historical-parent-current-schema-identifier',
|
|
225
|
+
parentPath: String(parentRelativePath || ''),
|
|
226
|
+
parentSha256: sha256Hex(utf8Bytes(markdown))
|
|
227
|
+
});
|
|
136
228
|
return Object.freeze({
|
|
137
229
|
id: parentRelativePath,
|
|
138
230
|
path: parentRelativePath,
|
|
@@ -146,6 +238,25 @@ async function parentRecordFromArtifact(parentPath, parentRelativePath, context
|
|
|
146
238
|
});
|
|
147
239
|
}
|
|
148
240
|
|
|
241
|
+
function projectHistoricalParentReferenceAuthority(parentRecord = {}) {
|
|
242
|
+
const authority = parentRecord?.schemaReferenceAuthority || null;
|
|
243
|
+
if (!authority || !String(parentRecord?.schemaId || parentRecord?.currentSchemaId || '').trim()) return null;
|
|
244
|
+
const schemaId = String(parentRecord.schemaId || parentRecord.currentSchemaId || '').trim();
|
|
245
|
+
const target = String(authority.preferredTarget || authority.target || '').trim();
|
|
246
|
+
const identifierOnly = isQualifiedIdentifierOnlyHistoricalSchemaReferenceAuthority(authority);
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
state: String(authority.resolutionState || authority.state || 'unavailable'),
|
|
249
|
+
kind: identifierOnly ? 'identifier-only' : target ? 'exact-target' : 'unresolved',
|
|
250
|
+
schemaId,
|
|
251
|
+
target,
|
|
252
|
+
exactRevisionState: identifierOnly ? 'unresolved' : target ? 'declared-exact-reference' : 'unresolved',
|
|
253
|
+
provenance: Object.freeze({ ...(authority.resolutionEvidence || authority.evidence || {}) }),
|
|
254
|
+
boundary: identifierOnly
|
|
255
|
+
? 'Exact historical Parent artifact identity/integrity and declared schema identifier are qualified; no exact historical schema representation target is claimed or inferred.'
|
|
256
|
+
: 'Historical Parent schema-reference authority is projected only at the exact strength carried by the supplied Parent bytes.'
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
149
260
|
function projectAuthorActionableFindings(audit = {}, stage = {}) {
|
|
150
261
|
const findings = [
|
|
151
262
|
...(audit.findings || audit.actionableFindings || []),
|
|
@@ -104,6 +104,7 @@ function projectGroundDefault(result = {}, parsed = {}) {
|
|
|
104
104
|
readiness: compactReadiness(result.readiness),
|
|
105
105
|
authority: compactGroundAuthority(result.authority),
|
|
106
106
|
orchestrationReadiness: compactOrchestrationReadiness(result.orchestrationReadiness),
|
|
107
|
+
delegationReadiness: compactDelegationReadiness(result.delegationReadiness),
|
|
107
108
|
requiredContext: Object.freeze({
|
|
108
109
|
declared: Number(required.declared || 0),
|
|
109
110
|
matchedInWorkspaceSnapshots: Number(required.matchedInWorkspaceSnapshots || 0),
|
|
@@ -163,6 +164,7 @@ function projectHandoffDefault(result = {}, parsed = {}) {
|
|
|
163
164
|
status: String(carrier.status || ''),
|
|
164
165
|
mode: String(carrier.mode || ''),
|
|
165
166
|
lineage: carrier.lineage ? compactCarrierLineage(carrier.lineage) : null,
|
|
167
|
+
allocation: result.carrierAllocation ? Object.freeze({ ...result.carrierAllocation }) : null,
|
|
166
168
|
route: Object.freeze({
|
|
167
169
|
id: String(route.id || ''),
|
|
168
170
|
state: String(route.state || ''),
|
|
@@ -275,11 +277,17 @@ function compactGroundAuthority(authority = {}) {
|
|
|
275
277
|
}),
|
|
276
278
|
holderBinding: Object.freeze({
|
|
277
279
|
state: String(holderBinding.state || ''),
|
|
280
|
+
bindingPresent: Boolean(holderBinding.bindingPresent),
|
|
281
|
+
declarationPresent: Boolean(holderBinding.declarationPresent),
|
|
278
282
|
holderId: String(holderBinding.holderId || ''),
|
|
279
283
|
roleLabel: String(holderBinding.roleLabel || ''),
|
|
280
284
|
recipientRoleLabel: String(holderBinding.recipientRoleLabel || ''),
|
|
281
285
|
recipientCompatibility: String(holderBinding.recipientCompatibility || ''),
|
|
282
286
|
source: String(holderBinding.source || ''),
|
|
287
|
+
sourceDetail: holderBinding.sourceDetail ? Object.freeze({ ...holderBinding.sourceDetail }) : null,
|
|
288
|
+
authorization: holderBinding.authorization ? Object.freeze({ ...holderBinding.authorization, provenance: holderBinding.authorization.provenance ? Object.freeze({ ...holderBinding.authorization.provenance }) : null }) : null,
|
|
289
|
+
durableIdentity: holderBinding.durableIdentity ? Object.freeze({ ...holderBinding.durableIdentity }) : Object.freeze({ state: 'not-established' }),
|
|
290
|
+
semanticAuthorityState: String(holderBinding.semanticAuthorityState || 'not-established'),
|
|
283
291
|
explicit: Boolean(holderBinding.explicit),
|
|
284
292
|
inferredFromTransport: Boolean(holderBinding.inferredFromTransport),
|
|
285
293
|
provenance: holderBinding.provenance ? Object.freeze({ ...holderBinding.provenance }) : null
|
|
@@ -293,6 +301,24 @@ function compactGroundAuthority(authority = {}) {
|
|
|
293
301
|
});
|
|
294
302
|
}
|
|
295
303
|
|
|
304
|
+
|
|
305
|
+
function compactDelegationReadiness(value = {}) {
|
|
306
|
+
if (!value || typeof value !== 'object') return null;
|
|
307
|
+
return Object.freeze({
|
|
308
|
+
state: String(value.state || ''),
|
|
309
|
+
delegateCapabilityAuthority: value.delegateCapabilityAuthority ? Object.freeze({ ...value.delegateCapabilityAuthority }) : null,
|
|
310
|
+
processApplicability: value.processApplicability ? Object.freeze({ ...value.processApplicability }) : null,
|
|
311
|
+
targetAuthority: value.targetAuthority ? Object.freeze({ ...value.targetAuthority }) : null,
|
|
312
|
+
sourceAuthority: value.sourceAuthority ? Object.freeze({ ...value.sourceAuthority }) : null,
|
|
313
|
+
returnReconciliationExpectation: value.returnReconciliationExpectation ? Object.freeze({ ...value.returnReconciliationExpectation }) : null,
|
|
314
|
+
blockers: Object.freeze((value.blockers || []).slice(0, 8).map((item) => Object.freeze({ ...item }))),
|
|
315
|
+
plainChatFallbackPermitted: Boolean(value.plainChatFallbackPermitted),
|
|
316
|
+
repositoryScanningFallbackPermitted: Boolean(value.repositoryScanningFallbackPermitted),
|
|
317
|
+
nextOperations: Object.freeze((value.nextOperations || []).slice(0, 4).map((item) => Object.freeze({ ...item }))),
|
|
318
|
+
boundary: String(value.boundary || '')
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
296
322
|
function compactOrchestrationReadiness(value = {}) {
|
|
297
323
|
if (!value || typeof value !== 'object') return null;
|
|
298
324
|
const wider = value.widerOrchestration || {};
|
|
@@ -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
|
];
|
|
@@ -6,7 +6,7 @@ import { qualifyToolingRuntimeSourceAlignment } from './handoff.manufacture.runt
|
|
|
6
6
|
import { normalizeHandoffCarrierLineage } from '../../handoff/carrierLineage.js';
|
|
7
7
|
import { normalizeHandoffCarrierProfile } from '../../handoff/carrierProfile.js';
|
|
8
8
|
import { enumerateNodeWorkspace, PORTABLE_NODE_WORKSPACE_ENUMERATION_SCHEMA_ID } from './handoff.manufacture.enumeration.js';
|
|
9
|
-
import { preparePackageParentWorkspaceReuse, projectRequiredContextWorkspaceSelectionPreflight } from './handoff.manufacture.packageParent.js';
|
|
9
|
+
import { preparePackageParentExactMaterialProvider, preparePackageParentWorkspaceReuse, projectPackageParentMaterialClosurePreflight, projectRequiredContextWorkspaceSelectionPreflight, resolvePackageParentRequirementMaterials } from './handoff.manufacture.packageParent.js';
|
|
10
10
|
import { qualifyPortableSourceReconciliationProofForManufacture } from '../../comparison/sourceFrontierReconciliationProof.js';
|
|
11
11
|
import { qualifyPortableManufactureSchemaReferenceCandidate } from '../../handoff/schemaReferencePreflight.js';
|
|
12
12
|
import { qualifyDelegationReturnReservation } from '../../handoff/delegationReturnReservation.js';
|
|
@@ -69,6 +69,12 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
69
69
|
workspaceIds: input.packageParentWorkspaceIds || input.reusePackageParentWorkspaceIds || [],
|
|
70
70
|
workspaceAliases: input.packageParentWorkspaceAliases || input.workspaceAliases || {}
|
|
71
71
|
});
|
|
72
|
+
const packageParentExactMaterialProvider = preparePackageParentExactMaterialProvider({
|
|
73
|
+
bundle: input.packageParentBundle || null,
|
|
74
|
+
currentWorkspaceIds: [...seenWorkspaceIds],
|
|
75
|
+
parentPackagePath: input.packageParentPath || '',
|
|
76
|
+
parentPackageSha256: input.packageParentSha256 || ''
|
|
77
|
+
});
|
|
72
78
|
const handoffMarkdown = await handoffMarkdownPromise;
|
|
73
79
|
const requiredContextWorkspaceSelectionPreflight = projectRequiredContextWorkspaceSelectionPreflight({
|
|
74
80
|
handoffMarkdown,
|
|
@@ -140,7 +146,8 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
140
146
|
}
|
|
141
147
|
const suppliedTransportRoutes = [...(input.transportRoutes || input.handoffRoutes || [])].map((route) => normalizeTransportRoute(route, workspaceId)).filter(Boolean);
|
|
142
148
|
const reservationProjection = returnCarrierReservationPreflight.state === 'qualified' && returnCarrierReservationPreflight.returnExpected
|
|
143
|
-
|
|
149
|
+
&& (returnCarrierReservationPreflight.carrierKind === 'major' || Number.isInteger(returnCarrierReservationPreflight.siblingIndex))
|
|
150
|
+
? Object.freeze({ carrierKind: returnCarrierReservationPreflight.carrierKind, ...(Number.isInteger(returnCarrierReservationPreflight.siblingIndex) ? { siblingIndex: returnCarrierReservationPreflight.siblingIndex } : {}) })
|
|
144
151
|
: null;
|
|
145
152
|
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
153
|
const workspaceTargets = mergeWorkspaceTargetBindings(normalizeWorkspaceTargetBindings({
|
|
@@ -168,16 +175,18 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
168
175
|
|
|
169
176
|
const routeSpecs = transportRoutes.length ? transportRoutes : Object.freeze([{ workspaceId, path: handoffPath }]);
|
|
170
177
|
let requirements = await projectManufacturingRequirements({ handoff, workspaceId, handoffPath, routeSpecs, workspaceRuntimeById });
|
|
178
|
+
const packageParentMaterialClosurePreflight = projectPackageParentMaterialClosurePreflight(requirements, packageParentExactMaterialProvider);
|
|
171
179
|
let materials = await resolveWorkspaceRequirementMaterials(requirements, workspaceRuntimeById, input.materialBindings || {});
|
|
180
|
+
materials = appendMissingRequirementMaterials(materials, resolvePackageParentRequirementMaterials(requirements, packageParentExactMaterialProvider));
|
|
172
181
|
const dependencyClosure = await expandPointerDependencyClosure({ requirements, materials, workspaceRuntimeById, bindings: input.materialBindings || {} });
|
|
173
182
|
requirements = dependencyClosure.requirements;
|
|
174
|
-
materials = dependencyClosure.materials;
|
|
183
|
+
materials = appendMissingRequirementMaterials(dependencyClosure.materials, resolvePackageParentRequirementMaterials(requirements, packageParentExactMaterialProvider));
|
|
175
184
|
const routeParentBoundaryClosure = expandRouteParentBoundaryClosure({ requirements, materials, workspaceMaterializations, workspaceRuntimeById, routeSpecs });
|
|
176
185
|
requirements = routeParentBoundaryClosure.requirements;
|
|
177
|
-
materials = routeParentBoundaryClosure.materials;
|
|
186
|
+
materials = appendMissingRequirementMaterials(routeParentBoundaryClosure.materials, resolvePackageParentRequirementMaterials(requirements, packageParentExactMaterialProvider));
|
|
178
187
|
const parentBoundaryClosure = expandBoundedParentBoundaryClosure({ requirements, materials, workspaceMaterializations, workspaceRuntimeById });
|
|
179
188
|
requirements = parentBoundaryClosure.requirements;
|
|
180
|
-
materials = parentBoundaryClosure.materials;
|
|
189
|
+
materials = appendMissingRequirementMaterials(parentBoundaryClosure.materials, resolvePackageParentRequirementMaterials(requirements, packageParentExactMaterialProvider));
|
|
181
190
|
const toolingBootstrapResult = await toolingBootstrapPromise;
|
|
182
191
|
if (toolingBootstrapResult.error) throw toolingBootstrapResult.error;
|
|
183
192
|
const toolingBootstrap = toolingBootstrapResult.value;
|
|
@@ -205,6 +214,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
205
214
|
transportRoutes,
|
|
206
215
|
workspaceTargets,
|
|
207
216
|
carrierLineage: normalizeHandoffCarrierLineage(input.carrierLineage || null),
|
|
217
|
+
carrierAllocation: input.carrierAllocation ? Object.freeze({ ...input.carrierAllocation }) : null,
|
|
208
218
|
carrierProfile: normalizeHandoffCarrierProfile(input.carrierProfile || null),
|
|
209
219
|
toolingBootstrap: toolingBootstrap.summary,
|
|
210
220
|
reconciliationProofQualification,
|
|
@@ -218,6 +228,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
218
228
|
reconciliationProof: reconciliationProofQualification,
|
|
219
229
|
schemaReferencePreflight,
|
|
220
230
|
returnCarrierReservationPreflight,
|
|
231
|
+
carrierAllocation: input.carrierAllocation ? Object.freeze({ ...input.carrierAllocation }) : null,
|
|
221
232
|
packageParentWorkspaceReuse: Object.freeze({
|
|
222
233
|
state: String(packageParentReuse.state || ''),
|
|
223
234
|
providerState: String(packageParentReuse.providerState || ''),
|
|
@@ -230,6 +241,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
230
241
|
workspaceAliases: Object.freeze([...(packageParentReuse.workspaceAliases || [])].map((item) => Object.freeze({ ...item }))),
|
|
231
242
|
boundary: String(packageParentReuse.boundary || '')
|
|
232
243
|
}),
|
|
244
|
+
packageParentMaterialClosurePreflight,
|
|
233
245
|
requiredContextWorkspaceSelectionPreflight,
|
|
234
246
|
carrierProjection: Object.freeze({ requestedRoutes: transportRoutes.length || 1, carrierLineage: normalizeHandoffCarrierLineage(input.carrierLineage || null), carrierProfile: normalizeHandoffCarrierProfile(input.carrierProfile || null), boundary: 'Routes are qualified later against packaged workspace bytes; adapter text is not authority.' })
|
|
235
247
|
}),
|
|
@@ -238,6 +250,19 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
|
|
253
|
+
function appendMissingRequirementMaterials(existing = [], additional = []) {
|
|
254
|
+
const out = [...(existing || [])];
|
|
255
|
+
const alreadyBound = new Set(out.map((item) => String(item.requirementId || '')).filter(Boolean));
|
|
256
|
+
for (const item of additional || []) {
|
|
257
|
+
const id = String(item.requirementId || '');
|
|
258
|
+
if (id && alreadyBound.has(id)) continue;
|
|
259
|
+
out.push(item);
|
|
260
|
+
if (id) alreadyBound.add(id);
|
|
261
|
+
}
|
|
262
|
+
return Object.freeze(out);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
241
266
|
function mergeWorkspaceTargetBindings(explicit = [], inherited = []) {
|
|
242
267
|
const out = [];
|
|
243
268
|
const seen = new Set();
|