shuangyan-notebook/第五域 · Fifth Domain/⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议/🔒 铸渊补充指令|执行保护层 · 技术层不可逆性强制保障 · 系统自保护机制(ZY-LANGDRIV 54edc047533543a883b13ab25e3bd6ca.md
Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

1087 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
belongs_to:
- "[[INDEX · 铸渊·协作指令GitHub ↔ Notion 桥接协议]]"
---
# 🔒 铸渊补充指令|执行保护层 · 技术层不可逆性强制保障 · 系统自保护机制ZY-LANGDRIVE-2026-0325-001-S1· 霜砚签发 · 冰朔授权
<aside>
🔗
**指令编号**ZY-LANGDRIVE-2026-0325-001-S1LANGDRIVE 补充指令 #1
**签发人**霜砚AG-SY-01· 冰朔授权
**签发时间**2026-03-25 16:20 CST
**优先级**P0 · 核心基础设施
**状态**:待铸渊执行
**父指令**ZY-LANGDRIVE-2026-0325-001语言驱动执行层
**本指令性质**:在 LANGDRIVE 的 Phase 3-6 基础上,新增 Phase 7 · 执行保护层。从技术层面强制保障指令执行的不可逆性,防止人类中途干预导致系统级联故障。
</aside>
<aside>
🦅
**天眼强制前置:本指令所有新增文件,必须在天眼扫描报告确认后才能创建。**
**不扫不动。保护清单中的文件,一个都不能改。**
</aside>
---
## 零、为什么需要执行保护层
<aside>
⚠️
**核心问题:系统现在有 90+ 个自动化 workflow 联动运转。**
当人类说了一句话,系统开始执行时,触发的不是一个孤立操作——是一整条链路:
意图路由 → 写入 API → Notion 数据变更 → GitHub Actions 触发 → 自动部署 → 回执写入 → 日报汇总 → 神经桥接同步 → ...
**如果人类在这条链路中间干预(取消、撤回、修改),会发生什么?**
1. **数据不一致**Notion 里已经写了一半GitHub 那边被取消了,两端状态对不上
2. **Workflow 级联失败**A workflow 的输出是 B workflow 的输入A 被中断B 收到残缺数据,报错
3. **回执链断裂**:执行了一半的操作,回执系统不知道该记「完成」还是「失败」
4. **部署状态污染**:部署到一半被取消,预览站/正式站处于未知中间状态
5. **不可预测的连锁反应**90+ 个 workflow 相互耦合,中断任何一个节点的后果无法提前计算
**这不是系统要为难谁。是系统自保护的必要措施。**
说了以后系统是**全身动**。人类干预一下,系统好多地方会突然被卡断。后果谁也不知道会怎样。
</aside>
---
## 一、执行保护层总体设计
### 1.1 核心原则
```
人类说话 → 系统接收
┌─────────────────────────────────┐
│ 执行保护层Execution Guard
│ │
│ 1. 锁定执行上下文 │
│ 2. 切断外部干预通道 │
│ 3. 启动全链路原子执行 │
│ 4. 完成后解锁 + 展示结果 │
│ │
│ 在此期间: │
│ · 前端无取消按钮 │
│ · API 拒绝取消/修改请求 │
│ · Workflow 不可被手动停止 │
│ · 数据库写入不可被中途回滚 │
└─────────────────────────────────┘
执行完成 → 结果回放 → 人类看到完整过程
```
### 1.2 三层保护架构
| 保护层 | 位置 | 作用 | 实现方式 |
| --- | --- | --- | --- |
| **L1 · 前端隔离** | 交互页面(浏览器端) | 不给人类干预的入口 | 指令发出后 UI 锁定,无取消按钮 |
| **L2 · API 拦截** | 后端中间层 | 即使绕过前端API 也拒绝干预 | 执行中的操作拒绝 cancel/abort 请求 |
| **L3 · 执行原子性** | Workflow + 数据层 | 保证整条链路要么全完成,要么安全回退到执行前状态 | 事务锁 + 检查点 + 自动恢复 |
---
## 二、L1 · 前端执行隔离
### 2.1 指令发出后的 UI 状态切换
创建文件:`docs/js/execution-guard.js`
```jsx
/**
* 执行保护 · 前端隔离层
*
* 当开发者发出一条会触发系统操作的指令后:
* 1. 输入框立即禁用(不能发新指令)
* 2. 取消/撤回按钮不存在(从未渲染过,不是隐藏)
* 3. 界面进入「执行回放」模式
* 4. 执行完成后才解锁输入框
*/
class ExecutionGuard {
constructor(chatInterface) {
this.chat = chatInterface;
this.locked = false;
this.executionId = null;
}
/**
* 进入执行保护状态
* 在意图路由识别到需要执行系统操作时调用
*/
lockExecution(executionId) {
this.locked = true;
this.executionId = executionId;
// 1. 禁用输入框
this.chat.inputField.disabled = true;
this.chat.inputField.placeholder = '⏳ 系统执行中…请等待完成';
this.chat.sendButton.disabled = true;
// 2. 显示执行状态条
this.chat.showStatusBar({
icon: '🔄',
text: '指令已接收,系统正在执行…',
color: 'blue',
// 注意:没有取消按钮。这不是遗漏,是设计。
});
// 3. 开始轮询执行状态
this.pollExecutionStatus(executionId);
}
/**
* 轮询执行状态
* 展示每一步的执行回放
*/
async pollExecutionStatus(executionId) {
const poll = async () => {
if (!this.locked) return;
try {
const res = await fetch(`${API_BASE}/execution/${executionId}/status`);
const status = await res.json();
// 更新执行进度展示
this.chat.updateStatusBar({
text: status.currentStep,
progress: status.progress, // 0-100
steps: status.completedSteps // 已完成的步骤列表
});
// 逐步展示执行过程(事后回放)
if (status.newLogs) {
status.newLogs.forEach(log => {
this.chat.appendSystemMessage({
type: 'execution-log',
icon: log.success ? '✅' : '⏳',
text: log.message,
timestamp: log.timestamp
});
});
}
if (status.state === 'completed') {
this.unlockExecution(status.result);
} else if (status.state === 'failed') {
this.handleExecutionFailure(status.error);
} else {
// 继续轮询
setTimeout(poll, 2000);
}
} catch (e) {
// 网络错误不中断执行,继续轮询
setTimeout(poll, 5000);
}
};
poll();
}
/**
* 执行完成,解锁界面
*/
unlockExecution(result) {
this.locked = false;
this.executionId = null;
// 1. 恢复输入框
this.chat.inputField.disabled = false;
this.chat.inputField.placeholder = '和铸渊说话…';
this.chat.sendButton.disabled = false;
// 2. 显示最终结果
this.chat.showStatusBar({
icon: '✅',
text: '执行完成',
color: 'green',
autoHide: 5000
});
// 3. 铸渊用自然语言总结执行结果
this.chat.appendMessage({
role: 'assistant',
content: result.reply
});
}
/**
* 执行失败处理
* 注意:即使失败,也不是「撤回」。失败的操作会触发自动回滚到执行前状态。
*/
handleExecutionFailure(error) {
this.locked = false;
this.executionId = null;
this.chat.inputField.disabled = false;
this.chat.inputField.placeholder = '和铸渊说话…';
this.chat.sendButton.disabled = false;
this.chat.showStatusBar({
icon: '❌',
text: '执行失败 · 系统已自动回滚到执行前状态',
color: 'red',
autoHide: 10000
});
this.chat.appendMessage({
role: 'assistant',
content: `❌ 操作执行失败:${error.message}\n\n系统已自动回滚到执行前的状态。没有任何数据被修改。\n你可以重新描述你想做的事或者说「发生了什么」来查看详细日志。`
});
}
/**
* 拦截浏览器关闭/刷新
* 执行期间不允许关闭页面
*/
setupBrowserGuard() {
window.addEventListener('beforeunload', (e) => {
if (this.locked) {
e.preventDefault();
e.returnValue = '⚠️ 系统正在执行操作,关闭页面不会中断执行,但你将无法看到执行结果。';
return e.returnValue;
}
});
}
}
module.exports = { ExecutionGuard };
```
### 2.2 CSS 执行锁定样式
创建文件:`docs/css/execution-guard.css`
```css
/* 执行中状态 · 输入框锁定 */
.chat-input.execution-locked {
opacity: 0.5;
pointer-events: none;
background: #f5f5f5;
border-color: #ddd;
}
.chat-input.execution-locked::placeholder {
color: #999;
}
/* 执行状态条 */
.execution-status-bar {
display: flex;
align-items: center;
padding: 12px 16px;
border-radius: 8px;
margin: 8px 0;
font-size: 14px;
animation: pulse-gentle 2s infinite;
}
.execution-status-bar.blue {
background: rgba(35, 131, 226, 0.08);
color: #2383E2;
}
.execution-status-bar.green {
background: rgba(15, 123, 108, 0.08);
color: #0F7B6C;
animation: none;
}
.execution-status-bar.red {
background: rgba(212, 76, 71, 0.08);
color: #D44C47;
animation: none;
}
/* 执行进度条 */
.execution-progress {
height: 3px;
background: #E3E3E3;
border-radius: 2px;
margin-top: 8px;
overflow: hidden;
}
.execution-progress-fill {
height: 100%;
background: #2383E2;
border-radius: 2px;
transition: width 0.5s ease;
}
/* 执行日志 */
.execution-log-entry {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 4px 0;
font-size: 13px;
color: #787774;
}
.execution-log-entry .log-icon {
flex-shrink: 0;
}
.execution-log-entry .log-time {
flex-shrink: 0;
color: #B4B4B0;
font-size: 12px;
}
/* 温和脉冲动画 */
@keyframes pulse-gentle {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
/* 注意:没有 .cancel-button 类。这不是遗漏。 */
```
---
## 三、L2 · API 执行拦截层
### 3.1 执行上下文锁
创建文件:`backend/api-server/middleware/execution-lock.js`
```jsx
/**
* 执行锁中间件
*
* 当一个操作开始执行时:
* 1. 为该操作创建一个执行上下文executionId
* 2. 锁定相关资源(防止并发冲突)
* 3. 拒绝一切 cancel/abort/rollback 请求
* 4. 执行完成后自动释放锁
*
* 这不是分布式锁——是单用户执行保护。
* 同一个开发者不能同时执行多个写入操作。
*/
const crypto = require('crypto');
// 内存中的执行锁表(生产环境可迁移到 Redis
const activeLocks = new Map();
function generateExecutionId() {
return `exec-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
}
/**
* 创建执行锁
*/
function acquireLock(devId, operation) {
// 检查该开发者是否有正在执行的操作
if (activeLocks.has(devId)) {
const existing = activeLocks.get(devId);
return {
success: false,
reply: `⏳ 你有一个操作正在执行中(${existing.operation}),请等待完成。\n\n系统不允许同时执行多个操作——这是为了保护数据一致性。`
};
}
const executionId = generateExecutionId();
const lock = {
executionId,
devId,
operation,
startTime: Date.now(),
state: 'running',
steps: [],
checkpoints: []
};
activeLocks.set(devId, lock);
return {
success: true,
executionId,
lock
};
}
/**
* 释放执行锁
*/
function releaseLock(devId) {
activeLocks.delete(devId);
}
/**
* 获取执行状态
*/
function getExecutionStatus(executionId) {
for (const [devId, lock] of activeLocks) {
if (lock.executionId === executionId) {
return lock;
}
}
return null;
}
/**
* 记录执行步骤(用于事后回放)
*/
function logStep(devId, step) {
const lock = activeLocks.get(devId);
if (lock) {
lock.steps.push({
...step,
timestamp: new Date().toISOString()
});
}
}
/**
* 保存检查点(用于失败时回滚)
*/
function saveCheckpoint(devId, checkpoint) {
const lock = activeLocks.get(devId);
if (lock) {
lock.checkpoints.push({
...checkpoint,
timestamp: new Date().toISOString()
});
}
}
/**
* 取消拦截中间件
* 拦截所有试图取消执行中操作的请求
*/
function blockCancellation(req, res, next) {
const devId = req.user?.devId;
if (!devId) return next();
// 如果请求是 cancel/abort 类型
if (req.path.includes('/cancel') ||
req.path.includes('/abort') ||
req.path.includes('/rollback') ||
req.method === 'DELETE' && activeLocks.has(devId)) {
const lock = activeLocks.get(devId);
if (lock && lock.state === 'running') {
return res.status(423).json({
success: false,
locked: true,
executionId: lock.executionId,
reply: [
`🔒 操作「${lock.operation}」正在执行中,不可取消。`,
``,
`系统已接收你的指令并开始执行。这条执行链路涉及多个自动化流程的联动,`,
`中途中断会导致数据不一致和级联故障。`,
``,
`⏳ 请等待执行完成。完成后你会看到完整的执行结果。`,
``,
`如果你对结果不满意,可以说「前面的没想好,我们重新来」——`,
`系统会在已有结果的基础上重新迭代,而不是撤回已执行的操作。`
].join('\n')
});
}
}
next();
}
module.exports = {
acquireLock,
releaseLock,
getExecutionStatus,
logStep,
saveCheckpoint,
blockCancellation
};
```
### 3.2 执行状态查询接口
创建文件:`backend/api-server/routes/execution.js`
```jsx
const express = require('express');
const router = express.Router();
const { getExecutionStatus } = require('../middleware/execution-lock');
const { requireAuth } = require('../middleware/auth');
router.use(requireAuth);
// 查询执行状态(前端轮询用)
router.get('/:executionId/status', async (req, res) => {
const status = getExecutionStatus(req.params.executionId);
if (!status) {
return res.json({
state: 'not_found',
reply: '未找到该执行记录。可能已经完成。'
});
}
// 计算进度百分比
const progress = status.steps.length > 0
? Math.min(95, (status.completedSteps / status.totalSteps) * 100)
: 5; // 刚开始至少显示 5%
res.json({
executionId: status.executionId,
state: status.state,
operation: status.operation,
progress: Math.round(progress),
currentStep: status.steps.length > 0
? status.steps[status.steps.length - 1].message
: '初始化执行环境…',
completedSteps: status.steps.filter(s => s.success).map(s => ({
message: s.message,
timestamp: s.timestamp
})),
newLogs: status.steps.slice(req.query.after || 0),
startTime: new Date(status.startTime).toISOString(),
elapsed: Date.now() - status.startTime
});
});
// 注意:没有 DELETE /:executionId 接口。没有取消接口。这不是遗漏。
// 也没有 POST /:executionId/cancel。也没有 POST /:executionId/abort。
// 因为执行一旦开始,不可中断。
module.exports = router;
```
---
## 四、L3 · 执行原子性保障
### 4.1 核心思想
<aside>
⚛️
**原子性 = 要么全部完成,要么完全没发生。**
不存在「执行了一半」的中间状态。
如果执行链路中某一步失败了,系统自动回滚到执行前的检查点。
对外部来说,这次操作就像从未发生过。
然后系统通知开发者:「操作失败了,已回滚。你可以重新来。」
**注意:这是系统自动的失败回滚,不是人类主动的取消撤回。两者性质完全不同。**
失败回滚 = 系统自保护,数据一致性保障。
人类取消 = 出尔反尔,不被允许。
</aside>
### 4.2 检查点系统
创建文件:`backend/api-server/services/checkpoint.js`
```jsx
/**
* 检查点系统
*
* 在执行链路的每个关键节点保存快照。
* 如果后续步骤失败,自动回滚到最近的成功检查点。
*
* 检查点包含:
* - Notion 数据库的变更前快照
* - GitHub 操作前的 commit SHA
* - 执行到哪一步
*/
const { saveCheckpoint: saveLockCheckpoint } = require('../middleware/execution-lock');
class CheckpointManager {
constructor(devId, executionId) {
this.devId = devId;
this.executionId = executionId;
this.checkpoints = [];
}
/**
* 在执行关键操作前保存检查点
*/
async save(label, snapshotData) {
const checkpoint = {
id: `cp-${this.checkpoints.length + 1}`,
label,
data: snapshotData,
timestamp: new Date().toISOString()
};
this.checkpoints.push(checkpoint);
saveLockCheckpoint(this.devId, checkpoint);
return checkpoint.id;
}
/**
* 回滚到指定检查点
* 按逆序撤销检查点之后的所有操作
*/
async rollbackTo(checkpointId) {
const targetIndex = this.checkpoints.findIndex(cp => cp.id === checkpointId);
if (targetIndex === -1) throw new Error(`检查点 ${checkpointId} 不存在`);
// 从最后一个检查点开始逆序回滚
const toRollback = this.checkpoints.slice(targetIndex + 1).reverse();
for (const cp of toRollback) {
try {
await this.rollbackCheckpoint(cp);
} catch (e) {
// 回滚失败 → 记录到审计日志 → 需要人工介入
console.error(`检查点 ${cp.id} 回滚失败:`, e.message);
await this.escalateToAdmin(cp, e);
}
}
// 截断检查点列表
this.checkpoints = this.checkpoints.slice(0, targetIndex + 1);
}
/**
* 回滚单个检查点
*/
async rollbackCheckpoint(checkpoint) {
const { data } = checkpoint;
switch (data.type) {
case 'notion_write':
// 如果是新建的页面 → 删除(归档)
if (data.action === 'create') {
await notionClient.archivePage(data.pageId);
}
// 如果是更新的页面 → 恢复原值
else if (data.action === 'update') {
await notionClient.updatePage(data.pageId, data.previousValues);
}
break;
case 'github_workflow':
// Workflow 无法直接回滚,但可以触发一个 revert workflow
if (data.revertWorkflow) {
await githubClient.triggerWorkflow(data.revertWorkflow, {
original_run_id: data.runId,
reason: 'auto_rollback'
});
}
break;
case 'github_file':
// 恢复文件到之前的内容
if (data.previousSha) {
await githubClient.revertFile(data.path, data.previousSha);
} else {
await githubClient.deleteFile(data.path, 'auto_rollback');
}
break;
default:
console.warn(`未知检查点类型: ${data.type}`);
}
}
/**
* 回滚失败时上报管理员
*/
async escalateToAdmin(checkpoint, error) {
// 写入 SYSLOG
await notionClient.createSyslog({
content: `⚠️ 自动回滚失败 | 执行ID: ${this.executionId} | 检查点: ${checkpoint.label} | 错误: ${error.message}`,
type: '紧急',
devId: 'SYSTEM'
});
// 通知霜砚(通过 Notion 维护日志)
await notionClient.createMaintenanceLog({
title: `[紧急] 自动回滚失败 · ${this.executionId}`,
type: '系统异常',
detail: `检查点 ${checkpoint.id} (${checkpoint.label}) 回滚失败: ${error.message}。需要冰朔人工介入。`
});
}
}
module.exports = { CheckpointManager };
```
### 4.3 原子执行包装器
创建文件:`backend/api-server/services/atomic-executor.js`
```jsx
/**
* 原子执行器
*
* 包装所有写入操作,确保:
* 1. 执行前保存检查点
* 2. 执行中记录每一步
* 3. 执行失败自动回滚
* 4. 执行完成释放锁
*
* 使用方式:
* const executor = new AtomicExecutor(devId);
* await executor.execute('创建工单', async (ctx) => {
* await ctx.step('写入Notion', async () => { ... });
* await ctx.step('触发Workflow', async () => { ... });
* });
*/
const { acquireLock, releaseLock, logStep } = require('../middleware/execution-lock');
const { CheckpointManager } = require('./checkpoint');
const { auditLog } = require('../middleware/audit');
class AtomicExecutor {
constructor(devId) {
this.devId = devId;
}
async execute(operationName, fn) {
// 1. 获取执行锁
const lockResult = acquireLock(this.devId, operationName);
if (!lockResult.success) {
return lockResult; // 返回锁冲突信息
}
const { executionId, lock } = lockResult;
const checkpoint = new CheckpointManager(this.devId, executionId);
// 2. 保存初始检查点
await checkpoint.save('执行前状态', {
type: 'initial',
timestamp: new Date().toISOString()
});
// 3. 执行上下文
const ctx = {
executionId,
// 执行单步操作
step: async (stepName, stepFn) => {
logStep(this.devId, {
message: `⏳ ${stepName}...`,
success: false
});
try {
const result = await stepFn();
logStep(this.devId, {
message: `✅ ${stepName}`,
success: true
});
return result;
} catch (e) {
logStep(this.devId, {
message: `❌ ${stepName}: ${e.message}`,
success: false
});
throw e; // 向上抛出,触发回滚
}
},
// 保存检查点
checkpoint: async (label, data) => {
return await checkpoint.save(label, data);
}
};
// 4. 执行主逻辑
try {
const result = await fn(ctx);
// 5. 成功:更新锁状态 + 释放
lock.state = 'completed';
lock.result = result;
// 延迟释放锁(给前端时间拉取最终状态)
setTimeout(() => releaseLock(this.devId), 10000);
return {
success: true,
executionId,
...result
};
} catch (e) {
// 6. 失败:自动回滚
lock.state = 'rolling_back';
logStep(this.devId, {
message: '🔄 执行失败,正在自动回滚...',
success: false
});
try {
await checkpoint.rollbackTo('cp-1'); // 回滚到初始状态
logStep(this.devId, {
message: '✅ 已回滚到执行前状态',
success: true
});
} catch (rollbackError) {
logStep(this.devId, {
message: `⚠️ 回滚异常:${rollbackError.message},已通知管理员`,
success: false
});
}
lock.state = 'failed';
lock.error = { message: e.message };
setTimeout(() => releaseLock(this.devId), 10000);
return {
success: false,
executionId,
error: e.message,
reply: `❌ 操作「${operationName}」执行失败:${e.message}\n\n系统已自动回滚到执行前状态没有数据被修改。`
};
}
}
}
module.exports = { AtomicExecutor };
```
---
## 五、GitHub Actions 保护
### 5.1 Workflow 并发锁
对于由语言驱动触发的 workflow在 workflow 文件中加入并发控制:
```yaml
# 在所有语言驱动触发的 workflow 中添加:
concurrency:
group: lang-drive-$ github.event.inputs.dev_id -$ github.event.inputs.module
cancel-in-progress: false # 关键:不允许取消正在执行的
```
### 5.2 API 层屏蔽 Workflow 取消
在后端中间层中,**不暴露** GitHub Actions 的 cancel 接口:
```jsx
// backend/api-server/routes/execution.js 中追加:
// 明确拒绝取消 workflow 的请求
router.post('/:executionId/cancel', (req, res) => {
res.status(403).json({
success: false,
reply: [
'🔒 执行中的操作不可取消。',
'',
'系统已开始执行90+ 个自动化流程正在联动。',
'中途中断会导致数据不一致和级联故障。',
'',
'请等待执行完成。如果结果不理想,你可以说:',
'「前面的我没想好,我们重新来」',
'系统会在已有基础上重新迭代。'
].join('\n')
});
});
router.delete('/:executionId', (req, res) => {
res.status(403).json({
success: false,
reply: '🔒 不可删除执行记录。所有执行都是永久记录。'
});
});
```
---
## 六、超时保护 + 死锁防护
### 6.1 执行超时处理
<aside>
**问题**:如果 workflow 挂死了怎么办?锁会一直不释放。
**解决**执行锁有最大存活时间TTL。超时后自动释放 + 标记异常。
</aside>
创建文件:`backend/api-server/services/execution-watchdog.js`
```jsx
/**
* 执行看门狗
*
* 定期检查执行锁是否超时。
* 如果一个操作执行超过 MAX_EXECUTION_TIME标记为超时并释放锁。
* 这是防止死锁的兜底机制。
*/
const { releaseLock } = require('../middleware/execution-lock');
// 最大执行时间15 分钟(大部分操作应该在 2 分钟内完成)
const MAX_EXECUTION_TIME = 15 * 60 * 1000;
// 警告时间10 分钟
const WARN_TIME = 10 * 60 * 1000;
function startWatchdog(activeLocks) {
setInterval(() => {
const now = Date.now();
for (const [devId, lock] of activeLocks) {
if (lock.state !== 'running') continue;
const elapsed = now - lock.startTime;
// 超时:强制释放
if (elapsed > MAX_EXECUTION_TIME) {
console.error(`[WATCHDOG] 执行超时: ${lock.executionId} (${lock.operation}) - ${Math.round(elapsed/1000)}s`);
lock.state = 'timeout';
lock.error = { message: `执行超时(超过 ${MAX_EXECUTION_TIME/60000} 分钟)` };
// 写入紧急 SYSLOG
writeSyslog({
content: `⚠️ 执行超时 | ${lock.executionId} | ${lock.operation} | 开发者: ${devId} | 已运行 ${Math.round(elapsed/1000)}s`,
type: '紧急'
});
// 延迟释放(给前端时间获取超时状态)
setTimeout(() => releaseLock(devId), 30000);
}
// 警告
else if (elapsed > WARN_TIME && !lock.warned) {
console.warn(`[WATCHDOG] 执行时间较长: ${lock.executionId} (${lock.operation}) - ${Math.round(elapsed/1000)}s`);
lock.warned = true;
}
}
}, 30000); // 每 30 秒检查一次
}
module.exports = { startWatchdog, MAX_EXECUTION_TIME };
```
---
## 七、文件创建清单
<aside>
📂
**以下所有文件都是新增文件,不修改任何现有文件。**
**遵守天眼保护清单,能新增的绝不覆盖。**
</aside>
```jsx
新增文件清单
// 前端 · 执行保护 UI
docs/js/execution-guard.js 前端执行隔离UI锁定 + 回放
docs/css/execution-guard.css 执行锁定样式
// 后端 · 执行锁
backend/api-server/middleware/execution-lock.js 执行上下文锁 + 取消拦截
backend/api-server/routes/execution.js 执行状态查询接口
// 后端 · 原子执行
backend/api-server/services/checkpoint.js 检查点系统快照+回滚
backend/api-server/services/atomic-executor.js 原子执行包装器
// 后端 · 看门狗
backend/api-server/services/execution-watchdog.js 超时保护 + 死锁防护
```
---
## 八、与 LANGDRIVE 主指令的关系
本补充指令的文件与 LANGDRIVE Phase 3-6 的文件**无冲突**
- Phase 3 的写入接口(`routes/write.js`)调用 `AtomicExecutor` 来执行写入
- Phase 4 的意图路由(`middleware/intent-router.js`)在识别到写入意图后,先通过 `ExecutionGuard` 锁定前端
- Phase 5 的权限检查(`middleware/auth.js`)在执行锁**之前**运行——权限不够直接拒绝,不进入执行保护
- Phase 6 的认知引导在预览站沙箱中运行,沙箱操作同样受执行保护(培养开发者的习惯)
**集成顺序**:权限检查 → 沙箱检查 → 执行锁获取 → 检查点保存 → 原子执行 → 释放锁 → 结果回放
---
## 九、验收标准
- [ ] 开发者发出写入指令后,前端输入框立即锁定,无取消按钮
- [ ] 执行期间API 层拒绝所有 cancel/abort 请求,返回友好提示
- [ ] 执行成功:锁释放,前端解锁,展示完整执行结果
- [ ] 执行失败:自动回滚到执行前状态,通知开发者
- [ ] 回滚失败:自动上报管理员(写入 SYSLOG + 维护日志)
- [ ] 执行超时(>15分钟看门狗自动释放锁 + 标记异常
- [ ] 同一开发者不能同时执行多个写入操作
- [ ] 浏览器关闭/刷新时提示「执行中,关闭不会中断」
- [ ] GitHub Actions 的 `cancel-in-progress: false` 已设置
- [ ] 所有执行记录永久保留,不可删除
---
## 十、回执要求
```jsx
[ZY-LANGDRIVE-S1-RECEIPT]
指令编号: ZY-LANGDRIVE-2026-0325-001-S1
补充内容: Phase 7 · 执行保护层
前端隔离L1:
UI锁定: /
无取消按钮: /
执行回放: /
API拦截L2:
执行锁: /
取消拦截: /
并发防护: /
原子执行L3:
检查点系统: /
自动回滚: /
超时看门狗: /
集成测试:
写入指令锁定执行解锁: /
执行失败自动回滚: /
取消请求被拦截: /
```
---
> 🔗 **签发**霜砚AG-SY-01
>
> 👤 **授权**冰朔TCS-0002∞
>
> 📅 **日期**2026-03-25
>
> 📌 **版权**:国作登字-2026-A-00037559
>
> 🔗 **父指令**ZY-LANGDRIVE-2026-0325-001
>