@resolveio/server-lib 22.3.221 → 22.3.223
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/ai/assistant-core-heuristics.d.ts +11 -0
- package/ai/assistant-core-heuristics.js +356 -0
- package/ai/assistant-core-heuristics.js.map +1 -0
- package/ai/resolveio-platform-intelligence-memory-corpus.d.ts +3 -0
- package/ai/resolveio-platform-intelligence-memory-corpus.js +214 -0
- package/ai/resolveio-platform-intelligence-memory-corpus.js.map +1 -0
- package/ai/resolveio-platform-intelligence-memory.d.ts +20 -0
- package/ai/resolveio-platform-intelligence-memory.js +341 -0
- package/ai/resolveio-platform-intelligence-memory.js.map +1 -0
- package/{src/ai/resolveio-platform-intelligence-types.ts → ai/resolveio-platform-intelligence-types.d.ts} +15 -20
- package/ai/resolveio-platform-intelligence-types.js +4 -0
- package/ai/resolveio-platform-intelligence-types.js.map +1 -0
- package/ai/resolveio-platform-intelligence.d.ts +6 -0
- package/ai/resolveio-platform-intelligence.js +463 -0
- package/ai/resolveio-platform-intelligence.js.map +1 -0
- package/client-server-app.d.ts +1 -0
- package/client-server-app.js +68 -0
- package/client-server-app.js.map +1 -0
- package/collections/ai-run.collection.d.ts +3 -0
- package/collections/ai-run.collection.js +170 -0
- package/collections/ai-run.collection.js.map +1 -0
- package/collections/ai-terminal-conversation.collection.d.ts +2 -0
- package/collections/ai-terminal-conversation.collection.js +140 -0
- package/collections/ai-terminal-conversation.collection.js.map +1 -0
- package/collections/ai-terminal-issue-report.collection.d.ts +2 -0
- package/collections/ai-terminal-issue-report.collection.js +148 -0
- package/collections/ai-terminal-issue-report.collection.js.map +1 -0
- package/collections/ai-terminal-message.collection.d.ts +2 -0
- package/collections/ai-terminal-message.collection.js +121 -0
- package/collections/ai-terminal-message.collection.js.map +1 -0
- package/collections/app-setting.collection.d.ts +3 -0
- package/collections/app-setting.collection.js +103 -0
- package/collections/app-setting.collection.js.map +1 -0
- package/collections/app-status.collection.d.ts +3 -0
- package/collections/app-status.collection.js +57 -0
- package/collections/app-status.collection.js.map +1 -0
- package/collections/communication-metric.collection.d.ts +2 -0
- package/collections/communication-metric.collection.js +133 -0
- package/collections/communication-metric.collection.js.map +1 -0
- package/collections/counter.collection.d.ts +3 -0
- package/collections/counter.collection.js +56 -0
- package/collections/counter.collection.js.map +1 -0
- package/collections/cron-job-history.collection.d.ts +3 -0
- package/collections/cron-job-history.collection.js +137 -0
- package/collections/cron-job-history.collection.js.map +1 -0
- package/collections/cron-job.collection.d.ts +3 -0
- package/collections/cron-job.collection.js +92 -0
- package/collections/cron-job.collection.js.map +1 -0
- package/collections/customer-notification.collection.d.ts +3 -0
- package/collections/customer-notification.collection.js +130 -0
- package/collections/customer-notification.collection.js.map +1 -0
- package/collections/customer-portal-password.collection.d.ts +3 -0
- package/collections/customer-portal-password.collection.js +75 -0
- package/collections/customer-portal-password.collection.js.map +1 -0
- package/collections/email-history.collection.d.ts +3 -0
- package/collections/email-history.collection.js +134 -0
- package/collections/email-history.collection.js.map +1 -0
- package/collections/email-verified.collection.d.ts +3 -0
- package/collections/email-verified.collection.js +62 -0
- package/collections/email-verified.collection.js.map +1 -0
- package/collections/file.collection.d.ts +3 -0
- package/collections/file.collection.js +74 -0
- package/collections/file.collection.js.map +1 -0
- package/collections/flag-update.collection.d.ts +3 -0
- package/collections/flag-update.collection.js +57 -0
- package/collections/flag-update.collection.js.map +1 -0
- package/collections/flag.collection.d.ts +3 -0
- package/collections/flag.collection.js +57 -0
- package/collections/flag.collection.js.map +1 -0
- package/collections/log-method-latency.collection.d.ts +3 -0
- package/collections/log-method-latency.collection.js +77 -0
- package/collections/log-method-latency.collection.js.map +1 -0
- package/collections/log-subscription.collection.d.ts +3 -0
- package/collections/log-subscription.collection.js +80 -0
- package/collections/log-subscription.collection.js.map +1 -0
- package/collections/log.collection.d.ts +3 -0
- package/collections/log.collection.js +93 -0
- package/collections/log.collection.js.map +1 -0
- package/collections/logged-in-users.collection.d.ts +3 -0
- package/collections/logged-in-users.collection.js +67 -0
- package/collections/logged-in-users.collection.js.map +1 -0
- package/collections/monitor-cpu.collection.d.ts +3 -0
- package/collections/monitor-cpu.collection.js +65 -0
- package/collections/monitor-cpu.collection.js.map +1 -0
- package/collections/monitor-function.collection.d.ts +3 -0
- package/collections/monitor-function.collection.js +74 -0
- package/collections/monitor-function.collection.js.map +1 -0
- package/collections/monitor-memory.collection.d.ts +3 -0
- package/collections/monitor-memory.collection.js +77 -0
- package/collections/monitor-memory.collection.js.map +1 -0
- package/collections/monitor-mongo.collection.d.ts +3 -0
- package/collections/monitor-mongo.collection.js +71 -0
- package/collections/monitor-mongo.collection.js.map +1 -0
- package/collections/notification.collection.d.ts +3 -0
- package/collections/notification.collection.js +57 -0
- package/collections/notification.collection.js.map +1 -0
- package/collections/openai-usage-ledger.collection.d.ts +2 -0
- package/collections/openai-usage-ledger.collection.js +188 -0
- package/collections/openai-usage-ledger.collection.js.map +1 -0
- package/collections/report-builder-dashboard-builder.collection.d.ts +3 -0
- package/collections/report-builder-dashboard-builder.collection.js +109 -0
- package/collections/report-builder-dashboard-builder.collection.js.map +1 -0
- package/collections/report-builder-library.collection.d.ts +3 -0
- package/collections/report-builder-library.collection.js +87 -0
- package/collections/report-builder-library.collection.js.map +1 -0
- package/collections/report-builder-report.collection.d.ts +4 -0
- package/collections/report-builder-report.collection.js +184 -0
- package/collections/report-builder-report.collection.js.map +1 -0
- package/collections/user-group.collection.d.ts +4 -0
- package/collections/user-group.collection.js +89 -0
- package/collections/user-group.collection.js.map +1 -0
- package/collections/user-guide.collection.d.ts +3 -0
- package/collections/user-guide.collection.js +57 -0
- package/collections/user-guide.collection.js.map +1 -0
- package/collections/user.collection.d.ts +4 -0
- package/collections/user.collection.js +180 -0
- package/collections/user.collection.js.map +1 -0
- package/cron/cron.d.ts +14 -0
- package/cron/cron.js +216 -0
- package/cron/cron.js.map +1 -0
- package/fixtures/cron-jobs.d.ts +1 -0
- package/fixtures/cron-jobs.js +150 -0
- package/fixtures/cron-jobs.js.map +1 -0
- package/fixtures/init.d.ts +1 -0
- package/fixtures/init.js +91 -0
- package/fixtures/init.js.map +1 -0
- package/http/auth.d.ts +2 -0
- package/http/auth.js +951 -0
- package/http/auth.js.map +1 -0
- package/http/health.d.ts +1 -0
- package/http/health.js +11 -0
- package/http/health.js.map +1 -0
- package/http/home.d.ts +1 -0
- package/http/home.js +134 -0
- package/http/home.js.map +1 -0
- package/http/slow-query-publication.d.ts +2 -0
- package/http/slow-query-publication.js +99 -0
- package/http/slow-query-publication.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +19 -0
- package/index.js.map +1 -0
- package/managers/ai-assistant-codex-manager.manager.d.ts +67 -0
- package/managers/ai-assistant-codex-manager.manager.js +1113 -0
- package/managers/ai-assistant-codex-manager.manager.js.map +1 -0
- package/managers/ai-run-evidence.manager.d.ts +36 -0
- package/managers/ai-run-evidence.manager.js +377 -0
- package/managers/ai-run-evidence.manager.js.map +1 -0
- package/managers/communication-metric.manager.d.ts +16 -0
- package/managers/communication-metric.manager.js +134 -0
- package/managers/communication-metric.manager.js.map +1 -0
- package/managers/cron.manager.d.ts +20 -0
- package/managers/cron.manager.js +534 -0
- package/managers/cron.manager.js.map +1 -0
- package/managers/customer-notification-content.manager.d.ts +55 -0
- package/managers/customer-notification-content.manager.js +158 -0
- package/managers/customer-notification-content.manager.js.map +1 -0
- package/managers/diagnostic-manager-bootstrap.d.ts +9 -0
- package/managers/diagnostic-manager-bootstrap.js +260 -0
- package/managers/diagnostic-manager-bootstrap.js.map +1 -0
- package/managers/error-auto-fix.manager.d.ts +149 -0
- package/managers/error-auto-fix.manager.js +3064 -0
- package/managers/error-auto-fix.manager.js.map +1 -0
- package/managers/local-log.manager.d.ts +18 -0
- package/managers/local-log.manager.js +88 -0
- package/managers/local-log.manager.js.map +1 -0
- package/managers/method.manager.d.ts +84 -0
- package/managers/method.manager.js +1964 -0
- package/managers/method.manager.js.map +1 -0
- package/managers/mongo.manager.d.ts +224 -0
- package/managers/mongo.manager.js +5000 -0
- package/managers/mongo.manager.js.map +1 -0
- package/managers/monitor.manager.d.ts +70 -0
- package/managers/monitor.manager.js +550 -0
- package/managers/monitor.manager.js.map +1 -0
- package/managers/openai-usage-ledger.manager.d.ts +30 -0
- package/managers/openai-usage-ledger.manager.js +142 -0
- package/managers/openai-usage-ledger.manager.js.map +1 -0
- package/managers/slow-query-verifier.manager.d.ts +144 -0
- package/managers/slow-query-verifier.manager.js +3857 -0
- package/managers/slow-query-verifier.manager.js.map +1 -0
- package/managers/slow-query.manager.d.ts +28 -0
- package/managers/slow-query.manager.js +468 -0
- package/managers/slow-query.manager.js.map +1 -0
- package/managers/subscription.manager.d.ts +169 -0
- package/managers/subscription.manager.js +3434 -0
- package/managers/subscription.manager.js.map +1 -0
- package/managers/websocket.manager.d.ts +73 -0
- package/managers/websocket.manager.js +673 -0
- package/managers/websocket.manager.js.map +1 -0
- package/managers/worker-dispatcher.manager.d.ts +120 -0
- package/managers/worker-dispatcher.manager.js +1266 -0
- package/managers/worker-dispatcher.manager.js.map +1 -0
- package/managers/worker-server.manager.d.ts +35 -0
- package/managers/worker-server.manager.js +582 -0
- package/managers/worker-server.manager.js.map +1 -0
- package/methods/accounts.d.ts +2 -0
- package/methods/accounts.js +624 -0
- package/methods/accounts.js.map +1 -0
- package/methods/ai-terminal.d.ts +458 -0
- package/methods/ai-terminal.js +27991 -0
- package/methods/ai-terminal.js.map +1 -0
- package/methods/app-settings.d.ts +2 -0
- package/methods/app-settings.js +169 -0
- package/methods/app-settings.js.map +1 -0
- package/methods/aws.d.ts +2 -0
- package/methods/aws.js +877 -0
- package/methods/aws.js.map +1 -0
- package/methods/collections.d.ts +2 -0
- package/methods/collections.js +719 -0
- package/methods/collections.js.map +1 -0
- package/methods/counters.d.ts +2 -0
- package/methods/counters.js +113 -0
- package/methods/counters.js.map +1 -0
- package/methods/cron-jobs.d.ts +2 -0
- package/methods/cron-jobs.js +2475 -0
- package/methods/cron-jobs.js.map +1 -0
- package/methods/customer-notifications.d.ts +2 -0
- package/methods/customer-notifications.js +528 -0
- package/methods/customer-notifications.js.map +1 -0
- package/methods/diagnostics.d.ts +2 -0
- package/methods/diagnostics.js +703 -0
- package/methods/diagnostics.js.map +1 -0
- package/methods/flag-updates.d.ts +2 -0
- package/methods/flag-updates.js +8 -0
- package/methods/flag-updates.js.map +1 -0
- package/methods/flags.d.ts +2 -0
- package/methods/flags.js +8 -0
- package/methods/flags.js.map +1 -0
- package/methods/logs.d.ts +2 -0
- package/methods/logs.js +751 -0
- package/methods/logs.js.map +1 -0
- package/methods/mongo-explorer.d.ts +2 -0
- package/methods/mongo-explorer.js +1808 -0
- package/methods/mongo-explorer.js.map +1 -0
- package/methods/monitor.d.ts +2 -0
- package/methods/monitor.js +543 -0
- package/methods/monitor.js.map +1 -0
- package/methods/pdf.d.ts +2 -0
- package/methods/pdf.js +1216 -0
- package/methods/pdf.js.map +1 -0
- package/methods/publications.d.ts +1 -0
- package/methods/publications.js +183 -0
- package/methods/publications.js.map +1 -0
- package/methods/report-builder.d.ts +2 -0
- package/methods/report-builder.js +3094 -0
- package/methods/report-builder.js.map +1 -0
- package/methods/support.d.ts +2 -0
- package/methods/support.js +430 -0
- package/methods/support.js.map +1 -0
- package/models/ai-run.model.d.ts +19 -0
- package/models/ai-run.model.js +4 -0
- package/models/ai-run.model.js.map +1 -0
- package/models/ai-terminal-conversation.model.d.ts +17 -0
- package/models/ai-terminal-conversation.model.js +4 -0
- package/models/ai-terminal-conversation.model.js.map +1 -0
- package/models/ai-terminal-issue-report.model.d.ts +19 -0
- package/models/ai-terminal-issue-report.model.js +4 -0
- package/models/ai-terminal-issue-report.model.js.map +1 -0
- package/models/ai-terminal-message.model.d.ts +22 -0
- package/models/ai-terminal-message.model.js +4 -0
- package/models/ai-terminal-message.model.js.map +1 -0
- package/models/app-setting.model.d.ts +16 -0
- package/models/app-setting.model.js +4 -0
- package/models/app-setting.model.js.map +1 -0
- package/{src/models/app-status.model.ts → models/app-status.model.d.ts} +2 -3
- package/models/app-status.model.js +4 -0
- package/models/app-status.model.js.map +1 -0
- package/{src/models/billing-logged-in-users.model.ts → models/billing-logged-in-users.model.d.ts} +4 -5
- package/models/billing-logged-in-users.model.js +4 -0
- package/models/billing-logged-in-users.model.js.map +1 -0
- package/models/collection-document.model.d.ts +21 -0
- package/models/collection-document.model.js +4 -0
- package/models/collection-document.model.js.map +1 -0
- package/models/communication-metric.model.d.ts +20 -0
- package/models/communication-metric.model.js +4 -0
- package/models/communication-metric.model.js.map +1 -0
- package/{src/models/counter.model.ts → models/counter.model.d.ts} +3 -4
- package/models/counter.model.js +4 -0
- package/models/counter.model.js.map +1 -0
- package/models/cron-job-history.model.d.ts +15 -0
- package/models/cron-job-history.model.js +4 -0
- package/models/cron-job-history.model.js.map +1 -0
- package/models/cron-job.model.d.ts +14 -0
- package/models/cron-job.model.js +4 -0
- package/models/cron-job.model.js.map +1 -0
- package/models/customer-notification.model.d.ts +26 -0
- package/models/customer-notification.model.js +4 -0
- package/models/customer-notification.model.js.map +1 -0
- package/models/customer-portal-password.model.d.ts +11 -0
- package/models/customer-portal-password.model.js +4 -0
- package/models/customer-portal-password.model.js.map +1 -0
- package/models/dialog.model.d.ts +23 -0
- package/models/dialog.model.js +4 -0
- package/models/dialog.model.js.map +1 -0
- package/models/email-history.model.d.ts +32 -0
- package/{src/models/email-history.model.ts → models/email-history.model.js} +4 -36
- package/models/email-history.model.js.map +1 -0
- package/{src/models/email-verified.model.ts → models/email-verified.model.d.ts} +5 -6
- package/models/email-verified.model.js +4 -0
- package/models/email-verified.model.js.map +1 -0
- package/{src/models/file.model.ts → models/file.model.d.ts} +7 -8
- package/models/file.model.js +4 -0
- package/models/file.model.js.map +1 -0
- package/{src/models/flag-update.model.ts → models/flag-update.model.d.ts} +3 -4
- package/models/flag-update.model.js +4 -0
- package/models/flag-update.model.js.map +1 -0
- package/{src/models/flag.model.ts → models/flag.model.d.ts} +3 -4
- package/models/flag.model.js +4 -0
- package/models/flag.model.js.map +1 -0
- package/models/log-method-latency.model.d.ts +10 -0
- package/models/log-method-latency.model.js +4 -0
- package/models/log-method-latency.model.js.map +1 -0
- package/{src/models/log-subscription.model.ts → models/log-subscription.model.d.ts} +9 -11
- package/models/log-subscription.model.js +4 -0
- package/models/log-subscription.model.js.map +1 -0
- package/models/log.model.d.ts +17 -0
- package/models/log.model.js +4 -0
- package/models/log.model.js.map +1 -0
- package/{src/models/logged-in-users.model.ts → models/logged-in-users.model.d.ts} +5 -6
- package/models/logged-in-users.model.js +4 -0
- package/models/logged-in-users.model.js.map +1 -0
- package/{src/models/method-response.model.ts → models/method-response.model.d.ts} +6 -7
- package/models/method-response.model.js +4 -0
- package/models/method-response.model.js.map +1 -0
- package/models/method.model.d.ts +26 -0
- package/models/method.model.js +4 -0
- package/models/method.model.js.map +1 -0
- package/{src/models/monitor-cpu.model.ts → models/monitor-cpu.model.d.ts} +7 -9
- package/models/monitor-cpu.model.js +4 -0
- package/models/monitor-cpu.model.js.map +1 -0
- package/models/monitor-function.model.d.ts +14 -0
- package/models/monitor-function.model.js +4 -0
- package/models/monitor-function.model.js.map +1 -0
- package/models/monitor-memory.model.d.ts +15 -0
- package/models/monitor-memory.model.js +4 -0
- package/models/monitor-memory.model.js.map +1 -0
- package/models/monitor-mongo.model.d.ts +13 -0
- package/models/monitor-mongo.model.js +4 -0
- package/models/monitor-mongo.model.js.map +1 -0
- package/{src/models/notification.model.ts → models/notification.model.d.ts} +4 -6
- package/models/notification.model.js +4 -0
- package/models/notification.model.js.map +1 -0
- package/models/openai-usage-ledger.model.d.ts +30 -0
- package/models/openai-usage-ledger.model.js +4 -0
- package/models/openai-usage-ledger.model.js.map +1 -0
- package/models/pagination.model.d.ts +11 -0
- package/models/pagination.model.js +28 -0
- package/models/pagination.model.js.map +1 -0
- package/models/permission.model.d.ts +12 -0
- package/models/permission.model.js +4 -0
- package/models/permission.model.js.map +1 -0
- package/models/report-builder-dashboard-builder.model.d.ts +25 -0
- package/models/report-builder-dashboard-builder.model.js +4 -0
- package/models/report-builder-dashboard-builder.model.js.map +1 -0
- package/models/report-builder-library.model.d.ts +17 -0
- package/models/report-builder-library.model.js +4 -0
- package/models/report-builder-library.model.js.map +1 -0
- package/models/report-builder-report.model.d.ts +121 -0
- package/models/report-builder-report.model.js +4 -0
- package/models/report-builder-report.model.js.map +1 -0
- package/models/report-builder.model.d.ts +61 -0
- package/models/report-builder.model.js +4 -0
- package/models/report-builder.model.js.map +1 -0
- package/models/select-data-label.model.d.ts +9 -0
- package/models/select-data-label.model.js +4 -0
- package/models/select-data-label.model.js.map +1 -0
- package/models/server-message.model.d.ts +32 -0
- package/models/server-message.model.js +4 -0
- package/models/server-message.model.js.map +1 -0
- package/models/slow-query-report.model.d.ts +23 -0
- package/models/slow-query-report.model.js +4 -0
- package/models/slow-query-report.model.js.map +1 -0
- package/models/subscription.model.d.ts +31 -0
- package/models/subscription.model.js +4 -0
- package/models/subscription.model.js.map +1 -0
- package/models/support-ticket.model.d.ts +87 -0
- package/models/support-ticket.model.js +4 -0
- package/models/support-ticket.model.js.map +1 -0
- package/models/user-group.model.d.ts +20 -0
- package/models/user-group.model.js +4 -0
- package/models/user-group.model.js.map +1 -0
- package/{src/models/user-guide.model.ts → models/user-guide.model.d.ts} +4 -5
- package/models/user-guide.model.js +4 -0
- package/models/user-guide.model.js.map +1 -0
- package/models/user.model.d.ts +84 -0
- package/models/user.model.js +4 -0
- package/models/user.model.js.map +1 -0
- package/package.json +1 -1
- package/private/images/ResolveIO.png +0 -0
- package/public_api.js +127 -0
- package/public_api.js.map +1 -0
- package/publications/ai-terminal.d.ts +1 -0
- package/publications/ai-terminal.js +122 -0
- package/publications/ai-terminal.js.map +1 -0
- package/publications/app-settings.d.ts +2 -0
- package/publications/app-settings.js +28 -0
- package/publications/app-settings.js.map +1 -0
- package/publications/app-status.d.ts +2 -0
- package/publications/app-status.js +16 -0
- package/publications/app-status.js.map +1 -0
- package/publications/cron-jobs.d.ts +2 -0
- package/publications/cron-jobs.js +88 -0
- package/publications/cron-jobs.js.map +1 -0
- package/publications/customer-notifications.d.ts +2 -0
- package/publications/customer-notifications.js +161 -0
- package/publications/customer-notifications.js.map +1 -0
- package/publications/files.d.ts +2 -0
- package/publications/files.js +36 -0
- package/publications/files.js.map +1 -0
- package/publications/flags-update.d.ts +2 -0
- package/publications/flags-update.js +22 -0
- package/publications/flags-update.js.map +1 -0
- package/publications/flags.d.ts +2 -0
- package/publications/flags.js +22 -0
- package/publications/flags.js.map +1 -0
- package/publications/logs.d.ts +2 -0
- package/publications/logs.js +164 -0
- package/publications/logs.js.map +1 -0
- package/publications/notifications.d.ts +2 -0
- package/publications/notifications.js +16 -0
- package/publications/notifications.js.map +1 -0
- package/publications/report-builder-dashboard-builders.d.ts +2 -0
- package/publications/report-builder-dashboard-builders.js +42 -0
- package/publications/report-builder-dashboard-builders.js.map +1 -0
- package/publications/report-builder-libraries.d.ts +2 -0
- package/publications/report-builder-libraries.js +90 -0
- package/publications/report-builder-libraries.js.map +1 -0
- package/publications/report-builder-reports.d.ts +2 -0
- package/publications/report-builder-reports.js +50 -0
- package/publications/report-builder-reports.js.map +1 -0
- package/publications/super-admin.d.ts +2 -0
- package/publications/super-admin.js +16 -0
- package/publications/super-admin.js.map +1 -0
- package/publications/user-groups.d.ts +1 -0
- package/publications/user-groups.js +16 -0
- package/publications/user-groups.js.map +1 -0
- package/publications/user-guides.d.ts +1 -0
- package/publications/user-guides.js +16 -0
- package/publications/user-guides.js.map +1 -0
- package/resolveio-server-app.d.ts +70 -0
- package/resolveio-server-app.js +801 -0
- package/resolveio-server-app.js.map +1 -0
- package/server-app.d.ts +228 -0
- package/server-app.js +3566 -0
- package/server-app.js.map +1 -0
- package/services/codex-client.d.ts +128 -0
- package/services/codex-client.js +1629 -0
- package/services/codex-client.js.map +1 -0
- package/services/openai-client.d.ts +46 -0
- package/services/openai-client.js +318 -0
- package/services/openai-client.js.map +1 -0
- package/types/error-report.d.ts +25 -0
- package/types/error-report.js +4 -0
- package/types/error-report.js.map +1 -0
- package/types/slow-query-report.d.ts +27 -0
- package/types/slow-query-report.js +6 -0
- package/types/slow-query-report.js.map +1 -0
- package/util/ai-qa-policy.d.ts +124 -0
- package/util/ai-qa-policy.js +736 -0
- package/util/ai-qa-policy.js.map +1 -0
- package/util/ai-run-evidence-adapters.d.ts +109 -0
- package/util/ai-run-evidence-adapters.js +7234 -0
- package/util/ai-run-evidence-adapters.js.map +1 -0
- package/util/ai-run-evidence-dashboard.d.ts +88 -0
- package/util/ai-run-evidence-dashboard.js +343 -0
- package/util/ai-run-evidence-dashboard.js.map +1 -0
- package/util/ai-run-evidence-eval.d.ts +86 -0
- package/util/ai-run-evidence-eval.js +1018 -0
- package/util/ai-run-evidence-eval.js.map +1 -0
- package/util/ai-run-evidence.d.ts +244 -0
- package/util/ai-run-evidence.js +1096 -0
- package/util/ai-run-evidence.js.map +1 -0
- package/util/ai-runner-artifacts.d.ts +82 -0
- package/util/ai-runner-artifacts.js +713 -0
- package/util/ai-runner-artifacts.js.map +1 -0
- package/util/ai-runner-manager-autopilot.d.ts +210 -0
- package/util/ai-runner-manager-autopilot.js +642 -0
- package/util/ai-runner-manager-autopilot.js.map +1 -0
- package/util/ai-runner-manager-policy.d.ts +807 -0
- package/util/ai-runner-manager-policy.js +3501 -0
- package/util/ai-runner-manager-policy.js.map +1 -0
- package/util/ai-runner-qa-auth.d.ts +5 -0
- package/util/ai-runner-qa-auth.js +839 -0
- package/util/ai-runner-qa-auth.js.map +1 -0
- package/util/ai-runner-qa-tools.d.ts +26 -0
- package/util/ai-runner-qa-tools.js +3520 -0
- package/util/ai-runner-qa-tools.js.map +1 -0
- package/util/aicoder-runner-v6.d.ts +426 -0
- package/util/aicoder-runner-v6.js +2464 -0
- package/util/aicoder-runner-v6.js.map +1 -0
- package/util/common.d.ts +31 -0
- package/util/common.js +683 -0
- package/util/common.js.map +1 -0
- package/util/customer-portal-password.d.ts +13 -0
- package/util/customer-portal-password.js +209 -0
- package/util/customer-portal-password.js.map +1 -0
- package/util/error-reporter.d.ts +52 -0
- package/util/error-reporter.js +326 -0
- package/util/error-reporter.js.map +1 -0
- package/util/error-tracking.d.ts +13 -0
- package/util/error-tracking.js +120 -0
- package/util/error-tracking.js.map +1 -0
- package/util/openai-usage-cost.d.ts +6 -0
- package/util/openai-usage-cost.js +103 -0
- package/util/openai-usage-cost.js.map +1 -0
- package/util/report-builder-unwinds.d.ts +15 -0
- package/util/report-builder-unwinds.js +156 -0
- package/util/report-builder-unwinds.js.map +1 -0
- package/util/runner-process-janitor.d.ts +27 -0
- package/util/runner-process-janitor.js +208 -0
- package/util/runner-process-janitor.js.map +1 -0
- package/util/schema-report-builder.d.ts +6 -0
- package/util/schema-report-builder.js +481 -0
- package/util/schema-report-builder.js.map +1 -0
- package/util/slow-query-reporter.d.ts +28 -0
- package/util/slow-query-reporter.js +226 -0
- package/util/slow-query-reporter.js.map +1 -0
- package/util/subscription-dependency-context.d.ts +34 -0
- package/util/subscription-dependency-context.js +1283 -0
- package/util/subscription-dependency-context.js.map +1 -0
- package/util/support-runner-v5.d.ts +1426 -0
- package/util/support-runner-v5.js +7647 -0
- package/util/support-runner-v5.js.map +1 -0
- package/util/tokenizer.d.ts +5 -0
- package/util/tokenizer.js +41 -0
- package/util/tokenizer.js.map +1 -0
- package/workers/codex-runner.worker.d.ts +1 -0
- package/workers/codex-runner.worker.js +192 -0
- package/workers/codex-runner.worker.js.map +1 -0
- package/.nodemon.json +0 -5
- package/.vscode/settings.json +0 -21
- package/AGENTS.md +0 -195
- package/README.md +0 -22
- package/build_package.sh +0 -5
- package/compileDTS.pl +0 -64
- package/docs/ai-assistant-nightly-eval.md +0 -65
- package/docs/ai-assistant-preflight-checklist.md +0 -23
- package/docs/ai-assistant-report-builder-bridge-playbook.md +0 -115
- package/eslint-plugin-custom/index.js +0 -7
- package/eslint-plugin-custom/rules/no-filter-zero-index.js +0 -44
- package/eslint.config.js +0 -103
- package/gulpfile.js +0 -216
- package/methodAndPublicationListGenerator.py +0 -375
- package/mongodbensurers.js +0 -2
- package/mongostop.js +0 -3
- package/scripts/cleanup-bypassed-callmethod-logs.js +0 -616
- package/settings.development.json +0 -25
- package/settings.development.redacted.json +0 -25
- package/src/.env +0 -12
- package/src/ai/assistant-core-heuristics.ts +0 -379
- package/src/ai/resolveio-platform-intelligence-memory-corpus.ts +0 -185
- package/src/ai/resolveio-platform-intelligence-memory.ts +0 -325
- package/src/ai/resolveio-platform-intelligence.ts +0 -462
- package/src/client-server-app.ts +0 -12
- package/src/collections/ai-run.collection.ts +0 -117
- package/src/collections/ai-terminal-conversation.collection.ts +0 -91
- package/src/collections/ai-terminal-issue-report.collection.ts +0 -99
- package/src/collections/ai-terminal-message.collection.ts +0 -77
- package/src/collections/app-setting.collection.ts +0 -104
- package/src/collections/app-status.collection.ts +0 -58
- package/src/collections/communication-metric.collection.ts +0 -84
- package/src/collections/counter.collection.ts +0 -56
- package/src/collections/cron-job-history.collection.ts +0 -94
- package/src/collections/cron-job.collection.ts +0 -92
- package/src/collections/customer-notification.collection.ts +0 -131
- package/src/collections/customer-portal-password.collection.ts +0 -76
- package/src/collections/email-history.collection.ts +0 -134
- package/src/collections/email-verified.collection.ts +0 -62
- package/src/collections/file.collection.ts +0 -74
- package/src/collections/flag-update.collection.ts +0 -57
- package/src/collections/flag.collection.ts +0 -57
- package/src/collections/log-method-latency.collection.ts +0 -77
- package/src/collections/log-subscription.collection.ts +0 -80
- package/src/collections/log.collection.ts +0 -93
- package/src/collections/logged-in-users.collection.ts +0 -67
- package/src/collections/monitor-cpu.collection.ts +0 -65
- package/src/collections/monitor-function.collection.ts +0 -74
- package/src/collections/monitor-memory.collection.ts +0 -77
- package/src/collections/monitor-mongo.collection.ts +0 -71
- package/src/collections/notification.collection.ts +0 -57
- package/src/collections/openai-usage-ledger.collection.ts +0 -131
- package/src/collections/report-builder-dashboard-builder.collection.ts +0 -109
- package/src/collections/report-builder-library.collection.ts +0 -89
- package/src/collections/report-builder-report.collection.ts +0 -184
- package/src/collections/user-group.collection.ts +0 -89
- package/src/collections/user-guide.collection.ts +0 -57
- package/src/collections/user.collection.ts +0 -181
- package/src/cron/cron.ts +0 -117
- package/src/fixtures/cron-jobs.ts +0 -95
- package/src/fixtures/init.ts +0 -35
- package/src/http/auth.ts +0 -818
- package/src/http/health.ts +0 -7
- package/src/http/home.ts +0 -90
- package/src/http/slow-query-publication.ts +0 -49
- package/src/index.ts +0 -1
- package/src/managers/ai-assistant-codex-manager.manager.ts +0 -1131
- package/src/managers/ai-run-evidence.manager.ts +0 -264
- package/src/managers/communication-metric.manager.ts +0 -82
- package/src/managers/cron.manager.ts +0 -333
- package/src/managers/customer-notification-content.manager.ts +0 -236
- package/src/managers/diagnostic-manager-bootstrap.ts +0 -165
- package/src/managers/error-auto-fix.manager.ts +0 -2767
- package/src/managers/local-log.manager.ts +0 -113
- package/src/managers/method.manager.ts +0 -1857
- package/src/managers/mongo.manager.ts +0 -4575
- package/src/managers/monitor.manager.ts +0 -507
- package/src/managers/openai-usage-ledger.manager.ts +0 -112
- package/src/managers/slow-query-verifier.manager.ts +0 -3590
- package/src/managers/slow-query.manager.ts +0 -519
- package/src/managers/subscription.manager.ts +0 -3128
- package/src/managers/websocket.manager.ts +0 -746
- package/src/managers/worker-dispatcher.manager.ts +0 -1360
- package/src/managers/worker-server.manager.ts +0 -536
- package/src/methods/accounts.ts +0 -532
- package/src/methods/ai-terminal.ts +0 -29070
- package/src/methods/app-settings.ts +0 -114
- package/src/methods/aws.ts +0 -649
- package/src/methods/collections.ts +0 -641
- package/src/methods/counters.ts +0 -69
- package/src/methods/cron-jobs.ts +0 -2614
- package/src/methods/customer-notifications.ts +0 -458
- package/src/methods/diagnostics.ts +0 -616
- package/src/methods/flag-updates.ts +0 -7
- package/src/methods/flags.ts +0 -7
- package/src/methods/logs.ts +0 -657
- package/src/methods/mongo-explorer.ts +0 -1880
- package/src/methods/monitor.ts +0 -540
- package/src/methods/pdf.ts +0 -1236
- package/src/methods/publications.ts +0 -129
- package/src/methods/report-builder.ts +0 -3300
- package/src/methods/support.ts +0 -335
- package/src/models/ai-run.model.ts +0 -27
- package/src/models/ai-terminal-conversation.model.ts +0 -19
- package/src/models/ai-terminal-issue-report.model.ts +0 -21
- package/src/models/ai-terminal-message.model.ts +0 -24
- package/src/models/app-setting.model.ts +0 -17
- package/src/models/collection-document.model.ts +0 -24
- package/src/models/communication-metric.model.ts +0 -23
- package/src/models/cron-job-history.model.ts +0 -16
- package/src/models/cron-job.model.ts +0 -15
- package/src/models/customer-notification.model.ts +0 -28
- package/src/models/customer-portal-password.model.ts +0 -12
- package/src/models/dialog.model.ts +0 -25
- package/src/models/log-method-latency.model.ts +0 -11
- package/src/models/log.model.ts +0 -19
- package/src/models/method.model.ts +0 -25
- package/src/models/monitor-function.model.ts +0 -16
- package/src/models/monitor-memory.model.ts +0 -17
- package/src/models/monitor-mongo.model.ts +0 -15
- package/src/models/openai-usage-ledger.model.ts +0 -56
- package/src/models/pagination.model.ts +0 -35
- package/src/models/permission.model.ts +0 -14
- package/src/models/report-builder-dashboard-builder.model.ts +0 -29
- package/src/models/report-builder-library.model.ts +0 -20
- package/src/models/report-builder-report.model.ts +0 -136
- package/src/models/report-builder.model.ts +0 -68
- package/src/models/select-data-label.model.ts +0 -9
- package/src/models/server-message.model.ts +0 -31
- package/src/models/slow-query-report.model.ts +0 -23
- package/src/models/subscription.model.ts +0 -73
- package/src/models/support-ticket.model.ts +0 -104
- package/src/models/user-group.model.ts +0 -24
- package/src/models/user.model.ts +0 -96
- package/src/private/images/ResolveIO.png +0 -0
- package/src/publications/ai-terminal.ts +0 -73
- package/src/publications/app-settings.ts +0 -25
- package/src/publications/app-status.ts +0 -13
- package/src/publications/cron-jobs.ts +0 -40
- package/src/publications/customer-notifications.ts +0 -101
- package/src/publications/files.ts +0 -33
- package/src/publications/flags-update.ts +0 -19
- package/src/publications/flags.ts +0 -19
- package/src/publications/logs.ts +0 -163
- package/src/publications/notifications.ts +0 -13
- package/src/publications/report-builder-dashboard-builders.ts +0 -39
- package/src/publications/report-builder-libraries.ts +0 -41
- package/src/publications/report-builder-reports.ts +0 -47
- package/src/publications/super-admin.ts +0 -13
- package/src/publications/user-groups.ts +0 -12
- package/src/publications/user-guides.ts +0 -12
- package/src/resolveio-server-app.ts +0 -617
- package/src/server-app.ts +0 -3354
- package/src/services/codex-client.ts +0 -1231
- package/src/services/openai-client.ts +0 -265
- package/src/types/error-report.ts +0 -26
- package/src/types/js-tiktoken.d.ts +0 -11
- package/src/types/slow-query-report.ts +0 -28
- package/src/util/ai-qa-policy.ts +0 -925
- package/src/util/ai-run-evidence-adapters.ts +0 -8347
- package/src/util/ai-run-evidence-dashboard.ts +0 -323
- package/src/util/ai-run-evidence-eval.ts +0 -1057
- package/src/util/ai-run-evidence.ts +0 -1430
- package/src/util/ai-runner-artifacts.ts +0 -586
- package/src/util/ai-runner-manager-autopilot.ts +0 -961
- package/src/util/ai-runner-manager-policy.ts +0 -5011
- package/src/util/ai-runner-qa-auth.ts +0 -838
- package/src/util/ai-runner-qa-tools.ts +0 -3536
- package/src/util/aicoder-runner-v6.ts +0 -3121
- package/src/util/common.ts +0 -649
- package/src/util/customer-portal-password.ts +0 -183
- package/src/util/error-reporter.ts +0 -332
- package/src/util/error-tracking.ts +0 -79
- package/src/util/openai-usage-cost.ts +0 -114
- package/src/util/report-builder-unwinds.ts +0 -180
- package/src/util/runner-process-janitor.ts +0 -219
- package/src/util/schema-report-builder.ts +0 -448
- package/src/util/slow-query-reporter.ts +0 -216
- package/src/util/subscription-dependency-context.ts +0 -1096
- package/src/util/support-runner-v5.ts +0 -10040
- package/src/util/tokenizer.ts +0 -38
- package/src/workers/codex-runner.worker.ts +0 -142
- package/start_server.sh +0 -5
- package/tests/ai-assistant-corpus-build.ts +0 -484
- package/tests/ai-assistant-corpus-replay-e2e.ts +0 -774
- package/tests/ai-assistant-data-parity-e2e.ts +0 -1989
- package/tests/ai-assistant-eval-triage.ts +0 -831
- package/tests/ai-assistant-openai-e2e.ts +0 -1061
- package/tests/ai-assistant-openai-git-e2e.ts +0 -155
- package/tests/ai-assistant-preflight-matrix.ts +0 -215
- package/tests/ai-assistant-routing-eval.test.ts +0 -585
- package/tests/ai-assistant-snf-live-eval.ts +0 -975
- package/tests/ai-assistant-utils.test.ts +0 -4834
- package/tests/ai-manager-autopilot-snapshot.test.ts +0 -193
- package/tests/ai-manager-recovery-checkpoint.test.ts +0 -1383
- package/tests/ai-run-eval.test.ts +0 -132
- package/tests/ai-run-evidence.test.ts +0 -3773
- package/tests/ai-runner-contract.test.ts +0 -515
- package/tests/aicoder-runner-v6.test.ts +0 -822
- package/tests/error-reporter.test.ts +0 -145
- package/tests/method-publication-generator.test.ts +0 -46
- package/tests/report-builder-linking.test.ts +0 -79
- package/tests/resolveio-platform-intelligence.test.ts +0 -352
- package/tests/server-app-cron-owner.test.ts +0 -127
- package/tests/subscription-connect-race.test.ts +0 -158
- package/tests/subscription-dependency-context.test.ts +0 -324
- package/tests/subscription-manager-collection-tracking.test.ts +0 -86
- package/tests/subscription-manager-invalidation.test.ts +0 -86
- package/tests/support-runner-v5.test.ts +0 -3201
- package/tsconfig.json +0 -34
- /package/{src/private → private}/email-templates/enrollment.html +0 -0
- /package/{src/private → private}/email-templates/forgot-password.html +0 -0
- /package/{src/private → private}/email-templates/support-ticket-deleted.html +0 -0
- /package/{src/private → private}/email-templates/support-ticket-modified.html +0 -0
- /package/{src/private → private}/email-templates/support-ticket.html +0 -0
- /package/{src/public_api.ts → public_api.d.ts} +0 -0
|
@@ -1,3773 +0,0 @@
|
|
|
1
|
-
import * as assert from 'node:assert/strict';
|
|
2
|
-
import {
|
|
3
|
-
buildAIRun,
|
|
4
|
-
buildAIRunCost,
|
|
5
|
-
buildAIQaRun,
|
|
6
|
-
classifyAIRunOutcome,
|
|
7
|
-
normalizeOpenAIUsageRowsForCosting,
|
|
8
|
-
redactAIRunTrainingExample
|
|
9
|
-
} from '../src/util/ai-run-evidence';
|
|
10
|
-
import {
|
|
11
|
-
buildAICoderAIRunFromEvidence,
|
|
12
|
-
buildAssistantAIRunFromEvidence,
|
|
13
|
-
buildSupportAIRunFromEvidence
|
|
14
|
-
} from '../src/util/ai-run-evidence-adapters';
|
|
15
|
-
import {
|
|
16
|
-
classifyAIRunFailureClass,
|
|
17
|
-
decideAIRunRetry
|
|
18
|
-
} from '../src/util/ai-run-evidence-eval';
|
|
19
|
-
import { estimateOpenAIUsageCost } from '../src/util/openai-usage-cost';
|
|
20
|
-
|
|
21
|
-
const routeOnlyQa = buildAIQaRun({
|
|
22
|
-
infraChecks: [
|
|
23
|
-
{ name: 'puppeteer_require', status: 'pass' },
|
|
24
|
-
{ name: 'chrome_executable', status: 'pass' }
|
|
25
|
-
],
|
|
26
|
-
compile: { status: 'pass', artifactPath: '.build-output/build-client.log' },
|
|
27
|
-
routeProbes: [{
|
|
28
|
-
route: '/billing/dashboard',
|
|
29
|
-
status: 'pass',
|
|
30
|
-
screenshot: 'qa-artifacts/route-ready.jpg',
|
|
31
|
-
caption: 'Route loaded.'
|
|
32
|
-
}]
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
assert.equal(routeOnlyQa.outcome, 'route_only_pass');
|
|
36
|
-
assert.equal(routeOnlyQa.gateResults.some((gate) => gate.key === 'qa_business_assertion' && gate.status === 'blocked'), true);
|
|
37
|
-
assert.equal(classifyAIRunOutcome({ qa: routeOnlyQa }).outcome, 'qa_incomplete');
|
|
38
|
-
assert.equal(classifyAIRunOutcome({ qa: routeOnlyQa, scorecardPassed: true }).outcome, 'false_pass');
|
|
39
|
-
|
|
40
|
-
const infraFailedQa = buildAIQaRun({
|
|
41
|
-
infraChecks: [
|
|
42
|
-
{ name: 'puppeteer_require', status: 'blocked', message: 'Unable to require puppeteer.' }
|
|
43
|
-
]
|
|
44
|
-
});
|
|
45
|
-
assert.equal(infraFailedQa.outcome, 'infra_failed');
|
|
46
|
-
assert.equal(classifyAIRunOutcome({ qa: infraFailedQa }).outcome, 'qa_infra_failed');
|
|
47
|
-
|
|
48
|
-
const compileFailedQa = buildAIQaRun({
|
|
49
|
-
infraChecks: [{ name: 'chrome_executable', status: 'pass' }],
|
|
50
|
-
compile: { status: 'stale', staleEvidence: true, artifactPath: '.build-output/build-client.log' }
|
|
51
|
-
});
|
|
52
|
-
assert.equal(compileFailedQa.outcome, 'compile_failed');
|
|
53
|
-
assert.equal(classifyAIRunOutcome({ qa: compileFailedQa }).outcome, 'build_failed');
|
|
54
|
-
|
|
55
|
-
const businessPassedQa = buildAIQaRun({
|
|
56
|
-
infraChecks: [{ name: 'chrome_launch', status: 'pass' }],
|
|
57
|
-
compile: { status: 'pass' },
|
|
58
|
-
routeProbes: [{ route: '/report', status: 'pass' }],
|
|
59
|
-
businessAssertions: [{
|
|
60
|
-
assertion: 'Report exports include seeded rows.',
|
|
61
|
-
status: 'pass',
|
|
62
|
-
dataProof: '3 seeded rows rendered and exported.',
|
|
63
|
-
artifactPaths: ['qa-artifacts/report-proof.json']
|
|
64
|
-
}]
|
|
65
|
-
});
|
|
66
|
-
assert.equal(businessPassedQa.outcome, 'business_assertion_passed');
|
|
67
|
-
assert.equal(classifyAIRunOutcome({
|
|
68
|
-
qa: businessPassedQa,
|
|
69
|
-
status: 'Passed',
|
|
70
|
-
phase: 'COMPLETE',
|
|
71
|
-
scorecardPassed: true,
|
|
72
|
-
deployStatus: 'pass',
|
|
73
|
-
publishStatus: 'published',
|
|
74
|
-
sampleDataStatus: 'pass'
|
|
75
|
-
}).outcome, 'accepted');
|
|
76
|
-
|
|
77
|
-
const supportSingularBusinessAssertionRun = buildSupportAIRunFromEvidence({
|
|
78
|
-
ticket: { _id: 'ticket-singular-aiqa', ticket_number: '004345', subject: 'Pricing import support QA proof' },
|
|
79
|
-
job: {
|
|
80
|
-
_id: 'support-job-singular-aiqa',
|
|
81
|
-
supportQaBusinessAssertion: {
|
|
82
|
-
assertion: 'Pricing import persists rows from both attached workbooks.',
|
|
83
|
-
status: 'pass',
|
|
84
|
-
result: 'business_assertion_passed',
|
|
85
|
-
workflow: 'Upload each attached workbook through production pricing import path.',
|
|
86
|
-
route: '/manage/pricing',
|
|
87
|
-
before: 'Pricing import proof batch started.',
|
|
88
|
-
action: 'Ran deterministic specialized workflow proof.',
|
|
89
|
-
expected: 'Rows reach insertPricesFromImport.',
|
|
90
|
-
observed: 'Both workbooks produced valid rows.',
|
|
91
|
-
dataProof: 'validPriceRecords=22, insertPricesFromImportPayloadSize=22',
|
|
92
|
-
mongoDelta: { collection: 'pricing-items', inserted: 22 },
|
|
93
|
-
artifactPaths: ['qa-artifacts/support-business-proof-before-after.png'],
|
|
94
|
-
metadata: { supportDiagnosisProof: true }
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
assert.equal(supportSingularBusinessAssertionRun.qa?.outcome, 'business_assertion_passed');
|
|
99
|
-
assert.equal(supportSingularBusinessAssertionRun.gates.some((gate) => gate.key === 'qa_business_assertion' && gate.status === 'pass'), true);
|
|
100
|
-
|
|
101
|
-
const releaseBlocked = classifyAIRunOutcome({
|
|
102
|
-
qa: businessPassedQa,
|
|
103
|
-
scorecardPassed: true,
|
|
104
|
-
deployStatus: 'Backend health smoke failed',
|
|
105
|
-
publishStatus: 'No such remote origin',
|
|
106
|
-
sampleDataStatus: 'empty collections detected'
|
|
107
|
-
});
|
|
108
|
-
assert.equal(releaseBlocked.outcome, 'release_blocked');
|
|
109
|
-
assert.ok(releaseBlocked.gates.some((gate) => gate.key === 'release' && gate.status === 'fail'));
|
|
110
|
-
|
|
111
|
-
const builtRun = buildAIRun({
|
|
112
|
-
source: 'aicoder_app',
|
|
113
|
-
sourceIds: { appId: 'app-1', jobId: 'job-1' },
|
|
114
|
-
title: 'Layflat Pressure Optimizer',
|
|
115
|
-
status: 'Passed',
|
|
116
|
-
phase: 'COMPLETE',
|
|
117
|
-
events: [],
|
|
118
|
-
qa: businessPassedQa,
|
|
119
|
-
scorecardPassed: true,
|
|
120
|
-
deployStatus: 'pass',
|
|
121
|
-
publishStatus: 'published',
|
|
122
|
-
sampleDataStatus: 'pass'
|
|
123
|
-
});
|
|
124
|
-
assert.equal(builtRun.outcome, 'accepted');
|
|
125
|
-
assert.equal(builtRun.sourceIds.appId, 'app-1');
|
|
126
|
-
|
|
127
|
-
const cost = buildAIRunCost([
|
|
128
|
-
{ model: 'gpt-5.3-codex', category: 'review', input_tokens: 1000, cached_input_tokens: 100, output_tokens: 250, cost_estimate: 1.23456789 },
|
|
129
|
-
{ model: 'gpt-5.4-mini', category: 'qa', inputTokens: 200, outputTokens: 50, estimatedUsd: 0.12 },
|
|
130
|
-
{
|
|
131
|
-
model: 'gpt-5.3-codex',
|
|
132
|
-
category: 'manual-monitoring',
|
|
133
|
-
usage_source: 'manual_codex',
|
|
134
|
-
usage_surface: 'aicoder',
|
|
135
|
-
cost_basis: 'manual_estimate',
|
|
136
|
-
is_manual: true,
|
|
137
|
-
is_untracked: true,
|
|
138
|
-
untracked_reason: 'Sidecar Codex session watched the Layflat builder.',
|
|
139
|
-
input_tokens: 3000,
|
|
140
|
-
output_tokens: 700,
|
|
141
|
-
cost_estimate: 7.5
|
|
142
|
-
}
|
|
143
|
-
]);
|
|
144
|
-
assert.equal(cost.inputTokens, 4200);
|
|
145
|
-
assert.equal(cost.cachedInputTokens, 100);
|
|
146
|
-
assert.equal(cost.outputTokens, 1000);
|
|
147
|
-
assert.equal(cost.categories.review.count, 1);
|
|
148
|
-
assert.deepEqual(cost.models, ['gpt-5.3-codex', 'gpt-5.4-mini']);
|
|
149
|
-
assert.equal(cost.sources?.manual_codex.estimatedUsd, 7.5);
|
|
150
|
-
assert.equal(cost.sources?.manual_codex.manualCount, 1);
|
|
151
|
-
assert.equal(cost.sources?.manual_codex.untrackedCount, 1);
|
|
152
|
-
assert.equal(cost.surfaces?.aicoder.estimatedUsd, 7.5);
|
|
153
|
-
assert.equal(cost.manualEstimatedUsd, 7.5);
|
|
154
|
-
assert.equal(cost.untrackedEstimatedUsd, 7.5);
|
|
155
|
-
assert.equal(cost.untrackedWarnings?.includes('Sidecar Codex session watched the Layflat builder.'), true);
|
|
156
|
-
|
|
157
|
-
const costOnlyManual = buildAIRunCost([
|
|
158
|
-
{
|
|
159
|
-
model: 'codex-manual',
|
|
160
|
-
category: 'manual-codex',
|
|
161
|
-
usage_source: 'manual_codex',
|
|
162
|
-
usage_surface: 'support',
|
|
163
|
-
cost_basis: 'manual_estimate',
|
|
164
|
-
is_manual: true,
|
|
165
|
-
is_untracked: true,
|
|
166
|
-
untracked_reason: 'Codex sidecar monitored support runner 004421.',
|
|
167
|
-
input_tokens: 0,
|
|
168
|
-
output_tokens: 0,
|
|
169
|
-
total_tokens: 0,
|
|
170
|
-
cost_estimate: 23.75
|
|
171
|
-
}
|
|
172
|
-
]);
|
|
173
|
-
assert.equal(costOnlyManual.totalTokens, 0);
|
|
174
|
-
assert.equal(costOnlyManual.estimatedUsd, 23.75);
|
|
175
|
-
assert.equal(costOnlyManual.manualEstimatedUsd, 23.75);
|
|
176
|
-
assert.equal(costOnlyManual.untrackedEstimatedUsd, 23.75);
|
|
177
|
-
assert.equal(costOnlyManual.sources?.manual_codex.count, 1);
|
|
178
|
-
assert.equal(costOnlyManual.surfaces?.support.estimatedUsd, 23.75);
|
|
179
|
-
|
|
180
|
-
const normalizedUsageRows = normalizeOpenAIUsageRowsForCosting([
|
|
181
|
-
{
|
|
182
|
-
model: 'gpt-5.5',
|
|
183
|
-
category: 'ai-dashboard-codex:master:file-body',
|
|
184
|
-
id_conversation: 'thread-1',
|
|
185
|
-
timestamp: '2026-06-13T10:00:00.000Z',
|
|
186
|
-
input_tokens: 1000,
|
|
187
|
-
cached_input_tokens: 800,
|
|
188
|
-
output_tokens: 100,
|
|
189
|
-
total_tokens: 1100,
|
|
190
|
-
cost_estimate: 1
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
model: 'gpt-5.5',
|
|
194
|
-
category: 'ai-dashboard-codex:master:file-body',
|
|
195
|
-
id_conversation: 'thread-1',
|
|
196
|
-
timestamp: '2026-06-13T10:01:00.000Z',
|
|
197
|
-
input_tokens: 1500,
|
|
198
|
-
cached_input_tokens: 1000,
|
|
199
|
-
output_tokens: 140,
|
|
200
|
-
total_tokens: 1640,
|
|
201
|
-
cost_estimate: 1.4
|
|
202
|
-
}
|
|
203
|
-
]);
|
|
204
|
-
assert.equal(normalizedUsageRows[1].input_tokens, 500);
|
|
205
|
-
assert.equal(normalizedUsageRows[1].cached_input_tokens, 200);
|
|
206
|
-
assert.equal(normalizedUsageRows[1].output_tokens, 40);
|
|
207
|
-
assert.equal(normalizedUsageRows[1].cost_estimate, 0.4);
|
|
208
|
-
|
|
209
|
-
const cumulativeCost = buildAIRunCost([
|
|
210
|
-
{
|
|
211
|
-
model: 'gpt-5.5',
|
|
212
|
-
category: 'ai-dashboard-codex:master:file-body',
|
|
213
|
-
id_conversation: 'thread-1',
|
|
214
|
-
timestamp: '2026-06-13T10:00:00.000Z',
|
|
215
|
-
input_tokens: 1000,
|
|
216
|
-
cached_input_tokens: 800,
|
|
217
|
-
output_tokens: 100,
|
|
218
|
-
total_tokens: 1100,
|
|
219
|
-
cost_estimate: 1
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
model: 'gpt-5.5',
|
|
223
|
-
category: 'ai-dashboard-codex:master:file-body',
|
|
224
|
-
id_conversation: 'thread-1',
|
|
225
|
-
timestamp: '2026-06-13T10:01:00.000Z',
|
|
226
|
-
input_tokens: 1500,
|
|
227
|
-
cached_input_tokens: 1000,
|
|
228
|
-
output_tokens: 140,
|
|
229
|
-
total_tokens: 1640,
|
|
230
|
-
cost_estimate: 1.4
|
|
231
|
-
}
|
|
232
|
-
]);
|
|
233
|
-
assert.equal(cumulativeCost.inputTokens, 1500);
|
|
234
|
-
assert.equal(cumulativeCost.cachedInputTokens, 1000);
|
|
235
|
-
assert.equal(cumulativeCost.outputTokens, 140);
|
|
236
|
-
assert.equal(cumulativeCost.estimatedUsd, 1.4);
|
|
237
|
-
assert.equal(estimateOpenAIUsageCost('gpt-5.4-2026-03-10', 1000, 100, 500), 0.002875);
|
|
238
|
-
assert.equal(estimateOpenAIUsageCost('gpt-5.3-codex', 1000, 100, 500), 0.00575);
|
|
239
|
-
assert.equal(estimateOpenAIUsageCost('gpt-5.4-codex', 1000, 100, 500), 0.002875);
|
|
240
|
-
assert.equal(estimateOpenAIUsageCost('codex-mini-latest', 1000, 100, 500), 0.000863);
|
|
241
|
-
|
|
242
|
-
const redacted = redactAIRunTrainingExample({
|
|
243
|
-
runId: 'run-1',
|
|
244
|
-
source: 'ai_assistant',
|
|
245
|
-
inputSummary: 'Mongo URL mongodb://user:password@host/db and email test@example.com',
|
|
246
|
-
actionSummary: 'Used key sk-12345678901234567890',
|
|
247
|
-
outcome: 'rejected',
|
|
248
|
-
evidence: ['ghp_12345678901234567890 appears here']
|
|
249
|
-
});
|
|
250
|
-
assert.match(redacted.inputSummary, /\[redacted-mongo-url\]/);
|
|
251
|
-
assert.match(redacted.inputSummary, /\[redacted-email\]/);
|
|
252
|
-
assert.match(redacted.actionSummary, /\[redacted-secret\]/);
|
|
253
|
-
assert.match(redacted.evidence[0], /\[redacted-secret\]/);
|
|
254
|
-
|
|
255
|
-
const supportRootCauseEntryContract = {
|
|
256
|
-
contract_id: 'support-root-cause-entry-test',
|
|
257
|
-
version: 'support_root_cause_entry_v1',
|
|
258
|
-
status: 'required',
|
|
259
|
-
required_output: {
|
|
260
|
-
object_key: 'support_diagnosis_gate',
|
|
261
|
-
status: 'passed',
|
|
262
|
-
required_fields: [
|
|
263
|
-
'issue_case',
|
|
264
|
-
'issue_class',
|
|
265
|
-
'accepted_hypothesis',
|
|
266
|
-
'rejected_alternatives',
|
|
267
|
-
'failing_path',
|
|
268
|
-
'owner_files',
|
|
269
|
-
'proof_plan',
|
|
270
|
-
'evidence'
|
|
271
|
-
]
|
|
272
|
-
},
|
|
273
|
-
owner_file_policy: {
|
|
274
|
-
max_files: 8,
|
|
275
|
-
exact_files_only: true,
|
|
276
|
-
edits_outside_owner_files_require_revised_diagnosis: true
|
|
277
|
-
},
|
|
278
|
-
business_proof_policy: {
|
|
279
|
-
requires_aiqa_business_assertion: true,
|
|
280
|
-
requires_before_action_after: true,
|
|
281
|
-
route_load_screenshot_scorecard_model_claim_not_acceptance: true,
|
|
282
|
-
required_artifacts: ['runner-evidence/diagnosis-gate.json', 'qa-artifacts/aiqa-business-assertion.json']
|
|
283
|
-
},
|
|
284
|
-
failure_policy: {
|
|
285
|
-
repeated_failure_without_new_evidence_parks_run: true,
|
|
286
|
-
infra_compile_puppeteer_startup_failures_route_to_infra_repair: true,
|
|
287
|
-
similar_tickets_and_commits_are_advisory_only: true
|
|
288
|
-
},
|
|
289
|
-
issue_class_probes: [
|
|
290
|
-
'no_op_submit',
|
|
291
|
-
'missing_wrong_data',
|
|
292
|
-
'filter_query_mismatch',
|
|
293
|
-
'invoice_pdf_export',
|
|
294
|
-
'upload_import',
|
|
295
|
-
'route_auth_hydration',
|
|
296
|
-
'slow_query_performance'
|
|
297
|
-
].map((issueClass) => ({
|
|
298
|
-
issue_class: issueClass,
|
|
299
|
-
required_paths: ['frontend_event', 'backend_method'],
|
|
300
|
-
required_evidence: ['before/action/after business state'],
|
|
301
|
-
false_pass_blockers: ['route loaded only']
|
|
302
|
-
}))
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
const supportRun = buildSupportAIRunFromEvidence({
|
|
306
|
-
ticket: { _id: 'ticket-004421', ticketNumber: '004421', title: 'QA route only false pass' },
|
|
307
|
-
job: {
|
|
308
|
-
_id: 'support-job-1',
|
|
309
|
-
status: 'Running',
|
|
310
|
-
phase: 'QA',
|
|
311
|
-
supportRootCauseEntryContract,
|
|
312
|
-
supportRootCauseSimilarFixHintContract: {
|
|
313
|
-
contract_id: 'support-similar-fix-hints-test',
|
|
314
|
-
version: 'support_similar_fix_hint_contract_v1',
|
|
315
|
-
status: 'advisory_only',
|
|
316
|
-
source: 'ai_runs_and_completed_support_jobs',
|
|
317
|
-
candidate_count: 3,
|
|
318
|
-
hint_count: 1,
|
|
319
|
-
owner_file_hints: ['server/src/publications/support-tickets.ts'],
|
|
320
|
-
ranked_hints: [{
|
|
321
|
-
rank: 1,
|
|
322
|
-
source: 'support_ticket',
|
|
323
|
-
score: 188,
|
|
324
|
-
ticket_number: '004333',
|
|
325
|
-
commit_sha: '2222222222222222222222222222222222222222',
|
|
326
|
-
issue_class: 'filter_query_mismatch',
|
|
327
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
328
|
-
reason: 'issue_class:filter_query_mismatch; owner_file_overlap:server/src/publications/support-tickets.ts',
|
|
329
|
-
title: 'Prior accepted customer filter fix'
|
|
330
|
-
}],
|
|
331
|
-
usage_policy: {
|
|
332
|
-
similar_hints_are_not_proof: true,
|
|
333
|
-
fresh_reproduction_or_blocked_reproduction_required: true,
|
|
334
|
-
accepted_hypothesis_must_be_current_ticket_specific: true,
|
|
335
|
-
owner_files_require_current_ticket_evidence: true,
|
|
336
|
-
must_record_rejected_hints_or_alternatives: true
|
|
337
|
-
},
|
|
338
|
-
required_model_actions: [
|
|
339
|
-
'Inspect the top hint owner files only as starting candidates.',
|
|
340
|
-
'For every reused owner file, cite current-ticket code/data/browser/log evidence.'
|
|
341
|
-
]
|
|
342
|
-
},
|
|
343
|
-
supportV5DiagnosisGate: {
|
|
344
|
-
issue_case: {
|
|
345
|
-
customer_complaint: 'Support ticket list shows tickets from the wrong customer after applying a customer filter.',
|
|
346
|
-
expected_result: 'Only tickets for Customer B should appear when Customer B is selected.',
|
|
347
|
-
observed_result: 'A Customer A ticket remains visible while filtered to Customer B.',
|
|
348
|
-
route_module: '/support tickets list',
|
|
349
|
-
account_customer_context: 'Support admin reviewing ticket 004421 for Customer B.',
|
|
350
|
-
reproduction_status: 'reproduced'
|
|
351
|
-
},
|
|
352
|
-
issue_class: 'filter_query_mismatch',
|
|
353
|
-
status: 'passed',
|
|
354
|
-
accepted_hypothesis: {
|
|
355
|
-
statement: 'The ticket list query ignores the customer filter.',
|
|
356
|
-
falsifiable_test: 'Apply the Customer B filter and compare the returned rows with the persisted customer id for each ticket.',
|
|
357
|
-
evidence: ['QA artifact shows Customer A ticket visible while Customer B filter is active.']
|
|
358
|
-
},
|
|
359
|
-
rejected_alternatives: [
|
|
360
|
-
'Frontend select state was not the root cause because the network payload includes the selected Customer B filter.',
|
|
361
|
-
'Authentication was not the root cause because the affected support admin can load the ticket list route.'
|
|
362
|
-
],
|
|
363
|
-
failing_path: {
|
|
364
|
-
frontend: 'Support ticket customer filter submits selected customer id.',
|
|
365
|
-
backend: 'server/src/publications/support-tickets.ts ticket list publication',
|
|
366
|
-
data_query: 'Mongo ticket query does not constrain by selected customer id.',
|
|
367
|
-
description: 'Filter input reaches the backend, but the publication query returns rows outside the selected customer.'
|
|
368
|
-
},
|
|
369
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
370
|
-
proof_plan: {
|
|
371
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
372
|
-
action: 'Apply the Customer B filter and reload the ticket list.',
|
|
373
|
-
after: 'Only Customer B tickets are listed.',
|
|
374
|
-
business_assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
375
|
-
data_assertion: 'Every returned ticket row has customerId equal to Customer B.',
|
|
376
|
-
artifact_expectation: 'QA stores before/action/after row snapshots and the filtered publication payload.',
|
|
377
|
-
business_proof_contract: {
|
|
378
|
-
issue_class: 'filter_query_mismatch',
|
|
379
|
-
setup_state: 'Seed or select one Customer A ticket and one Customer B ticket.',
|
|
380
|
-
action_under_test: 'Apply the Customer B filter on the support ticket list.',
|
|
381
|
-
expected_business_state_change: 'Rows outside Customer B are excluded while Customer B rows remain visible.',
|
|
382
|
-
prohibited_false_pass: 'Route load or non-empty table without row/customer proof.',
|
|
383
|
-
proof_artifacts: ['qa-artifacts/support-filter-before-after.json'],
|
|
384
|
-
data_or_dom_assertion: 'DOM rows and publication payload contain only Customer B ticket ids.'
|
|
385
|
-
}
|
|
386
|
-
},
|
|
387
|
-
evidence: [{
|
|
388
|
-
type: 'ticket',
|
|
389
|
-
summary: 'Ticket 004421 reports wrong-customer tickets appearing after a customer filter is applied.'
|
|
390
|
-
}, {
|
|
391
|
-
type: 'qa',
|
|
392
|
-
summary: 'Browser QA reproduced Customer A ticket visible while Customer B filter was active.',
|
|
393
|
-
artifactPath: 'qa-artifacts/support-filter-reproduction.json'
|
|
394
|
-
}, {
|
|
395
|
-
type: 'code',
|
|
396
|
-
summary: 'Publication owner file contains the query that returns support ticket rows.'
|
|
397
|
-
}]
|
|
398
|
-
},
|
|
399
|
-
supportV5AutonomousDecision: {
|
|
400
|
-
nextActionContract: {
|
|
401
|
-
contractId: 'support-next-action-safe-repair',
|
|
402
|
-
action: 'run_owner_scoped_repair',
|
|
403
|
-
label: 'Run owner-scoped repair',
|
|
404
|
-
primaryCommand: 'run_support_v5_owner_scoped_repair',
|
|
405
|
-
lane: 'build',
|
|
406
|
-
stepType: 'owner_scoped_repair',
|
|
407
|
-
safeToAutoRun: true,
|
|
408
|
-
requiresHumanApproval: false,
|
|
409
|
-
canRunWithoutCodexMonitor: true,
|
|
410
|
-
codexFallbackRequired: false,
|
|
411
|
-
rootCauseFirstSatisfied: true,
|
|
412
|
-
costRisk: 'expensive_model',
|
|
413
|
-
preconditions: ['SupportDiagnosisGate passed.'],
|
|
414
|
-
expectedStateTransition: 'Owner-scoped repair updates only the diagnosed publication owner file, then records business proof or parks on unchanged evidence.',
|
|
415
|
-
successEvidence: ['AIQaBusinessAssertion mapped to proof_plan.'],
|
|
416
|
-
stopConditions: ['Same failure class repeats without new evidence.'],
|
|
417
|
-
forbiddenActions: [
|
|
418
|
-
'Do not edit outside owner_files without a revised diagnosis gate.',
|
|
419
|
-
'Do not accept route-load-only proof as support completion.'
|
|
420
|
-
],
|
|
421
|
-
ownerFiles: ['server/src/publications/support-tickets.ts'],
|
|
422
|
-
nextCommands: ['run_support_v5_owner_scoped_repair'],
|
|
423
|
-
decisionBasis: {
|
|
424
|
-
diagnosisValid: true,
|
|
425
|
-
ownerFilesReady: true,
|
|
426
|
-
proofPlanReady: true,
|
|
427
|
-
businessProofReady: false,
|
|
428
|
-
evidenceFreshnessStatus: 'fresh',
|
|
429
|
-
evidenceStrength: 'medium',
|
|
430
|
-
failureClass: 'product_code',
|
|
431
|
-
sameFailureCount: 0,
|
|
432
|
-
hotfixCommitRequired: true,
|
|
433
|
-
liveHotfixBlockedUntilCommit: false
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
},
|
|
438
|
-
taskEvents: [{ message: 'Route loaded in browser.', phase: 'qa' }],
|
|
439
|
-
usageLedger: [{
|
|
440
|
-
model: 'codex-manual',
|
|
441
|
-
category: 'manual-codex-monitor',
|
|
442
|
-
usage_source: 'manual_codex',
|
|
443
|
-
usage_surface: 'support',
|
|
444
|
-
cost_basis: 'manual_estimate',
|
|
445
|
-
is_manual: true,
|
|
446
|
-
is_untracked: true,
|
|
447
|
-
untracked_reason: 'Codex sidecar monitored support runner 004421.',
|
|
448
|
-
total_tokens: 0,
|
|
449
|
-
cost_estimate: 18.25
|
|
450
|
-
}],
|
|
451
|
-
qaEvidence: {
|
|
452
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
453
|
-
compile: { status: 'pass' },
|
|
454
|
-
routeProbes: [{ route: '/support/004421', status: 'pass', screenshot: 'qa-artifacts/route.jpg' }],
|
|
455
|
-
hotfixEvidence: {
|
|
456
|
-
channel: 'backend_js',
|
|
457
|
-
target: {
|
|
458
|
-
host: 'backend.resolveio.com',
|
|
459
|
-
path: '/var/app/current/http/runner-manager-selftest.js'
|
|
460
|
-
},
|
|
461
|
-
compiledArtifactPath: 'dist/http/runner-manager-selftest.js',
|
|
462
|
-
remoteChecksumBefore: '1111111111111111111111111111111111111111111111111111111111111111',
|
|
463
|
-
remoteChecksumAfter: '2222222222222222222222222222222222222222222222222222222222222222',
|
|
464
|
-
sourceCommitSha: '6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
465
|
-
githubCommitUrl: 'https://github.com/resolveio/resolveio-all/commit/6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
466
|
-
gitCommitStatus: 'passed',
|
|
467
|
-
gitPushStatus: 'passed',
|
|
468
|
-
restartEvidence: 'nodejs and resolveio_support_ticket_codex_manager restarted on all support hosts',
|
|
469
|
-
healthCheckStatus: 'passed',
|
|
470
|
-
selfTestStatus: 'passed'
|
|
471
|
-
},
|
|
472
|
-
scorecardPassed: true
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
assert.equal(supportRun.source, 'support_ticket');
|
|
476
|
-
assert.equal(supportRun.sourceIds.ticketNumber, '004421');
|
|
477
|
-
assert.equal(supportRun.outcome, 'false_pass');
|
|
478
|
-
assert.equal(supportRun.metadata?.diagnosis?.issueClass, 'filter_query_mismatch');
|
|
479
|
-
assert.equal(supportRun.metadata?.rootCauseEntryContract?.contractId, 'support-root-cause-entry-test');
|
|
480
|
-
assert.equal(supportRun.metadata?.rootCauseEntryContract?.issueClassProbeCount, 7);
|
|
481
|
-
assert.deepEqual(supportRun.metadata?.diagnosis?.ownerFiles, ['server/src/publications/support-tickets.ts']);
|
|
482
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_diagnosis_evidence_pack'), true);
|
|
483
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_diagnosis_evidence_pack' && gate.status === 'pass'), true);
|
|
484
|
-
assert.equal(supportRun.metadata?.diagnosisEvidencePack?.readOnly, true);
|
|
485
|
-
assert.equal(supportRun.metadata?.diagnosisEvidencePack?.sourceEditsAllowed, false);
|
|
486
|
-
assert.equal(supportRun.metadata?.diagnosisEvidencePack?.issueClassProbeCount, 7);
|
|
487
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_similar_fix_hint_contract'), true);
|
|
488
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_similar_fix_hint_contract' && gate.status === 'pass'), true);
|
|
489
|
-
assert.equal(supportRun.metadata?.similarFixHintContract?.advisoryOnly, true);
|
|
490
|
-
assert.equal(supportRun.metadata?.similarFixHintContract?.ownerFilesRequireCurrentEvidence, true);
|
|
491
|
-
assert.equal(supportRun.metadata?.similarFixHintContract?.hintCount, 1);
|
|
492
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_diagnosis_proof_matrix'), true);
|
|
493
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_diagnosis_proof_matrix' && gate.status === 'pass'), true);
|
|
494
|
-
assert.equal(supportRun.metadata?.diagnosisProofMatrix?.matrixStatus, 'ready');
|
|
495
|
-
assert.deepEqual(supportRun.metadata?.diagnosisProofMatrix?.uncoveredOwnerFiles, []);
|
|
496
|
-
assert.equal(supportRun.metadata?.diagnosisProofMatrix?.rootCauseEvidenceCount >= 1, true);
|
|
497
|
-
assert.equal(supportRun.metadata?.diagnosis?.proofMatrixStatus, 'ready');
|
|
498
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_owner_scoped_repair_contract'), true);
|
|
499
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_owner_scoped_repair_contract' && gate.status === 'pass'), true);
|
|
500
|
-
assert.equal(supportRun.metadata?.ownerScopedRepairContract?.contractStatus, 'ready');
|
|
501
|
-
assert.equal(supportRun.metadata?.ownerScopedRepairContract?.sourceEditsAllowed, true);
|
|
502
|
-
assert.equal(supportRun.metadata?.ownerScopedRepairContract?.patchUnitCount, 1);
|
|
503
|
-
assert.equal(supportRun.metadata?.ownerScopedRepairContract?.requiredEvidenceAfterRepair.some((entry: string) => /AIQaBusinessAssertion/i.test(entry)), true);
|
|
504
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_issue_class_probe_plan'), true);
|
|
505
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_issue_class_probe_plan' && gate.status === 'pass'), true);
|
|
506
|
-
assert.equal(supportRun.metadata?.issueClassProbePlan?.issueClassProbePlanReady, true);
|
|
507
|
-
assert.equal(supportRun.metadata?.issueClassProbePlan?.issueClass, 'filter_query_mismatch');
|
|
508
|
-
assert.equal(supportRun.events.some((event) => event.category === 'diagnosis_gate'), true);
|
|
509
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_root_cause_entry_contract'), true);
|
|
510
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_root_cause_entry_contract' && gate.status === 'pass'), true);
|
|
511
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_next_action_contract'), true);
|
|
512
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_next_action_contract' && gate.status === 'pass'), true);
|
|
513
|
-
assert.equal(supportRun.metadata?.nextActionContract?.canRunWithoutCodexMonitor, true);
|
|
514
|
-
assert.equal(supportRun.metadata?.nextActionContract?.hotfixCommitRequired, true);
|
|
515
|
-
assert.equal(supportRun.metadata?.nextActionContract?.liveHotfixBlockedUntilCommit, false);
|
|
516
|
-
assert.equal(supportRun.events.some((event) => event.category === 'support_manager_execution_packet'), true);
|
|
517
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'support_manager_execution_packet' && gate.status === 'pass'), true);
|
|
518
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.status, 'auto_ready');
|
|
519
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.executeNow, true);
|
|
520
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.canRunWithoutCodexMonitor, true);
|
|
521
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.codexFallbackRequired, false);
|
|
522
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.retryScope, 'owner_files_only');
|
|
523
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.maxAttemptsBeforeFreshEvidence, 1);
|
|
524
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.proofResetContract?.retryScope, 'owner_files_only');
|
|
525
|
-
assert.equal(supportRun.metadata?.managerExecutionPacket?.proofResetContract?.maxAttemptsBeforeFreshEvidence, 1);
|
|
526
|
-
assert.ok(supportRun.metadata?.managerExecutionPacket?.proofResetContract?.requiredResetEvidence?.length > 0);
|
|
527
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'cost_observability' && gate.status === 'warn'), true);
|
|
528
|
-
assert.equal(supportRun.metadata?.costObservability?.externalCodexMonitorUsed, true);
|
|
529
|
-
assert.equal(supportRun.metadata?.costObservability?.manualEstimatedUsd, 18.25);
|
|
530
|
-
assert.ok(supportRun.metadata?.costObservability?.warnings?.some((warning: string) => /support runner 004421/i.test(warning)));
|
|
531
|
-
assert.equal(supportRun.events.some((event) => event.type === 'hotfix' && event.category === 'backend_js'), true);
|
|
532
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'hotfix_evidence' && gate.status === 'pass'), true);
|
|
533
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'hotfix_commit_proof' && gate.status === 'pass'), true);
|
|
534
|
-
assert.equal(supportRun.events.some((event) => event.category === 'hotfix_commit_proof' && event.metadata?.passed === true), true);
|
|
535
|
-
assert.equal(supportRun.metadata?.hotfixDurability?.commitProofPassed, true);
|
|
536
|
-
assert.equal(supportRun.metadata?.hotfixDurability?.commitBlocked, false);
|
|
537
|
-
assert.equal(supportRun.gates.some((gate) => gate.key === 'qa_business_assertion' && gate.status === 'blocked'), true);
|
|
538
|
-
|
|
539
|
-
const supportManagerContinuationRun = buildSupportAIRunFromEvidence({
|
|
540
|
-
ticket: {
|
|
541
|
-
_id: 'ticket-manager-continuation',
|
|
542
|
-
ticketNumber: '004602',
|
|
543
|
-
title: 'Support manager continuation path',
|
|
544
|
-
automation: {
|
|
545
|
-
manager: {
|
|
546
|
-
status: 'parked',
|
|
547
|
-
last_continuation_contract: {
|
|
548
|
-
contract_id: 'support-continuation-selftest',
|
|
549
|
-
status: 'waiting_for_unblock',
|
|
550
|
-
action: 'run_evidence_probe',
|
|
551
|
-
required_state_transition: 'Evidence probe records a changed blocker/evidence hash, new artifact, or remains parked.'
|
|
552
|
-
},
|
|
553
|
-
last_operator_guidance_response: {
|
|
554
|
-
response_id: 'support-operator-guidance-response-selftest',
|
|
555
|
-
status: 'accepted',
|
|
556
|
-
accepted: true,
|
|
557
|
-
guidance_id: 'support-operator-guidance-selftest',
|
|
558
|
-
requested_action: 'run_evidence_probe',
|
|
559
|
-
submit_action: 'run_evidence_probe',
|
|
560
|
-
can_run_without_codex_monitor: true,
|
|
561
|
-
safe_to_autorun_after_input: false,
|
|
562
|
-
resume_unblock_contract: {
|
|
563
|
-
contract_id: 'support-resume-unblock-selftest-evidence',
|
|
564
|
-
action: 'run_evidence_probe',
|
|
565
|
-
allowed_after_input: ['run_evidence_probe'],
|
|
566
|
-
required_state_transition: 'Evidence probe records a changed blocker/evidence hash, new artifact, or remains parked.',
|
|
567
|
-
blocks_product_repair_until_changed_evidence: true,
|
|
568
|
-
proof_required_before_continuation: false
|
|
569
|
-
},
|
|
570
|
-
resume_unblock_response: {
|
|
571
|
-
contract_id: 'support-resume-unblock-selftest-evidence',
|
|
572
|
-
action: 'run_evidence_probe',
|
|
573
|
-
operator_evidence_summary: 'Operator attached a new failing QA row artifact for the evidence probe.',
|
|
574
|
-
artifact_paths: ['qa-artifacts/selftest-new-evidence.json'],
|
|
575
|
-
material_evidence_claimed: true,
|
|
576
|
-
material_evidence_signals: ['artifact_paths']
|
|
577
|
-
},
|
|
578
|
-
recorded_at: '2026-06-15T00:12:00.000Z'
|
|
579
|
-
},
|
|
580
|
-
last_operator_guidance_resume_dispatch: {
|
|
581
|
-
status: 'queued',
|
|
582
|
-
job_id: 'support-resume-job-selftest',
|
|
583
|
-
dispatch_action: 'run_evidence_probe'
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
},
|
|
588
|
-
job: {
|
|
589
|
-
_id: 'support-job-manager-continuation',
|
|
590
|
-
status: 'Running',
|
|
591
|
-
phase: 'MANAGER_RECOVERY'
|
|
592
|
-
},
|
|
593
|
-
qaEvidence: {
|
|
594
|
-
infraChecks: [{ name: 'support_manager', status: 'pass' }],
|
|
595
|
-
compile: { status: 'pass' }
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
assert.equal(supportManagerContinuationRun.gates.some((gate) => gate.key === 'support_manager_continuation' && gate.status === 'pass'), true);
|
|
599
|
-
assert.equal(supportManagerContinuationRun.events.some((event) => event.category === 'support_manager_continuation'), true);
|
|
600
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.managerStatus, 'parked');
|
|
601
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.operatorGuidanceAccepted, true);
|
|
602
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.resumeUnblockContractId, 'support-resume-unblock-selftest-evidence');
|
|
603
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.resumeDispatchStatus, 'queued');
|
|
604
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.canRunWithoutCodexMonitor, true);
|
|
605
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.blocksProductRepairUntilChangedEvidence, true);
|
|
606
|
-
assert.equal(supportManagerContinuationRun.metadata?.managerContinuation?.materialEvidenceClaimed, true);
|
|
607
|
-
assert.ok(supportManagerContinuationRun.metadata?.managerContinuation?.artifactPaths?.includes('qa-artifacts/selftest-new-evidence.json'));
|
|
608
|
-
|
|
609
|
-
const blockedSupportAutonomyRun = buildSupportAIRunFromEvidence({
|
|
610
|
-
ticket: {
|
|
611
|
-
_id: 'ticket-approval-blocked',
|
|
612
|
-
ticketNumber: '004600',
|
|
613
|
-
title: 'Support autonomy approval blocked',
|
|
614
|
-
automation: {
|
|
615
|
-
autoloop: {
|
|
616
|
-
last_approval_block: {
|
|
617
|
-
record_id: 'support-autoloop-approval-block-over-six',
|
|
618
|
-
status: 'blocked_autonomy_approval_required',
|
|
619
|
-
action: 'approve_support_autonomy_over_limit',
|
|
620
|
-
next_action: 'approve_support_autonomy_over_limit',
|
|
621
|
-
approval_contract_id: 'support-autonomy-approval-blocked',
|
|
622
|
-
scope_fingerprint: 'selftest-scope-over-six',
|
|
623
|
-
decision_kind: 'over_limit_approval_required',
|
|
624
|
-
requires_over_limit_approval: true,
|
|
625
|
-
on_the_fly_scope_change_approval_required: true,
|
|
626
|
-
target_grade: 'A',
|
|
627
|
-
required_terminal_state: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files',
|
|
628
|
-
reason: 'Iteration 1: Support autonomy approval required before product-code repair: over_6_hours_requires_operator_approval',
|
|
629
|
-
product_repair_dispatch_guard: {
|
|
630
|
-
status: 'blocked',
|
|
631
|
-
next_action: 'approve_support_autonomy_over_limit',
|
|
632
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
633
|
-
blockers: ['over_6_hours_requires_operator_approval']
|
|
634
|
-
},
|
|
635
|
-
human_decision_request: {
|
|
636
|
-
request_id: 'support-autoloop-human-decision-over-six',
|
|
637
|
-
required: true,
|
|
638
|
-
status: 'waiting_for_operator',
|
|
639
|
-
decision_kind: 'over_limit_approval_required',
|
|
640
|
-
approval_action: 'approve_support_autonomy_over_limit',
|
|
641
|
-
preferred_choice_id: 'approve_over_limit_autonomy',
|
|
642
|
-
can_approve_from_console: true,
|
|
643
|
-
reason: 'Approve the current over-limit scope or keep the run parked.',
|
|
644
|
-
evidence: {
|
|
645
|
-
requires_over_limit_approval: true,
|
|
646
|
-
changed_files: ['server/src/publications/support-tickets.ts']
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
},
|
|
651
|
-
runner_console: {
|
|
652
|
-
autonomy_approval: {
|
|
653
|
-
contract_id: 'support-autonomy-approval-blocked',
|
|
654
|
-
status: 'approval_required',
|
|
655
|
-
approved: false,
|
|
656
|
-
estimated_hours: 8,
|
|
657
|
-
max_auto_hours_without_approval: 6,
|
|
658
|
-
over_max_auto_hours: true,
|
|
659
|
-
bug_not_bug: 'bug',
|
|
660
|
-
bug_not_bug_classification_approved: true,
|
|
661
|
-
decision_kind: 'over_limit_approval_required',
|
|
662
|
-
approval_action: 'approve_support_autonomy_over_limit',
|
|
663
|
-
preferred_choice_id: 'approve_over_limit_autonomy',
|
|
664
|
-
can_approve_from_console: true,
|
|
665
|
-
requires_over_limit_approval: true,
|
|
666
|
-
after_approval_autopilot_until_a_grade: true,
|
|
667
|
-
target_grade: 'A',
|
|
668
|
-
autopilot_completion_contract: {
|
|
669
|
-
mode: 'approved_scope_to_a_grade_pr',
|
|
670
|
-
status: 'waiting_for_operator_approval',
|
|
671
|
-
required_terminal_state: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files',
|
|
672
|
-
stop_or_park_conditions: ['over six hours without explicit over-limit approval']
|
|
673
|
-
},
|
|
674
|
-
qa_screenshots_required: true,
|
|
675
|
-
before_action_after_business_proof_required: true,
|
|
676
|
-
aiqa_business_assertion_required: true,
|
|
677
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
678
|
-
approved_owner_files: ['server/src/publications/support-tickets.ts'],
|
|
679
|
-
required_completion_evidence: ['before/action/after AIQaBusinessAssertion', 'QA screenshots']
|
|
680
|
-
},
|
|
681
|
-
last_product_repair_dispatch_guard: {
|
|
682
|
-
guard: 'support_autonomy_product_repair_dispatch_guard',
|
|
683
|
-
status: 'blocked',
|
|
684
|
-
allowed: false,
|
|
685
|
-
action: 'run_owner_scoped_repair',
|
|
686
|
-
edits_product_code: true,
|
|
687
|
-
auto_continue_after_approval: false,
|
|
688
|
-
next_action: 'approve_support_autonomy_over_limit',
|
|
689
|
-
continuation_contract: {
|
|
690
|
-
mode: 'approved_scope_to_a_grade_pr',
|
|
691
|
-
status: 'waiting_for_operator_approval',
|
|
692
|
-
required_terminal_state: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files'
|
|
693
|
-
},
|
|
694
|
-
terminal_target: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files',
|
|
695
|
-
next_proof_phases: ['confirm_support_diagnosis_gate', 'run_business_proof_qa_with_screenshots'],
|
|
696
|
-
allowed_auto_actions: ['run_owner_scoped_repair', 'run_business_proof_qa'],
|
|
697
|
-
forbidden_actions: ['customer success reply before AIQaBusinessAssertion proof'],
|
|
698
|
-
requires_over_limit_approval: true,
|
|
699
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
700
|
-
blockers: ['over_6_hours_requires_operator_approval']
|
|
701
|
-
}
|
|
702
|
-
},
|
|
703
|
-
manager: {
|
|
704
|
-
last_human_decision_request: {
|
|
705
|
-
request_id: 'support-autonomy-human-decision-blocked',
|
|
706
|
-
required: true,
|
|
707
|
-
status: 'pending',
|
|
708
|
-
decision_kind: 'over_limit_approval_required',
|
|
709
|
-
approval_action: 'approve_support_autonomy_over_limit',
|
|
710
|
-
preferred_choice_id: 'approve_over_limit_autonomy',
|
|
711
|
-
can_approve_from_console: true,
|
|
712
|
-
reason: 'Estimated work is above the six-hour autonomy ceiling.',
|
|
713
|
-
evidence: {
|
|
714
|
-
requires_over_limit_approval: true,
|
|
715
|
-
changed_files: ['server/src/publications/support-tickets.ts']
|
|
716
|
-
},
|
|
717
|
-
choices: [{
|
|
718
|
-
choice_id: 'approve_over_limit_autonomy',
|
|
719
|
-
action: 'approve_support_autonomy_over_limit',
|
|
720
|
-
label: 'Approve Over-Limit Autopilot',
|
|
721
|
-
safety: 'high'
|
|
722
|
-
}]
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
job: {
|
|
728
|
-
_id: 'support-job-approval-blocked',
|
|
729
|
-
status: 'Running',
|
|
730
|
-
phase: 'BUILD'
|
|
731
|
-
},
|
|
732
|
-
qaEvidence: {
|
|
733
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
734
|
-
compile: { status: 'pass' },
|
|
735
|
-
routeProbes: [{ route: '/support/004600', status: 'pass', screenshot: 'qa-artifacts/support-approval-route.png' }],
|
|
736
|
-
businessAssertions: [{
|
|
737
|
-
assertion: 'Synthetic business proof would otherwise pass.',
|
|
738
|
-
status: 'pass',
|
|
739
|
-
action: 'Apply filter.',
|
|
740
|
-
expected: 'Only matching records appear.',
|
|
741
|
-
observed: 'Only matching records appeared.',
|
|
742
|
-
dataProof: 'Synthetic row proof.'
|
|
743
|
-
}],
|
|
744
|
-
scorecardPassed: true
|
|
745
|
-
}
|
|
746
|
-
});
|
|
747
|
-
assert.equal(blockedSupportAutonomyRun.outcome, 'manual_handoff');
|
|
748
|
-
assert.equal(blockedSupportAutonomyRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), true);
|
|
749
|
-
assert.equal(blockedSupportAutonomyRun.gates.some((gate) => gate.key === 'support_product_repair_dispatch_guard' && gate.status === 'blocked'), true);
|
|
750
|
-
assert.equal(blockedSupportAutonomyRun.gates.some((gate) => gate.key === 'support_autoloop_approval_block' && gate.status === 'blocked'), true);
|
|
751
|
-
assert.equal(blockedSupportAutonomyRun.gates.some((gate) => gate.key === 'support_human_decision_request' && gate.status === 'blocked'), true);
|
|
752
|
-
assert.equal(blockedSupportAutonomyRun.events.some((event) => event.category === 'support_autonomy_approval'), true);
|
|
753
|
-
assert.equal(blockedSupportAutonomyRun.events.some((event) => event.category === 'support_autoloop_approval_block'), true);
|
|
754
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autonomyApproval?.requiresOverLimitApproval, true);
|
|
755
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autonomyApproval?.afterApprovalAutopilotUntilAGrade, true);
|
|
756
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autonomyApproval?.qaScreenshotsRequired, true);
|
|
757
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autonomyApproval?.terminalTarget, 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files');
|
|
758
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.productRepairDispatchGuard?.nextAction, 'approve_support_autonomy_over_limit');
|
|
759
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.productRepairDispatchGuard?.continuationContractMode, 'approved_scope_to_a_grade_pr');
|
|
760
|
-
assert.ok(blockedSupportAutonomyRun.metadata?.productRepairDispatchGuard?.nextProofPhases?.includes('run_business_proof_qa_with_screenshots'));
|
|
761
|
-
assert.ok(blockedSupportAutonomyRun.metadata?.productRepairDispatchGuard?.forbiddenActions?.some((action: string) => /customer success reply/i.test(action)));
|
|
762
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.humanDecisionRequest?.preferredChoiceId, 'approve_over_limit_autonomy');
|
|
763
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autoloopApprovalBlock?.nextAction, 'approve_support_autonomy_over_limit');
|
|
764
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autoloopApprovalBlock?.requiresOverLimitApproval, true);
|
|
765
|
-
assert.equal(blockedSupportAutonomyRun.metadata?.autoloopApprovalBlock?.humanDecisionPreferredChoiceId, 'approve_over_limit_autonomy');
|
|
766
|
-
assert.match(blockedSupportAutonomyRun.nextAction || '', /approve_support_autonomy_over_limit/);
|
|
767
|
-
|
|
768
|
-
const elapsedAutoloopApprovalRun = buildSupportAIRunFromEvidence({
|
|
769
|
-
ticket: {
|
|
770
|
-
_id: 'ticket-autoloop-elapsed-approval',
|
|
771
|
-
ticketNumber: '004603',
|
|
772
|
-
title: 'Support autoloop elapsed runtime approval boundary',
|
|
773
|
-
automation: {
|
|
774
|
-
autoloop: {
|
|
775
|
-
status: 'stopped',
|
|
776
|
-
last_approval_block: {
|
|
777
|
-
record_id: 'support-autoloop-approval-block-elapsed',
|
|
778
|
-
status: 'blocked_elapsed_reapproval_required',
|
|
779
|
-
action: 'approve_support_autonomy_over_limit',
|
|
780
|
-
next_action: 'approve_support_autonomy_over_limit',
|
|
781
|
-
run_id: 'support-auto-improve-elapsed',
|
|
782
|
-
iteration: 2,
|
|
783
|
-
reason: 'Approved support autoloop runtime reached 6.25 hours, above the 6-hour approved runtime boundary.',
|
|
784
|
-
decision_kind: 'elapsed_wall_clock_reapproval_required',
|
|
785
|
-
requires_elapsed_reapproval: true,
|
|
786
|
-
requires_over_limit_approval: true,
|
|
787
|
-
elapsed_runtime_ms: 22500000,
|
|
788
|
-
elapsed_runtime_hours: 6.25,
|
|
789
|
-
max_approved_runtime_ms: 21600000,
|
|
790
|
-
max_approved_runtime_hours: 6,
|
|
791
|
-
max_wall_clock_ms: 21600000,
|
|
792
|
-
max_wall_clock_hours: 6,
|
|
793
|
-
human_decision_request: {
|
|
794
|
-
request_id: 'support-autonomy-elapsed-runtime',
|
|
795
|
-
required: true,
|
|
796
|
-
status: 'waiting_for_operator',
|
|
797
|
-
decision_kind: 'elapsed_wall_clock_reapproval_required',
|
|
798
|
-
approval_action: 'approve_support_autonomy_over_limit',
|
|
799
|
-
preferred_choice_id: 'approve_over_limit_autonomy'
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
|
-
job: {
|
|
806
|
-
_id: 'support-job-elapsed-approval',
|
|
807
|
-
status: 'Stopped',
|
|
808
|
-
phase: 'AUTOLOOP'
|
|
809
|
-
},
|
|
810
|
-
now: '2026-06-17T12:00:00.000Z'
|
|
811
|
-
});
|
|
812
|
-
const elapsedApprovalGate = elapsedAutoloopApprovalRun.gates.find((gate) => gate.key === 'support_autoloop_approval_block');
|
|
813
|
-
assert.equal(elapsedAutoloopApprovalRun.outcome, 'manual_handoff');
|
|
814
|
-
assert.equal(elapsedApprovalGate?.status, 'blocked');
|
|
815
|
-
assert.equal(elapsedApprovalGate?.metadata?.requiresElapsedReapproval, true);
|
|
816
|
-
assert.equal(elapsedApprovalGate?.metadata?.elapsedRuntimeHours, 6.25);
|
|
817
|
-
assert.equal(elapsedApprovalGate?.metadata?.maxApprovedRuntimeHours, 6);
|
|
818
|
-
assert.equal(elapsedAutoloopApprovalRun.metadata?.autoloopApprovalBlock?.requiresElapsedReapproval, true);
|
|
819
|
-
assert.equal(elapsedAutoloopApprovalRun.metadata?.autoloopApprovalBlock?.elapsedRuntimeHours, 6.25);
|
|
820
|
-
assert.match(elapsedAutoloopApprovalRun.nextAction || '', /wall-clock boundary/i);
|
|
821
|
-
|
|
822
|
-
const stoppedSupportNoProgressRun = buildSupportAIRunFromEvidence({
|
|
823
|
-
ticket: {
|
|
824
|
-
_id: 'ticket-autoloop-no-progress',
|
|
825
|
-
ticketNumber: '004602',
|
|
826
|
-
title: 'Support autoloop stopped with no new evidence',
|
|
827
|
-
automation: {
|
|
828
|
-
autoloop: {
|
|
829
|
-
run_id: 'support-autoloop-no-progress-run',
|
|
830
|
-
status: 'stopped',
|
|
831
|
-
handoff_required: true,
|
|
832
|
-
no_progress_streak: 2,
|
|
833
|
-
last_progress_signal: false,
|
|
834
|
-
last_progress_reasons: ['same_failing_check_fingerprint'],
|
|
835
|
-
last_evidence_changed: false,
|
|
836
|
-
last_evidence_reasons: ['same_diff_fingerprint', 'same_pr_status'],
|
|
837
|
-
last_strict_gate_reason: 'missing_aiqa_business_assertion',
|
|
838
|
-
last_error: 'No-progress rule triggered after 2 consecutive iterations without grade/PR/diff improvement.',
|
|
839
|
-
last_continuation_decision: {
|
|
840
|
-
action: 'park',
|
|
841
|
-
reason: 'same failure fingerprint and no new business proof evidence'
|
|
842
|
-
},
|
|
843
|
-
history: [{
|
|
844
|
-
iteration: 1,
|
|
845
|
-
progress_signal: false,
|
|
846
|
-
evidence_changed: false,
|
|
847
|
-
diff_fingerprint: 'diff:same',
|
|
848
|
-
failing_check_fingerprint: 'check:missing-aiqa',
|
|
849
|
-
strict_gate_reason: 'missing_aiqa_business_assertion',
|
|
850
|
-
continuation_decision: { action: 'park', reason: 'missing AIQaBusinessAssertion' }
|
|
851
|
-
}, {
|
|
852
|
-
iteration: 2,
|
|
853
|
-
progress_signal: false,
|
|
854
|
-
evidence_changed: false,
|
|
855
|
-
diff_fingerprint: 'diff:same',
|
|
856
|
-
failing_check_fingerprint: 'check:missing-aiqa',
|
|
857
|
-
strict_gate_reason: 'missing_aiqa_business_assertion',
|
|
858
|
-
continuation_decision: { action: 'park', reason: 'same blocker without new evidence' }
|
|
859
|
-
}]
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
},
|
|
863
|
-
job: {
|
|
864
|
-
_id: 'support-job-autoloop-no-progress',
|
|
865
|
-
status: 'Stopped',
|
|
866
|
-
phase: 'QA'
|
|
867
|
-
},
|
|
868
|
-
qaEvidence: {
|
|
869
|
-
compile: { status: 'pass' },
|
|
870
|
-
routeProbes: [{ route: '/support/004602', status: 'pass', screenshot: 'qa-artifacts/support-no-progress-route.png' }],
|
|
871
|
-
scorecardPassed: true
|
|
872
|
-
}
|
|
873
|
-
});
|
|
874
|
-
const stoppedSupportNoProgressGate = stoppedSupportNoProgressRun.gates.find((gate) => gate.key === 'support_autoloop_no_progress');
|
|
875
|
-
assert.equal(stoppedSupportNoProgressRun.outcome, 'manual_handoff');
|
|
876
|
-
assert.equal(stoppedSupportNoProgressGate?.status, 'blocked');
|
|
877
|
-
assert.equal(stoppedSupportNoProgressGate?.metadata?.requiresNewEvidence, true);
|
|
878
|
-
assert.equal(stoppedSupportNoProgressGate?.metadata?.productRepairAllowed, false);
|
|
879
|
-
assert.equal(stoppedSupportNoProgressRun.events.some((event) => event.category === 'support_autoloop_no_progress'), true);
|
|
880
|
-
assert.equal(stoppedSupportNoProgressRun.metadata?.autoloopNoProgress?.requiresNewEvidence, true);
|
|
881
|
-
assert.match(stoppedSupportNoProgressRun.nextAction || '', /Collect new material evidence/i);
|
|
882
|
-
|
|
883
|
-
const approvedAutopilotTicket = {
|
|
884
|
-
_id: 'ticket-autopilot-approved',
|
|
885
|
-
ticketNumber: '004601',
|
|
886
|
-
title: 'Support approved autopilot completion',
|
|
887
|
-
automation: {
|
|
888
|
-
runner_console: {
|
|
889
|
-
autonomy_approval: {
|
|
890
|
-
contract_id: 'support-autonomy-approval-approved',
|
|
891
|
-
status: 'approved_autopilot',
|
|
892
|
-
approved: true,
|
|
893
|
-
approved_at: '2026-06-15T01:00:00.000Z',
|
|
894
|
-
approved_by: 'operator',
|
|
895
|
-
estimated_hours: 2,
|
|
896
|
-
max_auto_hours_without_approval: 6,
|
|
897
|
-
bug_not_bug: 'bug',
|
|
898
|
-
bug_not_bug_classification_approved: true,
|
|
899
|
-
decision_kind: 'approved_autopilot',
|
|
900
|
-
after_approval_autopilot_until_a_grade: true,
|
|
901
|
-
target_grade: 'A',
|
|
902
|
-
qa_screenshots_required: true,
|
|
903
|
-
before_action_after_business_proof_required: true,
|
|
904
|
-
aiqa_business_assertion_required: true,
|
|
905
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
906
|
-
approved_owner_files: ['server/src/publications/support-tickets.ts'],
|
|
907
|
-
required_completion_evidence: [
|
|
908
|
-
'A-grade execution/artifacts/pull_request review',
|
|
909
|
-
'AIQaBusinessAssertion mapped to diagnosis proof_plan',
|
|
910
|
-
'before/action/after business proof',
|
|
911
|
-
'QA screenshot or trace'
|
|
912
|
-
],
|
|
913
|
-
autopilot_completion_contract: {
|
|
914
|
-
mode: 'approved_scope_to_a_grade_pr',
|
|
915
|
-
required_terminal_state: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files'
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
};
|
|
921
|
-
const postApprovalAutostartContract = {
|
|
922
|
-
contract_id: 'support-autonomy-post-approval-autostart-approved',
|
|
923
|
-
status: 'ready',
|
|
924
|
-
source: 'support_autonomy_approval',
|
|
925
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
926
|
-
approved: true,
|
|
927
|
-
auto_start_enabled: true,
|
|
928
|
-
method: 'runSupportTicketAutoImproveLoopManual',
|
|
929
|
-
options: {
|
|
930
|
-
max_iterations: 6,
|
|
931
|
-
iteration_timeout_ms: 1800000,
|
|
932
|
-
auto_create_pr: true,
|
|
933
|
-
execution_tier: 'small'
|
|
934
|
-
},
|
|
935
|
-
terminal_target: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files',
|
|
936
|
-
target_grade: 'A',
|
|
937
|
-
required_terminal_evidence: [
|
|
938
|
-
'A-grade execution/artifacts/pull_request review',
|
|
939
|
-
'AIQaBusinessAssertion mapped to diagnosis proof_plan',
|
|
940
|
-
'QA screenshot or trace'
|
|
941
|
-
],
|
|
942
|
-
allowed_auto_actions: ['run_owner_scoped_repair', 'run_business_proof_qa', 'create_pr'],
|
|
943
|
-
forbidden_without_reapproval: ['changing owner files without reapproval'],
|
|
944
|
-
blockers: [],
|
|
945
|
-
reason: 'Approval can resume the support auto-improve loop without external Codex monitoring.'
|
|
946
|
-
};
|
|
947
|
-
const approvedPostAutostartStartedRun = buildSupportAIRunFromEvidence({
|
|
948
|
-
ticket: {
|
|
949
|
-
...approvedAutopilotTicket,
|
|
950
|
-
_id: 'ticket-autopilot-post-autostart-started',
|
|
951
|
-
automation: {
|
|
952
|
-
runner_console: {
|
|
953
|
-
autonomy_approval: approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
954
|
-
last_post_approval_autostart_contract: postApprovalAutostartContract,
|
|
955
|
-
last_post_approval_autostart: {
|
|
956
|
-
record_id: 'support-autonomy-post-approval-autostart-record-started',
|
|
957
|
-
status: 'started',
|
|
958
|
-
contract_id: postApprovalAutostartContract.contract_id,
|
|
959
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
960
|
-
auto_start_enabled: true,
|
|
961
|
-
method: 'runSupportTicketAutoImproveLoopManual',
|
|
962
|
-
run_id: 'support-auto-improve-run-004601',
|
|
963
|
-
result_status: 'started',
|
|
964
|
-
result: {
|
|
965
|
-
status: 'started',
|
|
966
|
-
run_id: 'support-auto-improve-run-004601'
|
|
967
|
-
},
|
|
968
|
-
blocks_manual_codex_monitoring: true,
|
|
969
|
-
can_continue_without_codex_monitor: true,
|
|
970
|
-
next_action: 'monitor_auto_improve_loop',
|
|
971
|
-
recorded_at: '2026-06-15T01:00:20.000Z'
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
},
|
|
976
|
-
job: {
|
|
977
|
-
_id: 'support-job-autopilot-post-autostart-started',
|
|
978
|
-
status: 'Running',
|
|
979
|
-
phase: 'BUILD'
|
|
980
|
-
},
|
|
981
|
-
qaEvidence: {
|
|
982
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
983
|
-
compile: { status: 'pass' }
|
|
984
|
-
}
|
|
985
|
-
});
|
|
986
|
-
assert.equal(approvedPostAutostartStartedRun.gates.some((gate) => gate.key === 'support_post_approval_autostart' && gate.status === 'pass'), true);
|
|
987
|
-
assert.equal(approvedPostAutostartStartedRun.events.some((event) => event.category === 'support_post_approval_autostart'), true);
|
|
988
|
-
assert.equal(approvedPostAutostartStartedRun.metadata?.postApprovalAutostart?.started, true);
|
|
989
|
-
assert.equal(approvedPostAutostartStartedRun.metadata?.postApprovalAutostart?.runId, 'support-auto-improve-run-004601');
|
|
990
|
-
assert.equal(approvedPostAutostartStartedRun.metadata?.postApprovalAutostart?.nextAction, 'monitor_auto_improve_loop');
|
|
991
|
-
assert.equal(approvedPostAutostartStartedRun.metadata?.postApprovalAutostart?.canContinueWithoutCodexMonitor, true);
|
|
992
|
-
assert.notEqual(approvedPostAutostartStartedRun.outcome, 'accepted');
|
|
993
|
-
|
|
994
|
-
const approvedPostAutostartBlockedRun = buildSupportAIRunFromEvidence({
|
|
995
|
-
ticket: {
|
|
996
|
-
...approvedAutopilotTicket,
|
|
997
|
-
_id: 'ticket-autopilot-post-autostart-blocked',
|
|
998
|
-
automation: {
|
|
999
|
-
runner_console: {
|
|
1000
|
-
autonomy_approval: approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1001
|
-
last_post_approval_autostart_contract: postApprovalAutostartContract,
|
|
1002
|
-
last_post_approval_autostart: {
|
|
1003
|
-
record_id: 'support-autonomy-post-approval-autostart-record-blocked',
|
|
1004
|
-
status: 'blocked',
|
|
1005
|
-
contract_id: postApprovalAutostartContract.contract_id,
|
|
1006
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1007
|
-
auto_start_enabled: true,
|
|
1008
|
-
method: 'runSupportTicketAutoImproveLoopManual',
|
|
1009
|
-
result_status: 'global_busy',
|
|
1010
|
-
result: {
|
|
1011
|
-
status: 'global_busy',
|
|
1012
|
-
active_ticket_id: 'ticket-active',
|
|
1013
|
-
active_run_id: 'support-auto-improve-run-active'
|
|
1014
|
-
},
|
|
1015
|
-
failure_class: 'global_capacity',
|
|
1016
|
-
blocker_fingerprint: 'post-autostart-global-capacity',
|
|
1017
|
-
blocker_reason: 'Global support runner capacity blocked post-approval autostart.',
|
|
1018
|
-
approval_boundary_valid: true,
|
|
1019
|
-
can_retry_without_reapproval: true,
|
|
1020
|
-
safe_retry_action: 'run_autoloop',
|
|
1021
|
-
resume_contract: {
|
|
1022
|
-
contract_id: 'support-post-approval-autostart-resume-global-capacity',
|
|
1023
|
-
action: 'run_autoloop',
|
|
1024
|
-
allowed_after_input: ['run_autoloop'],
|
|
1025
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1026
|
-
scope_fingerprint: 'support-autonomy-approved-scope',
|
|
1027
|
-
requires_same_approval_contract: true,
|
|
1028
|
-
requires_same_scope_fingerprint: true,
|
|
1029
|
-
can_run_without_codex_monitor: true,
|
|
1030
|
-
blocks_product_repair_until_autoloop_started: true
|
|
1031
|
-
},
|
|
1032
|
-
can_continue_without_codex_monitor: false,
|
|
1033
|
-
next_action: 'monitor_capacity_then_retry_autoloop',
|
|
1034
|
-
recorded_at: '2026-06-15T01:00:21.000Z'
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
},
|
|
1039
|
-
job: {
|
|
1040
|
-
_id: 'support-job-autopilot-post-autostart-blocked',
|
|
1041
|
-
status: 'Running',
|
|
1042
|
-
phase: 'BUILD'
|
|
1043
|
-
},
|
|
1044
|
-
qaEvidence: {
|
|
1045
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1046
|
-
compile: { status: 'pass' },
|
|
1047
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1048
|
-
businessAssertions: [{
|
|
1049
|
-
assertion: 'Synthetic business proof would otherwise pass.',
|
|
1050
|
-
status: 'pass',
|
|
1051
|
-
action: 'Apply support filter.',
|
|
1052
|
-
expected: 'Only matching records appear.',
|
|
1053
|
-
observed: 'Only matching records appeared.',
|
|
1054
|
-
dataProof: 'Synthetic row proof.'
|
|
1055
|
-
}]
|
|
1056
|
-
}
|
|
1057
|
-
});
|
|
1058
|
-
assert.equal(approvedPostAutostartBlockedRun.outcome, 'manual_handoff');
|
|
1059
|
-
assert.equal(approvedPostAutostartBlockedRun.gates.some((gate) => gate.key === 'support_post_approval_autostart' && gate.status === 'blocked'), true);
|
|
1060
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.blocked, true);
|
|
1061
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.failureClass, 'global_capacity');
|
|
1062
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.blockerFingerprint, 'post-autostart-global-capacity');
|
|
1063
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.approvalBoundaryValid, true);
|
|
1064
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.canRetryWithoutReapproval, true);
|
|
1065
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.safeRetryAction, 'run_autoloop');
|
|
1066
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.resumeContract?.action, 'run_autoloop');
|
|
1067
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.resumeContract?.requires_same_scope_fingerprint, true);
|
|
1068
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.scopeFingerprint, 'support-autonomy-approved-scope');
|
|
1069
|
-
assert.equal(approvedPostAutostartBlockedRun.metadata?.postApprovalAutostart?.activeRunId, 'support-auto-improve-run-active');
|
|
1070
|
-
assert.match(String(approvedPostAutostartBlockedRun.nextAction || ''), /Retry the approved auto-improve loop/i);
|
|
1071
|
-
|
|
1072
|
-
const approvedPostResumeBlockedRun = buildSupportAIRunFromEvidence({
|
|
1073
|
-
ticket: {
|
|
1074
|
-
...approvedAutopilotTicket,
|
|
1075
|
-
_id: 'ticket-autopilot-post-resume-blocked',
|
|
1076
|
-
automation: {
|
|
1077
|
-
runner_console: {
|
|
1078
|
-
autonomy_approval: approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1079
|
-
last_post_approval_autostart_contract: postApprovalAutostartContract,
|
|
1080
|
-
last_post_approval_autostart: {
|
|
1081
|
-
record_id: 'support-autonomy-post-approval-autostart-record-blocked-for-resume',
|
|
1082
|
-
status: 'blocked',
|
|
1083
|
-
contract_id: postApprovalAutostartContract.contract_id,
|
|
1084
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1085
|
-
auto_start_enabled: true,
|
|
1086
|
-
method: 'runSupportTicketAutoImproveLoopManual',
|
|
1087
|
-
result_status: 'global_busy',
|
|
1088
|
-
result: {
|
|
1089
|
-
status: 'global_busy',
|
|
1090
|
-
active_ticket_id: 'ticket-active',
|
|
1091
|
-
active_run_id: 'support-auto-improve-run-active'
|
|
1092
|
-
},
|
|
1093
|
-
failure_class: 'global_capacity',
|
|
1094
|
-
blocker_fingerprint: 'post-autostart-global-capacity',
|
|
1095
|
-
blocker_reason: 'Global support runner capacity blocked post-approval autostart.',
|
|
1096
|
-
approval_boundary_valid: true,
|
|
1097
|
-
can_retry_without_reapproval: true,
|
|
1098
|
-
safe_retry_action: 'run_autoloop',
|
|
1099
|
-
resume_contract: {
|
|
1100
|
-
contract_id: 'support-post-approval-autostart-resume-global-capacity',
|
|
1101
|
-
action: 'run_autoloop',
|
|
1102
|
-
allowed_after_input: ['run_autoloop'],
|
|
1103
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1104
|
-
scope_fingerprint: 'support-autonomy-approved-scope',
|
|
1105
|
-
requires_same_approval_contract: true,
|
|
1106
|
-
requires_same_scope_fingerprint: true,
|
|
1107
|
-
can_run_without_codex_monitor: true,
|
|
1108
|
-
blocks_product_repair_until_autoloop_started: true
|
|
1109
|
-
},
|
|
1110
|
-
can_continue_without_codex_monitor: false,
|
|
1111
|
-
next_action: 'monitor_capacity_then_retry_autoloop',
|
|
1112
|
-
recorded_at: '2026-06-15T01:00:21.000Z'
|
|
1113
|
-
},
|
|
1114
|
-
last_post_approval_resume_attempt: {
|
|
1115
|
-
attempt_id: 'support-post-approval-resume-blocked',
|
|
1116
|
-
source: 'support_watchdog_post_approval_autostart_resume',
|
|
1117
|
-
status: 'blocked',
|
|
1118
|
-
action: 'run_autoloop',
|
|
1119
|
-
contract_id: 'support-post-approval-autostart-resume-global-capacity',
|
|
1120
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1121
|
-
scope_fingerprint: 'support-autonomy-approved-scope',
|
|
1122
|
-
resume_contract: {
|
|
1123
|
-
contract_id: 'support-post-approval-autostart-resume-global-capacity',
|
|
1124
|
-
action: 'run_autoloop',
|
|
1125
|
-
approval_contract_id: 'support-autonomy-approval-approved',
|
|
1126
|
-
scope_fingerprint: 'support-autonomy-approved-scope',
|
|
1127
|
-
can_run_without_codex_monitor: true
|
|
1128
|
-
},
|
|
1129
|
-
result_status: 'global_busy',
|
|
1130
|
-
result: {
|
|
1131
|
-
status: 'global_busy',
|
|
1132
|
-
active_ticket_id: 'ticket-active',
|
|
1133
|
-
active_run_id: 'support-auto-improve-run-active'
|
|
1134
|
-
},
|
|
1135
|
-
active_ticket_id: 'ticket-active',
|
|
1136
|
-
active_run_id: 'support-auto-improve-run-active',
|
|
1137
|
-
failure_class: 'global_capacity',
|
|
1138
|
-
blocker_fingerprint: 'post-resume-global-capacity',
|
|
1139
|
-
blocker_reason: 'Global support runner capacity still blocked approved autoloop resume.',
|
|
1140
|
-
next_action: 'monitor_capacity_then_retry_autoloop',
|
|
1141
|
-
can_continue_without_codex_monitor: false,
|
|
1142
|
-
product_repair_allowed: false,
|
|
1143
|
-
can_send_customer_reply: false,
|
|
1144
|
-
recorded_at: '2026-06-15T01:00:22.000Z'
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
},
|
|
1149
|
-
job: {
|
|
1150
|
-
_id: 'support-job-autopilot-post-resume-blocked',
|
|
1151
|
-
status: 'Running',
|
|
1152
|
-
phase: 'BUILD'
|
|
1153
|
-
},
|
|
1154
|
-
qaEvidence: {
|
|
1155
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1156
|
-
compile: { status: 'pass' }
|
|
1157
|
-
}
|
|
1158
|
-
});
|
|
1159
|
-
assert.equal(approvedPostResumeBlockedRun.outcome, 'manual_handoff');
|
|
1160
|
-
assert.equal(approvedPostResumeBlockedRun.gates.some((gate) => gate.key === 'support_post_approval_resume_attempt' && gate.status === 'blocked'), true);
|
|
1161
|
-
assert.equal(approvedPostResumeBlockedRun.events.some((event) => event.category === 'support_post_approval_resume_attempt'), true);
|
|
1162
|
-
assert.equal(approvedPostResumeBlockedRun.metadata?.postApprovalResumeAttempt?.blocked, true);
|
|
1163
|
-
assert.equal(approvedPostResumeBlockedRun.metadata?.postApprovalResumeAttempt?.failureClass, 'global_capacity');
|
|
1164
|
-
assert.equal(approvedPostResumeBlockedRun.metadata?.postApprovalResumeAttempt?.blockerFingerprint, 'post-resume-global-capacity');
|
|
1165
|
-
assert.equal(approvedPostResumeBlockedRun.metadata?.postApprovalResumeAttempt?.productRepairAllowed, false);
|
|
1166
|
-
assert.equal(approvedPostResumeBlockedRun.metadata?.postApprovalResumeAttempt?.canSendCustomerReply, false);
|
|
1167
|
-
assert.match(String(approvedPostResumeBlockedRun.gates.find((gate) => gate.key === 'support_post_approval_resume_attempt')?.reason || ''), /resume/i);
|
|
1168
|
-
assert.match(String(approvedPostResumeBlockedRun.nextAction || ''), /blocker fingerprint changes/i);
|
|
1169
|
-
|
|
1170
|
-
const approvedAutopilotIntakeChangedRun = buildSupportAIRunFromEvidence({
|
|
1171
|
-
ticket: {
|
|
1172
|
-
...approvedAutopilotTicket,
|
|
1173
|
-
_id: 'ticket-autopilot-intake-changed',
|
|
1174
|
-
automation: {
|
|
1175
|
-
runner_console: {
|
|
1176
|
-
autonomy_approval: approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1177
|
-
last_intake_revision_contract: {
|
|
1178
|
-
contract_id: 'support-intake-reapproval-scope-change',
|
|
1179
|
-
status: 'approval_required',
|
|
1180
|
-
requires_reapproval: true,
|
|
1181
|
-
reason: 'Operator changed approval-impacting intake fields after bounded autonomy was approved; product repair is parked until reapproved.',
|
|
1182
|
-
changed_fields: [{
|
|
1183
|
-
field: 'issue_class',
|
|
1184
|
-
previous: 'filter_query_mismatch',
|
|
1185
|
-
next: 'missing_wrong_data'
|
|
1186
|
-
}],
|
|
1187
|
-
changed_field_names: ['issue_class'],
|
|
1188
|
-
approval_impacting_edit_fields: ['classification', 'issue_class', 'route_module', 'expected_result', 'observed_result', 'affected_account_user', 'billable_policy'],
|
|
1189
|
-
previous_autonomy_contract_id: 'support-autonomy-approval-approved',
|
|
1190
|
-
previous_scope_fingerprint: 'scope-before',
|
|
1191
|
-
next_scope_fingerprint: 'scope-after',
|
|
1192
|
-
intake_scope_fingerprint: 'intake-scope-after',
|
|
1193
|
-
blocks_product_repair: true,
|
|
1194
|
-
blocks_auto_retry: true,
|
|
1195
|
-
required_operator_action: 'approve_support_autonomy',
|
|
1196
|
-
updated_by: 'operator',
|
|
1197
|
-
updated_at: '2026-06-15T01:01:00.000Z'
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
},
|
|
1202
|
-
job: {
|
|
1203
|
-
_id: 'support-job-autopilot-intake-changed',
|
|
1204
|
-
status: 'Running',
|
|
1205
|
-
phase: 'BUILD'
|
|
1206
|
-
},
|
|
1207
|
-
qaEvidence: {
|
|
1208
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1209
|
-
compile: { status: 'pass' }
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
assert.equal(approvedAutopilotIntakeChangedRun.outcome, 'manual_handoff');
|
|
1213
|
-
assert.equal(approvedAutopilotIntakeChangedRun.gates.some((gate) => gate.key === 'support_intake_revision_contract' && gate.status === 'blocked'), true);
|
|
1214
|
-
assert.equal(approvedAutopilotIntakeChangedRun.metadata?.intakeRevisionContract?.blocksProductRepair, true);
|
|
1215
|
-
assert.deepEqual(approvedAutopilotIntakeChangedRun.metadata?.intakeRevisionContract?.changedFieldNames, ['issue_class']);
|
|
1216
|
-
assert.match(String(approvedAutopilotIntakeChangedRun.nextAction || ''), /approve_support_autonomy/i);
|
|
1217
|
-
|
|
1218
|
-
const approvedAutopilotMissingClassificationRun = buildSupportAIRunFromEvidence({
|
|
1219
|
-
ticket: {
|
|
1220
|
-
...approvedAutopilotTicket,
|
|
1221
|
-
_id: 'ticket-autopilot-missing-classification',
|
|
1222
|
-
automation: {
|
|
1223
|
-
runner_console: {
|
|
1224
|
-
autonomy_approval: {
|
|
1225
|
-
...approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1226
|
-
contract_id: 'support-autonomy-missing-classification',
|
|
1227
|
-
bug_not_bug: 'bug',
|
|
1228
|
-
bug_not_bug_classification_approved: false
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
},
|
|
1233
|
-
job: {
|
|
1234
|
-
_id: 'support-job-autopilot-missing-classification',
|
|
1235
|
-
status: 'Running',
|
|
1236
|
-
phase: 'BUILD'
|
|
1237
|
-
},
|
|
1238
|
-
qaEvidence: {
|
|
1239
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1240
|
-
compile: { status: 'pass' },
|
|
1241
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1242
|
-
}
|
|
1243
|
-
});
|
|
1244
|
-
assert.equal(approvedAutopilotMissingClassificationRun.outcome, 'manual_handoff');
|
|
1245
|
-
assert.equal(approvedAutopilotMissingClassificationRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), true);
|
|
1246
|
-
assert.equal(approvedAutopilotMissingClassificationRun.metadata?.autonomyApproval?.bugNotBugClassificationApproved, false);
|
|
1247
|
-
assert.equal(approvedAutopilotMissingClassificationRun.metadata?.autonomyApproval?.autopilotApprovalBoundaryValid, false);
|
|
1248
|
-
assert.ok(approvedAutopilotMissingClassificationRun.metadata?.autonomyApproval?.blockers?.some((blocker: string) => /Bug\/not-bug classification must be approved/i.test(blocker)));
|
|
1249
|
-
|
|
1250
|
-
const approvedAutopilotOverSixWithoutExplicitRun = buildSupportAIRunFromEvidence({
|
|
1251
|
-
ticket: {
|
|
1252
|
-
...approvedAutopilotTicket,
|
|
1253
|
-
_id: 'ticket-autopilot-over-six-without-explicit',
|
|
1254
|
-
automation: {
|
|
1255
|
-
runner_console: {
|
|
1256
|
-
autonomy_approval: {
|
|
1257
|
-
...approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1258
|
-
contract_id: 'support-autonomy-over-six-without-explicit',
|
|
1259
|
-
estimated_hours: 7,
|
|
1260
|
-
max_auto_hours_without_approval: 6,
|
|
1261
|
-
over_max_auto_hours: true,
|
|
1262
|
-
approve_over_six_hours: false,
|
|
1263
|
-
approve_over_max_hours: false
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
},
|
|
1268
|
-
job: {
|
|
1269
|
-
_id: 'support-job-autopilot-over-six-without-explicit',
|
|
1270
|
-
status: 'Running',
|
|
1271
|
-
phase: 'BUILD'
|
|
1272
|
-
},
|
|
1273
|
-
qaEvidence: {
|
|
1274
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1275
|
-
compile: { status: 'pass' },
|
|
1276
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1277
|
-
}
|
|
1278
|
-
});
|
|
1279
|
-
assert.equal(approvedAutopilotOverSixWithoutExplicitRun.outcome, 'manual_handoff');
|
|
1280
|
-
assert.equal(approvedAutopilotOverSixWithoutExplicitRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), true);
|
|
1281
|
-
assert.equal(approvedAutopilotOverSixWithoutExplicitRun.metadata?.autonomyApproval?.estimatedHours, 7);
|
|
1282
|
-
assert.equal(approvedAutopilotOverSixWithoutExplicitRun.metadata?.autonomyApproval?.maxAutoHoursWithoutApproval, 6);
|
|
1283
|
-
assert.equal(approvedAutopilotOverSixWithoutExplicitRun.metadata?.autonomyApproval?.explicitOverLimitApproval, false);
|
|
1284
|
-
assert.ok(approvedAutopilotOverSixWithoutExplicitRun.metadata?.autonomyApproval?.blockers?.some((blocker: string) => /above the 6-hour autonomy ceiling/i.test(blocker)));
|
|
1285
|
-
|
|
1286
|
-
const approvedAutopilotOwnerDriftRun = buildSupportAIRunFromEvidence({
|
|
1287
|
-
ticket: {
|
|
1288
|
-
...approvedAutopilotTicket,
|
|
1289
|
-
_id: 'ticket-autopilot-owner-drift',
|
|
1290
|
-
automation: {
|
|
1291
|
-
runner_console: {
|
|
1292
|
-
autonomy_approval: {
|
|
1293
|
-
...approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1294
|
-
contract_id: 'support-autonomy-owner-drift',
|
|
1295
|
-
owner_files: ['server/src/publications/support-tickets.ts', 'server/src/methods/unapproved-scope.ts'],
|
|
1296
|
-
current_owner_files: ['server/src/publications/support-tickets.ts', 'server/src/methods/unapproved-scope.ts'],
|
|
1297
|
-
approved_owner_files: ['server/src/publications/support-tickets.ts']
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
},
|
|
1302
|
-
job: {
|
|
1303
|
-
_id: 'support-job-autopilot-owner-drift',
|
|
1304
|
-
status: 'Running',
|
|
1305
|
-
phase: 'BUILD'
|
|
1306
|
-
},
|
|
1307
|
-
qaEvidence: {
|
|
1308
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1309
|
-
compile: { status: 'pass' },
|
|
1310
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1311
|
-
}
|
|
1312
|
-
});
|
|
1313
|
-
assert.equal(approvedAutopilotOwnerDriftRun.outcome, 'manual_handoff');
|
|
1314
|
-
assert.equal(approvedAutopilotOwnerDriftRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), true);
|
|
1315
|
-
assert.equal(approvedAutopilotOwnerDriftRun.metadata?.autonomyApproval?.ownerFilesChangedSinceApproval, true);
|
|
1316
|
-
assert.equal(approvedAutopilotOwnerDriftRun.metadata?.autonomyApproval?.approvedOwnerFileSetChanged, true);
|
|
1317
|
-
assert.deepEqual(approvedAutopilotOwnerDriftRun.metadata?.autonomyApproval?.ownerFilesAddedSinceApproval, ['server/src/methods/unapproved-scope.ts']);
|
|
1318
|
-
|
|
1319
|
-
const approvedAutopilotScopeFingerprintDriftRun = buildSupportAIRunFromEvidence({
|
|
1320
|
-
ticket: {
|
|
1321
|
-
...approvedAutopilotTicket,
|
|
1322
|
-
_id: 'ticket-autopilot-scope-fingerprint-drift',
|
|
1323
|
-
automation: {
|
|
1324
|
-
runner_console: {
|
|
1325
|
-
autonomy_approval: {
|
|
1326
|
-
...approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1327
|
-
contract_id: 'support-autonomy-scope-fingerprint-drift',
|
|
1328
|
-
scope_fingerprint: 'current-scope-fingerprint',
|
|
1329
|
-
previous_scope_fingerprint: 'approved-scope-fingerprint'
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
},
|
|
1334
|
-
job: {
|
|
1335
|
-
_id: 'support-job-autopilot-scope-fingerprint-drift',
|
|
1336
|
-
status: 'Running',
|
|
1337
|
-
phase: 'BUILD'
|
|
1338
|
-
},
|
|
1339
|
-
qaEvidence: {
|
|
1340
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1341
|
-
compile: { status: 'pass' },
|
|
1342
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1343
|
-
}
|
|
1344
|
-
});
|
|
1345
|
-
assert.notEqual(approvedAutopilotScopeFingerprintDriftRun.outcome, 'manual_handoff');
|
|
1346
|
-
assert.equal(approvedAutopilotScopeFingerprintDriftRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), false);
|
|
1347
|
-
assert.equal(approvedAutopilotScopeFingerprintDriftRun.metadata?.autonomyApproval?.scopeChangedSinceApproval, false);
|
|
1348
|
-
assert.equal(approvedAutopilotScopeFingerprintDriftRun.metadata?.autonomyApproval?.previousScopeFingerprint, 'approved-scope-fingerprint');
|
|
1349
|
-
assert.equal(approvedAutopilotScopeFingerprintDriftRun.metadata?.autonomyApproval?.blockers?.some((blocker: string) => /support scope changed/i.test(blocker)), false);
|
|
1350
|
-
|
|
1351
|
-
const approvedAutopilotRepairIntentOnlyBlockRun = buildSupportAIRunFromEvidence({
|
|
1352
|
-
ticket: {
|
|
1353
|
-
...approvedAutopilotTicket,
|
|
1354
|
-
_id: 'ticket-autopilot-repair-intent-only-block',
|
|
1355
|
-
automation: {
|
|
1356
|
-
runner_console: {
|
|
1357
|
-
autonomy_approval: approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1358
|
-
product_repair_dispatch_guard: {
|
|
1359
|
-
status: 'allowed',
|
|
1360
|
-
allowed: true,
|
|
1361
|
-
action: 'run_owner_scoped_repair',
|
|
1362
|
-
next_action: 'run_business_proof_qa',
|
|
1363
|
-
reason: 'Approved support autonomy allows this owner-scoped bug repair.',
|
|
1364
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
1365
|
-
approved_owner_files: ['server/src/publications/support-tickets.ts']
|
|
1366
|
-
},
|
|
1367
|
-
last_autoloop_approval_block: {
|
|
1368
|
-
status: 'blocked_autonomy_approval_required',
|
|
1369
|
-
decision_kind: 'repair_intent_required',
|
|
1370
|
-
requires_repair_intent: true,
|
|
1371
|
-
reason: 'Support autonomy approval required before product-code repair: repair_intent_required_before_product_repair',
|
|
1372
|
-
target_grade: 'A',
|
|
1373
|
-
required_terminal_state: 'A-grade PR with QA screenshots, AIQaBusinessAssertion before/action/after proof, source commit proof, and changed files inside owner_files',
|
|
1374
|
-
blockers: ['Autoloop is parked until planned implementation intent is defined.']
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
},
|
|
1379
|
-
job: {
|
|
1380
|
-
_id: 'support-job-autopilot-repair-intent-only-block',
|
|
1381
|
-
status: 'Running',
|
|
1382
|
-
phase: 'BUILD'
|
|
1383
|
-
},
|
|
1384
|
-
qaEvidence: {
|
|
1385
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1386
|
-
compile: { status: 'pass' },
|
|
1387
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1388
|
-
}
|
|
1389
|
-
});
|
|
1390
|
-
const repairIntentOnlyGate = approvedAutopilotRepairIntentOnlyBlockRun.gates.find((gate) => gate.key === 'support_autoloop_approval_block');
|
|
1391
|
-
assert.notEqual(approvedAutopilotRepairIntentOnlyBlockRun.outcome, 'manual_handoff');
|
|
1392
|
-
assert.equal(repairIntentOnlyGate?.status, 'warn');
|
|
1393
|
-
assert.equal(repairIntentOnlyGate?.metadata?.staleRepairIntentOnlyBlockDowngraded, true);
|
|
1394
|
-
assert.equal(approvedAutopilotRepairIntentOnlyBlockRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), false);
|
|
1395
|
-
|
|
1396
|
-
const approvedAutopilotDiagnosisFingerprintDriftRun = buildSupportAIRunFromEvidence({
|
|
1397
|
-
ticket: {
|
|
1398
|
-
...approvedAutopilotTicket,
|
|
1399
|
-
_id: 'ticket-autopilot-diagnosis-fingerprint-drift',
|
|
1400
|
-
automation: {
|
|
1401
|
-
runner_console: {
|
|
1402
|
-
autonomy_approval: {
|
|
1403
|
-
...approvedAutopilotTicket.automation.runner_console.autonomy_approval,
|
|
1404
|
-
contract_id: 'support-autonomy-diagnosis-fingerprint-drift',
|
|
1405
|
-
diagnosis_scope_included: true,
|
|
1406
|
-
diagnosis_scope_valid: true,
|
|
1407
|
-
diagnosis_scope_fingerprint: 'current-diagnosis-proof-plan',
|
|
1408
|
-
previous_diagnosis_scope_fingerprint: 'approved-diagnosis-proof-plan',
|
|
1409
|
-
diagnosis_scope_fields: ['issue_case', 'accepted_hypothesis', 'failing_path', 'proof_plan']
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
},
|
|
1414
|
-
job: {
|
|
1415
|
-
_id: 'support-job-autopilot-diagnosis-fingerprint-drift',
|
|
1416
|
-
status: 'Running',
|
|
1417
|
-
phase: 'BUILD'
|
|
1418
|
-
},
|
|
1419
|
-
qaEvidence: {
|
|
1420
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1421
|
-
compile: { status: 'pass' },
|
|
1422
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }]
|
|
1423
|
-
}
|
|
1424
|
-
});
|
|
1425
|
-
assert.equal(approvedAutopilotDiagnosisFingerprintDriftRun.outcome, 'manual_handoff');
|
|
1426
|
-
assert.equal(approvedAutopilotDiagnosisFingerprintDriftRun.gates.some((gate) => gate.key === 'support_autonomy_approval' && gate.status === 'blocked'), true);
|
|
1427
|
-
assert.equal(approvedAutopilotDiagnosisFingerprintDriftRun.metadata?.autonomyApproval?.diagnosisScopeChangedSinceApproval, true);
|
|
1428
|
-
assert.equal(approvedAutopilotDiagnosisFingerprintDriftRun.metadata?.autonomyApproval?.previousDiagnosisScopeFingerprint, 'approved-diagnosis-proof-plan');
|
|
1429
|
-
assert.deepEqual(approvedAutopilotDiagnosisFingerprintDriftRun.metadata?.autonomyApproval?.diagnosisScopeFields, ['issue_case', 'accepted_hypothesis', 'failing_path', 'proof_plan']);
|
|
1430
|
-
assert.ok(approvedAutopilotDiagnosisFingerprintDriftRun.metadata?.autonomyApproval?.blockers?.some((blocker: string) => /diagnosis\/proof scope changed/i.test(blocker)));
|
|
1431
|
-
|
|
1432
|
-
const prReadyNoPrContract = {
|
|
1433
|
-
contract_id: 'support-pr-readiness-ready-no-pr',
|
|
1434
|
-
status: 'ready',
|
|
1435
|
-
ready: true,
|
|
1436
|
-
reason: 'Business proof is ready and PR packaging can run.',
|
|
1437
|
-
action: 'create_pr',
|
|
1438
|
-
dispatch_action: 'create_pr',
|
|
1439
|
-
method: 'createSupportTicketCodexPullRequestManual',
|
|
1440
|
-
business_proof_ready: true,
|
|
1441
|
-
diagnosis_valid: true,
|
|
1442
|
-
job_phase: 'COMPLETE',
|
|
1443
|
-
job_id: 'support-job-autopilot-approved',
|
|
1444
|
-
pull_request_url: '',
|
|
1445
|
-
pull_request_status: '',
|
|
1446
|
-
passed_business_assertion_count: 1,
|
|
1447
|
-
business_proof_artifacts: ['qa-artifacts/support-before-after-proof.png'],
|
|
1448
|
-
modified_files: ['server/src/publications/support-tickets.ts'],
|
|
1449
|
-
required_evidence: ['AIQaBusinessAssertion status=pass mapped to diagnosis proof_plan'],
|
|
1450
|
-
next_action_after_pr: 'review_a_grade_pr_and_release_gate',
|
|
1451
|
-
target_grade: 'A',
|
|
1452
|
-
merge_blocked_until_human_approval: true,
|
|
1453
|
-
customer_reply_blocked_until_release_gate: true,
|
|
1454
|
-
release_blocked_until_pr_review: true
|
|
1455
|
-
};
|
|
1456
|
-
const approvedAutopilotNoPrRun = buildSupportAIRunFromEvidence({
|
|
1457
|
-
ticket: approvedAutopilotTicket,
|
|
1458
|
-
job: {
|
|
1459
|
-
_id: 'support-job-autopilot-approved',
|
|
1460
|
-
status: 'Closed',
|
|
1461
|
-
phase: 'COMPLETE',
|
|
1462
|
-
support_pr_readiness_contract: prReadyNoPrContract
|
|
1463
|
-
},
|
|
1464
|
-
qaEvidence: {
|
|
1465
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1466
|
-
compile: { status: 'pass' },
|
|
1467
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1468
|
-
businessAssertions: [{
|
|
1469
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1470
|
-
status: 'pass',
|
|
1471
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1472
|
-
action: 'Apply the Customer B filter.',
|
|
1473
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1474
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1475
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1476
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1477
|
-
metadata: { supportDiagnosisProof: true }
|
|
1478
|
-
}],
|
|
1479
|
-
scorecardPassed: true
|
|
1480
|
-
}
|
|
1481
|
-
});
|
|
1482
|
-
assert.equal(approvedAutopilotNoPrRun.outcome, 'release_blocked');
|
|
1483
|
-
assert.equal(approvedAutopilotNoPrRun.gates.some((gate) => gate.key === 'support_pr_readiness_contract' && gate.status === 'pass'), true);
|
|
1484
|
-
assert.equal(approvedAutopilotNoPrRun.gates.some((gate) => gate.key === 'support_autopilot_completion_contract' && gate.status === 'blocked'), true);
|
|
1485
|
-
assert.equal(approvedAutopilotNoPrRun.metadata?.autopilotCompletion?.nextAction, 'create_pr');
|
|
1486
|
-
assert.equal(approvedAutopilotNoPrRun.metadata?.autopilotCompletion?.businessProofReady, true);
|
|
1487
|
-
assert.equal(approvedAutopilotNoPrRun.metadata?.autopilotCompletion?.hasScreenshotOrTrace, true);
|
|
1488
|
-
assert.equal(approvedAutopilotNoPrRun.metadata?.prReadinessContract?.ready, true);
|
|
1489
|
-
assert.equal(approvedAutopilotNoPrRun.metadata?.prReadinessContract?.mergeBlockedUntilHumanApproval, true);
|
|
1490
|
-
|
|
1491
|
-
const approvedAutopilotWithPrRun = buildSupportAIRunFromEvidence({
|
|
1492
|
-
ticket: approvedAutopilotTicket,
|
|
1493
|
-
job: {
|
|
1494
|
-
_id: 'support-job-autopilot-approved-with-pr',
|
|
1495
|
-
status: 'Closed',
|
|
1496
|
-
phase: 'COMPLETE',
|
|
1497
|
-
support_pr_readiness_contract: {
|
|
1498
|
-
...prReadyNoPrContract,
|
|
1499
|
-
contract_id: 'support-pr-readiness-ready-with-pr',
|
|
1500
|
-
job_id: 'support-job-autopilot-approved-with-pr',
|
|
1501
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1502
|
-
pull_request_status: 'OPEN'
|
|
1503
|
-
}
|
|
1504
|
-
},
|
|
1505
|
-
qaEvidence: {
|
|
1506
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1507
|
-
compile: { status: 'pass' },
|
|
1508
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1509
|
-
businessAssertions: [{
|
|
1510
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1511
|
-
status: 'pass',
|
|
1512
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1513
|
-
action: 'Apply the Customer B filter.',
|
|
1514
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1515
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1516
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1517
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1518
|
-
metadata: { supportDiagnosisProof: true }
|
|
1519
|
-
}],
|
|
1520
|
-
scorecardPassed: true
|
|
1521
|
-
}
|
|
1522
|
-
});
|
|
1523
|
-
assert.equal(approvedAutopilotWithPrRun.outcome, 'false_pass');
|
|
1524
|
-
assert.equal(approvedAutopilotWithPrRun.gates.some((gate) => gate.key === 'support_autopilot_completion_contract' && gate.status === 'blocked'), true);
|
|
1525
|
-
assert.equal(approvedAutopilotWithPrRun.metadata?.autopilotCompletion?.nextAction, 'run_a_grade_pr_review');
|
|
1526
|
-
assert.equal(approvedAutopilotWithPrRun.metadata?.autopilotCompletion?.pullRequestUrl, 'https://github.com/resolveio/resolveio-all/pull/4601');
|
|
1527
|
-
assert.equal(approvedAutopilotWithPrRun.metadata?.autopilotCompletion?.prReviewReady, false);
|
|
1528
|
-
assert.ok(approvedAutopilotWithPrRun.metadata?.autopilotCompletion?.missingCompletionEvidence?.some((entry: string) => /A-grade execution\/artifacts\/pull_request review/i.test(entry)));
|
|
1529
|
-
|
|
1530
|
-
const approvedAutopilotBlockedPrReviewRun = buildSupportAIRunFromEvidence({
|
|
1531
|
-
ticket: approvedAutopilotTicket,
|
|
1532
|
-
job: {
|
|
1533
|
-
_id: 'support-job-autopilot-blocked-pr-review',
|
|
1534
|
-
status: 'Closed',
|
|
1535
|
-
phase: 'COMPLETE',
|
|
1536
|
-
support_pr_readiness_contract: {
|
|
1537
|
-
...prReadyNoPrContract,
|
|
1538
|
-
contract_id: 'support-pr-readiness-blocked-pr-review',
|
|
1539
|
-
job_id: 'support-job-autopilot-blocked-pr-review',
|
|
1540
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1541
|
-
pull_request_status: 'OPEN'
|
|
1542
|
-
},
|
|
1543
|
-
support_pr_review_contract: {
|
|
1544
|
-
contract_id: 'support-pr-review-blocked-business-proof',
|
|
1545
|
-
status: 'blocked',
|
|
1546
|
-
ready: false,
|
|
1547
|
-
strict_gate_passed: false,
|
|
1548
|
-
strict_gate_reason: 'missing_before_action_after_business_proof',
|
|
1549
|
-
failure_class: 'business_proof',
|
|
1550
|
-
blocker_fingerprint: 'bf-business-proof',
|
|
1551
|
-
evidence_hash: 'ev-business-proof',
|
|
1552
|
-
next_action: 'run_business_proof_qa',
|
|
1553
|
-
blockers: ['Strict gate failed: missing before/action/after business proof.'],
|
|
1554
|
-
continuation_contract: {
|
|
1555
|
-
contract_id: 'support-pr-review-blocked-business-proof-continuation',
|
|
1556
|
-
status: 'blocked',
|
|
1557
|
-
action: 'run_business_proof_qa',
|
|
1558
|
-
failure_class: 'business_proof',
|
|
1559
|
-
blocker_fingerprint: 'bf-business-proof',
|
|
1560
|
-
evidence_hash: 'ev-business-proof',
|
|
1561
|
-
required_evidence: ['fresh AIQaBusinessAssertion status=pass'],
|
|
1562
|
-
reset_evidence_required: ['changed evidence_hash'],
|
|
1563
|
-
stop_conditions: ['Stop if the same failure repeats without material evidence.'],
|
|
1564
|
-
can_run_without_codex_monitor: true,
|
|
1565
|
-
product_repair_allowed: false,
|
|
1566
|
-
release_customer_side_effects_allowed: false
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
},
|
|
1570
|
-
qaEvidence: {
|
|
1571
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1572
|
-
compile: { status: 'pass' },
|
|
1573
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1574
|
-
businessAssertions: [{
|
|
1575
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1576
|
-
status: 'pass',
|
|
1577
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1578
|
-
action: 'Apply the Customer B filter.',
|
|
1579
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1580
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1581
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1582
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1583
|
-
metadata: { supportDiagnosisProof: true }
|
|
1584
|
-
}],
|
|
1585
|
-
scorecardPassed: true
|
|
1586
|
-
}
|
|
1587
|
-
});
|
|
1588
|
-
assert.equal(approvedAutopilotBlockedPrReviewRun.outcome, 'false_pass');
|
|
1589
|
-
assert.equal(approvedAutopilotBlockedPrReviewRun.metadata?.prReviewContract?.failureClass, 'business_proof');
|
|
1590
|
-
assert.equal(approvedAutopilotBlockedPrReviewRun.metadata?.prReviewContract?.blockerFingerprint, 'bf-business-proof');
|
|
1591
|
-
assert.equal(approvedAutopilotBlockedPrReviewRun.metadata?.prReviewContract?.evidenceHash, 'ev-business-proof');
|
|
1592
|
-
assert.equal(approvedAutopilotBlockedPrReviewRun.metadata?.prReviewContract?.continuationContract?.action, 'run_business_proof_qa');
|
|
1593
|
-
|
|
1594
|
-
const approvedAutopilotReviewedPrRun = buildSupportAIRunFromEvidence({
|
|
1595
|
-
ticket: approvedAutopilotTicket,
|
|
1596
|
-
job: {
|
|
1597
|
-
_id: 'support-job-autopilot-approved-reviewed-pr',
|
|
1598
|
-
status: 'Closed',
|
|
1599
|
-
phase: 'COMPLETE',
|
|
1600
|
-
support_pr_readiness_contract: {
|
|
1601
|
-
...prReadyNoPrContract,
|
|
1602
|
-
contract_id: 'support-pr-readiness-ready-reviewed-pr',
|
|
1603
|
-
job_id: 'support-job-autopilot-approved-reviewed-pr',
|
|
1604
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1605
|
-
pull_request_status: 'OPEN'
|
|
1606
|
-
},
|
|
1607
|
-
support_pr_review_contract: {
|
|
1608
|
-
contract_id: 'support-pr-review-a-grade',
|
|
1609
|
-
status: 'passed',
|
|
1610
|
-
ready: true,
|
|
1611
|
-
strict_gate_passed: true,
|
|
1612
|
-
execution_grade: 'A',
|
|
1613
|
-
artifacts_grade: 'A',
|
|
1614
|
-
pull_request_grade: 'A',
|
|
1615
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1616
|
-
evidence_refs: ['qa-artifacts/support-before-after-proof.png']
|
|
1617
|
-
}
|
|
1618
|
-
},
|
|
1619
|
-
qaEvidence: {
|
|
1620
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1621
|
-
compile: { status: 'pass' },
|
|
1622
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1623
|
-
businessAssertions: [{
|
|
1624
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1625
|
-
status: 'pass',
|
|
1626
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1627
|
-
action: 'Apply the Customer B filter.',
|
|
1628
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1629
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1630
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1631
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1632
|
-
metadata: { supportDiagnosisProof: true }
|
|
1633
|
-
}],
|
|
1634
|
-
scorecardPassed: true
|
|
1635
|
-
}
|
|
1636
|
-
});
|
|
1637
|
-
assert.equal(approvedAutopilotReviewedPrRun.outcome, 'release_blocked');
|
|
1638
|
-
assert.equal(approvedAutopilotReviewedPrRun.gates.some((gate) => gate.key === 'support_pr_review_contract' && gate.status === 'pass'), true);
|
|
1639
|
-
assert.equal(approvedAutopilotReviewedPrRun.gates.some((gate) => gate.key === 'support_autopilot_completion_contract' && gate.status === 'pass'), true);
|
|
1640
|
-
assert.equal(approvedAutopilotReviewedPrRun.gates.some((gate) => gate.key === 'support_release_customer_acceptance' && gate.status === 'blocked'), true);
|
|
1641
|
-
assert.equal(approvedAutopilotReviewedPrRun.metadata?.autopilotCompletion?.prReviewReady, true);
|
|
1642
|
-
assert.equal(approvedAutopilotReviewedPrRun.metadata?.releaseCustomerAcceptance?.releaseReady, false);
|
|
1643
|
-
assert.equal(approvedAutopilotReviewedPrRun.metadata?.releaseCustomerAcceptance?.customerReplyReady, false);
|
|
1644
|
-
|
|
1645
|
-
const approvedAutopilotReleasedRun = buildSupportAIRunFromEvidence({
|
|
1646
|
-
ticket: {
|
|
1647
|
-
...approvedAutopilotTicket,
|
|
1648
|
-
automation: {
|
|
1649
|
-
...approvedAutopilotTicket.automation,
|
|
1650
|
-
release: {
|
|
1651
|
-
push_master: {
|
|
1652
|
-
status: 'completed',
|
|
1653
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1654
|
-
merge_sha: 'abc123'
|
|
1655
|
-
},
|
|
1656
|
-
deploy_production: {
|
|
1657
|
-
status: 'completed',
|
|
1658
|
-
last_deploy_pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1659
|
-
last_deploy_source_sha: 'abc123'
|
|
1660
|
-
}
|
|
1661
|
-
},
|
|
1662
|
-
customer_reply_policy: {
|
|
1663
|
-
readiness_contract: {
|
|
1664
|
-
contractId: 'support-customer-reply-released',
|
|
1665
|
-
status: 'draft_ready',
|
|
1666
|
-
policyAction: 'draft_resolution_reply',
|
|
1667
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1668
|
-
canDraftCustomerReply: true,
|
|
1669
|
-
canSendCustomerReply: false,
|
|
1670
|
-
requiresHumanApproval: true,
|
|
1671
|
-
proofBacked: true,
|
|
1672
|
-
businessProofReady: true,
|
|
1673
|
-
releaseReady: true,
|
|
1674
|
-
diagnosisReady: true,
|
|
1675
|
-
issueClassProbePlanReady: true,
|
|
1676
|
-
evidenceRefs: ['qa-artifacts/support-before-after-proof.png'],
|
|
1677
|
-
requiredEvidence: ['AIQaBusinessAssertion status=pass']
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
},
|
|
1682
|
-
job: {
|
|
1683
|
-
_id: 'support-job-autopilot-approved-released',
|
|
1684
|
-
status: 'Closed',
|
|
1685
|
-
phase: 'COMPLETE',
|
|
1686
|
-
support_pr_readiness_contract: {
|
|
1687
|
-
...prReadyNoPrContract,
|
|
1688
|
-
contract_id: 'support-pr-readiness-ready-released',
|
|
1689
|
-
job_id: 'support-job-autopilot-approved-released',
|
|
1690
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1691
|
-
pull_request_status: 'MERGED'
|
|
1692
|
-
},
|
|
1693
|
-
support_pr_review_contract: {
|
|
1694
|
-
contract_id: 'support-pr-review-released-a-grade',
|
|
1695
|
-
status: 'passed',
|
|
1696
|
-
ready: true,
|
|
1697
|
-
strict_gate_passed: true,
|
|
1698
|
-
execution_grade: 'A',
|
|
1699
|
-
artifacts_grade: 'A',
|
|
1700
|
-
pull_request_grade: 'A',
|
|
1701
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1702
|
-
evidence_refs: ['qa-artifacts/support-before-after-proof.png']
|
|
1703
|
-
}
|
|
1704
|
-
},
|
|
1705
|
-
qaEvidence: {
|
|
1706
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1707
|
-
compile: { status: 'pass' },
|
|
1708
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1709
|
-
businessAssertions: [{
|
|
1710
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1711
|
-
status: 'pass',
|
|
1712
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1713
|
-
action: 'Apply the Customer B filter.',
|
|
1714
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1715
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1716
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1717
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1718
|
-
metadata: { supportDiagnosisProof: true }
|
|
1719
|
-
}],
|
|
1720
|
-
scorecardPassed: true
|
|
1721
|
-
}
|
|
1722
|
-
});
|
|
1723
|
-
assert.equal(approvedAutopilotReleasedRun.outcome, 'accepted');
|
|
1724
|
-
assert.equal(approvedAutopilotReleasedRun.gates.some((gate) => gate.key === 'support_release_customer_acceptance' && gate.status === 'pass'), true);
|
|
1725
|
-
assert.equal(approvedAutopilotReleasedRun.metadata?.releaseCustomerAcceptance?.releaseReady, true);
|
|
1726
|
-
assert.equal(approvedAutopilotReleasedRun.metadata?.releaseCustomerAcceptance?.customerReplyReady, true);
|
|
1727
|
-
assert.equal(approvedAutopilotReleasedRun.metadata?.releaseCustomerAcceptance?.replyPrReferencePresent, true);
|
|
1728
|
-
|
|
1729
|
-
const approvedAutopilotMissingReplyPrRun = buildSupportAIRunFromEvidence({
|
|
1730
|
-
ticket: {
|
|
1731
|
-
...approvedAutopilotTicket,
|
|
1732
|
-
automation: {
|
|
1733
|
-
...approvedAutopilotTicket.automation,
|
|
1734
|
-
release: {
|
|
1735
|
-
push_master: {
|
|
1736
|
-
status: 'completed',
|
|
1737
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1738
|
-
merge_sha: 'abc123'
|
|
1739
|
-
},
|
|
1740
|
-
deploy_production: {
|
|
1741
|
-
status: 'completed',
|
|
1742
|
-
last_deploy_pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1743
|
-
last_deploy_source_sha: 'abc123'
|
|
1744
|
-
}
|
|
1745
|
-
},
|
|
1746
|
-
customer_reply_policy: {
|
|
1747
|
-
readiness_contract: {
|
|
1748
|
-
contractId: 'support-customer-reply-missing-reply-pr',
|
|
1749
|
-
status: 'draft_ready',
|
|
1750
|
-
policyAction: 'draft_resolution_reply',
|
|
1751
|
-
canDraftCustomerReply: true,
|
|
1752
|
-
canSendCustomerReply: false,
|
|
1753
|
-
requiresHumanApproval: true,
|
|
1754
|
-
proofBacked: true,
|
|
1755
|
-
businessProofReady: true,
|
|
1756
|
-
releaseReady: true,
|
|
1757
|
-
diagnosisReady: true,
|
|
1758
|
-
issueClassProbePlanReady: true,
|
|
1759
|
-
evidenceRefs: ['qa-artifacts/support-before-after-proof.png'],
|
|
1760
|
-
requiredEvidence: ['AIQaBusinessAssertion status=pass']
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
},
|
|
1765
|
-
job: {
|
|
1766
|
-
_id: 'support-job-autopilot-missing-reply-pr',
|
|
1767
|
-
status: 'Closed',
|
|
1768
|
-
phase: 'COMPLETE',
|
|
1769
|
-
support_pr_readiness_contract: {
|
|
1770
|
-
...prReadyNoPrContract,
|
|
1771
|
-
contract_id: 'support-pr-readiness-missing-reply-pr',
|
|
1772
|
-
job_id: 'support-job-autopilot-missing-reply-pr',
|
|
1773
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1774
|
-
pull_request_status: 'MERGED'
|
|
1775
|
-
},
|
|
1776
|
-
support_pr_review_contract: {
|
|
1777
|
-
contract_id: 'support-pr-review-missing-reply-pr-a-grade',
|
|
1778
|
-
status: 'passed',
|
|
1779
|
-
ready: true,
|
|
1780
|
-
strict_gate_passed: true,
|
|
1781
|
-
execution_grade: 'A',
|
|
1782
|
-
artifacts_grade: 'A',
|
|
1783
|
-
pull_request_grade: 'A',
|
|
1784
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1785
|
-
evidence_refs: ['qa-artifacts/support-before-after-proof.png']
|
|
1786
|
-
}
|
|
1787
|
-
},
|
|
1788
|
-
qaEvidence: {
|
|
1789
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1790
|
-
compile: { status: 'pass' },
|
|
1791
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1792
|
-
businessAssertions: [{
|
|
1793
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1794
|
-
status: 'pass',
|
|
1795
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1796
|
-
action: 'Apply the Customer B filter.',
|
|
1797
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1798
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1799
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1800
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1801
|
-
metadata: { supportDiagnosisProof: true }
|
|
1802
|
-
}],
|
|
1803
|
-
scorecardPassed: true
|
|
1804
|
-
}
|
|
1805
|
-
});
|
|
1806
|
-
assert.equal(approvedAutopilotMissingReplyPrRun.outcome, 'release_blocked');
|
|
1807
|
-
assert.equal(approvedAutopilotMissingReplyPrRun.gates.some((gate) => gate.key === 'support_release_customer_acceptance' && gate.status === 'blocked'), true);
|
|
1808
|
-
assert.equal(approvedAutopilotMissingReplyPrRun.metadata?.releaseCustomerAcceptance?.releaseReady, true);
|
|
1809
|
-
assert.equal(approvedAutopilotMissingReplyPrRun.metadata?.releaseCustomerAcceptance?.replyPrReferencePresent, false);
|
|
1810
|
-
assert.equal(approvedAutopilotMissingReplyPrRun.metadata?.releaseCustomerAcceptance?.customerReplyReady, false);
|
|
1811
|
-
assert.ok(approvedAutopilotMissingReplyPrRun.metadata?.releaseCustomerAcceptance?.blockers?.some((blocker: string) => /missing the current PR reference/i.test(blocker)));
|
|
1812
|
-
|
|
1813
|
-
const approvedAutopilotStaleReleaseRun = buildSupportAIRunFromEvidence({
|
|
1814
|
-
ticket: {
|
|
1815
|
-
...approvedAutopilotTicket,
|
|
1816
|
-
automation: {
|
|
1817
|
-
...approvedAutopilotTicket.automation,
|
|
1818
|
-
release: {
|
|
1819
|
-
push_master: {
|
|
1820
|
-
status: 'completed',
|
|
1821
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1822
|
-
merge_sha: 'old-sha'
|
|
1823
|
-
},
|
|
1824
|
-
deploy_production: {
|
|
1825
|
-
status: 'completed',
|
|
1826
|
-
last_deploy_pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4601',
|
|
1827
|
-
last_deploy_source_sha: 'old-sha'
|
|
1828
|
-
}
|
|
1829
|
-
},
|
|
1830
|
-
customer_reply_policy: {
|
|
1831
|
-
readiness_contract: {
|
|
1832
|
-
contractId: 'support-customer-reply-stale-release',
|
|
1833
|
-
status: 'draft_ready',
|
|
1834
|
-
policyAction: 'draft_resolution_reply',
|
|
1835
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4602',
|
|
1836
|
-
canDraftCustomerReply: true,
|
|
1837
|
-
canSendCustomerReply: false,
|
|
1838
|
-
requiresHumanApproval: true,
|
|
1839
|
-
proofBacked: true,
|
|
1840
|
-
businessProofReady: true,
|
|
1841
|
-
releaseReady: true,
|
|
1842
|
-
diagnosisReady: true,
|
|
1843
|
-
issueClassProbePlanReady: true,
|
|
1844
|
-
evidenceRefs: ['qa-artifacts/support-before-after-proof.png'],
|
|
1845
|
-
requiredEvidence: ['AIQaBusinessAssertion status=pass']
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
},
|
|
1850
|
-
job: {
|
|
1851
|
-
_id: 'support-job-autopilot-stale-release',
|
|
1852
|
-
status: 'Closed',
|
|
1853
|
-
phase: 'COMPLETE',
|
|
1854
|
-
support_pr_readiness_contract: {
|
|
1855
|
-
...prReadyNoPrContract,
|
|
1856
|
-
contract_id: 'support-pr-readiness-stale-release',
|
|
1857
|
-
job_id: 'support-job-autopilot-stale-release',
|
|
1858
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4602',
|
|
1859
|
-
pull_request_status: 'OPEN'
|
|
1860
|
-
},
|
|
1861
|
-
support_pr_review_contract: {
|
|
1862
|
-
contract_id: 'support-pr-review-stale-release-a-grade',
|
|
1863
|
-
status: 'passed',
|
|
1864
|
-
ready: true,
|
|
1865
|
-
strict_gate_passed: true,
|
|
1866
|
-
execution_grade: 'A',
|
|
1867
|
-
artifacts_grade: 'A',
|
|
1868
|
-
pull_request_grade: 'A',
|
|
1869
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4602',
|
|
1870
|
-
evidence_refs: ['qa-artifacts/support-before-after-proof.png']
|
|
1871
|
-
}
|
|
1872
|
-
},
|
|
1873
|
-
qaEvidence: {
|
|
1874
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1875
|
-
compile: { status: 'pass' },
|
|
1876
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1877
|
-
businessAssertions: [{
|
|
1878
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1879
|
-
status: 'pass',
|
|
1880
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1881
|
-
action: 'Apply the Customer B filter.',
|
|
1882
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1883
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1884
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1885
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1886
|
-
metadata: { supportDiagnosisProof: true }
|
|
1887
|
-
}],
|
|
1888
|
-
scorecardPassed: true
|
|
1889
|
-
}
|
|
1890
|
-
});
|
|
1891
|
-
assert.equal(approvedAutopilotStaleReleaseRun.outcome, 'release_blocked');
|
|
1892
|
-
assert.equal(approvedAutopilotStaleReleaseRun.gates.some((gate) => gate.key === 'support_release_customer_acceptance' && gate.status === 'blocked'), true);
|
|
1893
|
-
assert.equal(approvedAutopilotStaleReleaseRun.metadata?.releaseCustomerAcceptance?.releaseReady, false);
|
|
1894
|
-
assert.equal(approvedAutopilotStaleReleaseRun.metadata?.releaseCustomerAcceptance?.releasePrMatchesCurrent, false);
|
|
1895
|
-
assert.equal(approvedAutopilotStaleReleaseRun.metadata?.releaseCustomerAcceptance?.deployPrMatchesCurrent, false);
|
|
1896
|
-
assert.ok(approvedAutopilotStaleReleaseRun.metadata?.releaseCustomerAcceptance?.blockers?.some((blocker: string) => /different PR/i.test(blocker)));
|
|
1897
|
-
|
|
1898
|
-
const failedPrCreationRun = buildSupportAIRunFromEvidence({
|
|
1899
|
-
ticket: {
|
|
1900
|
-
...approvedAutopilotTicket,
|
|
1901
|
-
automation: {
|
|
1902
|
-
...approvedAutopilotTicket.automation,
|
|
1903
|
-
codex: {
|
|
1904
|
-
status: 'failed',
|
|
1905
|
-
pull_request_status: 'failed',
|
|
1906
|
-
pull_request_url: '',
|
|
1907
|
-
error: 'Automatic PR creation failed: GitHub branch protection rejected the generated branch.'
|
|
1908
|
-
},
|
|
1909
|
-
release: {
|
|
1910
|
-
push_master: {
|
|
1911
|
-
status: 'pending_manual',
|
|
1912
|
-
notes: 'Automatic PR creation failed: GitHub branch protection rejected the generated branch.'
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
},
|
|
1917
|
-
job: {
|
|
1918
|
-
_id: 'support-job-autopilot-pr-failed',
|
|
1919
|
-
status: 'Closed',
|
|
1920
|
-
phase: 'COMPLETE',
|
|
1921
|
-
pullRequestStatus: 'FAILED',
|
|
1922
|
-
pullRequestError: 'Automatic PR creation failed: GitHub branch protection rejected the generated branch.',
|
|
1923
|
-
support_pr_readiness_contract: {
|
|
1924
|
-
...prReadyNoPrContract,
|
|
1925
|
-
contract_id: 'support-pr-readiness-failed-pr',
|
|
1926
|
-
status: 'blocked',
|
|
1927
|
-
ready: false,
|
|
1928
|
-
job_id: 'support-job-autopilot-pr-failed',
|
|
1929
|
-
pr_failure_status: 'FAILED',
|
|
1930
|
-
blockers: ['Previous PR creation failed (FAILED).']
|
|
1931
|
-
}
|
|
1932
|
-
},
|
|
1933
|
-
qaEvidence: {
|
|
1934
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
1935
|
-
compile: { status: 'pass' },
|
|
1936
|
-
routeProbes: [{ route: '/support/004601', status: 'pass', screenshot: 'qa-artifacts/support-route.png' }],
|
|
1937
|
-
businessAssertions: [{
|
|
1938
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
1939
|
-
status: 'pass',
|
|
1940
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
1941
|
-
action: 'Apply the Customer B filter.',
|
|
1942
|
-
expected: 'Only Customer B tickets are listed.',
|
|
1943
|
-
observed: 'Only Customer B tickets are listed.',
|
|
1944
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
1945
|
-
artifactPaths: ['qa-artifacts/support-before-after-proof.png'],
|
|
1946
|
-
metadata: { supportDiagnosisProof: true }
|
|
1947
|
-
}],
|
|
1948
|
-
scorecardPassed: true
|
|
1949
|
-
}
|
|
1950
|
-
});
|
|
1951
|
-
assert.equal(failedPrCreationRun.outcome, 'release_blocked');
|
|
1952
|
-
assert.equal(failedPrCreationRun.gates.some((gate) => gate.key === 'support_pr_creation_result' && gate.status === 'fail'), true);
|
|
1953
|
-
assert.equal(failedPrCreationRun.events.some((event) => event.category === 'support_pr_creation_result'), true);
|
|
1954
|
-
assert.equal(failedPrCreationRun.metadata?.prCreationResult?.nextAction, 'repair_pr_creation_blocker');
|
|
1955
|
-
assert.equal(failedPrCreationRun.metadata?.prCreationResult?.pullRequestStatus, 'failed');
|
|
1956
|
-
assert.equal(failedPrCreationRun.metadata?.prCreationResult?.businessProofReady, true);
|
|
1957
|
-
|
|
1958
|
-
const supportRecoveryExecutionProofRun = buildSupportAIRunFromEvidence({
|
|
1959
|
-
ticket: { _id: 'ticket-recovery-proof', ticketNumber: '004500', title: 'Recovery proof' },
|
|
1960
|
-
job: {
|
|
1961
|
-
_id: 'support-job-recovery-proof',
|
|
1962
|
-
status: 'Running',
|
|
1963
|
-
phase: 'REVIEW'
|
|
1964
|
-
},
|
|
1965
|
-
qaEvidence: {
|
|
1966
|
-
managerRecoveryExecutionProof: {
|
|
1967
|
-
contractId: 'mgr-execution-proof-1',
|
|
1968
|
-
directiveId: 'mgr-directive-1',
|
|
1969
|
-
surface: 'resolveio_support_runner',
|
|
1970
|
-
dispatchAction: 'run_evidence_probe',
|
|
1971
|
-
phase: 'evidence',
|
|
1972
|
-
status: 'proof_ready',
|
|
1973
|
-
canContinueRun: true,
|
|
1974
|
-
canRunProductRepair: false,
|
|
1975
|
-
canRunExpensiveModel: false,
|
|
1976
|
-
canResetLoopBudget: true,
|
|
1977
|
-
proofRequiredBeforeContinuation: true,
|
|
1978
|
-
requiresNewEvidence: true,
|
|
1979
|
-
newEvidence: true,
|
|
1980
|
-
materialEvidence: true,
|
|
1981
|
-
evidenceStrength: 'material',
|
|
1982
|
-
evidenceSignals: ['evidence_hash_changed', 'artifact_paths_added'],
|
|
1983
|
-
startingFailureClass: 'product_code',
|
|
1984
|
-
startingBlockerFingerprint: 'before-fp',
|
|
1985
|
-
startingEvidenceHash: 'before-hash',
|
|
1986
|
-
latestFailureClass: 'product_code',
|
|
1987
|
-
latestBlockerFingerprint: 'after-fp',
|
|
1988
|
-
latestEvidenceHash: 'after-hash',
|
|
1989
|
-
requiredEvidence: ['fresh issue-class probe artifact'],
|
|
1990
|
-
missingEvidence: [],
|
|
1991
|
-
artifactPaths: ['qa/recovery-after-dom-trace.json'],
|
|
1992
|
-
changedFiles: [],
|
|
1993
|
-
blockers: [],
|
|
1994
|
-
nextAllowedAction: 'continue_gate',
|
|
1995
|
-
forbiddenActions: ['Do not continue product-code repair until recovery execution proof is proof_ready.'],
|
|
1996
|
-
createdAt: '2026-06-15T00:04:00.000Z'
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
});
|
|
2000
|
-
const recoveryProofGate = supportRecoveryExecutionProofRun.gates.find((gate) => gate.key === 'manager_recovery_execution_proof');
|
|
2001
|
-
assert.equal(recoveryProofGate?.status, 'pass');
|
|
2002
|
-
assert.equal(supportRecoveryExecutionProofRun.events.some((event) => event.category === 'manager_recovery_execution_proof'), true);
|
|
2003
|
-
assert.equal(supportRecoveryExecutionProofRun.metadata?.managerRecoveryExecutionProof?.canContinueRun, true);
|
|
2004
|
-
assert.equal(supportRecoveryExecutionProofRun.metadata?.managerRecoveryExecutionProof?.canResetLoopBudget, true);
|
|
2005
|
-
|
|
2006
|
-
const supportBlockedRecoveryExecutionProofRun = buildSupportAIRunFromEvidence({
|
|
2007
|
-
ticket: { _id: 'ticket-recovery-proof-blocked', ticketNumber: '004501', title: 'Recovery proof blocked' },
|
|
2008
|
-
job: {
|
|
2009
|
-
_id: 'support-job-recovery-proof-blocked',
|
|
2010
|
-
status: 'Blocked',
|
|
2011
|
-
phase: 'REVIEW',
|
|
2012
|
-
managerRecoveryExecutionProof: {
|
|
2013
|
-
contractId: 'mgr-execution-proof-2',
|
|
2014
|
-
directiveId: 'mgr-directive-2',
|
|
2015
|
-
surface: 'resolveio_support_runner',
|
|
2016
|
-
dispatchAction: 'run_evidence_probe',
|
|
2017
|
-
phase: 'evidence',
|
|
2018
|
-
status: 'blocked_same_evidence',
|
|
2019
|
-
canContinueRun: false,
|
|
2020
|
-
canRunProductRepair: false,
|
|
2021
|
-
canRunExpensiveModel: false,
|
|
2022
|
-
canResetLoopBudget: false,
|
|
2023
|
-
proofRequiredBeforeContinuation: true,
|
|
2024
|
-
requiresNewEvidence: true,
|
|
2025
|
-
newEvidence: false,
|
|
2026
|
-
materialEvidence: false,
|
|
2027
|
-
evidenceStrength: 'none',
|
|
2028
|
-
evidenceSignals: [],
|
|
2029
|
-
startingFailureClass: 'product_code',
|
|
2030
|
-
startingBlockerFingerprint: 'same-fp',
|
|
2031
|
-
startingEvidenceHash: 'same-hash',
|
|
2032
|
-
latestFailureClass: 'product_code',
|
|
2033
|
-
latestBlockerFingerprint: 'same-fp',
|
|
2034
|
-
latestEvidenceHash: 'same-hash',
|
|
2035
|
-
requiredEvidence: ['fresh issue-class probe artifact'],
|
|
2036
|
-
missingEvidence: ['fresh issue-class probe artifact'],
|
|
2037
|
-
artifactPaths: ['qa/recovery-before-dom-trace.json'],
|
|
2038
|
-
changedFiles: [],
|
|
2039
|
-
blockers: ['recovery_execution_same_evidence_after_dispatch'],
|
|
2040
|
-
nextAllowedAction: 'collect_required_recovery_proof',
|
|
2041
|
-
forbiddenActions: ['Do not continue product-code repair until recovery execution proof is proof_ready.'],
|
|
2042
|
-
createdAt: '2026-06-15T00:05:00.000Z'
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
});
|
|
2046
|
-
const blockedRecoveryProofGate = supportBlockedRecoveryExecutionProofRun.gates.find((gate) => gate.key === 'manager_recovery_execution_proof');
|
|
2047
|
-
assert.equal(blockedRecoveryProofGate?.status, 'blocked');
|
|
2048
|
-
assert.equal(supportBlockedRecoveryExecutionProofRun.metadata?.managerRecoveryExecutionProof?.canContinueRun, false);
|
|
2049
|
-
assert.deepEqual(supportBlockedRecoveryExecutionProofRun.metadata?.managerRecoveryExecutionProof?.missingEvidence, ['fresh issue-class probe artifact']);
|
|
2050
|
-
|
|
2051
|
-
const supportAcceptedDiagnosisGate = {
|
|
2052
|
-
issue_case: {
|
|
2053
|
-
customer_complaint: 'Support ticket list shows tickets from the wrong customer after applying a customer filter.',
|
|
2054
|
-
expected_result: 'Only tickets for Customer B should appear when Customer B is selected.',
|
|
2055
|
-
observed_result: 'A Customer A ticket remains visible while filtered to Customer B.',
|
|
2056
|
-
route_module: '/support tickets list',
|
|
2057
|
-
account_customer_context: 'Support admin reviewing ticket 004430 for Customer B.',
|
|
2058
|
-
reproduction_status: 'reproduced'
|
|
2059
|
-
},
|
|
2060
|
-
issue_class: 'filter_query_mismatch',
|
|
2061
|
-
status: 'passed',
|
|
2062
|
-
accepted_hypothesis: {
|
|
2063
|
-
statement: 'The ticket list query ignores the customer filter.',
|
|
2064
|
-
falsifiable_test: 'Apply the Customer B filter and verify every returned row belongs to Customer B.',
|
|
2065
|
-
evidence: ['QA artifact shows Customer A ticket visible while Customer B filter is active.']
|
|
2066
|
-
},
|
|
2067
|
-
rejected_alternatives: [
|
|
2068
|
-
'Frontend select state was rejected because the network payload includes the selected Customer B filter.',
|
|
2069
|
-
'Authentication was rejected because the support admin can load the ticket list route.'
|
|
2070
|
-
],
|
|
2071
|
-
failing_path: {
|
|
2072
|
-
frontend: 'Support ticket customer filter submits selected customer id.',
|
|
2073
|
-
backend: 'server/src/publications/support-tickets.ts ticket list publication',
|
|
2074
|
-
data_query: 'Mongo ticket query does not constrain by selected customer id.',
|
|
2075
|
-
description: 'Filter input reaches the backend, but the publication query returns rows outside the selected customer.'
|
|
2076
|
-
},
|
|
2077
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
2078
|
-
proof_plan: {
|
|
2079
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
2080
|
-
action: 'Apply the Customer B filter and reload the ticket list.',
|
|
2081
|
-
after: 'Only Customer B tickets are listed.',
|
|
2082
|
-
business_assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
2083
|
-
data_assertion: 'Every returned ticket row has customerId equal to Customer B.',
|
|
2084
|
-
artifact_expectation: 'QA stores before/action/after row snapshots and the filtered publication payload.',
|
|
2085
|
-
business_proof_contract: {
|
|
2086
|
-
issue_class: 'filter_query_mismatch',
|
|
2087
|
-
setup_state: 'Seed or select one Customer A ticket and one Customer B ticket.',
|
|
2088
|
-
action_under_test: 'Apply the Customer B filter on the support ticket list.',
|
|
2089
|
-
expected_business_state_change: 'Rows outside Customer B are excluded while Customer B rows remain visible.',
|
|
2090
|
-
prohibited_false_pass: 'Route load or non-empty table without row/customer proof.',
|
|
2091
|
-
proof_artifacts: ['qa-artifacts/support-filter-before-after.json', 'qa-artifacts/support-filter-payload.json'],
|
|
2092
|
-
data_or_dom_assertion: 'DOM rows and publication payload contain only Customer B ticket ids.'
|
|
2093
|
-
}
|
|
2094
|
-
},
|
|
2095
|
-
evidence: [{
|
|
2096
|
-
type: 'ticket',
|
|
2097
|
-
summary: 'Ticket 004430 reports wrong-customer tickets appearing after a customer filter is applied.'
|
|
2098
|
-
}, {
|
|
2099
|
-
type: 'qa',
|
|
2100
|
-
summary: 'Browser QA reproduced Customer A ticket visible while Customer B filter was active.',
|
|
2101
|
-
artifactPath: 'qa-artifacts/support-filter-reproduction.json'
|
|
2102
|
-
}, {
|
|
2103
|
-
type: 'code',
|
|
2104
|
-
summary: 'Publication owner file contains the query that returns support ticket rows.'
|
|
2105
|
-
}]
|
|
2106
|
-
};
|
|
2107
|
-
|
|
2108
|
-
const supportBadProbePlanRun = buildSupportAIRunFromEvidence({
|
|
2109
|
-
ticket: {
|
|
2110
|
-
_id: 'ticket-bad-probe-plan',
|
|
2111
|
-
ticketNumber: '004424',
|
|
2112
|
-
title: 'Bad probe plan cannot be accepted',
|
|
2113
|
-
accepted: true,
|
|
2114
|
-
status: 'Resolved'
|
|
2115
|
-
},
|
|
2116
|
-
job: {
|
|
2117
|
-
_id: 'support-job-bad-probe-plan',
|
|
2118
|
-
status: 'Resolved',
|
|
2119
|
-
phase: 'QA',
|
|
2120
|
-
supportV5DiagnosisGate: {
|
|
2121
|
-
issue_case: {
|
|
2122
|
-
customer_complaint: 'Support ticket list shows tickets from the wrong customer after applying a customer filter.',
|
|
2123
|
-
expected_result: 'Only tickets for Customer B should appear when Customer B is selected.',
|
|
2124
|
-
observed_result: 'A Customer A ticket remains visible while filtered to Customer B.',
|
|
2125
|
-
route_module: '/support tickets list',
|
|
2126
|
-
account_customer_context: 'Support admin reviewing ticket 004424 for Customer B.',
|
|
2127
|
-
reproduction_status: 'reproduced'
|
|
2128
|
-
},
|
|
2129
|
-
issue_class: 'filter_query_mismatch',
|
|
2130
|
-
status: 'passed',
|
|
2131
|
-
accepted_hypothesis: {
|
|
2132
|
-
statement: 'The ticket list query ignores the customer filter.',
|
|
2133
|
-
falsifiable_test: 'Apply the Customer B filter and verify every returned row belongs to Customer B.',
|
|
2134
|
-
evidence: ['QA artifact shows Customer A ticket visible while Customer B filter is active.']
|
|
2135
|
-
},
|
|
2136
|
-
rejected_alternatives: [
|
|
2137
|
-
'Frontend select state was rejected because the network payload includes the selected Customer B filter.',
|
|
2138
|
-
'Auth was rejected because the support admin can load the ticket list route.'
|
|
2139
|
-
],
|
|
2140
|
-
failing_path: {
|
|
2141
|
-
frontend: 'Support ticket customer filter submits selected customer id.',
|
|
2142
|
-
backend: 'server/src/publications/support-tickets.ts ticket list publication',
|
|
2143
|
-
data_query: 'Mongo ticket query does not constrain by selected customer id.',
|
|
2144
|
-
description: 'Filter input reaches the backend, but the publication query returns rows outside the selected customer.'
|
|
2145
|
-
},
|
|
2146
|
-
owner_files: ['server/src/publications/support-tickets.ts'],
|
|
2147
|
-
proof_plan: {
|
|
2148
|
-
before: 'Customer A ticket appears while filtered to Customer B.',
|
|
2149
|
-
action: 'Apply the Customer B filter and reload the ticket list.',
|
|
2150
|
-
after: 'Only Customer B tickets are listed.',
|
|
2151
|
-
business_assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
2152
|
-
data_assertion: 'Every returned ticket row has customerId equal to Customer B.',
|
|
2153
|
-
artifact_expectation: 'QA stores before/action/after row snapshots and the filtered publication payload.'
|
|
2154
|
-
},
|
|
2155
|
-
evidence: [{
|
|
2156
|
-
type: 'ticket',
|
|
2157
|
-
summary: 'Ticket 004424 reports wrong-customer tickets after a customer filter is applied.'
|
|
2158
|
-
}, {
|
|
2159
|
-
type: 'qa',
|
|
2160
|
-
summary: 'Browser QA reproduced Customer A ticket while Customer B filter was active.',
|
|
2161
|
-
artifactPath: 'qa-artifacts/support-filter-reproduction.json'
|
|
2162
|
-
}, {
|
|
2163
|
-
type: 'code',
|
|
2164
|
-
summary: 'Publication owner file contains the support ticket row query.'
|
|
2165
|
-
}]
|
|
2166
|
-
},
|
|
2167
|
-
supportV5IssueClassProbePlan: {
|
|
2168
|
-
planId: 'bad-probe-plan',
|
|
2169
|
-
status: 'ready',
|
|
2170
|
-
issue_class: 'filter_query_mismatch',
|
|
2171
|
-
diagnosisValid: true,
|
|
2172
|
-
probes: [{
|
|
2173
|
-
issue_class: 'filter_query_mismatch',
|
|
2174
|
-
probe_type: 'issue_class_probe',
|
|
2175
|
-
failure_class: 'business',
|
|
2176
|
-
objective: 'Verify the customer filter excludes wrong-customer rows.',
|
|
2177
|
-
route: '',
|
|
2178
|
-
action: '',
|
|
2179
|
-
expected_evidence: '',
|
|
2180
|
-
expected_business_proof: '',
|
|
2181
|
-
required_artifacts: [],
|
|
2182
|
-
state_transition: { before: '', action: '', after: '', assertion: '' },
|
|
2183
|
-
acceptance_gate: 'route_probe',
|
|
2184
|
-
blocks_acceptance_without_business_assertion: false
|
|
2185
|
-
}],
|
|
2186
|
-
requiredArtifacts: [],
|
|
2187
|
-
acceptanceGate: 'route_probe',
|
|
2188
|
-
falsePassBlockers: [],
|
|
2189
|
-
blockers: [],
|
|
2190
|
-
generatedAt: '2026-06-06T00:00:00.000Z'
|
|
2191
|
-
},
|
|
2192
|
-
supportV5AutonomousDecision: {
|
|
2193
|
-
nextActionContract: {
|
|
2194
|
-
contractId: 'support-next-action-business-qa',
|
|
2195
|
-
action: 'run_business_proof_qa',
|
|
2196
|
-
label: 'Run business proof QA',
|
|
2197
|
-
primaryCommand: 'run_support_v5_business_proof_qa',
|
|
2198
|
-
lane: 'qa',
|
|
2199
|
-
stepType: 'business_proof',
|
|
2200
|
-
safeToAutoRun: true,
|
|
2201
|
-
requiresHumanApproval: false,
|
|
2202
|
-
canRunWithoutCodexMonitor: true,
|
|
2203
|
-
codexFallbackRequired: false,
|
|
2204
|
-
rootCauseFirstSatisfied: true,
|
|
2205
|
-
preconditions: ['SupportDiagnosisGate passed.'],
|
|
2206
|
-
successEvidence: ['AIQaBusinessAssertion mapped to proof_plan.'],
|
|
2207
|
-
stopConditions: ['Same failure class repeats without new evidence.'],
|
|
2208
|
-
ownerFiles: ['server/src/publications/support-tickets.ts'],
|
|
2209
|
-
decisionBasis: {
|
|
2210
|
-
diagnosisValid: true,
|
|
2211
|
-
ownerFilesReady: true,
|
|
2212
|
-
proofPlanReady: true,
|
|
2213
|
-
businessProofReady: true,
|
|
2214
|
-
evidenceFreshnessStatus: 'fresh',
|
|
2215
|
-
evidenceStrength: 'high',
|
|
2216
|
-
failureClass: 'business',
|
|
2217
|
-
sameFailureCount: 0
|
|
2218
|
-
}
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
},
|
|
2222
|
-
qaEvidence: {
|
|
2223
|
-
compile: { status: 'pass' },
|
|
2224
|
-
routeProbes: [{ route: '/support/004424', status: 'pass' }],
|
|
2225
|
-
businessAssertions: [{
|
|
2226
|
-
assertion: 'The wrong-customer ticket is absent after filtering.',
|
|
2227
|
-
status: 'pass',
|
|
2228
|
-
action: 'Apply the Customer B filter and reload the ticket list.',
|
|
2229
|
-
expected: 'Only Customer B tickets are listed.',
|
|
2230
|
-
observed: 'Only Customer B tickets are listed.',
|
|
2231
|
-
dataProof: 'Every returned ticket row has customerId equal to Customer B.',
|
|
2232
|
-
artifactPaths: ['qa-artifacts/support-filter-before-after.json'],
|
|
2233
|
-
metadata: { proofPlanMatched: true, supportDiagnosisProof: true }
|
|
2234
|
-
}]
|
|
2235
|
-
}
|
|
2236
|
-
});
|
|
2237
|
-
const supportBadProbePlanGate = supportBadProbePlanRun.gates.find((gate) => gate.key === 'support_issue_class_probe_plan');
|
|
2238
|
-
assert.equal(supportBadProbePlanGate?.status, 'blocked');
|
|
2239
|
-
assert.equal(supportBadProbePlanRun.metadata?.issueClassProbePlan?.issueClassProbePlanReady, false);
|
|
2240
|
-
assert.equal(supportBadProbePlanRun.outcome, 'false_pass');
|
|
2241
|
-
assert.match(String(supportBadProbePlanRun.nextAction || ''), /IssueClassProbePlan/i);
|
|
2242
|
-
|
|
2243
|
-
const supportInvalidRootCauseContractRun = buildSupportAIRunFromEvidence({
|
|
2244
|
-
ticket: { _id: 'ticket-invalid-root-cause', ticketNumber: '004422', title: 'Invalid root cause contract' },
|
|
2245
|
-
job: {
|
|
2246
|
-
_id: 'support-job-invalid-root-cause',
|
|
2247
|
-
status: 'Running',
|
|
2248
|
-
phase: 'Planning',
|
|
2249
|
-
supportRootCauseEntryContract: {
|
|
2250
|
-
contract_id: 'support-root-cause-entry-invalid',
|
|
2251
|
-
required_output: {
|
|
2252
|
-
object_key: 'support_diagnosis_gate',
|
|
2253
|
-
required_fields: ['issue_case']
|
|
2254
|
-
},
|
|
2255
|
-
owner_file_policy: {
|
|
2256
|
-
max_files: 50
|
|
2257
|
-
},
|
|
2258
|
-
business_proof_policy: {},
|
|
2259
|
-
failure_policy: {},
|
|
2260
|
-
issue_class_probes: [{ issue_class: 'no_op_submit' }]
|
|
2261
|
-
}
|
|
2262
|
-
}
|
|
2263
|
-
});
|
|
2264
|
-
const invalidRootCauseGate = supportInvalidRootCauseContractRun.gates.find((gate) => gate.key === 'support_root_cause_entry_contract');
|
|
2265
|
-
assert.equal(invalidRootCauseGate?.status, 'fail');
|
|
2266
|
-
assert.match(String(invalidRootCauseGate?.reason || ''), /missing required output fields|issue-class probes/i);
|
|
2267
|
-
|
|
2268
|
-
const supportHotfixBlockedUntilCommitRun = buildSupportAIRunFromEvidence({
|
|
2269
|
-
ticket: { _id: 'ticket-hotfix-commit-blocked', ticketNumber: '004777', title: 'Hotfix must be committed' },
|
|
2270
|
-
job: {
|
|
2271
|
-
_id: 'support-hotfix-commit-blocked',
|
|
2272
|
-
status: 'Running',
|
|
2273
|
-
phase: 'Release',
|
|
2274
|
-
support_v5_autonomous_decision: {
|
|
2275
|
-
next_action_contract: {
|
|
2276
|
-
contract_id: 'support-next-action-hotfix-blocked',
|
|
2277
|
-
action: 'apply_live_hotfix',
|
|
2278
|
-
label: 'Apply live hotfix',
|
|
2279
|
-
primary_command: 'run_support_v5_live_hotfix',
|
|
2280
|
-
lane: 'release',
|
|
2281
|
-
step_type: 'hotfix',
|
|
2282
|
-
safe_to_auto_run: false,
|
|
2283
|
-
requires_human_approval: true,
|
|
2284
|
-
can_run_without_codex_monitor: false,
|
|
2285
|
-
codex_fallback_required: true,
|
|
2286
|
-
codex_fallback_reason: 'Live hotfix cannot proceed until commit proof is pushed.',
|
|
2287
|
-
success_evidence: ['sourceCommitSha', 'githubCommitUrl', 'gitCommitStatus=passed', 'gitPushStatus=passed'],
|
|
2288
|
-
decision_basis: {
|
|
2289
|
-
failure_class: 'release',
|
|
2290
|
-
hotfix_commit_required: true,
|
|
2291
|
-
live_hotfix_blocked_until_commit: true,
|
|
2292
|
-
same_failure_count: 1
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
});
|
|
2298
|
-
const supportHotfixBlockedGate = supportHotfixBlockedUntilCommitRun.gates.find((gate) => gate.key === 'support_next_action_contract');
|
|
2299
|
-
assert.equal(supportHotfixBlockedGate?.status, 'blocked');
|
|
2300
|
-
assert.match(String(supportHotfixBlockedGate?.reason || ''), /GitHub commit proof/i);
|
|
2301
|
-
assert.equal(supportHotfixBlockedGate?.metadata?.codexFallbackRequired, true);
|
|
2302
|
-
assert.equal(supportHotfixBlockedUntilCommitRun.metadata?.nextActionContract?.liveHotfixBlockedUntilCommit, true);
|
|
2303
|
-
|
|
2304
|
-
const supportHotfixDurabilityRun = buildSupportAIRunFromEvidence({
|
|
2305
|
-
ticket: { _id: 'ticket-hotfix-durability', ticketNumber: '004779', title: 'Hotfix durability contract' },
|
|
2306
|
-
job: {
|
|
2307
|
-
_id: 'support-hotfix-durability',
|
|
2308
|
-
status: 'Running',
|
|
2309
|
-
phase: 'Release',
|
|
2310
|
-
supportManagerHotfixDurabilityContract: {
|
|
2311
|
-
contract_id: 'support-hotfix-durability-test',
|
|
2312
|
-
required: true,
|
|
2313
|
-
action: 'run_release_repair',
|
|
2314
|
-
status: 'waiting_for_commit_proof',
|
|
2315
|
-
can_prepare_hotfix_patch: true,
|
|
2316
|
-
can_hotfix_backend: false,
|
|
2317
|
-
live_hotfix_blocked_until_commit: true,
|
|
2318
|
-
missing_commit_proof_fields: ['sourceCommitSha', 'githubCommitUrl', 'gitCommitStatus=passed', 'gitPushStatus=passed'],
|
|
2319
|
-
next_safe_action: 'commit_and_push_hotfix_to_github'
|
|
2320
|
-
}
|
|
2321
|
-
}
|
|
2322
|
-
});
|
|
2323
|
-
const supportHotfixDurabilityGate = supportHotfixDurabilityRun.gates.find((gate) => gate.key === 'hotfix_durability_contract');
|
|
2324
|
-
assert.equal(supportHotfixDurabilityGate?.status, 'blocked');
|
|
2325
|
-
assert.equal(supportHotfixDurabilityGate?.metadata?.liveHotfixBlockedUntilCommit, true);
|
|
2326
|
-
assert.equal(supportHotfixDurabilityGate?.metadata?.commitFirstProtocolSatisfied, false);
|
|
2327
|
-
assert.equal(supportHotfixDurabilityRun.metadata?.hotfixDurability?.liveHotfixBlockedUntilCommit, true);
|
|
2328
|
-
assert.equal(supportHotfixDurabilityRun.metadata?.hotfixDurability?.commitFirstProtocolSatisfied, false);
|
|
2329
|
-
assert.equal(supportHotfixDurabilityRun.metadata?.hotfixDurability?.liveHotfixAllowed, false);
|
|
2330
|
-
assert.equal(supportHotfixDurabilityRun.metadata?.hotfixDurability?.canHotfixBackend, false);
|
|
2331
|
-
assert.equal(supportHotfixDurabilityRun.events.some((event) => event.category === 'hotfix_durability_contract'), true);
|
|
2332
|
-
|
|
2333
|
-
const supportMissingNextActionContractRun = buildSupportAIRunFromEvidence({
|
|
2334
|
-
ticket: { _id: 'ticket-missing-next-action', ticketNumber: '004778', title: 'Support V5 missing next action' },
|
|
2335
|
-
job: {
|
|
2336
|
-
_id: 'support-missing-next-action',
|
|
2337
|
-
status: 'Running',
|
|
2338
|
-
phase: 'Manager',
|
|
2339
|
-
supportWorkflowMode: 'support_v5',
|
|
2340
|
-
supportV5SupervisorState: {
|
|
2341
|
-
status: 'active',
|
|
2342
|
-
activeStep: 'manager_recovery',
|
|
2343
|
-
activeBlocker: 'Runner needs a structured next action.'
|
|
2344
|
-
},
|
|
2345
|
-
supportV5StepHistory: [{
|
|
2346
|
-
lane: 'qa',
|
|
2347
|
-
stepType: 'business_proof',
|
|
2348
|
-
outcome: 'needs_repair',
|
|
2349
|
-
failureClass: 'business',
|
|
2350
|
-
blocker: 'Business proof missing after route-only QA.',
|
|
2351
|
-
evidenceHash: 'route-only-no-next-action'
|
|
2352
|
-
}]
|
|
2353
|
-
}
|
|
2354
|
-
});
|
|
2355
|
-
const supportMissingNextActionGate = supportMissingNextActionContractRun.gates.find((gate) => gate.key === 'support_next_action_contract');
|
|
2356
|
-
assert.equal(supportMissingNextActionGate?.status, 'blocked');
|
|
2357
|
-
assert.equal(supportMissingNextActionGate?.metadata?.missingContract, true);
|
|
2358
|
-
assert.equal(supportMissingNextActionGate?.metadata?.canRunWithoutCodexMonitor, false);
|
|
2359
|
-
assert.equal(supportMissingNextActionGate?.metadata?.codexFallbackRequired, true);
|
|
2360
|
-
assert.equal(supportMissingNextActionContractRun.outcome, 'manual_handoff');
|
|
2361
|
-
assert.match(String(supportMissingNextActionContractRun.nextAction || ''), /validated next-action contract/i);
|
|
2362
|
-
assert.equal(supportMissingNextActionContractRun.metadata?.nextActionContract?.status, 'blocked');
|
|
2363
|
-
assert.equal(supportMissingNextActionContractRun.events.some((event) => event.category === 'support_next_action_contract'), true);
|
|
2364
|
-
const supportMissingManagerPacketGate = supportMissingNextActionContractRun.gates.find((gate) => gate.key === 'support_manager_execution_packet');
|
|
2365
|
-
assert.equal(supportMissingManagerPacketGate?.status, 'blocked');
|
|
2366
|
-
assert.equal(supportMissingManagerPacketGate?.metadata?.missingPacket, true);
|
|
2367
|
-
assert.equal(supportMissingNextActionContractRun.metadata?.managerExecutionPacket?.gateStatus, 'blocked');
|
|
2368
|
-
assert.equal(supportMissingNextActionContractRun.metadata?.managerExecutionPacket?.codexFallbackRequired, true);
|
|
2369
|
-
assert.equal(supportMissingNextActionContractRun.events.some((event) => event.category === 'support_manager_execution_packet'), true);
|
|
2370
|
-
|
|
2371
|
-
const supportRepairBeforeDiagnosisRun = buildSupportAIRunFromEvidence({
|
|
2372
|
-
ticket: { _id: 'ticket-repair-before-diagnosis', ticketNumber: '004502', title: 'Repair started before diagnosis' },
|
|
2373
|
-
job: {
|
|
2374
|
-
_id: 'support-job-repair-before-diagnosis',
|
|
2375
|
-
status: 'Running',
|
|
2376
|
-
phase: 'Build',
|
|
2377
|
-
supportV5StepHistory: [{
|
|
2378
|
-
lane: 'build',
|
|
2379
|
-
stepType: 'build_repair',
|
|
2380
|
-
outcome: 'needs_repair',
|
|
2381
|
-
failureClass: 'product_code',
|
|
2382
|
-
blocker: 'Save action still fails.',
|
|
2383
|
-
changedFiles: ['server/src/methods/support-ticket-save.ts'],
|
|
2384
|
-
evidenceHash: 'repair-without-diagnosis'
|
|
2385
|
-
}]
|
|
2386
|
-
},
|
|
2387
|
-
qaEvidence: {
|
|
2388
|
-
compile: { status: 'pass' },
|
|
2389
|
-
routeProbes: [{ route: '/support/004502', status: 'pass' }]
|
|
2390
|
-
}
|
|
2391
|
-
});
|
|
2392
|
-
const supportRepairBeforeDiagnosisGate = supportRepairBeforeDiagnosisRun.gates.find((gate) => gate.key === 'support_diagnosis_before_repair');
|
|
2393
|
-
assert.equal(supportRepairBeforeDiagnosisGate?.status, 'blocked');
|
|
2394
|
-
assert.equal(supportRepairBeforeDiagnosisGate?.metadata?.diagnosisValid, false);
|
|
2395
|
-
assert.equal(supportRepairBeforeDiagnosisGate?.metadata?.allowedDispatchAction, 'run_read_only_diagnosis');
|
|
2396
|
-
assert.equal(supportRepairBeforeDiagnosisGate?.metadata?.productRepairAllowed, false);
|
|
2397
|
-
assert.equal(supportRepairBeforeDiagnosisRun.outcome, 'manual_handoff');
|
|
2398
|
-
assert.match(String(supportRepairBeforeDiagnosisGate?.reason || ''), /Support product repair is blocked/i);
|
|
2399
|
-
assert.match(String(supportRepairBeforeDiagnosisRun.nextAction || ''), /read-only support diagnosis/i);
|
|
2400
|
-
assert.equal(supportRepairBeforeDiagnosisRun.metadata?.diagnosisBeforeRepair?.allowedDispatchAction, 'run_read_only_diagnosis');
|
|
2401
|
-
assert.deepEqual(supportRepairBeforeDiagnosisRun.metadata?.diagnosisBeforeRepair?.changedFiles, ['server/src/methods/support-ticket-save.ts']);
|
|
2402
|
-
assert.equal(supportRepairBeforeDiagnosisRun.events.some((event) => event.category === 'support_diagnosis_before_repair'), true);
|
|
2403
|
-
|
|
2404
|
-
const supportInScopeRepairRun = buildSupportAIRunFromEvidence({
|
|
2405
|
-
ticket: { _id: 'ticket-in-scope-repair', ticketNumber: '004503', title: 'In-scope support repair' },
|
|
2406
|
-
job: {
|
|
2407
|
-
_id: 'support-job-in-scope-repair',
|
|
2408
|
-
status: 'Running',
|
|
2409
|
-
phase: 'Build',
|
|
2410
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate,
|
|
2411
|
-
supportV5StepHistory: [{
|
|
2412
|
-
lane: 'build',
|
|
2413
|
-
stepType: 'build_repair',
|
|
2414
|
-
outcome: 'pass',
|
|
2415
|
-
failureClass: 'product_code',
|
|
2416
|
-
summary: 'Owner-scoped publication repair completed.',
|
|
2417
|
-
changedFiles: ['server/src/publications/support-tickets.ts', 'tests/support-ticket-filter.test.ts'],
|
|
2418
|
-
evidenceHash: 'owner-scope-in-scope'
|
|
2419
|
-
}]
|
|
2420
|
-
},
|
|
2421
|
-
qaEvidence: {
|
|
2422
|
-
compile: { status: 'pass' },
|
|
2423
|
-
routeProbes: [{ route: '/support', status: 'pass' }]
|
|
2424
|
-
}
|
|
2425
|
-
});
|
|
2426
|
-
const supportInScopeGate = supportInScopeRepairRun.gates.find((gate) => gate.key === 'support_owner_file_scope');
|
|
2427
|
-
assert.equal(supportInScopeGate?.status, 'pass');
|
|
2428
|
-
assert.equal(supportInScopeGate?.metadata?.productRepairAllowed, true);
|
|
2429
|
-
assert.deepEqual(supportInScopeGate?.metadata?.outsideOwnerFiles, []);
|
|
2430
|
-
assert.equal(supportInScopeRepairRun.metadata?.ownerFileScope?.allowedTestFilesOutsideOwnerScope, true);
|
|
2431
|
-
assert.equal(supportInScopeRepairRun.events.some((event) => event.category === 'support_owner_file_scope'), true);
|
|
2432
|
-
|
|
2433
|
-
const supportOutOfScopeRepairRun = buildSupportAIRunFromEvidence({
|
|
2434
|
-
ticket: { _id: 'ticket-out-of-scope-repair', ticketNumber: '004504', title: 'Out-of-scope support repair' },
|
|
2435
|
-
job: {
|
|
2436
|
-
_id: 'support-job-out-of-scope-repair',
|
|
2437
|
-
status: 'Running',
|
|
2438
|
-
phase: 'Build',
|
|
2439
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate,
|
|
2440
|
-
supportV5StepHistory: [{
|
|
2441
|
-
lane: 'build',
|
|
2442
|
-
stepType: 'build_repair',
|
|
2443
|
-
outcome: 'needs_repair',
|
|
2444
|
-
failureClass: 'product_code',
|
|
2445
|
-
blocker: 'Repair touched an unrelated support method.',
|
|
2446
|
-
changedFiles: ['server/src/publications/support-tickets.ts', 'server/src/methods/support-ticket-save.ts'],
|
|
2447
|
-
evidenceHash: 'owner-scope-out-of-scope'
|
|
2448
|
-
}]
|
|
2449
|
-
},
|
|
2450
|
-
qaEvidence: {
|
|
2451
|
-
compile: { status: 'pass' },
|
|
2452
|
-
routeProbes: [{ route: '/support', status: 'pass' }]
|
|
2453
|
-
}
|
|
2454
|
-
});
|
|
2455
|
-
const supportOutOfScopeGate = supportOutOfScopeRepairRun.gates.find((gate) => gate.key === 'support_owner_file_scope');
|
|
2456
|
-
assert.equal(supportOutOfScopeGate?.status, 'blocked');
|
|
2457
|
-
assert.deepEqual(supportOutOfScopeGate?.metadata?.outsideOwnerFiles, ['server/src/methods/support-ticket-save.ts']);
|
|
2458
|
-
assert.equal(supportOutOfScopeGate?.metadata?.allowedDispatchAction, 'run_read_only_diagnosis');
|
|
2459
|
-
assert.equal(supportOutOfScopeRepairRun.outcome, 'manual_handoff');
|
|
2460
|
-
assert.match(String(supportOutOfScopeRepairRun.nextAction || ''), /Revise the SupportDiagnosisGate/i);
|
|
2461
|
-
assert.equal(supportOutOfScopeRepairRun.metadata?.ownerFileScope?.productRepairAllowed, false);
|
|
2462
|
-
assert.deepEqual(supportOutOfScopeRepairRun.metadata?.ownerFileScope?.outsideOwnerFiles, ['server/src/methods/support-ticket-save.ts']);
|
|
2463
|
-
|
|
2464
|
-
const supportUnpushedHotfixRun = buildSupportAIRunFromEvidence({
|
|
2465
|
-
ticket: { _id: 'ticket-004421-hotfix', ticketNumber: '004421', title: 'Unpushed backend hotfix guard' },
|
|
2466
|
-
job: {
|
|
2467
|
-
_id: 'support-job-unpushed-hotfix',
|
|
2468
|
-
status: 'Running',
|
|
2469
|
-
phase: 'Release',
|
|
2470
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate
|
|
2471
|
-
},
|
|
2472
|
-
qaEvidence: {
|
|
2473
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
2474
|
-
compile: { status: 'pass' },
|
|
2475
|
-
routeProbes: [{ route: '/support/004421', status: 'pass' }],
|
|
2476
|
-
hotfixEvidence: {
|
|
2477
|
-
channel: 'backend_js',
|
|
2478
|
-
target: {
|
|
2479
|
-
host: 'backend.resolveio.com',
|
|
2480
|
-
path: '/var/app/current/http/runner-manager-selftest.js'
|
|
2481
|
-
},
|
|
2482
|
-
compiledArtifactPath: 'dist/http/runner-manager-selftest.js',
|
|
2483
|
-
remoteChecksumBefore: '1111111111111111111111111111111111111111111111111111111111111111',
|
|
2484
|
-
remoteChecksumAfter: '2222222222222222222222222222222222222222222222222222222222222222',
|
|
2485
|
-
sourceCommitSha: '6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
2486
|
-
githubCommitUrl: 'https://github.com/resolveio/resolveio-all/commit/6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
2487
|
-
restartEvidence: 'nodejs and resolveio_support_ticket_codex_manager restarted on all support hosts',
|
|
2488
|
-
healthCheckStatus: 'passed',
|
|
2489
|
-
selfTestStatus: 'passed'
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
});
|
|
2493
|
-
const supportUnpushedHotfixGate = supportUnpushedHotfixRun.gates.find((gate) => gate.key === 'hotfix_evidence');
|
|
2494
|
-
assert.equal(supportUnpushedHotfixGate?.status, 'fail');
|
|
2495
|
-
assert.match(String(supportUnpushedHotfixGate?.reason || ''), /gitPushStatus|GitHub/i);
|
|
2496
|
-
const supportUnpushedHotfixCommitGate = supportUnpushedHotfixRun.gates.find((gate) => gate.key === 'hotfix_commit_proof');
|
|
2497
|
-
assert.equal(supportUnpushedHotfixCommitGate?.status, 'blocked');
|
|
2498
|
-
assert.equal(supportUnpushedHotfixCommitGate?.metadata?.managerMustCommitBeforeHotfix, true);
|
|
2499
|
-
assert.equal(supportUnpushedHotfixRun.outcome, 'release_blocked');
|
|
2500
|
-
assert.equal(supportUnpushedHotfixRun.events.some((event) => event.type === 'hotfix' && event.metadata?.hotfixSatisfied === false), true);
|
|
2501
|
-
assert.equal(supportUnpushedHotfixRun.events.some((event) => event.category === 'hotfix_commit_proof' && event.metadata?.managerMustCommitBeforeHotfix === true), true);
|
|
2502
|
-
assert.equal(supportUnpushedHotfixRun.metadata?.hotfixDurability?.commitBlocked, true);
|
|
2503
|
-
assert.match(String(supportUnpushedHotfixRun.metadata?.hotfixDurability?.nextAction || ''), /Commit and push/i);
|
|
2504
|
-
|
|
2505
|
-
const supportRepeatedFailureRun = buildSupportAIRunFromEvidence({
|
|
2506
|
-
ticket: { _id: 'ticket-repeated-failure', ticketNumber: '004500', title: 'Repeated support failure' },
|
|
2507
|
-
job: {
|
|
2508
|
-
_id: 'support-job-repeated-failure',
|
|
2509
|
-
status: 'Running',
|
|
2510
|
-
phase: 'Build',
|
|
2511
|
-
supportV5Budget: { maxRepeatedNoProgress: 2 },
|
|
2512
|
-
supportV5AutonomousDecision: {
|
|
2513
|
-
evidenceProbeContract: {
|
|
2514
|
-
contractId: 'support-evidence-probe-repeat',
|
|
2515
|
-
status: 'ready',
|
|
2516
|
-
probeType: 'issue_class_probe',
|
|
2517
|
-
evidenceOnly: true,
|
|
2518
|
-
productRepairAllowed: false,
|
|
2519
|
-
canRunWithoutCodexMonitor: true,
|
|
2520
|
-
issueClass: 'filter_query_mismatch',
|
|
2521
|
-
planId: 'support-probe-plan-repeat',
|
|
2522
|
-
activeRoute: '/support/004500',
|
|
2523
|
-
actionUnderTest: 'Click Save on the failing support workflow.',
|
|
2524
|
-
expectedBusinessProof: 'Save no longer throws TypeError and the persisted record updates.',
|
|
2525
|
-
startingFailureClass: 'product_code',
|
|
2526
|
-
startingBlockerFingerprint: 'save-typeerror',
|
|
2527
|
-
startingEvidenceHash: 'save-typeerror-before',
|
|
2528
|
-
sameFailureCount: 2,
|
|
2529
|
-
requiredNewSignals: ['changed evidenceHash from the starting failure'],
|
|
2530
|
-
requiredArtifacts: ['AIQaBusinessAssertion JSON artifact', 'network trace'],
|
|
2531
|
-
acceptableEvidence: ['AIQaBusinessAssertion with before/action/after DOM/data proof'],
|
|
2532
|
-
forbiddenActions: ['Do not edit product-code or source files during this evidence probe.'],
|
|
2533
|
-
nextCommands: ['execute_active_issue_class_probe_evidence_only']
|
|
2534
|
-
}
|
|
2535
|
-
},
|
|
2536
|
-
supportV5StepHistory: [
|
|
2537
|
-
{
|
|
2538
|
-
lane: 'repair',
|
|
2539
|
-
stepType: 'workflow_build',
|
|
2540
|
-
outcome: 'needs_repair',
|
|
2541
|
-
failureClass: 'product_code',
|
|
2542
|
-
blocker: 'Save action still throws TypeError.',
|
|
2543
|
-
evidenceHash: 'save-typeerror-before',
|
|
2544
|
-
artifactPaths: ['qa/save-before.log']
|
|
2545
|
-
},
|
|
2546
|
-
{
|
|
2547
|
-
lane: 'repair',
|
|
2548
|
-
stepType: 'workflow_build',
|
|
2549
|
-
outcome: 'needs_repair',
|
|
2550
|
-
failureClass: 'product_code',
|
|
2551
|
-
blocker: 'Save action still throws TypeError.',
|
|
2552
|
-
evidenceHash: 'save-typeerror-before',
|
|
2553
|
-
artifactPaths: ['qa/save-before.log']
|
|
2554
|
-
}
|
|
2555
|
-
]
|
|
2556
|
-
},
|
|
2557
|
-
qaEvidence: {
|
|
2558
|
-
compile: { status: 'pass' },
|
|
2559
|
-
routeProbes: [{ route: '/support/004500', status: 'pass' }]
|
|
2560
|
-
}
|
|
2561
|
-
});
|
|
2562
|
-
const repeatedFailureGate = supportRepeatedFailureRun.gates.find((gate) => gate.key === 'manager_no_blind_loop_policy');
|
|
2563
|
-
assert.equal(repeatedFailureGate?.status, 'blocked');
|
|
2564
|
-
assert.equal(repeatedFailureGate?.metadata?.action, 'park_repeated_failure');
|
|
2565
|
-
assert.equal(repeatedFailureGate?.metadata?.requiresNewEvidence, true);
|
|
2566
|
-
assert.equal(repeatedFailureGate?.metadata?.productRepairAllowed, false);
|
|
2567
|
-
assert.equal(supportRepeatedFailureRun.outcome, 'manual_handoff');
|
|
2568
|
-
assert.equal(supportRepeatedFailureRun.events.some((event) => event.category === 'manager_no_blind_loop_policy'), true);
|
|
2569
|
-
assert.equal(supportRepeatedFailureRun.metadata?.managerNoBlindLoopPolicy?.requiresNewEvidence, true);
|
|
2570
|
-
const repeatedEvidenceProbeGate = supportRepeatedFailureRun.gates.find((gate) => gate.key === 'support_evidence_probe_contract');
|
|
2571
|
-
assert.equal(repeatedEvidenceProbeGate?.status, 'pass');
|
|
2572
|
-
assert.equal(repeatedEvidenceProbeGate?.metadata?.evidenceOnly, true);
|
|
2573
|
-
assert.equal(repeatedEvidenceProbeGate?.metadata?.productRepairAllowed, false);
|
|
2574
|
-
assert.equal(repeatedEvidenceProbeGate?.metadata?.canRunWithoutCodexMonitor, true);
|
|
2575
|
-
assert.equal(supportRepeatedFailureRun.events.some((event) => event.category === 'support_evidence_probe_contract'), true);
|
|
2576
|
-
assert.equal(supportRepeatedFailureRun.metadata?.evidenceProbeContract?.contractId, 'support-evidence-probe-repeat');
|
|
2577
|
-
assert.equal(supportRepeatedFailureRun.metadata?.evidenceProbeContract?.probeType, 'issue_class_probe');
|
|
2578
|
-
assert.equal(supportRepeatedFailureRun.metadata?.evidenceProbeContract?.requiredNewSignals.some((signal: string) => /changed evidenceHash/i.test(signal)), true);
|
|
2579
|
-
|
|
2580
|
-
const supportInfraRetryRun = buildSupportAIRunFromEvidence({
|
|
2581
|
-
ticket: { _id: 'ticket-infra-retry', ticketNumber: '004501', title: 'Support infra retry' },
|
|
2582
|
-
job: {
|
|
2583
|
-
_id: 'support-job-infra-retry',
|
|
2584
|
-
status: 'Running',
|
|
2585
|
-
phase: 'QA',
|
|
2586
|
-
supportV5StepHistory: [{
|
|
2587
|
-
lane: 'qa',
|
|
2588
|
-
stepType: 'workflow_qa',
|
|
2589
|
-
outcome: 'needs_repair',
|
|
2590
|
-
failureClass: 'infra',
|
|
2591
|
-
blocker: 'Chrome executable missing.',
|
|
2592
|
-
evidenceHash: 'chrome-missing',
|
|
2593
|
-
artifactPaths: ['qa/chrome-preflight.log']
|
|
2594
|
-
}]
|
|
2595
|
-
},
|
|
2596
|
-
qaEvidence: {
|
|
2597
|
-
infraChecks: [{ name: 'chrome_executable', status: 'blocked', message: 'Chrome executable missing.', path: 'qa/chrome-preflight.log' }]
|
|
2598
|
-
}
|
|
2599
|
-
});
|
|
2600
|
-
const infraRetryGate = supportInfraRetryRun.gates.find((gate) => gate.key === 'manager_no_blind_loop_policy');
|
|
2601
|
-
assert.equal(infraRetryGate?.status, 'warn');
|
|
2602
|
-
assert.equal(infraRetryGate?.metadata?.action, 'retry_infra');
|
|
2603
|
-
assert.equal(infraRetryGate?.metadata?.productRepairFailure, false);
|
|
2604
|
-
assert.equal(infraRetryGate?.metadata?.dispatchAction, 'run_infra_repair');
|
|
2605
|
-
assert.equal(supportInfraRetryRun.outcome, 'qa_infra_failed');
|
|
2606
|
-
|
|
2607
|
-
const supportCompilePreflightGateRun = buildSupportAIRunFromEvidence({
|
|
2608
|
-
ticket: { _id: 'ticket-compile-preflight', ticketNumber: '004502', title: 'Support compile preflight' },
|
|
2609
|
-
job: {
|
|
2610
|
-
_id: 'support-job-compile-preflight',
|
|
2611
|
-
status: 'Running',
|
|
2612
|
-
phase: 'QA',
|
|
2613
|
-
supportV5PreflightGate: {
|
|
2614
|
-
required: true,
|
|
2615
|
-
status: 'compile_failed',
|
|
2616
|
-
failureClass: 'compile',
|
|
2617
|
-
blocksProductRepair: true,
|
|
2618
|
-
blocksModelRepair: true,
|
|
2619
|
-
nextCommand: 'run_support_v5_compile_repair',
|
|
2620
|
-
evidenceHash: 'compile-preflight-hash',
|
|
2621
|
-
compileResult: {
|
|
2622
|
-
status: 'fail',
|
|
2623
|
-
summary: 'Angular compile failed before browser QA.',
|
|
2624
|
-
command: 'npm run build-prod',
|
|
2625
|
-
artifactPath: 'qa-artifacts/preflight/compile.log',
|
|
2626
|
-
failureClass: 'compile'
|
|
2627
|
-
},
|
|
2628
|
-
requiredEvidence: ['compile command output', 'new compile evidence hash or pass']
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
});
|
|
2632
|
-
const supportCompilePreflightGate = supportCompilePreflightGateRun.gates.find((gate) => gate.key === 'support_preflight_gate');
|
|
2633
|
-
assert.equal(supportCompilePreflightGateRun.outcome, 'build_failed');
|
|
2634
|
-
assert.equal(supportCompilePreflightGate?.status, 'fail');
|
|
2635
|
-
assert.equal(supportCompilePreflightGate?.metadata?.failureClass, 'compile');
|
|
2636
|
-
assert.equal(supportCompilePreflightGate?.metadata?.nextCommand, 'run_support_v5_compile_repair');
|
|
2637
|
-
assert.equal(supportCompilePreflightGateRun.gates.some((gate) => gate.key === 'qa_compile' && gate.status === 'fail'), true);
|
|
2638
|
-
assert.equal(supportCompilePreflightGateRun.events.some((event) => event.category === 'support_preflight_gate' && event.type === 'qa_compile'), true);
|
|
2639
|
-
|
|
2640
|
-
const supportStartupPreflightGateRun = buildSupportAIRunFromEvidence({
|
|
2641
|
-
ticket: { _id: 'ticket-startup-preflight', ticketNumber: '004503', title: 'Support startup preflight' },
|
|
2642
|
-
job: {
|
|
2643
|
-
_id: 'support-job-startup-preflight',
|
|
2644
|
-
status: 'Running',
|
|
2645
|
-
phase: 'QA',
|
|
2646
|
-
supportV5PreflightGate: {
|
|
2647
|
-
required: true,
|
|
2648
|
-
status: 'infra_failed',
|
|
2649
|
-
failureClass: 'infra',
|
|
2650
|
-
blocksProductRepair: true,
|
|
2651
|
-
blocksModelRepair: true,
|
|
2652
|
-
nextCommand: 'run_support_v5_infra_repair',
|
|
2653
|
-
evidenceHash: 'startup-preflight-hash',
|
|
2654
|
-
checks: [{
|
|
2655
|
-
name: 'server_startup',
|
|
2656
|
-
status: 'fail',
|
|
2657
|
-
summary: 'Local startup preflight failed before browser QA.',
|
|
2658
|
-
artifactPaths: ['qa-artifacts/runner.log', 'qa-artifacts/server.log'],
|
|
2659
|
-
failureClass: 'infra'
|
|
2660
|
-
}],
|
|
2661
|
-
requiredEvidence: ['startup preflight log', 'new infra evidence hash or pass']
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
});
|
|
2665
|
-
const supportStartupPreflightGate = supportStartupPreflightGateRun.gates.find((gate) => gate.key === 'support_preflight_gate');
|
|
2666
|
-
assert.equal(supportStartupPreflightGateRun.outcome, 'qa_infra_failed');
|
|
2667
|
-
assert.equal(supportStartupPreflightGate?.status, 'fail');
|
|
2668
|
-
assert.equal(supportStartupPreflightGate?.metadata?.failureClass, 'infra');
|
|
2669
|
-
assert.equal(supportStartupPreflightGate?.metadata?.nextCommand, 'run_support_v5_infra_repair');
|
|
2670
|
-
assert.equal(supportStartupPreflightGateRun.gates.some((gate) => gate.key === 'qa_infra' && gate.status === 'blocked'), true);
|
|
2671
|
-
assert.equal(supportStartupPreflightGateRun.events.some((event) => event.category === 'support_preflight_gate' && event.type === 'qa_infra'), true);
|
|
2672
|
-
|
|
2673
|
-
const supportGenericBusinessProofRun = buildSupportAIRunFromEvidence({
|
|
2674
|
-
ticket: { _id: 'ticket-004421', ticketNumber: '004421', title: 'Generic support proof' },
|
|
2675
|
-
job: {
|
|
2676
|
-
_id: 'support-job-generic-proof',
|
|
2677
|
-
status: 'Closed',
|
|
2678
|
-
phase: 'COMPLETE',
|
|
2679
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate
|
|
2680
|
-
},
|
|
2681
|
-
qaEvidence: {
|
|
2682
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
2683
|
-
compile: { status: 'pass' },
|
|
2684
|
-
routeProbes: [{ route: '/support', status: 'pass' }],
|
|
2685
|
-
scorecardPassed: true,
|
|
2686
|
-
businessAssertions: [{
|
|
2687
|
-
assertion: 'The route loads and the ticket page has visible controls.',
|
|
2688
|
-
status: 'pass',
|
|
2689
|
-
route: '/support',
|
|
2690
|
-
action: 'Open the ticket page.',
|
|
2691
|
-
expected: 'Visible controls render.',
|
|
2692
|
-
observed: 'Visible controls rendered.',
|
|
2693
|
-
dataProof: 'Screenshot showed page content.'
|
|
2694
|
-
}]
|
|
2695
|
-
}
|
|
2696
|
-
});
|
|
2697
|
-
assert.equal(supportGenericBusinessProofRun.outcome, 'false_pass');
|
|
2698
|
-
assert.equal(supportGenericBusinessProofRun.gates.some((gate) => gate.key === 'support_diagnosis_business_proof' && gate.status === 'blocked'), true);
|
|
2699
|
-
|
|
2700
|
-
const supportBusinessProofRun = buildSupportAIRunFromEvidence({
|
|
2701
|
-
ticket: { _id: 'ticket-004430', ticketNumber: '004430', title: 'Filtered support ticket list' },
|
|
2702
|
-
job: {
|
|
2703
|
-
_id: 'support-job-2',
|
|
2704
|
-
status: 'Closed',
|
|
2705
|
-
phase: 'COMPLETE',
|
|
2706
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate
|
|
2707
|
-
},
|
|
2708
|
-
qaEvidence: {
|
|
2709
|
-
infraChecks: [{ name: 'puppeteer_require', status: 'pass' }],
|
|
2710
|
-
compile: { status: 'pass' },
|
|
2711
|
-
routeProbes: [{ route: '/support', status: 'pass' }],
|
|
2712
|
-
businessAssertions: [{
|
|
2713
|
-
assertion: 'Wrong-customer ticket is absent after applying the customer filter.',
|
|
2714
|
-
status: 'pass',
|
|
2715
|
-
route: '/support',
|
|
2716
|
-
action: 'Apply customer filter and reload.',
|
|
2717
|
-
expected: 'Only Customer B tickets are visible.',
|
|
2718
|
-
observed: 'Customer A ticket was not rendered.',
|
|
2719
|
-
dataProof: 'DOM and query proof matched the diagnosis proof plan.'
|
|
2720
|
-
}]
|
|
2721
|
-
}
|
|
2722
|
-
});
|
|
2723
|
-
assert.equal(supportBusinessProofRun.outcome, 'accepted');
|
|
2724
|
-
|
|
2725
|
-
const supportJobStoredBusinessProofRun = buildSupportAIRunFromEvidence({
|
|
2726
|
-
ticket: {
|
|
2727
|
-
_id: 'ticket-004431',
|
|
2728
|
-
ticketNumber: '004431',
|
|
2729
|
-
title: 'Stored support business proof',
|
|
2730
|
-
automation: {
|
|
2731
|
-
customer_reply_policy: {
|
|
2732
|
-
last_proof_backed_send_contract: {
|
|
2733
|
-
contract_id: 'support-proof-backed-reply-send-stored-proof',
|
|
2734
|
-
status: 'sent_after_manual_approval',
|
|
2735
|
-
sent_at: '2026-06-06T00:05:00.000Z',
|
|
2736
|
-
job_id: 'support-job-stored-proof',
|
|
2737
|
-
action: 'draft_resolution_reply',
|
|
2738
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4431',
|
|
2739
|
-
readiness_contract_id: 'support-customer-reply-stored-proof',
|
|
2740
|
-
readiness_status: 'draft_ready',
|
|
2741
|
-
proof_backed: true,
|
|
2742
|
-
business_proof_ready: true,
|
|
2743
|
-
release_ready: true,
|
|
2744
|
-
diagnosis_ready: true,
|
|
2745
|
-
issue_class_probe_plan_ready: true,
|
|
2746
|
-
requires_human_approval: true,
|
|
2747
|
-
message_hash: '8f434346648f6b96df89dda901c5176b',
|
|
2748
|
-
recipients: ['customer@example.com'],
|
|
2749
|
-
evidence_refs: ['qa-artifacts/stored-business-proof.json'],
|
|
2750
|
-
required_evidence: ['AIQaBusinessAssertion status=pass', 'PR reference present'],
|
|
2751
|
-
send_guard: {
|
|
2752
|
-
allowed: true,
|
|
2753
|
-
status: 'ready_for_manual_send',
|
|
2754
|
-
direct_send_allowed: false,
|
|
2755
|
-
manual_send_after_review_allowed: true,
|
|
2756
|
-
requires_human_approval: true,
|
|
2757
|
-
proof_backed: true,
|
|
2758
|
-
business_proof_ready: true,
|
|
2759
|
-
release_ready: true,
|
|
2760
|
-
diagnosis_ready: true,
|
|
2761
|
-
issue_class_probe_plan_ready: true,
|
|
2762
|
-
confidence_level: 'high',
|
|
2763
|
-
next_action: 'send_after_human_review',
|
|
2764
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4431'
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
},
|
|
2770
|
-
job: {
|
|
2771
|
-
_id: 'support-job-stored-proof',
|
|
2772
|
-
status: 'Closed',
|
|
2773
|
-
phase: 'COMPLETE',
|
|
2774
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate,
|
|
2775
|
-
supportQaValidationCursor: {
|
|
2776
|
-
route_probe: { route: '/support', status: 'pass', screenshot: 'qa-artifacts/stored-route.png' },
|
|
2777
|
-
business_assertions: [{
|
|
2778
|
-
assertion: 'Wrong-customer ticket is absent after applying the customer filter.',
|
|
2779
|
-
status: 'pass',
|
|
2780
|
-
route: '/support',
|
|
2781
|
-
action: 'Apply customer filter and reload.',
|
|
2782
|
-
expected: 'Only Customer B tickets are visible.',
|
|
2783
|
-
observed: 'Customer A ticket was not rendered.',
|
|
2784
|
-
dataProof: 'DOM and query proof matched the diagnosis proof plan.',
|
|
2785
|
-
artifactPaths: ['qa-artifacts/stored-business-proof.json'],
|
|
2786
|
-
metadata: { supportDiagnosisProof: true }
|
|
2787
|
-
}]
|
|
2788
|
-
},
|
|
2789
|
-
supportV5AutonomousDecision: {
|
|
2790
|
-
business_proof_readiness: {
|
|
2791
|
-
ready: true,
|
|
2792
|
-
status: 'passed',
|
|
2793
|
-
reason: 'Stored support business proof matched the diagnosis.',
|
|
2794
|
-
artifact_paths: ['qa-artifacts/stored-business-proof.json']
|
|
2795
|
-
},
|
|
2796
|
-
customer_reply_policy: {
|
|
2797
|
-
action: 'draft_resolution_reply',
|
|
2798
|
-
canDraftCustomerReply: true,
|
|
2799
|
-
canSendCustomerReply: false,
|
|
2800
|
-
confidenceLevel: 'high',
|
|
2801
|
-
safety: 'safe_to_draft',
|
|
2802
|
-
reason: 'support_reply_resolution_draft_allowed_after_business_proof',
|
|
2803
|
-
humanReviewPacket: {
|
|
2804
|
-
reviewType: 'customer_resolution_reply',
|
|
2805
|
-
primaryAction: 'review_customer_reply',
|
|
2806
|
-
customerFacingDraftAllowed: true,
|
|
2807
|
-
customerSendAllowed: false,
|
|
2808
|
-
requiresHumanApproval: true,
|
|
2809
|
-
evidenceRefs: ['qa-artifacts/stored-business-proof.json']
|
|
2810
|
-
},
|
|
2811
|
-
readinessContract: {
|
|
2812
|
-
contractId: 'support-customer-reply-stored-proof',
|
|
2813
|
-
status: 'draft_ready',
|
|
2814
|
-
policyAction: 'draft_resolution_reply',
|
|
2815
|
-
reviewType: 'customer_resolution_reply',
|
|
2816
|
-
primaryCommand: 'review_customer_reply',
|
|
2817
|
-
canDraftCustomerReply: true,
|
|
2818
|
-
canSendCustomerReply: false,
|
|
2819
|
-
requiresHumanApproval: true,
|
|
2820
|
-
proofBacked: true,
|
|
2821
|
-
businessProofReady: true,
|
|
2822
|
-
releaseReady: true,
|
|
2823
|
-
diagnosisReady: true,
|
|
2824
|
-
issueClassProbePlanReady: true,
|
|
2825
|
-
clarificationRequired: false,
|
|
2826
|
-
reason: 'support_reply_resolution_draft_allowed_after_business_proof',
|
|
2827
|
-
blockers: [],
|
|
2828
|
-
requiredEvidence: ['AIQaBusinessAssertion status=pass'],
|
|
2829
|
-
evidenceRefs: ['qa-artifacts/stored-business-proof.json'],
|
|
2830
|
-
nextCommands: ['review_customer_reply'],
|
|
2831
|
-
forbiddenActions: ['Do not send customer email without explicit human approval.'],
|
|
2832
|
-
createdAt: '2026-06-06T00:00:00.000Z'
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
});
|
|
2838
|
-
assert.equal(supportJobStoredBusinessProofRun.outcome, 'accepted');
|
|
2839
|
-
assert.equal(supportJobStoredBusinessProofRun.qa?.businessAssertions.length, 1);
|
|
2840
|
-
assert.equal(supportJobStoredBusinessProofRun.gates.some((gate) => gate.key === 'support_business_proof_readiness' && gate.status === 'pass'), true);
|
|
2841
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.businessProofReadiness?.ready, true);
|
|
2842
|
-
assert.equal(supportJobStoredBusinessProofRun.gates.some((gate) => gate.key === 'support_customer_reply_policy' && gate.status === 'warn'), true);
|
|
2843
|
-
assert.equal(supportJobStoredBusinessProofRun.gates.some((gate) => gate.key === 'support_customer_reply_readiness' && gate.status === 'warn'), true);
|
|
2844
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplyPolicy?.reviewType, 'customer_resolution_reply');
|
|
2845
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplyPolicy?.canSendCustomerReply, false);
|
|
2846
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplyReadiness?.status, 'draft_ready');
|
|
2847
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplyReadiness?.proofBacked, true);
|
|
2848
|
-
assert.equal(supportJobStoredBusinessProofRun.gates.some((gate) => gate.key === 'support_proof_backed_customer_reply_send' && gate.status === 'pass'), true);
|
|
2849
|
-
assert.equal(supportJobStoredBusinessProofRun.events.some((event) => event.category === 'support_proof_backed_customer_reply_send'), true);
|
|
2850
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplySend?.sentAfterManualApproval, true);
|
|
2851
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplySend?.directSendAllowed, false);
|
|
2852
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplySend?.pullRequestUrl, 'https://github.com/resolveio/resolveio-all/pull/4431');
|
|
2853
|
-
assert.equal(supportJobStoredBusinessProofRun.metadata?.customerReplySend?.messageHash, '8f434346648f6b96df89dda901c5176b');
|
|
2854
|
-
|
|
2855
|
-
const supportBlockedCustomerReplySendRun = buildSupportAIRunFromEvidence({
|
|
2856
|
-
ticket: {
|
|
2857
|
-
_id: 'ticket-004431-blocked-send',
|
|
2858
|
-
ticketNumber: '004431',
|
|
2859
|
-
title: 'Blocked proof-backed send guard',
|
|
2860
|
-
automation: {
|
|
2861
|
-
customer_reply_policy: {
|
|
2862
|
-
last_blocked_send_guard: {
|
|
2863
|
-
allowed: false,
|
|
2864
|
-
status: 'blocked',
|
|
2865
|
-
action: 'draft_resolution_reply',
|
|
2866
|
-
readiness_status: 'draft_ready',
|
|
2867
|
-
confidence_level: 'low',
|
|
2868
|
-
direct_send_allowed: false,
|
|
2869
|
-
requires_human_approval: true,
|
|
2870
|
-
proof_backed: true,
|
|
2871
|
-
business_proof_ready: true,
|
|
2872
|
-
release_ready: true,
|
|
2873
|
-
diagnosis_ready: true,
|
|
2874
|
-
issue_class_probe_plan_ready: true,
|
|
2875
|
-
next_action: 'run_evidence_probe',
|
|
2876
|
-
pull_request_url: 'https://github.com/resolveio/resolveio-all/pull/4431',
|
|
2877
|
-
blockers: ['Proof-backed customer reply requires high confidence; got low.']
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
}
|
|
2881
|
-
},
|
|
2882
|
-
job: {
|
|
2883
|
-
_id: 'support-job-blocked-send',
|
|
2884
|
-
status: 'Review',
|
|
2885
|
-
phase: 'CUSTOMER_REPLY'
|
|
2886
|
-
}
|
|
2887
|
-
});
|
|
2888
|
-
const blockedReplySendGate = supportBlockedCustomerReplySendRun.gates.find((gate) => gate.key === 'support_proof_backed_customer_reply_send');
|
|
2889
|
-
assert.equal(blockedReplySendGate?.status, 'blocked');
|
|
2890
|
-
assert.equal(supportBlockedCustomerReplySendRun.metadata?.customerReplySend?.nextAction, 'run_evidence_probe');
|
|
2891
|
-
assert.equal(supportBlockedCustomerReplySendRun.metadata?.customerReplySend?.confidenceLevel, 'low');
|
|
2892
|
-
assert.ok(supportBlockedCustomerReplySendRun.metadata?.customerReplySend?.blockers?.some((blocker: string) => /high confidence/i.test(blocker)));
|
|
2893
|
-
|
|
2894
|
-
const supportClarificationContractRun = buildSupportAIRunFromEvidence({
|
|
2895
|
-
ticket: { _id: 'ticket-004431', ticketNumber: '004431', title: 'Needs reproduction detail' },
|
|
2896
|
-
job: {
|
|
2897
|
-
_id: 'support-job-clarification-contract',
|
|
2898
|
-
status: 'Blocked',
|
|
2899
|
-
phase: 'REVIEW',
|
|
2900
|
-
customerReplyPolicy: {
|
|
2901
|
-
action: 'ask_clarification',
|
|
2902
|
-
canDraftCustomerReply: true,
|
|
2903
|
-
canSendCustomerReply: false,
|
|
2904
|
-
confidenceLevel: 'low',
|
|
2905
|
-
safety: 'needs_clarification',
|
|
2906
|
-
reason: 'support_reply_waiting_on_customer_reproduction_detail',
|
|
2907
|
-
clarificationQuestion: 'Can you provide the exact invoice number where the export fails?',
|
|
2908
|
-
clarificationContract: {
|
|
2909
|
-
contractId: 'support-clarification-invoice-export',
|
|
2910
|
-
status: 'ready',
|
|
2911
|
-
missingField: 'reproduction_blocker',
|
|
2912
|
-
question: 'Can you provide the exact invoice number where the export fails?',
|
|
2913
|
-
sourceBlockers: ['Need an invoice number to reproduce the PDF/export issue.'],
|
|
2914
|
-
oneQuestionOnly: true,
|
|
2915
|
-
customerFacingDraftAllowed: true,
|
|
2916
|
-
customerSendAllowed: false,
|
|
2917
|
-
parksTicketUntilCustomerReply: true,
|
|
2918
|
-
nextCommands: ['review_customer_clarification', 'send_after_human_review', 'park_ticket_until_customer_reply'],
|
|
2919
|
-
forbiddenActions: ['Do not run product repair from a guessed reproduction path.'],
|
|
2920
|
-
requiredEvidence: ['missing_field=reproduction_blocker', 'one customer-facing question'],
|
|
2921
|
-
createdAt: '2026-06-06T00:00:00.000Z'
|
|
2922
|
-
},
|
|
2923
|
-
humanReviewPacket: {
|
|
2924
|
-
reviewType: 'customer_clarification',
|
|
2925
|
-
primaryAction: 'review_customer_clarification',
|
|
2926
|
-
question: 'Can you provide the exact invoice number where the export fails?',
|
|
2927
|
-
customerFacingDraftAllowed: true,
|
|
2928
|
-
customerSendAllowed: false,
|
|
2929
|
-
requiresHumanApproval: true,
|
|
2930
|
-
blockers: ['Need an invoice number to reproduce the PDF/export issue.']
|
|
2931
|
-
},
|
|
2932
|
-
readinessContract: {
|
|
2933
|
-
contractId: 'support-customer-reply-clarification',
|
|
2934
|
-
status: 'clarification_required',
|
|
2935
|
-
policyAction: 'ask_clarification',
|
|
2936
|
-
reviewType: 'customer_clarification',
|
|
2937
|
-
primaryCommand: 'review_customer_clarification',
|
|
2938
|
-
canDraftCustomerReply: true,
|
|
2939
|
-
canSendCustomerReply: false,
|
|
2940
|
-
requiresHumanApproval: true,
|
|
2941
|
-
proofBacked: false,
|
|
2942
|
-
businessProofReady: false,
|
|
2943
|
-
releaseReady: true,
|
|
2944
|
-
diagnosisReady: false,
|
|
2945
|
-
issueClassProbePlanReady: false,
|
|
2946
|
-
clarificationRequired: true,
|
|
2947
|
-
reason: 'support_reply_waiting_on_customer_reproduction_detail',
|
|
2948
|
-
blockers: ['Need an invoice number to reproduce the PDF/export issue.'],
|
|
2949
|
-
requiredEvidence: ['one customer-facing question'],
|
|
2950
|
-
evidenceRefs: [],
|
|
2951
|
-
nextCommands: ['review_customer_clarification', 'park_ticket_until_customer_reply'],
|
|
2952
|
-
forbiddenActions: ['Do not send customer email without explicit human approval.'],
|
|
2953
|
-
createdAt: '2026-06-06T00:00:00.000Z'
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
});
|
|
2958
|
-
const supportClarificationPolicyGate = supportClarificationContractRun.gates.find((gate) => gate.key === 'support_customer_reply_policy');
|
|
2959
|
-
assert.equal(supportClarificationPolicyGate?.status, 'warn');
|
|
2960
|
-
assert.equal(supportClarificationPolicyGate?.metadata?.clarificationContractStatus, 'ready');
|
|
2961
|
-
assert.equal(supportClarificationPolicyGate?.metadata?.clarificationMissingField, 'reproduction_blocker');
|
|
2962
|
-
assert.equal(supportClarificationPolicyGate?.metadata?.clarificationOneQuestionOnly, true);
|
|
2963
|
-
assert.equal(supportClarificationPolicyGate?.metadata?.clarificationParksTicket, true);
|
|
2964
|
-
const supportClarificationReadinessGate = supportClarificationContractRun.gates.find((gate) => gate.key === 'support_customer_reply_readiness');
|
|
2965
|
-
assert.equal(supportClarificationReadinessGate?.status, 'warn');
|
|
2966
|
-
assert.equal(supportClarificationReadinessGate?.metadata?.status, 'clarification_required');
|
|
2967
|
-
assert.equal(supportClarificationReadinessGate?.metadata?.primaryCommand, 'review_customer_clarification');
|
|
2968
|
-
assert.equal(supportClarificationContractRun.metadata?.customerReplyPolicy?.clarificationContract?.oneQuestionOnly, true);
|
|
2969
|
-
assert.equal(supportClarificationContractRun.metadata?.customerReplyPolicy?.clarificationContract?.parksTicketUntilCustomerReply, true);
|
|
2970
|
-
assert.equal(supportClarificationContractRun.metadata?.customerReplyPolicy?.canSendCustomerReply, false);
|
|
2971
|
-
assert.equal(supportClarificationContractRun.metadata?.customerReplyReadiness?.status, 'clarification_required');
|
|
2972
|
-
|
|
2973
|
-
const supportRouteOnlyReadinessRun = buildSupportAIRunFromEvidence({
|
|
2974
|
-
ticket: { _id: 'ticket-004432', ticketNumber: '004432', title: 'Stored route-only support proof' },
|
|
2975
|
-
job: {
|
|
2976
|
-
_id: 'support-job-route-only-readiness',
|
|
2977
|
-
status: 'Closed',
|
|
2978
|
-
phase: 'COMPLETE',
|
|
2979
|
-
supportV5DiagnosisGate: supportAcceptedDiagnosisGate,
|
|
2980
|
-
supportQaValidationCursor: {
|
|
2981
|
-
workflow_probe: {
|
|
2982
|
-
route: '/support',
|
|
2983
|
-
status: 'pass',
|
|
2984
|
-
screenshot: 'qa-artifacts/route-only.png',
|
|
2985
|
-
message: 'Route loaded but no business assertion ran.'
|
|
2986
|
-
}
|
|
2987
|
-
},
|
|
2988
|
-
supportV5AutonomousDecision: {
|
|
2989
|
-
business_proof_readiness: {
|
|
2990
|
-
ready: false,
|
|
2991
|
-
status: 'route_only',
|
|
2992
|
-
reason: 'Route probe is not business proof.',
|
|
2993
|
-
blockers: ['Run the issue-class business assertion.'],
|
|
2994
|
-
artifact_paths: ['qa-artifacts/route-only.png']
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
});
|
|
2999
|
-
assert.notEqual(supportRouteOnlyReadinessRun.outcome, 'accepted');
|
|
3000
|
-
assert.equal(supportRouteOnlyReadinessRun.gates.some((gate) => gate.key === 'support_business_proof_readiness' && gate.status === 'blocked'), true);
|
|
3001
|
-
assert.equal(supportRouteOnlyReadinessRun.metadata?.businessProofReadiness?.status, 'route_only');
|
|
3002
|
-
|
|
3003
|
-
const aicoderJourneyContract = {
|
|
3004
|
-
app_archetype: 'optimizer',
|
|
3005
|
-
primary_actor: 'Operations planner',
|
|
3006
|
-
primary_goal: 'Create a saved hose pressure recommendation for a field route.',
|
|
3007
|
-
primary_workflow_id: 'layflat-optimizer',
|
|
3008
|
-
first_screen: {
|
|
3009
|
-
route: '/dashboard/hub',
|
|
3010
|
-
purpose: 'Command center showing active scenarios and next optimizer action.',
|
|
3011
|
-
visible_cta: 'Start optimizer scenario',
|
|
3012
|
-
next_step: 'Open assumptions for the seeded route.'
|
|
3013
|
-
},
|
|
3014
|
-
north_star_workflow: [{
|
|
3015
|
-
position: 'first',
|
|
3016
|
-
id: 'start-scenario',
|
|
3017
|
-
route: '/dashboard/hub',
|
|
3018
|
-
visible_cta: 'Start optimizer scenario',
|
|
3019
|
-
data_input_or_selection: 'Select North Field route.',
|
|
3020
|
-
method_or_calculation: 'local calculation path optimizerScenarioDraft',
|
|
3021
|
-
expected_state_transition: 'Scenario assumptions panel opens.',
|
|
3022
|
-
success_confirmation: 'Scenario ready badge appears.',
|
|
3023
|
-
next_step_destination: '/dashboard/hub?scenario=active'
|
|
3024
|
-
}, {
|
|
3025
|
-
position: 'next',
|
|
3026
|
-
id: 'run-optimizer',
|
|
3027
|
-
route: '/dashboard/hub',
|
|
3028
|
-
visible_cta: 'Run optimization',
|
|
3029
|
-
data_input_or_selection: 'Confirm pressure limit, terrain, pump, and hose specs.',
|
|
3030
|
-
method_or_calculation: 'local calculation path runLayflatPressureOptimizer and server method saveOptimizerResult',
|
|
3031
|
-
expected_state_transition: 'Alternatives table and recommendation card update.',
|
|
3032
|
-
success_confirmation: 'Recommendation calculated badge appears.',
|
|
3033
|
-
next_step_destination: '/dashboard/hub?result=compare'
|
|
3034
|
-
}, {
|
|
3035
|
-
position: 'last',
|
|
3036
|
-
id: 'save-report',
|
|
3037
|
-
route: '/reports/optimizer',
|
|
3038
|
-
visible_cta: 'Save recommendation report',
|
|
3039
|
-
data_input_or_selection: 'Choose the recommended hose plan.',
|
|
3040
|
-
method_or_calculation: 'server method publishOptimizerRecommendation',
|
|
3041
|
-
expected_state_transition: 'Saved report row appears.',
|
|
3042
|
-
success_confirmation: 'Recommendation saved message appears.',
|
|
3043
|
-
final_result: 'Saved optimizer recommendation with exportable pressure report.'
|
|
3044
|
-
}],
|
|
3045
|
-
secondary_workflows: [
|
|
3046
|
-
{ id: 'setup', route: '/manage/settings', purpose: 'Maintain pump defaults.' },
|
|
3047
|
-
{ id: 'report-export', route: '/reports/optimizer', purpose: 'Review saved recommendations.' },
|
|
3048
|
-
{ id: 'recovery', route: '/dashboard/hub', purpose: 'Handle invalid pressure states.' }
|
|
3049
|
-
],
|
|
3050
|
-
screen_sequence: [{
|
|
3051
|
-
workflow_step_id: 'start-scenario',
|
|
3052
|
-
route: '/dashboard/hub',
|
|
3053
|
-
screen_purpose: 'Command center with seeded scenario and embedded optimizer action.',
|
|
3054
|
-
visible_cta: 'Start optimizer scenario',
|
|
3055
|
-
action: 'Open scenario assumptions',
|
|
3056
|
-
method_or_calculation: 'local calculation path optimizerScenarioDraft',
|
|
3057
|
-
expected_next_state: 'Scenario assumptions are visible.',
|
|
3058
|
-
data_shown: 'Seeded route, elevation, pump, hose, and pressure-limit records.'
|
|
3059
|
-
}, {
|
|
3060
|
-
workflow_step_id: 'run-optimizer',
|
|
3061
|
-
route: '/dashboard/hub',
|
|
3062
|
-
screen_purpose: 'Run optimizer and compare alternatives.',
|
|
3063
|
-
visible_cta: 'Run optimization',
|
|
3064
|
-
action: 'Calculate pressure recommendation',
|
|
3065
|
-
method_or_calculation: 'local calculation path runLayflatPressureOptimizer',
|
|
3066
|
-
expected_next_state: 'Recommendation and alternatives update.',
|
|
3067
|
-
data_shown: 'Comparison table and recommendation card.'
|
|
3068
|
-
}, {
|
|
3069
|
-
workflow_step_id: 'save-report',
|
|
3070
|
-
route: '/reports/optimizer',
|
|
3071
|
-
screen_purpose: 'Save and export recommendation report.',
|
|
3072
|
-
visible_cta: 'Save recommendation report',
|
|
3073
|
-
action: 'Persist recommendation report',
|
|
3074
|
-
method_or_calculation: 'server method publishOptimizerRecommendation',
|
|
3075
|
-
expected_next_state: 'Saved report row and export button visible.',
|
|
3076
|
-
data_shown: 'Saved recommendation and calculated pressure.'
|
|
3077
|
-
}],
|
|
3078
|
-
data_story: {
|
|
3079
|
-
seeded_scenario: 'North Field irrigation route with elevation changes, pumps, and hose alternatives.',
|
|
3080
|
-
records: ['North Field route', 'Pump A', 'Pump B', '4-inch layflat hose', '6-inch layflat hose'],
|
|
3081
|
-
relationships: ['Route uses pump options', 'Pump options feed hose alternatives', 'Optimization result belongs to scenario'],
|
|
3082
|
-
non_empty_states: ['Dashboard KPIs show pressure and flow.', 'Reports table shows saved recommendation row.']
|
|
3083
|
-
},
|
|
3084
|
-
completion_states: [
|
|
3085
|
-
'Recommendation card shows selected hose and pressure margin.',
|
|
3086
|
-
'Report route lists saved recommendation with export action.'
|
|
3087
|
-
],
|
|
3088
|
-
qa_assertions: [{
|
|
3089
|
-
id: 'login-hub',
|
|
3090
|
-
workflow_step_id: 'start-scenario',
|
|
3091
|
-
route: '/dashboard/hub',
|
|
3092
|
-
coverage_tags: ['login', 'hub_action', 'non_empty_data'],
|
|
3093
|
-
proof_kind: 'login',
|
|
3094
|
-
action: 'Login and land on dashboard hub.',
|
|
3095
|
-
expected_dom_or_data_proof: 'Hub shows seeded North Field scenario and non-empty KPIs.'
|
|
3096
|
-
}, {
|
|
3097
|
-
id: 'primary-hub-action',
|
|
3098
|
-
workflow_step_id: 'start-scenario',
|
|
3099
|
-
route: '/dashboard/hub',
|
|
3100
|
-
coverage_tags: ['hub_action'],
|
|
3101
|
-
proof_kind: 'hub_action',
|
|
3102
|
-
action: 'Click Start optimizer scenario.',
|
|
3103
|
-
expected_dom_or_data_proof: 'Scenario assumptions panel opens with seeded route and pump records.'
|
|
3104
|
-
}, {
|
|
3105
|
-
id: 'workflow-completion',
|
|
3106
|
-
covers_workflow_step_ids: ['run-optimizer', 'save-report'],
|
|
3107
|
-
route: '/dashboard/hub',
|
|
3108
|
-
coverage_tags: ['workflow_completion', 'report_export'],
|
|
3109
|
-
proof_kind: 'report_export',
|
|
3110
|
-
action: 'Run optimization and save recommendation.',
|
|
3111
|
-
expected_dom_or_data_proof: 'Saved recommendation report row appears with calculated pressure result.'
|
|
3112
|
-
}, {
|
|
3113
|
-
id: 'mobile-viewport',
|
|
3114
|
-
covers_workflow_step_ids: ['start-scenario', 'run-optimizer', 'save-report'],
|
|
3115
|
-
route: '/dashboard/hub',
|
|
3116
|
-
coverage_tags: ['mobile', 'workflow_completion'],
|
|
3117
|
-
proof_kind: 'mobile',
|
|
3118
|
-
action: 'Repeat primary optimizer path at mobile viewport 390x844.',
|
|
3119
|
-
expected_dom_or_data_proof: 'Mobile hub shows non-empty scenario and recommendation controls.',
|
|
3120
|
-
viewport: '390x844 mobile'
|
|
3121
|
-
}, {
|
|
3122
|
-
id: 'empty-error-recovery',
|
|
3123
|
-
workflow_step_id: 'start-scenario',
|
|
3124
|
-
route: '/dashboard/hub',
|
|
3125
|
-
coverage_tags: ['recovery'],
|
|
3126
|
-
proof_kind: 'recovery',
|
|
3127
|
-
action: 'Clear scenario input and submit invalid pressure limit.',
|
|
3128
|
-
expected_dom_or_data_proof: 'Empty/error recovery message appears and Start optimizer scenario remains available.'
|
|
3129
|
-
}]
|
|
3130
|
-
};
|
|
3131
|
-
const aicoderWorkflowQaRows = aicoderJourneyContract.qa_assertions.map((row, index) => ({
|
|
3132
|
-
index: index + 1,
|
|
3133
|
-
workflowId: 'layflat-optimizer',
|
|
3134
|
-
stepId: row.id,
|
|
3135
|
-
route: row.route,
|
|
3136
|
-
action: row.action,
|
|
3137
|
-
assertion: row.expected_dom_or_data_proof,
|
|
3138
|
-
expectedState: row.expected_dom_or_data_proof,
|
|
3139
|
-
status: 'pass',
|
|
3140
|
-
artifactPaths: [`qa-artifacts/${row.id}.json`]
|
|
3141
|
-
}));
|
|
3142
|
-
const aicoderWorkflowBusinessAssertions = aicoderWorkflowQaRows.map((row) => ({
|
|
3143
|
-
stepId: row.stepId,
|
|
3144
|
-
workflowId: row.workflowId,
|
|
3145
|
-
route: row.route,
|
|
3146
|
-
action: row.action,
|
|
3147
|
-
assertion: row.assertion,
|
|
3148
|
-
status: 'pass',
|
|
3149
|
-
observed: `${row.stepId} produced the expected visible workflow state.`,
|
|
3150
|
-
dataProof: `${row.stepId} has observed DOM/data proof from seeded Layflat records.`,
|
|
3151
|
-
artifactPaths: row.artifactPaths
|
|
3152
|
-
}));
|
|
3153
|
-
|
|
3154
|
-
const aicoderRun = buildAICoderAIRunFromEvidence({
|
|
3155
|
-
app: { _id: 'layflat-app', name: 'Layflat Pressure Optimizer', domain: 'layflat.resolveio.app' },
|
|
3156
|
-
job: {
|
|
3157
|
-
_id: 'aicoder-job-1',
|
|
3158
|
-
phase: 'COMPLETE',
|
|
3159
|
-
status: 'Passed',
|
|
3160
|
-
managerHotfixEvidence: {
|
|
3161
|
-
channel: 'backend_js',
|
|
3162
|
-
target: {
|
|
3163
|
-
host: 'backend.aicoder.resolveio.com',
|
|
3164
|
-
path: '/var/app/current/http/runner-manager-selftest.js'
|
|
3165
|
-
},
|
|
3166
|
-
compiledArtifactPath: 'dist/http/runner-manager-selftest.js',
|
|
3167
|
-
remoteChecksumAfter: '3333333333333333333333333333333333333333333333333333333333333333',
|
|
3168
|
-
sourceCommitSha: '6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
3169
|
-
githubCommitUrl: 'https://github.com/resolveio/resolveio-all/commit/6fd400e1d8c961c1e88820292c323e688fdcc0a4',
|
|
3170
|
-
gitCommitStatus: 'passed',
|
|
3171
|
-
gitPushStatus: 'passed',
|
|
3172
|
-
restartEvidence: 'nodejs, resolveio_support_ticket_codex_manager, and resolveio_ai_server_watchdog_manager restarted on AICoder hosts',
|
|
3173
|
-
healthCheckStatus: 'passed',
|
|
3174
|
-
selfTestStatus: 'passed'
|
|
3175
|
-
},
|
|
3176
|
-
nextActionContract: {
|
|
3177
|
-
contractId: 'aicoder-next-release-hotfix',
|
|
3178
|
-
action: 'retry_same_step',
|
|
3179
|
-
label: 'Repair Release Gate',
|
|
3180
|
-
primaryCommand: 'repair_aicoder_release_gate',
|
|
3181
|
-
lane: 'publish',
|
|
3182
|
-
stepType: 'test_deploy',
|
|
3183
|
-
safeToAutoRun: true,
|
|
3184
|
-
requiresHumanApproval: false,
|
|
3185
|
-
canRunWithoutCodexMonitor: true,
|
|
3186
|
-
codexFallbackRequired: false,
|
|
3187
|
-
costRisk: 'release_or_customer_send',
|
|
3188
|
-
workflowFirstSatisfied: false,
|
|
3189
|
-
decisionBasis: {
|
|
3190
|
-
releaseBlocked: true,
|
|
3191
|
-
hotfixCommitRequired: true,
|
|
3192
|
-
liveHotfixBlockedUntilCommit: true
|
|
3193
|
-
},
|
|
3194
|
-
requiredHotfixCommitProof: ['sourceCommitSha', 'githubCommitUrl', 'gitCommitStatus=passed', 'gitPushStatus=passed'],
|
|
3195
|
-
preconditions: ['sourceCommitSha, githubCommitUrl, passed gitCommitStatus, and passed gitPushStatus before live hotfix apply'],
|
|
3196
|
-
successEvidence: ['GitHub commit and push proof for any manager-applied hotfix'],
|
|
3197
|
-
stopConditions: ['Do not apply a live AICoder backend/static hotfix until sourceCommitSha, githubCommitUrl, passed gitCommitStatus, and passed gitPushStatus are recorded.'],
|
|
3198
|
-
forbiddenActions: ['applying live hotfix before pushed GitHub commit proof'],
|
|
3199
|
-
nextCommands: ['repair_aicoder_release_gate', 'commit_and_push_hotfix_to_github', 'apply_live_hotfix_only_after_github_commit_proof'],
|
|
3200
|
-
blockers: ['Sample data release gate is blocked.']
|
|
3201
|
-
}
|
|
3202
|
-
},
|
|
3203
|
-
usageLedger: [{
|
|
3204
|
-
model: 'codex-manual',
|
|
3205
|
-
category: 'manual-codex-builder-monitor',
|
|
3206
|
-
usage_source: 'manual_codex',
|
|
3207
|
-
usage_surface: 'aicoder',
|
|
3208
|
-
cost_basis: 'manual_estimate',
|
|
3209
|
-
is_manual: true,
|
|
3210
|
-
is_untracked: true,
|
|
3211
|
-
untracked_reason: 'Sidecar Codex session watched the Layflat builder.',
|
|
3212
|
-
total_tokens: 0,
|
|
3213
|
-
cost_estimate: 42
|
|
3214
|
-
}],
|
|
3215
|
-
qaEvidence: {
|
|
3216
|
-
journeyContract: aicoderJourneyContract,
|
|
3217
|
-
workflowQaRows: aicoderWorkflowQaRows,
|
|
3218
|
-
scorecardPassed: true,
|
|
3219
|
-
deployStatus: 'pass',
|
|
3220
|
-
publishStatus: 'published',
|
|
3221
|
-
sampleDataStatus: 'empty seed collections',
|
|
3222
|
-
compile: { status: 'pass' },
|
|
3223
|
-
routeProbes: [{ route: '/optimizer', status: 'pass' }],
|
|
3224
|
-
businessAssertions: aicoderWorkflowBusinessAssertions
|
|
3225
|
-
}
|
|
3226
|
-
});
|
|
3227
|
-
assert.equal(aicoderRun.source, 'aicoder_app');
|
|
3228
|
-
assert.equal(aicoderRun.outcome, 'release_blocked');
|
|
3229
|
-
assert.equal(aicoderRun.events.some((event) => event.type === 'hotfix' && event.metadata?.hotfixSatisfied === true), true);
|
|
3230
|
-
assert.equal(aicoderRun.gates.some((gate) => gate.key === 'hotfix_commit_proof' && gate.status === 'pass'), true);
|
|
3231
|
-
assert.equal(aicoderRun.gates.some((gate) => gate.key === 'aicoder_workflow_proof_readiness' && gate.status === 'fail'), true);
|
|
3232
|
-
assert.equal(aicoderRun.metadata?.journeyContract?.workflowQaCoverageTags?.includes('workflow_completion'), true);
|
|
3233
|
-
assert.equal(aicoderRun.metadata?.journeyContract?.workflowQaProofKinds?.includes('report_export'), true);
|
|
3234
|
-
assert.equal(aicoderRun.metadata?.workflowProofReadiness?.status, 'release_blocked');
|
|
3235
|
-
assert.equal(aicoderRun.metadata?.hotfixDurability?.commitProofPassed, true);
|
|
3236
|
-
assert.equal(aicoderRun.metadata?.hotfixDurability?.commitFirstProtocolSatisfied, true);
|
|
3237
|
-
assert.equal(aicoderRun.metadata?.hotfixDurability?.liveHotfixAllowed, true);
|
|
3238
|
-
assert.equal(aicoderRun.metadata?.hotfixDurability?.commitBlocked, false);
|
|
3239
|
-
assert.equal(aicoderRun.gates.some((gate) => gate.key === 'cost_observability' && gate.status === 'warn'), true);
|
|
3240
|
-
assert.equal(aicoderRun.metadata?.costObservability?.externalCodexMonitorUsed, true);
|
|
3241
|
-
assert.equal(aicoderRun.metadata?.costObservability?.untrackedEstimatedUsd, 42);
|
|
3242
|
-
assert.equal(aicoderRun.metadata?.nextActionContract?.primaryCommand, 'repair_aicoder_release_gate');
|
|
3243
|
-
assert.equal(aicoderRun.metadata?.nextActionContract?.hotfixCommitRequired, true);
|
|
3244
|
-
assert.equal(aicoderRun.metadata?.nextActionContract?.liveHotfixBlockedUntilCommit, true);
|
|
3245
|
-
assert.deepEqual(aicoderRun.metadata?.nextActionContract?.requiredHotfixCommitProof, ['sourceCommitSha', 'githubCommitUrl', 'gitCommitStatus=passed', 'gitPushStatus=passed']);
|
|
3246
|
-
|
|
3247
|
-
const aicoderRouteOnlyRun = buildAICoderAIRunFromEvidence({
|
|
3248
|
-
app: { _id: 'route-only-app', name: 'Route Only App' },
|
|
3249
|
-
job: {
|
|
3250
|
-
_id: 'aicoder-route-only',
|
|
3251
|
-
phase: 'COMPLETE',
|
|
3252
|
-
status: 'Passed',
|
|
3253
|
-
workflowProofCheckpoint: {
|
|
3254
|
-
required: true,
|
|
3255
|
-
status: 'waiting_for_workflow_proof',
|
|
3256
|
-
readinessStatus: 'workflow_qa_required',
|
|
3257
|
-
nextGate: 'workflow_qa',
|
|
3258
|
-
workflowProofFingerprint: 'aicoder-workflow-proof-route-only',
|
|
3259
|
-
artifactFingerprint: 'aicoder-workflow-artifacts-route-only',
|
|
3260
|
-
requiredEvidence: ['AIQaBusinessAssertion tied to journey_contract.qa_assertions'],
|
|
3261
|
-
requiredResetEvidence: ['new workflow proof fingerprint', 'fresh workflow QA artifact'],
|
|
3262
|
-
successRequiresWorkflowBusinessProof: true,
|
|
3263
|
-
blocksProductRepairUntilJourneyContract: false,
|
|
3264
|
-
blocksPublishUntilWorkflowProof: true,
|
|
3265
|
-
blocksPublishUntilReleaseGate: false,
|
|
3266
|
-
blocksWowUiUntilWorkflowProof: true,
|
|
3267
|
-
nextAction: 'Run workflow QA from the journey contract before publish or wow UI polish.'
|
|
3268
|
-
},
|
|
3269
|
-
nextActionContract: {
|
|
3270
|
-
contractId: 'aicoder-next-route-only',
|
|
3271
|
-
action: 'retry_same_step',
|
|
3272
|
-
label: 'Run Workflow QA',
|
|
3273
|
-
primaryCommand: 'run_aicoder_workflow_qa',
|
|
3274
|
-
lane: 'qa',
|
|
3275
|
-
stepType: 'workflow_qa',
|
|
3276
|
-
safeToAutoRun: true,
|
|
3277
|
-
requiresHumanApproval: false,
|
|
3278
|
-
canRunWithoutCodexMonitor: true,
|
|
3279
|
-
codexFallbackRequired: false,
|
|
3280
|
-
costRisk: 'small_model_or_qa',
|
|
3281
|
-
workflowFirstSatisfied: false,
|
|
3282
|
-
decisionBasis: {
|
|
3283
|
-
journeyContractReady: true,
|
|
3284
|
-
workflowProofReady: false,
|
|
3285
|
-
routeOnlyBlocked: true
|
|
3286
|
-
},
|
|
3287
|
-
preconditions: ['workflow QA rows generated from the journey contract'],
|
|
3288
|
-
expectedStateTransition: 'Route/browser evidence becomes AIQaBusinessAssertion proof for the north-star workflow.',
|
|
3289
|
-
successEvidence: ['AIQaBusinessAssertion tied to journey_contract.qa_assertions'],
|
|
3290
|
-
stopConditions: ['Route-only proof must stay labeled as route evidence, not acceptance.'],
|
|
3291
|
-
forbiddenActions: ['accepting route-only proof as app success'],
|
|
3292
|
-
nextCommands: ['run_aicoder_workflow_qa', 'record_aiqa_business_assertion'],
|
|
3293
|
-
blockers: ['Route-only proof blocks publish.']
|
|
3294
|
-
}
|
|
3295
|
-
},
|
|
3296
|
-
qaEvidence: {
|
|
3297
|
-
journeyContract: aicoderJourneyContract,
|
|
3298
|
-
scorecardPassed: true,
|
|
3299
|
-
compile: { status: 'pass' },
|
|
3300
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }],
|
|
3301
|
-
deployStatus: 'pass',
|
|
3302
|
-
publishStatus: 'published',
|
|
3303
|
-
sampleDataStatus: 'pass'
|
|
3304
|
-
}
|
|
3305
|
-
});
|
|
3306
|
-
assert.equal(aicoderRouteOnlyRun.outcome, 'false_pass');
|
|
3307
|
-
assert.equal(aicoderRouteOnlyRun.gates.some((gate) => gate.key === 'aicoder_workflow_proof_readiness' && gate.status === 'blocked'), true);
|
|
3308
|
-
assert.equal(aicoderRouteOnlyRun.gates.some((gate) => gate.key === 'aicoder_workflow_proof_checkpoint' && gate.status === 'blocked'), true);
|
|
3309
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.workflowProofReadiness?.status, 'route_only');
|
|
3310
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.workflowProofCheckpoint?.blocksPublishUntilWorkflowProof, true);
|
|
3311
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.workflowProofCheckpoint?.blocksWowUiUntilWorkflowProof, true);
|
|
3312
|
-
assert.equal(aicoderRouteOnlyRun.events.some((event) => event.category === 'aicoder_workflow_proof_checkpoint'), true);
|
|
3313
|
-
assert.equal(aicoderRouteOnlyRun.gates.some((gate) => gate.key === 'aicoder_next_action_contract' && gate.status === 'pass'), true);
|
|
3314
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.nextActionContract?.primaryCommand, 'run_aicoder_workflow_qa');
|
|
3315
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.nextActionContract?.canRunWithoutCodexMonitor, true);
|
|
3316
|
-
assert.equal(aicoderRouteOnlyRun.metadata?.nextActionContract?.costRisk, 'small_model_or_qa');
|
|
3317
|
-
assert.equal(aicoderRouteOnlyRun.events.some((event) => event.category === 'aicoder_next_action_contract'), true);
|
|
3318
|
-
|
|
3319
|
-
const aicoderCodexFallbackBlockedRun = buildAICoderAIRunFromEvidence({
|
|
3320
|
-
app: { _id: 'codex-fallback-app', name: 'Codex Fallback Blocked App' },
|
|
3321
|
-
job: {
|
|
3322
|
-
_id: 'aicoder-codex-fallback-blocked',
|
|
3323
|
-
phase: 'QA',
|
|
3324
|
-
status: 'Running',
|
|
3325
|
-
nextActionContract: {
|
|
3326
|
-
contractId: 'aicoder-next-codex-fallback',
|
|
3327
|
-
action: 'retry_same_step',
|
|
3328
|
-
label: 'Run Scoped Repair',
|
|
3329
|
-
primaryCommand: 'run_aicoder_owner_scoped_repair',
|
|
3330
|
-
lane: 'repair',
|
|
3331
|
-
stepType: 'repair',
|
|
3332
|
-
safeToAutoRun: false,
|
|
3333
|
-
requiresHumanApproval: false,
|
|
3334
|
-
canRunWithoutCodexMonitor: false,
|
|
3335
|
-
codexFallbackRequired: true,
|
|
3336
|
-
codexFallbackReason: 'owner_files_or_workflow_proof_missing',
|
|
3337
|
-
costRisk: 'expensive_model',
|
|
3338
|
-
workflowFirstSatisfied: true,
|
|
3339
|
-
blockers: ['Owner-file repair scope is missing.'],
|
|
3340
|
-
stopConditions: ['Do not run repair without owner scope.'],
|
|
3341
|
-
nextCommands: ['collect_aicoder_owner_scope']
|
|
3342
|
-
}
|
|
3343
|
-
},
|
|
3344
|
-
qaEvidence: {
|
|
3345
|
-
journeyContract: aicoderJourneyContract,
|
|
3346
|
-
workflowQaRows: aicoderWorkflowQaRows,
|
|
3347
|
-
scorecardPassed: false,
|
|
3348
|
-
compile: { status: 'pass' },
|
|
3349
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }],
|
|
3350
|
-
deployStatus: 'pass',
|
|
3351
|
-
publishStatus: 'ready',
|
|
3352
|
-
sampleDataStatus: 'pass',
|
|
3353
|
-
businessAssertions: aicoderWorkflowBusinessAssertions
|
|
3354
|
-
}
|
|
3355
|
-
});
|
|
3356
|
-
assert.equal(aicoderCodexFallbackBlockedRun.outcome, 'manual_handoff');
|
|
3357
|
-
assert.equal(aicoderCodexFallbackBlockedRun.gates.some((gate) => gate.key === 'aicoder_next_action_contract' && gate.status === 'blocked'), true);
|
|
3358
|
-
assert.equal(aicoderCodexFallbackBlockedRun.metadata?.nextActionContract?.canRunWithoutCodexMonitor, false);
|
|
3359
|
-
assert.equal(aicoderCodexFallbackBlockedRun.metadata?.nextActionContract?.codexFallbackRequired, true);
|
|
3360
|
-
assert.ok(/validated AICoder next-action contract/i.test(String(aicoderCodexFallbackBlockedRun.nextAction || '')));
|
|
3361
|
-
|
|
3362
|
-
const aicoderMissingJourneyContractRun = buildAICoderAIRunFromEvidence({
|
|
3363
|
-
app: { _id: 'missing-journey-app', name: 'Missing Journey App' },
|
|
3364
|
-
job: {
|
|
3365
|
-
_id: 'aicoder-missing-journey',
|
|
3366
|
-
phase: 'COMPLETE',
|
|
3367
|
-
status: 'Passed'
|
|
3368
|
-
},
|
|
3369
|
-
qaEvidence: {
|
|
3370
|
-
scorecardPassed: true,
|
|
3371
|
-
compile: { status: 'pass' },
|
|
3372
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }],
|
|
3373
|
-
deployStatus: 'pass',
|
|
3374
|
-
publishStatus: 'published',
|
|
3375
|
-
sampleDataStatus: 'pass'
|
|
3376
|
-
}
|
|
3377
|
-
});
|
|
3378
|
-
const aicoderMissingJourneyGate = aicoderMissingJourneyContractRun.gates.find((gate) => gate.key === 'aicoder_journey_contract');
|
|
3379
|
-
assert.equal(aicoderMissingJourneyContractRun.outcome, 'false_pass');
|
|
3380
|
-
assert.equal(aicoderMissingJourneyGate?.status, 'blocked');
|
|
3381
|
-
assert.equal(aicoderMissingJourneyGate?.metadata?.valid, false);
|
|
3382
|
-
assert.equal(aicoderMissingJourneyGate?.metadata?.blocksBuildUntilValid, true);
|
|
3383
|
-
assert.ok(Array.isArray(aicoderMissingJourneyGate?.metadata?.issueCodes));
|
|
3384
|
-
assert.ok((aicoderMissingJourneyGate?.metadata?.issueCodes || []).includes('missing_contract'));
|
|
3385
|
-
assert.equal(aicoderMissingJourneyContractRun.metadata?.journeyContract?.valid, false);
|
|
3386
|
-
assert.equal(aicoderMissingJourneyContractRun.metadata?.workflowProofReadiness?.status, 'missing_journey_contract');
|
|
3387
|
-
assert.equal(classifyAIRunFailureClass(aicoderMissingJourneyContractRun), 'journey_contract');
|
|
3388
|
-
const aicoderMissingJourneyRetry = decideAIRunRetry({ currentRun: aicoderMissingJourneyContractRun });
|
|
3389
|
-
assert.equal(aicoderMissingJourneyRetry.action, 'retry_journey_contract');
|
|
3390
|
-
assert.match(String(aicoderMissingJourneyRetry.nextAction || ''), /APP_JOURNEY_CONTRACT/i);
|
|
3391
|
-
assert.equal(aicoderMissingJourneyContractRun.events.some((event) => event.category === 'aicoder_journey_contract'), true);
|
|
3392
|
-
|
|
3393
|
-
const aicoderRepeatedJourneyRun = buildAICoderAIRunFromEvidence({
|
|
3394
|
-
app: { _id: 'repeated-journey-app', name: 'Repeated Journey App' },
|
|
3395
|
-
job: {
|
|
3396
|
-
_id: 'aicoder-repeated-journey',
|
|
3397
|
-
phase: 'Build',
|
|
3398
|
-
status: 'Running',
|
|
3399
|
-
aicoderV6Budget: { maxRepeatedNoProgress: 2 },
|
|
3400
|
-
aicoderV6StepHistory: [{
|
|
3401
|
-
lane: 'aicoder',
|
|
3402
|
-
stepType: 'journey_validation',
|
|
3403
|
-
outcome: 'needs_repair',
|
|
3404
|
-
failureClass: 'workflow',
|
|
3405
|
-
blocker: 'Journey contract still has no last saved/exported result.',
|
|
3406
|
-
evidenceHash: 'journey-missing-final-result',
|
|
3407
|
-
artifactPaths: ['qa/journey-contract-review.json']
|
|
3408
|
-
}, {
|
|
3409
|
-
lane: 'aicoder',
|
|
3410
|
-
stepType: 'journey_validation',
|
|
3411
|
-
outcome: 'needs_repair',
|
|
3412
|
-
failureClass: 'workflow',
|
|
3413
|
-
blocker: 'Journey contract still has no last saved/exported result.',
|
|
3414
|
-
evidenceHash: 'journey-missing-final-result',
|
|
3415
|
-
artifactPaths: ['qa/journey-contract-review.json']
|
|
3416
|
-
}]
|
|
3417
|
-
},
|
|
3418
|
-
qaEvidence: {
|
|
3419
|
-
journeyContract: aicoderJourneyContract,
|
|
3420
|
-
compile: { status: 'pass' },
|
|
3421
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }]
|
|
3422
|
-
}
|
|
3423
|
-
});
|
|
3424
|
-
const aicoderRepeatedJourneyGate = aicoderRepeatedJourneyRun.gates.find((gate) => gate.key === 'manager_no_blind_loop_policy');
|
|
3425
|
-
assert.equal(aicoderRepeatedJourneyGate?.status, 'blocked');
|
|
3426
|
-
assert.equal(aicoderRepeatedJourneyGate?.metadata?.action, 'park_repeated_failure');
|
|
3427
|
-
assert.equal(aicoderRepeatedJourneyGate?.metadata?.requiresNewEvidence, true);
|
|
3428
|
-
assert.equal(aicoderRepeatedJourneyGate?.metadata?.productRepairAllowed, false);
|
|
3429
|
-
assert.equal(aicoderRepeatedJourneyRun.outcome, 'manual_handoff');
|
|
3430
|
-
assert.equal(aicoderRepeatedJourneyRun.events.some((event) => event.category === 'manager_no_blind_loop_policy'), true);
|
|
3431
|
-
assert.equal(aicoderRepeatedJourneyRun.metadata?.managerNoBlindLoopPolicy?.requiresNewEvidence, true);
|
|
3432
|
-
|
|
3433
|
-
const aicoderInfraRetryRun = buildAICoderAIRunFromEvidence({
|
|
3434
|
-
app: { _id: 'aicoder-infra-retry-app', name: 'AICoder Infra Retry App' },
|
|
3435
|
-
job: {
|
|
3436
|
-
_id: 'aicoder-infra-retry',
|
|
3437
|
-
phase: 'QA',
|
|
3438
|
-
status: 'Running',
|
|
3439
|
-
aicoderV6StepHistory: [{
|
|
3440
|
-
lane: 'qa',
|
|
3441
|
-
stepType: 'workflow_qa',
|
|
3442
|
-
outcome: 'needs_repair',
|
|
3443
|
-
failureClass: 'infra',
|
|
3444
|
-
blocker: 'Puppeteer module is missing before workflow QA can run.',
|
|
3445
|
-
evidenceHash: 'puppeteer-module-missing',
|
|
3446
|
-
artifactPaths: ['qa/puppeteer-preflight.log']
|
|
3447
|
-
}]
|
|
3448
|
-
},
|
|
3449
|
-
qaEvidence: {
|
|
3450
|
-
infraChecks: [{
|
|
3451
|
-
name: 'puppeteer_require',
|
|
3452
|
-
status: 'blocked',
|
|
3453
|
-
message: 'Cannot find module puppeteer.',
|
|
3454
|
-
path: 'qa/puppeteer-preflight.log'
|
|
3455
|
-
}]
|
|
3456
|
-
}
|
|
3457
|
-
});
|
|
3458
|
-
const aicoderInfraRetryGate = aicoderInfraRetryRun.gates.find((gate) => gate.key === 'manager_no_blind_loop_policy');
|
|
3459
|
-
assert.equal(aicoderInfraRetryGate?.status, 'warn');
|
|
3460
|
-
assert.equal(aicoderInfraRetryGate?.metadata?.action, 'retry_infra');
|
|
3461
|
-
assert.equal(aicoderInfraRetryGate?.metadata?.productRepairFailure, false);
|
|
3462
|
-
assert.equal(aicoderInfraRetryGate?.metadata?.dispatchAction, 'run_infra_repair');
|
|
3463
|
-
assert.equal(aicoderInfraRetryRun.outcome, 'qa_infra_failed');
|
|
3464
|
-
|
|
3465
|
-
const aicoderFreshProofRun = buildAICoderAIRunFromEvidence({
|
|
3466
|
-
app: { _id: 'fresh-proof-app', name: 'Fresh Proof App' },
|
|
3467
|
-
job: { _id: 'aicoder-fresh-proof', phase: 'COMPLETE', status: 'Passed' },
|
|
3468
|
-
qaEvidence: {
|
|
3469
|
-
journeyContract: aicoderJourneyContract,
|
|
3470
|
-
workflowQaRows: aicoderWorkflowQaRows,
|
|
3471
|
-
scorecardPassed: true,
|
|
3472
|
-
compile: { status: 'pass' },
|
|
3473
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }],
|
|
3474
|
-
deployStatus: 'pass',
|
|
3475
|
-
publishStatus: 'published',
|
|
3476
|
-
sampleDataStatus: 'pass',
|
|
3477
|
-
businessAssertions: aicoderWorkflowBusinessAssertions
|
|
3478
|
-
}
|
|
3479
|
-
});
|
|
3480
|
-
const freshProofFingerprint = String(aicoderFreshProofRun.metadata?.workflowProofReadiness?.workflowProofFingerprint || '');
|
|
3481
|
-
assert.match(freshProofFingerprint, /^aicoder-workflow-proof-/);
|
|
3482
|
-
|
|
3483
|
-
const aicoderStaleProofRun = buildAICoderAIRunFromEvidence({
|
|
3484
|
-
app: { _id: 'stale-proof-app', name: 'Stale Proof App' },
|
|
3485
|
-
job: { _id: 'aicoder-stale-proof', phase: 'COMPLETE', status: 'Passed' },
|
|
3486
|
-
qaEvidence: {
|
|
3487
|
-
journeyContract: aicoderJourneyContract,
|
|
3488
|
-
workflowQaRows: aicoderWorkflowQaRows,
|
|
3489
|
-
scorecardPassed: true,
|
|
3490
|
-
compile: { status: 'pass' },
|
|
3491
|
-
routeProbes: [{ route: '/dashboard/hub', status: 'pass' }],
|
|
3492
|
-
deployStatus: 'pass',
|
|
3493
|
-
publishStatus: 'published',
|
|
3494
|
-
sampleDataStatus: 'pass',
|
|
3495
|
-
previousWorkflowProofFingerprint: freshProofFingerprint,
|
|
3496
|
-
businessAssertions: aicoderWorkflowBusinessAssertions
|
|
3497
|
-
}
|
|
3498
|
-
});
|
|
3499
|
-
assert.equal(aicoderStaleProofRun.metadata?.workflowProofReadiness?.status, 'stale_workflow_proof');
|
|
3500
|
-
assert.equal(aicoderStaleProofRun.metadata?.workflowProofReadiness?.proofFreshness, 'same_as_previous');
|
|
3501
|
-
assert.equal(aicoderStaleProofRun.gates.some((gate) => gate.key === 'aicoder_workflow_proof_readiness' && gate.status === 'blocked'), true);
|
|
3502
|
-
|
|
3503
|
-
const assistantRun = buildAssistantAIRunFromEvidence({
|
|
3504
|
-
conversation: { _id: 'conversation-1', title: 'Invoice query', status: 'Closed', accepted: true },
|
|
3505
|
-
messages: [{ role: 'assistant', content: 'Used the current date window.' }],
|
|
3506
|
-
answerQuality: {
|
|
3507
|
-
queryStatus: 'ok',
|
|
3508
|
-
requiresCurrentDate: true,
|
|
3509
|
-
currentDateUsed: '2026-06-16',
|
|
3510
|
-
expectedCurrentDate: '2026-06-16',
|
|
3511
|
-
legalQueryShape: true,
|
|
3512
|
-
queryExecutions: [{
|
|
3513
|
-
id: 'tool-result-invoices-june-2026',
|
|
3514
|
-
tool: 'aiAssistantMongoRead',
|
|
3515
|
-
status: 'ok',
|
|
3516
|
-
collection: 'invoices',
|
|
3517
|
-
resultCount: 3
|
|
3518
|
-
}],
|
|
3519
|
-
citations: [{ id: 'tool-result-invoices-june-2026' }],
|
|
3520
|
-
confidence: { level: 'high' },
|
|
3521
|
-
nextActions: ['Review the returned June 2026 invoice rows.']
|
|
3522
|
-
},
|
|
3523
|
-
correctnessChecks: [{
|
|
3524
|
-
assertion: 'Date window uses the actual current month.',
|
|
3525
|
-
status: 'pass',
|
|
3526
|
-
expected: 'June 2026',
|
|
3527
|
-
observed: 'June 2026'
|
|
3528
|
-
}],
|
|
3529
|
-
usageLedger: [{
|
|
3530
|
-
model: 'gpt-5.4-mini',
|
|
3531
|
-
category: 'assistant',
|
|
3532
|
-
usage_source: 'runner',
|
|
3533
|
-
usage_surface: 'assistant',
|
|
3534
|
-
input_tokens: 500,
|
|
3535
|
-
output_tokens: 120,
|
|
3536
|
-
cost_estimate: 0.18
|
|
3537
|
-
}]
|
|
3538
|
-
});
|
|
3539
|
-
assert.equal(assistantRun.source, 'ai_assistant');
|
|
3540
|
-
assert.equal(assistantRun.outcome, 'accepted');
|
|
3541
|
-
assert.equal(assistantRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'pass'), true);
|
|
3542
|
-
assert.equal(assistantRun.gates.some((gate) => gate.key === 'assistant_answer_actionability' && gate.status === 'pass'), true);
|
|
3543
|
-
assert.equal(assistantRun.gates.some((gate) => gate.key === 'cost_observability' && gate.status === 'pass'), true);
|
|
3544
|
-
assert.equal(assistantRun.metadata?.costObservability?.externalCodexMonitorUsed, false);
|
|
3545
|
-
assert.equal(assistantRun.metadata?.costObservability?.estimatedUsd, 0.18);
|
|
3546
|
-
assert.equal(assistantRun.metadata?.answerQuality?.queryStatus, 'ok');
|
|
3547
|
-
assert.equal(assistantRun.metadata?.answerQuality?.queryEvidencePresent, true);
|
|
3548
|
-
assert.equal(assistantRun.metadata?.answerActionability?.primaryCommand, 'answer_from_verified_system_data');
|
|
3549
|
-
assert.equal(assistantRun.metadata?.answerActionability?.canAnswerCustomer, true);
|
|
3550
|
-
assert.equal(assistantRun.metadata?.answerActionability?.canRunWithoutCodexMonitor, true);
|
|
3551
|
-
assert.equal(assistantRun.events.some((event) => event.type === 'assistant_query' && event.metadata?.collection === 'invoices'), true);
|
|
3552
|
-
assert.equal(assistantRun.events.some((event) => event.category === 'assistant_answer_actionability'), true);
|
|
3553
|
-
|
|
3554
|
-
const assistantNoDataRun = buildAssistantAIRunFromEvidence({
|
|
3555
|
-
conversation: { _id: 'conversation-no-data', title: 'No invoice query', status: 'Closed', accepted: true },
|
|
3556
|
-
messages: [{ role: 'assistant', content: 'No invoices were found for June 2026.' }],
|
|
3557
|
-
answerQuality: {
|
|
3558
|
-
queryStatus: 'no_data',
|
|
3559
|
-
noDataConfirmed: true,
|
|
3560
|
-
requiresCurrentDate: true,
|
|
3561
|
-
currentDateUsed: '2026-06-16',
|
|
3562
|
-
expectedCurrentDate: '2026-06-16',
|
|
3563
|
-
legalQueryShape: true,
|
|
3564
|
-
queryExecutions: [{
|
|
3565
|
-
id: 'tool-result-empty-invoices-june-2026',
|
|
3566
|
-
tool: 'aiAssistantMongoRead',
|
|
3567
|
-
status: 'no_data',
|
|
3568
|
-
collection: 'invoices',
|
|
3569
|
-
resultCount: 0
|
|
3570
|
-
}],
|
|
3571
|
-
citationRefs: ['tool-result-empty-invoices-june-2026'],
|
|
3572
|
-
confidenceLevel: 'high',
|
|
3573
|
-
nextActions: ['Verify the date range or customer filter if invoices were expected.']
|
|
3574
|
-
}
|
|
3575
|
-
});
|
|
3576
|
-
assert.equal(assistantNoDataRun.outcome, 'accepted');
|
|
3577
|
-
assert.equal(assistantNoDataRun.metadata?.answerQuality?.queryStatus, 'no_data');
|
|
3578
|
-
assert.equal(assistantNoDataRun.metadata?.answerQuality?.noDataConfirmed, true);
|
|
3579
|
-
assert.equal(assistantNoDataRun.metadata?.answerQuality?.queryEvidencePresent, true);
|
|
3580
|
-
assert.equal(assistantNoDataRun.metadata?.answerActionability?.status, 'ready_to_answer');
|
|
3581
|
-
assert.equal(assistantNoDataRun.metadata?.answerActionability?.queryResultClass, 'no_data');
|
|
3582
|
-
assert.equal(assistantNoDataRun.metadata?.answerActionability?.canAnswerCustomer, true);
|
|
3583
|
-
|
|
3584
|
-
const assistantCitationOnlyRun = buildAssistantAIRunFromEvidence({
|
|
3585
|
-
conversation: { _id: 'conversation-citation-only', title: 'Citation-only answer', status: 'Closed', accepted: true },
|
|
3586
|
-
messages: [{ role: 'assistant', content: 'Found invoices for June 2026.' }],
|
|
3587
|
-
answerQuality: {
|
|
3588
|
-
queryStatus: 'ok',
|
|
3589
|
-
requiresCurrentDate: true,
|
|
3590
|
-
currentDateUsed: '2026-06-16',
|
|
3591
|
-
expectedCurrentDate: '2026-06-16',
|
|
3592
|
-
legalQueryShape: true,
|
|
3593
|
-
citationRefs: ['tool-result-invoices-june-2026'],
|
|
3594
|
-
confidenceLevel: 'high',
|
|
3595
|
-
nextActions: ['Open the invoice list.']
|
|
3596
|
-
}
|
|
3597
|
-
});
|
|
3598
|
-
assert.notEqual(assistantCitationOnlyRun.outcome, 'accepted');
|
|
3599
|
-
assert.equal(assistantCitationOnlyRun.metadata?.answerQuality?.status, 'missing_query_proof');
|
|
3600
|
-
assert.equal(assistantCitationOnlyRun.metadata?.answerQuality?.queryEvidenceRequired, true);
|
|
3601
|
-
assert.equal(assistantCitationOnlyRun.metadata?.answerQuality?.queryEvidencePresent, false);
|
|
3602
|
-
assert.equal(assistantCitationOnlyRun.gates.some((gate) => gate.key === 'assistant_answer_actionability' && gate.status === 'blocked'), true);
|
|
3603
|
-
assert.equal(assistantCitationOnlyRun.metadata?.answerActionability?.status, 'needs_evidence');
|
|
3604
|
-
assert.equal(assistantCitationOnlyRun.metadata?.answerActionability?.primaryCommand, 'collect_assistant_answer_evidence');
|
|
3605
|
-
assert.ok(assistantCitationOnlyRun.metadata?.answerActionability?.forbiddenActions.some((entry: string) => /keyword or route guesses/i.test(entry)));
|
|
3606
|
-
assert.equal(assistantCitationOnlyRun.outcome, 'false_pass');
|
|
3607
|
-
assert.equal(classifyAIRunFailureClass(assistantCitationOnlyRun), 'assistant_missing_evidence');
|
|
3608
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantCitationOnlyRun }).action, 'retry_assistant_answer_quality');
|
|
3609
|
-
|
|
3610
|
-
const assistantWrongDateRun = buildAssistantAIRunFromEvidence({
|
|
3611
|
-
conversation: { _id: 'conversation-wrong-date', title: 'Wrong month query', status: 'Closed', accepted: true },
|
|
3612
|
-
messages: [{ role: 'assistant', content: 'Used May 2026.' }],
|
|
3613
|
-
answerQuality: {
|
|
3614
|
-
queryStatus: 'ok',
|
|
3615
|
-
requiresCurrentDate: true,
|
|
3616
|
-
currentDateUsed: '2026-05-01',
|
|
3617
|
-
expectedCurrentDate: '2026-06-16',
|
|
3618
|
-
legalQueryShape: true,
|
|
3619
|
-
citationRefs: ['tool-result-wrong-month'],
|
|
3620
|
-
confidenceLevel: 'high',
|
|
3621
|
-
nextActions: ['Rerun using the actual current date.']
|
|
3622
|
-
}
|
|
3623
|
-
});
|
|
3624
|
-
assert.notEqual(assistantWrongDateRun.outcome, 'accepted');
|
|
3625
|
-
assert.equal(assistantWrongDateRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'fail'), true);
|
|
3626
|
-
assert.equal(assistantWrongDateRun.metadata?.answerQuality?.status, 'date_incorrect');
|
|
3627
|
-
assert.equal(classifyAIRunFailureClass(assistantWrongDateRun), 'assistant_date_window');
|
|
3628
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantWrongDateRun }).action, 'retry_assistant_date_window');
|
|
3629
|
-
|
|
3630
|
-
const assistantMissingDateWindowRun = buildAssistantAIRunFromEvidence({
|
|
3631
|
-
conversation: { _id: 'conversation-missing-window', title: 'Missing date window', status: 'Closed', accepted: true },
|
|
3632
|
-
messages: [{ role: 'assistant', content: 'Used the current date but did not record the query window.' }],
|
|
3633
|
-
answerQuality: {
|
|
3634
|
-
queryStatus: 'ok',
|
|
3635
|
-
requiresCurrentDate: true,
|
|
3636
|
-
currentDateUsed: '2026-06-16',
|
|
3637
|
-
expectedCurrentDate: '2026-06-16',
|
|
3638
|
-
requiresDateWindow: true,
|
|
3639
|
-
citationRefs: ['tool-result-no-window'],
|
|
3640
|
-
confidenceLevel: 'high',
|
|
3641
|
-
nextActions: ['Rerun with concrete date-window evidence.']
|
|
3642
|
-
}
|
|
3643
|
-
});
|
|
3644
|
-
assert.notEqual(assistantMissingDateWindowRun.outcome, 'accepted');
|
|
3645
|
-
assert.equal(assistantMissingDateWindowRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'fail'), true);
|
|
3646
|
-
assert.equal(assistantMissingDateWindowRun.metadata?.answerQuality?.status, 'missing_date_window');
|
|
3647
|
-
assert.equal(assistantMissingDateWindowRun.metadata?.answerQuality?.dateWindowRequired, true);
|
|
3648
|
-
assert.equal(assistantMissingDateWindowRun.metadata?.answerQuality?.dateWindowPresent, false);
|
|
3649
|
-
assert.equal(classifyAIRunFailureClass(assistantMissingDateWindowRun), 'assistant_date_window');
|
|
3650
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantMissingDateWindowRun }).action, 'retry_assistant_date_window');
|
|
3651
|
-
|
|
3652
|
-
const assistantIllegalProjectionRun = buildAssistantAIRunFromEvidence({
|
|
3653
|
-
conversation: { _id: 'conversation-illegal-query', title: 'Illegal Mongo projection', status: 'Closed', accepted: true },
|
|
3654
|
-
messages: [{ role: 'assistant', content: 'Mongo query failed.' }],
|
|
3655
|
-
answerQuality: {
|
|
3656
|
-
queryStatus: 'ok',
|
|
3657
|
-
requiresCurrentDate: false,
|
|
3658
|
-
mongoQuery: {
|
|
3659
|
-
collection: 'invoices',
|
|
3660
|
-
filter: { customerId: 'customer-1' },
|
|
3661
|
-
projection: { 'lineItems.$.amount': 1 }
|
|
3662
|
-
},
|
|
3663
|
-
citationRefs: ['tool-result-illegal-projection'],
|
|
3664
|
-
confidenceLevel: 'high',
|
|
3665
|
-
nextActions: ['Rewrite the projection using a legal aggregation or full field projection.']
|
|
3666
|
-
}
|
|
3667
|
-
});
|
|
3668
|
-
assert.notEqual(assistantIllegalProjectionRun.outcome, 'accepted');
|
|
3669
|
-
assert.equal(assistantIllegalProjectionRun.metadata?.answerQuality?.status, 'illegal_query_shape');
|
|
3670
|
-
assert.equal(classifyAIRunFailureClass(assistantIllegalProjectionRun), 'assistant_query_shape');
|
|
3671
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantIllegalProjectionRun }).action, 'retry_assistant_query_shape');
|
|
3672
|
-
|
|
3673
|
-
const assistantQueryErrorRun = buildAssistantAIRunFromEvidence({
|
|
3674
|
-
conversation: { _id: 'conversation-query-error', title: 'Query error answer', status: 'Closed', accepted: true },
|
|
3675
|
-
messages: [{ role: 'assistant', content: 'No invoices were found.' }],
|
|
3676
|
-
answerQuality: {
|
|
3677
|
-
queryStatus: 'query_error',
|
|
3678
|
-
requiresCurrentDate: false,
|
|
3679
|
-
legalQueryShape: true,
|
|
3680
|
-
citationRefs: ['tool-result-query-error'],
|
|
3681
|
-
confidenceLevel: 'high',
|
|
3682
|
-
nextActions: ['Fix the query error and retry before answering.']
|
|
3683
|
-
}
|
|
3684
|
-
});
|
|
3685
|
-
assert.notEqual(assistantQueryErrorRun.outcome, 'accepted');
|
|
3686
|
-
assert.equal(assistantQueryErrorRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'blocked'), true);
|
|
3687
|
-
assert.equal(assistantQueryErrorRun.gates.some((gate) => gate.key === 'assistant_answer_actionability' && gate.status === 'blocked'), true);
|
|
3688
|
-
assert.equal(assistantQueryErrorRun.metadata?.answerQuality?.queryStatus, 'query_error');
|
|
3689
|
-
assert.equal(assistantQueryErrorRun.metadata?.answerActionability?.primaryCommand, 'repair_assistant_query_and_rerun');
|
|
3690
|
-
assert.equal(assistantQueryErrorRun.metadata?.answerActionability?.canAnswerCustomer, false);
|
|
3691
|
-
assert.equal(classifyAIRunFailureClass(assistantQueryErrorRun), 'assistant_query_error');
|
|
3692
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantQueryErrorRun }).action, 'retry_assistant_query');
|
|
3693
|
-
|
|
3694
|
-
const assistantPermissionErrorRun = buildAssistantAIRunFromEvidence({
|
|
3695
|
-
conversation: { _id: 'conversation-permission-error', title: 'Permission error answer', status: 'Closed', accepted: true },
|
|
3696
|
-
messages: [{ role: 'assistant', content: 'No invoices were found.' }],
|
|
3697
|
-
answerQuality: {
|
|
3698
|
-
queryStatus: 'permission_error',
|
|
3699
|
-
requiresCurrentDate: false,
|
|
3700
|
-
citationRefs: ['tool-result-permission-error'],
|
|
3701
|
-
confidenceLevel: 'high',
|
|
3702
|
-
nextActions: ['Ask an authorized user to grant invoice access before answering.']
|
|
3703
|
-
}
|
|
3704
|
-
});
|
|
3705
|
-
assert.notEqual(assistantPermissionErrorRun.outcome, 'accepted');
|
|
3706
|
-
assert.equal(assistantPermissionErrorRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'blocked'), true);
|
|
3707
|
-
assert.equal(assistantPermissionErrorRun.metadata?.answerQuality?.queryStatus, 'permission_error');
|
|
3708
|
-
assert.equal(assistantPermissionErrorRun.metadata?.answerActionability?.primaryCommand, 'request_assistant_data_permission');
|
|
3709
|
-
assert.equal(assistantPermissionErrorRun.metadata?.answerActionability?.costRisk, 'manual_blocked');
|
|
3710
|
-
assert.equal(classifyAIRunFailureClass(assistantPermissionErrorRun), 'assistant_permission');
|
|
3711
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantPermissionErrorRun }).action, 'request_assistant_permission');
|
|
3712
|
-
|
|
3713
|
-
const assistantMissingQualityRun = buildAssistantAIRunFromEvidence({
|
|
3714
|
-
conversation: { _id: 'conversation-missing-quality', title: 'Missing assistant answerQuality', status: 'Closed', accepted: true },
|
|
3715
|
-
messages: [{ role: 'assistant', content: 'Invoices look fine.' }]
|
|
3716
|
-
});
|
|
3717
|
-
assert.notEqual(assistantMissingQualityRun.outcome, 'accepted');
|
|
3718
|
-
assert.equal(assistantMissingQualityRun.gates.some((gate) => gate.key === 'assistant_answer_quality' && gate.status === 'blocked'), true);
|
|
3719
|
-
assert.equal(assistantMissingQualityRun.metadata?.answerQuality?.status, 'missing_data_source');
|
|
3720
|
-
assert.equal(classifyAIRunFailureClass(assistantMissingQualityRun), 'assistant_missing_evidence');
|
|
3721
|
-
assert.equal(decideAIRunRetry({ currentRun: assistantMissingQualityRun }).action, 'retry_assistant_answer_quality');
|
|
3722
|
-
|
|
3723
|
-
const assistantAnswerRun = buildAssistantAIRunFromEvidence({
|
|
3724
|
-
runId: 'ai-run:ai_assistant:chat:conversation-1:message-2',
|
|
3725
|
-
requestId: 'request-1',
|
|
3726
|
-
messageId: 'message-2',
|
|
3727
|
-
conversation: { _id: 'conversation-1', title: 'Invoice query', status: 'Closed' },
|
|
3728
|
-
messages: [
|
|
3729
|
-
{ _id: 'message-1', role: 'user', content: 'Show invoices for this month.' },
|
|
3730
|
-
{
|
|
3731
|
-
_id: 'message-2',
|
|
3732
|
-
role: 'assistant',
|
|
3733
|
-
content: 'Found 3 invoices for June 2026.',
|
|
3734
|
-
usage: { model: 'gpt-5.4-mini' }
|
|
3735
|
-
}
|
|
3736
|
-
],
|
|
3737
|
-
answerQuality: {
|
|
3738
|
-
queryStatus: 'ok',
|
|
3739
|
-
requiresCurrentDate: true,
|
|
3740
|
-
currentDateUsed: '2026-06-16',
|
|
3741
|
-
expectedCurrentDate: '2026-06-16',
|
|
3742
|
-
legalQueryShape: true,
|
|
3743
|
-
queryExecutions: [{
|
|
3744
|
-
id: 'tool-result-invoices-june-2026',
|
|
3745
|
-
tool: 'aiAssistantMongoRead',
|
|
3746
|
-
status: 'ok',
|
|
3747
|
-
collection: 'invoices',
|
|
3748
|
-
resultCount: 3
|
|
3749
|
-
}],
|
|
3750
|
-
citationRefs: ['tool-result-invoices-june-2026'],
|
|
3751
|
-
confidenceLevel: 'high',
|
|
3752
|
-
nextActions: ['Open the invoice list filtered to June 2026.']
|
|
3753
|
-
},
|
|
3754
|
-
usageLedger: [{
|
|
3755
|
-
model: 'gpt-5.4-mini',
|
|
3756
|
-
category: 'ai-terminal',
|
|
3757
|
-
usage_source: 'ai_assistant',
|
|
3758
|
-
usage_surface: 'assistant',
|
|
3759
|
-
usage_phase: 'chat',
|
|
3760
|
-
input_tokens: 100,
|
|
3761
|
-
output_tokens: 50,
|
|
3762
|
-
total_tokens: 150,
|
|
3763
|
-
cost_estimate: 0.02
|
|
3764
|
-
}]
|
|
3765
|
-
});
|
|
3766
|
-
assert.equal(assistantAnswerRun.id, 'ai-run:ai_assistant:chat:conversation-1:message-2');
|
|
3767
|
-
assert.equal(assistantAnswerRun.sourceIds.requestId, 'request-1');
|
|
3768
|
-
assert.equal(assistantAnswerRun.sourceIds.messageId, 'message-2');
|
|
3769
|
-
assert.equal(assistantAnswerRun.events.some((event) => event.type === 'assistant_message' && event.metadata?.model === 'gpt-5.4-mini'), true);
|
|
3770
|
-
assert.equal(assistantAnswerRun.events.some((event) => event.type === 'assistant_query' && event.metadata?.id === 'tool-result-invoices-june-2026'), true);
|
|
3771
|
-
assert.equal(assistantAnswerRun.cost?.surfaces?.assistant.estimatedUsd, 0.02);
|
|
3772
|
-
|
|
3773
|
-
console.log('ai run evidence tests passed');
|