export const AUTOMATION_SUITES = Object.freeze([ { id: 'runtime-reproducibility', mode: 'upgrade', // Rebuilds .runtime/portal in place. Keep this suite isolated from all // suites that boot or inspect the shared candidate runtime. exclusive: true, scenarios: ['REL-03'], cases: { 'REL-03': ['two consecutive clean rebuilds produce the same sorted runtime tree SHA256'], }, command: [process.execPath, 'scripts/run-release-gate-artifact-repro.mjs'], }, { id: 'runtime-public-url-policy', mode: 'upgrade', scenarios: ['REL-05'], cases: { 'REL-05': [ 'built public HTML/CSS contains no loopback, private, or unknown TKMind public URL', 'production entry defaults the canonical H5 public base to https://m.tkmind.cn', ], }, command: [process.execPath, 'scripts/run-release-gate-public-url-scan.mjs'], }, { id: 'runtime-production-homolog-cold-start', mode: 'upgrade', scenarios: ['REL-06'], cases: { 'REL-06': [ 'packaged server cold-starts with NODE_ENV=production against unique isolated MySQL/PostgreSQL databases', 'schema initialization creates the service tables, health responds, and a second start is idempotent', ], }, command: [process.execPath, 'scripts/run-release-gate-runtime-cold-start.mjs'], }, { id: 'runtime-sanitized-data-upgrade', mode: 'upgrade', scenarios: ['REL-07'], cases: { 'REL-07': [ 'sanitized legacy MySQL user schema upgrades additively while preserving the row and password/plan defaults', 'sanitized Page Data PostgreSQL fixture remains unchanged across two packaged-runtime starts', ], }, command: [process.execPath, 'scripts/run-release-gate-runtime-upgrade.mjs'], }, { id: 'runtime-linux-dependency-closure', mode: 'upgrade', scenarios: ['REL-11'], cases: { 'REL-11': [ 'Linux ARM64 Node parses the Portal and WeChat bundles and loads the Agent Run worker', 'sandbox, MindSearch, and Excel MCP modules start in a no-network container and answer initialize', ], }, command: [process.execPath, 'scripts/run-release-gate-runtime-container.mjs'], }, { id: 'local-auth-full-stack', mode: 'scenarios', scenarios: [ 'AUTH-01', 'AUTH-02', 'AUTH-03', 'AUTH-04', 'AUTH-05', 'AUTH-06', 'FILE-07', ], cases: { 'AUTH-01': ['local-stack: login returns authenticated user, Cookie, and authenticated status'], 'AUTH-02': ['local-stack: five bad passwords return 401; next login is rate-limited with Retry-After'], 'AUTH-03': ['local-stack: a valid persisted session survives Portal restart; an invented Cookie does not'], 'AUTH-04': ['local-stack: logout revokes the old Cookie for a protected API'], 'AUTH-05': [ 'local-stack: a second user cannot read the first user session, attachment, or private page', 'Page Data tests: owner mismatch, visitor roles, and own-row policies prevent private data crossover', ], 'AUTH-06': ['admin route test: an ordinary user gets 403 for reads and self-role promotion'], 'FILE-07': [ 'local-stack: a second user cannot download the first user completed attachment', 'asset route tests: expired publication access and mismatched signed tokens fail closed', ], }, command: [process.execPath, 'scripts/run-release-gate-auth-scenarios.mjs'], }, { id: 'local-browser-smoke', mode: 'browser', scenarios: ['UI-01', 'UI-02', 'UI-03', 'UI-04', 'UI-05', 'UI-06', 'UI-07', 'UI-08'], cases: { 'UI-01': ['isolated browser: desktop login reaches the authenticated app with chat and history/navigation controls'], 'UI-02': ['isolated browser: 390x844 mobile viewport exposes the stream-capable chat composer'], 'UI-03': ['isolated browser: the real application exposes attachment upload controls'], 'UI-04': ['isolated public-page replay: preview, edit, stable publish URL, and share entry work'], 'UI-05': ['isolated public-page replay: form POST returns 201 and the submitted row is rendered'], 'UI-06': ['isolated browser: login error, loading, disabled, retry/result states are visible'], 'UI-07': ['isolated browser: refresh, back/forward, and app re-entry preserve authentication and navigation state'], 'UI-08': ['isolated browser: zero console/page errors, named controls, and no horizontal mobile overflow'], }, command: [process.execPath, 'scripts/run-release-gate-browser-smoke.mjs'], }, { id: 'chat-finish-merge', mode: 'deterministic', scenarios: ['CHAT-06'], cases: { 'CHAT-06': ['chat-finish-sync.test.mjs: Finish and UpdateConversation merge without message loss'], }, command: [process.execPath, '--test', 'chat-finish-sync.test.mjs'], }, { id: 'memory-ingestion-safety', mode: 'deterministic', scenarios: ['MEM-13', 'MEM-14', 'MEM-15'], cases: { 'MEM-13': [ 'memory shadow matrix rejects routing prompt, Memory Context, skill, tool, system, and assistant text', ], 'MEM-14': [ 'one 1000-clause evidence message produces at most one candidate and the pending pool stays bounded', ], 'MEM-15': [ 'exact and semantic preference repeats deduplicate to one candidate with source ID and evidence hash', ], }, command: [process.execPath, '--test', 'memory-v2-personal-shadow.test.mjs'], }, { id: 'page-public-materialization', mode: 'deterministic', scenarios: ['PAGE-08'], cases: { 'PAGE-08': ['mindspace-public-finish-sync.test.mjs: chained edit_file patches materialize to public HTML'], }, command: [process.execPath, '--test', 'mindspace-public-finish-sync.test.mjs'], }, { id: 'page-content-delivery-scenarios', mode: 'scenarios', scenarios: ['PAGE-01', 'PAGE-02'], cases: { 'PAGE-01': [ 'local scenario: a plain-text Suzhou request creates a new public HTML page, returns a MindSpace link, and responds HTTP 200 with the requested content', ], 'PAGE-02': [ 'local scenario: structured long-form source content becomes a new mobile-readable public page retaining its sections, keywords, shareable link, and HTTP 200 delivery', ], }, command: [process.execPath, 'scripts/run-release-gate-page-scenarios.mjs'], }, { id: 'page-data-access-contract', mode: 'deterministic', scenarios: ['DATA-06', 'DATA-07', 'DATA-09', 'DATA-10'], cases: { 'DATA-06': ['page-data acceptance/public tests: anonymous insert is policy-gated; admin data remains protected'], 'DATA-07': ['page-data route/public tests: CRUD, validation, export, restore, and closed-dataset behavior'], 'DATA-09': [ 'Page Data abuse tests: captcha is required and verified, insert rate limits fail with 429, and one idempotency key produces exactly one row under concurrent replay', ], 'DATA-10': ['page-data acceptance/routes tests: dataset registration, page policy, and workspace binding agree'], }, command: [ process.execPath, '--test', 'page-data-acceptance.test.mjs', 'page-data-browser-client.test.mjs', 'page-data-captcha.test.mjs', 'page-data-public-service.test.mjs', 'page-data-routes.test.mjs', 'page-data-session-store.test.mjs', ], }, { id: 'page-data-product-scenarios', mode: 'scenarios', scenarios: ['DATA-01', 'DATA-02', 'DATA-03', 'DATA-04'], cases: { 'DATA-01': [ 'local scenario: AI usage survey creates a fresh questionnaire and admin page, registers a dataset/policy, and returns both delivery links', ], 'DATA-02': [ 'local scenario: customer ordering creates a writable storefront plus authenticated management/statistics/export page backed by Page Data', ], 'DATA-03': [ 'local scenario: supplier reporting creates validated submission and management pages backed by a registered private dataset', ], 'DATA-04': [ 'local scenario: TKMind feature preference survey delivers questionnaire/admin pages, Page Data policy, dataset, and two public links', ], }, command: [process.execPath, 'scripts/run-release-gate-page-data-scenarios.mjs'], }, { id: 'wechat-native-image-delivery', mode: 'deterministic', scenarios: ['WX-05'], cases: { 'WX-05': ['wechat-media.test.mjs: generated image is converted, origin-checked, and uploaded as native media'], }, command: [process.execPath, '--test', 'wechat-media.test.mjs'], }, { id: 'mindspace-page-sync', mode: 'deterministic', scenarios: ['DATA-11', 'MS-04'], cases: { 'DATA-11': ['mindspace page sync tests: remote Page Data pages sync and storage misses fall back to workspace'], 'MS-04': ['mindspace page sync tests: remote sync, thumbnail generation, and workspace fallback'], }, command: [ process.execPath, '--test', 'mindspace-pages.test.mjs', 'mindspace-page-sync-service.test.mjs', ], }, { id: 'access-policy-modes', mode: 'deterministic', scenarios: ['AUTH-07'], cases: { 'AUTH-07': [ 'portal access policy tests: off, per-group enforce, master enforcement, and kill switch', ], }, command: [ process.execPath, '--test', 'server/portal-access-policy.test.mjs', 'server/portal-api-auth-middleware.test.mjs', ], }, { id: 'security-input-boundaries', mode: 'deterministic', scenarios: ['AUTH-08'], cases: { 'AUTH-08': [ 'asset tests: traversal filenames and script payloads are rejected', 'Page Data tests: SQL-like keys and unauthorized columns are rejected', 'content/CSP tests: unsafe scripts and browser persistence are blocked', 'admin configuration tests: provider secrets are masked', ], }, command: [ process.execPath, '--test', 'mindspace-assets.test.mjs', 'mindspace-content-scan.test.mjs', 'mindspace-published-page-csp.test.mjs', 'page-data-acceptance.test.mjs', 'page-data-integration.test.mjs', 'memory-v2-admin-config.test.mjs', ], }, { id: 'chat-routing-contract', mode: 'deterministic', scenarios: ['CHAT-01', 'CHAT-02', 'CHAT-03'], cases: { 'CHAT-01': ['chat router tests: ordinary greetings select Direct Chat and produce a user-facing reply'], 'CHAT-02': ['chat router tests: page, Page Data, file, and tool intents select Agent execution'], 'CHAT-03': ['chat router tests: realtime/news questions force the web capability instead of Direct Chat'], }, command: [ process.execPath, '--test', 'chat-intent-router.test.mjs', 'direct-chat-service.test.mjs', 'chat-skills.test.mjs', ], }, { id: 'chat-session-continuity', mode: 'deterministic', scenarios: ['CHAT-04', 'CHAT-05'], cases: { 'CHAT-04': ['router and broker tests: continuation/confirmation retain the active Agent session'], 'CHAT-05': ['session broker tests: explicit new sessions and eligible session reuse follow ownership rules'], }, command: [ process.execPath, '--test', 'chat-intent-router.test.mjs', 'session-broker.test.mjs', 'session-reconcile.test.mjs', ], }, { id: 'chat-stream-resume', mode: 'deterministic', scenarios: ['CHAT-07', 'CHAT-08'], cases: { 'CHAT-07': ['session stream tests: Portal cursor replay resumes after disconnect without gaps or duplicates'], 'CHAT-08': ['session stream tests: Portal replay IDs never become Goose Last-Event-ID values'], }, command: [ process.execPath, '--test', 'session-stream.test.mjs', 'session-stream-store.test.mjs', 'agent-run-stream.test.mjs', ], }, { id: 'chat-run-failure-contract', mode: 'deterministic', scenarios: ['CHAT-10', 'CHAT-14'], cases: { 'CHAT-10': ['Agent Run tests: idempotency, retry, cancel, timeout, and poisoned tool history recovery'], 'CHAT-14': ['conversation display/router tests: current user correction wins over hidden routing and skill text'], }, command: [ process.execPath, '--test', 'agent-run-gateway.test.mjs', 'agent-run-routes.test.mjs', 'conversation-display.test.mjs', 'chat-finish-sync.test.mjs', 'message-stream.test.mjs', ], }, { id: 'chat-terminal-recovery-and-persistence', mode: 'deterministic', scenarios: ['CHAT-09', 'CHAT-11', 'CHAT-13', 'CHAT-15'], cases: { 'CHAT-09': [ 'Agent wait tests: unavailable SSE and transient status errors still poll to terminal and restore final messages', ], 'CHAT-11': [ 'active-run gate tests: streaming/loading/connecting/waiting submissions are blocked before request creation', 'Agent Run route tests: active conflicts and stale recovery return bounded user-facing outcomes', ], 'CHAT-13': [ 'Agent Run tests: final snapshot refresh, normalized transcript persistence, and exact row count precede success', ], 'CHAT-15': [ 'canonical transcript tests: single-character visible user text is persisted in order and incomplete snapshots fail closed', ], }, command: [ process.execPath, '--test', 'agent-run-wait.test.mjs', 'chat-agent-run-gate.test.mjs', 'agent-run-gateway.test.mjs', 'agent-run-routes.test.mjs', 'conversation-transcript-persist.test.mjs', ], }, { id: 'legacy-chat-message-contract', mode: 'deterministic', scenarios: ['CHAT-12'], cases: { 'CHAT-12': [ 'goose message tests: missing legacy userVisible/agentVisible and optional metadata are normalized', 'session wait tests: non-UUID request IDs remain scoped through Message and Finish', 'conversation repair tests: damaged/placeholder history restores visible legacy messages', 'Agent/WeChat recovery tests: malformed tool history is repaired without exposing the raw failure', ], }, command: [ process.execPath, '--test', 'goose-message.test.mjs', 'session-reply-wait.test.mjs', 'conversation-repair.test.mjs', 'conversation-transcript-persist.test.mjs', 'wechat-mp.test.mjs', ], }, { id: 'memory-save-recall-lifecycle', mode: 'deterministic', scenarios: [ 'MEM-01', 'MEM-02', 'MEM-03', 'MEM-04', 'MEM-05', 'MEM-06', 'MEM-07', 'MEM-08', 'MEM-09', 'MEM-10', 'MEM-11', 'MEM-12', 'MEM-16', ], cases: { 'MEM-01': ['personal memory tests: explicit remember requests auto-accept and persist evidence-backed memory'], 'MEM-02': ['user memory profile tests: stored memories are injected into a newly built session context'], 'MEM-03': ['pgvector tests: semantic/hybrid retrieval recalls a paraphrased Chinese memory'], 'MEM-04': ['episodic tests: historical conversation topic is resolved with same-user evidence'], 'MEM-05': [ 'conversation memory tests: a replacement preference archives the conflicting old value before recall', 'suppression tests: archived preference text is blocked from legacy and semantic fallback injection', ], 'MEM-06': ['lifecycle tests: user-scoped forget removes only the selected memory'], 'MEM-07': ['episodic tests: ordinary unrelated chat does not trigger episodic retrieval'], 'MEM-08': ['episodic/lifecycle tests: every resolve, list, and forget operation is user scoped'], 'MEM-09': ['personal memory policy tests: sensitive candidates are rejected and deletions are user scoped'], 'MEM-10': ['candidate/lifecycle tests: confirmation, promotion, expiry, and rollout scope are enforced'], 'MEM-11': ['Memory V2 runtime tests: unavailable semantic providers fall back to legacy memory'], 'MEM-12': ['memory context tests: snapshot and router payloads are bounded with evidence/source retained'], 'MEM-16': [ 'deletion suppression tests: durable user tombstones block legacy, candidate, context, episodic index, and snapshot fallback re-ingestion', ], }, command: [ process.execPath, '--test', 'conversation-memory.test.mjs', 'user-memory-profile.test.mjs', 'episodic-memory.test.mjs', 'memory-v2.test.mjs', 'memory-v2-runtime.test.mjs', 'memory-v2-pgvector.test.mjs', 'memory-v2-lifecycle.test.mjs', 'memory-v2-personal-store.test.mjs', 'memory-v2-personal-shadow.test.mjs', 'memory-v2-suppression.test.mjs', ], }, { id: 'file-rejection-and-delivery', mode: 'deterministic', scenarios: ['FILE-06'], cases: { 'FILE-06': ['asset tests: traversal, script payload, MIME, size, and unsupported file rules fail closed'], }, command: [ process.execPath, '--test', 'mindspace-assets.test.mjs', 'mindspace-public-asset-token.test.mjs', 'mindspace-html-download-links.test.mjs', 'mindspace-chat-docx-package.test.mjs', 'wechat-media.test.mjs', ], }, { id: 'file-upload-selection-and-extraction', mode: 'deterministic', scenarios: ['FILE-01', 'FILE-02', 'FILE-03', 'FILE-04', 'FILE-05'], cases: { 'FILE-01': [ 'asset tests: image upload is scanned, normalized, previewed, session-associated, and read by vision in order', ], 'FILE-02': [ 'asset/Excel tests: an XLSX is uploaded, materialized, selected, parsed, and routed to the dedicated analyzer', ], 'FILE-03': [ 'attachment tests: UTF-8 BOM and GB18030 CSV preserve Chinese fields, quoted delimiters, and empty values', ], 'FILE-04': [ 'attachment tests: PDF and DOCX text plus filename/MIME metadata are extracted and previewed', ], 'FILE-05': [ 'attachment tests: current-turn multiple-file order is stable, cancelled selections are excluded, and reused files do not leak prior turn state', ], }, command: [ process.execPath, '--test', 'mindspace-assets.test.mjs', 'mindspace-asset-preview.test.mjs', 'mindspace-asset-agent.test.mjs', 'mindspace-chat-context.test.mjs', 'mindspace-attachment-text.test.mjs', 'tkmind-proxy-attachment.test.mjs', 'tkmind-proxy-vision.test.mjs', 'excel-analyst.test.mjs', ], }, { id: 'excel-analysis-verified-report', mode: 'deterministic', scenarios: ['XLS-01', 'XLS-02', 'XLS-03', 'XLS-04', 'XLS-05', 'XLS-07', 'XLS-10'], cases: { 'XLS-01': ['Excel engine test: a single sheet yields grouped metrics, chart, and accessible HTML report'], 'XLS-02': ['Excel engine test: sales and master-data sheets join to fixture-defined results'], 'XLS-03': ['Excel engine test: formulas, dates, totals, profit, and margin equal fixture answers'], 'XLS-04': ['Excel engine test: merged headers, blank rows, hidden sheets, and incomplete master data are bounded'], 'XLS-05': ['Excel engine test: every report KPI/chart is generated from the source workbook model and validated'], 'XLS-07': [ 'Excel engine test: XLSX succeeds while XLS and CSV fail with the explicit Phase 1 supported-format contract', ], 'XLS-10': [ 'Excel engine test: source workbooks remain private and absolute, traversal, symlink, and cross-user paths fail closed', ], }, command: [process.execPath, '--test', 'excel-analyst.test.mjs'], }, { id: 'page-image-policy-and-repair', mode: 'deterministic', scenarios: ['PAGE-03', 'PAGE-04', 'PAGE-05', 'PAGE-06', 'PAGE-07', 'PAGE-13'], cases: { 'PAGE-03': ['image policy tests: visual page intent independently decides body image generation'], 'PAGE-04': ['image generation tests: required image output is reviewed and stored before success'], 'PAGE-05': ['image policy tests: explicit no-image request disables body image generation'], 'PAGE-06': ['image generation tests: provider/review failure returns explicit failure and stores no stale image'], 'PAGE-07': ['image generation tests: purpose/idempotency keys reuse only the permitted hero/cover asset'], 'PAGE-13': [ 'router test: standalone image intent selects image-generation and explicitly forbids HTML/H5/page creation', 'image service test: a replacement request uses a new current-request idempotency key, job, asset, and bitmap path', ], }, command: [ process.execPath, '--test', 'mindspace-image-generation.test.mjs', 'mindspace-image-review.test.mjs', 'image-make-client.test.mjs', 'image-make-admin-config.test.mjs', 'wechat/image-generation-policy.test.mjs', 'mindspace-h5-html-finish-guard.test.mjs', 'chat-intent-router.test.mjs', ], }, { id: 'page-scope-and-public-link-contract', mode: 'deterministic', scenarios: ['PAGE-09', 'PAGE-10'], cases: { 'PAGE-09': ['public HTML scope tests: a multi-page run updates only paths touched by the current request'], 'PAGE-10': ['canonical/CSP/public link tests: filename conflicts and domain/link normalization remain valid'], }, command: [ process.execPath, '--test', 'mindspace-run-public-html-scope.test.mjs', 'mindspace-canonical-url.test.mjs', 'mindspace-published-page-csp.test.mjs', 'mindspace-public-links.test.mjs', 'mindspace-public-route.test.mjs', ], }, { id: 'page-bounded-delivery-repair', mode: 'deterministic', scenarios: ['PAGE-12'], cases: { 'PAGE-12': [ 'H5 finish guard tests: incomplete public HTML/assets trigger exactly one repair and a second incomplete Finish reaches the limit', 'Agent Run tests: missing current public HTML or Page Data deliverables produce a failed terminal state', ], }, command: [ process.execPath, '--test', 'mindspace-h5-html-finish-guard.test.mjs', 'agent-run-gateway.test.mjs', 'agent-run-deliverable-check.test.mjs', 'server/portal-session-routes.test.mjs', ], }, { id: 'page-data-policy-hardening', mode: 'deterministic', scenarios: ['DATA-08', 'DATA-12'], cases: { 'DATA-08': ['Page Data policy tests: updateRow/deleteRow HTML usage derives matching authenticated permissions'], 'DATA-12': ['Page Data integration tests: cross-user, SQL-like fields, unauthorized columns, and audit logs'], }, command: [ process.execPath, '--test', 'page-data-policy-index.test.mjs', 'page-data-browser-client.test.mjs', 'page-data-integration.test.mjs', 'page-data-ops.test.mjs', ], }, { id: 'search-provider-boundaries', mode: 'deterministic', scenarios: [ 'SEARCH-01', 'SEARCH-02', 'SEARCH-03', 'SEARCH-04', 'SEARCH-05', 'SEARCH-06', 'SEARCH-07', 'SEARCH-08', ], cases: { 'SEARCH-01': [ 'Deep Search research test: the search provider is called across multiple rounds and the completed report retains numbered, canonical, verifiable sources', ], 'SEARCH-02': ['Deep Search tests: SearXNG results are queried, normalized, and bounded'], 'SEARCH-03': ['Deep Search tests: Reader extracts public HTML and rejects private/failed destinations'], 'SEARCH-04': ['MindSearch tests: GitHub search is capability/config gated and token-isolated'], 'SEARCH-05': [ 'Deep Search LLM test: the selected provider/model drives planning and citation-safe synthesis through the authenticated Portal gateway without exposing provider secrets', ], 'SEARCH-06': [ 'Deep Search HTTP test: health remains public, but a mismatched service secret returns explicit 401 UNAUTHORIZED and cannot start research', ], 'SEARCH-07': ['Deep Search tests: provider cancellation and failure handling are bounded'], 'SEARCH-08': ['capability tests: loopback search endpoints are rewritten for container host gateway access'], }, command: [ process.execPath, '--test', 'deep-search.test.mjs', 'mindsearch.test.mjs', 'capabilities.test.mjs', ], }, { id: 'agent-worker-safety', mode: 'deterministic', scenarios: [ 'AGENT-01', 'AGENT-02', 'AGENT-03', 'AGENT-04', 'AGENT-05', 'AGENT-06', 'AGENT-07', 'AGENT-08', 'AGENT-09', ], cases: { 'AGENT-01': ['Agent Run tests: an ordinary run starts a goosed session and reaches succeeded'], 'AGENT-02': ['Agent Run tests: queue concurrency and session affinity are enforced'], 'AGENT-03': [ 'worker identity tests: Portal requirements and claimed worker runtime root/build ID normalize and match', ], 'AGENT-04': ['worker identity tests: required identity mismatch fails closed'], 'AGENT-05': ['Agent Run/Executor tests: request idempotency, retries, and duplicate claims are fenced'], 'AGENT-06': ['worker protocol tests: expired leases and stale runs recover or reach one terminal failure'], 'AGENT-07': ['Agent Run tests: allowlisted Aider users can execute validated code tasks'], 'AGENT-08': ['Agent Run tests: unapproved users and task types are rejected before run creation'], 'AGENT-09': ['tool/executor tests: artifact paths and workspace aliases cannot escape the user workspace'], }, command: [ process.execPath, '--test', 'agent-run-gateway.test.mjs', 'agent-run-routes.test.mjs', 'agent-run-deliverable-check.test.mjs', 'tool-gateway.test.mjs', 'services/orchestrator/executor-worker-protocol.test.mjs', 'services/orchestrator/executor-worker-runtime.test.mjs', 'services/orchestrator/executor-admission-policy.test.mjs', 'services/orchestrator/executor-adapters.test.mjs', ], }, { id: 'agent-extension-compatibility', mode: 'deterministic', scenarios: ['AGENT-10'], cases: { 'AGENT-10': [ 'capability tests: MySQL/PostgreSQL endpoints and bundled MCP module paths resolve for the target runtime', 'PostgreSQL tests: SQLite schema conversion and SET-capable tenant roles are reconciled before access', 'extension fallback test: private-data configuration failure disables only Page Data tools while non-data sandbox tools remain available', ], }, command: [ process.execPath, '--test', 'capabilities.test.mjs', 'mindspace-userdata-postgres.test.mjs', 'postgres-user-data-space-service.test.mjs', 'mindspace-sandbox-mcp.test.mjs', ], }, { id: 'agent-exactly-once-terminal-recovery', mode: 'deterministic', scenarios: ['AGENT-11'], cases: { 'AGENT-11': [ 'Agent Run tests: timeout and retry exhaustion each append exactly one terminal event', 'stale heartbeat/worker recovery is fenced and a second recovery cannot create another terminal result', 'deliverable-based recovery preserves one user-visible artifact and synchronizes it once', ], }, command: [ process.execPath, '--test', 'agent-run-gateway.test.mjs', 'agent-run-deliverable-check.test.mjs', 'services/orchestrator/executor-worker-protocol.test.mjs', ], }, { id: 'schedule-time-and-delivery', mode: 'deterministic', scenarios: ['SCHED-01', 'SCHED-02', 'SCHED-03', 'SCHED-04', 'SCHED-05'], cases: { 'SCHED-01': ['schedule service tests: wall-clock input resolves in the configured user timezone'], 'SCHED-02': ['schedule intent tests: missing or ambiguous times require clarification'], 'SCHED-03': ['schedule service tests: cancel and bulk delete update only the user reminder'], 'SCHED-04': [ 'worker tests: a failed delivery retries, reaches one success, and cannot send again after sent state', ], 'SCHED-05': [ 'worker restart test: shared persisted pending state survives process replacement and sends once', ], }, command: [ process.execPath, '--test', 'schedule-intent.test.mjs', 'schedule-service.test.mjs', 'schedule-reminder-worker.test.mjs', ], }, { id: 'wechat-channel-contract', mode: 'deterministic', scenarios: [ 'WX-01', 'WX-02', 'WX-03', 'WX-04', 'WX-06', 'WX-07', 'WX-08', 'FILE-08', ], cases: { 'WX-01': ['WeChat MP tests: plaintext/AES signatures and connectivity challenge validate'], 'WX-02': ['WeChat MP tests: duplicate message IDs are ignored'], 'WX-03': ['WeChat MP tests: openid binding and dedicated user session isolation are preserved'], 'WX-04': ['WeChat MP tests: page output resolves to the canonical public link'], 'WX-06': ['WeChat MP tests: current-run thumbnail is required and one unambiguous missing asset is repaired'], 'WX-07': ['WeChat OAuth tests: callback configuration, state, and return URL reject external redirects'], 'WX-08': ['WeChat Pay tests: sandbox callback signature and message/channel boundaries validate'], 'FILE-08': [ 'DOCX package tests: generated bytes are persisted, registered in the manifest, and exposed only through the canonical artifact download URL', 'download-link and asset-route tests: page buttons resolve to an existing sibling or asset API; authenticated, signed-public, expired, and denied access paths are enforced', 'WeChat tests: Word/Excel media is persisted into the user public area with H5 attachment metadata, and Word page tasks require the real DOCX artifact before HTML delivery', ], }, command: [ process.execPath, '--test', 'wechat-mp.test.mjs', 'wechat-oauth.test.mjs', 'wechat-pay.test.mjs', 'wechat-media.test.mjs', 'wechat/wechat-channel.test.mjs', 'wechat/image-generation-policy.test.mjs', 'mindspace-chat-docx-package.test.mjs', 'mindspace-html-download-links.test.mjs', 'mindspace-public-asset-token.test.mjs', 'server/portal-mindspace-asset-routes.test.mjs', ], }, { id: 'wechat-terminal-and-atomic-delivery', mode: 'deterministic', scenarios: ['WX-09', 'WX-10', 'WX-11', 'WX-12', 'WX-13'], cases: { 'WX-09': [ 'WeChat ledger tests: duplicates stay fenced, stale processing is reclaimed, and accepted work reaches done or failed', ], 'WX-10': [ 'image turn tests: historical image_url content is scrubbed before text follow-up and an unsupported update rotates the session', ], 'WX-11': [ 'WeChat delivery tests: 45047/45015 persist one deferred result and claim it once on the next passive response', ], 'WX-12': [ 'voice tests: AMR media reaches ASR and conversion/recognition failures return an explicit retry message without Agent execution', ], 'WX-13': [ 'page delivery tests: real HTML, fresh current-run raster cover, description, platform brand, and verified public URL are required before send', ], }, command: [ process.execPath, '--test', 'user-auth.test.mjs', 'wechat-mp.test.mjs', 'wechat-media.test.mjs', 'wechat/wechat-channel.test.mjs', 'chat-image-turn-scope.test.mjs', 'tkmind-proxy.test.mjs', ], }, { id: 'billing-plan-and-idempotency', mode: 'deterministic', scenarios: ['BILL-01', 'BILL-04', 'BILL-05'], cases: { 'BILL-01': ['subscription tests: free, paid, unlimited, and administrator entitlements are calculated'], 'BILL-04': ['billing concurrency tests: Finish/SSE replay with the same request is charged once'], 'BILL-05': ['billing concurrency tests: concurrent Finish settlement atomically deducts one charge'], }, command: [ process.execPath, '--test', 'billing.test.mjs', 'billing-token-state.test.mjs', 'billing-subscription.test.mjs', 'billing-session-concurrency.test.mjs', ], }, { id: 'billing-execution-terminal-contract', mode: 'deterministic', scenarios: ['BILL-02', 'BILL-03'], cases: { 'BILL-02': [ 'Direct Chat and Agent Finish tests: each successful execution enters settlement once with the stable request ID', 'billing state tests: repeated and concurrent settlement attempts charge once', ], 'BILL-03': [ 'Direct/Agent tests: provider failure, cancellation, and a truly hanging SSE timeout never enter billing', ], }, command: [ process.execPath, '--test', 'direct-chat-service.test.mjs', 'tkmind-proxy.test.mjs', 'session-reply-wait.test.mjs', 'billing-session-concurrency.test.mjs', ], }, { id: 'billing-recharge-and-admission-contract', mode: 'deterministic', scenarios: ['BILL-06', 'BILL-07'], cases: { 'BILL-06': [ 'recharge service tests: forged WeChat callback signatures fail before credit, and a signed callback plus replay credits exactly once', ], 'BILL-07': [ 'Portal Agent route test: an insufficient-balance response returns 402 before the run handler and leaves no residual task', ], }, command: [ process.execPath, '--test', 'billing-recharge.test.mjs', 'wechat-pay.test.mjs', 'server/portal-webhook-routes.test.mjs', 'server/portal-agent-runtime-routes.test.mjs', ], }, { id: 'mindspace-delivery-contract', mode: 'deterministic', scenarios: ['MS-01', 'MS-02', 'MS-03', 'MS-05', 'MS-06', 'MS-07', 'MS-08'], cases: { 'MS-01': ['MindSpace service tests: health and versioned contract endpoints respond with the contract'], 'MS-02': ['MindSpace adapter tests: local and remote adapters satisfy the same server contract'], 'MS-03': ['public delivery tests: canonical, OG, sharing, and access behavior are stable'], 'MS-05': ['conversation package tests: create, verify, registry, and historical backfill are consistent'], 'MS-06': ['publication/download tests: DOCX and long-image companions exist and use non-local canonical links'], 'MS-07': ['content/CSP tests: scan and localization reject dangerous scripts while retaining safe pages'], 'MS-08': ['cleanup/purge tests: page and conversation deletion removes linked resources without orphans'], }, command: [ process.execPath, '--test', 'mindspace-service/mindspace-rpc-server.test.mjs', 'mindspace-local-server-adapter.test.mjs', 'mindspace-remote-server-adapter.test.mjs', 'mindspace-server-adapter.test.mjs', 'mindspace-public-delivery.test.mjs', 'mindspace-publications.test.mjs', 'mindspace-conversation-package.test.mjs', 'mindspace-conversation-package-backfill.test.mjs', 'mindspace-conversation-package-verify.test.mjs', 'mindspace-html-download-links.test.mjs', 'mindspace-content-scan.test.mjs', 'mindspace-published-page-csp.test.mjs', 'mindspace-cleanup.test.mjs', 'mindspace-page-purge.test.mjs', ], }, { id: 'plaza-publication-contract', mode: 'deterministic', scenarios: ['PLAZA-01', 'PLAZA-02', 'PLAZA-03', 'PLAZA-04', 'PLAZA-05'], cases: { 'PLAZA-01': ['Plaza integration tests: publish, moderate, and feed visibility preserve page content/link'], 'PLAZA-02': ['Plaza post/SEO tests: discovery, search metadata, cover, and public URL normalize'], 'PLAZA-03': ['Plaza interaction tests: reaction types and moderation/role permissions are enforced'], 'PLAZA-04': ['Plaza algorithm tests: fixed fixtures yield stable hot score, MMR, cursor, and cold start order'], 'PLAZA-05': [ 'Plaza public/feed/recommendation tests: hidden posts and offline, private, or deleted source pages are inaccessible and invalidate stale feed caches', ], }, command: [ process.execPath, '--test', 'plaza-integration.test.mjs', 'plaza-posts.test.mjs', 'plaza-interactions.test.mjs', 'plaza-ops.test.mjs', 'plaza-seo.test.mjs', 'plaza-algorithm.test.mjs', 'plaza-recommend.test.mjs', 'plaza-public.test.mjs', ], }, { id: 'configuration-observability-contract', mode: 'deterministic', scenarios: ['CFG-01', 'CFG-02', 'CFG-03', 'CFG-04', 'CFG-05', 'CFG-06', 'CFG-07'], cases: { 'CFG-01': ['Orchestrator config/bootstrap tests: disabled mode is not a Portal startup/request dependency'], 'CFG-02': ['shadow dispatcher/observer tests: Shadow failures never change the Native user result'], 'CFG-03': ['Orchestrator/access policy tests: emergency kill switches stop controlled execution immediately'], 'CFG-04': ['analytics tests: disabled mode emits nothing; enabled events use bounded pseudonymous context'], 'CFG-05': ['system disclosure tests: shadow records only, enforce refuses before execution'], 'CFG-06': ['configuration migration tests: env-to-database setup is versioned and idempotent'], 'CFG-07': ['observability tests: logs, metrics, and audit are traceable and exclude raw identity/secrets'], }, command: [ process.execPath, '--test', 'services/orchestrator/admin-config.test.mjs', 'services/orchestrator/shadow-dispatcher.test.mjs', 'services/orchestrator/shadow-observer.test.mjs', 'services/orchestrator/observability.test.mjs', 'mindspace-analytics.test.mjs', 'mindspace-rybbit.test.mjs', 'system-disclosure-policy.test.mjs', ], }, { id: 'provider-model-catalog-compatibility', mode: 'deterministic', scenarios: ['CFG-08'], cases: { 'CFG-08': [ 'Provider tests: every model stored in an active custom database profile is accepted', 'Provider tests: a builtin legacy model removed from the current catalog is rejected before selection or sync', ], }, command: [process.execPath, '--test', 'llm-providers.test.mjs'], }, { id: 'release-goosed-runtime-identity', mode: 'upgrade', scenarios: ['REL-08'], cases: { 'REL-08': [ 'release contract: exactly nine goosed containers are recreated after live swap, then ports, health, MCP paths, runtime identity, Portal, worker, and tunnel are checked', ], }, command: [process.execPath, 'scripts/check-release-runtime-safety.mjs', 'REL-08'], }, { id: 'release-rollback-restoration', mode: 'upgrade', scenarios: ['REL-09'], cases: { 'REL-09': [ 'release contract: post-swap failure must archive the failed new live, restore old live, and restart the previous Portal', ], }, command: [process.execPath, 'scripts/check-release-runtime-safety.mjs', 'REL-09'], }, { id: 'release-drain-backup-and-pre-swap-safety', mode: 'upgrade', scenarios: ['REL-10'], cases: { 'REL-10': [ 'release contract: block new Agent runs, drain active work within a bound, checksum and back up, then recheck zero active runs immediately before swap', 'canary contract: immutable user and WeChat identities route to an isolated candidate, while missing identity, resolver errors, and candidate failure fall back to stable', ], }, command: [ process.execPath, '--test', 'release-gate/canary-routing.test.mjs', 'memind-canary-proxy.test.mjs', 'release-gate/release-runtime-safety.test.mjs', ], }, { id: 'image-to-page-recorded-replay', mode: 'deterministic', scenarios: [ 'IMGPG-01', 'IMGPG-02', 'IMGPG-03', 'IMGPG-04', 'IMGPG-05', 'IMGPG-06', 'IMGPG-07', 'IMGPG-08', 'PAGE-11', ], cases: { 'IMGPG-01': ['recorded vision/tool replay materializes a responsive single-image-capable HTML page'], 'IMGPG-02': ['recorded Qwen vision/OCR result is retained in the structurally valid page artifact'], 'IMGPG-03': ['two current-turn image inputs and generated figure references preserve user order'], 'IMGPG-04': ['recorded image facts plus text requirements jointly determine copy, color, and responsive layout'], 'IMGPG-05': ['artifact uses relative uploaded image paths and rejects host filesystem, loopback, and temporary URLs'], 'IMGPG-06': ['delivery injects OG/share metadata with the public image and stable canonical page URL'], 'IMGPG-07': ['edit_file replay changes copy in place while preserving page path and original image references'], 'IMGPG-08': ['403/unreadable image cannot call vision, bill usage, or invent recognition text'], 'PAGE-11': ['daily page fixture requires news, weather, market, knowledge, authoritative HTTPS citations, compliance notice, viewport, and HTML artifact'], }, command: [ process.execPath, '--test', 'release-gate/image-page-replay.test.mjs', 'mindspace-thumbnails.test.mjs', 'mindspace-og-tags.test.mjs', ], }, { id: 'excel-continuity-and-fallback', mode: 'deterministic', scenarios: ['XLS-06', 'XLS-08', 'XLS-09', 'XLS-11', 'XLS-12'], cases: { 'XLS-06': ['file, scan-cell, sample-row, and memory-facing ZIP budgets reject oversized input before unbounded work'], 'XLS-08': ['a follow-up changes group dimension while reusing the exact same uploaded workbook path'], 'XLS-09': ['report names the source workbook and renders a validated asset download URL'], 'XLS-11': ['an approximately 5MB multi-sheet input crosses a bounded tool budget; fallback contains only preverified totals and a real artifact'], 'XLS-12': ['updated workbook regenerates the same dashboard path while retaining old rows, confirmed title, and dimensions'], }, command: [process.execPath, '--test', 'release-gate/excel-continuity.test.mjs'], }, { id: 'page-data-schema-evolution', mode: 'deterministic', scenarios: ['DATA-05', 'DATA-13'], cases: { 'DATA-05': ['children survey adds diet additively; historical hobby row remains and new diet row is writable'], 'DATA-13': [ 'incomplete/readonly dataset fails closed, then additive fields and actions rebind without losing the historical row or duplicating created_at', 'legacy API and browser storage are rejected; soft-delete policy is derived only after matching schema registration', ], }, command: [ process.execPath, '--test', 'release-gate/page-data-evolution.test.mjs', 'mindspace-page-data-finish-guard.test.mjs', 'page-data-workspace-bind.test.mjs', 'mindspace-pages.test.mjs', ], }, { id: 'offline-document-native-delivery', mode: 'deterministic', scenarios: ['MS-09'], cases: { 'MS-09': [ 'stdlib DOCX generator has no network/font dependency, produces a real ZIP/DOCX, is synced beside HTML, and uses verified direct/native download paths', ], }, command: [ process.execPath, '--test', 'release-gate/document-offline.test.mjs', 'mindspace-sandbox-mcp.test.mjs', 'mindspace-public-finish-sync.test.mjs', 'mindspace-html-download-links.test.mjs', ], }, { id: 'legacy-data-compatibility', mode: 'deterministic', scenarios: ['COMP-01', 'COMP-02', 'COMP-03', 'COMP-04'], cases: { 'COMP-01': ['legacy/non-UUID messages and prior direct-session transcript survive normalization and continue in a Goose session'], 'COMP-02': ['legacy public routes, browser-storage pages, missing storage objects, and existing page identity remain readable after sync'], 'COMP-03': ['existing Page Data rows, registry, policy, public form, export, soft delete, and restore remain usable'], 'COMP-04': ['legacy memory remains recallable through Memory V2 and safely falls back when semantic storage is unavailable'], }, command: [ process.execPath, '--test', 'conversation-transcript-persist.test.mjs', 'goose-message.test.mjs', 'mindspace-public-route.test.mjs', 'mindspace-pages.test.mjs', 'mindspace-page-sync.test.mjs', 'page-data-integration.test.mjs', 'memory-v2.test.mjs', 'episodic-memory.test.mjs', ], }, { id: 'fault-isolation-and-concurrency', mode: 'deterministic', scenarios: ['COMP-05', 'COMP-06', 'COMP-07', 'COMP-08'], cases: { 'COMP-05': ['worker protocol fences one failed/expired worker lease and recovers the run exactly once'], 'COMP-06': ['temporary status/database failures retry or recover to one consistent terminal state'], 'COMP-07': ['image, search, and semantic-memory provider failures are bounded and do not break core direct chat'], 'COMP-08': ['concurrent billing, session allocation, file parsing, and page generation tests enforce bounded completion and no duplicate terminal/resource state'], }, command: [ process.execPath, '--test', 'services/orchestrator/executor-worker-protocol.test.mjs', 'agent-run-wait.test.mjs', 'agent-run-gateway.test.mjs', 'direct-chat-service.test.mjs', 'mindspace-image-generation.test.mjs', 'deep-search.test.mjs', 'memory-v2-runtime.test.mjs', 'billing-session-concurrency.test.mjs', 'session-broker.test.mjs', ], }, { id: 'sanitized-production-regression-replay', mode: 'upgrade', scenarios: ['COMP-09'], cases: { 'COMP-09': [ 'every active privacy-reviewed production regression fixture executes in the isolated runner; production addresses/credentials are refused in code', ], }, command: [process.execPath, 'scripts/run-release-gate-regression-corpus.mjs'], }, ]); export function validateAutomationSuites(catalog) { const catalogIds = new Set(catalog.map((scenario) => scenario.id)); const seen = new Set(); for (const suite of AUTOMATION_SUITES) { if ( !suite.id || !suite.mode || !Array.isArray(suite.command) || suite.command.length < 2 || !suite.cases || typeof suite.cases !== 'object' ) { throw new Error(`Invalid automation suite: ${suite.id ?? ''}`); } for (const scenarioId of suite.scenarios) { if (!catalogIds.has(scenarioId)) { throw new Error(`Automation suite ${suite.id} references unknown scenario ${scenarioId}`); } if (seen.has(scenarioId)) { throw new Error(`Scenario ${scenarioId} is assigned to multiple automation suites`); } if (!Array.isArray(suite.cases[scenarioId]) || suite.cases[scenarioId].length === 0) { throw new Error(`Automation suite ${suite.id} has no asserted cases for ${scenarioId}`); } if (suite.cases[scenarioId].some((item) => typeof item !== 'string' || item.trim() === '')) { throw new Error(`Automation suite ${suite.id} has an invalid asserted case for ${scenarioId}`); } seen.add(scenarioId); } const extraCases = Object.keys(suite.cases).filter((scenarioId) => !suite.scenarios.includes(scenarioId)); if (extraCases.length > 0) { throw new Error(`Automation suite ${suite.id} has cases for unassigned scenarios: ${extraCases.join(', ')}`); } } return AUTOMATION_SUITES; }