先提交到云仓库

结论:已提交当前 Python-remap proof 链路、runtime/browser/UI/docs 相关变更;保持 L4-PYTHON-REMAP inventory baseline 不直接批量 PASS。
This commit is contained in:
2026-06-20 00:06:10 +08:00
parent fbf9dade9c
commit ac52b48d62
36 changed files with 4388 additions and 240 deletions

View File

@@ -27,6 +27,22 @@ export const PYTHON_REMAP_LIFECYCLE_PLAN = [
{ phase: "export_diagnostics", method: "exportDiagnostics" },
];
export const PYTHON_REMAP_ROW_RUNTIME_PROOF_PHASES = Object.freeze([
"initialize_python",
"apply_ini_python_path",
"execute_toplevel",
"import_module",
"callable_lookup",
"callable_invoke",
"remap_phase_dispatch",
"generator_finish",
"stage_ngc_remap_asset",
"reject_ngc_only_standalone",
"export_interpreter_state",
"export_canonical_events",
"export_diagnostics",
]);
function requireString(value, label) {
if (typeof value !== "string" || value.length === 0) {
throw new Error(`${label} must be a non-empty string.`);
@@ -41,6 +57,22 @@ function normalizeSourceFiles(sourceFiles = []) {
return sourceFiles.map((sourceFile) => requireString(sourceFile, "source file"));
}
function normalizeStringList(values = [], label = "value") {
if (values === "-" || values === null || values === undefined) {
return [];
}
if (!Array.isArray(values)) {
throw new Error(`${label} must be an array.`);
}
return values
.filter((value) => value !== "-")
.map((value) => requireString(value, label));
}
function callableNameFromSpec(callableSpec) {
return requireString(callableSpec, "callable").split("@")[0];
}
function stableTextHash(text) {
let hash = 0x811c9dc5;
for (let index = 0; index < text.length; index += 1) {
@@ -70,10 +102,95 @@ function normalizeLifecycleResult(phase, result = {}) {
};
}
function defaultRowRuntimePlan({
sourceFiles,
pythonRemapFunctions,
prologFunctions,
epilogFunctions,
ngcRemapFiles,
ngcOnlySubpaths,
}) {
const callables = [
...pythonRemapFunctions,
...prologFunctions,
...epilogFunctions,
];
return [
{ phase: "initialize_python", method: "initializePython" },
{ phase: "apply_ini_python_path", method: "applyIniPythonPath" },
{ phase: "execute_toplevel", method: "executeTopLevel" },
...sourceFiles.map((modulePath) => ({
phase: "import_module",
method: "importModule",
modulePath,
})),
...callables.flatMap((callableSpec) => {
const callableName = callableNameFromSpec(callableSpec);
return [
{
phase: "callable_lookup",
method: "lookupCallable",
callableName,
callableSpec,
},
{
phase: "callable_invoke",
method: "invokeGenerator",
callableName,
callableSpec,
},
{
phase: "remap_phase_dispatch",
method: "observeFirstYield",
callableName,
callableSpec,
},
{
phase: "generator_finish",
method: "finishGenerator",
callableName,
callableSpec,
},
];
}),
...ngcRemapFiles.map((ngcPath) => ({
phase: "stage_ngc_remap_asset",
method: "stageNgcRemapAsset",
ngcPath,
})),
...ngcOnlySubpaths.map((ngcPath) => ({
phase: "reject_ngc_only_standalone",
method: "rejectNgcOnlyStandalone",
ngcPath,
})),
{ phase: "export_interpreter_state", method: "exportInterpreterState" },
{ phase: "export_canonical_events", method: "exportCanonicalEvents" },
{ phase: "export_diagnostics", method: "exportDiagnostics" },
];
}
export function createPythonRemapLifecyclePlan() {
return clonePlan(PYTHON_REMAP_LIFECYCLE_PLAN);
}
export function createPythonRemapRowRuntimePlan({
sourceFiles = [],
pythonRemapFunctions = [],
prologFunctions = [],
epilogFunctions = [],
ngcRemapFiles = [],
ngcOnlySubpaths = [],
} = {}) {
return clonePlan(defaultRowRuntimePlan({
sourceFiles: normalizeStringList(sourceFiles, "source file"),
pythonRemapFunctions: normalizeStringList(pythonRemapFunctions, "Python remap function"),
prologFunctions: normalizeStringList(prologFunctions, "prolog function"),
epilogFunctions: normalizeStringList(epilogFunctions, "epilog function"),
ngcRemapFiles: normalizeStringList(ngcRemapFiles, "NGC remap file"),
ngcOnlySubpaths: normalizeStringList(ngcOnlySubpaths, "NGC-only subpath"),
}));
}
export function validatePythonRemapLifecycleTranscript(transcript) {
if (!Array.isArray(transcript)) {
throw new Error("transcript must be an array.");
@@ -85,11 +202,21 @@ export function validatePythonRemapLifecycleTranscript(transcript) {
.filter((entry) => entry?.ready === false || entry?.status === "blocked" || entry?.status === "failed")
.map((entry) => entry.phase);
const firstYield = byPhase.get("remap_phase_dispatch")?.value ?? null;
const expectedValues = {
apply_ini_python_path: PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.pythonPathPrepend,
execute_toplevel: PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.topLevelPath,
import_module: "python/remap.py",
callable_lookup: PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.callableName,
};
const mismatchedValues = Object.entries(expectedValues)
.filter(([phase, expectedValue]) => byPhase.get(phase)?.value !== expectedValue)
.map(([phase]) => phase);
const hasInterpreterState = byPhase.has("export_interpreter_state");
const hasDiagnostics = byPhase.has("export_diagnostics");
const ready = (
missingPhases.length === 0 &&
failedPhases.length === 0 &&
mismatchedValues.length === 0 &&
Number(firstYield) === PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.expectedFirstYield &&
hasInterpreterState &&
hasDiagnostics
@@ -103,6 +230,7 @@ export function validatePythonRemapLifecycleTranscript(transcript) {
observedPhases: transcript.map((entry) => entry.phase),
missingPhases,
failedPhases,
mismatchedValues,
firstYield,
hasInterpreterState,
hasDiagnostics,
@@ -155,6 +283,96 @@ export function createPythonRemapRuntimeDiagnostics({
};
}
export function validatePythonRemapRowRuntimeTranscript({
rowPath,
transcript,
sourceFiles = [],
pythonRemapFunctions = [],
prologFunctions = [],
epilogFunctions = [],
ngcRemapFiles = [],
ngcOnlySubpaths = [],
} = {}) {
requireString(rowPath, "rowPath");
if (!Array.isArray(transcript)) {
throw new Error("transcript must be an array.");
}
const expectedPlan = createPythonRemapRowRuntimePlan({
sourceFiles,
pythonRemapFunctions,
prologFunctions,
epilogFunctions,
ngcRemapFiles,
ngcOnlySubpaths,
});
const expectedPhases = expectedPlan.map((step) => step.phase);
const observedPhases = transcript.map((entry) => entry.phase);
const phaseCounts = new Map();
for (const phase of observedPhases) {
phaseCounts.set(phase, (phaseCounts.get(phase) ?? 0) + 1);
}
const failedPhases = transcript
.filter((entry) => entry?.ready === false || entry?.status === "blocked" || entry?.status === "failed")
.map((entry) => entry.phase);
const missingPhases = [...new Set(expectedPhases)].filter((phase) => !phaseCounts.has(phase));
const expectedModuleCount = normalizeStringList(sourceFiles, "source file").length;
const expectedCallableCount = [
...normalizeStringList(pythonRemapFunctions, "Python remap function"),
...normalizeStringList(prologFunctions, "prolog function"),
...normalizeStringList(epilogFunctions, "epilog function"),
].length;
const expectedNgcRemapCount = normalizeStringList(ngcRemapFiles, "NGC remap file").length;
const expectedNgcOnlyCount = normalizeStringList(ngcOnlySubpaths, "NGC-only subpath").length;
const countDrift = [
["import_module", expectedModuleCount],
["callable_lookup", expectedCallableCount],
["callable_invoke", expectedCallableCount],
["remap_phase_dispatch", expectedCallableCount],
["generator_finish", expectedCallableCount],
["stage_ngc_remap_asset", expectedNgcRemapCount],
["reject_ngc_only_standalone", expectedNgcOnlyCount],
].filter(([phase, expectedCount]) => (phaseCounts.get(phase) ?? 0) !== expectedCount)
.map(([phase]) => phase);
const hasInterpreterState = phaseCounts.has("export_interpreter_state");
const hasCanonicalEvents = phaseCounts.has("export_canonical_events");
const hasDiagnostics = phaseCounts.has("export_diagnostics");
const ready = (
missingPhases.length === 0 &&
failedPhases.length === 0 &&
countDrift.length === 0 &&
hasInterpreterState &&
hasCanonicalEvents &&
hasDiagnostics
);
return {
contractVersion: PYTHON_REMAP_RUNTIME_PORT_CONTRACT_VERSION,
rowPath,
requiredPhases: [...new Set(expectedPhases)],
observedPhases,
missingPhases,
failedPhases,
countDrift,
moduleImportReady: (phaseCounts.get("import_module") ?? 0) === expectedModuleCount,
callableLookupReady: (phaseCounts.get("callable_lookup") ?? 0) === expectedCallableCount,
generatorLifecycleReady: (
(phaseCounts.get("callable_invoke") ?? 0) === expectedCallableCount &&
(phaseCounts.get("remap_phase_dispatch") ?? 0) === expectedCallableCount &&
(phaseCounts.get("generator_finish") ?? 0) === expectedCallableCount
),
ngcRemapAssetsReady: (phaseCounts.get("stage_ngc_remap_asset") ?? 0) === expectedNgcRemapCount,
ngcOnlySubpathsGuarded: (phaseCounts.get("reject_ngc_only_standalone") ?? 0) === expectedNgcOnlyCount,
interpreterStateBindingReady: hasInterpreterState,
canonicalEventsReady: hasCanonicalEvents,
diagnosticsReady: hasDiagnostics,
rowRuntimeTranscriptReady: ready,
ready,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
}
export function createLinuxCncPythonRemapRuntimePort({
fixtureFamily = PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.fixtureFamily,
iniPath = PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE.iniPath,
@@ -348,3 +566,241 @@ export function createLinuxCncPythonRemapRuntimePort({
},
};
}
export function createLinuxCncPythonRemapRowRuntimePort({
path,
iniPath,
family = null,
machineRoot = "",
pythonPathPrepend = "-",
topLevelPath = "-",
sourceFiles = [],
remapDeclarations = [],
pythonRemapFunctions = [],
prologFunctions = [],
epilogFunctions = [],
ngcRemapFiles = [],
ngcOnlySubpaths = [],
runtimeMode = "row-runtime-contract-only",
runtimeAdapter = null,
} = {}) {
requireString(path, "path");
requireString(iniPath, "iniPath");
const normalizedFamily = family ?? path.split("/").slice(0, -1).join("/");
requireString(normalizedFamily, "family");
const normalizedMachineRoot = machineRoot === "-" ? "" : String(machineRoot ?? "");
const normalizedPythonPathPrepend = pythonPathPrepend === "-" ? "" : String(pythonPathPrepend ?? "");
const normalizedTopLevelPath = topLevelPath === "-" ? "" : String(topLevelPath ?? "");
const normalizedSourceFiles = normalizeStringList(sourceFiles, "source file");
const normalizedRemapDeclarations = normalizeStringList(remapDeclarations, "remap declaration");
const normalizedPythonRemapFunctions = normalizeStringList(pythonRemapFunctions, "Python remap function");
const normalizedPrologFunctions = normalizeStringList(prologFunctions, "prolog function");
const normalizedEpilogFunctions = normalizeStringList(epilogFunctions, "epilog function");
const normalizedNgcRemapFiles = normalizeStringList(ngcRemapFiles, "NGC remap file");
const normalizedNgcOnlySubpaths = normalizeStringList(ngcOnlySubpaths, "NGC-only subpath");
const transcript = [];
let started = false;
let closed = false;
let runtimeExecutionReady = false;
let startStatus = null;
function assertOpen() {
if (closed) {
throw new Error("PythonRemapRowRuntimePort is closed.");
}
}
async function callAdapterMethod(method, payload = {}) {
if (!runtimeAdapter?.[method]) {
return normalizeLifecycleResult(payload.phase ?? method, {
status: "blocked",
ready: false,
source: "missing-runtime-adapter-method",
});
}
return normalizeLifecycleResult(payload.phase ?? method, await runtimeAdapter[method](payload));
}
async function runStep(step) {
const payload = {
...step,
path,
iniPath,
family: normalizedFamily,
machineRoot: normalizedMachineRoot,
pythonPathPrepend: normalizedPythonPathPrepend,
topLevelPath: normalizedTopLevelPath,
sourceFiles: normalizedSourceFiles,
remapDeclarations: normalizedRemapDeclarations,
pythonRemapFunctions: normalizedPythonRemapFunctions,
prologFunctions: normalizedPrologFunctions,
epilogFunctions: normalizedEpilogFunctions,
ngcRemapFiles: normalizedNgcRemapFiles,
ngcOnlySubpaths: normalizedNgcOnlySubpaths,
};
const result = await callAdapterMethod(step.method, payload);
transcript.push(result);
return result;
}
function rowPlan() {
return createPythonRemapRowRuntimePlan({
sourceFiles: normalizedSourceFiles,
pythonRemapFunctions: normalizedPythonRemapFunctions,
prologFunctions: normalizedPrologFunctions,
epilogFunctions: normalizedEpilogFunctions,
ngcRemapFiles: normalizedNgcRemapFiles,
ngcOnlySubpaths: normalizedNgcOnlySubpaths,
});
}
function validation() {
return validatePythonRemapRowRuntimeTranscript({
rowPath: path,
transcript,
sourceFiles: normalizedSourceFiles,
pythonRemapFunctions: normalizedPythonRemapFunctions,
prologFunctions: normalizedPrologFunctions,
epilogFunctions: normalizedEpilogFunctions,
ngcRemapFiles: normalizedNgcRemapFiles,
ngcOnlySubpaths: normalizedNgcOnlySubpaths,
});
}
return {
path,
iniPath,
family: normalizedFamily,
machineRoot: normalizedMachineRoot,
pythonPathPrepend: normalizedPythonPathPrepend,
topLevelPath: normalizedTopLevelPath,
sourceFiles: normalizedSourceFiles,
remapDeclarations: normalizedRemapDeclarations,
pythonRemapFunctions: normalizedPythonRemapFunctions,
prologFunctions: normalizedPrologFunctions,
epilogFunctions: normalizedEpilogFunctions,
ngcRemapFiles: normalizedNgcRemapFiles,
ngcOnlySubpaths: normalizedNgcOnlySubpaths,
runtimeMode,
createRowRuntimePlan: rowPlan,
async start() {
assertOpen();
started = true;
let adapterStartResult = {};
if (runtimeAdapter?.start) {
adapterStartResult = await runtimeAdapter.start({
path,
iniPath,
family: normalizedFamily,
machineRoot: normalizedMachineRoot,
pythonPathPrepend: normalizedPythonPathPrepend,
topLevelPath: normalizedTopLevelPath,
sourceFiles: normalizedSourceFiles,
remapDeclarations: normalizedRemapDeclarations,
pythonRemapFunctions: normalizedPythonRemapFunctions,
prologFunctions: normalizedPrologFunctions,
epilogFunctions: normalizedEpilogFunctions,
ngcRemapFiles: normalizedNgcRemapFiles,
ngcOnlySubpaths: normalizedNgcOnlySubpaths,
});
}
runtimeExecutionReady = adapterStartResult.runtimeExecutionReady === true;
startStatus = adapterStartResult.status ?? (runtimeExecutionReady ? "python_remap_row_runtime_adapter_started" : null);
return {
runtimeMode,
runtimeExecutionReady,
status: startStatus,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
},
async runRowRuntimePlan(plan = rowPlan()) {
assertOpen();
if (!started) {
throw new Error("PythonRemapRowRuntimePort must be started before runRowRuntimePlan().");
}
if (!runtimeAdapter || runtimeExecutionReady !== true) {
return {
status: runtimeAdapter ? (startStatus ?? "blocked_row_runtime_execution_not_ready") : "blocked_row_runtime_adapter_required",
plan: clonePlan(plan),
runtimeExecutionReady: false,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
}
for (const step of plan) {
await runStep(step);
}
return {
status: "row_runtime_adapter_plan_executed",
plan: clonePlan(plan),
transcript: this.exportTranscript(),
validation: validation(),
runtimeExecutionReady: true,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
},
exportTranscript() {
return transcript.map((entry) => ({ ...entry }));
},
exportDiagnostics() {
const rowValidation = validation();
return {
contractVersion: PYTHON_REMAP_RUNTIME_PORT_CONTRACT_VERSION,
runtimeMode,
runtimeExecutionReady,
path,
iniPath,
family: normalizedFamily,
machineRoot: normalizedMachineRoot,
pythonPathPrepend: normalizedPythonPathPrepend,
topLevelPath: normalizedTopLevelPath,
sourceFiles: [...normalizedSourceFiles],
remapDeclarations: [...normalizedRemapDeclarations],
pythonRemapFunctions: [...normalizedPythonRemapFunctions],
prologFunctions: [...normalizedPrologFunctions],
epilogFunctions: [...normalizedEpilogFunctions],
ngcRemapFiles: [...normalizedNgcRemapFiles],
ngcOnlySubpaths: [...normalizedNgcOnlySubpaths],
rowRuntimeTranscriptReady: rowValidation.rowRuntimeTranscriptReady,
moduleImportReady: rowValidation.moduleImportReady,
callableLookupReady: rowValidation.callableLookupReady,
generatorLifecycleReady: rowValidation.generatorLifecycleReady,
ngcRemapAssetsReady: rowValidation.ngcRemapAssetsReady,
ngcOnlySubpathsGuarded: rowValidation.ngcOnlySubpathsGuarded,
interpreterStateBindingReady: rowValidation.interpreterStateBindingReady,
canonicalEventsReady: rowValidation.canonicalEventsReady,
transcriptHash: stableTextHash(transcriptText(transcript)),
transcriptPhaseCount: transcript.length,
linuxCncOwnedLifecycle: true,
jsCncSemantics: false,
ngcOnlySubroutinePromoted: false,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
},
async close() {
if (runtimeAdapter?.close) {
await runtimeAdapter.close();
}
closed = true;
return {
closed,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
};
},
};
}