diff --git a/scripts/agents-index-contract.ps1 b/scripts/agents-index-contract.ps1 index ef1cb940b..64d1dbb6d 100644 --- a/scripts/agents-index-contract.ps1 +++ b/scripts/agents-index-contract.ps1 @@ -199,19 +199,34 @@ Assert-Contains $rootAgents 'docs/独立任务协作登记.md' '根测试协作 Assert-Contains $engineeringConstraints '不得同时加载两表后混合选取任务' '工程协作登记选择门禁' Assert-Contains $docsIndex '[测试环境独立任务协作登记](独立任务协作登记.md)' '文档测试登记入口' Assert-Contains $docsIndex '[开发环境独立任务协作登记](开发环境独立任务协作登记.md)' '文档开发登记入口' -# 当前测试登记已明确清空;历史 projectId/task_id 不得成为恢复调度的依据。 -Assert-Contains $testTaskRegistry '当前无登记任务' '测试登记清空明示' -Assert-Contains $testTaskRegistry '清空全部任务登记与调度规则' '测试登记清空状态' -Assert-Contains $testTaskRegistry '不根据旧登记、历史消息或历史台账自动派工、恢复任务或回传进度' '测试登记禁止历史派工' -Assert-Contains $testTaskRegistry '不作为当前调度或授权依据' '测试登记清空授权边界' -Assert-NotContains $testTaskRegistry '已重新启用测试环境总控调度' '测试登记不得隐式启用' -$checked++ -if ($testTaskRegistry -match '(?m)^\|\s*`[0-9a-f-]{36}`\s*\|') { - Add-Failure '测试登记不得残留任务行' +# BEGIN CURRENT TEST REGISTRY CONTRACT +function Assert-TestTaskRegistry([string]$registry) { + Assert-Contains $registry '用户 2026-09-30 的明确请求重新创建' '测试任务明确创建依据' + Assert-Contains $registry '按4个创建,你直接负责汇总' '测试任务精确数量授权' + Assert-Contains $registry '不根据旧台账恢复或派工' '测试任务禁止历史复用' + Assert-Contains $registry 'task_id=01a0d0da-130f-7d43-97b5-9c76abc1b5f1' '测试所属总控' + Assert-Contains $registry 'projectId=c64729ff-6710-43c6-8ef2-d84e9666cc1e' '测试保存项目' + Assert-Contains $registry '`C:/Users/BY-OY/Desktop/code/chongchong-global`' '测试工作目录' + Assert-Contains $registry '不操作开发或生产环境' '测试授权环境边界' + $expectedIds = @( + '01a0f14c-9262-7b43-990a-0e3beddcdd8a', + '01a0f14c-962f-73c3-b1aa-9df555b91586', + '01a0f14c-9a66-7f61-bc2b-6ad17a6c940a', + '01a0f14c-9e33-7a01-903d-a5febd50774b' + ) + $actualIds = @([regex]::Matches($registry, '(?m)^\|\s*`([0-9a-f-]{36})`\s*\|') | ForEach-Object { $_.Groups[1].Value }) + $script:checked++ + if ($actualIds.Count -ne 4 -or @($actualIds | Select-Object -Unique).Count -ne 4 -or + @($expectedIds | Where-Object { $actualIds -notcontains $_ }).Count -gt 0) { + Add-Failure '测试登记必须恰为本轮明确创建的四个唯一任务' + } + Assert-NotContains $registry '当前无登记任务' '测试登记不得混入过期清空状态' + Assert-NotContains $registry '01a0194a-259c-7171-8967-074731a27618' '测试登记历史总控' + Assert-NotContains $registry '01a06c0b-0515-7c60-b329-77342b54e666' '测试登记开发总控' + Assert-NotContains $registry '6f874ec3-d3b2-49bd-8625-327f4d685f98' '测试登记开发项目' } -Assert-NotContains $testTaskRegistry '01a0194a-259c-7171-8967-074731a27618' '测试登记历史总控' -Assert-NotContains $testTaskRegistry '01a06c0b-0515-7c60-b329-77342b54e666' '测试登记当前开发总控' -Assert-NotContains $testTaskRegistry '6f874ec3-d3b2-49bd-8625-327f4d685f98' '测试登记开发 projectId' +# END CURRENT TEST REGISTRY CONTRACT +Assert-TestTaskRegistry $testTaskRegistry Assert-Contains $devTaskRegistry 'projectId `6f874ec3-d3b2-49bd-8625-327f4d685f98`' '开发登记保存项目' Assert-Contains $devTaskRegistry 'C:\Users\BY-OY\Desktop\code\chongchong-global-dev`' '开发登记工作目录' Assert-Contains $devTaskRegistry '`01a06c0b-0515-7c60-b329-77342b54e666`' '开发环境全流程总控' diff --git a/scripts/agents-index-registry-contract.test.mjs b/scripts/agents-index-registry-contract.test.mjs index cba8c5e78..67b75e092 100644 --- a/scripts/agents-index-registry-contract.test.mjs +++ b/scripts/agents-index-registry-contract.test.mjs @@ -1,24 +1,35 @@ import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' +import { execFileSync } from 'node:child_process' import test from 'node:test' -const source = readFileSync(new URL('./agents-index-contract.ps1', import.meta.url), 'utf8') - -test('cleared test registry is mandatory and cannot inherit historical task authorization', () => { - for (const token of [ - "Assert-Contains $testTaskRegistry '当前无登记任务'", - "Assert-Contains $testTaskRegistry '清空全部任务登记与调度规则'", - "Assert-Contains $testTaskRegistry '不根据旧登记、历史消息或历史台账自动派工、恢复任务或回传进度'", - "Assert-Contains $testTaskRegistry '不作为当前调度或授权依据'", - "Assert-NotContains $testTaskRegistry '已重新启用测试环境总控调度'", - ]) assert.ok(source.includes(token), token) - assert.match(source, /if \(\$testTaskRegistry -match '\(\?m\)\^\\\|\\s\*`\[0-9a-f-\]\{36\}`\\s\*\\\|'\)/) -}) - -test('cleared registry rejects every retired controller and project identity', () => { - for (const retired of [ - '01a0194a-259c-7171-8967-074731a27618', - '01a06c0b-0515-7c60-b329-77342b54e666', - '6f874ec3-d3b2-49bd-8625-327f4d685f98', - ]) assert.match(source, new RegExp(`Assert-NotContains \\$testTaskRegistry '${retired}'`)) +const source = readFileSync(new URL('./agents-index-contract.ps1', import.meta.url), 'utf8').replaceAll('\r\n', '\n') +const registry = readFileSync(new URL('../../docs/独立任务协作登记.md', import.meta.url), 'utf8') +const contract = source.split('# BEGIN CURRENT TEST REGISTRY CONTRACT\n')[1]?.split('# END CURRENT TEST REGISTRY CONTRACT')[0] +assert.ok(contract, 'test exercises the production PowerShell registry validator') +function failures(text) { + const encoded = Buffer.from(text).toString('base64') + const command = `$ErrorActionPreference='Stop' +$script:failures=[System.Collections.Generic.List[string]]::new();$script:checked=0 +function Add-Failure([string]$message){$script:failures.Add($message)} +function Assert-Contains([string]$text,[string]$needle,[string]$scope){if(-not $text.Contains($needle)){Add-Failure $scope}} +function Assert-NotContains([string]$text,[string]$needle,[string]$scope){if($text.Contains($needle)){Add-Failure $scope}} +${contract} +Assert-TestTaskRegistry ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encoded}'))) +ConvertTo-Json -InputObject @($script:failures) -Compress` + return JSON.parse(execFileSync('pwsh', ['-NoProfile', '-NonInteractive', '-Command', command], { encoding: 'utf8' })) +} +test('actual explicitly authorized TEST registry passes the production validator', () => { + assert.deepEqual(failures(registry), []) }) +for (const [name, mutate] of [ + ['missing creation authorization', s => s.replace('按4个创建,你直接负责汇总', '安排任务')], + ['wrong controller', s => s.replace('task_id=01a0d0da-130f-7d43-97b5-9c76abc1b5f1', 'task_id=unknown')], + ['wrong project', s => s.replace('projectId=c64729ff-6710-43c6-8ef2-d84e9666cc1e', 'projectId=wrong')], + ['wrong workspace', s => s.replace('`C:/Users/BY-OY/Desktop/code/chongchong-global`', '`C:/Users/BY-OY/Desktop/code/chongchong-global-dev`')], + ['duplicate task', s => s.replace('01a0f14c-962f-73c3-b1aa-9df555b91586', '01a0f14c-9262-7b43-990a-0e3beddcdd8a')], + ['unregistered replacement', s => s.replace('01a0f14c-962f-73c3-b1aa-9df555b91586', '00000000-0000-0000-0000-000000000000')], + ['obsolete empty status', s => s + '\n当前无登记任务'], + ['foreign project identity', s => s + '\n6f874ec3-d3b2-49bd-8625-327f4d685f98'], + ['retired controller', s => s + '\n01a0194a-259c-7171-8967-074731a27618'], +]) test(`production validator rejects ${name}`, () => assert.ok(failures(mutate(registry)).length > 0))