From 355c4f12cf2d083e33ba8aa251adc3a7467b226c Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Sun, 17 May 2026 15:13:42 -0400 Subject: [PATCH] Refresh Linear progress readiness detection --- scripts/operator-readiness-dashboard.js | 50 ++++++++++++++++--- .../operator-readiness-dashboard.test.js | 45 ++++++++++++++++- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/scripts/operator-readiness-dashboard.js b/scripts/operator-readiness-dashboard.js index 014dad93..247f0606 100644 --- a/scripts/operator-readiness-dashboard.js +++ b/scripts/operator-readiness-dashboard.js @@ -389,6 +389,46 @@ function supplyChainLocalProtectionGap({ roadmap, scripts }) { return 'Linear status synchronization remains ITO-57 follow-up after each significant merge batch'; } +function hasCurrentLinearProgressSync({ roadmap, progressSync }) { + return includesAll(roadmap, [ + 'Linear live sync is current', + 'operator progress snapshot', + ]) && includesAll(progressSync, [ + 'node scripts/work-items.js sync-github --repo ', + 'node scripts/status.js --json', + 'Linear remains the external status surface', + ]); +} + +function hasLinearProgressContract({ roadmap, progressSync }) { + return includesAll(roadmap, ['ITO-44', 'ITO-59', 'Linear']) + && includesAll(progressSync, ['GitHub', 'Linear', 'handoff', 'repo roadmap']); +} + +function linearProgressStatus(context) { + if (hasCurrentLinearProgressSync(context)) { + return 'current'; + } + + return hasLinearProgressContract(context) ? 'in_progress' : 'not_complete'; +} + +function linearProgressEvidence(context) { + if (hasCurrentLinearProgressSync(context)) { + return 'Linear live sync and project progress snapshot are current; progress-sync contract defines the file-backed work-items/status path'; + } + + return 'repo mirror and progress-sync contract are present'; +} + +function linearProgressGap(context) { + if (hasCurrentLinearProgressSync(context)) { + return 'repeat Linear/project status update and local work-items sync after each significant merge batch'; + } + + return 'recurring Linear status sync and productized realtime sync remain pending'; +} + function runCommand(command, args, options = {}) { const result = spawnSync(command, args, { cwd: options.cwd, @@ -568,11 +608,9 @@ function buildRequirements(rootDir, platformReport) { 'linear-roadmap-and-progress', 'Keep Linear roadmap detailed and progress tracking synchronized', 'Linear project mirror plus progress-sync contract', - includesAll(roadmap, ['ITO-44', 'ITO-59', 'Linear']) && includesAll(progressSync, ['GitHub', 'Linear', 'handoff', 'repo roadmap']) - ? 'in_progress' - : 'not_complete', - 'repo mirror and progress-sync contract are present', - 'recurring Linear status sync and productized realtime sync remain pending' + linearProgressStatus({ roadmap, progressSync }), + linearProgressEvidence({ roadmap, progressSync }), + linearProgressGap({ roadmap, progressSync }) ), buildRequirement( 'observability-for-self-use', @@ -651,7 +689,7 @@ function buildReport(options) { top_actions: topActions, next_work_order: [ 'Regenerate this dashboard from the final release commit before publication evidence is recorded.', - 'Continue ITO-57 with Linear status synchronization for the scheduled supply-chain watch advisory-source report.', + 'Repeat ITO-57 Linear/project status sync after the next significant merge batch or advisory-source refresh.', 'Complete ECC Tools Marketplace purchase/webhook readback, then run preflight and the live announcement gate before publishing native-payments copy.', 'Resume ITO-45, ITO-46, and ITO-56 only after the generated dashboard and final release gates are refreshed.', ], diff --git a/tests/scripts/operator-readiness-dashboard.test.js b/tests/scripts/operator-readiness-dashboard.test.js index 90ad074b..91a3c30e 100644 --- a/tests/scripts/operator-readiness-dashboard.test.js +++ b/tests/scripts/operator-readiness-dashboard.test.js @@ -57,7 +57,9 @@ function seedRepo(rootDir, overrides = {}) { 'production Marketplace readback state', 'eb69412', 'announcementGate', - 'ITO-55' + 'ITO-55', + 'Linear live sync is current for the May 17 merge batch', + 'operator progress snapshot' ].join('\n'), 'docs/releases/2.0.0-rc.1/publication-readiness.md': 'Claude plugin Codex plugin', 'docs/releases/2.0.0-rc.1/naming-and-publication-matrix.md': 'Claude plugin Codex plugin npm package Publication Paths', @@ -97,7 +99,12 @@ function seedRepo(rootDir, overrides = {}) { '#1565 pt-BR README sync', 'no automatic import remains release-blocking' ].join('\n'), - 'docs/architecture/progress-sync-contract.md': 'GitHub PRs/issues/discussions Linear project local handoff repo roadmap scripts/work-items.js', + 'docs/architecture/progress-sync-contract.md': [ + 'GitHub PRs/issues/discussions Linear project local handoff repo roadmap scripts/work-items.js', + 'node scripts/work-items.js sync-github --repo ', + 'node scripts/status.js --json', + 'Linear remains the external status surface' + ].join('\n'), 'docs/architecture/observability-readiness.md': 'observability-readiness.js', 'docs/security/supply-chain-incident-response.md': 'TanStack Mini Shai-Hulud node-ipc scan-supply-chain-iocs.js supply-chain-advisory-sources.js', 'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-15.md': 'TanStack Mini Shai-Hulud Node IPC follow-up node-ipc IOC scan', @@ -239,8 +246,42 @@ function runTests() { && item.evidence.includes('all localization tails are attached to Linear ITO-55') && item.gap === 'repeat legacy scan before release' ))); + assert.ok(report.requirements.some(item => ( + item.id === 'linear-roadmap-and-progress' + && item.status === 'current' + && item.evidence.includes('Linear live sync') + && item.gap === 'repeat Linear/project status update and local work-items sync after each significant merge batch' + ))); assert.ok(report.top_actions.some(item => item.id === 'naming-and-plugin-publication')); assert.ok(!report.top_actions.some(item => item.id === 'legacy-salvage')); + assert.ok(!report.top_actions.some(item => item.id === 'linear-roadmap-and-progress')); + } finally { + cleanup(rootDir); + } + })) passed++; else failed++; + + if (test('Linear progress stays in progress until live sync evidence is mirrored', () => { + const rootDir = createTempDir('operator-dashboard-linear-progress-'); + + try { + seedRepo(rootDir, { + 'docs/ECC-2.0-GA-ROADMAP.md': [ + 'https://linear.app/itomarkets/project/ecc-platform-roadmap-52b328ee03e1', + 'Linear ITO-44 ITO-59', + 'AgentShield Enterprise Iteration', + 'ECC-Tools PR #78', + 'hosted promotion', + 'announcementGate', + 'ITO-55' + ].join('\n') + }); + + const report = buildSeededReport(rootDir); + const linearProgress = report.requirements.find(item => item.id === 'linear-roadmap-and-progress'); + assert.strictEqual(linearProgress.status, 'in_progress'); + assert.strictEqual(linearProgress.evidence, 'repo mirror and progress-sync contract are present'); + assert.strictEqual(linearProgress.gap, 'recurring Linear status sync and productized realtime sync remain pending'); + assert.ok(report.top_actions.some(item => item.id === 'linear-roadmap-and-progress')); } finally { cleanup(rootDir); }