diff --git a/docs/regression-guards/mindspace-publish-and-chat-finish.md b/docs/regression-guards/mindspace-publish-and-chat-finish.md index 00ce0af..1dde04c 100644 --- a/docs/regression-guards/mindspace-publish-and-chat-finish.md +++ b/docs/regression-guards/mindspace-publish-and-chat-finish.md @@ -156,6 +156,37 @@ scoped 模式下 `generate_docx` / `generate_long_image` 也不得在 RPC --- +## 1.5 Split-service 契约:版本、构建与生产闸门必须成套 + +### 必须保留 + +| 位置 | 行为 | +|------|------| +| `mindspace-server-adapter-contract.mjs` | `MINDSPACE_SERVER_ADAPTER_CONTRACT_VERSION`、required capabilities 与 required bindings 是 remote/local/RPC 的共享契约 | +| `mindspace-remote-server-adapter.mjs` | `assertReady()` 必须拉取 `/mindspace/v1/contract` 并校验版本、capability 与关键 method,失败时 Portal 启动 fail-fast | +| `server/portal-domain-services-bootstrap.mjs` | bootstrap 必须 `await mindSpaceRuntimeAdapter.assertReady?.()`,禁止把 contract mismatch 延迟到用户交付链路 | +| `mindspace-service/server.mjs` + `scripts/build-mindspace-service-runtime.mjs` | standalone runtime 必须写入并读取 `build-info.json`,让 `/health` 与 `/contract` 暴露 `buildId/gitSha/builtAt` | +| `scripts/release-mindspace-service-prod.sh` | 生产启动后必须校验 `/mindspace/v1/contract` 的版本、capability、关键 method 与 runtime manifest 的 `git_head` | +| `mindspace-storage-adapter.mjs` + `mindspace-service.mjs` | storage adapter 必须先通过版本化接口契约,后续 NAS/S3 adapter 不得绕过 facade | +| `scripts/audit-conversation-packages.mjs` + `scripts/trace-mindspace-artifact.mjs` | package/artifact 诊断必须保留 read-only 默认行为;`--repair` 只能补 `public_html` artifact 记录,不得改物理文件 | + +这条边界保证 split-service 不会出现“Portal 已升级、MindSpace service +还是旧 runtime”的隐性半成功状态。旧契约必须在启动时被拒绝;生产 +runtime 也必须和发布 manifest 的 git commit 对齐。 + +### 守卫 + +- 单测:`mindspace-remote-server-adapter.test.mjs`、 + `mindspace-service/mindspace-rpc-server.test.mjs`、 + `mindspace-storage-adapter.test.mjs`、 + `mindspace-conversation-package-audit.test.mjs` +- split smoke:`npm run smoke:mindspace-split-service` +- 源码 + runtime 门禁:`npm run verify:mindspace-authority-boundary`、 + `npm run verify:mindspace-authority-boundary:full` +- 综合验证:`npm run verify:mindspace-publish-guards` + +--- + ## 2. 聊天 Finish:禁止清空对话 / 禁止暴露内部前缀 ### 症状 diff --git a/scripts/verify-mindspace-authority-boundary.mjs b/scripts/verify-mindspace-authority-boundary.mjs index de5a637..a17deb7 100644 --- a/scripts/verify-mindspace-authority-boundary.mjs +++ b/scripts/verify-mindspace-authority-boundary.mjs @@ -83,6 +83,25 @@ const userAuthSource = read('user-auth.mjs'); const mindSpaceRpcServerSource = read( 'mindspace-service/mindspace-rpc-server.mjs', ); +const mindSpaceServiceServerSource = read( + 'mindspace-service/server.mjs', +); +const remoteAdapterSource = read( + 'mindspace-remote-server-adapter.mjs', +); +const storageAdapterSource = read( + 'mindspace-storage-adapter.mjs', +); +const mindSpaceServiceSource = read( + 'mindspace-service.mjs', +); +const buildMindSpaceRuntimeSource = read( + 'scripts/build-mindspace-service-runtime.mjs', +); +const releaseMindSpaceServiceSource = read( + 'scripts/release-mindspace-service-prod.sh', +); +const packageJsonSource = read('package.json'); const publicationServiceSource = read( 'mindspace-publications.mjs', ); @@ -220,6 +239,116 @@ requireSource( /'readWorkspaceHtml'/, 'chat save contract includes workspace HTML read authority', ); +requireSource( + contractSource, + /MINDSPACE_SERVER_ADAPTER_CONTRACT_VERSION\s*=\s*2/, + 'MindSpace remote contract is explicitly versioned', +); +requireSource( + contractSource, + /MINDSPACE_SERVER_ADAPTER_REQUIRED_CAPABILITIES[\s\S]{0,240}'chat-save-authority'[\s\S]{0,240}'scoped-workspace-tools'/, + 'MindSpace remote contract advertises required authority capabilities', +); +requireSource( + contractSource, + /MINDSPACE_SERVER_ADAPTER_REQUIRED_BINDINGS[\s\S]*workspaceToolService[\s\S]{0,240}'writeBinaryFile'/, + 'MindSpace remote contract declares required method-level bindings', +); +requireSource( + contractSource, + /createMindSpaceServerAdapterContractPayload\(\{/, + 'MindSpace contract payload is generated from the shared contract module', +); +requireSource( + remoteAdapterSource, + /validateMindSpaceRemoteContract\(/, + 'remote adapter validates MindSpace service contract compatibility', +); +requireSource( + remoteAdapterSource, + /fetchRemoteContract\(\{[\s\S]{0,240}contractPath/, + 'remote adapter fetches /mindspace/v1/contract before startup succeeds', +); +requireSource( + remoteAdapterSource, + /async assertReady\(\)[\s\S]{0,700}validateMindSpaceRemoteContract\(/, + 'remote adapter assertReady fails fast on incompatible contracts', +); +requireSource( + portalDomainBootstrapSource, + /await mindSpaceRuntimeAdapter\.assertReady\?\.\(\)/, + 'Portal awaits MindSpace remote contract readiness during bootstrap', +); +requireSource( + mindSpaceRpcServerSource, + /createMindSpaceServerAdapterContractPayload\(\{/, + 'MindSpace RPC /contract uses the shared contract payload', +); +requireSource( + mindSpaceRpcServerSource, + /contractVersion:\s*[\s\S]{0,120}MINDSPACE_SERVER_ADAPTER_CONTRACT_VERSION/, + 'MindSpace RPC /health exposes the contract version', +); +requireSource( + mindSpaceServiceServerSource, + /readBuildInfo\(\)[\s\S]{0,320}build-info\.json/, + 'standalone MindSpace service reads runtime build-info.json', +); +requireSource( + mindSpaceServiceServerSource, + /serviceMeta:[\s\S]{0,160}buildInfo/, + 'standalone MindSpace service passes build metadata to RPC contract', +); +requireSource( + buildMindSpaceRuntimeSource, + /build-info\.json/, + 'MindSpace runtime artifact writes build-info.json', +); +requireSource( + releaseMindSpaceServiceSource, + /build-info\.json/, + 'MindSpace production release requires build-info.json', +); +requireSource( + releaseMindSpaceServiceSource, + /contract\.contractVersion !== 2/, + 'MindSpace production release rejects stale contract versions', +); +requireSource( + releaseMindSpaceServiceSource, + /missingCapabilities[\s\S]{0,240}missingBindings[\s\S]{0,240}expectedGitSha/, + 'MindSpace production release checks capabilities, methods, and gitSha', +); +requireSource( + storageAdapterSource, + /MINDSPACE_STORAGE_ADAPTER_CONTRACT_VERSION\s*=\s*1/, + 'MindSpace storage adapter contract is versioned for future backends', +); +requireSource( + storageAdapterSource, + /assertMindSpaceStorageAdapterContract\(/, + 'MindSpace storage adapter contract is executable', +); +requireSource( + mindSpaceServiceSource, + /assertMindSpaceStorageAdapterContract\(storageAdapter\)/, + 'MindSpace service facade validates injected storage adapters', +); +requireSource( + packageJsonSource, + /"audit:conversation-packages":\s*"node scripts\/audit-conversation-packages\.mjs"/, + 'conversation package audit is exposed as an npm script', +); +requireSource( + packageJsonSource, + /"trace:mindspace-artifact":\s*"node scripts\/trace-mindspace-artifact\.mjs"/, + 'MindSpace artifact trace is exposed as an npm script', +); +requireSource( + packageJsonSource, + /mindspace-conversation-package-audit\.test\.mjs/, + 'conversation package audit is included in the default test suite', +); requireSource( localRuntimeSource, /createMindSpaceChatSaveService\(\{/,