@tiinex/core 0.12.0 → 0.14.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/audit/audit.run.js +1 -1
- package/src/public/index.js +18 -0
- package/src/public/node.js +1 -0
- package/src/schemas/creation.contracts.js +1 -1
- package/src/schemas/creation.schemaReferences.js +28 -8
- package/src/schemas/schema.reference.js +30 -4
- package/src/schemas/tiinex.root.v1.schema.json +2 -1
- package/src/tooling/portable/adapters/cli/cli.command-input.js +5 -0
- package/src/tooling/portable/adapters/cli/cli.common-output.js +23 -0
- package/src/tooling/portable/adapters/cli/cli.handoff-manufacture.js +52 -11
- package/src/tooling/portable/adapters/cli/cli.help.js +15 -2
- package/src/tooling/portable/adapters/cli/cli.run.js +1 -1
- package/src/tooling/portable/adapters/cli/cli.source-frontier-comparison.js +6 -6
- package/src/tooling/portable/adapters/cli/cli.source-frontier-reconciliation.js +18 -0
- package/src/tooling/portable/adapters/node/bootstrapCarrier.manufacture.js +18 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.enumeration.js +27 -8
- package/src/tooling/portable/adapters/node/handoff.manufacture.js +17 -0
- package/src/tooling/portable/adapters/node/sourceFrontierComparison.js +2 -1
- package/src/tooling/portable/adapters/node/sourceFrontierReconciliationProof.js +23 -0
- package/src/tooling/portable/adapters/node/workspaceCarrier.manufacture.js +14 -3
- package/src/tooling/portable/audit/audit.capability.js +2 -1
- package/src/tooling/portable/bootstrap/tiinex.llm.bootstrap.md +2 -2
- package/src/tooling/portable/comparison/sourceFrontierComparison.js +54 -4
- package/src/tooling/portable/comparison/sourceFrontierReconciliationProof.js +569 -0
- package/src/tooling/portable/draft/draft.create.js +3 -0
- package/src/tooling/portable/draft/draft.operations.js +1 -1
- package/src/tooling/portable/editor/editor.assistance.js +2 -25
- package/src/tooling/portable/handoff/bootstrapCarrier.manufacture.js +56 -0
- package/src/tooling/portable/handoff/contracts/tiinex.handoff.package.v1.schema.md +340 -77
- package/src/tooling/portable/handoff/manufacture.js +17 -3
- package/src/tooling/portable/handoff/pointerEntrypoint.js +4 -1
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.build.js +73 -32
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.closure.js +1 -1
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.inspect.js +9 -1
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.materials.js +28 -6
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.shared.js +8 -0
- package/src/tooling/portable/handoff/recipientV2.coldProjection.js +11 -6
- package/src/tooling/portable/handoff/recipientV2.entryContract.js +12 -0
- package/src/tooling/portable/handoff/recipientV2.humanOutput.js +48 -6
- package/src/tooling/portable/handoff/recipientV2.packageV1.build.js +55 -43
- package/src/tooling/portable/handoff/recipientV2.packageV1.contract.js +57 -31
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.helpers.js +63 -10
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +55 -16
- package/src/tooling/portable/handoff/recipientV2.packageV1.workspaceProjection.js +14 -1
- package/src/tooling/portable/handoff/recipientV2.topology.js +3 -4
- package/src/tooling/portable/handoff/recipientV2.topology.materials.js +14 -0
- package/src/tooling/portable/handoff/schemaReferencePreflight.js +26 -0
- package/src/tooling/portable/handoff/transportEnvelopeV1.js +5 -0
- package/src/tooling/portable/handoff/workspaceCarrier.manufacture.js +42 -13
- package/src/tooling/portable/index.js +1 -0
- package/src/tooling/portable/operation.catalog.js +8 -0
- package/src/tooling/portable/source/sourceEligibility.js +108 -0
- package/src/validation/validateArtifact.js +62 -6
|
@@ -2,17 +2,25 @@ import { readdir, readFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { sha256Hex } from '../../../../export/package.bytes.js';
|
|
4
4
|
import { safeWorkspaceToken, serializableMetadata } from './handoff.manufacture.multiRoot.js';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_PORTABLE_SOURCE_EXCLUDED_DIRECTORIES,
|
|
7
|
+
DEFAULT_PORTABLE_SOURCE_EXCLUDED_RELATIVE_PATHS,
|
|
8
|
+
portableSourceEligibilityPolicy,
|
|
9
|
+
qualifyPortableSourcePath
|
|
10
|
+
} from '../../source/sourceEligibility.js';
|
|
5
11
|
|
|
6
12
|
export const PORTABLE_NODE_WORKSPACE_ENUMERATION_SCHEMA_ID = 'tiinex.portable.node-workspace-enumeration.v1';
|
|
7
|
-
export const DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_DIRECTORIES =
|
|
8
|
-
export const DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_RELATIVE_PATHS =
|
|
13
|
+
export const DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_DIRECTORIES = DEFAULT_PORTABLE_SOURCE_EXCLUDED_DIRECTORIES;
|
|
14
|
+
export const DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_RELATIVE_PATHS = DEFAULT_PORTABLE_SOURCE_EXCLUDED_RELATIVE_PATHS;
|
|
9
15
|
const DEFAULT_MAX_FILES = 10000;
|
|
10
16
|
|
|
11
17
|
export async function enumerateNodeWorkspace(rootInput = '.', options = {}) {
|
|
12
18
|
const root = path.resolve(String(rootInput || '.'));
|
|
13
19
|
const maxFiles = positiveInteger(options.maxFiles, DEFAULT_MAX_FILES);
|
|
14
|
-
const
|
|
15
|
-
|
|
20
|
+
const sourceEligibility = portableSourceEligibilityPolicy({
|
|
21
|
+
excludeDirectories: options.excludeDirectories == null ? DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_DIRECTORIES : options.excludeDirectories,
|
|
22
|
+
excludeRelativePaths: options.excludeRelativePaths == null ? DEFAULT_HANDOFF_MANUFACTURE_EXCLUDED_RELATIVE_PATHS : options.excludeRelativePaths
|
|
23
|
+
});
|
|
16
24
|
const queue = [root];
|
|
17
25
|
const absoluteFiles = [];
|
|
18
26
|
const skippedSymlinks = [];
|
|
@@ -21,10 +29,15 @@ export async function enumerateNodeWorkspace(rootInput = '.', options = {}) {
|
|
|
21
29
|
const entries = await readdir(current, { withFileTypes: true });
|
|
22
30
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
23
31
|
for (const entry of entries) {
|
|
24
|
-
if (entry.isDirectory() && excluded.has(entry.name)) continue;
|
|
25
32
|
const absolute = path.join(current, entry.name);
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
const relative = normalizeRelativePath(path.relative(root, absolute));
|
|
34
|
+
const eligibility = qualifyPortableSourcePath(relative, {
|
|
35
|
+
excludeDirectories: sourceEligibility.excludedDirectories,
|
|
36
|
+
excludeRelativePaths: sourceEligibility.excludedRelativePaths,
|
|
37
|
+
entryKind: entry.isDirectory() ? 'directory' : 'file'
|
|
38
|
+
});
|
|
39
|
+
if (!eligibility.eligible) continue;
|
|
40
|
+
if (entry.isSymbolicLink()) { skippedSymlinks.push(relative); continue; }
|
|
28
41
|
if (entry.isDirectory()) queue.push(absolute);
|
|
29
42
|
else if (entry.isFile()) absoluteFiles.push(absolute);
|
|
30
43
|
if (absoluteFiles.length > maxFiles) {
|
|
@@ -62,7 +75,13 @@ export async function enumerateNodeWorkspace(rootInput = '.', options = {}) {
|
|
|
62
75
|
workspaceId,
|
|
63
76
|
entryCount: includedEntries.length,
|
|
64
77
|
totalBytes,
|
|
65
|
-
exclusions: Object.freeze({
|
|
78
|
+
exclusions: Object.freeze({
|
|
79
|
+
directories: sourceEligibility.excludedDirectories,
|
|
80
|
+
relativePaths: sourceEligibility.excludedRelativePaths,
|
|
81
|
+
fileSuffixes: sourceEligibility.excludedFileSuffixes,
|
|
82
|
+
symbolicLinks: 'excluded-and-reported',
|
|
83
|
+
sourceEligibilitySchema: sourceEligibility.schema
|
|
84
|
+
}),
|
|
66
85
|
skippedSymlinks: Object.freeze(skippedSymlinks.sort()),
|
|
67
86
|
entriesFingerprint: sha256Text(stableJson(includedEntries))
|
|
68
87
|
});
|
|
@@ -7,6 +7,8 @@ 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
9
|
import { preparePackageParentWorkspaceReuse } from './handoff.manufacture.packageParent.js';
|
|
10
|
+
import { qualifyPortableSourceReconciliationProofForManufacture } from '../../comparison/sourceFrontierReconciliationProof.js';
|
|
11
|
+
import { qualifyPortableManufactureSchemaReferenceCandidate } from '../../handoff/schemaReferencePreflight.js';
|
|
10
12
|
import {
|
|
11
13
|
assertInside,
|
|
12
14
|
expandPointerDependencyClosure,
|
|
@@ -48,6 +50,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
48
50
|
workspaceTitle: requestedWorkspaceTitle,
|
|
49
51
|
sourceMetadata: input.workspaceSource || input.sourceMetadata || {},
|
|
50
52
|
excludeDirectories: input.excludeDirectories || options.excludeDirectories,
|
|
53
|
+
excludeRelativePaths: input.excludeRelativePaths || options.excludeRelativePaths,
|
|
51
54
|
maxFiles: input.maxFiles || options.maxFiles
|
|
52
55
|
});
|
|
53
56
|
const additionalWorkspaceDescriptors = normalizeAdditionalWorkspaceDescriptors(input.additionalWorkspaces || input.workspaceRoots || input.workspaceDescriptors || []);
|
|
@@ -79,6 +82,7 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
79
82
|
workspaceTitle: requestedTitle,
|
|
80
83
|
sourceMetadata: descriptor.source || descriptor.sourceMetadata || {},
|
|
81
84
|
excludeDirectories: descriptor.excludeDirectories || input.excludeDirectories || options.excludeDirectories,
|
|
85
|
+
excludeRelativePaths: descriptor.excludeRelativePaths || input.excludeRelativePaths || options.excludeRelativePaths,
|
|
82
86
|
maxFiles: descriptor.maxFiles || input.maxFiles || options.maxFiles
|
|
83
87
|
});
|
|
84
88
|
if (enumerated.status !== 'qualified-complete') throw new Error(`portable.handoff-manufacture.workspace-enumeration.${id}.${enumerated.status}`);
|
|
@@ -97,6 +101,8 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
97
101
|
markdown: handoffMarkdown
|
|
98
102
|
});
|
|
99
103
|
|
|
104
|
+
const schemaReferencePreflight = qualifyPortableManufactureSchemaReferenceCandidate(handoff);
|
|
105
|
+
|
|
100
106
|
if (enumeration.status !== 'qualified-complete') throw new Error(`portable.handoff-manufacture.workspace-enumeration.${enumeration.status}`);
|
|
101
107
|
const workspaceTitle = requestedWorkspaceTitle || inferWorkspaceTitle(enumeration) || workspaceId;
|
|
102
108
|
const primaryMaterialization = Object.freeze({ ...enumeration.materialization, title: workspaceTitle });
|
|
@@ -138,6 +144,13 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
138
144
|
if (targets.length !== 1) throw new Error(`portable.handoff-manufacture.workspace-scope.target-${targets.length ? 'ambiguous' : 'required'}:${materialization.id}`);
|
|
139
145
|
workspaceMaterializations[index] = projectBoundedWorkspaceMaterialization(materialization, scope, targets[0].path);
|
|
140
146
|
}
|
|
147
|
+
const hasReconciliationProof = Boolean(input.reconciliationProof && typeof input.reconciliationProof === 'object' && Object.keys(input.reconciliationProof).length);
|
|
148
|
+
const reconciliationProofQualification = qualifyPortableSourceReconciliationProofForManufacture({
|
|
149
|
+
proof: input.reconciliationProof || null,
|
|
150
|
+
requireProof: input.requireReconciliationProof === true,
|
|
151
|
+
workspaceMaterializations,
|
|
152
|
+
requiredWorkspaceIds: hasReconciliationProof || input.requireReconciliationProof === true ? [workspaceId] : []
|
|
153
|
+
});
|
|
141
154
|
|
|
142
155
|
const routeSpecs = transportRoutes.length ? transportRoutes : Object.freeze([{ workspaceId, path: handoffPath }]);
|
|
143
156
|
let requirements = await projectManufacturingRequirements({ handoff, workspaceId, handoffPath, routeSpecs, workspaceRuntimeById });
|
|
@@ -180,11 +193,15 @@ export async function prepareNodeHandoffManufacturingInput(input = {}, options =
|
|
|
180
193
|
carrierLineage: normalizeHandoffCarrierLineage(input.carrierLineage || null),
|
|
181
194
|
carrierProfile: normalizeHandoffCarrierProfile(input.carrierProfile || null),
|
|
182
195
|
toolingBootstrap: toolingBootstrap.summary,
|
|
196
|
+
reconciliationProofQualification,
|
|
197
|
+
schemaReferencePreflight,
|
|
183
198
|
manufacturingEvidence: Object.freeze({
|
|
184
199
|
enumeration: enumeration.evidence,
|
|
185
200
|
workspaceEnumerations: Object.freeze(workspaceEnumerations),
|
|
186
201
|
toolingBootstrap: toolingBootstrap.summary,
|
|
187
202
|
runtimeSourceAlignment,
|
|
203
|
+
reconciliationProof: reconciliationProofQualification,
|
|
204
|
+
schemaReferencePreflight,
|
|
188
205
|
packageParentWorkspaceReuse: Object.freeze({
|
|
189
206
|
state: String(packageParentReuse.state || ''),
|
|
190
207
|
providerState: String(packageParentReuse.providerState || ''),
|
|
@@ -59,7 +59,7 @@ async function frontierFromLocalWorkspace(descriptor, options) {
|
|
|
59
59
|
id: descriptor.label || `${options.side || 'input'}:${workspaceId}`,
|
|
60
60
|
source: { kind: 'local-workspace', ref: root, snapshotContract: 'shared-handoff-manufacture-node-enumeration-v1' },
|
|
61
61
|
workspaces: [workspaceFromEnumeration(workspaceId, enumeration, root)],
|
|
62
|
-
boundary: 'Local source is enumerated by the same deterministic Node Workspace enumerator used by Handoff manufacture;
|
|
62
|
+
boundary: 'Local source is enumerated by the same deterministic Node Workspace enumerator used by Handoff manufacture; durable-source eligibility, generated-cache exclusions, configured path exclusions, and symlink policy therefore remain shared.'
|
|
63
63
|
});
|
|
64
64
|
} catch (error) {
|
|
65
65
|
return createPortableSourceFrontier({ id: descriptor.label || options.side || '', state: 'qualification-error', source: { kind: 'local-workspace', ref: root }, workspaces: [{ workspaceId, state: 'unavailable', reason: 'local-workspace-read-failed', source: { kind: 'local-workspace', ref: root } }], findings: [portableFinding('error', 'portable.source-frontier.node.local-read-failed', 'Local Workspace source could not be enumerated.', { workspaceId, ref: root, detail: String(error?.message || error || '') })] });
|
|
@@ -180,6 +180,7 @@ function enumerationOptions(descriptor, options, workspaceId) {
|
|
|
180
180
|
workspaceTitle: String(descriptor.workspaceTitle || descriptor.title || workspaceId),
|
|
181
181
|
sourceMetadata: descriptor.sourceMetadata || {},
|
|
182
182
|
excludeDirectories: descriptor.excludeDirectories || options.excludeDirectories,
|
|
183
|
+
excludeRelativePaths: descriptor.excludeRelativePaths || options.excludeRelativePaths,
|
|
183
184
|
maxFiles: descriptor.maxFiles || options.maxFiles
|
|
184
185
|
};
|
|
185
186
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { prepareNodeSourceFrontier } from './sourceFrontierComparison.js';
|
|
2
|
+
import { provePortableSourceReconciliation } from '../../comparison/sourceFrontierReconciliationProof.js';
|
|
3
|
+
|
|
4
|
+
export async function prepareNodeSourceReconciliationProofInput(input = {}, options = {}) {
|
|
5
|
+
const [base, incoming, current, reconciled] = await Promise.all([
|
|
6
|
+
prepareNodeSourceFrontier(input.base, { ...options, side: 'base' }),
|
|
7
|
+
prepareNodeSourceFrontier(input.incoming, { ...options, side: 'incoming' }),
|
|
8
|
+
prepareNodeSourceFrontier(input.current, { ...options, side: 'current' }),
|
|
9
|
+
prepareNodeSourceFrontier(input.reconciled, { ...options, side: 'reconciled' })
|
|
10
|
+
]);
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
base,
|
|
13
|
+
incoming,
|
|
14
|
+
current,
|
|
15
|
+
reconciled,
|
|
16
|
+
dispositions: input.dispositions || []
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function proveNodeSourceReconciliation(input = {}, options = {}) {
|
|
21
|
+
const normalized = await prepareNodeSourceReconciliationProofInput(input, options);
|
|
22
|
+
return provePortableSourceReconciliation(normalized);
|
|
23
|
+
}
|
|
@@ -3,7 +3,7 @@ import { enumerateNodeWorkspace } from './handoff.manufacture.enumeration.js';
|
|
|
3
3
|
import { buildToolingBootstrapTransportFiles } from './handoff.manufacture.bootstrap.js';
|
|
4
4
|
import { qualifyToolingRuntimeSourceAlignment } from './handoff.manufacture.runtimeSource.js';
|
|
5
5
|
import { inferWorkspaceTitle, normalizeAdditionalWorkspaceDescriptors, safeWorkspaceToken } from './handoff.manufacture.multiRoot.js';
|
|
6
|
-
import { normalizeWorkspaceTargetBindings } from './handoff.manufacture.scope.js';
|
|
6
|
+
import { normalizeWorkspaceScopes, normalizeWorkspaceTargetBindings, projectBoundedWorkspaceMaterialization } from './handoff.manufacture.scope.js';
|
|
7
7
|
import { normalizeHandoffCarrierLineage } from '../../handoff/carrierLineage.js';
|
|
8
8
|
import { normalizeHandoffCarrierProfile } from '../../handoff/carrierProfile.js';
|
|
9
9
|
|
|
@@ -29,6 +29,7 @@ export async function prepareNodeWorkspaceCarrierManufacturingInput(input = {},
|
|
|
29
29
|
workspaceTitle: descriptor.title,
|
|
30
30
|
sourceMetadata: descriptor.source || descriptor.sourceMetadata || {},
|
|
31
31
|
excludeDirectories: descriptor.excludeDirectories || input.excludeDirectories || options.excludeDirectories,
|
|
32
|
+
excludeRelativePaths: descriptor.excludeRelativePaths || input.excludeRelativePaths || options.excludeRelativePaths,
|
|
32
33
|
maxFiles: descriptor.maxFiles || input.maxFiles || options.maxFiles
|
|
33
34
|
});
|
|
34
35
|
if (enumeration.status !== 'qualified-complete') throw new Error(`portable.workspace-carrier.workspace-enumeration.${descriptor.id}.${enumeration.status}`);
|
|
@@ -42,6 +43,15 @@ export async function prepareNodeWorkspaceCarrierManufacturingInput(input = {},
|
|
|
42
43
|
explicitBindings: input.workspaceTargets || input.workspaceTargetBindings || [],
|
|
43
44
|
additionalWorkspaceDescriptors
|
|
44
45
|
});
|
|
46
|
+
const workspaceScopes = normalizeWorkspaceScopes(input.workspaceScopes || input.workspaceScopeBindings || []);
|
|
47
|
+
const materializations = enumerations.map((item) => {
|
|
48
|
+
const materialization = item.materialization;
|
|
49
|
+
const scope = workspaceScopes.get(String(materialization.id || '')) || null;
|
|
50
|
+
if (!scope || scope.coverage !== 'bounded') return materialization;
|
|
51
|
+
const targets = workspaceTargets.filter((target) => String(target.workspaceId || '') === String(materialization.id || ''));
|
|
52
|
+
if (targets.length !== 1) throw new Error(`portable.workspace-carrier.workspace-scope.target-${targets.length ? 'ambiguous' : 'required'}:${materialization.id}`);
|
|
53
|
+
return projectBoundedWorkspaceMaterialization(materialization, scope, targets[0].path);
|
|
54
|
+
});
|
|
45
55
|
const toolingBootstrap = await buildToolingBootstrapTransportFiles({
|
|
46
56
|
delivery: input.toolingBootstrap || input.bootstrapDelivery || 'embedded',
|
|
47
57
|
runtimeRoot: input.runtimeRoot || options.runtimeRoot,
|
|
@@ -50,13 +60,14 @@ export async function prepareNodeWorkspaceCarrierManufacturingInput(input = {},
|
|
|
50
60
|
});
|
|
51
61
|
const runtimeSourceAlignment = await qualifyToolingRuntimeSourceAlignment({
|
|
52
62
|
runtimeIdentity: toolingBootstrap.runtimeIdentity,
|
|
53
|
-
localWorkspaces: enumerations.map((item) => Object.freeze({ id:
|
|
63
|
+
localWorkspaces: enumerations.map((item, index) => Object.freeze({ id: materializations[index].id, root: item.root, materialization: item.materialization })),
|
|
54
64
|
maxFiles: input.bootstrapMaxFiles || options.bootstrapMaxFiles
|
|
55
65
|
});
|
|
56
66
|
return Object.freeze({
|
|
57
67
|
carrierMode: 'workspace',
|
|
58
68
|
createdAt: String(input.createdAt || ''),
|
|
59
|
-
workspaceMaterializations: Object.freeze(
|
|
69
|
+
workspaceMaterializations: Object.freeze(materializations),
|
|
70
|
+
materialRepresentationWorkspaceIds: Object.freeze([...(input.materialRepresentationWorkspaceIds || input.genericMaterialWorkspaceIds || [])].map(String)),
|
|
60
71
|
workspaceTargets,
|
|
61
72
|
additionalTransportFiles: toolingBootstrap.files,
|
|
62
73
|
carrierLineage: normalizeHandoffCarrierLineage(input.carrierLineage || null),
|
|
@@ -16,7 +16,8 @@ export function auditPortableRecord(record = {}, options = {}) {
|
|
|
16
16
|
record,
|
|
17
17
|
markdown: record.markdown,
|
|
18
18
|
validationContractOverride: runtimeProjection?.state === 'qualified' ? runtimeProjection.compiledContract : null,
|
|
19
|
-
schemaValidationAuthority: requireExactSchemaAuthority ? runtimeAuthority : null
|
|
19
|
+
schemaValidationAuthority: requireExactSchemaAuthority ? runtimeAuthority : null,
|
|
20
|
+
schemaReferenceContext: options.schemaReferenceContext || 'historical'
|
|
20
21
|
});
|
|
21
22
|
} catch (error) {
|
|
22
23
|
const finding = portableFinding('error', 'portable.audit.exception', error?.message || 'Audit failed.', {
|
|
@@ -18,9 +18,9 @@ The same workflow must survive different host arrangements:
|
|
|
18
18
|
|
|
19
19
|
When this bootstrap or the portable repository is available as a project source, normalize only the explicitly uploaded Markdown, archive, and project-source material, then start with `discover-tooling` or `prepare-task`.
|
|
20
20
|
|
|
21
|
-
### Qualified
|
|
21
|
+
### Qualified Tiinex package
|
|
22
22
|
|
|
23
|
-
When a received carrier exposes the qualified recipient-facing Tiinex
|
|
23
|
+
When a received carrier exposes the qualified recipient-facing Tiinex package surface, start at its declared Start artifact (normally `001-1-READ-BEFORE-PROCEEDING.trace.md`). Before Tiinex Tooling is available, the host may perform only the bounded bootstrap exception: read the declared bootstrap node, extract `001-2-bootstrap.zip` into a writable runtime location, and make its Tooling entrypoint callable. Prefer a location that survives turns in the current runtime, but never treat that location as project or artifact authority. Do not manually unpack Workspace/cache payloads or perform broad ZIP/filesystem/repository archaeology. The Tooling entrypoint is exactly `runtime/tools/tiinex-portable.mjs` relative to the chosen extraction root; do not search/list the extracted runtime to discover it. Give the untouched original package carrier to that entrypoint and use `orient-handoff-package` as the first semantic operation. Package role is qualified from the carried package contract rather than inferred from filenames, Workspace/Role presence, or transport labels. A bootstrap-only or pointerless Workspace carrier has no Handoff route and must not be upgraded into recipient, holder, participation, delegation, current-work, or grounded-to-act authority; use the qualified route-less orientation/material projection only. For a routed Handoff carrier, keep the outer Continue-from path opaque to native access and, after orientation, use `ground <same-package.zip> --route <same-Continue-from>` as the one shared human/LLM decision-grounding path. Its bounded default receipt composes the selected Handoff authority, exact qualified Required Context identities, the selected-route declared-Parent leaf, a compact declared-Parent continuity-to-qualified-root proof, declared current-work frontier, blockers, and explicit unresolved evidence. Continue substantive bounded work only when `readiness.state` is `grounded-to-act`; `grounded-to-discuss` and `insufficient-grounding` must not be upgraded by generic inference. An apparent loaded root that still declares an unavailable Parent is not cold-start closure: follow `readiness.nextAction.recovery` exactly. If a bound exact repository-read host capability is available, use the projected `plan-host-action` request, normalize the host result through `accept-host-receipt`, then resume the same `ground` command with `--recovery <accepted-host-receipt.json>`; otherwise request exactly the named material from the Transport Operator. When an accepted pinned repository Parent declares a deterministic relative Parent, Tooling may derive only that exact sibling path from the accepted repository/commit/base-path context. For repeated recovery, call `accept-host-receipt --prior <previous-accepted.json>` so the newest accepted result explicitly carries all prior accepted recovery material; pass only that newest cumulative result back to the same `ground --recovery` seam. Never broaden search or treat fetched material as verified before lineage identity/integrity qualification. Re-run the same `ground` command with `--include-required-context <requirement-id,name|all>` only when exact qualified Required Context body text is needed. No external qualification schema, Tooling source inspection, `--help`/operation discovery, context-audit detour, or separate `ground-cold-consumer` call is required before this decision grounding. Native host tools remain valid execution mechanics after Tiinex takeover on already-resolved ordinary source, and explicit degraded fallback only when qualification explains why it was required.
|
|
24
24
|
|
|
25
25
|
### Bootstrap travels inside an archive
|
|
26
26
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sha256Hex, utf8Bytes } from '../../../export/package.bytes.js';
|
|
2
2
|
import { portableFinding, summarizePortableFindings } from '../findings.js';
|
|
3
|
+
import { portableSourceEligibilityPolicy, qualifyPortableSourcePath } from '../source/sourceEligibility.js';
|
|
3
4
|
|
|
4
5
|
export const PORTABLE_SOURCE_FRONTIER_SCHEMA_ID = 'tiinex.portable.source-frontier.v1';
|
|
5
6
|
export const PORTABLE_SOURCE_FRONTIER_COMPARISON_SCHEMA_ID = 'tiinex.portable.source-frontier-comparison.v1';
|
|
@@ -45,16 +46,34 @@ export function createPortableSourceFrontier(input = {}) {
|
|
|
45
46
|
workspaces: Object.freeze(workspaces),
|
|
46
47
|
findings: normalizedFindings,
|
|
47
48
|
findingSummary: summarizePortableFindings(normalizedFindings),
|
|
48
|
-
boundary: String(input.boundary || '
|
|
49
|
+
boundary: String(input.boundary || 'Eligible durable source-byte frontier only. Source-ineligible transport/runtime/cache bytes are outside frontier identity; Workspace/path equality does not establish semantic equivalence, authority, acceptance, deletion, or merge disposition.')
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
export function createPortableWorkspaceSnapshot(entries = [], evidence = {}) {
|
|
53
54
|
const findings = [];
|
|
54
|
-
const
|
|
55
|
+
const selection = normalizeEntries(entries, findings);
|
|
55
56
|
if (findings.length) return deepFreeze({ state: 'qualification-error', entries: Object.freeze([]), findings: Object.freeze(findings) });
|
|
57
|
+
const normalized = selection.entries;
|
|
56
58
|
const totalBytes = normalized.reduce((sum, entry) => sum + entry.bytes, 0);
|
|
57
59
|
const fingerprint = snapshotFingerprint(normalized);
|
|
60
|
+
const inheritedEvidence = serializableObject(evidence);
|
|
61
|
+
const priorEligibility = inheritedEvidence?.sourceEligibility && typeof inheritedEvidence.sourceEligibility === 'object'
|
|
62
|
+
? inheritedEvidence.sourceEligibility
|
|
63
|
+
: null;
|
|
64
|
+
const upstreamSelection = priorEligibility?.upstreamSelection || (priorEligibility && Number(priorEligibility.excludedEntryCount || 0) > 0 ? portableSourceSelectionReceipt(priorEligibility) : null);
|
|
65
|
+
const sourceEligibility = Object.freeze({
|
|
66
|
+
schema: selection.policy.schema,
|
|
67
|
+
inputEntryCount: selection.inputEntryCount,
|
|
68
|
+
eligibleEntryCount: normalized.length,
|
|
69
|
+
excludedEntryCount: selection.excludedEntryCount,
|
|
70
|
+
excludedByReason: Object.freeze({ ...selection.excludedByReason }),
|
|
71
|
+
excludedDirectories: selection.policy.excludedDirectories,
|
|
72
|
+
excludedRelativePaths: selection.policy.excludedRelativePaths,
|
|
73
|
+
excludedFileSuffixes: selection.policy.excludedFileSuffixes,
|
|
74
|
+
...(upstreamSelection ? { upstreamSelection: Object.freeze(upstreamSelection) } : {}),
|
|
75
|
+
boundary: selection.policy.boundary
|
|
76
|
+
});
|
|
58
77
|
return deepFreeze({
|
|
59
78
|
state: QUALIFIED,
|
|
60
79
|
entryCount: normalized.length,
|
|
@@ -62,7 +81,7 @@ export function createPortableWorkspaceSnapshot(entries = [], evidence = {}) {
|
|
|
62
81
|
fingerprint,
|
|
63
82
|
fingerprintMethod: 'sha256-path-bytes-sha256-v1',
|
|
64
83
|
entries: Object.freeze(normalized),
|
|
65
|
-
evidence: Object.freeze(
|
|
84
|
+
evidence: Object.freeze({ ...inheritedEvidence, sourceEligibility }),
|
|
66
85
|
findings: Object.freeze([])
|
|
67
86
|
});
|
|
68
87
|
}
|
|
@@ -181,13 +200,28 @@ function normalizeWorkspace(raw, workspaceId, findings) {
|
|
|
181
200
|
function normalizeEntries(entries, findings) {
|
|
182
201
|
const out = [];
|
|
183
202
|
const seen = new Set();
|
|
203
|
+
const policy = portableSourceEligibilityPolicy();
|
|
204
|
+
const excludedByReason = {};
|
|
205
|
+
let inputEntryCount = 0;
|
|
206
|
+
let excludedEntryCount = 0;
|
|
184
207
|
for (const raw of entries || []) {
|
|
208
|
+
inputEntryCount += 1;
|
|
185
209
|
const rawPath = String(raw?.path || raw?.innerPath || '').trim();
|
|
186
210
|
const path = normalizePath(rawPath);
|
|
187
211
|
if (unsafeRawPath(rawPath) || !path || unsafePath(path)) {
|
|
188
212
|
findings.push(portableFinding('error', 'portable.source-frontier.entry.path-invalid', 'Comparable source entry has an unsafe or empty Workspace-relative path.', { path: rawPath }));
|
|
189
213
|
continue;
|
|
190
214
|
}
|
|
215
|
+
const eligibility = qualifyPortableSourcePath(path, {
|
|
216
|
+
excludeDirectories: policy.excludedDirectories,
|
|
217
|
+
excludeRelativePaths: policy.excludedRelativePaths,
|
|
218
|
+
entryKind: 'file'
|
|
219
|
+
});
|
|
220
|
+
if (!eligibility.eligible) {
|
|
221
|
+
excludedEntryCount += 1;
|
|
222
|
+
excludedByReason[eligibility.reason] = Number(excludedByReason[eligibility.reason] || 0) + 1;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
191
225
|
if (seen.has(path)) {
|
|
192
226
|
findings.push(portableFinding('error', 'portable.source-frontier.entry.path-duplicate', 'Comparable source snapshot contains a duplicate normalized path.', { path }));
|
|
193
227
|
continue;
|
|
@@ -202,7 +236,23 @@ function normalizeEntries(entries, findings) {
|
|
|
202
236
|
out.push(Object.freeze({ path, bytes, sha256 }));
|
|
203
237
|
}
|
|
204
238
|
out.sort((a, b) => a.path.localeCompare(b.path));
|
|
205
|
-
return
|
|
239
|
+
return Object.freeze({
|
|
240
|
+
entries: Object.freeze(out),
|
|
241
|
+
policy,
|
|
242
|
+
inputEntryCount,
|
|
243
|
+
excludedEntryCount,
|
|
244
|
+
excludedByReason: Object.freeze(Object.fromEntries(Object.entries(excludedByReason).sort(([a], [b]) => a.localeCompare(b))))
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function portableSourceSelectionReceipt(value = {}) {
|
|
249
|
+
return {
|
|
250
|
+
schema: String(value.schema || ''),
|
|
251
|
+
inputEntryCount: Number(value.inputEntryCount || 0),
|
|
252
|
+
eligibleEntryCount: Number(value.eligibleEntryCount || 0),
|
|
253
|
+
excludedEntryCount: Number(value.excludedEntryCount || 0),
|
|
254
|
+
excludedByReason: Object.freeze({ ...serializableObject(value.excludedByReason || {}) })
|
|
255
|
+
};
|
|
206
256
|
}
|
|
207
257
|
|
|
208
258
|
function compareWorkspaceUnion(left, right) {
|