先提交到云仓库

结论:已提交当前 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

@@ -58,6 +58,19 @@ const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadF
manifestText: sourceManifestText,
});
const virtualHalState = createVirtualHalState();
const pythonRemapRuntimeProof = {
nativeLifecycleReady: true,
nativeProbeStatus: "runtime_lifecycle_probe_passed",
nativeProofArtifactPath: "wasm-port/build/native/native-runtime-probe-summary.tsv",
wasmLifecycleReady: true,
browserLifecycleReady: true,
interpreterStateBindingReady: true,
generatorLifecycleReady: true,
promotionAllowed: false,
executionEnabled: false,
bulkPromotionAllowed: false,
manualLockUpdateRequired: true,
};
const browserDiagnosticsArtifact = {
apiName: "real-browser-simulation-diagnostics-artifact",
artifactVersion: 1,
@@ -113,6 +126,7 @@ const readyArtifactJson = JSON.stringify(createProjectReleaseReadinessReport({
evidenceExpansionRows,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix: browserDiagnosticsArtifact.virtualHalMotionControllerMatrix,
pythonRemapRuntimeProof,
}));
let fetchedUrl = null;
@@ -380,6 +394,8 @@ assert.deepEqual(
["hard-block-runtime-family-L4-PYTHON-REMAP-paths", "axis/laser/raster_test.ngc, axis/laser/vector_test.ngc, axis/laser/vector_test2.ngc, axis/remap/cycle/nc_files/examples.ngc, axis/remap/extend-builtins/nc_files/examples.ngc, axis/remap/getting-started/nc_files/examples.ngc, axis/remap/manual-toolchange-with-tool-length-switch/nc_files/tcdemo.ngc, axis/remap/rack-toolchange/nc_files/tcdemo.ngc, axis/remap/stop-lookahead/nc_files/examples.ngc, axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/circular_pocket.ngc, axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_back_and_forth.ngc, axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition.ngc, axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/simple_example.ngc, axis/vismach/VMC_toolchange/toolchange.ngc, gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzac.ngc, gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzbc.ngc, gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc"],
["tool-db-process-proof", "ready"],
["tool-db-process-proof-detail", "wasm=ready browser=ready opfs=ready promotion_allowed=0"],
["python-remap-runtime-proof", "ready"],
["python-remap-runtime-proof-detail", "native=ready wasm=ready browser=ready promotion_allowed=0"],
...expectedPromotionFamilyRows,
["browser-diagnostics", "ready"],
["virtual-hal-promotion-candidate-summary", "ready"],

View File

@@ -31,6 +31,19 @@ const virtualHalSimConfigPromotionCandidates = createVirtualHalSimConfigPromotio
motionControllerMatrix: virtualHalMotionControllerMatrix,
});
const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixtureReport();
const pythonRemapRuntimeProof = {
nativeLifecycleReady: true,
nativeProbeStatus: "runtime_lifecycle_probe_passed",
nativeProofArtifactPath: "wasm-port/build/native/native-runtime-probe-summary.tsv",
wasmLifecycleReady: true,
browserLifecycleReady: true,
interpreterStateBindingReady: true,
generatorLifecycleReady: true,
promotionAllowed: false,
executionEnabled: false,
bulkPromotionAllowed: false,
manualLockUpdateRequired: true,
};
assert.equal(manifest.apiName, "project-release-gate-manifest");
assert.equal(manifest.manifestVersion, 1);
@@ -227,6 +240,7 @@ const report = createProjectReleaseReadinessReport({
virtualHalSimConfigPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix,
pythonRemapRuntimeProof,
});
assert.deepEqual(report.gateManifest, manifest);
assert.equal(report.gateExecutionManifest.apiName, "project-release-gate-execution-manifest");
@@ -324,6 +338,16 @@ assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), {
label: "Tool DB process proof detail",
value: "wasm=ready browser=ready opfs=ready promotion_allowed=0",
},
{
id: "python-remap-runtime-proof",
label: "Python remap runtime proof",
value: "ready",
},
{
id: "python-remap-runtime-proof-detail",
label: "Python remap runtime proof detail",
value: "native=ready wasm=ready browser=ready promotion_allowed=0",
},
{
id: "blocked-runtime-families",
label: "Blocked runtime families",
@@ -353,7 +377,7 @@ assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), {
});
assert.equal(
createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport()).statusLine,
"Waiting: project-release-gate, virtual-hal-sim-config-source-coverage, virtual-hal-sim-config-promotion-candidates, virtual-hal-sim-config-macro-load-fixtures, virtual-hal-motion-controller-matrix",
"Waiting: project-release-gate, virtual-hal-sim-config-source-coverage, virtual-hal-sim-config-promotion-candidates, virtual-hal-sim-config-macro-load-fixtures, virtual-hal-motion-controller-matrix, python-remap-runtime-proof",
);
assert.equal(
createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport({
@@ -362,6 +386,7 @@ assert.equal(
virtualHalSimConfigPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix,
pythonRemapRuntimeProof,
promotedRuntimeFamilies: ["L4-PYTHON-REMAP"],
})).rows.find(({ id }) => id === "blocked-runtime-families")?.value,
"promoted: L4-PYTHON-REMAP",
@@ -428,6 +453,8 @@ assert.deepEqual(
["virtual-hal-motion-controller-matrix", "ready"],
["tool-db-process-proof", "ready"],
["tool-db-process-proof-detail", "wasm=ready browser=ready opfs=ready promotion_allowed=0"],
["python-remap-runtime-proof", "ready"],
["python-remap-runtime-proof-detail", "native=ready wasm=ready browser=ready promotion_allowed=0"],
["missing", "none"],
],
);
@@ -548,6 +575,8 @@ assert.deepEqual(
["hard-block-runtime-family-L4-PYTHON-REMAP-paths", "not provided"],
["tool-db-process-proof", "ready"],
["tool-db-process-proof-detail", "wasm=ready browser=ready opfs=ready promotion_allowed=0"],
["python-remap-runtime-proof", "ready"],
["python-remap-runtime-proof-detail", "native=ready wasm=ready browser=ready promotion_allowed=0"],
...expectedPromotionFamilyRows,
["browser-diagnostics", "not requested"],
["virtual-hal-promotion-candidate-summary", "not requested"],

View File

@@ -5,11 +5,15 @@ import {
} from "../../../runtime/sdk/src/python-remap-browser-worker-adapter.js";
import {
PYTHON_REMAP_RUNTIME_PORT_CONTRACT_VERSION,
PYTHON_REMAP_ROW_RUNTIME_PROOF_PHASES,
PYTHON_REMAP_STOP_LOOKAHEAD_FIXTURE,
createLinuxCncPythonRemapRowRuntimePort,
createLinuxCncPythonRemapRuntimePort,
createPythonRemapLifecyclePlan,
createPythonRemapRowRuntimePlan,
createPythonRemapRuntimeDiagnostics,
validatePythonRemapLifecycleTranscript,
validatePythonRemapRowRuntimeTranscript,
} from "../../../runtime/sdk/src/python-remap-runtime-port.js";
assert.equal(PYTHON_REMAP_RUNTIME_PORT_CONTRACT_VERSION, 1);
@@ -31,6 +35,133 @@ assert.deepEqual(
"export_diagnostics",
],
);
assert.ok(PYTHON_REMAP_ROW_RUNTIME_PROOF_PHASES.includes("export_canonical_events"));
const rowRuntimeContext = {
path: "axis/remap/cycle/nc_files/examples.ngc",
iniPath: "axis/remap/cycle/cycle.ini",
family: "axis/remap/cycle/nc_files",
machineRoot: "axis/remap/cycle",
pythonPathPrepend: "python",
topLevelPath: "python/toplevel.py",
sourceFiles: [
"axis/nc_files/remap_lib/python-stdglue/stdglue.py",
"axis/remap/cycle/python/remap.py",
"axis/remap/cycle/python/toplevel.py",
],
remapDeclarations: ["G84.2"],
pythonRemapFunctions: ["g842@axis/remap/cycle/python/remap.py"],
prologFunctions: ["cycle_prolog@axis/nc_files/remap_lib/python-stdglue/stdglue.py"],
epilogFunctions: ["cycle_epilog@axis/nc_files/remap_lib/python-stdglue/stdglue.py"],
ngcRemapFiles: ["axis/remap/cycle/nc_subroutines/g843.ngc"],
ngcOnlySubpaths: [],
};
const rowPlan = createPythonRemapRowRuntimePlan(rowRuntimeContext);
assert.equal(rowPlan.filter((step) => step.phase === "import_module").length, 3);
assert.equal(rowPlan.filter((step) => step.phase === "callable_lookup").length, 3);
assert.equal(rowPlan.filter((step) => step.phase === "stage_ngc_remap_asset").length, 1);
assert.ok(rowPlan.some((step) => step.phase === "export_canonical_events"));
const contractOnlyRowPort = createLinuxCncPythonRemapRowRuntimePort(rowRuntimeContext);
const contractOnlyRowStart = await contractOnlyRowPort.start();
assert.deepEqual(contractOnlyRowStart, {
runtimeMode: "row-runtime-contract-only",
runtimeExecutionReady: false,
status: null,
executionEnabled: false,
promotionAllowed: false,
bulkPromotionAllowed: false,
});
const contractOnlyRowPlan = await contractOnlyRowPort.runRowRuntimePlan();
assert.equal(contractOnlyRowPlan.status, "blocked_row_runtime_adapter_required");
assert.equal(contractOnlyRowPlan.promotionAllowed, false);
await contractOnlyRowPort.close();
const fakeRowAdapter = {
async start(context) {
assert.equal(context.path, rowRuntimeContext.path);
assert.equal(context.sourceFiles.length, 3);
assert.equal(context.ngcRemapFiles.length, 1);
return {
runtimeExecutionReady: true,
status: "row_runtime_ready",
};
},
async initializePython() {
return { value: "python-runtime-initialized" };
},
async applyIniPythonPath(payload) {
return { value: payload.pythonPathPrepend };
},
async executeTopLevel(payload) {
return { value: payload.topLevelPath };
},
async importModule(payload) {
return { value: payload.modulePath };
},
async lookupCallable(payload) {
return { value: payload.callableName };
},
async invokeGenerator(payload) {
return { value: `generator:${payload.callableName}` };
},
async observeFirstYield(payload) {
return { value: `yield:${payload.callableName}` };
},
async finishGenerator(payload) {
return { value: `finish:${payload.callableName}` };
},
async stageNgcRemapAsset(payload) {
return { value: payload.ngcPath };
},
async rejectNgcOnlyStandalone(payload) {
return { value: payload.ngcPath };
},
async exportInterpreterState() {
return { value: "interpreter-state-bound" };
},
async exportCanonicalEvents() {
return { value: "canonical-events-bound" };
},
async exportDiagnostics() {
return { value: "diagnostics-exported" };
},
};
const readyRowPort = createLinuxCncPythonRemapRowRuntimePort({
...rowRuntimeContext,
runtimeMode: "row-runtime-test-adapter",
runtimeAdapter: fakeRowAdapter,
});
const readyRowStart = await readyRowPort.start();
assert.equal(readyRowStart.runtimeExecutionReady, true);
assert.equal(readyRowStart.status, "row_runtime_ready");
const readyRowPlan = await readyRowPort.runRowRuntimePlan();
assert.equal(readyRowPlan.status, "row_runtime_adapter_plan_executed");
assert.equal(readyRowPlan.validation.ready, true);
assert.equal(readyRowPlan.validation.moduleImportReady, true);
assert.equal(readyRowPlan.validation.callableLookupReady, true);
assert.equal(readyRowPlan.validation.generatorLifecycleReady, true);
assert.equal(readyRowPlan.validation.ngcRemapAssetsReady, true);
assert.equal(readyRowPlan.validation.ngcOnlySubpathsGuarded, true);
assert.equal(readyRowPlan.validation.interpreterStateBindingReady, true);
assert.equal(readyRowPlan.validation.canonicalEventsReady, true);
assert.equal(readyRowPlan.promotionAllowed, false);
assert.equal(readyRowPlan.bulkPromotionAllowed, false);
const rowTranscript = readyRowPort.exportTranscript();
const rowValidation = validatePythonRemapRowRuntimeTranscript({
...rowRuntimeContext,
rowPath: rowRuntimeContext.path,
transcript: rowTranscript,
});
assert.equal(rowValidation.ready, true);
const rowDiagnostics = readyRowPort.exportDiagnostics();
assert.equal(rowDiagnostics.rowRuntimeTranscriptReady, true);
assert.equal(rowDiagnostics.jsCncSemantics, false);
assert.equal(rowDiagnostics.ngcOnlySubroutinePromoted, false);
assert.equal(rowDiagnostics.executionEnabled, false);
assert.equal(rowDiagnostics.promotionAllowed, false);
assert.equal(rowDiagnostics.bulkPromotionAllowed, false);
await readyRowPort.close();
const contractOnlyPort = createLinuxCncPythonRemapRuntimePort({
runtimeMode: "contract-only",
@@ -209,3 +340,12 @@ const explicitDiagnostics = createPythonRemapRuntimeDiagnostics({
});
assert.equal(explicitDiagnostics.transcriptHash.length, 8);
assert.equal(explicitDiagnostics.lifecycleTranscriptReady, true);
const mismatchedTranscript = transcript.map((entry) =>
entry.phase === "execute_toplevel"
? { ...entry, value: "python/not-toplevel.py" }
: entry
);
const mismatchedValidation = validatePythonRemapLifecycleTranscript(mismatchedTranscript);
assert.equal(mismatchedValidation.ready, false);
assert.deepEqual(mismatchedValidation.mismatchedValues, ["execute_toplevel"]);

View File

@@ -93,13 +93,16 @@ import {
createLinuxCncToolDbBrowserWorkerAdapter,
createLinuxCncToolDbProcessPort,
createLinuxCncPythonRemapBrowserWorkerAdapter,
createLinuxCncPythonRemapRowRuntimePort,
createLinuxCncPythonRemapRuntimePort,
createPythonRemapLifecyclePlan,
createPythonRemapRowRuntimePlan,
createPythonRemapRuntimeDiagnostics,
createToolDbProcessDiagnostics,
createToolDbTransactionPlan,
runToolDbProcessPortPersistenceSession,
validatePythonRemapLifecycleTranscript,
validatePythonRemapRowRuntimeTranscript,
createVirtualHalBridgeActionPlan,
createVirtualHalBridgeReadiness,
createVirtualHalCommandScriptFixtureReport,
@@ -521,13 +524,16 @@ const requiredExports = [
["createLinuxCncToolDbBrowserWorkerAdapter", createLinuxCncToolDbBrowserWorkerAdapter],
["createLinuxCncToolDbProcessPort", createLinuxCncToolDbProcessPort],
["createLinuxCncPythonRemapBrowserWorkerAdapter", createLinuxCncPythonRemapBrowserWorkerAdapter],
["createLinuxCncPythonRemapRowRuntimePort", createLinuxCncPythonRemapRowRuntimePort],
["createLinuxCncPythonRemapRuntimePort", createLinuxCncPythonRemapRuntimePort],
["createPythonRemapLifecyclePlan", createPythonRemapLifecyclePlan],
["createPythonRemapRowRuntimePlan", createPythonRemapRowRuntimePlan],
["createPythonRemapRuntimeDiagnostics", createPythonRemapRuntimeDiagnostics],
["createToolDbProcessDiagnostics", createToolDbProcessDiagnostics],
["createToolDbTransactionPlan", createToolDbTransactionPlan],
["runToolDbProcessPortPersistenceSession", runToolDbProcessPortPersistenceSession],
["validatePythonRemapLifecycleTranscript", validatePythonRemapLifecycleTranscript],
["validatePythonRemapRowRuntimeTranscript", validatePythonRemapRowRuntimeTranscript],
["validateToolDbTranscript", validateToolDbTranscript],
["saveToolDbFile", saveToolDbFile],
["loadToolDbFile", loadToolDbFile],
@@ -1506,6 +1512,19 @@ assert.equal(normalizeOpfsPath("linuxcnc/machines/sdk-mill/tool.tbl"), "linuxcnc
assert.equal(gcodeFilenameFromProgramPath("linuxcnc/gcode/demo.ngc"), "demo.ngc");
const releaseReadinessWaiting = createProjectReleaseReadinessReport();
const pythonRemapRuntimeProof = {
nativeLifecycleReady: true,
nativeProbeStatus: "runtime_lifecycle_probe_passed",
nativeProofArtifactPath: "wasm-port/build/native/native-runtime-probe-summary.tsv",
wasmLifecycleReady: true,
browserLifecycleReady: true,
interpreterStateBindingReady: true,
generatorLifecycleReady: true,
promotionAllowed: false,
executionEnabled: false,
bulkPromotionAllowed: false,
manualLockUpdateRequired: true,
};
const batchCapabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({
capabilities: [
{
@@ -1621,6 +1640,7 @@ assert.deepEqual(releaseReadinessWaiting.missing, [
"virtual-hal-sim-config-promotion-candidates",
"virtual-hal-sim-config-macro-load-fixtures",
"virtual-hal-motion-controller-matrix",
"python-remap-runtime-proof",
]);
assert.equal(releaseReadinessWaiting.simConfigInventory.unexpectedFail, 0);
assert.deepEqual(releaseReadinessWaiting.promotedBlockedFamilies, []);
@@ -1645,6 +1665,7 @@ const releaseReadinessReady = createProjectReleaseReadinessReport({
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
pythonRemapRuntimeProof,
});
assert.equal(releaseReadinessReady.ready, true);
assert.equal(releaseReadinessReady.releaseGate.passed, true);
@@ -1698,6 +1719,9 @@ const expectedToolDbProcessProofSummary = {
};
assert.deepEqual(releaseReadinessReady.toolDbProcessProofSummary, expectedToolDbProcessProofSummary);
assert.equal(releaseReadinessReady.toolDbProcessProofReady, true);
assert.equal(releaseReadinessReady.pythonRemapRuntimeProofReady, true);
assert.equal(releaseReadinessReady.pythonRemapRuntimeProofSummary.nativeLifecycleReady, true);
assert.equal(releaseReadinessReady.pythonRemapRuntimeProofSummary.promotionAllowed, false);
assert.deepEqual(releaseReadinessReady.gateManifest, createProjectReleaseGateManifest());
assert.equal(releaseReadinessReady.gateResultMatrix.rows.length, createProjectReleaseGateManifest().gateCount);
assert.equal(createProjectReleaseGateActionPlan({
@@ -1723,6 +1747,7 @@ const releaseReadinessWithCandidateArtifacts = createProjectReleaseReadinessRepo
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
promotionCandidateRows: promotionCandidateArtifactRows,
evidenceExpansionRows: evidenceExpansionArtifactRows,
pythonRemapRuntimeProof,
});
assert.equal(releaseReadinessWithCandidateArtifacts.promotionCandidateArtifactSummary.artifactRows.promotionCandidates, 27);
assert.equal(releaseReadinessWithCandidateArtifacts.promotionCandidateArtifactSummary.artifactRows.evidenceExpansion, 14);
@@ -1792,6 +1817,7 @@ const releaseReadinessWithScreenshots = createProjectReleaseReadinessReport({
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
pythonRemapRuntimeProof,
axisScreenshotArtifacts: ["desktop-preview", "desktop-dro", "mobile-preview", "mobile-mdi"].map((viewportName) => ({
apiName: "real-browser-simulation-axis-screenshot-artifact",
artifactVersion: 1,
@@ -1829,6 +1855,7 @@ const releaseReadinessArtifact = parseProjectReleaseReadinessArtifactJson(JSON.s
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
pythonRemapRuntimeProof,
})));
assert.equal(releaseReadinessArtifact.apiName, "project-release-readiness-report");
const releaseReadinessArtifactValidation = createProjectReleaseReadinessArtifactValidation(releaseReadinessArtifact);
@@ -1858,6 +1885,39 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
virtualHalMotionControllerMatrixReady: true,
toolDbProcessProofSummary: expectedToolDbProcessProofSummary,
toolDbProcessProofReady: true,
pythonRemapRuntimeProofSummary: {
apiName: "python-remap-runtime-proof-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
boundaryClass: "L4-PYTHON-REMAP",
fixtureFamily: "axis/remap/stop-lookahead/nc_files",
fixtureId: "stop_lookahead_python_runtime_lifecycle",
iniPath: "axis/remap/stop-lookahead/demo.ini",
pythonPathPrepend: "python",
topLevelPath: "python/toplevel.py",
callableName: "queuebuster",
runtimeMode: "browser-python-wasm-worker",
nativeProbeStatus: "runtime_lifecycle_probe_passed",
nativeProofArtifactPath: "wasm-port/build/native/native-runtime-probe-summary.tsv",
nativeProofStdoutLog: null,
nativeLifecycleReady: true,
wasmLifecycleReady: true,
browserLifecycleReady: true,
interpreterStateBindingReady: true,
generatorLifecycleReady: true,
promotionAllowed: false,
executionEnabled: false,
bulkPromotionAllowed: false,
manualLockUpdateRequired: true,
requiredCommands: [
"ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1 wasm-port/tests/native/probe_python_remap_runtime.sh",
"wasm-port/tests/sdk/node/verify_python_remap_runtime_port.sh",
"SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_python_remap_runtime_port_wasm.sh",
"SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_python_remap_runtime_browser.sh",
],
},
pythonRemapRuntimeProofReady: true,
axisScreenshotArtifactSummaryReady: true,
axisScreenshotArtifactCount: 0,
blockedRuntimeFamilies: [
@@ -1993,6 +2053,16 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
label: "Tool DB process proof detail",
value: "wasm=ready browser=ready opfs=ready promotion_allowed=0",
},
{
id: "python-remap-runtime-proof",
label: "Python remap runtime proof",
value: "ready",
},
{
id: "python-remap-runtime-proof-detail",
label: "Python remap runtime proof detail",
value: "native=ready wasm=ready browser=ready promotion_allowed=0",
},
{
id: "blocked-runtime-families",
label: "Blocked runtime families",