Skip to content

Commit 5c75a96

Browse files
committed
feat(agent-workspace): add replay triage and retention governance
1 parent 27a2684 commit 5c75a96

8 files changed

Lines changed: 378 additions & 15 deletions

docs/brainstorms/2026-04-16-mainline-ci-stabilization-and-m7-direction-requirements.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,29 @@ Deliverables:
282282
- `npm run test:agent-workspace:contracts`
283283
- `npm run verify:agent-workspace:runtime`
284284

285+
### M7.8 (Now): Operator Replay Triage and Bounded Retention Governance (Lane Ops Bridge)
286+
287+
Deliverables:
288+
289+
- add operator replay triage summary surface with explicit runbook links.
290+
- enforce bounded retention governance so diagnostics index and report files stay aligned.
291+
292+
#### M7.8 Progress Note (2026-04-16)
293+
294+
- [Done] expanded `src/server.ts` with replay triage route:
295+
- `GET /api/knowledge/operator/agent-workspace-diagnostics/triage`.
296+
- [Done] expanded diagnostics summary semantics for operator triage:
297+
- `replayCandidateRate` and `replayRiskLevel` (`low|medium|high`) are now stored in diagnostics index entries.
298+
- [Done] landed bounded retention governance:
299+
- stale diagnostics report files beyond retained index bounds are pruned to keep file/index consistency under `AGENT_WORKSPACE_DIAGNOSTICS_MAX_ENTRIES`.
300+
- [Done] expanded evidence coverage:
301+
- `src/server.migration.test.ts` now asserts replay triage semantics and retention-bound enforcement,
302+
- `scripts/verify-agent-workspace-runtime.js` + `src/agent_workspace.verification.contract.test.ts` now fail fast on triage/retention gate drift.
303+
- [Done] verification evidence:
304+
- `npm test -- src/server.migration.test.ts --runInBand --testNamePattern "agent workspace diagnostics report|triage route summarizes replay risk"`
305+
- `npm run test:agent-workspace:contracts`
306+
- `npm run verify:agent-workspace:runtime`
307+
285308
## Success Criteria
286309

287310
- CI failure mode that previously blocked the three agent-workspace suites is eliminated on mainline.
@@ -291,4 +314,4 @@ Deliverables:
291314

292315
## Next Step
293316

294-
Proceed to `/prompts:ce-plan` using this document as the source for `M7.8` decomposition (operator runbook replay triage and bounded retention governance), while preserving M7 lane boundary constraints.
317+
Proceed to `/prompts:ce-plan` using this document as the source for `M7.9` decomposition (operator triage trend history and alert-threshold governance), while preserving M7 lane boundary constraints.

docs/diataxis/en/explanation/development-progress-dashboard.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,22 @@ Execution anchor:
350350
- `npm run test:agent-workspace:contracts`
351351
- `npm run verify:agent-workspace:runtime`
352352

353+
## Latest Mainline Increment (2026-04-16 M7.8 Operator Replay Triage and Bounded Retention Governance Lane)
354+
355+
- Extended sidecar diagnostics governance in `src/server.ts`:
356+
- added `GET /api/knowledge/operator/agent-workspace-diagnostics/triage` for replay-risk triage summary and runbook links,
357+
- added bounded retention cleanup for diagnostics report files so retained files stay aligned with index bounds (`AGENT_WORKSPACE_DIAGNOSTICS_MAX_ENTRIES`).
358+
- Extended diagnostics summary semantics:
359+
- each diagnostics index entry now carries `replayCandidateRate` and `replayRiskLevel` (`low|medium|high`) for operator triage.
360+
- Expanded executable evidence:
361+
- `src/server.migration.test.ts` now validates replay-risk triage output and verifies retention enforcement at max-entry boundary.
362+
- Hardened runtime verification gate:
363+
- `scripts/verify-agent-workspace-runtime.js` now fail-fast checks triage route and retention-governance helper wiring.
364+
- Verification evidence:
365+
- `npm test -- src/server.migration.test.ts --runInBand --testNamePattern \"agent workspace diagnostics report|triage route summarizes replay risk\"`
366+
- `npm run test:agent-workspace:contracts`
367+
- `npm run verify:agent-workspace:runtime`
368+
353369
## Mainline vs Working-Branch Snapshot (2026-04-14)
354370

355371
| Capability Slice | Working Branch (`feat/learning-multi-tutor-adapter`) | Mainline (`origin/main`) | Integration Status |
@@ -358,7 +374,7 @@ Execution anchor:
358374
| Focus + learning-path side-by-side pane model | Implemented in branch UI/runtime | Dock coexistence baseline integrated (`styles.css`, `path_styles.css`, `path_app.js`) | Partially integrated |
359375
| Agent workspace contract parity suite | Implemented (`src/agent_workspace.contract.parity.test.ts`, `src/agent_workspace.frontend.test.ts`, `src/agent_workspace.locale.contract.test.ts`, `src/agent_workspace.tauri.contract.test.ts`) | Baseline parity suite integrated (`src/agent_workspace.contract.parity.test.ts`, `src/agent_workspace.frontend.test.ts`, `src/agent_workspace.runtime.integration.test.ts`) | Partially integrated |
360376
| Result-presentation allowlist/override fail-fast governance | Implemented in branch execution registry and parity tests | Integrated in M1 (`src/frontend/agent_workspace.js` + parity tests) | Baseline integrated |
361-
| Conversation turn stream/replay/operator diagnostics expansion | Implemented in branch routes/tests | Mainline has snapshot + trend/index/export diagnostics baseline in runtime (`src/frontend/agent_workspace_runtime.js`) | Partially integrated |
377+
| Conversation turn stream/replay/operator diagnostics expansion | Implemented in branch routes/tests | Mainline has runtime snapshot+trend/index/export plus sidecar persistence+triage+bounded retention governance (`src/frontend/agent_workspace_runtime.js`, `src/server.ts`) | Partially integrated |
362378
| Graphdb/ANN foundation hardening lane | Branch-oriented lane claims exist in prior docs | Mainline currently exposes file-backed store baseline (`src/learning/store.ts`) | Not integrated on mainline |
363379
| Markdown reader governance refactor lane | Planned and partially implemented in branch | Mainline baseline only | Partially integrated |
364380

@@ -398,7 +414,7 @@ This dashboard aligns against the following requirement chain:
398414
| L2 Retrieval | explainable hybrid/vector retrieval + governance | Expanded in branch-oriented plans | Mainline file-backed baseline only (`src/learning/store.ts`) | Re-enter lane after concrete module evidence lands on mainline |
399415
| L3 Learning | mastery diagnostics + path/session loop | Expanded in branch | Partially integrated | Contract and integration parity |
400416
| L4 Interaction | agent conversation + focus/path pane runtime | Implemented in branch | M1-M4 baseline integrated on mainline | Expand capability surface via typed contract only |
401-
| L5 Governance | runbook, diagnostics, replay/autonomy controls | Expanded in branch | Earlier runbook baseline | Integrate operator and CI gates |
417+
| L5 Governance | runbook, diagnostics, replay/autonomy controls | Expanded in branch | Operator diagnostics persistence/triage/retention baseline integrated | Expand operator runbook automation and CI evidence depth |
402418

403419
## Verification Baseline
404420

docs/diataxis/zh/explanation/development-progress-dashboard.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,22 @@
352352
- `npm run test:agent-workspace:contracts`
353353
- `npm run verify:agent-workspace:runtime`
354354

355+
## 主线最新增量(2026-04-16 M7.8 运维回放分级与有界保留治理链路)
356+
357+
- 已在 `src/server.ts` 扩展运维诊断治理能力:
358+
- 新增 `GET /api/knowledge/operator/agent-workspace-diagnostics/triage`,输出 replay 风险分级摘要与 runbook 链接,
359+
- 新增诊断报告文件有界保留清理逻辑,确保落盘文件集合与索引上限(`AGENT_WORKSPACE_DIAGNOSTICS_MAX_ENTRIES`)一致。
360+
- 已扩展诊断摘要语义:
361+
- 每条诊断索引新增 `replayCandidateRate``replayRiskLevel``low|medium|high`)字段,用于运维分级研判。
362+
- 已补可执行证据:
363+
- `src/server.migration.test.ts` 新增 replay 分级摘要断言与保留上限断言。
364+
- 已加固 runtime 验证门禁:
365+
- `scripts/verify-agent-workspace-runtime.js` 新增 triage 路由与 retention helper 的 fail-fast 接线断言。
366+
- 验证证据:
367+
- `npm test -- src/server.migration.test.ts --runInBand --testNamePattern \"agent workspace diagnostics report|triage route summarizes replay risk\"`
368+
- `npm run test:agent-workspace:contracts`
369+
- `npm run verify:agent-workspace:runtime`
370+
355371
## 主线 vs 工作分支快照(2026-04-14)
356372

357373
| 能力切片 | 工作分支(`feat/learning-multi-tutor-adapter`| 主线(`origin/main`| 集成状态 |
@@ -360,7 +376,7 @@
360376
| Focus + learning-path 并排 pane 模型 | 分支已实现 | 已落入 dock 并排基线(`styles.css``path_styles.css``path_app.js`| 部分集成 |
361377
| Agent workspace 合同门禁测试 | 已实现(`src/agent_workspace.contract.parity.test.ts``src/agent_workspace.frontend.test.ts``src/agent_workspace.locale.contract.test.ts``src/agent_workspace.tauri.contract.test.ts`| 已落入基线门禁(`src/agent_workspace.contract.parity.test.ts``src/agent_workspace.frontend.test.ts``src/agent_workspace.runtime.integration.test.ts`| 部分集成 |
362378
| 结果呈现 allowlist/override fail-fast 治理 | 分支已实现 | M1 已集成(`src/frontend/agent_workspace.js` + parity tests) | 基线已集成 |
363-
| conversation turn 流式/重放/诊断扩展 | 分支已扩展 | 主线已落入 snapshot + trend/index/export 诊断基线`src/frontend/agent_workspace_runtime.js`| 部分集成 |
379+
| conversation turn 流式/重放/诊断扩展 | 分支已扩展 | 主线已落入 runtime snapshot+trend/index/export + sidecar 持久化/分级/有界保留治理基线`src/frontend/agent_workspace_runtime.js``src/server.ts`| 部分集成 |
364380
| graphdb/ANN 底座收敛 | 先前文档存在分支导向结论 | 主线当前为 file-backed store 基线(`src/learning/store.ts`| 主线未集成 |
365381
| Markdown 阅读器治理升级 | 分支已有规划与部分实现 | 主线为旧基线 | 部分集成 |
366382

@@ -400,7 +416,7 @@
400416
| L2 检索层 | 可解释混合/向量检索 + 治理 | 分支规划增强中 | 主线当前为 file-backed 基线(`src/learning/store.ts`| 待主线出现对应模块证据后再收敛 |
401417
| L3 学习层 | 掌握诊断 + 路径/会话闭环 | 分支增强中 | 主线部分集成 | 契约与集成一致性 |
402418
| L4 交互层 | agent 对话 + focus/path pane 运行时 | 分支已实现 | 主线 M1-M4 已落入基线 | 继续通过 typed contract 扩展动作面 |
403-
| L5 治理层 | runbook/诊断/回放与自动化 | 分支增强中 | 主线旧 runbook 基线 | 集成运维门禁 |
419+
| L5 治理层 | runbook/诊断/回放与自动化 | 分支增强中 | 主线已集成运维诊断持久化/分级/保留治理基线 | 扩展 runbook 自动化与 CI 证据深度 |
404420

405421
## 验证基线
406422

scripts/verify-agent-workspace-runtime.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,18 @@ function verifyAgentWorkspaceRuntime(repoRoot = path.resolve(__dirname, '..')) {
104104
serverSource.includes('/api/knowledge/operator/agent-workspace-diagnostics/latest'),
105105
'Missing diagnostics report latest route in src/server.ts'
106106
);
107+
assert(
108+
serverSource.includes('/api/knowledge/operator/agent-workspace-diagnostics/triage'),
109+
'Missing diagnostics report triage route in src/server.ts'
110+
);
111+
assert(
112+
serverSource.includes('cleanupStaleAgentWorkspaceDiagnosticsReports'),
113+
'Missing diagnostics retention cleanup helper in src/server.ts'
114+
);
115+
assert(
116+
serverSource.includes('AGENT_WORKSPACE_DIAGNOSTICS_MAX_ENTRIES'),
117+
'Missing diagnostics retention bound constant in src/server.ts'
118+
);
107119
assert(
108120
runtimeSource.includes('persistDiagnosticsReport'),
109121
'Missing persistDiagnosticsReport runtime surface in src/frontend/agent_workspace_runtime.js'
@@ -119,6 +131,8 @@ function verifyAgentWorkspaceRuntime(repoRoot = path.resolve(__dirname, '..')) {
119131
'frontend contract module exists',
120132
'conversation route wiring exists',
121133
'diagnostics report persistence routes exist',
134+
'diagnostics triage route exists',
135+
'diagnostics retention governance exists',
122136
'runtime diagnostics persistence surface exists',
123137
'agent workspace contract test suite passes',
124138
],

src/agent_workspace.verification.contract.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ describe('agent workspace verification script contracts', () => {
4747
expect(runtimeSource).toContain('/api/knowledge/operator/agent-workspace-diagnostics/report');
4848
expect(runtimeSource).toContain('/api/knowledge/operator/agent-workspace-diagnostics/index');
4949
expect(runtimeSource).toContain('/api/knowledge/operator/agent-workspace-diagnostics/latest');
50+
expect(runtimeSource).toContain('/api/knowledge/operator/agent-workspace-diagnostics/triage');
51+
expect(runtimeSource).toContain('cleanupStaleAgentWorkspaceDiagnosticsReports');
52+
expect(runtimeSource).toContain('AGENT_WORKSPACE_DIAGNOSTICS_MAX_ENTRIES');
5053
expect(runtimeSource).toContain('persistDiagnosticsReport');
5154
expect(browserSource).toContain('verifyAgentWorkspaceBrowser');
5255
expect(tauriSource).toContain('verifyAgentWorkspaceTauri');

src/knowledge.api.contract.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ describe('Knowledge mastery API contract wiring', () => {
1111
'/api/knowledge/store-diagnostics',
1212
'/api/knowledge/operator/agent-workspace-diagnostics/index',
1313
'/api/knowledge/operator/agent-workspace-diagnostics/latest',
14+
'/api/knowledge/operator/agent-workspace-diagnostics/triage',
1415
'/api/knowledge/operator/agent-workspace-diagnostics/report',
1516
'/api/knowledge/store/reload',
1617
'/api/knowledge/ingest',

src/server.migration.test.ts

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,10 @@ describe('server migration settings routes', () => {
465465
conversationRequests: 2,
466466
replayCandidateTurns: 1,
467467
userTurns: 2,
468+
replayCandidateRate: 0.5,
468469
capabilityEvents: 2,
469-
hasLastFailure: false
470+
hasLastFailure: false,
471+
replayRiskLevel: 'high'
470472
})
471473
})
472474
})
@@ -536,6 +538,99 @@ describe('server migration settings routes', () => {
536538
).resolves.toContain(reportId);
537539
});
538540

541+
test('triage route summarizes replay risk and retention stays bounded to max entries', async () => {
542+
const createReport = async (index: number) => {
543+
const pattern = index % 3;
544+
const userTurns = pattern === 0 ? 6 : pattern === 1 ? 5 : 4;
545+
const replayCandidateTurns = pattern === 0 ? 4 : pattern === 1 ? 1 : 0;
546+
const hasFailure = pattern === 2;
547+
return requestJson(
548+
port,
549+
'POST',
550+
'/api/knowledge/operator/agent-workspace-diagnostics/report',
551+
{
552+
source: `triage-test-${index}`,
553+
report: {
554+
snapshot: {
555+
conversationRequests: 1,
556+
replayCandidateTurns,
557+
turnCounts: {
558+
user: userTurns
559+
},
560+
capabilityEvents: [{ eventId: `cap_${index}`, status: 'success' }],
561+
lastFailure: hasFailure ? { source: 'triage-test', message: 'simulated failure' } : null
562+
},
563+
trend: {
564+
userTurns
565+
},
566+
index: {
567+
capabilityIndex: {
568+
operationIds: ['build_learning_path']
569+
}
570+
}
571+
}
572+
}
573+
);
574+
};
575+
576+
for (let index = 0; index < 45; index += 1) {
577+
const response = await createReport(index);
578+
expect(response.status).toBe(200);
579+
expect(response.body.success).toBe(true);
580+
}
581+
582+
const indexResponse = await requestJson(
583+
port,
584+
'GET',
585+
'/api/knowledge/operator/agent-workspace-diagnostics/index'
586+
);
587+
expect(indexResponse.status).toBe(200);
588+
expect(indexResponse.body.success).toBe(true);
589+
expect(indexResponse.body.count).toBe(40);
590+
expect(indexResponse.body.index.length).toBe(40);
591+
592+
const triageResponse = await requestJson(
593+
port,
594+
'GET',
595+
'/api/knowledge/operator/agent-workspace-diagnostics/triage'
596+
);
597+
expect(triageResponse.status).toBe(200);
598+
expect(triageResponse.body.success).toBe(true);
599+
expect(triageResponse.body.triage).toEqual(
600+
expect.objectContaining({
601+
maxEntries: 40,
602+
indexedEntries: 40,
603+
byRiskLevel: expect.objectContaining({
604+
high: expect.any(Number),
605+
medium: expect.any(Number),
606+
low: expect.any(Number)
607+
}),
608+
withFailureCount: expect.any(Number),
609+
replayCandidateRateAverage: expect.any(Number),
610+
topReplayReports: expect.any(Array),
611+
runbookLinks: expect.arrayContaining([
612+
expect.objectContaining({
613+
id: 'development-progress-dashboard'
614+
}),
615+
expect.objectContaining({
616+
id: 'm7-direction-requirements'
617+
})
618+
])
619+
})
620+
);
621+
expect(triageResponse.body.triage.topReplayReports.length).toBeLessThanOrEqual(5);
622+
const riskBucketTotal = triageResponse.body.triage.byRiskLevel.high
623+
+ triageResponse.body.triage.byRiskLevel.medium
624+
+ triageResponse.body.triage.byRiskLevel.low;
625+
expect(riskBucketTotal).toBe(40);
626+
expect(triageResponse.body.triage.byRiskLevel.high).toBeGreaterThan(0);
627+
628+
const diagnosticsDir = path.join(runtimeDataDir, 'agent_workspace_diagnostics');
629+
const diagnosticsFiles = (await fs.promises.readdir(diagnosticsDir))
630+
.filter((entry) => /^awd-[a-z0-9_-]+\.json$/i.test(entry));
631+
expect(diagnosticsFiles.length).toBe(40);
632+
});
633+
539634
test('server runtime path avoids synchronous filesystem APIs', () => {
540635
const serverSourcePath = path.join(__dirname, 'server.ts');
541636
const serverSource = fs.readFileSync(serverSourcePath, 'utf8');

0 commit comments

Comments
 (0)