132 lines
8.6 KiB
JavaScript
132 lines
8.6 KiB
JavaScript
import { readFile, writeFile } from 'node:fs/promises'
|
|
import { resolve } from 'node:path'
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
|
const outputPath = resolve(root, 'config/freecad-active-work-queue.json')
|
|
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
|
|
const [gui, workflowPlan, composite, correlation, production, recoveredNaming] = await Promise.all([
|
|
load('.cache/freecad/reference-desktop-gui-commands.json'),
|
|
load('config/freecad-gui-workflow-plan.json'),
|
|
load('config/freecad-composite-history-elementmap-oracle.json'),
|
|
load('config/freecad-tsn-stage-correlation-oracle.json'),
|
|
load('config/chrome-freecad-naming-production-verification.json'),
|
|
load('config/freecad-recovered-naming-classification.json'),
|
|
])
|
|
|
|
const guiShardTasks = gui.guiCommands.mergedShards.map((shard, index) => ({
|
|
id: `ORA-GUI-SHARD-${String(index).padStart(3, '0')}`,
|
|
title: `Probe GUI command indexes [${shard.start}, ${shard.end})`,
|
|
status: 'completed',
|
|
dependencies: index === 0 ? ['ORA-GUI-SETUP-002'] : [`ORA-GUI-SHARD-${String(index - 1).padStart(3, '0')}`],
|
|
evidence: [shard.path, shard.sha256],
|
|
exit: `${shard.end - shard.start} commands have three native state observations`,
|
|
}))
|
|
const workflowTitles = [
|
|
'Select one GUI command family from the sensitivity report',
|
|
'Capture the native success workflow',
|
|
'Capture the native disabled workflow',
|
|
'Capture the native failure workflow',
|
|
'Capture the native cancel workflow',
|
|
'Capture recovery after failure or cancel',
|
|
'Update the exact blocker and focused checks',
|
|
]
|
|
const workflowProgress = new Map(workflowPlan.progress.map((entry) => [entry.taskId, entry]))
|
|
const workflowTasks = workflowTitles.map((title, index) => ({
|
|
id: `ORA-GUI-WF-${String(index).padStart(3, '0')}`,
|
|
title,
|
|
status: workflowProgress.get(`ORA-GUI-WF-${String(index).padStart(3, '0')}`).status,
|
|
dependencies: [index === 0 ? 'ORA-GUI-CONTEXT-001' : `ORA-GUI-WF-${String(index - 1).padStart(3, '0')}`],
|
|
...(index === 0 ? { family: workflowPlan.family.id, primaryCommand: workflowPlan.family.primaryCommand, exactTask: workflowPlan.family.primaryExactTask } : {}),
|
|
...(workflowProgress.get(`ORA-GUI-WF-${String(index).padStart(3, '0')}`).evidence.length > 0 ? { evidence: workflowProgress.get(`ORA-GUI-WF-${String(index).padStart(3, '0')}`).evidence } : {}),
|
|
exit: index === 0 ? 'one command family and its exact task are recorded' : 'one native workflow fixture and its focused assertion pass',
|
|
}))
|
|
const workflowClosed = workflowTasks.every((task) => task.status === 'completed')
|
|
const driftCases = composite.cases.filter((fixture) => fixture.mutation.metrics.namingRestorationDriftStages > 0)
|
|
const classifications = new Map(recoveredNaming.classifications.map((entry) => [entry.caseId, entry]))
|
|
if (classifications.size !== recoveredNaming.classifications.length) throw new Error('Recovered naming classifications contain duplicate cases.')
|
|
for (const entry of recoveredNaming.classifications) {
|
|
if (!driftCases.some(({ id }) => id === entry.caseId) || !['stable_semantics', 'allowed_evolution', 'implementation_defect'].includes(entry.classification)) throw new Error(`Recovered naming classification ${entry.caseId} is invalid.`)
|
|
}
|
|
const classifiedPrefix = driftCases.findIndex(({ id }) => !classifications.has(id))
|
|
const completedDriftCases = classifiedPrefix < 0 ? driftCases.length : classifiedPrefix
|
|
if (driftCases.slice(completedDriftCases).some(({ id }) => classifications.has(id))) throw new Error('Recovered naming classifications must form a contiguous serial prefix.')
|
|
const driftTasks = driftCases.map((fixture, index) => ({
|
|
id: `TSN-DRIFT-${String(index).padStart(3, '0')}`,
|
|
title: `Classify recovered naming evolution for ${fixture.id}`,
|
|
status: index < completedDriftCases ? 'completed' : workflowClosed && index === completedDriftCases ? 'in_progress' : 'pending',
|
|
dependencies: index === 0 ? ['ORA-GUI-WF-006'] : [`TSN-DRIFT-${String(index - 1).padStart(3, '0')}`],
|
|
caseId: fixture.id,
|
|
driftStages: fixture.mutation.metrics.namingRestorationDriftStages,
|
|
driftOrdinals: fixture.mutation.metrics.namingRestorationDriftOrdinals,
|
|
...(classifications.has(fixture.id) ? { classification: classifications.get(fixture.id).classification, evidence: ['config/freecad-recovered-naming-classification.json', classifications.get(fixture.id).reasonCode] } : {}),
|
|
exit: 'the case is classified as stable semantics, allowed evolution, or an implementation defect',
|
|
}))
|
|
const productionDriftTasks = correlation.mutations
|
|
.filter((mutation) => mutation.restoreTopologyDriftStages > 0)
|
|
.map((mutation, index) => ({
|
|
id: `TSN-PROD-DRIFT-${String(index).padStart(3, '0')}`,
|
|
title: `Classify production restore topology drift for ${mutation.operation}`,
|
|
status: 'pending',
|
|
dependencies: [index === 0 ? driftTasks.at(-1).id : `TSN-PROD-DRIFT-${String(index - 1).padStart(3, '0')}`],
|
|
operation: mutation.operation,
|
|
driftStages: mutation.restoreTopologyDriftStages,
|
|
exit: 'every changed downstream stage has a native comparison and classification',
|
|
}))
|
|
const coveredTransitions = new Set(['cut->rotate', 'rotate->fillet', 'fillet->mirrored', 'mirrored->linear-pattern'])
|
|
const transitionTasks = production.operations.flatMap((from) => production.operations.map((to) => {
|
|
const pair = `${from}->${to}`
|
|
return {
|
|
id: `TSN-PAIR-${from}-${to}`,
|
|
title: `Classify ordered operation pair ${pair}`,
|
|
status: coveredTransitions.has(pair) ? 'completed' : 'pending',
|
|
dependencies: coveredTransitions.has(pair) ? [] : [productionDriftTasks.at(-1).id],
|
|
pair,
|
|
exit: 'native acceptance or rejection is recorded; accepted pairs include builder, mutation, naming, and resave evidence',
|
|
}
|
|
}))
|
|
|
|
const setupTasks = [
|
|
{ id: 'ORA-GUI-SETUP-000', title: 'Split GUI state probing from object/property probing', status: 'completed' },
|
|
{ id: 'ORA-GUI-SETUP-001', title: 'Diagnose the BIM first-run modal block', status: 'completed', dependencies: ['ORA-GUI-SETUP-000'] },
|
|
{ id: 'ORA-GUI-SETUP-002', title: 'Isolate FreeCAD config and suppress BIM first-run welcome before probing', status: 'completed', dependencies: ['ORA-GUI-SETUP-001'] },
|
|
]
|
|
const closureTasks = [
|
|
{ id: 'ORA-GUI-MERGE-000', title: 'Merge and verify all 100 GUI command shards', status: 'completed', dependencies: [guiShardTasks.at(-1).id] },
|
|
{ id: 'ORA-GUI-CONTEXT-000', title: 'Classify Import_ReadBREP as explicit module-import context', status: 'completed', dependencies: ['ORA-GUI-MERGE-000'] },
|
|
{ id: 'ORA-GUI-CONTEXT-001', title: 'Classify NaviCubeDraggableCmd as context-menu lazy registration', status: 'completed', dependencies: ['ORA-GUI-CONTEXT-000'] },
|
|
]
|
|
const milestones = [
|
|
{ id: 'ORA-GUI-BASELINE', exactTask: 'EX-ORA-01', status: 'completed', tasks: [...setupTasks, ...guiShardTasks, ...closureTasks] },
|
|
{ id: 'ORA-GUI-WORKFLOWS', exactTask: 'EX-ORA-01', status: workflowClosed ? 'completed' : 'in_progress', tasks: workflowTasks },
|
|
{ id: 'TSN-RECOVERY-DRIFT', exactTask: 'EX-TSN-04', status: workflowClosed ? 'in_progress' : 'pending', tasks: [...driftTasks, ...productionDriftTasks] },
|
|
{ id: 'TSN-ORDERED-PAIRS', exactTask: 'EX-TSN-04', status: 'pending', tasks: transitionTasks },
|
|
]
|
|
const allTasks = milestones.flatMap((milestone) => milestone.tasks)
|
|
const count = (status) => allTasks.filter((task) => task.status === status).length
|
|
const nextTask = allTasks.find((task) => task.status === 'in_progress')?.id
|
|
if (!nextTask) throw new Error('FreeCAD active work queue requires one in-progress task.')
|
|
const queue = {
|
|
schemaVersion: 1,
|
|
baseline: { freecadVersion: '1.1.1', commit: '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' },
|
|
updatedAt: '2026-08-15',
|
|
generatedBy: 'scripts/generate-freecad-active-work-queue.mjs',
|
|
policy: {
|
|
maxInProgress: 1,
|
|
unit: 'one artifact, one focused check, one explicit exit condition',
|
|
transitionUnit: 'one ordered operation pair',
|
|
driftUnit: 'one native case',
|
|
},
|
|
nextTask,
|
|
summary: { tasks: allTasks.length, completed: count('completed'), inProgress: count('in_progress'), pending: count('pending') },
|
|
milestones,
|
|
}
|
|
const content = `${JSON.stringify(queue, null, 2)}\n`
|
|
if (process.argv.includes('--check')) {
|
|
const current = await readFile(outputPath, 'utf8').catch(() => '')
|
|
if (current !== content) throw new Error('FreeCAD active work queue is stale; run generate:freecad-active-work-queue.')
|
|
console.log(JSON.stringify({ status: 'freecad-active-work-queue-pass', nextTask: queue.nextTask, ...queue.summary }, null, 2))
|
|
} else {
|
|
await writeFile(outputPath, content)
|
|
console.log(JSON.stringify({ status: 'freecad-active-work-queue-generated', output: outputPath, nextTask: queue.nextTask, ...queue.summary }, null, 2))
|
|
}
|