完善借款、编号、付款与预算并发及验收(09-06-release-gate-integrity)

汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。
统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。
纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。

关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。
预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。
完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
这个提交包含在:
2026-09-19 13:11:04 +08:00
父节点 729d90576f
当前提交 1f8d5b658a
共修改 367 个文件,包含 21079 行新增和 12287 行删除
@@ -1,6 +1,7 @@
const fs = require('node:fs');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const net = require('node:net');
const { createInterface } = require('node:readline');
const GLOBAL_VALUES = new Set(['-p', '--project-name', '-f', '--file', '--env-file', '--profile']);
const OPTION_VALUES = new Set(['--entrypoint', '-e', '--env', '--tail', '--format', '--type', '--timeout', '-t']);
@@ -52,14 +53,13 @@ function lifecycleServices(call, services) {
return [...result];
}
function main() {
const root = process.env.HYB_DEPLOYMENT_FIXTURE_ROOT;
if (!root || !path.basename(root).startsWith('hyb-db-lifecycle-') || path.dirname(process.argv[1]) !== path.join(root, 'bin')) {
throw new Error('fixture_only');
}
const COMMANDS = new Set(['docker', 'docker-compose', 'curl', 'timeout', 'sleep', 'ssh', 'rsync', 'node', 'git', 'sudo']);
const result = (code = 0, stdout = '') => ({ code, stdout });
const output = value => result(0, String(value) + '\n');
async function executeCommand(root, command, args, readStdin, signal) {
if (!COMMANDS.has(command) || !Array.isArray(args) || args.some(arg => typeof arg !== 'string')) throw new Error('fixture_only');
const config = JSON.parse(fs.readFileSync(path.join(root, 'config.json'), 'utf8'));
const command = path.basename(process.argv[1]);
const args = process.argv.slice(2);
const event = { command, args };
if (command === 'docker-compose' || (command === 'docker' && args[0] === 'compose')) {
event.compose = parseCompose(args);
@@ -70,88 +70,111 @@ function main() {
fs.writeFileSync(path.join(root, 'health-drift'), '1');
}
if (command === 'timeout') {
const child = spawnSync('/usr/bin/timeout', args, { env: process.env, stdio: 'inherit' });
process.exit(child.status ?? (child.signal === 'SIGKILL' ? 137 : 99));
return { action: 'timeout' };
}
if (command === 'sleep') return;
if (command === 'sleep') return result();
if (command === 'curl') {
if (args.join(' ') !== '-fsS http://127.0.0.1:31001/ready') throw new Error('unexpected_network_request');
console.log(JSON.stringify({ data: { buildSha: '123456789abc' } }));
return;
return output(JSON.stringify({ data: { buildSha: '123456789abc' } }));
}
if (command === 'docker' && args[0] === 'inspect') {
if (args.at(-1) === 'e'.repeat(64) && args.includes('{{.Config.Image}}')) {
console.log('synthetic-project-worker:latest');
return;
return output('synthetic-project-worker:latest');
}
if (args.at(-1) !== 'd'.repeat(64)) throw new Error('unexpected_container');
if (config.health === 'inspect_error') process.exit(18);
if (config.health === 'inspect_error') return result(18);
const counterFile = path.join(root, 'inspect-count');
const count = fs.existsSync(counterFile) ? Number(fs.readFileSync(counterFile, 'utf8')) : 0;
fs.writeFileSync(counterFile, String(count + 1));
if (config.health === 'query_hang') {
setTimeout(() => {}, 20000);
return;
await new Promise(resolve => {
const finish = () => { clearTimeout(timer); signal.removeEventListener('abort', finish); resolve(); };
const timer = setTimeout(finish, 20000);
signal.addEventListener('abort', finish, { once: true });
if (signal.aborted) finish();
});
return result();
}
const states = { stopped: 'exited|healthy', unhealthy: 'running|unhealthy', no_health: 'running|missing', starting: 'running|starting' };
const state = fs.existsSync(path.join(root, 'health-drift')) ? 'running|unhealthy' : config.health === 'warming' && count === 0 ? 'running|starting' : states[config.health] ?? 'running|healthy';
console.log(state);
return;
return output(state);
}
if (command === 'docker' && args.join(' ') === 'image inspect synthetic-project-worker:latest') process.exit(config.workerTagPresent ? 0 : 1);
if (command === 'docker' && args.join(' ') === 'image inspect synthetic-project-worker:latest') return result(config.workerTagPresent ? 0 : 1);
const call = event.compose;
if (!call) throw new Error('forbidden_external_command');
if (call.operation === 'version') {
process.exit(command === 'docker' && config.engine === 'v1' ? 1 : 0);
return result(command === 'docker' && config.engine === 'v1' ? 1 : 0);
}
if (call.globals['-p'] !== 'synthetic-project') throw new Error('wrong_compose_project');
if (call.noDeps && config.unsupportedIsolation) process.exit(2);
if (call.noDeps && config.unsupportedIsolation) return result(2);
if (LIFECYCLE.has(call.operation)) {
if (call.operation === 'up' && call.targets.includes('db')) fs.writeFileSync(path.join(root, 'db-started'), '1');
if (call.operation === 'run') {
if (call.targets.join() !== 'init' || call.containerArgs.join(' ') !== '-lc cd /app/server && npm run deploy:init' ||
!args.includes('DEPLOY_DATA_MODE=' + process.env.DEPLOY_DATA_MODE)) {
!args.includes('DEPLOY_DATA_MODE=' + config.mode)) {
throw new Error('unexpected_init_command');
}
if (config.initFails) process.exit(23);
if (config.initFails) return result(23);
}
return;
return result();
}
if (call.operation === 'ps') {
if (!call.targets.length) return;
if (!call.targets.length) return result();
if (call.targets.join() === 'worker') {
if (config.workerImagePresent) console.log('e'.repeat(64));
return;
return config.workerImagePresent ? output('e'.repeat(64)) : result();
}
if (call.targets.join() !== 'db') throw new Error('unexpected_ps_service');
if (config.health === 'query_error') process.exit(17);
if (config.health === 'missing' && !fs.existsSync(path.join(root, 'db-started'))) return;
console.log(config.health === 'multiple' ? 'd'.repeat(64) + '\n' + 'e'.repeat(64) : 'd'.repeat(64));
return;
if (config.health === 'query_error') return result(17);
if (config.health === 'missing' && !fs.existsSync(path.join(root, 'db-started'))) return result();
return output(config.health === 'multiple' ? 'd'.repeat(64) + '\n' + 'e'.repeat(64) : 'd'.repeat(64));
}
if (call.operation === 'port' && call.targets.join() === 'server' && call.containerArgs.join() === '3000') {
console.log('127.0.0.1:31001');
return;
return output('127.0.0.1:31001');
}
if (call.operation === 'config') return;
if (call.operation === 'build' && ['init', 'server', 'worker'].includes(call.targets.join())) return;
if (call.operation === 'logs' && call.targets.join() === 'server') return;
if (call.operation === 'config') return result();
if (call.operation === 'build' && ['init', 'server', 'worker'].includes(call.targets.join())) return result();
if (call.operation === 'logs' && call.targets.join() === 'server') return result();
if (call.operation === 'exec' && call.targets.join() === 'server') {
const expected = ['sh -lc cd /app/server && npx prisma migrate status', 'node src/scripts/smoke-external-deps.js', 'node src/scripts/smoke-trialrun-runtime.js'];
if (expected.includes(call.containerArgs.join(' '))) return;
if (expected.includes(call.containerArgs.join(' '))) return result();
if (call.containerArgs[0] === 'node' && call.containerArgs[1] === '-e' && call.containerArgs[2]?.includes('EXPECTED_BUILD_SHA')) {
const input = JSON.parse(fs.readFileSync(0, 'utf8'));
const input = JSON.parse(await readStdin());
if (input.data?.buildSha !== '123456789abc') throw new Error('wrong_ready_build');
return;
return result();
}
}
throw new Error('unknown_fake_command');
}
module.exports = { parseCompose, lifecycleServices };
if (require.main === module) {
try { main(); } catch (error) {
console.error('[deployment-fixture] ' + (/^[a-z_]+$/.test(error.message) ? error.message : 'unexpected_failure'));
process.exitCode = 97;
}
async function startCommandServer(root) {
if (!root || !path.basename(root).startsWith('hyb-db-lifecycle-')) throw new Error('fixture_only');
const sockets = new Set();
const server = net.createServer(async socket => {
sockets.add(socket);
const abort = new AbortController();
socket.on('error', () => socket.destroy());
socket.on('close', () => { sockets.delete(socket); abort.abort(); });
const lines = createInterface({ input: socket, crlfDelay: Infinity });
const reader = lines[Symbol.asyncIterator]();
try {
const request = JSON.parse((await reader.next()).value);
const reply = await executeCommand(root, request.command, request.args, async () => {
socket.write(JSON.stringify({ action: 'stdin' }) + '\n');
const input = JSON.parse((await reader.next()).value);
if (typeof input !== 'string') throw new Error('invalid_stdin');
return input;
}, abort.signal);
if (!socket.destroyed) socket.end(JSON.stringify(reply) + '\n');
} catch (error) {
if (!socket.destroyed) socket.end(JSON.stringify({ code: 97, stderr: '[deployment-fixture] ' + (/^[a-z_]+$/.test(error.message) ? error.message : 'unexpected_failure') + '\n' }) + '\n');
} finally { lines.close(); }
});
await new Promise((resolve, reject) => { server.once('error', reject); server.listen(path.join(root, 'command.sock'), resolve); });
fs.chmodSync(path.join(root, 'command.sock'), 0o600);
return async () => {
for (const socket of sockets) socket.destroy();
await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve()));
};
}
module.exports = { parseCompose, lifecycleServices, startCommandServer };