Compare commits

..
Author SHA1 Message Date
weichen bd038b126b merge: dev to test (rc-v1.0.0-beta.7 promotion) 2026-09-20 14:04:30 +00:00
weichen 950f881968 merge: fix/workflow-seed-bootstrap-2026-09-20 2026-09-20 14:03:42 +00:00
weichenandCursor 7da2c1fdef docs(ops): occupy integration slot for rdev seed hotfix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 14:03:42 +00:00
weichenandCursor 079225495e fix(workflowdef): heal retired seeds and fall back published_by
启动种子不再依赖固定用户 id=1,并把白名单工作流的 retired 状态恢复为 active。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 14:03:30 +00:00
weichenandCursor badfc19812 docs(ops): claim rdev workflow seed hotfix
dev 库 rdev 停在 retired,test 库因 publishedBy 外键失败未发布研发工作流。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 14:03:30 +00:00
weichen e83de73fd0 merge: docs/module-decoupling-spec-2026-09-20 slot release 2026-09-20 13:25:44 +00:00
weichenandCursor a3d382c6d9 docs(ops): release integration slot after docs-only smoke
Record that go vet passed and the two short-test failures are docker registry EOF, not this documentation change.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:25:44 +00:00
weichen 133ceb454c merge: docs/module-decoupling-spec-2026-09-20 2026-09-20 13:23:54 +00:00
weichenandCursor a94745370d docs(status): record module standards and planned decoupling batches
Mark the documentation task done and hold the integration slot while the docs merge into dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:23:41 +00:00
weichenandCursor 22cac8dcbe docs(remediation): plan module decoupling batches A through G
Keep each hotspot on its own branch and mutex so a later code fix cannot spread across modules.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:22:59 +00:00
weichenandCursor fe46705b67 docs(system-design): list the module standards file in the design index
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:22:21 +00:00
weichenandCursor e71db3dce6 docs(system-design): add module communication and isolation standards
Give implementers one entry for narrow ports, the event bus, and the rule that a fault stays inside its module.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:22:11 +00:00
weichenandCursor 0504884e04 docs(audit): record remaining module coupling hotspots
Keep the modular-monolith baseline and name the seven places where a fault still crosses a module boundary.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:21:36 +00:00
weichenandCursor 6b43007d7a docs(ops): claim module decoupling spec and coupling audit
Register the docs-only audit so later batches do not collide with the architecture-docs mutex.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 13:21:03 +00:00
weichen 4ac8ca2308 merge: docs/p0-closeout-2026-09-20 2026-09-20 10:58:12 +00:00
weichenandCursor eaad5c74d4 docs(test): archive P0 hotfixes verification report and close gap rows
Record schema 58 / IDOR curl / credential rotation evidence and release the integration slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:58:12 +00:00
weichen 8a9fbd8280 merge: fix/credential-hardening-2026-09-20 2026-09-20 10:57:04 +00:00
weichenandCursor c47b437b22 fix(ops): stop hardcoding DB passwords and URL-embed git tokens
Load backup credentials from env/secrets files and push via a temporary credential helper so tokens never appear in process listings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:57:04 +00:00
weichen 8ef95891a4 merge: fix/runtime-panic-races-2026-09-20 2026-09-20 10:54:18 +00:00
weichenandCursor 48c985318c docs(ops): claim integration slot for runtime-panic-races merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:54:18 +00:00
weichenandCursor b4388934a0 fix(runtime): hold taskrun fanout lock, guard goroutines, and escape math XSS
Serialize appendEvent sends under the subscriber mutex, wrap worker/memory goroutines with recover, lock synchronous chat SendMessage, and escape KaTeX error HTML.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:54:18 +00:00
weichen 3a3a79769e merge: fix/authz-idor-hotfixes-2026-09-20 2026-09-20 10:42:58 +00:00
weichenandCursor 58f0ed65c1 docs(ops): claim integration slot for authz-idor merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:42:58 +00:00
weichenandCursor fad7fac044 fix(authz): close preference, session project, and recategorize IDOR gaps
Bind preference writes and session-scoped project reads to the authenticated principal, and require an owned session_id for recategorize so empty ids cannot touch all messages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:42:58 +00:00
weichen e347c0d138 merge: fix/capability-merge-00058-2026-09-20 2026-09-20 10:39:21 +00:00
weichenandCursor d4b38a273b docs(ops): claim integration slot for capability-00058 merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:39:21 +00:00
weichenandCursor 37fb1ba44e merge: feature/capability-enablement-impact-plan; renumber chat_summaries to 00058
Absorb stalled capability fixes and avoid goose out-of-order on schema 57 DBs by shipping chat_summaries as 00058.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:38:12 +00:00
weichen 43688fd4c3 merge: docs/p0-triage-2026-09-20 2026-09-20 10:37:18 +00:00
weichenandCursor 1313cf19b1 docs(ops): archive 2026-09-20 system triage audit and P0 remediation plan
Claim P0 hotfixes waves, correct schema snapshot to 57, and park non-P0 findings in long-term backlog.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:37:08 +00:00
weichenandCursor 518d5d6132 docs(ops): release integration slot after duty-reassign smoke
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:52:22 +00:00
weichenandCursor 5c9f9aa57c docs(ops): close duty-reassign task and release integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:52:14 +00:00
weichenandCursor 95329aad58 docs(test): archive duty-reassign and member-chat verification report
Record test-env evidence for chenwei stage chat and post-activation
PATCH duty reassignment after merge and rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:52:04 +00:00
weichen 9d98f1ae33 merge: fix/post-activation-duty-reassign-member-chat
Member stage chat without duties; controlled post-activation duty reassign.
2026-09-20 09:48:59 +00:00
weichenandCursor 2b96987ddd docs(ops): claim integration slot for duty-reassign merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:48:59 +00:00
weichenandCursor c3dad4c643 docs(ops): claim post-activation duty reassign and member chat task
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:48:27 +00:00
weichenandCursor 8e4beff5f8 feat(web): allow duty reassignment in frozen project settings
Show editable duty selects after activation when the user has
project:assign_lead, calling the new PATCH API instead of workflow-plan PUT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:48:27 +00:00
weichenandCursor 1497473186 feat(projectworkflow): controlled post-activation document duty reassign
Add PATCH /doc-tasks/{taskKey}/duties that updates live snapshot,
assignments, and document_records while blocking when a squad run holds
the document lease. Planning PUT remains PLAN_FROZEN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:48:27 +00:00
weichenandCursor a82bfdb6d1 fix(authz): allow project members stage chat without document duties
Live workflows still restrict document actions to duty holders, but
AllowedStageKeys now include active/completed stages so members can chat.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:48:19 +00:00
weichen 6d04d98c5f merge: docs/triage-task-done 2026-09-20 09:23:42 +00:00
weichenandCursor 69cae9e4e7 docs(ops): mark test-env triage task done
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:23:42 +00:00
weichen 89abc757f9 merge: docs/test-env-triage-report-2026-09-20 2026-09-20 09:23:31 +00:00
weichenandCursor 95880bf168 docs(test): archive test-env triage fixes verification report
Record E2E PASS for global unique names, member session visibility,
and asset raw preview; release integration slot and mark task done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:23:31 +00:00
weichen 213ad0159a merge: fix/test-env-triage-2026-09-20
Global unique project names, member chat session provisioning, and
project asset raw preview recovery for test-env triage.
2026-09-20 09:19:08 +00:00
weichenandCursor f603f63ca7 docs(ops): claim integration slot for test-env triage merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:19:08 +00:00
weichenandCursor 18a323c4dc test: cover asset raw round-trip and harden cross-user session upsert
Deny foreign user_id upsert without manage rights (403); unique project
names in ctxmgr PG fixture for global name index; add test-env data repair SQL.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:18:36 +00:00
weichenandCursor 21782751ab fix(server,web): serve project asset raw and recover preview after refresh
Add GET /assets/{id}/raw with project access checks; frontend falls back
to CAS by assetId or filename when local blob is gone. Align upload accept
list with backend whitelist and register binaries into CAS on chat upload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:14:12 +00:00
weichenandCursor aef3d6d5cb fix(server): create member chat sessions on invite and allow manager upsert
Project managers can register sess-p{N}-u{uid} for other members; adding a
member also ensures their private session so the sidebar is never empty.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:11:36 +00:00
weichenandCursor 28478bdca5 fix(db): enforce global unique project names across creators
Replace per-creator name uniqueness with a global index among
non-retired projects, and reject cross-user duplicate creates with 409.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:10:55 +00:00
weichenandCursor 638083cc74 docs(ops): claim test-env triage fixes (dup name / member session / preview)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:10:04 +00:00
weichen bee907ef7e merge: docs/test-env-beta6-verification 2026-09-20 08:06:24 +00:00
weichenandCursor 782b2dd2ce docs(test): archive beta.6 test-env assistant/squad verification report
Record rc-v1.0.0-beta.6 C-level evidence (pi-agent dialogue, intake docs,
12 regressions) and flip CURRENT to test schema 56 with idle integration slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 08:06:24 +00:00
weichen 7a6cfeefeb merge: dev to test (rc-v1.0.0-beta.6 promotion) 2026-09-20 07:22:42 +00:00
weichen 9f29b0badb merge: docs/bug-hunt-2026-09-20-closeout 2026-09-20 07:05:51 +00:00
weichenandCursor c7ee6b825e docs(ops): close bug-hunt permissions-uploads task after merge to dev
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:05:51 +00:00
weichen 032fdb050f merge: fix/bug-hunt-2026-09-20-permissions-and-uploads 2026-09-20 07:05:34 +00:00
weichenandCursor 6800a2af29 docs(ops): record permissions/uploads bug-hunt audit and short-term task
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:05:06 +00:00
weichenandCursor c8dbefe8a1 fix(web): align settings CAS, PDF preview, and collaboration UX guards
Wire expected_revision, blob PDF framing, mustChangePassword session rewrite,
client_key project create, no-project send disable, and right-rail persistence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:05:06 +00:00
weichenandCursor 5cd22c7327 fix(authz): harden permissions, chat gate, and project create idempotency
Add project:manage_members, CSP frame-src, task-run member view, CreateUser
tx error handling, ERR_NO_PROJECT chat gate, and creator-scoped project
name/client_key uniqueness to stop duplicate creates and auth gaps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:04:57 +00:00
weichen 5a5a91dd7f feat(docrevision): keep candidate estimates separate from committed reports
A candidate used the same report later attached to the version, so a preview could be treated as the formal result. Proposed reports now close on replace or reject, and only the commit writes an authoritative successor.
2026-09-20 05:15:41 +00:00
weichenandCursor db1706cd24 feat(docrevision): send clipped diff text to the change-report narrator
The narrator only received counts, so it could not describe the actual change. Caps keep the full document out and leave the input digest unchanged; the flag stays off.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 05:03:31 +00:00
weichenandCursor 686f739b19 fix(pi-agent): enforce a no-tool reasoning profile
语义摘要、变更叙事和 U9 分段改为请求 reasoning。该 profile 的 argv 使用 --no-tools 且不加载搜索扩展;未知 profile 拒绝启动。文档生成仍保留读写工具。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 04:59:15 +00:00
weichenandCursor 848a0457a0 fix(chat): stop treating failed summary writes as durable
新增 chat_summaries 迁移。数据库写失败会返回错误并标明仅本进程可见。test_manager 血缘改用文档版本,不再写死 1。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 04:02:41 +00:00
weichenandCursor 033462a4e6 fix(authz): separate capability readiness from configured flags
管理台不再把开关值当成能力已接入。lineage 读取必须落在 URL 项目内,并按两端文档可见性裁剪,跨项目或不可见文档只返回空列表。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 03:45:16 +00:00
weichenandCursor d3364f9125 docs(capability): record enablement research and remediation plan
把“看似实现、实际未启用”的复核、三条独立轨道和七视角审阅落盘,避免后续把未接线开关当成可以上线。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 03:45:16 +00:00
weichen 8fdcd983a6 docs(ops): record test promotion rc-v1.0.0-beta.5 and release integration slot 2026-09-20 01:10:43 +00:00
weichen dec963c16f merge: dev to test (rc-v1.0.0-beta.5 promotion) 2026-09-20 01:07:10 +00:00
weichen 0fd765a392 docs(test): record full deep test report for dev and test promotion 2026-09-20 00:48:11 +00:00
weichen bcbf4eba1c fix(pi-agent): register both MiniMax-M2.7-highspeed and MiniMax-M3 in models.json 2026-09-20 00:47:50 +00:00
weichen f47e40edad test(server): align test_manager task key to tm_system_verification in e2e test 2026-09-20 00:45:33 +00:00
weichen 97b868a942 docs(arch): allow squad in intent and workflowdef in squad and template 2026-09-20 00:44:47 +00:00
weichen 24bc4e6a2f merge: fix/audit-remainder-closeout (audit remainder closeout M1-M15, web modularization, rdev matching, schema 53) 2026-09-20 00:43:33 +00:00
weichen 89e8fb92b0 docs(ops): occupy integration slot for dev sub-branch merge, deep test and test promotion 2026-09-20 00:43:28 +00:00
weichenandCursor 3ae13bfae2 docs(test): record the U7 restart matrix and the gate follow-up
Postgres and app reach ready in about a second. Vite cold cache is not the old ten-second stall, and the login form was not measured.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 15:39:49 +00:00
weichenandCursor b48a832281 fix(squad): score only the first review-minutes table
A later standards table in the same section was counted as issue rows and failed the saved P3 sample.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 15:39:49 +00:00
weichenandCursor 6bd338e273 test(rdev): record the three real PI samples on dev
Software-plan N/A stayed closed and the proposal completed, but the planning review finished quality_failed at score 20. The poller now treats that status as terminal so it does not spin until timeout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 14:33:25 +00:00
weichenandCursor 56a8719863 refactor(web): move the workbench shell out of App
Session state stays in App. The shell, rights dialogs, and project modals now render from WorkbenchView, so App no longer mounts AppShell itself.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 14:11:32 +00:00
weichenandCursor 8a9599fbb0 refactor(web): render the chat column outside App
The workbench shell still owns session and modal state. Message stream, filters, and the composer now live in ChatColumn so App stops assembling that column inline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:57:10 +00:00
weichenandCursor b3a1305e46 docs(test): record twenty-run slow-network login and app restart
The rebuilt bundle stays under the draft login budgets on this machine. Restart-to-health is under half a second, and the wider restart matrix is still open.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:35:52 +00:00
weichenandCursor 69e2cd259d refactor(web): render the active document column outside App
The revision toolbar, file preview, and governance bars stay with the document pane so the workbench shell no longer owns that column.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:32:39 +00:00
weichenandCursor 26d14b534b docs(test): record schema 53 rebuild and login fanout on dev
The rebuilt workbench issues one member request and one session list request. Slow-network samples improved, but twenty-run percentiles and the restart matrix are still open.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:22:38 +00:00
weichenandCursor 404defced2 test(server): reject non-member comment and audit reads on postgres
The in-memory authorizer treats any positive user id as a member, so the HTTP negative has to run against a real project row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:22:37 +00:00
weichenandCursor c49637cbb5 fix(db): restore applied goose files so fresh migrate can parse
The checksum-immutable note inside 00001 contained a goose annotation and would fail a new database. Keep that warning out of files goose already applied.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:22:37 +00:00
weichenandCursor 4b2d92a1be docs(test): record login-load baseline against Vite and deployed dev
The current workbench stays at one member fetch across 20 logins, while the deployed bundle still fans out. Slow-network samples stay diagnostic until the container is rebuilt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 13:00:39 +00:00
weichenandCursor eabaadd2a0 test(web): record login waterfall and init request counts
Give the initial-load baseline a repeatable probe that strips query strings and can assert the login member fanout stays on the current project.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:57:12 +00:00
weichenandCursor 95f0e7bcf9 refactor(web): share and save freeform docs from one hook
Keep private-library share, revoke, delete, and save-to-private off the workbench shell so those side effects stay testable without growing App.tsx.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:57:12 +00:00
weichenandCursor 8de29466e1 refactor(web): persist project members from one hook
Refresh the roster and workflow documents only after the member write succeeds, so a failed add does not invent a local session.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:11:52 +00:00
weichenandCursor a29e98096a refactor(web): create projects from one hook
Remember the new project id as soon as create succeeds so a later member failure retries members instead of creating a second project.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:09:28 +00:00
weichenandCursor 9f39fbaaf3 refactor(web): handle interactive cards from one hook
Keep plan confirmation, reject, undo, and approval on the same card so a revision conflict still reconciles before the card changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:07:08 +00:00
weichenandCursor 57873f6c84 refactor(web): retry chat and task runs from one hook
Keep reconnect on the existing run id so a dropped stream does not start a second task.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:05:01 +00:00
weichenandCursor f9c2b3acdf refactor(web): edit document blocks from one hook
Apply a controlled block only after the server patch succeeds, and keep insert, move, delete, and comments on the same document state.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 12:00:43 +00:00
weichenandCursor 52f69fe180 refactor(web): send chat messages from one hook
Keep attachment registration, task dispatch, and the demo shortcuts on the same path so a failed upload still blocks before any local message is stored.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:46:07 +00:00
weichenandCursor c22faecfcb refactor(web): move document lifecycle actions into a hook
Keep claim, review, and approval on one server record so the open document and the sidebar stay in the same state.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:40:03 +00:00
weichenandCursor 22ea4c31ed refactor(web): sync server documents from one hook
Keep freeform append, workflow reconcile, and lease polling together so a failed list cannot wipe local docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:33:03 +00:00
weichenandCursor 113dea4ac5 refactor(web): hydrate controlled documents from one hook
Keep the editor gate, cancel, and error skeleton together so App no longer owns the fetch path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:29:40 +00:00
weichenandCursor 27c1be86d5 refactor(web): move login workspace sync out of App
Project list, member roster, and session fetch ran as four effects inside the workbench component. They now share one hook so the entry file is not the only place that knows the login startup order.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:05:29 +00:00
weichenandCursor bfe8cb1407 refactor(web): persist the workbench from one hook
Session, project, and deliverable caches were written from scattered effects, and the legacy message migration ran twice on mount. One hook keeps that write path in a single place.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 11:01:44 +00:00
weichenandCursor 63b0f72081 feat(web): load the formula engine only when math appears
The login entry no longer ships KaTeX. Chat bubbles and document text render formulas after a dynamic import, and rich-text copy does the same.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:57:49 +00:00
weichenandCursor dba8139d56 feat(workflow): namespace task keys without breaking old instances
Published manifests now use bd_/pm_/tm_/sw_ prefixes so workflows cannot share a doc id. Frozen instances keep the old keys; lookup, templates, and duty checks treat the two names as the same task.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:50:25 +00:00
weichenandCursor 2a0f8b4549 docs(ops): record the frontend test and build gate
npm test and the production build passed on this branch. The entry bundle stays near 1 MB, and CURRENT still correctly says schema 52 until the containers are rebuilt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:34:50 +00:00
weichenandCursor 7e0f3cbf9c feat(web): show the rdev start prerequisite before activation
Selecting the design-control workflow now repeats the server rule: business handover must finish with an approved CDO quote first. Other workflows stay quiet.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:33:11 +00:00
weichenandCursor 6367f865d5 feat(web): fold long workflow stages and batch their approval
Later stages with more than four documents start collapsed, and one action can put the whole stage under human approval or take it back out. The workflow chip still names the design-control flow when the catalog has not loaded.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:30:32 +00:00
weichenandCursor 5bf10c7536 docs(ops): keep the login fan-out note next to the rdev matcher
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:27:08 +00:00
weichenandCursor 2fbb5bab49 feat(intent): match rdev document names when the user asks to generate
生成项目建议书 now resolves to rd_proposal. Longer titles win, so 系统设计方案 is not mistaken for the shorter business-stage phrase, and an explicit generate command is no longer swallowed by a progress question.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:26:57 +00:00
weichenandCursor 890d2fd14e fix(web): stop login from fetching every project member list
The project list is already limited to the current user, so other rosters wait until the member panel opens. Session reload no longer follows project updates, and a newer response cannot overwrite an older user.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:22:04 +00:00
weichenandCursor b550911667 feat(squad): load rdev overlays and enforce document gates
Each rdev step now gets a role-filtered overlay so writing discipline stays out of the template. User needs, system requirements, review minutes, and upload indexes fail the quality gate when IDs, decisions, or attachment indexes are incomplete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:12:10 +00:00
weichenandCursor 93ee98af0e feat(squad): apply rdev stage step overrides and aliases
Stage-specific squad steps now win over the kind default, including always-on regulatory and searcher roles. Each of the 60 tasks carries its writing hint and Chinese alias so lookup and the writer accept line use them.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 10:05:26 +00:00
weichenandCursor 8365de3426 docs(ops): keep the load and auth notes next to the rdev remainder
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:58:51 +00:00
weichenandCursor 754cba764c feat(squad): gate rdev regulatory steps on complexity tier
Listed tasks still get a regulatory step when complexity is unset or high. Medium and low skip it, and the squad model now comes from SQUAD_MODEL_ID or MINIMAX_MODEL_ID instead of a fixed name.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:58:40 +00:00
weichenandCursor 32d838285d fix(auth): resolve session and user status once per request
/auth/me was authenticating again after the middleware had already done it, and the session lookup queried user status in a second round trip. Reuse the request principal and join status into the session read so a revoked token still fails on the next request.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:54:10 +00:00
weichenandCursor 17f7fed1db feat(web): load export, preview, and charts only when opened
The login shell was downloading the document engines with the workbench. Those modules now load on click or when a matching block appears, and a failed chunk can be retried without submitting an edit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:51:04 +00:00
weichenandCursor 1b17e01ce7 docs(ops): record frontend gate and the memory authz limit
The branch frontend suite and production build passed. Cross-user document comments still need a Postgres negative because the in-memory authorizer is intentionally open.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:42:30 +00:00
weichenandCursor 952a94b6d5 fix(docrevision): ack content projection only after the fact source is written
The human ledger and the document body are different stores. Record the projection intent in the same transaction as the ledger, and clear it only when the body write succeeds so a retry cannot append a second revision.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:35:14 +00:00
weichenandCursor fc32ba3dc3 fix(web): version chat window cache and cover cross-user session list
Drop window-cache payloads that lack a schema field. Prove a non-owner listing another user's sessions is forbidden. Correct the stale test schema note in CURRENT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:28:11 +00:00
weichenandCursor 2a666df3c1 fix(events): hold aggregate gaps on production claim
PostgreSQL claim now uses the same next-version rule as MemoryBus, and checkpoints only move forward. A later version cannot be leased while an earlier one is still missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:24:51 +00:00
weichenandCursor 01ca861e94 docs(ops): record which audit remainder items are closed
Keep M7, M15, the frontend split, and the red-line features open so the next pass does not treat them as done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:20:07 +00:00
weichenandCursor d4041a4f0c fix(coordinator): use the caller name and reject non-decimal user ids
Ambiguous consult only redirects on low confidence, and the testing template greets the signed-in user instead of a hardcoded name. Session tokens no longer parse as user id 0. Live chat sessions now evict the oldest entry at a hard cap.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:19:36 +00:00
weichenandCursor 265f09c1f2 fix(server): cache health probes, surface SSE marshal errors, fail closed on missing duties
Health checks reuse a two-second snapshot and bound the schema query. Task SSE writes an error frame when an event cannot be encoded. ResolveDocTask errors when the frozen plan has no duty row, while explicit none-duties stay zero. Drop the unwired semantic-summary replace env, record the intentional dev versus release model split, document the test/main cutover path, and archive pre-goose SQL.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:16:18 +00:00
weichenandCursor 4c34e8a503 fix(server): close security headers, lease clamp, replay digest, double start
Add nosniff, frame denial, referrer policy, and a self-origin CSP. Clamp human and squad lease TTLs and require author edit rights before a human lease. Include DryRun in replay digests so a dry-run approval cannot authorize apply. Stop Server.Start from swallowing a second Runtime.Start.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 09:12:17 +00:00
weichenandCursor 62ce2781ae docs(ops): record pre-test promotion readiness review
Capture the read-only check that planned capabilities are wired, while dev is not ready to merge into test until the container is rebuilt and the remaining gates run.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 08:36:58 +00:00
weichen 66421b162d merge: docs/audit-remediation-backlog (audit batch 4 report + medium backlog) 2026-09-19 07:55:48 +00:00
weichenandCursor d9cd7ebb82 docs(ops): close audit batch 4 report and park medium leftovers
Critical/high fixes are already on dev. Record the frontend test report, restore the audit note, and move remaining medium/low items into long-term so they are not treated as release blockers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 07:55:43 +00:00
weichen d73bc79800 merge: fix/audit-b4-frontend (audit batch 4: markdown XSS, unread rollback, excel preview cap) 2026-09-19 07:53:36 +00:00
weichenandCursor 6c28fca98f fix(web): close markdown placeholder XSS and unread/excel edge cases
- Escape KaTeX fallback HTML and salt math/code placeholders per render
- Roll back optimistic unread marks when POST /chat/read fails
- Reset MessageStream scroll baseline when the session changes
- Preview only the first 1000 Excel rows and say so in the sheet header

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 07:53:31 +00:00
weichen 84ba1c97d7 docs(test): audit batch 3 test report and slot release 2026-09-19 07:49:45 +00:00
weichen a2a49a64f5 merge: fix/audit-b3-sse-events (audit batch 3: sse heartbeat, task idempotency, write deadline, fencing log) 2026-09-19 07:49:15 +00:00
weichenandCursor b65e8fb642 docs(db): mark baseline and seed migrations as checksum-immutable
Goose checksums forbid rewriting applied files. Document that 00001-00009
have no down migration and that 00012's unconditional DELETE is demo-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 07:49:01 +00:00
weichenandCursor 0531462acc fix(sse): bound heartbeat lifetime and reuse idempotent task streams
- Wait for the chat SSE heartbeat goroutine to exit before the handler
  returns, so it cannot write a recycled connection
- Extend /tasks/run write deadline to 75m so long sync runs are not cut
  by the global 120s WriteTimeout before the response is written
- Reuse an existing task run on the SSE path when the idempotency key
  already belongs to the same user/session/project
- Log stale fencing on event ack so unbounded replay is observable

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 07:49:01 +00:00
weichen 9fa29bec42 docs(test): audit batch 2 test report 2026-09-19 06:03:31 +00:00
weichen c3c2b39abd docs(ops): record audit batch 1+2 merges and slot release 2026-09-19 06:02:38 +00:00
weichen 08f4e0bbf8 merge: fix/audit-b2-authz-hardening (audit batch 2: principal identity, docgov access, rate limit, compose secrets) 2026-09-19 06:01:00 +00:00
weichenandCursor 2dd8f46e64 fix(server): login/register rate limiting + compose secret hygiene (H4/H8/M8)
- H4: sliding-window rate limiter (10 attempts / 5min per IP+username)
  on login and register; successful login resets the counter; pure
  stdlib, no new dependency
- H8: docker-compose.test.yml DB/ADMIN passwords now :?required (align
  with main); docker-compose.main.yml AUTH_REGISTRATION_ENABLED
  defaults to false
- M8: fix FAV_PUBLISHER_ENABLE -> FAV_PUBLISHER_ENABLED typo so the
  gate test actually guards the real flag

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 06:00:30 +00:00
weichenandCursor d2903a1662 fix(server): enforce principal identity and docgov project access (H1-H3)
- H1: log legacy test-principal fallback (path/method/remote_addr) via
  slog.Warn so silent unauthenticated access is observable
- H2: AddComment/Claim now derive actor ID/Name/Role from the auth
  principal and server-side doc duty resolution (resolveDocGovRole),
  never from request body; GetDocument/ListComments/ListAuditLogs now
  require project membership via requireDocGovDocAccess
- H3: handleGetChatTurn asserts session ownership; handleListChatSessions
  and handleGetUserContext reject cross-user user_id (403) and stop
  defaulting to user id=1

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 05:33:38 +00:00
weichen 844f757af3 merge: fix/audit-b1-data-consistency (audit batch 1: docgov persist errors, session race, workflow plan tx, ctx threading) 2026-09-19 05:04:18 +00:00
weichenandCursor a81db16cdd fix(server): thread request ctx through session bootstrap, drop Background DB calls
- getOrCreateSession now takes ctx; GetSessionOwnerID/
  RestoreSessionContext/CompilePromptGuidance run under
  context.WithTimeout(5s) instead of context.Background()
- SyncRecentDialogue's rolling summary uses a 30s timeout context
  instead of Background, so client disconnect cancels the LLM call

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 05:03:01 +00:00
weichenandCursor e2b13406db fix(projectinstance): atomic plan save and correct completed_by attribution
- Add Store.SavePlanWithRevision: single-transaction planning upsert +
  revision bump (bump first with optimistic lock, conflict rolls back
  before any plan write), closing the SaveWorkflowPlan split-transaction
  race where plan content and revision could diverge
- AdvanceStage now takes operatorID and writes completed_by explicitly
  instead of SELECT activated_by, so the completing operator is the
  actual advancing user, not the original activator
- Service.SaveWorkflowPlan/AdvanceStage pass userID through; memStore
  implements SavePlanWithRevision under its single mutex

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 05:00:01 +00:00
weichenandCursor c7eab1f7d1 fix(chat): add RWMutex to Session and snapshot accessors to close data race
- Session gains mu sync.RWMutex + SnapshotMessages/AppendMessage/
  TouchLastAccessed/SetProjectID/Project accessors
- sendMessageInternal, hydrateVisibleHistory, getOrCreateSession,
  cleanStaleSessionsLocked, handleChat, handleChatStream,
  enrichSessionWorkflowStage, bindSessionDocumentSummaryReader all use
  locked accessors instead of raw field access
- ProjectID mutation now goes through SetProjectID (only when changed),
  closing the cross-project pollution window in handleChat/handleChatStream

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 04:55:55 +00:00
weichenandCursor 11f375f53d fix(docgov): surface lease/audit persist failures and read back fencing token
- persistLeaseLocked now returns error; AcquireLease rolls back in-memory
  lease on DB failure so memory and PG stay consistent
- appendAuditLocked uses request ctx and logs audit INSERT failures
  instead of swallowing them with context.Background()
- loadDocumentFromDBLocked now SELECTs lease_fencing_token so fencing
  survives process restart
- SaveDocumentContent/RecordDocumentViewed/RecordDocumentEdited/
  DecideModificationProposal/SetDocumentWorkDir log persist failures
  via slog.Error instead of silent _, _

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 04:50:40 +00:00
weichen e8ed33b0aa merge: fix/remove-control-center leftover cleanup 2026-09-19 03:55:40 +00:00
weichenandCursor 597aa76e60 docs: record leftover Control Center cleanup
The untracked node_modules tree and the local feature branch are gone.
The remote branch was left in place.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:55:40 +00:00
weichen d21f024dbe merge: fix/remove-control-center health closeout 2026-09-19 03:43:22 +00:00
weichenandCursor 9f2c510b62 docs(test): record dev health after Control Center removal
The rebuilt dev service returned 200 with schema 52.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:43:22 +00:00
weichen 03ec351643 merge: fix/remove-control-center 2026-09-19 03:42:23 +00:00
weichenandCursor 87f6b68001 docs(test): record Control Center removal verification
The short tests, archtest, and product web build passed after the
module was deleted.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:42:23 +00:00
weichenandCursor 14f75df1ac refactor: remove Control Center from this repository
Progress tracking now lives in a separate project. Drop the server,
docs, and module-boundary entries without restoring engineering-dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:40:00 +00:00
weichen 2641045547 merge: feature/control-center-server (supersede engineering-dashboard) 2026-09-19 03:21:12 +00:00
weichenandCursor 55fa8ddfcd docs(test): keep the merge-gate command log
*.log is ignored, so the vet/test/build transcript is stored as verify.txt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:21:05 +00:00
weichenandCursor be0a71cf7f docs(control-center): close the merge gate
Record the unit, live LLM, and SPA walkthrough evidence, and mark the
control-center row done now that engineering-dashboard is superseded.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:20:22 +00:00
weichenandCursor 0929f58aef chore(control-center): bind the database port to loopback
The compose file published 5440 on all interfaces. Match the other
environment databases and listen only on 127.0.0.1.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:20:22 +00:00
weichenandCursor 69524205b0 fix(audit): ignore MiniMax think blocks when parsing findings
Real highspeed responses wrap reasoning in think tags that contain
brackets, which made the JSON span extractor fail before the array.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 03:04:25 +00:00
weichenandCursor 049a18d5bc test(controlcenter): cover config pick, store, and leases
Gate the merge on unit coverage for the three packages that previously
had none: env precedence, migrate/query, and claim/heartbeat/reap.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 02:58:03 +00:00
weichenandCursor b3093f1b60 merge: dev into feature/control-center-server
Keep Control Center and drop engineering-dashboard. Resolve CURRENT
claim rows and module-boundaries by removing the superseded dashboard
entry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 02:55:35 +00:00
weichen 283f39df34 merge: fix/user-manual-dist 2026-09-18 09:53:32 +00:00
weichen 0d94556c4f docs(ops): 记录 dist 补录合入 2026-09-18 09:53:32 +00:00
weichen 65df9d13ed docs(user-manual): 强制纳入 dist 交付物(html/pdf/docx)并补充重建说明 2026-09-18 09:53:17 +00:00
weichen 8142389b4b merge: feature/user-manual slot release 2026-09-18 09:51:32 +00:00
weichen f38e1d5ee6 docs(ops): 释放集成槽位(user-manual 冒烟 PASS) 2026-09-18 09:51:10 +00:00
weichen 6c2fbc45a3 merge: feature/user-manual 2026-09-18 09:49:04 +00:00
weichen f746a59862 docs(ops): 占用集成槽位(feature/user-manual 合入 dev) 2026-09-18 09:48:13 +00:00
weichen f6f34b87cb merge: docs/wave7-roadmap-orchestration 2026-09-18 04:43:32 +00:00
weichenandCursor 60120b7977 docs(test): archive Wave 7 orchestration confirmation report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:43:19 +00:00
weichenandCursor e64bf5ca8b docs(ops): mark Wave 0-7 done and flag Control Center conflict
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:22:22 +00:00
weichenandCursor a42e7902d7 docs(remediation): mark Wave 7 done and link orchestration record
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:21:56 +00:00
weichenandCursor 7d8029978e docs(ops): record Wave 7 roadmap orchestration confirmations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:21:37 +00:00
weichen a88ed85cf3 merge: docs/wave6-doc-drift 2026-09-18 04:13:48 +00:00
weichenandCursor 4d7b1b5d25 docs(ops): close Wave 6 doc-drift D-1~D-6 and update SSOT
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:13:29 +00:00
weichenandCursor 28e1fa2e4b docs(project): align remaining-blocker section with gap-matrix production_ready=yes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:11:15 +00:00
weichenandCursor 6b70d28b2e docs(backlog): sync D3/D7 status with FEATURE-MATRIX
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:11:15 +00:00
weichenandCursor 447b830ff5 docs(ops): backfill closure note on intent dual-tab handoff
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:11:15 +00:00
weichenandCursor 8e17814cea docs(adr): accept modular-monolith-decoupling ADR (Phase 1/2 landed)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:11:15 +00:00
weichenandCursor eee392d93d docs(ops): archive completed PU8/W4 U9-U12 short-term tasks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:10:53 +00:00
weichenandCursor ca0d334d57 docs(ops): flip PU8 U9-U12 contracts to status done
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:10:48 +00:00
weichen 688d9d30eb docs(user-manual): 新增系统使用说明书(33 张 dev 真实截图 + md/html/pdf/docx 四格式) 2026-09-18 04:08:49 +00:00
weichen 2ce2625c94 merge: fix/wave5-deadcode-decisions 2026-09-18 04:02:26 +00:00
weichenandCursor 60b17c03ab docs(ops): close Wave5 deadcode decisions
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:19 +00:00
weichenandCursor 2e14b3563c fix(web): remove dead notification/workflow/settings components and orphaned APIs (X-5)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichenandCursor da62c49952 docs(sysadmin): annotate unwired system_settings keys as phase-2 backlog (X-4)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichenandCursor 527e6daa99 docs(swboot): mark 00048 tables deferred to SWBOOT-10 (X-3)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichenandCursor 6c61a5bc37 docs(ctxmgr): seal SEMANTIC_SUMMARY_REPLACE with decision link (X-2)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichenandCursor a41836dec0 fix(intent,sysadmin): delete dead SEMANTIC_FALLBACK_ENABLED flag (X-1)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichenandCursor e0f6d5991c docs(ops): plan Wave5 deadcode decisions (X-1~X-5)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 04:02:18 +00:00
weichen a12c94700f merge: fix/wave4-hardening-r1-r8 (slot release) 2026-09-18 03:47:59 +00:00
weichenandCursor e30ae4b96b docs(ops): 释放 Wave4 集成槽位为 idle
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:47:59 +00:00
weichen c4db565c40 merge: fix/wave4-hardening-r1-r8
Wave 4 隐患加固 R-1~R-8 合入本地 dev。
2026-09-18 03:47:46 +00:00
weichenandCursor e4c53a4ccd docs(ops): Wave4 R-1~R-8 收口
归档 test-report 与 assets;CURRENT/remediation 标 Wave 4 done;勾选跨用户会话挂靠负例。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:47:46 +00:00
weichenandCursor e8d2d86542 test(docrevision): hydrate 负例写入类型错误 JSONB 并先落 blob
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:46:22 +00:00
weichenandCursor c1ea8f156c fix(server): 清除 NewSession ProjectID=1 占位以免误触发项目鉴权
非项目会话创建时 ProjectID 归零,避免跨用户负例在 PG 上被 ERR_FORBIDDEN 误挡。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:46:21 +00:00
weichenandCursor 4473a2ae10 test(web): 补 401 fail-fast、单帧容错、abortAllSessions 单测
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor be9b855783 fix(web): 登出主动 abort 所有会话在途流(R-8)
新增 abortAllSessions;logout 先中止全会话再清 session。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor 21049607f4 fix(web): SSE 重连 401/404 fail-fast,单帧解析容错(R-7)
TaskRunHttpError 携带 status;非法 JSON 帧跳过并保留 seq。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor ce7d1b8ac5 fix(server): 后台 ticker 纳入 Shutdown;vault Drain 告警;bizdev 心跳超时(R-6)
reminder/vault 可停止;Drain 失败 slog.Warn;心跳/释放 lease 使用 10s 超时。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor 58b69a2b08 fix(docrevision): pg_store JSONB 反序列化失败显式报错(R-5)
hydrateDocLocked 损坏字段不再静默零值化;补 PG 负例测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor e25a197410 fix(ctxmgr): memTurns 改为实例作用域并加 TTL/容量淘汰(R-4)
消除跨 ContextManager 实例共享;超过容量时淘汰 2h 陈旧回合。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor 207e26241c fix(events): dispatcher Handlers 读路径加 RWMutex(R-3)
Register 写锁不变;shadowScan/handle 读路径 RLock,消除导出字段无锁读隐患。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:44:08 +00:00
weichenandCursor 9038c65329 fix: 补齐 rows.Err() 检查(R-2,其余包)
覆盖 kb/storage/projectworkflow/docgov/freedoc 与两个 document CLI。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:40:24 +00:00
weichenandCursor b53a97b36d fix(ctxmgr): 补齐 rows.Err() 检查(R-2,ctxmgr 包)
A 类硬失败返回;manager 降级读路径用 slog.Warn 保持既有容忍语义。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:40:24 +00:00
weichenandCursor ba1fc71f16 test(server): 跨用户会话挂靠负例测试(PG + 内存双实现)
覆盖 chat / chat/stream / chat/sessions 三条路径;受害者续用不受影响。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:39:08 +00:00
weichenandCursor a805a6bfd7 fix(server): chat/sessions upsert 与任务创建强制取 principal(R-1b)
upsert 忽略客户端自报 user_id;EnsureChatSessionOwned 拒绝跨用户挂靠。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:39:08 +00:00
weichenandCursor ecdf1fc833 fix(server): getOrCreateSession 增加会话归属校验(R-1a)
调用方传入 callerUserID;持久层与内存会话归属不匹配时返回 SESSION_FORBIDDEN;覆盖 NewSession 默认 UserID=1 占位。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:39:08 +00:00
weichenandCursor 426af51365 fix(ctxmgr): EnsureChatSession 归属 COALESCE 改为已有值优先(R-1c)
防止跨用户通过 upsert/消息落库覆盖已绑定的 chat_sessions.user_id;新增 EnsureChatSessionOwned。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:39:08 +00:00
weichen 32932e468e merge: fix/wave3-test-debt-blindspots 2026-09-18 03:02:59 +00:00
weichenandCursor 2ebf6adb2d docs(ops): close Wave 3 test-debt-blindspots (S-1/S-2/S-4/S-5)
Archive isolated PG reconcile evidence, mark gap-matrix debt closed, and
release the integration slot for Wave 4 hardening.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:02:59 +00:00
weichenandCursor 17f430b267 fix(web): reuse projectSettingsError envelope across API clients
Prefer error_code when present and route projectMembers/freeformDoc/
taskRuns/chatSessions failures through the shared structured parser.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:02:06 +00:00
weichenandCursor 3b4c9cfddf test(web): add npm scripts for all e2e specs; retire redundant revision smoke
Eliminate DOCREV_E2E_BASE_URL dual gating by deleting the one-assert smoke
spec covered by document-revision-runtime UI-10, and expose per-spec scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:02:06 +00:00
weichenandCursor a99e3f725f test(server,app): delete dead resume-workspace test; clarify plan_owner redirect
Remove the skipped client work_dir resume coverage that targeted a deleted
entry point, and document why the real-PI stop-gate stays redirected to
internal/server to avoid an import cycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 03:02:06 +00:00
weichenandCursor c6e7656f8e docs(ops): sync Wave 2 closeout checklist into dev lineage
Carry the done checklist and test-report link that lagged the Wave 2
merge tip so Wave 3 starts from a consistent ops state.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:59:03 +00:00
weichen 423f7e7413 merge: fix/wave2-config-flag-align 2026-09-18 02:29:07 +00:00
weichenandCursor 24c0e5b16a docs(ops): close Wave 2 config flag alignment (E-3/E-4/E-6/E-7/E-9)
Archive three-env compose/env smoke evidence, mark remediation Wave 2
done, and release the integration slot for Wave 3.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:29:07 +00:00
weichenandCursor 8d97dd6b18 test(config): add compose flag declaration regression tests
Pin E-3/E-4/E-6 compose declarations so dead runner config and missing
flag wiring cannot silently regress.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:26:47 +00:00
weichenandCursor 55a539c551 chore(infra): drop CURSOR_RUNNER_PORT from env examples
Placeholder cursor-agent service is gone; keep CURSOR_API_KEY/MODEL/BIN
for the local cursor-cli subprocess backend.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:26:47 +00:00
weichenandCursor e0aabecf59 fix(infra): declare MULTI_INTENT_PLAN_TIER and U9-U12 flags in all compose envs
Also declare SEMANTIC_SUMMARY_SHADOW and PI_CHANGE_REPORT_NARRATIVE on
test/main, remove dead CURSOR_RUNNER_URL/cursor-agent, and set main
SEED_DEMO_USERS=false. Defaults stay legacy/false (no behavior change).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:26:47 +00:00
weichenandCursor 07fc0ecf55 fix(intent): fail closed INTENT_V2_DECISION_TIER unknown values to none
Align illegal-tier fallback with PlanTier's conservative policy so
unrecognized values never silently enable V2 query routing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 02:26:47 +00:00
weichen e35f106162 merge: Wave 1 docs closeout 2026-09-17 17:08:12 +00:00
weichenandCursor c61963633e docs(test): archive Wave 1 main env fix acceptance evidence
Close short-term task, mark remediation Wave 1 done, release integration
slot, and record main env=main / schema 52 / modes-off smoke evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:08:12 +00:00
weichen 805aa1259f merge: Wave 1 events secrets unblock 2026-09-17 17:06:24 +00:00
weichenandCursor fb4a4f263d fix(infra): supply main events secrets so ENV=main can boot
validateProductionSecrets rejected events under ENV=main without
KB/admin passwords; depends_on events healthy then blocked app forever.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:06:24 +00:00
weichen 27ccd12116 merge: fix/wave1-main-env-fix
Wave 1: align main app/events ENV=main, app depends_on events healthy,
fail-closed empty-Env chat import.
2026-09-17 17:03:54 +00:00
weichenandCursor 053bfe234b docs(ops): occupy integration slot for Wave 1 main env merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:03:54 +00:00
weichenandCursor e286fca71b fix(server): fail-closed chat import when Env is empty
Drop Env==\"\" as a dev alias; pin compose app/events ENV alignment and
main depends_on events with unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:03:08 +00:00
weichenandCursor db964da21a fix(infra): align main app ENV with events and gate on events health
Set app ENV=main (was prod) and require events service_healthy before
app starts so goose migrations finish before app queries new columns.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:03:08 +00:00
weichenandCursor 5ad2585ed7 docs(ops): claim Wave 1 main env fix branch
Register short-term task and CURRENT mutex=infra for E-1/E-2/E-5.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 17:03:08 +00:00
weichen af0912b0b3 merge: Wave 0 SSE evidence asset 2026-09-17 16:49:48 +00:00
weichenandCursor 7aca97e9b3 docs(test): store Wave 0 SSE evidence as txt (log gitignored)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:49:48 +00:00
weichen 4bccedb4ad merge: docs Wave 0 P0 closeout 2026-09-17 16:49:32 +00:00
weichenandCursor 40a9c1b285 docs(test): archive Wave 0 P0 bug-fix acceptance evidence
Close short-term task, mark remediation Wave 0 done, release integration
slot, and attach real pi-agent SSE heartbeat log plus suite results.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:49:32 +00:00
weichen 810fb96e76 merge: fix/wave0-p0-sse-chat-cache-bugs
Wave 0 P0: SSE heartbeat/deadline, run/stream 400+pre-flush start,
chat window cache key/LRU, IndexedDB restore merge.
2026-09-17 16:43:01 +00:00
weichenandCursor 2620d808c4 fix(web): unify chat window cache keys and merge IndexedDB restore
Pass userId on every saveSessionWindowCache write, LRU-evict full cache
keys, and applyRestoredFileRaw so mount restore cannot drop newer deliverables.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:42:56 +00:00
weichenandCursor 54244ed97a fix(server): extend SSE write deadline for chat and run/stream
Wire heartbeat + SetWriteDeadline into handleChatStream and
handleRunTaskStream; reject malformed run/stream JSON with 400; move
CreateAndStart/Subscribe before SSE Flush so failures stay JSON errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:42:56 +00:00
weichenandCursor 64efaa32c8 docs(ops): register system health audit and claim Wave 0 fix branch
Archive the 2026-09-17 health-check audit/remediation and short-term Wave 0
task so P0 SSE/cache fixes can proceed under mutex chat+web.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:42:55 +00:00
weichen dfa2d2d4bd merge: chore/release-s1c-integration-slot
CI / go-vet-and-short-test (push) Failing after 0s
CI / backup-restore-drill (push) Failing after 0s
CI / web (push) Failing after 0s
2026-09-17 15:52:53 +00:00
weichenandCursor 1dd1a8d23f docs(ops): release integration slot after S1-continued smoke
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 15:52:53 +00:00
weichen e58c707df6 merge: feature/rdev-template-depth-s1-continued
S1 continued: deepen remaining 46 rdev templates, lint 60/60, real-PI samples, instance_no fix.
2026-09-17 15:51:41 +00:00
weichenandCursor 36261e9d13 docs(ops): claim merge slot and archive S1-continued short-term
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 15:51:30 +00:00
weichenandCursor 9b35c1abd1 docs(test): archive S1-continued rdev template depth report and sync matrix
Record real-PI samples for review and verification templates, mark S1 continued done across writing-spec/backlog/FEATURE-MATRIX/CURRENT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 15:51:09 +00:00
weichenandCursor 12608c21ef fix(projectinstance): allocate next instance_no for planning drafts
Avoid unique (project_id, instance_no) collisions when saving a new
workflow plan after a completed main instance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:56:50 +00:00
weichenandCursor 04243e64d8 feat(rdev-templates): deepen stage-10–13 transfer/validation templates (S1 batch 5)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:37:19 +00:00
weichenandCursor 7c50128bd1 feat(rdev-templates): deepen stage-08 verification templates (S1 batch 4)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:37:18 +00:00
weichenandCursor 05629721f0 feat(rdev-templates): deepen stage-06 software/inspection/list templates (S1 batch 3)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:37:18 +00:00
weichenandCursor 1692a57175 feat(rdev-templates): deepen stage-06 hardware/process templates (S1 batch 2)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:37:18 +00:00
weichenandCursor 8c37ac0cd5 feat(rdev-templates): deepen 6 review-record templates (S1 batch 1)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:37:03 +00:00
weichenandCursor 535eb442b5 docs(ops): add short-term for rdev-template-depth-s1-continued
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:34:45 +00:00
weichenandCursor b800f9adf9 docs(ops): claim rdev-template-depth-s1-continued and open short-term
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:34:34 +00:00
weichen f8c4a61922 merge: chore/archive-proposal-http-task
CI / go-vet-and-short-test (push) Failing after 0s
CI / backup-restore-drill (push) Failing after 0s
CI / web (push) Failing after 0s
2026-09-17 14:12:13 +00:00
weichenandCursor 51d6d53ede docs(ops): archive proposal-http short-term after closeout
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:12:13 +00:00
weichen 21fb95458a merge: chore/closeout-claim-cleanup
CI / go-vet-and-short-test (push) Failing after 1s
CI / backup-restore-drill (push) Failing after 0s
CI / web (push) Failing after 0s
2026-09-17 14:12:02 +00:00
weichenandCursor fc227f339c docs(ops): clear closed feature worktree claims after closeout
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:12:02 +00:00
weichenandCursor dcc859ecb0 docs(test): archive proposal HTTP live evidence and release slot
CI / go-vet-and-short-test (push) Failing after 0s
CI / backup-restore-drill (push) Failing after 0s
CI / web (push) Failing after 0s
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:11:23 +00:00
weichen 1f2fcd0727 merge: feature/docgov-modification-proposal-http 2026-09-17 14:08:06 +00:00
weichenandCursor c89a58e026 docs(ops): occupy integration slot for proposal-http merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:08:02 +00:00
weichenandCursor d01694b556 docs(ops): record author-only pilot and proposal-http task claim
Archive CAS evidence for workflow.allow_author_only_approval on dev,
mark proposal HTTP audit resolved, and claim the feature branch in CURRENT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:07:52 +00:00
weichenandCursor c0e7df5abf feat(docgov): expose proposal HTTP and wire frontend decide flow
Add POST /api/v1/docgov/proposal for ProposeModification, harden decide
status mapping, and replace App pendingProposal local mock with real API calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:07:52 +00:00
weichen bea70b064b docs(control-center): strengthen agent integration spec — onboarding protocol, per-stage entry/exit criteria, decision quality bar, event cadence 2026-09-17 14:06:24 +00:00
weichen b5bacee331 refactor(control-center): remove legacy engineering-dashboard, superseded by control-center
- delete cmd/engineering-dashboard, internal/engineeringdashboard, scripts/engineering-dashboard.sh
- archive old design doc to .doc/archive/design/ with deprecation banner
- FEATURE-MATRIX: mark old row removed, add removed to status contract
- system-design README: section 8 now points to Control Center SSOT
2026-09-17 14:00:38 +00:00
weichenandCursor ba92a8b3a5 docs(status): note author-only merged to dev in FEATURE-MATRIX
CI / go-vet-and-short-test (push) Failing after 0s
CI / backup-restore-drill (push) Failing after 0s
CI / web (push) Failing after 0s
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:58:30 +00:00
weichenandCursor cbeefdb9ed docs(ops): release integration slot after author-only merge smoke
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:58:19 +00:00
weichenandCursor 09a9921e87 merge: feature/document-author-only-plan
Close out document author_only U1–U6 into dev (default policy off).
Resolved CURRENT claim table and bizdev service conflicts with rdev prior-doc injection.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:57:12 +00:00
weichenandCursor 4f1bb1f02d docs(ops): archive author-only U1–U6 and close remediation DoD
Move short-term tasks to archive, update MATRIX/INDEX/CURRENT, and hand off merge to dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:55:17 +00:00
weichenandCursor 472f845a88 docs(test): track U6 API evidence as txt (logs gitignored)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:49:12 +00:00
weichenandCursor 7b09da1f99 docs(ops): close document-author-only U6 and note proposal HTTP gap
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor 58b785e110 docs(test): add document-author-only U6 closed-loop report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor cf7f55a1b9 test(web): cover author_only action visibility and docgov client shapes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor 916931f5d8 feat(web): surface duty_policy author_only badge end-to-end
Propagate summary.duty_policy into deliverables/AST and show 编制人兼任 on the action bar.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor b87fc5007f feat(web): call real docgov lifecycle APIs from action handlers
Replace local lifecycleState mocks; add handleRejectApprove; use holdsDocDuty for chat shortcuts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor aed7f3f9b5 fix(web): gate docgov actions by duty id, not folded role
author_only A/A/A users were stuck as author-only under resolveCurrentDocRole priority.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor 3c6342bfee feat(web): add docgov claim/submit/review/approve API client
Wire frontend to existing lifecycle HTTP so approval actions can leave local mock state.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00
weichenandCursor 8658a135ab docs(ops): claim and close document-author-only U4 and U5
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor 7ccb821d6c test(web): cover author_only duty resolution and validation
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor 72686d13cb feat(web): add per-document author_only toggle in project settings
Show a single author picker when兼任 is enabled, respect the system
capability flag, and surface author_only docs in activation preview.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor be128602e4 feat(web): resolve client duty_policy for author_only plans
Align TypeScript types and projectSettingsDuties with backend
ResolveDocTaskDuty so author_only no longer fails as partial.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor 2c012ee59f test: cover author_only access matrix and duty_policy audits
Prove A can run the full action chain and outsiders stay denied; assert
audit Details carry duty_policy on all five transitions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor 3f7358d454 feat(docgov): record duty_policy on lifecycle audit details
Surface the document duty mode on submit/review/approve transitions for
consistent logs under author_only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichenandCursor f02600d75c fix(projectinstance): resolve author_only duties in ABAC gates
Use ResolveDocTaskDuty so normalized author-only plans (author ID only)
are treated as full A/A/A for access, stage visibility, and readiness.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:15:05 +00:00
weichen 87bcf05043 feat(control-center): allow LAN bind with mandatory fixed console token (serve-lan) 2026-09-17 13:11:52 +00:00
weichen 6714081b12 docs(control-center): P6 design spec, agent integration guide, acceptance report
Also fixes ListTasks ?q= filter 500 (duplicate $%d placeholder rendered as
%!d(MISSING)) found in P6 smoke; adds TestTaskListQueryFilter regression.
2026-09-17 12:59:12 +00:00
weichen 07a8e126fc feat(control-center): P5 scheduled repo audits — deterministic checks, LLM review, findings UI 2026-09-17 12:39:46 +00:00
weichen f79956c498 feat(control-center): P4 .doc importer, agent CLI, task doc export
- internal/controlcenter/importer: scan .doc/ops/{short-term,long-term}
  and .doc/backlog for task docs, upsert cc_tasks keyed by slug; maps doc
  status/stage, auto-creates the three plans, follows doc status only
  while a task is planned/in_progress (terminal statuses never regress),
  skips unchanged docs, and resolves cross-directory slug collisions by
  fixed directory precedence with a warning
- cmd/control-center: import-docs subcommand (also runs at serve startup
  and on the doc-sync ticker) plus the agent CLI: next / instruction /
  claim / heartbeat / release / event / artifact / advance-request /
  decision / report, thin net/http client, compact JSON output
- console API POST /api/v1/tasks/{id}/export-doc renders a task per
  .doc/ops/templates/short-term-task.md into .doc/ops/short-term/, refuses
  overwrite (409) and unsafe slugs, then backfills doc_path
- fix pre-existing TestAgentHasNoAdvanceRoute: SPA catch-all GET / makes
  the mux answer 405 for unmatched POST paths; accept 404 or 405
- archtest allowlist: controlcenter/importer -> pipeline, store
2026-09-17 11:57:47 +00:00
weichen b0095de398 feat(control-center): P3 web SPA — overview, stage kanban, task pipeline, decisions, docs search
- control-center/web: Vite+React+TS SPA (hash routing, token login via
  localStorage, marked-lexer markdown rendering without raw HTML injection)
- pages: overview (stage x state matrix, SSE feed w/ 10s poll fallback),
  8-lane kanban + task create, task detail stepper/pipeline/ops
  (assign/advance/send-back/external-submit), decision inbox, docs browse
  + semantic/keyword/hybrid search, global stage settings, audit placeholder
- internal/controlcenter/webui: //go:embed dist, SPA fallback, index no-store;
  dist committed so go build works without node
- server: GET / serves embedded SPA; pipeline view now includes artifact
  content for console rendering
- archtest: allowlist controlcenter/server -> controlcenter/webui
2026-09-17 10:13:16 +00:00
weichenandCursor c6c07263c7 docs(ops): claim and close document-author-only U3
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 67b3b5e070 test: cover duty lock, heal/revoke skip, and instance duty adapter
Unit evidence for AE5a/AE5b filters; optional PG cases when
TEST_DATABASE_URL is set.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 750b904439 feat(app): wire projectinstance duties into bizdev
Composition-root adapter maps live instance DocTasks to bizdev's narrow
InstanceDutySource without crossing module boundaries.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 5b9b46ee8d feat(bizdev): prefer instance-governed duties when generating docs
Inject InstanceDutySource, resolve governed bindings, lock duties after
create, and skip in-memory HealBinding overwrite for governed docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 42a3b1e56c feat(docduty): skip duty_locked rows in heal and revoke
Keep instance-governed A/A/A (or separated) bindings immune to project
default heal and member-slot revocation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 89484177ee feat(docgov): lock document duties and project duty_policy
Add LockDocumentDuty for PG/memory and expose duty_policy on workflow
document summaries for later UI marking.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 7d3474816b feat(db): add document_records duty_locked and duty_policy columns
Stamp instance-governed document duties at create time so heal/revoke can
skip locked rows without importing projectinstance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00
weichenandCursor 748df016b2 docs(ops): release rdev merge slot, archive P0/P1 task, register S1续批
Also record the ad-hoc verification Path("") join pitfall as a low-severity
audit note so future sampling scripts fail closed instead of scanning bizdev/.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:52:24 +00:00
weichenandCursor 7e6860f861 docs(ops): smoke phase for rdev merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:47:57 +00:00
weichen 68f63d3c30 merge: feature/rdev-template-depth 2026-09-17 09:47:49 +00:00
weichen 9bb4ec3665 merge: feature/rdev-core 2026-09-17 09:47:44 +00:00
weichen 63f1fa5f87 feat(control-center): P2 document vector store — ingestion, chunking, embedding, hybrid search
- internal/controlcenter/embed: OpenAI-compatible /embeddings client
  (batch<=16, 30s timeout, 5xx/network retried once, 4xx not), Embedder
  interface, deterministic offline Stub, pgvector literal formatting
- internal/controlcenter/docs: .doc/**/*.md sync into cc_documents with
  sha256 diffing and vanished-file removal; YAML front matter -> jsonb,
  title fallback, taxonomy from first .doc dir; heading-based chunking
  with paragraph bisection over ~1800 est. tokens; chunk_hash idempotent
  inserts (unchanged chunks keep embeddings); embedding failures degrade
  to NULL vectors without failing the sync; IndexArtifact for
  cc_stage_artifacts; StartPeriodic ticker (CC_DOC_SYNC_SECONDS)
- server: GET /api/v1/docs (taxonomy/q filters), /api/v1/docs/{id},
  /api/v1/docs/search (semantic|keyword|hybrid, ts_rank+ILIKE keyword
  fallback, 0.6/0.4 max-normalized fusion, degraded flag when embedding
  unavailable); async artifact indexing hooked into agent artifacts and
  external-submit handlers
- archtest module-boundaries allowlist updated for new packages
2026-09-17 09:47:29 +00:00
weichenandCursor 7f30a5049e docs(ops): occupy slot to merge rdev-core and template-depth
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:47:14 +00:00
weichenandCursor 4e271c54bb docs(test): archive rdev template-depth S0/S1 real-PI evidence
Record true PI samples (intake + rd_design_input_spec), update FEATURE-MATRIX
remaining work, backlog S1续批/S2/S3, and allowlist engineeringdashboard for
archtest green on this branch lineage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:47:05 +00:00
weichenandCursor ca7b7da237 docs(ops): claim rdev-template-depth short-term and CURRENT mutex
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:52 +00:00
weichenandCursor 93ad80b9a7 feat(rdev): deepen phase 01-05 templates with ISO 13485 sections
Replace generic placeholders for 14 rd_* docs, add writing-norm doc and
allowlist lint so structure and per-section instructions stay enforceable.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:37 +00:00
weichenandCursor dc3aef4607 fix(squad): inject rdev_leader InstructionsFile for DHF final review
Prefer AgentSpec.InstructionsFile when building AGENTS.md so rd_* leader
steps no longer fall back to business-tone leader.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:37 +00:00
weichenandCursor aba38ef7a9 fix(engineering-dashboard): drop startup token for personal local use
Rely on loopback bind plus Host/Origin checks; open http://127.0.0.1:8787/
without a query token after SSH tunnel.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:26 +00:00
weichenandCursor 37b1aaa3ae feat(rdev): add medical design-control workflow (13 stages / 60 docs)
Seed rdev.v2.json, rd_ templates, catalog policy (order 40), squad
kind orchestration, and hard precheck requiring completed main (CDO).
Includes StageKey dynamicization from P0 and docs for P2–P4 skeleton.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:26 +00:00
weichenandCursor a39823da38 fix(docgov): pass dynamic StageKey into document ledger create
Stop hardcoding V0.5_feasibility when creating docgov records; prefer
frozen-instance StageKey from TaskRunRequest with main-task fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:46:09 +00:00
weichenandCursor c03d0a3a6e docs(ops): claim and close document-author-only U2
Record short-term evidence and mark the CURRENT claim done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor 68dbe8a6b2 test(projectinstance): cover author_only planning and activation
Verify resolve/normalize/hash stability, policy gating, stale token
rejection, and HTTP error mapping for the new duty policy path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor 1651c30e90 feat(api): map author-only policy errors on workflow settings
Return 403/409/503 for disabled, changed, and unavailable governance
policy conditions during plan save and activation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor 0b67a901a9 feat(app): wire sysadmin author-only policy into projectinstance
Adapt sysadmin.AuthorOnlyPolicySource at the composition root so
projectinstance stays within module-boundary allowlists.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor a2aa3d41bd feat(projectinstance): support per-doc author_only duty policy
Add ResolveDocTaskDuty, require the system policy on save/preview,
lock the policy row during activation, and derive A/A/A assignments.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor ba57c9a4de feat(db): bind activation tokens to author-only policy revision
Prevent preview tokens from activating after the governance switch
revision changes by storing the revision on each confirmation token.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:39:59 +00:00
weichenandCursor 3b6def256e docs(ops): claim and close document-author-only U1
Record short-term task evidence and mark the CURRENT claim done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:15:15 +00:00
weichenandCursor 430a47ad8c test(sysadmin): cover author-only CAS, audit rollback, and HTTP gates
Verify concurrent revision conflicts, null/string rejection, plain-user
denials, and PG lock/read paths for the new policy key.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:15:15 +00:00
weichenandCursor a2cbaf1e33 feat(sysadmin): CAS author-only policy with transactional audit
Register the workflow total switch, require expected_revision for
updates, and expose AuthorOnlyPolicySource for activation locking.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:15:15 +00:00
weichenandCursor b4b300bb8a feat(db): add author-only approval policy revision and audit
Seed workflow.allow_author_only_approval closed, add monotonic
revision on system_settings, and a narrow policy audit table.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:15:15 +00:00
weichen b11cc64845 feat(control-center): P1 pipeline core — stage machine, decisions, artifacts, leases, SSE
- pipeline: 8-stage order, NextStage (testing skippable), gate pure
  functions (agents may never advance; only in_progress->awaiting_review)
- tasks: domain layer over cc_* tables — CRUD, claim/heartbeat/release
  leases, advance-request, decisions with strict suggestion validation,
  stage transitions, external submit, stage settings, overview, lease reaping
- server: agent + console routes, SSE broker broadcasting every event
  insert, 60s lease reaper goroutine, 1MB body limit, domain error mapping
- archtest: allowlist controlcenter/* and engineeringdashboard packages
2026-09-17 09:13:36 +00:00
weichenandCursor 7a590670e9 docs(workflow): approve R9/R10 and harden heal acceptance
Mark lifecycle boundaries reviewed; require HealProjectDocuments
projection stability across list/generate/member triggers, and
explicitly exclude emergency stop from the global switch scope.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:06:51 +00:00
weichen f6c9638e60 docs(workflow): plan per-document author-only approval policy 2026-09-17 08:49:46 +00:00
weichen 2be43efddd feat(control-center): P0 skeleton — standalone server, pgvector compose, goose schema, token auth 2026-09-17 08:38:50 +00:00
weichen cf805a73a7 docs(ops): claim control-center-server task and register in CURRENT 2026-09-17 08:33:10 +00:00
weichen adb48c86a5 merge: feature/initial-load-perf-u2 (docs acceptance) 2026-09-17 08:25:43 +00:00
weichenandCursor ae219955ab docs(test): archive initial-load U2 acceptance evidence
Record curl/browser before-after metrics, mark U2 done, and release the
integration slot while leaving U1/U3–U7 open.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 08:25:43 +00:00
weichen bc01781438 merge: feature/initial-load-perf-u2 2026-09-17 08:18:18 +00:00
weichenandCursor 9335c4c90c feat(server): negotiate static compression and fix asset SPA fallback
Serve precompressed .br/.gz with Cache-Control and Vary, and return 404
for missing /assets and /fonts instead of index.html.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 08:18:11 +00:00
weichenandCursor 3dbd9770b5 feat(web): precompress dist assets to .br and .gz at build time
Use Node zlib in a post-vite step so the Go server can serve negotiated
variants without per-request compression cost.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 08:18:02 +00:00
weichenandCursor dc769686a9 feat(web): self-host Inter and JetBrains Mono for login shell
Remove blocking Google Fonts stylesheet so the login form is not gated
on an external CSS request; keep unicode-range subsets and OFL license.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 08:18:02 +00:00
weichen 59e6fade72 merge: feature/initial-load-performance-plan 2026-09-17 08:08:23 +00:00
weichenandCursor 3445d386ea docs(perf): archive initial-load diagnosis and remediation plan
Capture audit evidence, performance baseline, and U1–U7 remediation plan
without business code changes so the work can land on dev before U2.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 08:08:20 +00:00
weichenandCursor d0ef6961b4 docs(ops): release slot after engineering-dashboard CSP fix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:40:28 +00:00
weichen 0a1302eab0 merge: fix/engineering-dashboard-csp-token 2026-09-17 07:40:27 +00:00
weichenandCursor 2319138800 docs(ops): occupy slot to merge engineering-dashboard CSP fix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:40:27 +00:00
weichenandCursor 7fd7fb8a2a fix(engineering-dashboard): read token from URL/meta under CSP
Remove the inline token script blocked by script-src 'self', so the
live page no longer calls the snapshot API with token=undefined.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:39:21 +00:00
weichenandCursor ce2a561d4d docs(ops): release slot after engineering-dashboard merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:11:18 +00:00
weichenandCursor f47161131c merge: feature/engineering-dashboard
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:11:17 +00:00
weichenandCursor fd1659a416 docs(ops): occupy slot to merge engineering-dashboard
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:10:36 +00:00
weichenandCursor 7e05473cf5 docs(engineering-dashboard): closeout report matrix and launcher
Add test report, FEATURE-MATRIX row, archive the short-term task,
mark CURRENT claim done, and ship the thin serve/export script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:10:04 +00:00
weichenandCursor e251ce325a feat(engineering-dashboard): U6-U7 serve UI and offline export
Add loopback-only HTTP server with startup token, Host/Origin/CSP
guards, embedded live UI, CLI serve/export, and safe single-file HTML.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:08:27 +00:00
weichen dd887bb08f merge: feature/system-admin-console closeout docs 2026-09-17 07:08:07 +00:00
weichen 62d6241348 docs(test): system admin console acceptance report and closeout
- test report: dev smoke (schema 48->49), 4 admin endpoints, settings
  write-read roundtrip, anon 401 / unknown-key 400 / non-admin 403
- task status done; FEATURE-MATRIX row done; release integration slot;
  env snapshot dev schema 49
2026-09-17 07:08:07 +00:00
weichenandCursor 79ee72267c feat(engineering-dashboard): U5 reconcile and snapshot publisher
Merge docs/git/runtime facts into an immutable snapshot with conflict
retention, last-known stale handling, and acceptance-sample coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:04:46 +00:00
weichenandCursor a07ba1065b feat(engineering-dashboard): U2-U4 docs git and runtime collectors
Add allowlisted markdown indexing, read-only git plumbing via injected
runners, and docker/readiness collection with path and loopback guards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:03:32 +00:00
weichen dc7c31edc9 merge: feature/system-admin-console 2026-09-17 06:59:21 +00:00
weichen 0088ae7d44 docs(ops): occupy integration slot for system-admin-console merge 2026-09-17 06:59:21 +00:00
weichenandCursor e46ec0e4e7 feat(engineering-dashboard): U1 freeze snapshot and facet model
Define versioned Snapshot/Fact/Conflict/TaskState contracts with
independent plan/git/verification/deployment axes and acceptance fixtures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:59:02 +00:00
weichen e7fa6fb023 docs(status): add system admin console row to FEATURE-MATRIX 2026-09-17 06:58:08 +00:00
weichen e310f06504 docs(ops): register system-admin-console task and claim 2026-09-17 06:57:13 +00:00
weichen 0eaca61545 feat(web): full-screen system admin console, absorb AdminSettingsModal
- top-level view switch workbench|admin in App.tsx (no router; hash #turn
  anchors untouched)
- new admin/console/AdminConsoleView with left group nav in the existing
  token/inline-style idiom, plus 8 self-fetching sections: overview, kb,
  features, settings, workflows, roles, users, docs
- absorb the six AdminSettingsModal tabs into sections and delete the modal
- new api/systemAdmin.ts + types for /api/v1/admin/system/* endpoints
- playwright smoke spec web/e2e/admin-console.spec.ts (skip by default)
2026-09-17 06:57:03 +00:00
weichen f1404d5bd2 feat(sysadmin): add system admin aggregation API and system_settings store
- new internal/sysadmin package (overview/kb/features/settings) with small
  port interfaces; business packages stay unaware of sysadmin
- new routes /api/v1/admin/system/{overview,kb,features,settings} guarded
  by requireSystemAdmin
- goose 00049: system_settings table (key/jsonb value, updated_by/at)
- SettingSpec whitelist registry with DB > env > default precedence
- register sysadmin in module-boundaries.yaml (archtest rules)
2026-09-17 06:56:46 +00:00
weichenandCursor fa5e10542a docs(ops): claim engineering-dashboard implementation
Register CURRENT mutex and mark short-term in_progress on the
feature/engineering-dashboard worktree before coding.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:56:20 +00:00
weichenandCursor 12884a1710 docs(ops): release slot after engineering-dashboard plan merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:55:44 +00:00
weichen c336de59b8 merge: feature/project-control-center-plan 2026-09-17 06:55:44 +00:00
weichenandCursor 44fa8d5059 docs(ops): occupy slot to merge engineering-dashboard plan
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:55:44 +00:00
weichenandCursor ed4a49bfa6 docs(engineering-dashboard): add personal control center design plan
Freeze the independent local readonly engineering-dashboard design,
short-term task entry, and system-design index before implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:55:32 +00:00
weichen 15881cd0e6 docs: sync null-fk promote closeout onto test 2026-09-17 06:20:40 +00:00
weichen 173a512c28 merge: docs/promote-null-fk-to-test-closeout 2026-09-17 06:20:40 +00:00
weichenandCursor ef5f0fdef9 docs(ops): close null-fk promote to test at rc-v1.0.0-beta.4
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 06:20:40 +00:00
889 changed files with 63242 additions and 7282 deletions
@@ -2,7 +2,7 @@
## 状态
提议(2026-09-14;架构与实施计划已修订,等待用户确认后进入首个实现里程碑)
已接受(2026-09-14 提议;2026-09-18 确认——Phase 1 纵向绞杀与 Phase 2 持久事件交付已落地并验收,见 gap-matrix `DOC-RELIABILITY-PILOT` PASS、[Phase 1 计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)、[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)、[Track E 复盘](../ops/research/2026-09-15-track-e-retrospective.md))
## 背景
@@ -0,0 +1,609 @@
---
title: "个人工程中控台:实时项目看板与离线 HTML 快照"
type: feat
date: 2026-09-17
artifact_contract: ce-unified-plan/v1
product_contract_source: ce-plan-bootstrap
execution: code
---
> **已废弃(2026-09-17;2026-09-19 更新)**:旧版只读工程中控台代码已移除。后来短暂合入的 Control Center 也已移出本仓库,进度管理由独立项目承担。本文仅作历史证据保留。
# 个人工程中控台:实时项目看板与离线 HTML 快照
## Goal Capsule
为仓库所有者提供一个独立于产品后台的本地只读中控台。打开一个页面即可判断当前系统由什么组成、哪些任务正在计划或实施、真实分支和 worktree 在哪里、各环境实际运行了什么,并能在两次点击内到达对应的设计、审计、整改、任务和测试材料。
中控台同时提供两种输出:
1. `serve`:持续采集本地仓库、Git 和运行环境,提供自动刷新的 HTML 页面与机器可读 JSON;
2. `export`:基于同一份不可变快照生成单文件 HTML,便于归档、离线查看和交接。
这不是产品功能,不接入产品后台、产品数据库或产品权限体系;它也不是发布系统,不执行 Git、Docker、部署或文档写操作。
### 成功标准
- 在当前仓库规模下,首次可用页面目标为 2 秒内出现;慢数据源可随后标记为 `degraded`,不得拖垮整页。
- 正常情况下,本地文件、Git 或运行态变化在 5 秒内反映到新快照。
- 页面分别展示“文档声明、Git 实施、验证证据、环境实装”,不把任务文档的 `done` 翻译为已合并或已部署。
- 每个关键结论均显示来源、采集时间、新鲜度和可信类型;冲突保留双方证据,不静默选边。
- 在线模式检索 allowlist 内未截断的 Markdown 正文;离线导出同时给出 included、truncated 和 metadata-only 清单,二进制附件只索引路径、类型、大小和归属。
- 单文件 HTML 默认权限为 `0600`,可脱离仓库阅读已纳入 inclusion manifest 的 Markdown 正文,并醒目标出截断或仅元数据条目;不打包 `.doc/**/assets`。
- 任一采集源失败时仍可查看最近成功数据,并明确显示 `stale/error/last_success_at`。
---
## Product Contract
### 用户与使用场景
唯一主要用户是仓库所有者。典型使用包括:
- 每天开始工作时查看焦点任务、阻塞、集成槽和环境异常;
- 从模块进入设计、任务、测试和部署证据链;
- 判断某项工作究竟只是有计划、正在实现、已经验证,还是已在某环境实装;
- 查看本地分支、远端跟踪引用、ahead/behind、worktree 和未提交变更;
- 发现 `CURRENT`、功能矩阵、发布门禁、Git 与 Docker 之间的漂移;
- 导出一个自包含 HTML,作为某一时点的项目快照。
### 已确定的产品决策
#### PKD-1:独立本地工具
采用独立 Go CLI 和本地 Web 页面,不加入现有产品后台。
(session-settled: user-approved — chosen over product-admin integration: the console is for the repository owner’s local engineering management and the production image excludes `.doc` and `.git`)
#### PKD-2:只读实时页与离线快照共用数据模型
实时服务和导出文件必须由同一份版本化快照生成,避免在线页面与离线报告出现两套口径。
(session-settled: user-approved — chosen over a static-only report: the requested console must follow agent tasks and project state as they change)
### 核心需求
| ID | 需求 |
|---|---|
| R1 | CLI 默认解析当前 Git 仓库根,也接受显式 `--repo`;页面始终显示绝对根路径、当前分支、HEAD 和采集时间。 |
| R2 | 仅监听 `127.0.0.1`,不依赖产品容器、产品数据库或产品登录。 |
| R3 | 架构与模块页聚合 `module-boundaries.yaml`、系统设计索引和 `FEATURE-MATRIX`,展示模块、能力、依赖和证据链。 |
| R4 | 任务状态至少拆为 `doc_status`、Git facets、`verification_result`/`verification_freshness`、deployment facets;可并存事实不得压成单值枚举。 |
| R5 | Git 页展示本地/跟踪分支、ahead/behind、最近提交、worktree、dirty/untracked 和任务声明匹配情况;不得隐式 `fetch`。 |
| R6 | 部署页按 shared/dev/test/main 分别展示容器状态、应用 readiness、服务完整性、schema、镜像与 promotion receipt;不得计算未经定义的综合绿灯。 |
| R7 | 文档页支持按 taxonomy、状态、模块和关键词筛选,展示正文、正向链接、反向链接、broken、orphan 与 unindexed 状态;查询状态可通过 URL 恢复。 |
| R8 | 一个不可变快照包含 `schema_version`、`generation_id`、`revision_id`、`generated_at`、仓库/提交身份、来源状态、事实与冲突。 |
| R9 | 自动刷新采用完整快照原子切换;每个来源独立超时,失败时保留最近成功数据并标注过期。 |
| R10 | 每条关键事实标注 `declared`、`observed`、`verified` 或 `inferred`,并保留来源路径和采集时间。 |
| R11 | 单 HTML 内嵌结构化模型、页面资源和允许导出的 Markdown 正文;附件只保留元数据及相对链接,并显示内容覆盖清单。 |
| R12 | 对 Agent 暴露稳定的只读 JSON,而不是让 Agent 解析 HTML;JSON 与页面引用同一 `generation_id` 和 `revision_id`。 |
| R13 | TaskState 显示声明的 owner/Agent 类型/认领/mutex 与基于 Git 的最近活动证据;Herdr 工程 Agent 和产品 PI Agent Runner 使用不同类型。没有运行态来源时必须显示 unknown,不得把“已认领”写成“正在执行”。 |
| R14 | 文件、命令和 HTTP 均采用 allowlist;拒绝路径穿越、symlink 越界、原始 HTML 执行、远程资源加载和凭证读取。 |
### 事实源与权威边界
| 领域 | 权威来源 | 中控台处理方式 |
|---|---|---|
| 发布门禁 | `.doc/remediation/gap-matrix.md` | 只解释发布 blocker,不替代能力完成度。 |
| 能力成熟度 | `.doc/status/FEATURE-MATRIX.md` | 显示功能完成度,不据此推断是否部署。 |
| 当前焦点、认领、集成槽 | `.doc/ops/CURRENT.md` | 作为团队声明,与 Git 和运行态对账。 |
| 任务计划 | `ops/short-term`、`ops/long-term`、backlog front matter | 作为计划状态,不据此推断实现。 |
| 分支与 worktree | Git plumbing | 作为本地观测;远端状态注明“基于本地 refs,未联网刷新”。 |
| 环境运行态 | Docker/Compose 元数据与 `/ready` | 分开展示容器、应用与服务完整性。 |
| 验收证据 | `.doc/test-reports` 及 promotion receipts | 显示证据存在性与身份,不以文件名替代内容校验。 |
来源之间不设全局覆盖顺序。各来源回答自己的问题;值不一致时生成 drift,并并列展示原值、时间和来源。
### 用户流程
```mermaid
flowchart LR
Start[启动 serve 或 export] --> Root[解析显式 repo root]
Root --> Collect[并行采集文档 Git 运行态]
Collect --> Snapshot[构建不可变快照]
Snapshot --> Reconcile[按领域对账]
Reconcile --> Live[本地实时页面和 JSON]
Reconcile --> Export[单文件 HTML]
Live --> Refresh[定时生成下一快照]
Refresh --> Snapshot
```
总览默认优先显示 `in_progress`、`blocked`、`planned`、`partial/deferred`、drift 和 degraded。`done` 与 archive 默认收起,避免历史材料淹没当前工作。
任务详情按照以下证据链导航:
```mermaid
flowchart LR
Audit[audit 问题] --> Remediation[remediation 方案]
Remediation --> Task[任务声明]
Task --> Git[分支 worktree commit merge]
Git --> Test[测试与验收报告]
Test --> Deploy[环境 artifact 与 readiness]
```
显式 Markdown 链接和既定 taxonomy 属于强关系;仅由文件名或 slug 推断的关系标为“候选”,不得参与完成度计算。
### 状态模型
```mermaid
flowchart TB
D[doc_status: planned/in_progress/blocked/done] --> View[并列状态视图]
G[Git facets: branch/worktree/merge/cleanliness/ahead-behind] --> View
V[Verification: result + freshness + bound identity] --> View
P[Deployment facets: container/readiness/services/artifact identity] --> View
View --> Drift{来源是否一致}
Drift -->|是| Consistent[consistent]
Drift -->|否| Conflict[drift + 双方证据]
```
“实装”定义为存在可核对的环境观测证据,而不是任务文档为 `done`。容器可达但 artifact identity 无法核对时显示“运行可见、版本未验证”,不得提升为 verified deployment。当文档声明 healthy、Docker 显示异常而 `/ready` 为 ok 时,页面保留多值并标记 drift,不输出统一绿灯。
### 真实验收样本
1. rdev:存在调研、设计、任务与 backlog,但若没有 CURRENT 认领和真实分支,应显示“已计划、未认领、未实施、未实装”。
2. main 环境:若 CURRENT 声明整体 healthy,而 events 容器实际 restarting、应用 `/ready` 仍为 ok,应同时显示三项证据与 drift。
3. 本地 dev:若分支领先 `origin/dev`,必须显示“本地已具备、远端未确认可用”,不得写成已远程发布。
4. `system-admin-console`:作为产品管理后台能力,与本计划的个人工程中控台分开展示,名称和边界不得混淆。
### 安全与非目标
一期明确不做:
- 不写文档,不修改任务状态,不占用集成槽;
- 不创建、切换、合并、删除或推送 Git 分支;
- 不执行 `git fetch`,不调用远端托管平台 API;
- 不启动、停止、重建或部署容器;
- 不控制 Herdr 或向 Agent 派发任务;
- 不读取 `.env`、`.secrets`、Docker `Config.Env`、数据库数据或 `.git` 内部文件正文;
- 不加入产品 API、产品前端、产品数据库或生产镜像;
- 不执行 Markdown 原始 HTML、脚本、Mermaid 或远程资源。
后续候选包括跨快照历史、远端 CI/Gitea 聚合、受限 Markdown/Mermaid 渲染、Agent 查询 API 和修复建议。任何写操作继续保持在本工具之外。
---
## Planning Contract
### High-Level Technical Design
以下图示冻结边界和协议,不规定具体函数签名。
```mermaid
flowchart LR
Docs[.doc sources] --> DC[Document collector]
Git[Git/worktrees] --> GC[Git collector]
Run[Docker/ready/receipts] --> RC[Runtime collector]
DC --> Build[Snapshot builder]
GC --> Build
RC --> Build
Build --> Rec[Reconcile facts and conflicts]
Rec --> JSON[Read-only JSON]
Rec --> Web[Local HTML]
Rec --> File[Offline HTML]
```
```mermaid
sequenceDiagram
participant UI as Browser
participant C as Collection coordinator
participant S as Sources
participant P as Snapshot publisher
UI->>C: poll with revision_id
C-->>UI: current snapshot immediately
C->>S: singleflight collection with deadlines
S-->>C: facts or source error
C->>P: publish complete generation atomically
P-->>UI: new revision or not-modified
```
```mermaid
stateDiagram-v2
[*] --> Loading
Loading --> Fresh: first collection succeeds
Loading --> ErrorUnknown: first collection fails
Fresh --> Refreshing: TTL expires
Refreshing --> Fresh: new generation succeeds
Refreshing --> Stale: source fails and last-known exists
Stale --> Fresh: source recovers
ErrorUnknown --> Fresh: source first succeeds
```
### 技术决策
#### KTD-1:采用仓库内独立 Go CLI
新增 `cmd/engineering-dashboard` 与 `internal/engineeringdashboard`,复用仓库 Go 工具链但不导入产品业务包。Go 标准库足以提供本地 HTTP、资源嵌入、JSON、并发和原子文件输出;现有 `yaml.v3` 可用于已定义的 YAML 契约。
#### KTD-2:快照是唯一交付模型
采集器只生产事实,reconcile 层只生产派生状态和冲突,HTTP/API/export 只消费已完成的不可变快照。快照至少包含:
```text
schema_version, generation_id, revision_id, generated_at, collection_duration
repository { root, branch, head, dirty }
sources[] { name, status, observed_at, last_success_at, error }
facts[] { subject, field, value, provenance, source_ref, observed_at, confidence }
conflicts[] { subject, field, kind, fact_refs[] }
documents[], modules[], tasks[], git[], environments[]
```
`generation_id` 唯一标识一次采集,包含采集批次语义;`revision_id` 只由 schema、仓库身份和规范化的非易变事实、冲突、来源状态确定,明确排除 `generated_at`、`observed_at` 和采集耗时。HTML 与 JSON 必须展示同一对标识,HTTP ETag 和前端是否重绘使用 `revision_id`。一期不读取旧 schema 的外部 JSON;离线 HTML 自带对应 renderer,因此不依赖未来二进制迁移。
#### KTD-3:专用解析器与容错索引并存
对 CURRENT、FEATURE-MATRIX、gap-matrix、任务 front matter 和 module boundaries 编写契约化解析器。文档层只索引 promotion receipt 的路径与链接,结构化部署凭证由运行态采集器唯一负责。对其余 Markdown 只提取安全元数据、标题、正文与链接。专用解析器失败时保留原文入口并标记 degraded,不凭模糊规则编造状态。
#### KTD-4:命令执行采用固定 argv 和超时
Git 与 Docker 采集通过注入式 command runner 执行固定程序和分离 argv,不通过 shell 拼接。`--repo` 先转为绝对、symlink-resolved 的 Git 根并作为单个参数传递。每个来源默认 2 秒超时;错误输出做长度限制和敏感字段清理。Git 使用 porcelain/plumbing 输出,例如 `status --porcelain=v2`、`worktree list --porcelain`、`for-each-ref`、`rev-list`、`merge-base`。
#### KTD-5:一期采用短轮询,不引入持久数据库
服务端由单一采集协调器按 TTL 触发完整重采集,2–5 秒刷新;同一仓库最多一轮采集在途,请求只读取当前快照,不直接叠加扫描。每轮带单调 generation 序号和整轮 deadline,只有当前有效轮次能原子发布。页面使用 ETag/`revision_id` 避免重复传输。last-known 只在同一 `serve` 进程内有效;冷启动或单次 export 首次采集失败时显示 unknown/error,不伪造历史值。文件监听、SSE 通知、持久缓存和历史数据库均后置。
#### KTD-6:安全阅读优先于富渲染
在线详情页一期将 Markdown 全部作为纯文本安全转义,并保留换行和空白;标题、列表、链接、代码、图片和 Mermaid 均显示源码,不生成 HTML 节点或发起资源请求。静态导出内嵌同一正文和内部导航。所有文档 ID 都是规范化仓库相对路径,只允许 `.doc/**/*.md` 及明确列入 allowlist 的根 Markdown;读取前后都校验解析路径,直接拒绝 symlink,并对 `.git`、`.env*`、`.secrets`、`data` 等敏感路径执行最终目标 denylist。
#### KTD-7:导出为自包含、有限尺寸的证据快照
导出将模型、CSS、JS 和允许的 Markdown 正文写入单 HTML,采用临时文件加 rename 原子落盘,默认 `0600`。数据使用 HTML-safe JSON 或等价编码封装,正文只通过 `textContent`/DOM API 写入;CSP 禁止网络、外部资源和内联事件执行。默认只嵌入 Git tracked、allowlist 内的 Markdown;untracked Markdown 只列元数据,除非用户显式选择。导出前输出 inclusion manifest 与敏感模式告警;`.doc/**/assets`、数据库、构建产物和二进制报告不嵌入。
### 建议目录
```text
cmd/engineering-dashboard/
main.go
internal/engineeringdashboard/
model.go
collector.go
source_docs.go
source_git.go
source_runtime.go
reconcile.go
server.go
export.go
assets/
index.html
app.js
app.css
testdata/
docs/
git/
runtime/
scripts/
engineering-dashboard.sh
.doc/test-reports/
YYYY-MM-DD-engineering-dashboard-test-report.md
```
### 风险与缓解
| 风险 | 缓解 |
|---|---|
| 文档结构并不完全统一 | 只对 SSOT 和任务 front matter 使用严格契约;其余文档容错索引并暴露解析告警。 |
| 看板制造“假完成” | 多轴 facets、事实 provenance、验证身份绑定、冲突不覆盖、真实反例测试。 |
| Docker/Git 卡住或不可用 | 独立超时、并行采集、last-known 状态、degraded 页面。 |
| 文档 XSS 或路径穿越 | 纯文本渲染、HTML-safe 数据封装、CSP、路径 allowlist、拒绝 symlink、最终目标敏感路径 denylist。 |
| `.doc` 附件导致扫描/导出失控 | 默认跳过 assets 内容,只采集元数据;设置单文档和总正文上限并报告截断。 |
| 导出副本离开本机后 `0600` 不再提供保护 | 页面首部标明敏感快照、仓库身份和生成时间;输出 inclusion manifest,交接者自行控制接收者、保留期与删除。 |
| worktree 与主 checkout 混淆 | 只管理 `--repo` 指定/解析出的根,页面常驻显示根与 HEAD;其他 worktree 仅作为 Git 元数据。 |
| 本地 remote refs 被误认为远端实时状态 | 显示 refs 观测时间和“未联网刷新”,不自动 fetch。 |
| 与产品 `system-admin-console` 命名冲突 | CLI、包和文档统一使用 `engineering-dashboard` / “个人工程中控台”。 |
---
## Implementation Units
### U1:冻结快照、事实与状态契约
**目标**:先建立不会把计划、实现、验证、部署混为一谈的模型与测试夹具。
**覆盖需求**:R4、R8、R10、R12、R13;承接 PKD-2 的同源快照决策。
**依赖**:无。
**文件**:
- `internal/engineeringdashboard/model.go`
- `internal/engineeringdashboard/model_test.go`
- `internal/engineeringdashboard/testdata/**`
**实施要点**:
1. 定义版本化 `Snapshot`、`SourceState`、`Fact`、`Conflict`、`TaskState`、`AgentClaim`、`EnvironmentState`。
2. provenance 固定为 `declared|observed|verified|inferred`;freshness 固定为 `fresh|stale|error|unknown`。
3. 状态使用可组合 facets:Git 分为 branch/worktree/merge/cleanliness/ahead-behind;验证分为 result/freshness/subject identity;部署分为 container/readiness/services/artifact identity。
4. TaskState 保留 owner、agent kind、claim、mutex、声明分支、观测 worktree、最近活动时间及证据;声明与观测不可互相提升。
5. 建立 rdev、dev ahead、main events restarting、CURRENT/worktree 不匹配等夹具。
**测试场景**:
- 文档 `done` 但无 merge/deploy 时,Git 与部署 facets 不改变;
- `claimed` 但无可观测运行信号时,Agent 活动保持 unknown;Herdr 与产品 PI Runner 不共享类型;
- 同字段多来源不一致时生成 conflict 并保留所有 fact 引用;
- JSON round-trip 保留 schema 与 snapshot identity;
- 枚举未知值失败且错误可定位。
**完成证据**:模型测试通过,schema 示例落入 Go fixture,不存在页面专用的第二套状态类型。
### U2:实现文档图谱与领域解析器
**目标**:将 `.doc` taxonomy、模块、任务、测试和链接转换为可追溯文档图谱。
**覆盖需求**:R3、R7、R10、R11、R14。
**依赖**:U1。
**文件**:
- `internal/engineeringdashboard/source_docs.go`
- `internal/engineeringdashboard/docs_test.go`
**实施要点**:
1. 扫描 allowlist 内 Markdown,默认跳过任何 `assets` 目录正文;记录附件元数据。
2. 解析 front matter、标题、显式 Markdown 链接和反向链接。
3. 为 CURRENT、FEATURE-MATRIX、gap-matrix、任务文、module boundaries 和 test report 建立专用适配器;receipt 只在文档图谱中作为文档与链接,结构化解析归 U4。
4. 区分 `broken`、`orphan`、`unindexed`;slug 相似只形成候选关系。
5. 规范化路径并阻止 `..`、绝对路径和任何 symlink;最终目标再次应用扩展名 allowlist 与敏感路径 denylist。
**测试场景**:
- taxonomy 内文档可检索且反向链接正确;
- broken link 不导致整个索引失败;
- front matter 缺失或非标准时产生告警并仍可阅读;
- assets 不读正文,越界 symlink 被拒绝;
- rdev 文档链被发现,但没有被推断为已实现。
**完成证据**:文档索引能从 fixture 生成稳定 JSON,路径安全负例通过。
### U3:实现 Git 与 worktree 采集
**目标**:以只读 Git plumbing 形成可复现的分支、提交和 worktree 观测。
**覆盖需求**:R1、R4、R5、R10、R14。
**依赖**:U1。
**文件**:
- `internal/engineeringdashboard/source_git.go`
- `internal/engineeringdashboard/git_test.go`
**实施要点**:
1. 抽象 command runner,固定 argv、工作目录、超时和输出上限。
2. 收集当前分支/HEAD、dirty/untracked、local/remote-tracking refs、ahead/behind、merge-base 和 worktree。
3. 不执行 fetch;remote tracking ref 始终带本地观测时间与免责声明。
4. 对账任务声明的 branch/worktree,但不因路径名相似而认定一致。
**测试场景**:
- 本地分支领先 origin 时显示 ahead 且不显示“远端可用”;
- worktree 目录名与真实检出分支不一致时生成 drift;
- 命令超时、Git 不存在、非 Git 目录时单源 degraded;
- runner 记录中不存在 shell、fetch、push 或写命令。
**完成证据**:临时 Git 仓库集成测试和 fake runner 单元测试通过。
### U4:实现运行态与部署证据采集
**目标**:按环境独立呈现容器、应用 readiness、服务完整性、schema、镜像和晋升凭证。
**覆盖需求**:R4、R6、R10、R14。
**依赖**:U1。
**文件**:
- `internal/engineeringdashboard/source_runtime.go`
- `internal/engineeringdashboard/runtime_test.go`
**实施要点**:
1. 从仓库内批准的 Compose 静态配置和 allowlist labels 映射环境与服务;无法明确映射时显示 unknown,不用名称猜测。容器 JSON 只提取容器名、image/digest、状态、restart count、health,以及 allowlist 内的 Compose project/service labels;不复制 Env、Mounts、完整 NetworkSettings 或任意 labels。
2. 对 allowlist 中的本地 `/ready` 端点执行短超时、响应大小受限的请求;禁用重定向,或对每一跳重新校验 scheme、解析后 IP、端口和 host。
3. 解析 promotion receipt/candidate image 等仓库证据,保留 artifact identity。
4. 将 container health、app readiness、required-service completeness 分开建模。
**测试场景**:
- app ready 且 events restarting 时同时保留两项状态;
- Docker 不可用或 HTTP 超时时,其他数据源仍可输出;
- receipt 与容器 image 不一致时生成 deployment drift;容器可达但 identity 缺失时标记“运行可见、版本未验证”;
- readiness 重定向到外网或非 allowlist 本地端口时拒绝访问;
- 输出中不存在容器环境变量或凭证。
**完成证据**:fixture 和 fake HTTP/Docker runner 测试通过,main 分叉场景被覆盖。
### U5:实现对账、派生视图与新鲜度
**目标**:把来源事实组合成用户可判断的视图,但不替来源做未经定义的裁决。
**覆盖需求**:R3、R4、R6、R8、R9、R10、R13。
**依赖**:U2、U3、U4。
**文件**:
- `internal/engineeringdashboard/reconcile.go`
- `internal/engineeringdashboard/reconcile_test.go`
**实施要点**:
1. 按领域 SSOT 规则构建 module、task、environment 和 evidence-chain 视图。
2. 实现 conflict 分类:declared-vs-observed、task-vs-git、test-vs-subject、receipt-vs-runtime、stale-source、missing-evidence。
3. 快照构建期间每个来源独立记录 `observed_at`、持续时间和错误;成功后一次性发布。
4. 失败源只可复用同一 serve 进程的 last-known,并标注 stale、age 与 last-success;冷启动无缓存时为 unknown/error。过期数据不隐藏,但按年龄提升告警级别。
5. 测试报告只有在 commit/artifact identity 与当前 subject 对齐时才能派生 pass;身份缺失为 unbound,身份不匹配为 stale/drift。
**测试场景**:
- 三个真实样本得到预期多轴状态;
- 同一组输入顺序变化不改变规范化快照;
- 单源失败不会删除其他源,也不会重写 last-known 的观测时间;冷启动失败没有伪造 last-known;
- 旧测试报告、新 HEAD 与不同 image 不会派生当前验证通过;
- 恢复后 stale 自动清除并产生新 snapshot ID。
**完成证据**:reconcile table tests 覆盖一致、漂移、缺失、过期和恢复。
### U6:实现本地服务、总览与文档导航
**目标**:提供能快速判断异常并下钻证据的本地只读页面和 JSON。
**覆盖需求**:R1、R2、R3、R7–R10、R12–R14;承接 PKD-1 和 PKD-2。
**依赖**:U5。
**文件**:
- `internal/engineeringdashboard/server.go`
- `internal/engineeringdashboard/server_test.go`
- `internal/engineeringdashboard/assets/index.html`
- `internal/engineeringdashboard/assets/app.js`
- `internal/engineeringdashboard/assets/app.css`
- `cmd/engineering-dashboard/main.go`
**实施要点**:
1. `serve --repo <path> --addr 127.0.0.1:<port>`;一期无条件拒绝所有非 loopback 地址,包括通配、IPv6 非 loopback 和显式传入值。
2. 暴露 `/api/v1/snapshot`、`/api/v1/doc/<id>`、`/healthz`;所有接口只读。严格校验 Host/Origin/Fetch Metadata,不信任代理转发头;页面和 API 使用每次启动生成的不可预测访问令牌,降低 DNS rebinding 与跨站读取风险。
3. 页面分为总览、架构/模块、任务、Git、部署、文档和证据链。
4. 自动刷新完整快照,保留当前筛选、滚动位置、焦点和选中文档;ETag 未变化时不重绘。
5. 明确一级视图状态:initial loading、fresh empty、fresh success、partial/degraded with last-known、hard error without cache、refreshing、recovered。刷新中继续展示上一完整快照,直到下一版本原子替换。
6. 搜索覆盖标题、仓库相对路径、front matter 和未截断正文;不同维度用 AND、同一维度多选用 OR,默认先排当前任务和异常证据,再按匹配度与路径稳定排序。筛选、查询和选中文档写入 URL 参数,支持浏览器前进/后退与深链。
7. 桌面优先;窄屏下侧栏变为可关闭抽屉,宽表格保留可横向滚动的语义表头,详情区单列。所有功能可键盘完成,使用 landmark/标题/表格语义,drift/degraded 不只靠颜色表达,自动刷新通过非打断式 live region 报告且不抢焦点。
8. Markdown 正文只进入文本节点;在线页与导出页均设置限制性 CSP,不执行 HTML、脚本、SVG、远程 URL 或事件属性。
**测试场景**:
- 只监听 loopback,方法 allowlist 拒绝写请求;Host/Origin/token、DNS rebinding 和跨 Origin 负例被拒绝;
- HTML 与 JSON 的 generation/revision identity 一致;
- 文档 ID 越界、symlink 越界、未知 ID 返回安全错误;
- degraded source 在总览可见且页面仍可导航;
- 任务状态四轴、drift 和来源时间在浏览器中可见。
- 首次加载、空数据、无缓存错误、刷新、恢复状态可区分;键盘、焦点、语义结构、窄屏和非颜色告警验收通过。
- 搜索组合逻辑、排序、无结果、URL 深链和刷新后的视图保持通过。
**完成证据**:HTTP tests、基本无障碍检查和真实浏览器验收通过。
### U7:实现离线导出、启动脚本与治理文档
**目标**:生成安全、可携带、可追踪的单文件快照,并完成仓库治理接线。
**覆盖需求**:R1、R8、R9、R11、R14;承接 PKD-1 和 PKD-2。
**依赖**:U6。
**文件**:
- `internal/engineeringdashboard/export.go`
- `internal/engineeringdashboard/export_test.go`
- `scripts/engineering-dashboard.sh`
- `.doc/status/FEATURE-MATRIX.md`
- `.doc/ops/CURRENT.md`
- `.doc/test-reports/YYYY-MM-DD-engineering-dashboard-test-report.md`
**实施要点**:
1. `export --repo <path> --output <file>` 构建一次不可变快照并原子写入;首次采集失败的来源显示 unknown/error。
2. 以 HTML-safe JSON/等价编码内嵌允许的 Markdown 正文、索引和页面资源;附件保持元数据与相对链接,所有正文只写入文本节点。
3. 默认权限 `0600`,输出页显示生成时间、repo、HEAD、snapshot ID 和 degraded/drift。
4. 薄脚本只负责定位仓库与调用 Go CLI,不隐藏参数或执行安装/部署副作用。
5. 实施期间按仓库规范更新 CURRENT、FEATURE-MATRIX 和 test report;完成后再迁移任务生命周期状态。
**测试场景**:
- 导出文件脱离仓库后仍能搜索和阅读 Markdown;
- 导出中不含附件字节、绝对凭证路径、env 值或远程请求;`</script>`、事件属性、SVG、危险 URL scheme 和 Unicode 边界载荷不能逃逸数据上下文;
- 默认 tracked/untracked 与敏感模式策略、inclusion manifest 和覆盖清单符合契约;
- 采集部分失败时仍能导出并保留错误;
- 输出中 JSON/HTML snapshot identity 一致,权限符合预期;
- 大文档和总正文上限触发时明确标记截断。
**完成证据**:export tests、离线浏览器验收和治理文档回链完整。
---
## Verification Contract
### 自动验证
实施阶段至少运行:
```bash
go test ./internal/engineeringdashboard/...
go test ./cmd/engineering-dashboard/...
go vet ./...
go test -short ./...
git diff --check
```
涉及共享容器的只读验收也必须遵守 CURRENT 集成槽规则;中控台本身不得为测试启动、停止或重建共享容器。
### 契约验证矩阵
| 领域 | 必须证明 |
|---|---|
| 模型 | 计划、Git facets、验证、部署 facets 互不覆盖;Agent 声明和运行观测分离;所有派生结论可追溯到 facts。 |
| 文档 | taxonomy、全文检索、反链、broken/unindexed、路径安全与 assets 排除。 |
| Git | ahead/behind、worktree、dirty、local refs 新鲜度和无隐式 fetch。 |
| 部署 | container/app/service 三类信号分离,receipt/artifact 身份可核对。 |
| 降级 | 每个源超时、错误、stale、恢复都不会让整页不可用。 |
| 实时 | 变化在目标时间内形成完整新快照,不出现半新半旧卡片。 |
| 导出 | 单文件离线可读、默认 `0600`、不嵌 assets、不产生网络请求。 |
| 安全 | loopback、Host/Origin/startup token、read-only methods、命令 allowlist、路径边界、Docker 字段 allowlist、CSP 与输出脱敏。 |
### 浏览器验收
1. 从总览进入 rdev,确认“计划/实施/验证/实装”四轴与源文档链接均可见。
2. 在仓库外复制导出 HTML,断网打开并全文搜索、阅读至少一份设计与一份测试报告。
3. 制造 fixture 中的 CURRENT/Docker/readiness 冲突,确认页面保留多值且不出现综合绿灯。
4. 切换 fixture 快照,确认页面刷新后筛选条件和当前文档保持不变。
5. 尝试路径穿越、未知文档、POST、DNS rebinding、跨 Origin、readiness 重定向和含原始 HTML/脚本逃逸载荷的 Markdown,确认均不能越界、外联或执行。
### 性能与容量验证
- 记录当前 `.doc` 规模下的冷启动、增量刷新、JSON 大小和 HTML 导出大小。
- 建议一期门槛:UI shell 与来源状态在 2 秒内可交互,P95 完整快照重建不超过 5 秒,单源超时不超过 2 秒;基线不达标时必须记录实测并拆分后台正文索引,不能伪造 PASS。
- 导出达到配置上限时必须显式列出被截断文档,不允许静默丢失。
---
## Definition of Done
- [ ] `serve` 和 `export` 在显式仓库根下可重复运行,且没有产品后台依赖。
- [ ] 实时 HTML、离线 HTML 与 JSON 使用同一版本化快照契约。
- [ ] `generation_id` 标识采集实例,`revision_id` 标识内容版本并驱动 ETag;无内容变化不会触发重绘。
- [ ] 架构、模块、功能、任务、Git、部署、文档和证据链均可从页面访问。
- [ ] 计划、实施、验证、实装四轴独立,rdev、dev ahead、main events 分叉样本通过。
- [ ] Agent 认领与可观测活动分开,Herdr 工程 Agent 与产品 PI Agent Runner 不混称。
- [ ] 所有 drift、degraded、stale 都带来源和时间,不存在未经定义的综合绿灯。
- [ ] 默认 loopback、Host/Origin/startup token、只读命令、路径边界、脱敏、CSP 和 Markdown 安全测试通过。
- [ ] 首次加载、空数据、部分失败、无缓存失败、恢复、键盘、窄屏和 URL 深链验收通过。
- [ ] 导出 HTML 脱离仓库可读 Markdown,且不包含二进制 assets 或凭证数据。
- [ ] 单元、集成、全仓短测、浏览器验收和 `git diff --check` 均有真实输出。
- [ ] `.doc/test-reports` 报告回链任务文,FEATURE-MATRIX 与 CURRENT 按实际状态更新。
- [ ] 没有遗留调试入口、写操作按钮、未使用的替代模型或与产品后台重名的组件。
---
## Appendix
### 一期交付边界
一期交付:本地只读服务、版本化快照 JSON、架构/任务/Git/部署/文档视图、四轴状态、drift/degraded、全文搜索、安全文档阅读和单 HTML 导出。
后续评估:跨快照历史趋势、远端托管/CI 聚合、受限富文本与 Mermaid、跨仓库聚合、面向 Agent 的筛选查询 API。
永久排除:在页面中修改文档、切换或推送分支、控制 Agent、执行部署、读取密钥、成为产品后台模块。
### 方案依据
- `.doc/README.md` 定义的文档 taxonomy 与生命周期;
- `.doc/ops/CURRENT.md` 的焦点、认领、集成槽与环境声明;
- `.doc/status/FEATURE-MATRIX.md` 的模块完成度口径;
- `.doc/remediation/gap-matrix.md` 的发布门禁口径;
- `.doc/system-design/README.md` 与模块边界清单;
- Git/worktree、Docker/Compose、`/ready` 和 promotion receipts 的当前可观测能力。
@@ -0,0 +1,48 @@
---
title: "docgov 变更提案 HTTP + 前端接线"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/docgov-modification-proposal-http
worktree: .worktrees/feature-docgov-modification-proposal-http
mutex: docgov
---
# docgov 变更提案 HTTP + 前端接线
## 目标
暴露 `POST /api/v1/docgov/proposal`,前端「修改」快捷分支与 `ProposalConfirmCard` 走真实 propose/decide,不再本地假装成功。
## 范围
- API:`ProposeModification` 路由;decide 补 404/403 映射
- 前端:`docgov.ts` + `App.tsx` 接线
- 单测 + 真实 HTTP 证据
- 关闭 audit 缺口;dev 试点总开关证据归档
## 非目标
- 晋升 test/main
- 变更提案自动改写受控正文(批准后仍为 UI 演示增补)
## 步骤
1. [x] 实现 propose handler + 路由
2. [x] 前端 client + App 接线
3. [x] handler/client 单测
4. [x] 合入 dev + rebuild + 真实 HTTP
5. [x] push origin/dev;清理 author-only worktree
## 验收标准
- [x] `POST /api/v1/docgov/proposal` 可写库(单测)
- [x] 真实 HTTP claim → propose → decide PASS
- [x] audit 缺口 resolved;CURRENT 认领收敛
## 相关链接
- Audit: [../../audit/2026-09-17-docgov-modification-proposal-http-gap.md](../../audit/2026-09-17-docgov-modification-proposal-http-gap.md)
- Pilot: [../../test-reports/assets/2026-09-17-author-only-pilot/](../../test-reports/assets/2026-09-17-author-only-pilot/)
- Closeout: [../handoffs/2026-09-17-document-author-only-closeout.md](../handoffs/2026-09-17-document-author-only-closeout.md)
@@ -0,0 +1,47 @@
---
title: 文档编制人兼任审核批准方案
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Codex
branch: feature/document-author-only-plan
worktree: .worktrees/feature-document-author-only-plan
mutex: document-duty-policy-plan
---
# 文档编制人兼任审核批准方案
## 目标
基于当前源码形成管理员总授权、项目创建者逐文档选择的详细实施方案,交用户审核。
## 范围
权限、系统设置、工作流规划和冻结、文档三职、动作鉴权、状态机、前端、迁移与验收。
## 非目标
本次不修改业务代码、不变更数据库或共享容器、不推送。
## 步骤
1. [x] 阅读启动链并从本地 dev 建立隔离分支。
2. [x] 核查实现并记录证据。
3. [x] 编写方案、检查边界与验收覆盖。
## 验收标准
- [x] 方案覆盖用户两个权限层级及逐文档持久化。
- [x] 当前事实与拟议行为分开,列明实施单元与测试场景。
## 证据 / 备注
基线 dev adb48c8。已 fetch origin/dev,本地 dev 领先 44、落后 0,保留未推送集成成果;主工作区 feature/control-center-server 未切换。worktree 脚本默认从当前 HEAD 创建,故直接指定 dev 创建本 worktree,避免引入他人分支。
## 交付
- 方案:`.doc/remediation/2026-09-17-document-author-only-plan.md`
- 核查:`.doc/audit/2026-09-17-document-author-only-analysis.md`
- 本任务完成仅指方案交付,业务实现为 planned;R9/R10 待用户审核。
- 未合入 dev:方案保留在独立分支供审核;未推送、未修改业务代码或容器。
- 验证:源码与文档一致性检查、git diff --check;未执行业务测试。
@@ -0,0 +1,57 @@
---
title: "文档编制人兼任:U1 策略存储与总授权"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: sysadmin + document-duty-policy
---
# 文档编制人兼任:U1 策略存储与总授权
## 目标
落地 `workflow.allow_author_only_approval` 管理员总开关:默认关闭、严格 bool、revision CAS、事务内审计,并向 projectinstance 提供可参与激活事务的窄读取接口。
## 范围
- Goose 增量迁移(revision 列、种子行、策略审计表)
- `internal/sysadmin` 存储/服务/窄 Policy 接口
- `admin_system_handlers` 对本 key 的 `expected_revision` 协议
- 单元 / PG / HTTP 负例测试
## 非目标
- 逐文档 duty_policy(U2)
- 前端设置页文案(U5)
- 已激活实例紧急熔断
## 步骤
1. [x] 认领 CURRENT
2. [x] 迁移 00050
3. [x] sysadmin CAS + 审计 + PolicySource
4. [x] admin handler
5. [x] 测试与提交
## 验收标准
- [x] 管理员可开关;非管理员 403
- [x] null/字符串布尔拒绝
- [x] 并发 CAS 仅一版成功
- [x] 审计失败回滚设置
- [x] 窄接口可读 allowed+revision;缺行默认 false;DB 故障不伪装
## 相关链接
- Plan: `.doc/remediation/2026-09-17-document-author-only-plan.md` U1
- Checklist:
## 证据 / 备注
- `go test ./internal/sysadmin/ ./internal/server/ -run 'Settings|AuthorOnly|PGSettings|AdminSystem'` PASS
- `go test -short ./internal/sysadmin/ ./internal/server/` PASS
- Key: `workflow.allow_author_only_approval`
- 窄接口: `sysadmin.AuthorOnlyPolicySource`
@@ -0,0 +1,54 @@
---
title: "文档编制人兼任:U2 逐文档模式与激活"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: projectinstance + document-duty-policy
---
# 文档编制人兼任:U2 逐文档模式与激活
## 目标
落地逐文档 `duty_policy=author_only`:规划校验、预览摘要、激活 token 绑定策略 revision,激活事务内行锁串行化关闭总开关。
## 范围
- DocTaskPlan / PreviewSummary / ProjectSettings 扩展
- ResolveDocTaskDuty、Save/Preview/Activate 消费 U1 策略
- Goose 00051 token revision 列
- app 适配器装配、HTTP 错误码映射
- 单元测试
## 非目标
- Heal/文档投影(U3)
- 前端 UI(U5)
- 运行时动作多职责(U4/U6)
## 步骤
1. [x] 类型与解析器
2. [x] service/store/迁移
3. [x] app 装配与 handler
4. [x] 测试与提交
## 验收标准
- [x] 一位成员兼任可存/预览/激活(总开关开)
- [x] 总开关关时 Save 拒绝
- [x] 预览后 revision 变化旧 token 409
- [x] 未开模式只填作者仍 partial 拒绝
- [x] 旧快照缺 duty_policy 时 hash 稳定
## 相关链接
- Plan: `.doc/remediation/2026-09-17-document-author-only-plan.md` U2
## 证据 / 备注
- `go vet ./internal/projectinstance/ ./internal/app/ ./internal/server/`
- `go test -short ./internal/projectinstance/ ./internal/server/ ./internal/app/` PASS
@@ -0,0 +1,55 @@
---
title: "文档编制人兼任:U3 文档绑定与职责投影"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: docgov + docduty + bizdev + document-duty-policy
---
# 文档编制人兼任:U3 文档绑定与职责投影
## 目标
生成时写入实例治理职责并 `duty_locked`;heal/revoke 跳过锁定行;读侧投影 `duty_policy`。
## 范围
- Goose 00052:`document_records.duty_locked` / `duty_policy`
- `docgov.LockDocumentDuty` + 列表投影
- `docduty` heal/revoke `AND NOT duty_locked`
- `bizdev.InstanceDutySource` + `resolveTaskDocumentDuties` 治理分支;跳过 governed 内存 heal
- `app/instance_duty_adapter.go` 装配
## 非目标
- U4 动作鉴权 / allowed_actions
- U5/U6 前端
- 合入 `dev`
## 步骤
1. [x] 迁移
2. [x] docgov / docduty
3. [x] bizdev + app 适配器
4. [x] 测试与提交
## 验收标准
- [x] 受治理文档创建后 `duty_locked=true` 且三职来自实例
- [x] heal/revoke 不清锁定行(SQL 过滤 + 单测/PG 可选)
- [x] 生成后 governed 路径不再用项目默认覆盖内存态
- [x] 模块边界:bizdev/docduty/docgov 不导入 projectinstance
## 相关链接
- Plan: U3(文档绑定与职责投影一致性)
- 依赖:U1 `3b6def2`、U2 `c03d0a3`
## 证据 / 备注
- `go vet ./internal/docgov/ ./internal/docduty/ ./internal/bizdev/ ./internal/app/ ./internal/projectinstance/`
- `go test -short` 上述包 PASS
- PG:`TEST_DATABASE_URL` 未配置时 `Heal/Revoke SkipsDutyLocked` 自动跳过
@@ -0,0 +1,47 @@
---
title: "文档编制人兼任:U4 动作鉴权与审计"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: projectinstance + docgov + document-duty-policy
---
# 文档编制人兼任:U4 动作鉴权与审计
## 目标
ABAC 门禁识别 `duty_policy=author_only` 派生职责;审计 Details 携带 duty_policy。
## 范围
- `duty_action` / `stage_access` / `gate` 改用 `ResolveDocTaskDuty`
- `state_machine` Transition* Details 补 `duty_policy`
- author_only 动作矩阵与阶段可见性测试
## 非目标
- U5 UI / U6 浏览器闭环
## 步骤
1. [x] ABAC 三文件
2. [x] 审计详情
3. [x] 测试与提交
## 验收标准
- [x] author_only 规范存储(仅 Author ID)下 A 可 run/edit/submit/review/approve
- [x] 非 A 拒绝;阶段门禁将 author_only 视为 approvalManaged
- [x] 审计 Details 含 duty_policy
## 相关链接
- Plan: U4+U5 实施计划
- 依赖:U1–U3
## 证据 / 备注
- `go test -short ./internal/projectinstance/ ./internal/docgov/ ./internal/app/ ./internal/server/` PASS
@@ -0,0 +1,48 @@
---
title: "文档编制人兼任:U5 系统设置与逐文档 UI"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: web + document-duty-policy
---
# 文档编制人兼任:U5 系统设置与逐文档 UI
## 目标
前端识别 `duty_policy` / `author_only_policy`;项目设置可逐文档开启兼任。
## 范围
- `projectSettings.ts` 类型
- `projectSettingsDuties.ts` resolveClientDocTaskDuty + 校验
- `ProjectSettingsModal` 兼任勾选与预览
- SettingsSection 不改(白名单通用渲染)
## 非目标
- U6 多职责动作栏 / 浏览器 E2E
## 步骤
1. [x] 类型与 lib
2. [x] UI
3. [x] 测试与提交
## 验收标准
- [x] author_only 客户端校验通过且不计三人门槛
- [x] 总开关关闭时兼任勾选禁用并提示
- [x] 预览展示兼任文档计数
## 相关链接
- Plan: U4+U5 实施计划
## 证据 / 备注
- `npx tsc --noEmit` PASS
- `npm test` PASS(含 projectSettingsDuties author_only 用例)
@@ -0,0 +1,55 @@
---
title: "文档编制人兼任:U6 多职责动作与真实闭环"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/document-author-only-plan
worktree: ".worktrees/feature-document-author-only-plan"
mutex: web + document-duty-policy
---
# 文档编制人兼任:U6 多职责动作与真实闭环
## 目标
去掉 author-first 动作短路,把认领/送审/审核/批准接到真实 docgov HTTP,完成 author_only 端到端验收。
## 范围
- `web/src/api/docgov.ts` 四接口客户端
- `docGovActionVisibility` / `holdsDocDuty`
- `App.tsx` 真实 handler + 快捷指令
- `duty_policy` 透传与「编制人兼任」徽标
- 单测 + 真实闭环报告
## 非目标
- 变更提案 HTTP 路由(另记 audit)
- 合入 `dev` / 推送远端(未授权不推)
## 步骤
1. [x] API 客户端
2. [x] ID 直判可见性
3. [x] App 接线 + 驳回批准修正
4. [x] duty_policy 徽标透传
5. [x] 单测 / tsc
6. [x] 真实闭环与报告
## 验收标准
- [x] author_only 下 A 可见三动作;非 A 403
- [x] 真实 API 闭环写库与审计含 duty_policy
- [x] 浏览器可见「编制人兼任」徽标
- [x] 测试报告归档
## 相关链接
- Test report: [../../test-reports/2026-09-17-document-author-only-u6-test-report.md](../../test-reports/2026-09-17-document-author-only-u6-test-report.md)
- Remediation U6: [../../remediation/2026-09-17-document-author-only-plan.md](../../remediation/2026-09-17-document-author-only-plan.md)
## 证据 / 备注
- `npm test` 390 pass;`tsc --noEmit` clean
- assets: `test-reports/assets/2026-09-17-document-author-only-u6/`
@@ -0,0 +1,41 @@
---
title: "首次加载性能诊断与改进方案"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Codex
branch: feature/initial-load-performance-plan
worktree: .worktrees/feature-initial-load-performance-plan
mutex: loading-performance-audit
---
# 首次加载性能诊断与改进方案
## 目标
以源码、现有容器静态资源和只读浏览器测量定位首次加载瓶颈,输出可审核的分期改进方案。
## 范围
登录前首屏、登录后初始化、项目/文档首次打开、静态资源交付;区分事实与待验证假设。
## 非目标
不修改业务代码,不重启/重建共享服务,不触发真实对话或文档写任务,不提交或推送其他人的工作。
## 步骤
1. [x] 阅读仓库启动链;独立 dev 基线 worktree,主仓保留其他 Agent 分支。
2. [x] 采集数值基线和源码证据。
3. [x] 写 audit 和 remediation,同步 CURRENT,归档任务。
## 验收标准
- [x] 原因有文件位置或运行时测量支持,未覆盖环境明确标注。
- [x] 方案包含优先级、改动边界、性能预算、回归门禁和回滚。
## 证据 / 备注
仅诊断与方案,不代表优化已实施。fetch 后 origin/dev 落后本地 dev;不拉回或覆盖本地工作。worktree 从创建瞬间的 dev 建立。
## 交付
- 诊断:`.doc/audit/2026-09-17-initial-load-performance-audit.md`
- 方案:`.doc/remediation/2026-09-17-initial-load-performance-plan.md`
- 报告:`.doc/test-reports/2026-09-17-initial-load-performance-baseline.md`
- 本轮仅方案;没有业务代码、没有部署、未提交、未合dev、未推送。主仓仅同步本任务认领。
- 临时3199 Vite已停止;既有3100/8080/8081未重启。未占集成槽。
@@ -0,0 +1,57 @@
---
title: "rdev 模板深度补强 S1 续批(剩余 46 份)"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/rdev-template-depth-s1-continued
worktree: ".worktrees/feature-rdev-template-depth-s1-continued"
mutex: rdev-templates
---
# rdev 模板深度补强 S1 续批(剩余 46 份)
## 目标
将剩余 46 份 `rd_*` 模板按写作规范做同等深度补强,lint allowlist 扩至全 60 份,抽样真 PI 打样收口。
## 范围
- 批1:6 份评审记录
- 批2:阶段06 硬件/工艺 8 份
- 批3:阶段06 软件/检验/技术要求+清单 9 份
- 批4:阶段08 验证 12 份
- 批5:阶段10–13 转换/确认 11 份
- lint allowlist + 抽样真 PI + 文档同步
## 非目标
- S2/S3、P2 前端、P3 三样本全量 E2E、P4 键名空间化
- 晋升 test/main
## 步骤
1. [x] 批1 评审记录 6 份
2. [x] 批2 硬件/工艺 8 份
3. [x] 批3 软件/检验/清单 9 份
4. [x] 批4 验证 12 份
5. [x] 批5 转换/确认 11 份
6. [x] 抽样真 PI + 文档同步(合入 push 见 merge 步骤)
## 验收标准
- [x] 46 份无「按本阶段专业结构写」;lint allowlist 60/60
- [x] 抽样 1–2 份真 PI PASS(`rd_planning_review` + `rd_design_vv`,项目 6446)
- [x] FEATURE-MATRIX / 写作规范 / backlog 已更新
## 相关链接
- Backlog: [.doc/backlog/2026-09-17-rdev-phase2-backlog.md](../../backlog/2026-09-17-rdev-phase2-backlog.md)
- 写作规范: [.doc/system-design/project-workflow/08-rdev模板写作规范.md](../../system-design/project-workflow/08-rdev模板写作规范.md)
- 首批报告: [.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md](../../test-reports/2026-09-17-rdev-template-depth-test-report.md)
- 续批报告: [.doc/test-reports/2026-09-17-rdev-template-depth-s1-continued-test-report.md](../../test-reports/2026-09-17-rdev-template-depth-s1-continued-test-report.md)
## 证据 / 备注
- 资产:`.doc/test-reports/assets/2026-09-17-rdev-template-depth-s1-continued/`
- 附带:`fix(projectinstance): allocate next instance_no for planning drafts`
@@ -0,0 +1,54 @@
---
title: "rdev 模板深度补强 S0 + S1 首批"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/rdev-template-depth
worktree: ".worktrees/feature-rdev-template-depth"
mutex: rdev-templates
---
# rdev 模板深度补强 S0 + S1 首批
## 目标
修复 rdev leader prompt 错配,并为阶段 01–05 的 14 份 rdev 模板补齐 ISO 13485 专业章节与逐节写作指令,以 dev 真实 PI 打样验证收口。
## 范围
- S0.1 B1:`rdev_leader.md` + InstructionsFile 注入链
- S0.2:`rd_design_input_spec` 样例 + 写作规范 + lint
- S0.3:dev 真实 PI 打样
- S1 首批:阶段 01–05 共 14 份模板(分 3 批)
## 非目标
- overlay 机制本体、R1–R7 二期、per-stage 步骤定制、模型配置化、manifest 元数据、前端(P2)、键名空间化(P4)、阶段 06–13 模板
## 步骤
1. [x] S0.1 leader prompt 注入链(`6a09062`)
2. [x] S0.2 样例模板 + 规范 + lint(含于 `eb09b21`)
3. [x] S0.3 真实 PI 打样(项目 6424 intake + 6425 `rd_design_input_spec`)
4. [x] S1 批 1–3(`eb09b21`)
5. [x] 文档与门禁
## 验收标准
- [x] rdev leader AGENTS.md 含「设计控制」且不含「商务对接负责人」「CDO」
- [x] intake leader 回归仍含「商务对接负责人」
- [x] 14 份模板 lint 绿灯;真 PI 终稿五节实质论证
- [x] `go vet` + `go test -short` 全绿
## 相关链接
- Test report: [.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md](../../test-reports/2026-09-17-rdev-template-depth-test-report.md)
- Assets: [.doc/test-reports/assets/2026-09-17-rdev-template-depth/](../../test-reports/assets/2026-09-17-rdev-template-depth/)
- Backlog: [.doc/backlog/2026-09-17-rdev-phase2-backlog.md](../../backlog/2026-09-17-rdev-phase2-backlog.md)
- 写作规范: [.doc/system-design/project-workflow/08-rdev模板写作规范.md](../../system-design/project-workflow/08-rdev模板写作规范.md)
## 证据 / 备注
- 依赖 `feature/rdev-core`(尚未合 dev);合入前需 rebase 丢弃已进 dev 的 engineering-dashboard 重复提交。
- 真 PI:`run_1789635054471569201`(intake ~220s);`run_1789635960880707641`(DI ~450s,`stage=RD03_design_input`)。
@@ -0,0 +1,70 @@
---
title: "研发工作流(rdev)接入:13 阶段 / 60 文档任务"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: fix/docgov-stage-dynamic → feature/rdev-core
worktree: "-"
mutex: workflow-def
---
# 研发工作流(rdev)接入:13 阶段 / 60 文档任务
## 目标
在现有 5 个正式工作流外新增医疗第 4 工作流「研发设计控制流程」(key: `rdev`),完整承载参考项目 13 phase / 60 文档任务的 ISO 13485 DHF 设计控制链,并通过真实 PI 验收;随后完成全工作流任务键命名空间化(P4)。
## 范围
- 方案:[07-研发工作流rdev接入-设计与实施计划](../../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md)(P0–P4 五期;§8 四项决策已确认)
- P0:docgov Stage 去硬编码 + stage key 透传
- P1:rdev.v2.json manifest(13×60 一次到位)+ 60 份 rd_ 前缀模板 + catalog/seed/registry + squad kind 编排 + main-completed precheck + 齐套测试 + stub PG 全链路
- P2:前端激活规划/切换/前置 Banner + intent 文档名匹配 + prior docs 注入与血缘
- P3:真实 PI Agent E2E(rd_proposal / rd_planning_review / rd_sw_plan 三样本)+ CI 门禁扩四
- P4:现有工作流(main/pm/tm + 软件两盘点)任务键 `bd_`/`pm_`/`tm_`(`sw_`)空间化,alias 兼容式改名(D12),独立分支独立验收
## 非目标
- 二期增强全部移入 backlog:[2026-09-17-rdev-phase2-backlog](../../backlog/2026-09-17-rdev-phase2-backlog.md)(N/A 不适用页生成、UR/RS 结构化门禁、kind 专用门禁、depends_on 精确血缘、DMR 归档、sw_ 键盘点、complexity regulatory 注入)
- 云盘 canonical DHF/DMR 归档(本仓库无云盘模块)
- 软件域(non_medical_software)开放 rdev
## 步骤
1. [x] 用户确认方案 §8 四项决策(2026-09-17:名称「研发设计控制流程」/ 60 任务一次到位 / N/A 规划期关闭 + backlog / rd_ 前缀并扩展到现有工作流键名空间化)
2. [x] P0 分支 `fix/docgov-stage-dynamic`(StageKey 透传;已叠入 `feature/rdev-core`)
3. [x] P1 分支 `feature/rdev-core`(manifest/模板/seed/编排/precheck/齐套测试)
4. [ ] P2 分支 `feature/rdev-web-governance`(前端 + intent + 血缘)— **骨架已定,待独立认领**
5. [ ] P3 真实 PI 验收 + 报告归档 + FEATURE-MATRIX 更新 — **骨架已定,待独立认领**
6. [ ] P4 分支 `feature/workflow-key-namespace`(D12 alias 兼容式改名 + 双路径回归)— **骨架已定,待独立认领**
## 验收标准
- [x] `go vet ./...` && `go test -short` 相关包 PASS(P0+P1)
- [x] 齐套断言:manifest 60 任务 ↔ `templates/docs/rd_*.md` 存在非空;rd_ 键与既有任务键不相交
- [x] precheck:main 未 completed 时 rd 任务启动被拒且文案含 CDO
- [ ] PG 集成:rdev 实例 planning→live→推进(`TestPG_RDevActivateWithNAClose`,需 `TEST_DATABASE_URL`)
- [ ] web `npm test && npm run build` PASS;Playwright 抽检激活/推进(P2)
- [ ] 真实 PI + MiniMax 三样本 E2E 报告归档 `.doc/test-reports/`(P3)
- [ ] P4:旧 live 实例(旧键)+ 新实例(新键)双路径回归 PASS;全工作流任务键集合无交集
## 相关链接
- 设计方案: [07-研发工作流rdev接入-设计与实施计划](../../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md)
- 参考调研: [2026-09-17-rdev-workflow-reference-analysis](../research/2026-09-17-rdev-workflow-reference-analysis.md)
- 二期 backlog: [2026-09-17-rdev-phase2-backlog](../../backlog/2026-09-17-rdev-phase2-backlog.md)
- Checklist: -
- Handoff: -
- Test report: -
## 证据 / 备注
- 参考项目:`.refs/weichen-agent-system`(configs/workflows/rdev.yaml 60 stage、templates/docs 60 模板、squads/overlays 配套)
- 关键约束:WF-DEF-06(无流程级依赖,precheck 先例 test_manager);doc_id `doc_proj{pid}_{taskKey}` 平铺命名 → rd_ 前缀
## 合入说明(2026-09-17)
- P0+P1 已 `--no-ff` 合入本地 `dev`(含 template-depth S0+S1)。
- P2/P3/P4 仍 planned,待独立认领。
@@ -0,0 +1,40 @@
---
title: "功能启用与文档修改影响分析调研"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Codex
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: capability-impact-research
---
# 功能启用与文档修改影响分析调研
## 目标
核实已实现功能的有效启用状态,形成分阶段启用方案及需求追踪、增量影响分析设计。
## 范围
源码、配置、只读运行态、已有证据;研究报告与整改方案落盘。
## 非目标
本轮不修改业务代码、不启用开关、不改变共享容器或真实项目数据。
## 步骤
1. [x] 核实功能状态和接线。
2. [x] 调研已有修改报告、依赖与需求追踪模型。
3. [x] 编写详细报告和可实施方案,完成文档核查。
## 验收标准
- [x] 当前事实与历史验收分开;每项启用方案有前置条件、验收、回退。
- [x] 影响分析有版本、权限、增量更新、一致性和用户交互契约。
## 证据 / 备注
开始时 dev=8fdcd98,工作区干净;git pull --ff-only 返回 Already up to date。无集成槽占用、无 push 授权。
产物:
- [调研报告](../../ops/research/2026-09-20-capability-enablement-impact-research.md)
- [整改方案](../../remediation/2026-09-20-capability-enablement-impact-plan.md)
- [FEATURE-MATRIX 校准](../../status/FEATURE-MATRIX.md)
- [方案审阅记录](../../ops/research/2026-09-20-capability-enablement-impact-plan-review.md)
@@ -0,0 +1,49 @@
---
title: "2026-09-20 P0 热修(迁移 / 越权 / 稳定性 / 凭证)"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: docs/p0-closeout-2026-09-20
worktree: "-"
mutex: docs
---
# 2026-09-20 P0 热修
## 目标
关闭系统体检发现的 P0 critical:迁移断链、三项 IDOR、进程 panic/race、凭证泄漏与生产口令轮换。
## 范围
- Wave 0–4(见 [整改方案](../../remediation/2026-09-20-p0-remediation-plan.md))
- 后续实现分支:`fix/capability-merge-00058-2026-09-20`、`fix/authz-idor-hotfixes-2026-09-20`、`fix/runtime-panic-races-2026-09-20`、`fix/credential-hardening-2026-09-20`、`docs/p0-closeout-2026-09-20`
## 非目标
- main 分支对齐晋升
- FAV / SWBOOT-10 / D7 / MULTI_INTENT full
## 步骤
1. [x] Wave 0:审计与整改文档、CURRENT 认领、long-term 增补
2. [x] Wave 1:capability 合入 + 00058 + rebuild
3. [x] Wave 2:三项越权
4. [x] Wave 2b:panic/race/recover/XSS
5. [x] Wave 3:凭证 + 口令轮换
6. [x] Wave 4:测试报告与收口
## 验收标准
- [x] 见 [测试报告](../../test-reports/2026-09-20-p0-hotfixes-test-report.md)
## 相关链接
- Audit: [../../audit/2026-09-20-system-triage-audit.md](../../audit/2026-09-20-system-triage-audit.md)
- Remediation: [../../remediation/2026-09-20-p0-remediation-plan.md](../../remediation/2026-09-20-p0-remediation-plan.md)
- Test report: [../../test-reports/2026-09-20-p0-hotfixes-test-report.md](../../test-reports/2026-09-20-p0-hotfixes-test-report.md)
## 证据 / 备注
(各波次合入 commit 与健康输出)
@@ -0,0 +1,59 @@
---
title: "个人工程中控台:实时项目看板与离线 HTML 快照"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor-Auto
branch: feature/engineering-dashboard
worktree: .worktrees/feature-engineering-dashboard
mutex: engineering-dashboard
---
# 个人工程中控台:实时项目看板与离线 HTML 快照
## 目标
实现一个独立于产品后台的本地只读中控台,以同一不可变快照驱动实时页面、机器可读 JSON 与单文件 HTML 导出。
## 范围
- 聚合 `.doc`、Git/worktree、Docker/Compose、`/ready` 和晋升凭证。
- 展示架构、模块、功能、任务、分支、验证和环境实装证据。
- 提供 Markdown 搜索、阅读、正反向链接和证据链导航。
- 显示来源、新鲜度、degraded 与 drift,不把声明状态当作观测状态。
## 非目标
- 不接入产品后台、产品数据库或产品权限体系。
- 不写文档,不操作 Git、Docker、部署或 Herdr。
- 不隐式联网或执行 `git fetch`。
## 步骤
1. [x] U1:冻结快照、事实与四轴状态契约。
2. [x] U2:实现文档图谱与领域解析器。
3. [x] U3:实现 Git 与 worktree 采集。
4. [x] U4:实现运行态与部署证据采集。
5. [x] U5:实现对账、派生视图与新鲜度。
6. [x] U6:实现本地服务、总览与文档导航。
7. [x] U7:实现离线导出、脚本、浏览器验收和治理文档同步。
## 验收标准
- [x] 实时 HTML、离线 HTML 和 JSON 引用同一 `generation_id` 与 `revision_id`。
- [x] 计划、实施、验证、实装四轴独立展示。
- [x] rdev、dev ahead、main events 分叉三个真实样本按方案输出。
- [x] 单源失败时页面仍可用,且显示 stale/error/last-success。
- [x] 默认仅监听 loopback,无写操作、凭证暴露、路径越界和远程资源执行。
- [x] 导出 HTML 离开仓库后仍可阅读 Markdown,且不嵌入 assets。
## 相关链接
- 设计与实施方案:[../../archive/design/2026-09-17-personal-engineering-control-center-plan.md](../../archive/design/2026-09-17-personal-engineering-control-center-plan.md)
- Test report: [../../test-reports/2026-09-17-engineering-dashboard-test-report.md](../../test-reports/2026-09-17-engineering-dashboard-test-report.md)
## 证据 / 备注
- 实现提交序列见 `feature/engineering-dashboard`(U1→U7)。
- 启动:`./scripts/engineering-dashboard.sh serve --repo . --addr 127.0.0.1:8787`
- 导出:`./scripts/engineering-dashboard.sh export --repo . --output /tmp/engdash.html`
@@ -0,0 +1,45 @@
---
title: "临时验证脚本 Path 空字符串拼接导致跨任务取证串味"
status: done
created: 2026-09-17
updated: 2026-09-17
severity: low
---
# 临时验证脚本 Path 空字符串拼接导致跨任务取证串味
## 现象
S0.3 真 PI 打样归档时,`rd_design_input_spec-final.md` 一度被写成无关客户的商务对标报告(「掌上无线超声系统 × GE Vscan / Philips Lumify」),而非设计输入规格书终稿。
## 根因分析
产品侧小队/工作区创建正常:失败的 `rd_*` 请求因 main-completed 硬 precheck 拒绝,`task_runs.WorkspaceID` 如实为空。
缺陷在**本地临时取证脚本**(`.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_*.py`)的兜底逻辑:
1. `ws_id = pi_result.get("workspace_id") or ""` 在响应无该字段时得到空串;
2. Python `pathlib`:`Path(bizdev_root) / ""` **坍缩为父目录本身**(无报错);
3. 随后 `root.rglob("output.md")` 扫遍共享 `data/dev/workspaces/bizdev/` 全树;
4. 「取最长文本」启发式选中历史商务任务终稿并误归档。
证据:会话内 `task_runs` 失败记录 `WorkspaceID=""`;`Path('/a/b') / '' == Path('/a/b')` 可复现;误归档文件内含 `adhoc_GEVsca_...` 工作区路径。
## 严重度
`low` — 仅本地取证脚本;未污染产品库、未改小队/黑板创建逻辑;同轮已用精确工作区路径重归档并随测试报告提交干净终稿。
## 关联整改
- 无需产品代码改动。
- 经验红线:临时验证脚本禁止「空路径拼接 + 全树 `rglob` + 取最大值」组合;`work_dir`/`WorkspaceID` 为空时必须失败退出,不得扩大搜索范围。
## 证据
- 正确终稿:`.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md`
- 测试报告:`.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md`
- 工作区 ID 生成:`internal/squad/workspace.go`(`ws_%s_%d` + UnixNano)
## 开放问题
- 无。
@@ -0,0 +1,32 @@
---
title: "docgov 变更提案缺少 HTTP 路由"
status: resolved
created: 2026-09-17
updated: 2026-09-17
severity: medium
---
# docgov 变更提案缺少 HTTP 路由
## 现象
引擎侧存在 `docgov.ProposeModification` / `DecideModificationProposal`,但服务端此前仅注册 `POST /api/v1/docgov/proposal/decide`;前端 `App.tsx`「变更方案提议」(`pendingProposal`)为本地模拟。
## 根因分析
生命周期三接口与 claim 已注册;变更提案 **propose** 路径从未暴露为 HTTP。
## 严重度
`medium` — 不阻塞编制→审核→批准主链;阻塞「认领后小队修改须提案确认」的真实治理。
## 处置(resolved)
- 新增 `POST /api/v1/docgov/proposal` → `ProposeModification`
- 前端 `proposeModification` / `decideModificationProposal` + App 接线
- 单测:`TestServer_DocGovProposeAndDecideHTTP`、`web/src/api/docgov.test.ts`
- 任务:`.doc/ops/short-term/2026-09-17-docgov-modification-proposal-http.md`
## 证据
- 合入后真实 HTTP 证据见 `.doc/test-reports/assets/2026-09-17-docgov-modification-proposal-http/`
@@ -0,0 +1,45 @@
---
title: 文档编制人兼任模式源码核查
status: done
created: 2026-09-17
updated: 2026-09-17
severity: medium
---
# 文档编制人兼任模式源码核查
## 结论
当前 dev 基线 adb48c8 不支持本需求。已有标准三人审批、可选免审批、系统设置白名单可复用,但必须补齐逐文档模式、职责来源和前端多职责。
## 根因与证据
1. `internal/projectinstance/duty_mode.go`:partial 拒绝,full 要求三人分离。
2. `internal/projectinstance/service.go`:创建者规划权限与激活后冻结已存在。新需求需在这条链上增加总授权,不能只改 UI。
3. `internal/docduty/store.go`:HealProjectDocuments 按项目默认职责回填受控文档。`internal/docgov/project_docs.go` 在列表读取时调用;`internal/bizdev/service.go` 在生成后调用。新增逐文档策略必须阻止该链覆盖实例职责。
4. `web/src/lib/currentDocRole.ts` 优先返回 author;`docGovActionVisibility.ts` 按单角色显示动作。同人三职会缺审核和批准入口。
5. `internal/server/handlers.go` 三个动作端点固定使用相应 action role,并以登录身份调用引擎;`internal/docgov/state_machine.go` 可复用逐步流转。
6. `internal/sysadmin/settings.go` 有白名单 bool 设置,但没有本需求 key;存储只保留最后修改人时间,新策略需独立版本与审计。
以上为静态源码核查,未查询真实用户数据,未执行功能测试,未声称线上已复现或已修复。完整源码映射与实施单元见方案。
## 关联方案
[文档编制人兼任审核批准](../remediation/2026-09-17-document-author-only-plan.md)
## 文档检查
已检查两级权限、逐文档独立性、full/none 兼容、前后端职责来源、状态与锁、并发授权撤销、成员退出、迁移及回滚。修正一处 docflow 路径为 internal/app/docflow。方案明确区分已知事实与建议口径。
ce-doc-review 未运行:当前工具目录未提供可调用的 skill invocation 入口;按 ce-plan 的 skill_unreachable 分支记录,不能把本地自检当作独立文档审查通过。
```yaml
fixes_applied: 0
proposed_fixes_count: 0
decisions_count: 0
fyi_count: 0
skipped_reason: skill_unreachable
skipped_detail: No callable skill invocation interface in this session; local source and consistency checks only.
```
上方计数仅为未运行技能的占位,不代表产品决策已解决。开放问题仍为 R9、R10;用户未答复时保持方案建议,业务实现不得自行视为授权。
@@ -0,0 +1,117 @@
---
title: "首次加载慢:静态资源、字体与初始化请求诊断"
status: done
created: 2026-09-17
updated: 2026-09-17
severity: high
---
# 首次加载性能诊断
## 结论与适用范围
当前已复现的主要问题在浏览器加载入口:登录页也下载约 2.82 MB 未压缩 JavaScript;外部 Google Fonts CSS 阻塞页面加载;若用户访问 Vite 3100,首访进一步扩大为 207 个资源请求、12.24 MB。冷缓存与热缓存差异很大,与“尤其第一次慢”一致。
登录后还有已确认的请求放大和后端重复工作,但没有登录态浏览器瀑布图或 SQL 耗时,不能声称已量化其贡献。用户已确认 3100/8080/8081,系统重启后第一次访问约十数秒;设备、网络与“系统重启”包含宿主机还是仅应用尚未确认;本次未复现用户原始环境的完整等待时间。
- 主仓读取时 `feature/rdev-core@52f0fbc`;其他 Agent 正在工作,未切换其分支。
- 文档独立 worktree 基线为 `dev@d0ef696`。创建前已 fetch;本地 dev 有未推送提交,未 reset/覆盖。
- 实测现有 8080/8081/8000 构建入口与 3100 Vite;以资源 hash 为运行产物标识,**没有证据证明容器恰好等于上述源码 commit**。
- “首次”定义为新浏览器 context、空 HTTP 缓存;没有重启服务、清空 DB 缓存或重启 Vite,故不是服务/依赖预构建冷启动。
- 未登录、没有调用对话/文档写接口;浏览器探针未使用真实用户会话。
## 实测基线
工具:隔离 Playwright v1.63.0 Docker 浏览器,host 网络访问既有服务。宿主浏览器缺 libatk,改用本机已有浏览器镜像;未修改应用容器。每个场景一个样本,仅诊断,不是 p95 或交付验收。
| 场景 | 登录输入框可见 | FCP | 资源数 | transferSize 合计 |
|---|---:|---:|---:|---:|
| 8080 本机冷缓存 | 662 ms | 664 ms | 4 | 2,857,761 B |
| 同 context 再次导航 | 62 ms | 60 ms | 5 | 353 B |
| 8080 CDP 10 Mbps / 80 ms 冷缓存 | 2,636 ms | 2,636 ms | 4 | 2,857,761 B |
| 同 context 再次导航 | 60 ms | 60 ms | 5 | 353 B |
| 8080 CDP 2 Mbps / 80 ms 冷缓存 | 11,776 ms | 11,776 ms | 4 | 2,857,761 B |
| 3100 本机冷缓存 | 659 ms | 652 ms | 207 | 12,238,086 B |
| 3100 同 context 再次导航 | 162 ms | 160 ms | 208 | 52,253 B |
transferSize 是浏览器 Resource Timing 可观测资源求和,不含顶层 HTML,不等于全链路抓包流量。输入框可见按导航命令开始至 selector 可见计时,FCP 来自页面 Performance API,两者采样时钟和帧提交不同。CDP 限速为模拟设置,不能代替真实公网 RTT;本机 document TTFB 仍约 1–3 ms。首次/再次均保持已有服务运行,未运行 Vite 冷预构建基准。
### F1. 入口包过大且未按需加载(高置信)
- `web/src/main.tsx:2` 静态导入 App;`web/src/App.tsx:98,103,108,145-146` 静态导入导出、系统管理、文件预览等模块;未登录判断直到 `App.tsx:3461`,无法避免入口依赖下载和求值。
- `web/src/features/replyExport/download.ts:1` → docx;`web/src/engine/docxRenderer.ts:19-22` → docx、KaTeX、Mermaid;`web/src/engine/xlsxRenderer.ts:1` → XLSX。
- `web/src/components/doc/preview/FilePreviewPanel.tsx:19-24` 全部静态导入预览器;DocxViewer、ExcelViewer 各自静态导入重依赖。
- 浏览器访问登录页即可观测大 JS。3100 瀑布中含 katex.js 485,944 B、xlsx.js 870,702 B(decodedBodySize)。并非仅仅源码中出现依赖但构建已经排除。
- 8080 主 JS `/assets/index-BLnmtk_3.js` = **2,820,055 B**;8081 = 2,805,141 B;8000 = 2,798,137 B。
因果链:空缓存 → 登录视图与全部工具共入口 → 下载/解析无关依赖 → 网络较慢时登录表单迟迟出现。10 Mbps 下主 JS 下载约 2,373 ms;2 Mbps 首屏约 11.78 秒。没有采集 CPU trace,不能进一步把时间分解成具体库的执行成本。
### F2. 静态响应无压缩、无明确长缓存策略(高置信)
- 三个构建入口均携带 `Accept-Encoding: gzip, br` 请求主 JS,响应没有 `Content-Encoding`,`Content-Length` 为原始字节数。
- `internal/server/server.go:344-384` 使用 `http.ServeFile`,没有静态压缩协商或显式 Cache-Control。
- 同一 8080 JS 离线 gzip 后 **796,146 B**,相对原始包减少约 **71.8%**。这是体积估算,不是已部署优化结果,也不是端到端提速承诺。
- 资源有 Last-Modified,没有显式 Cache-Control/ETag。本次再次导航已命中浏览器缓存;**不能写成“完全没有缓存”**。问题是版本化资源缺少可预测的长期缓存契约。
源站是上述行为,未知用户实际入口是否另有反向代理压缩。优先在真正提供构建资源的层验证和修复。
### F3. 外部字体 CSS 可放大首次白屏(高置信机制,用户网络贡献待测)
- `web/index.html:9-15` 的 Google Fonts 是 head 中普通 stylesheet。`display=swap` 控制字体显示,不会让外链 CSS 本身变为非阻塞。
- 本机自然请求字体 CSS 耗时 **508 ms**,DOMContentLoaded 609 ms,登录可见 662 ms。
- 浏览器拦截并立即失败字体 CSS:登录可见 **210 ms**。Playwright route 会禁用 HTTP cache,因此这个场景不能用于热缓存收益对比,也不能据单样本得出精确净收益。
- 控制实验仅让字体 CSS 等待 5 秒再失败,其余请求正常:DOMContentLoaded **5,111 ms**、登录可见 **5,161 ms**。证明该依赖可以把外部等待传到登录首屏,**不表示自然字体请求真的用了 5 秒**。
### F4. 登录后项目成员扇出并放大会话同步(源码已证实,耗时待测)
`web/src/App.tsx:524-540` 获取项目后,对每个项目调用成员接口;`:383-387` 每次成员结果用 map 生成新的 projects 数组;`:560-590` 的会话列表 effect 依赖 projects,因此成员返回可重复触发会话列表请求。取消标志仅忽略部分返回,没有 AbortController 终止已发请求。React 批处理可能合并更新,**不能写成固定 N 次会话请求**。
项目数 N 增大时,初始成员请求为 N,叠加会话重取、setProjects 及本地持久化。`web/src/data/storage.ts:63` JSON.stringify + localStorage.setItem,`App.tsx:343` 随 projects 更新保存。持久化是否成为长任务还须 profile,不能预设为主要根因。
### F5. 认证有重复查询和同 session 写放大(源码已证实,耗时待测)
`internal/server/auth_middleware.go:48,62` 已认证并保存 principal;`internal/server/auth_handlers.go:126-139` 的 me 再认证。每次经 `internal/auth/service.go:197-203`、`internal/auth/pg_store.go:335-367` 执行 SELECT session、SELECT status、UPDATE session、GetUserByID。正常 PG me 路径共 8 次认证 DB 操作,加一次权限查询。
其他鉴权请求也无条件 UPDATE 同一 auth_sessions 行;首屏并发可能放大行锁/连接等待。未采集 pg_stat_activity/锁等待或接口 p95,锁竞争是待验证风险。
### F6. 文档列表的隐含写修复与轮询叠加(源码已证实,耗时待测)
`internal/docgov/project_docs.go:59-74` 列表先调用 `HealProjectDocuments`;`internal/docduty/store.go:173-205` 开事务并取得项目 advisory lock(`internal/docduty/revoke.go:111-126`),重复读取创建者/成员,扫描文档,按需逐条 UPDATE,commit 后才正式 SELECT。
前端 `App.tsx:1507-1545` 每 5 秒为租约同步调用这个完整列表。请求时长超过间隔时可能重叠;相同项目多个标签放大成本。**不能直接删除 heal**:须先补齐创建/成员变更/转交/撤销写路径与历史数据修复闭环。本轮没有用该 GET 做只读探针。
### F7. 会话列表先聚合消息再分页(源码已证实,耗时待测)
`internal/ctxmgr/chat_history.go:110-125` 候选会话 JOIN 消息、COUNT、GROUP BY/ORDER BY 后 LIMIT,另取最新消息内容。仅返回少量会话不代表少量消息扫描。`internal/projectworkflow/store.go:171-240` 项目列表也无分页。
已有 `chat_messages(session_id, created_at)` 索引(`deploy/postgres/goose/00001_baseline.sql:119`);不笼统认定缺索引。先 EXPLAIN/数据量和可见性分析,再决定先分页后统计、索引或摘要。
### F8. 重启场景补查(用户补充后)
用户明确 3100、8080、8081 在系统重启后首次进入约十数秒。三种冷态须分开:浏览器 HTTP 缓存、Vite 转换/依赖缓存、Go/DB/代理启动就绪。重启若不改变构建 hash,并不会自动清掉浏览器持久 HTTP 缓存;不能直接用新 context 测量解释全部重启现象。
现存容器启动记录:dev StartedAt `2026-09-17T07:00:38.127811581Z`,打印“监听地址”于 `07:00:38.293728694Z`(约 **166 ms**);test StartedAt `06:20:05.243037366Z`,打印监听于 `06:20:05.384607542Z`(约 **142 ms**)。这是已有 DB 就绪条件下的一次启动、且日志先于真正 ListenAndServe,**不是 host reboot→ready 时间**;但未支持“Go 每次初始化必然十几秒”。
`cmd/server/main.go:41-50` 的初始化在监听前,`internal/bizdev/service.go:69-114` 包括 DB Ping/迁移/成员补齐/seed;DB连接段 timeout 5 秒,后续 seed 使用 Background,缺少分阶段耗时。`internal/app/app.go:355` 的 Runtime.Start 幂等,入口重复调用不会重复启动 worker,不能据此误判双倍启动。
Compose app healthcheck 每 10 秒、start_period 20 秒;start_period 是失败宽限窗口,**不代表强制等待20秒**。若代理/运维脚本等健康状态才放流,则探测周期可能影响可见就绪,需要对齐宿主启动、DB healthy、app listen、ready、首次请求时间。3100 的无缓存 Vite 预构建/按请求转换为独立候选,8080/8081 构建产物不存在 Vite 首次编译。
隔离 Vite 在 3199 使用独立空 cacheDir,同源码、未重启宿主/DB:监听准备 43 ms,首访登录可见 **1,580 ms**、207 资源/14,445,631 B,再次 171 ms。服务先启动、浏览器随后连接,部分预构建可能已在导航前完成;该值不是“启动到首屏”总时间。支持开发冷态有额外成本,但本机未复现自然网络十数秒;不得仅靠 warmup 宣称已解决 8080/8081。证据见 `../test-reports/assets/2026-09-17-initial-load-performance/vite-cold.json`。
本轮不重启正在使用的共享服务;U1/U7 纳入计划中的隔离重启矩阵和阶段计时。没有把服务冷启动排除在用户需求之外。
## 已排除与未证明
- 本机静态 HTML TTFB 约 1–3 ms;这组未登录测试并非后端生成首页耗时数秒。
- 没有请求产品 PI Runner,因此本次首屏慢不能归因于大模型冷启动。
- 服务监听前迁移/种子初始化(`cmd/server/main.go:41-50,84-85`;`internal/bizdev/service.go:69-114`)只解释重启就绪,不等于每个新浏览器首访。
- 没有用户重启时的 FRP/公网瀑布、登录后基线、慢 CPU profile、数据库 EXPLAIN;不对这些项宣称已复现。
- 基线现有测试以功能为主;本轮未发现首屏资源预算/冷缓存性能门禁。未运行业务测试,因为没有业务代码变更。
## 关联整改与证据
- [改进方案](../remediation/2026-09-17-initial-load-performance-plan.md)
- [诊断测量报告](../test-reports/2026-09-17-initial-load-performance-baseline.md)
- [完整浏览器数据](../test-reports/assets/2026-09-17-initial-load-performance/browser.json)
- [受控实验](../test-reports/assets/2026-09-17-initial-load-performance/controlled.json)
- [静态响应摘要](../test-reports/assets/2026-09-17-initial-load-performance/assets.json)
@@ -0,0 +1,180 @@
---
title: "系统全面体检:任务收口、缺陷与未启用功能审计"
status: done
created: 2026-09-17
updated: 2026-09-17
severity: high
---
# 系统全面体检(2026-09-17)
> 范围:① 规划未实现 / 需变更 / 实施中任务;② 现存与潜在 bug;③ 已实现但未启用或未测试的功能。
> 方法:文档 SSOT 盘点(CURRENT / FEATURE-MATRIX / gap-matrix / short-term / long-term / backlog / ADR / handoff)+ Go 全量 vet/build/test + 前端 test/build + 特性开关与环境配置交叉核对。只读审计,未实施任何修改。
> 基线验证:`go vet ./...` 与 `go build ./...` 全绿;`go test -short -count=1 ./...` 62 包全 ok;`web` npm test(380+32)与 build 通过。
---
## 一、任务状态盘点
### 1.1 实施中(in_progress)
| # | 任务 | 位置 | 剩余工作 |
|---|------|------|----------|
| T1 | partial/deferred 全量收口总控 | `.doc/ops/short-term/2026-09-16-partial-deferred-completion.md`(owner Cline) | W5(SWBOOT-10 真实现 + 真实 PI + UI 二次验收)、W6(FAV shadow→live 放量)、W7(D7 按 ADR 整改,待合规签字)、逐行升 done |
| T2 | Control Center 个人中控台 | 2026-09-19 已移出本仓库 | 进度管理改由独立项目承担;本仓库不再保留该模块 |
| T3 | 纯软件项目自举 W5b | `.doc/ops/long-term/2026-09-14-software-project-bootstrap-implementation.md` | SWBOOT-10 受控执行器(真 patch/merge)未启动,需独立安全评审,当前 fail-closed stub |
### 1.2 已规划未开始
| # | 任务 | 位置 |
|---|------|------|
| T4 | 首次加载性能 U1/U3–U7 | `.doc/remediation/2026-09-17-initial-load-performance-plan.md`(仅 U2 done:主 JS 传输 2.82 MB→~624 KB) |
| T5 | 选择性模块解耦 M4–M6 | `.doc/ops/long-term/2026-09-14-selective-module-decoupling.md`(planned,owner=TBD) |
| T6 | 产品 backlog:B5 报价复核、A5/A6 小队降级与 trace、A7 中文注释迁移、D5 KB 按环境隔离评估 | `.doc/backlog/chat-agent-p6-backlog.md`(均无任务文件) |
| T7 | `TestReconcile_LegacyRepair_PG` 工程测试债 | gap-matrix DOC-CONTENT-CANONICAL-HASH-DRIFT 行(需隔离 PG,本机无) |
| T8 | IAM 收尾开放项:410 退役产品拍板、R13 全量清单勾选 | handoff `2026-09-16-phase3-leftover-closeout.md` |
### 1.3 部分完成(partial,剩余关闭条件)
| 行 | 剩余关闭条件 |
|----|--------------|
| 纯软件项目自举 | SWBOOT-10 非 stub(W5b)+ 真实 PI 全链路 + UI 二次验收 |
| FAV | W6 shadow 已合;live 未放量(staging→artifact→publication 各 ≥7 天观察窗) |
| Control Center | 2026-09-19 已移出本仓库,不再作为本仓库关闭条件 |
| 首次加载性能 | U1/U3–U7 |
| 文档可靠性试点 | M1 结论「停止扩面」;M2(U5–U12)明确禁止开工,真实 PI/浏览器验收未勾 |
### 1.4 deferred 待决策
- **D7 对话数据治理**:ADR `2026-09-17-d7-chat-data-retention.md` 仍 `pending-compliance-signoff`;W7 盘点未发现违规;签字前禁止物理删除。
- **`SEMANTIC_SUMMARY_REPLACE`**:决策默认不启用;启用须另开授权 + fail-closed 灰度。
- **`MULTI_INTENT_PLAN_TIER` 升 confirm**:W4 证据闭环,升级需独立授权;永不默认 full。
### 1.5 文档漂移 / 矛盾(文档债)
| # | 漂移 | 涉及文件 |
|---|------|----------|
| D-1 | PU8 四份契约文件仍 `status: in_progress`,但 U9–U12 已升 done、报告已归档 | `.doc/ops/long-term/2026-09-16-pu8-u9/u10/u11/u12-*.md` |
| D-2 | ADR modular-monolith-decoupling 仍「提议,等待用户确认」,但 Phase 1/2 已落地并被当作已确认结论引用 | `.doc/adr/2026-09-14-modular-monolith-decoupling.md` |
| D-3 | audit/INDEX.md 与 remediation/INDEX.md 末行称首次加载性能「方案未实施」,与 U2 已验收矛盾 | 两个 INDEX.md(**本审计已顺手修正为准确表述**) |
| D-4 | handoff `2026-09-15-conversation-intent-dual-tab.md` 的「未完成」已被后续 PASS 覆盖但未回标 | 该 handoff |
| D-5 | backlog D3/D7 条目与 W2 done、W7/ADR 草案并存,backlog 未同步 | `.doc/backlog/chat-agent-p6-backlog.md` |
| D-6 | PROJECT.md §9「剩余 blocker」表述与 gap-matrix「门禁已签、production_ready=yes」口径冲突 | `PROJECT.md` |
---
## 二、Bug 清单
### 2.1 确认 bug(有明确证据)
**后端**
| ID | 描述 | 证据 | 严重度 |
|----|------|------|--------|
| B-1 | **SSE 聊天流被全局 WriteTimeout=120s 强杀**:`server.go:350` 的 WriteTimeout 是绝对期限;`handleChatStream`(`sse.go:129`)从不调用 `extendSSEWriteDeadline`、无心跳,该机制只接到了 run-events 订阅端点。任何 >120s 的聊天回合(长 PI 推演常见)必断流 | `internal/server/server.go:350`、`internal/server/sse.go:46-64,129` | high |
| B-2 | **`POST /tasks/run/stream` 同样无 deadline 延长/心跳**,且断线后无法续订:`sse.go:390` 写死 `Subscribe(created.RunID, 0)`,不接受 `after_seq` | `internal/server/sse.go:305-424,390` | high |
| B-3 | `handleRunTaskStream` **静默吞 JSON 解析错误**:`_ = json.NewDecoder(r.Body).Decode(&req)`,畸形 body 以空请求走默认 `TaskKey="intake"`,可能误启动 intake 任务 | `internal/server/sse.go:315,362-364` | medium |
| B-4 | `handleRunTaskStream` **Flush 200 SSE 头之后才做会失败的操作**(CreateAndStart/Subscribe),失败时往 SSE 流里写 JSON 错误体;同文件 chat 路径明确「授权必须在 Flush 前」,task 路径未对齐 | `internal/server/sse.go:355-360,383-393` | medium |
**前端**
| ID | 描述 | 证据 | 严重度 |
|----|------|------|--------|
| B-5 | **会话窗口缓存 key 不一致**:读/初次写带 `userId` 前缀,但 `loadOlder`/`loadFullDay`/`jumpToDate`/`loadDayForAnchor`/`appendLiveMessage` 等 7 处后续写入不带前缀 → 刷新/切会话恢复到旧窗口;且 LRU 驱逐只用无前缀 key,带前缀缓存永不驱逐,localStorage 只增不减 | `web/src/hooks/useChatWindow.ts:84,100,136,235,271,315,365,416,439,471`、`web/src/data/storage.ts:164-176` | high |
| B-6 | **mount 时 IndexedDB 恢复用陈旧快照整体覆盖 deliverables**:捕获 mount 闭包、非函数式 set,resolve 前新增的 deliverable 被静默丢弃(旁边已有 `deliverablesRef` 未用) | `web/src/App.tsx:326-336` | medium |
| B-7 | `useTaskRunStream` 返回**伪 ref**(每渲染新建对象、快照值非 live),且全仓库无消费方——误导性 API | `web/src/hooks/useTaskRunStream.ts:96` | low |
### 2.2 高风险隐患
| ID | 描述 | 证据 |
|----|------|------|
| R-1 | **聊天会话无归属校验**:`getOrCreateSession` 仅凭客户端传入 `session_id` 返回既有内存会话,随后直接覆盖 `sess.UserID`;非项目会话(ProjectID==0)无任何授权关卡,内存 Messages/Facts 可进入他人 Prompt 与 SSE。缓解:session ID 为纳秒时间戳不易猜 | `internal/server/server.go:394-415`、`handlers.go:181`、`sse.go:187`、`stage_access_helpers.go:251-253` |
| R-2 | **18 个非测试文件 `rows.Next()` 循环后未查 `rows.Err()`**,中途断连静默截断结果集(ctxmgr 历史/窗口/搜索、docgov engine、freedoc、storage/cas、`cmd/document-content-reconcile` 漏检会让 reconcile 漏报文档) | 如 `internal/ctxmgr/chat_history.go`、`internal/docgov/engine.go`、`cmd/document-content-reconcile/main.go:82` |
| R-3 | 事件 dispatcher `Handlers` map **写持锁、读不持锁**(当前仅启动期注册则良性,动态注册即 race) | `internal/events/worker.go:87,154,234` |
| R-4 | `memTurns` 全局幂等表只增不删且跨实例共享,长期运行内存缓增、测试间可能串扰 | `internal/ctxmgr/chat_turns.go:169` |
| R-5 | `internal/docrevision/pg_store.go:68-208` 十余处 `_ = json.Unmarshal(...)`,账本 JSONB 损坏时静默零值化 | 同左 |
| R-6 | 后台 ticker goroutine 无关停通道(通知提醒、vault Drain 错误被丢弃、bizdev 心跳用 `context.Background()`),`Shutdown` 未覆盖 | `notification_reminder_loop.go:15`、`vault.go:63`、`bizdev/service.go:682` |
| R-7 | SSE 重连对 401/404 无 fail-fast:任何错误一律退避重连 40 次(~3 分钟)期间 UI 一直 thinking;`streamChat` 对畸形 data 帧直接抛错中断整条流 | `web/src/api/taskRuns.ts:108-140`、`api/chatStream.ts:122` |
| R-8 | 组件卸载/登出不 abort 任务流,在途 SSE 继续写 localStorage | `web/src/App.tsx:595,2804` |
### 2.3 环境 / 配置缺陷
| ID | 描述 | 证据 | 严重度 |
|----|------|------|--------|
| E-1 | **main 环境 app `ENV=prod` 与 events `ENV=main` 不一致**:事件信封以 `Environment="prod"` 写入,而 `event_consumer_modes` 只种子 dev/test/main 三行 → app 侧 `WriterLive("prod")` 恒 false(in-process 直连不退出),events worker 按 'main' 判定 → **main 存在双写或 durable 管道空转风险**(取决于 main 行 mode)。dev/test 两服务 ENV 一致,无此问题 | `docker-compose.main.yml:90,160`、`internal/app/docflow/commands.go:276`、`goose/00040:55-59`、`internal/events/dispatcher.go:308-313` | **critical(main 专属)** |
| E-2 | **main schema 落后两版(47 vs dev 49)**:00048 给 projects 加 13 列,当前 HEAD 代码直接 SELECT/INSERT 这些列;00049 建 system_settings。若把 dev HEAD 镜像升 main 而不先跑迁移,项目工作流查询/系统设置 API 直接 SQL 报错。**main 晋升顺序必须 events(跑迁移)先于 app** | `goose/00048`、`goose/00049`、`internal/projectworkflow/store.go:76,113` | high(晋升窗口) |
| E-3 | `MULTI_INTENT_PLAN_TIER` 未在任何 compose environment 声明(configs/.env 设了也传不进容器);test/main 连 U9–U12 flag 都未声明 → 容器内锁死 legacy,授权升级时需先改 compose | `docker-compose.*.yml` | medium |
| E-4 | `CURSOR_RUNNER_URL` 三环境 compose 都注入但代码零读取;cursor-agent 容器是 alpine 占位,cursor-cli 后端容器部署不可达 | `docker-compose.*.yml` | low |
| E-5 | `ENABLE_DEV_IMPORT` 不在任何 compose/.env.example;且判断把 `cfg.Env==""` 也算 dev——配置缺失时导入门禁自动放开 | `internal/server/chat_window_api.go:171` | medium |
| E-6 | `SEED_DEMO_USERS` 仅 test compose 显式 false;dev 依赖默认播种(demo 密码 123456),main 靠代码 `Env!="dev/test"` 兜底,主 compose 未显式关闭 | `docker-compose.test.yml:91`、`internal/auth/bootstrap.go:67-116` | low |
| E-7 | `INTENT_V2_DECISION_TIER` 非法值回退 `query`(激进),与 `MULTI_INTENT_PLAN_TIER` 回退 `legacy`(保守)策略不一致 | `internal/intent/flags.go:47-64` | low |
| E-8 | `publisher_gate_test.go:16` 读 `FAV_PUBLISHER_ENABLE`(少 D),与正式变量名不符,该测试门永远走默认分支 | `internal/artifactvault/publisher_gate_test.go:16` | low |
| E-9 | main compose 的 system-db initdb 只挂 00001_baseline.sql,与 dev/test 不一致;新建卷时初始脚本漂移(依赖 events 启动迁移补齐) | `docker-compose.main.yml:23` | low |
---
## 三、已实现但未启用 / 未测试的功能
### 3.1 特性开关封存(实现完整,全环境 off)
| 功能 | 实现位置 | 状态与门禁 |
|------|----------|-----------|
| FAV 事件订阅者 | `internal/app/fav/subscriber.go` | 三重硬门禁:cmd/events 刻意不注册、registry fail-closed、SetMode 拒绝非 off;仅 ObserveShadow 可达 |
| FAV 发布器 | `internal/server/vault.go:18-67` | `FAV_PUBLISHER_ENABLED=false` 三环境显式;且 VAULT_* 三变量 compose 全未声明,容器内即使开 flag 也会静默 return(E-类:实际不可误开,属设计内封存) |
| FAV 降级读 | `internal/docquery/service.go:70` | `FAV_DEGRADED_READ=false` 红线保持 |
| 多意图 PlanTier shadow/auto_read/confirm | `internal/app/intentflow/turn.go` | 容器内锁死 legacy(见 E-3) |
| U9–U12 扩面 | `intentflow/expansion.go`、`mux.go` | 全 false;dev compose 已声明可调,test/main 未声明 |
| 意图 V2 shadow/decision | `internal/intent/shadow_v2.go`、`v2_decision.go` | 三环境显式 false |
| 语义摘要 shadow | `internal/ctxmgr/semantic_summary.go:216` | 默认 off,且仅 AGENT_BACKEND=pi-agent 时挂载 |
| PI change-report 叙事 | `internal/docrevision/narrative.go:68` | 默认 off,仅确定性 fallback(不得冒充完整 PI) |
| artifact-vault CLI | `cmd/artifact-vault/main.go` | 未部署 stub |
| eventmode cutover CLI | `cmd/eventmode/main.go` | 硬门禁仅 dev 可用(`internal/events/cutover.go:13`) |
### 3.2 死代码 / 机制先行无消费方
| # | 项 | 位置 |
|---|----|------|
| X-1 | `SEMANTIC_FALLBACK_ENABLED` 死 flag:无任何业务消费方,仅 sysadmin 展示;三环境 compose 都在设一个没用的变量 | `internal/intent/flags.go:43`、`internal/app/app.go:285` |
| X-2 | `SEMANTIC_SUMMARY_REPLACE` 读取后 `_=` 显式丢弃,刻意永久未接线 | `internal/ctxmgr/semantic_summary.go:257` |
| X-3 | goose 00048 三张新表 `project_source_bindings`/`repo_path_allowlist`/`project_type_workflows` 无代码消费方(swboot 目录硬编码内存版,RepoAllowlist 为 stub) | `internal/swboot/catalog.go:92,118`、`repo_allowlist.go` |
| X-4 | `system_settings` 白名单 6 键全部无业务消费方——可写不生效,纯机制先行 | `internal/sysadmin/settings.go:57-66` |
| X-5 | 前端死组件:`DocumentNotificationList.tsx`(含已读回写,功能完整无挂载点)、`WorkflowPrerequisiteBanner.tsx`、`user/SettingsModal.tsx`(已被 UserSettingsModal 取代);死 API:`api/projectWorkflow.ts:71 activateWorkflow`;`data/storage.ts:141 saveMessages` deprecated no-op | web/src 各文件 |
| X-6 | `useTaskRunStream` 伪 ref(同 B-7) | — |
### 3.3 测试盲区
| # | 盲区 | 说明 |
|---|------|------|
| S-1 | `TestReconcile_LegacyRepair_PG` 从未执行 | 要求隔离 PG 且硬拒绝 5433/5434/5435;canonical-hash 修复链路零自动化验证(gap-matrix 已记测试债) |
| S-2 | 两个「永久跳过」 | `taskstream_test.go:189`(功能已删,测试成死代码应删除);`plan_owner_test.go:125`(重定向跳过) |
| S-3 | 无测试的 cmd 入口 | `cmd/server`、`cmd/events`、`cmd/artifact-vault`、`cmd/dataset`、`cmd/eventmode`、`cmd/recategorize`、`cmd/document-revision-backfill`(仅 bizdev-cli、document-content-reconcile 有);`internal/observability`、`internal/workflow` 无测试文件 |
| S-4 | **E2E 默认全不跑**:web/e2e 9 个 spec 全部被环境门禁(`RUN_UI_ACCEPTANCE=1`/`DOCREV_E2E_BASE_URL`/`INTENT_DUAL_TAB=1`),默认 `playwright test` 实跑 0 用例;`test:ui-acceptance` script 只覆盖 1 个 spec,其余 8 个无 script 入口 | web/e2e/、web/package.json:11 |
| S-5 | 409 信封处理只覆盖部分消费方:projectMembers、freeformDoc、createTaskRun、chatSessions upsert 等 409 只能裸报错(与 FEATURE-MATRIX hardening backlog 一致) | `web/src/api/projectMembers.ts`、`freeformDoc.ts:177`、`taskRuns.ts`、`chatSessions.ts` |
| S-6 | 前端 bundle 大 chunk 未分割(mermaid/katex/xlsx/docx 各成 >500 kB chunk,已有 precompress 缓解) | vite build 警告 |
---
## 四、结论与优先级
**总体判断**:发布门禁与 FEATURE-MATRIX 的 `done/partial/deferred` 口径与代码实况基本一致,未发现「stub 冒充验收」类违规;质量门禁(vet/test/build)全绿。主要风险集中在三处:
1. **E-1(main ENV 不一致 → 双写/空转)是唯一 critical 级发现**,且只在 main 环境存在, dev/test 的「healthy」不能证明 main 事件链路正确。
2. **SSE 120s 断流(B-1/B-2)直接影响长任务可用性**,是用户可感知的现存 bug。
3. **封存面(FAV/多意图 tier/U9–U12/语义摘要/PI 叙事)实现完整但容器内不可调或硬门禁封存**,红线达标,但授权放量时会发现 compose 层缺失(E-3)与若干死接线(X-1/X-2)。
详细整改顺序见 [remediation 方案](../remediation/2026-09-17-system-health-remediation-plan.md)。
## 关联整改
- Remediation: [2026-09-17-system-health-remediation-plan.md](../remediation/2026-09-17-system-health-remediation-plan.md)
## 证据
- `go vet ./...` / `go build ./...` / `go test -short -count=1 ./...`(62 包 ok)/ `cd web && npm test && npm run build`:2026-09-17 全绿。
- 文中所有 `文件:行号` 引用均为 2026-09-17 dev 分支工作区实测。
## 开放问题
- E-1 的修复取向(app 改 `ENV=main` vs 事件信封/consumer mode 键改用部署名)需架构决策。
- D7 合规签字、`MULTI_INTENT_PLAN_TIER` 升 confirm、FAV live 放量均需用户显式授权,不在本整改自动范围内。
- configs/.env.dev/.env.test/.env.main 实际文件未读取(含密钥);若偏离 example 模板,E-3/E-4/E-6 结论需复核。
+130
View File
@@ -0,0 +1,130 @@
---
title: "系统深度体检审计(2026-09-19,dev@e8ed33b)"
status: done
created: 2026-09-19
updated: 2026-09-19
severity: high
---
# 系统深度体检审计(2026-09-19)
> 只读审计,未修改业务代码。分支 `docs/system-deep-audit-2026-09-19`,基点 dev@e8ed33b。
> 方法:go vet / go test -short 静态基线 + 五路并行深潜(后端 server/chat、docgov/events/工作流/迁移、前端 web、配置 flag/死代码、安全鉴权)。
## 一、总体结论
- **静态基线健康**:`go vet ./...` 零告警;`go test -short ./...` 55 包全 PASS;全仓 TODO/FIXME 仅 2 处非实质。
- **四条已声明红线全部核实一致**:`MULTI_INTENT_PLAN_TIER=legacy`、`SEMANTIC_SUMMARY_REPLACE` 未接线、`FAV_DEGRADED_READ=false`、SWBOOT-10 fail-closed stub——代码与三环境 compose 均对齐,无漂移。
- **IAM 主链路复核成立**:路由统一挂鉴权中间件、SQL 全参数化、token 哈希存储、错误出参有内部信息过滤。但存在 dev/test 兜底与端点级鉴权缺口(见 S1/S2)。
- **本次新发现**:2 项 critical(后端数据竞态 + docgov 吞错)、10 项 high、若干 medium/low。其中 3 项被两路独立审查交叉命中(见 ★ 标记),可信度最高。
- FEATURE-MATRIX 已声明的 partial/deferred(rdev、SWBOOT、FAV、D7、首载性能)不在本次重复申报范围;本次发现均为**新增**缺口。
## 二、Critical(发布前必须评估)
### C1 ★ docgov 持久化全链路 fire-and-forget 吞错;fencing token 未读回
`internal/docgov/lease.go:460-467, 485-490`;`internal/docgov/engine.go:318, 392, 405, 470, 477, 650, 743, 750, 1081-1134`
租约获取/续约/回收、正文哈希、认领状态、提案决定及**全部审计日志**均为 `_, _ = e.pool.Exec(...)` 静默吞错:
- 审计 INSERT 失败 → 合规事件永久丢失,无重试无告警;
- 租约 UPDATE 失败 → 内存与 DB 分叉,重启后可并行编辑同一文档;
- `lease.go:485` 用 `context.Background()` 脱离请求生命周期;
- `loadDocumentFromDBLocked` 的 SELECT 列表**不含 `lease_fencing_token` 列**(00034 迁移已建列)→ 进程重启后 fencing 语义完全失效(合法持锁者被误判 stale,或 stale 写者被放行——两个方向都有缺口)。
**建议**:持久化失败必须返回 error 或 slog.Error+指标;审计写入失败进重试队列;lease SELECT 补 fencing 列;persistLeaseLocked 失败回滚内存状态。
### C2 ★ Session 全字段数据竞态 + 跨项目污染
`internal/chat/session.go:275-277`;`internal/server/server.go:432-435`;`internal/server/handlers.go:196-198`
- `Messages`/`UserCtx`/`LastAccessedAt` 的读写锁粒度碎片化:SSE 路径持 `execMu`,而 `hydrateVisibleHistory`、`handleGetProject`、`cleanStaleSessionsLocked`、`server.go:435` 均不持锁。并发 SSE+REST 同会话时 `go test -race` 可复现 data race。
- `handleChat` 无锁写 `sess.ProjectID = req.ProjectID`,同一 sessionID 被不同项目请求交错时跨项目串扰。
**建议**:Session 加 `sync.RWMutex` 统一保护;ProjectID 改为请求级参数不写回共享 sess。
### C3 SSE WriteTimeout=120s 硬杀长任务 + 心跳 goroutine 生命周期不一致
`internal/server/server.go:352-355`;`internal/server/sse.go:252-271`
全局 `WriteTimeout: 120s`;SSE 靠 45s 续期+15s 心跳兜底,心跳被中间代理吞掉时长 LLM 回合(dialogueTimeout=3min)被强杀。非流式 `handleRunTask` 同步执行数十分钟任务,120s 必然截断响应(业务已执行、客户端收不到结果 → 幂等重试造成重复执行观感)。心跳 goroutine 模式与 `handleTaskRunEvents`(主循环 select,无此问题)不一致。
**建议**:长任务端点异步化(提交+轮询/SSE);心跳并入主 select 或 WaitGroup 收敛。
### C4 工作流计划保存跨语句竞态 + completed_by 错填
`internal/projectinstance/service.go:185-190`;`internal/projectinstance/stage_store.go:132-138`
- `SaveWorkflowPlan`:upsert 与 bump revision 两条独立事务,并发下同版本号先互相覆盖 plan 再一方 bump 失败 → **版本号与 plan 内容错位落库**。`Activate` 的 token 前置校验与激活事务间存在 TOCTOU。
- `completed_by = (SELECT activated_by ...)`:最终阶段完成的归属人被错填为激活人,审计归属错误。
**建议**:upsert+bump 同事务 + `FOR UPDATE` 锁 project 行;completed_by 显式传当前操作者。
## 三、High(建议进入 short-term 整改)
| # | 发现 | 位置 | 要点 |
|---|------|------|------|
| H1 ★ | dev/test 未认证静默兜底为 user id=1 | `internal/server/auth_middleware.go:48-51` | `Env=dev|test` + `AllowInMemory` + 无 ContextDB 时,无 token 请求静默识别为 id=1(管理员)。main 已被 `validateProductionSecrets` 兜住。建议:兜底路径加审计日志+启动告警;中期删除 legacy 兜底 |
| H2 ★ | docgov 批注/审计端点无资源级鉴权且信任请求体身份 | `internal/server/handlers.go:858-940, 534-552` | 任意登录用户读任意文档批注/审计;`AddComment` 直接用 `req.UserID/UserName/UserRole` 可伪造他人身份;`Claim` 角色由客户端自选。两路审查交叉命中。建议:actor 一律取 principal;读类端点加项目成员校验 |
| H3 ★ | 会话查询类端点水平越权 | `chat_turn_api.go:12-45`;`handlers.go:947-981, 429-451` | `handleGetChatTurn`/`handleListChatSessions`/`handleGetUserContext` 的 session_id/user_id 来自 query 不校验归属;userID<=0 时默认 1(种子 admin)。建议:改用 principal 或比对不一致 403 |
| H4 | 登录/注册无速率限制 | `server.go:295-296` | 全仓无限流;bcrypt 高成本反而便于 CPU 耗尽 DoS。建议:IP+用户名滑动窗口限流 |
| H5 | SSE 任务流缺幂等前置检查 | `internal/server/sse.go:398-424` | REST 路径有 `FindByIdempotencyKey`,SSE 路径没有;EventSource 断线重连产生重复任务执行 |
| H6 | 事件 dispatcher stale-fencing 无限重放 | `internal/events/worker.go:206-275` | ErrStaleFencing 直接 cancel+return 不计 Failed;handler 半成功被回滚后事件无限重放,永不可达 dead,无告警 |
| H7 | 迁移 00001–00009 缺 down;00012 seed 迁移破坏性 DELETE | `deploy/postgres/goose/` | 前 9 个迁移无 down;00012 无条件 DELETE 30 个 session 的真实消息再插种子;多个迁移事务内 CREATE INDEX(非 CONCURRENTLY)大表会锁表 |
| H8 | compose 弱口令兜底 + main 注册默认开放 | `docker-compose.{dev,test}.yml:17,86,101`;`main.yml:101` | dev/test 的 DB/ADMIN 口令有弱默认值;main 已用 `:?required` 强制但 `AUTH_REGISTRATION_ENABLED` 默认 true。建议 test 对齐 main 必填,main 注册默认 false |
| H9 | 前端 KaTeX 占位符 XSS | `web/src/engine/renderMarkdown.ts:44-64, 106-108` | 数学公式 catch 分支把未转义原文放入占位符数组,还原发生在 escapeHtml 之后 → XSS。建议:catch 分支 escapeHtml(math) + 占位符随机化 |
| H10 | `context.Background()` 脱离请求生命周期 | `internal/chat/session.go:131-134`;`server.go:423,458,566` | LLM 摘要/DB 调用用 Background,客户端断开无法取消,慢库时 handler 挂死。建议:透传请求 ctx + WithTimeout |
## 四、Medium(选录,详见各专项)
| # | 发现 | 位置 |
|---|------|------|
| M1 | 全局缺安全响应头(CSP/nosniff/X-Frame-Options/Referrer-Policy) | `internal/server/server.go:624-636` |
| M2 | 租约 TTL 无上限(可锁文档 1000 天)+ AcquireLease 无编辑权校验 | `handlers.go:1196-1203`;`docgov/lease.go:62-70` |
| M3 | coordinator 关键词命中强制改写意图 + 模板硬编码"张工您好" | `internal/coordinator/engine.go:409-416, 485` |
| M4 | `fmt.Sscanf` 解析 `u_sess_xxx` 必然失败 → UserID=0 审计落空 | `coordinator/engine.go:930-934, 1067-1071` |
| M5 | `Runtime.Start` 被 main 与 Server.Start 双重调用且错误被吞 | `server.go:343-345`;`cmd/server/main.go:47` |
| M6 | sessions map 无硬上限,惰性清理可被随机 session_id 放大 | `server.go:451-453` |
| M7 | 修订三阶段写(账本→DocGov→freeform)无事务,靠客户端重试补偿 | `document_revision_handlers.go:274-318` |
| M8 | 测试 flag 名笔误 `FAV_PUBLISHER_ENABLE`(少 D)门闩失效 | `internal/artifactvault/publisher_gate_test.go:16` |
| M9 | dev compose 声明永不消费的 `SEMANTIC_SUMMARY_REPLACE`(诱导性配置);dev 与 test/main 默认模型不一致(M2.7-highspeed vs M3) | `docker-compose.dev.yml:119,44` |
| M10 | OpsCutover 硬编码 `"dev"`,test/main 无合规 cutover 路径 | `internal/events/cutover.go:12-19` |
| M11 | 前端乐观已读无失败回滚;MessageStream prevMsgCount 跨会话不重置;SSE 无 online 感知重连 | `web/src/hooks/useUnreadMarks.ts:176-233`;`MessageStream.tsx:148-154` |
| M12 | ExcelViewer 无行数上限内存爆炸;React 19 下 30+ 处裸 setTimeout 无清理 | `ExcelViewer.tsx:42-55` |
| M13 | `deploy/postgres/migrations/` 疑似死目录(14 个旧 SQL 无引用,与 goose 重复) | `deploy/postgres/migrations/` |
| M14 | `Orchestrator.ResolveDocTask` 静默返回 0 值三权掩盖数据不一致 | `internal/workflow/runtime/orchestrator.go:69-83` |
| M15 | PG 事件投递允许乱序而 MemoryBus 有 gap 语义——测试替身与生产行为分叉 | `internal/events/dispatcher.go:56-63` vs `bus.go:99-103` |
## 五、Low(选录)
- `handleHealth` 每请求同步两次 DB 往返无缓存无超时(`handlers.go:97-110`)
- `writeStoredEvents` json.Marshal 错误被吞(`task_run_handlers.go:437`)
- `ReplayPlan.Digest()` 不含 DryRun 字段(纵深防御,`internal/events/replay.go:24-38`)
- 前端 localStorage 缓存无版本字段;`lucide-react@^1.16.0` 版本异常需确认来源;App.tsx 4600 行/30 个 useEffect 巨石组件
- `handleRunTaskStream` 死参数 `includeDetails/requestID`(`sse.go:417-418`)
## 六、复核确认无问题的面(证据性记录)
- SQL 注入:全部 pgx 参数化;仅 4 处 fmt.Sprintf 涉 SQL 均为常量
- CORS:白名单制、无 `*`+凭证;SSE 鉴权失败返回 JSON 而非污染流
- 日志:密码 bcrypt、token SHA-256 摘要存储;`httpx.LooksInternal` 过滤内部错误串
- os/exec:bridge 路径来自服务端配置,用户输入只进 stdin payload;无 text/template 引用
- 事件系统:claim 幂等(SKIP LOCKED + fencing 复合判断)、ack+inbox+checkpoint 单事务、envelope 完整性校验、replay 审批人≠操作人——设计正确
- 前端:Mermaid strict 模式、链接 noopener、ErrorBoundary 覆盖根组件、EventSource 卸载清理正确
## 七、优先级建议
1. **进 main 前必须处理**:C1–C4、H1–H5、H8、H9(H8 的 main 注册默认开放一项)
2. **short-term 整改批**:H6、H7、H10、M1、M2、M8(一行修复恢复门闩)
3. **backlog**:其余 medium/low
## 关联整改
- Remediation: 待立项(建议按第七节优先级拆 short-term 任务)
## 证据
- `go vet ./...` 零输出;`go test -short ./...` 55 包 ok(2026-09-19,dev@e8ed33b)
- 五路只读深潜:后端 server/chat、docgov/events/工作流/迁移、前端 web、配置/flag/死代码、安全鉴权
- 任务条目:[ops/short-term/2026-09-19-system-deep-audit.md](../ops/short-term/2026-09-19-system-deep-audit.md)
## 开放问题
- dev 与 test/main 默认模型不一致(M2.7-highspeed vs M3)是否刻意?未见 `.doc/ops` 对齐记录
- `deploy/postgres/migrations/` 是否还有外部工具依赖?无则建议归档
- H1 legacy 兜底是否有仍在使用的内部工具依赖?删除前需盘点
@@ -0,0 +1,48 @@
---
title: "系统权限设置与项目协作多项缺陷排查"
status: done
created: 2026-09-20
updated: 2026-09-20
severity: high
---
# 系统权限设置与项目协作多项缺陷排查
## 现象
用户报告:成员管理勾选无效、系统设置「允许编制人兼任审核批准」400、PDF 预览被拦截、任务 runs 403 刷屏、发起编制被标 NETWORK_ERROR、注册/建号 rollback、改密后刷新再强制改密、退出重登出现同名重复项目、无项目仍可对话、右侧工具栏默认展开且不记忆。
## 根因分析
| # | 根因 | 关键路径 |
|---|------|----------|
| 1 | CSP 缺 `frame-src`,blob iframe fallback 到 `default-src 'self'` | `internal/server/cors.go` |
| 2 | PdfViewer 同源 iframe 直连,触发 `X-Frame-Options: DENY` 原生拦截页 | `web/src/components/doc/preview/renderers/PdfViewer.tsx` |
| 3 | 前端未传 `expected_revision`(该 key 后端强制 CAS) | `web/src/api/systemAdmin.ts` / SettingsSection |
| 4 | `ProjectSettingsApiError` 字段名与消费方 `httpStatus`/`errorCode` 不一致 | `web/src/api/projectSettingsError.ts` |
| 5 | task-run view 仅放行创建者/owner;前端 403 无停止轮询 | `task_run_auth.go` / `App.tsx` |
| 6 | `CanManageProjectMembers` 未读细粒度权限位 | `internal/authz/service.go` |
| 7 | memStore `ListProjectsForUser` 忽略成员表 | `internal/projectworkflow/store.go` |
| 8 | `user_role_bindings` 插入吞错 → commit rollback;handler 一律 400 | `internal/auth/pg_store.go` |
| 9 | 嵌套 `user.mustChangePassword` OR 合并复活 + fetchMe 未回写 session | `authUserMap.ts` / WorkbenchView / useAuthenticatedWorkspaceSync |
| 10 | `projects.name` 无唯一约束 + Create 无幂等键;logout 不清 projects 缓存 | `service.go` / migration 00056 / App logout |
| 11 | `Project()<=0` 时跳过项目访问校验 | `handlers.go` / `sse.go` / `stage_access_helpers.go` |
| 12 | `rightCollapsed` 默认 false 且无持久化 | `AppShell.tsx` / `storage.ts` |
## 严重度
`high`
## 关联整改
- Short-term: `.doc/ops/short-term/2026-09-20-bug-hunt-permissions-uploads.md`
- 分支: `fix/bug-hunt-2026-09-20-permissions-and-uploads`
## 证据
- 产品决策:新增 `project:manage_members`;无项目禁止对话并置灰发送按钮;同创建人内项目名唯一 + `client_key` 幂等。
- 迁移:`00055_...project-manage-members-permission.sql`、`00056_...project-create-idempotency.sql`
## 开放问题
- 无(本批范围内)
@@ -0,0 +1,142 @@
---
title: "模块耦合现状审计(规范与分批整改基线)"
status: done
created: 2026-09-20
updated: 2026-09-20
severity: high
---
# 模块耦合现状审计(规范与分批整改基线)
## 现象
系统已经是模块化单体,不是未治理的大泥球:`module-boundaries.yaml` + `internal/archtest` 已把 import 与事件登记清到零违规(`baseline_counts.import=0`、`event=0`,二者在 `block_kinds`),可靠事件由独立 `cmd/events` worker 经 PostgreSQL lease 消费。
故障仍会跨模块扩散的原因不在“缺总线”,而在四类残留:
1. HTTP 适配层直接持有领域具体类型,而不是只调用用例端口。
2. `chat`、`app` 子包与 `coordinator` 用子包拆分避开了 Go 编译环,逻辑上仍互相依赖。
3. `docgov` 的状态、角色和错误被多个模块当成本模块词汇使用。
4. 带到期日的 SQL/路径例外仍允许非属主写入或拼接工作区路径。
本审计只记录证据与分级,不改代码。整改批次见 [分批计划](../remediation/2026-09-20-module-decoupling-batch-plan.md)。
## 根因分析
### 已有隔离基线(不要推倒)
| 机制 | 位置 | 现状 |
|------|------|------|
| 模块化单体 ADR | [2026-09-14-modular-monolith-decoupling](../adr/2026-09-14-modular-monolith-decoupling.md) | 不拆微服务;窄端口 + 组合根 + 领域事件 |
| 静态边界 | [module-boundaries.yaml](../system-design/module-boundaries.yaml) | import allowlist、表唯一写者、路径属主、事件生产者/消费者 |
| 架构门禁 | `internal/archtest`、`scripts/arch-check.sh --mode block` | import/event 零容忍 |
| 进程内端口 | `internal/app/*flow`(例:`internal/app/chatflow/ports.go`) | 消费者拥有窄接口;组合根注入实现 |
| 跨进程事件 | `internal/events` + `cmd/events` | PG outbox/inbox;dev `:8088` / test `:8089` / main `:8090` |
| 事件契约 | `internal/events/registry.go` `StaticContracts()` | 11 个事件名、schema version、payload 字段 allowlist;与 YAML parity |
`StaticContracts` 现有事件:`document.agent_candidate_ready`、`document.agent_version_committed`、`document.downstream_impact_detected`、`document.change_report_degraded`、`document.approved`、`taskrun.completed`、`taskrun.cancelled`、`fav.artifact_staged`(`Enabled: false`)、`intent.plan.awaiting_input`、`intent.plan.step_changed`、`intent.plan.completed`。
### 热点 1(P1):`server` 上帝适配层
`internal/server/server.go` 的 `Server`(约 40–80 行)同时持有 `*bizdev.Service`、`*coordinator.CoordinatorEngine`、`*docgov.GovernanceEngine`、`*docrevision.Service`、`*taskrun.Manager`、`*projectinstance.Service`、`*pgxpool.Pool` 等具体类型。同结构体里只有少数字段是端口(`chatflow.ChatLog`、`chatflow.ContextAssembler`、`intentflow.Service`、`intent.Recognizer`)。
生产 import 覆盖约 30 个内部包(`server.go` 11–34 行)。handler 直接解释领域错误,例如 `internal/server/handlers.go` 对 `docgov.ErrDocumentBusy` 的分支(426、449 行)以及 `docgov.RoleAuthor`(702、1291 行)。
后果:领域包改一个错误或角色常量,HTTP 层必须跟着改;`pool` 还让适配层有机会绕过表属主写 SQL。
### 热点 2(P2):`chat` ↔ `app` ↔ `coordinator` 逻辑环
编译环被子包拆开了,依赖方向没有:
- `internal/chat/session.go` 11–13 行 import `app/chatflow`、`app/intentflow`、`coordinator`。
- `internal/chat/action_executor.go` 10–14 行 import `app/intentflow`、`app/stageflow`、`coordinator`、`docgov`、`taskrun`,并持有具体引擎指针。
- `internal/app/chatflow/ports.go` 又 import `coordinator`、`ctxmgr`、`projectinstance`(`AssembleRequest` 直接嵌 `coordinator.UserInfo`)。
`chat` 既是领域会话,又反向依赖用例包。用例一变,会话执行器就会编译失败,问题不会停在单一模块。
### 热点 3(P3):`docgov` 词汇泄漏
生产代码(不含本包测试)直接使用 `docgov` 状态/角色/错误的位置包括:
- `internal/coordinator/engine.go`:`ErrDocumentBusy`(955)、`StateDrafting`(1596、1598)。
- `internal/bizdev/service.go`:`ErrDocumentLocked` / `ErrDocumentBusy`(718)。
- `internal/server/handlers.go`、`document_revision_handlers.go`、`auth_helpers.go`:`RoleAuthor`、`ErrDocumentBusy`。
- `internal/chat/action_executor.go`:动作名字符串 `"docgov.review_approve"`(58、150 行),以及 `docgov.StateDrafting`(90)。
这些不是稳定共享词汇(`internal/contracts/vocabulary` 尚未承接它们),而是领域实现类型被当公共 API。
### 热点 4(P3):工作流定义与实例网
- `internal/workflowdef/catalog.go` import `projectworkflow`。
- `internal/workflowdef/validator_v2.go` import `workflow`。
- `internal/projectinstance` 生产文件(`store.go`、`service.go`、`gate.go`、`types.go` 等)import `workflowdef`。
- `internal/workflow/runtime/orchestrator.go` import `projectinstance`。
定义、目录、实例和运行时互相看得见对方的包。改一份工作流校验会同时碰到定义包和实例包。
### 热点 5(P4):巨型文件
非测试生产文件行数(2026-09-20 `wc -l` 口径,探索盘点):
| 行数 | 文件 |
|------|------|
| 1844 | `internal/coordinator/engine.go` |
| 1590 | `internal/bizdev/service.go` |
| 1395 | `internal/server/handlers.go` |
| 1291 | `internal/projectinstance/store.go` |
| 1245 | `internal/intent/recognizer.go` |
| 1235 | `internal/projectworkflow/store.go` |
| 1207 | `internal/docgov/engine.go` |
| 1172 | `internal/docrevision/service.go` |
| 1151 | `internal/squad/workspace.go` |
| 1028 | `internal/freedoc/service.go` |
单文件过大本身不是耦合,但它把多个用例绑在同一变更面上,评审和回滚半径变大。拆分应跟在解环之后,避免边搬边改依赖。
### 热点 6(P4):前端 API 层无统一客户端
`web/src/api/` 约 37 个文件按域各写 `fetch()`,`API_BASE` 与鉴权头分散。错误信封、重试和 401 处理无法在一处收口,后端错误契约一变就会在多个 api 文件重复漏改。这是适配层问题,不是把前端改成 RPC。
### 热点 7(P2,有到期日):边界例外未清零
[module-boundaries.yaml](../system-design/module-boundaries.yaml) `exceptions` 共 21 条,`baseline_counts` 为 sql_write 5、path 16。
| 种类 | 条数 | 里程碑 | 到期 | 风险 |
|------|------|--------|------|------|
| `sql_write` | 4 | U3 | 2026-09-28 | **8 天后到期**。`docduty`、`docrevision` 仍写 `document_records` / `freeform_documents` |
| `sql_write` | 1 | U8 | 2026-10-26 | `projectinstance` 终止流程直接取消 `task_runs` |
| `path` | 2 | U4 | 2026-09-28 | **同样 8 天后到期**。`server` 与 `docrevision` 仍点名 `output.md` |
| `path` | 14 | U5 | 2026-10-12 | `agent`、`bizdev`、`coordinator`、`docgov`、`storage` 仍拼接工作区路径或把 `data/dev` 写进提示 |
到期后若门禁把这些 kind 升为 block 而代码未迁走,构建会失败;若继续延期而不迁,非属主写入会继续让文档/任务故障跨包扩散。本轮不改 YAML,清零归整改批次 G。
## 严重度
整体 `high`:不会单独打穿已签发布门禁(`production_ready` 不因本审计回退),但 P1/P2 使“问题停在单一模块”尚未成立。
| 级别 | 热点 | 扩散方式 |
|------|------|----------|
| P1 | server 具体类型装配 | 领域改动直接编译失败到 HTTP |
| P2 | chat/app/coordinator 逻辑环 | 会话、意图用例、协调引擎必须同改 |
| P2 | 2026-09-28 到期的 sql_write/path 例外 | 非属主写表或读工作区文件 |
| P3 | docgov 词汇泄漏 | 状态机常量变成跨包协议 |
| P3 | workflow 定义/实例网 | 校验与运行时同改 |
| P4 | 巨型文件、前端 fetch 分散 | 变更面大,不立刻产生跨表写入 |
## 关联整改
- Remediation: [2026-09-20-module-decoupling-batch-plan.md](../remediation/2026-09-20-module-decoupling-batch-plan.md)
- 开发规范: [2026-09-20-module-development-standards.md](../system-design/2026-09-20-module-development-standards.md)
- 上位约束(不重复制定): [架构](../system-design/2026-09-14-module-decoupling-architecture.md)、[Phase 2](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)、[影响面守则 §2](../remediation/2026-09-16-partial-deferred-completion-plan.md)
## 证据
- 结构体与 import:`internal/server/server.go`、`internal/chat/session.go`、`internal/chat/action_executor.go`、`internal/app/chatflow/ports.go`。
- 事件契约:`internal/events/registry.go` `StaticContracts`。
- 例外账本:`module-boundaries.yaml` `exceptions` 与 `baseline_counts`(import 0 / sql_write 5 / path 16 / event 0)。
- 盘点方式:2026-09-20 只读检索生产 import 与 `docgov` 符号引用;行数来自当时文件长度,后续拆分后以 `wc -l` 重测为准。
## 开放问题
- U3/U4 例外在 2026-09-28 到期后,是先延长豁免并写原因,还是立刻占用 `docgov` mutex 做批次 G 的第一刀。本审计不代决,批次 G 开工前必须二选一,禁止静默改到期日。
- `internal/contracts/vocabulary` 在架构文档中已定义,代码侧尚未作为 docgov 状态/角色的唯一出口。批次 C 再决定是新建该包还是把稳定枚举留在消费者端口。
@@ -0,0 +1,68 @@
---
title: "2026-09-20 系统全量体检审计"
status: done
created: 2026-09-20
updated: 2026-09-20
severity: high
---
# 2026-09-20 系统全量体检审计
## 现象
在 `production_ready=yes`、dev/test/main 健康、近期 triage 已合入的前提下,对全系统做只读深度体检,发现若干**未写入 gap-matrix 的 critical/high**,以及一批 medium/low 加固项。
方法:四路并行深潜(后端 Go、安全鉴权、前端 web、基础设施)+ 本机实证(goose 版本表、容器 health、口令登录、代码交叉复核)。
## 根因分析(P0 / critical,均已实证)
| ID | 发现 | 位置 | 证据 |
|----|------|------|------|
| P0-MIG | 迁移序号空洞 00054;`chat_summaries` 建表与 summarizer 写失败修复滞留未合入分支 | `feature/capability-enablement-impact-plan@848a0457`;dev 代码仍读写不存在表 | `goose_db_version` 53→55→57 跳号;`to_regclass('chat_summaries')` 空;`summarizer.go:119` `_ = err` |
| P0-IDOR-PREF | 偏好写入信任请求体 `user_id`,无归属校验 | `internal/server/handlers.go:508-537` | 无 `requireAuthenticatedUser` 比对 |
| P0-IDOR-SESS | `handleGetProject` 以 `callerUserID=0` 调会话,归属校验被跳过 | `server.go:458-463`;`handlers.go` / `project_handlers.go` | `if callerUserID > 0` 守卫 |
| P0-IDOR-RECAT | 重分类无会话归属;空 `session_id` 触及全库消息 | `chat_recategorize_api.go`;`ctxmgr/recategorize.go` | `WHERE ($1 = '' OR session_id = $1)` |
| P0-PANIC | taskrun 订阅发送在锁外,Unsubscribe `close` 后向 closed channel 发送 panic | `taskrun/manager.go:481-497` vs `:590` | select default 不挡 closed;全仓非测试 `recover()`=0 |
| P0-RACE | 同步 `POST /chat` 不取 `execMu`,与 SSE 并发 data race | `handlers.go:240` vs `sse.go:341` | 09-19 C2 残留半修 |
| P0-CRED-BACKUP | 三环境 DB 口令硬编码进仓库;生产口令与脚本一致可登录 | `scripts/backup-system-db.sh:43-56` | 实测 `prod_highly_secure_db_pass` 可连 main |
| P0-CRED-PUSH | push 脚本把 token 拼进 URL,`ps` 可见 | `scripts/git-push-dev.sh:23` | `https://oauth2:${TOKEN}@...` |
| P0-XSS | 块编辑器 math 错误分支未转义 | `BlockEditorModal.tsx:206`;`MathBlockView.tsx:20` | catch 裸拼 + `dangerouslySetInnerHTML` |
### 环境与分支脱节(本轮不做晋升,记 backlog)
| ID | 发现 | 证据 |
|----|------|------|
| ENV-MAIN-DRIFT | main 分支 goose 最高 00025,main 库 schema 52;灾备从分支重建不可复现 | `git ls-tree main`;`goose_db_version` MAX=52 |
| ENV-TEST-DRIFT | test 分支最高 00056,test 库已 57 | 实测 |
| DOC-SCHEMA | CURRENT 写 dev schema 56,实测 57 | health JSON |
| GOOSE-DUP56 | dev 库 version_id=56 记账两行(id 57/58,间隔 2ms) | SQL 取证 |
## 严重度
- **critical / P0**:上表 P0-*(本轮整改)
- **high / medium / low**:见下方「非 P0 清单」与 [long-term](../ops/long-term/2026-09-19-audit-remainder.md) 2026-09-20 增补区
## 关联整改
- Remediation: [../remediation/2026-09-20-p0-remediation-plan.md](../remediation/2026-09-20-p0-remediation-plan.md)
- Short-term: [../ops/short-term/2026-09-20-p0-hotfixes.md](../ops/short-term/2026-09-20-p0-hotfixes.md)
## 证据
- `go vet ./...` 零告警(2026-09-20)
- `go test -short ./...`:仅 `TestPiAgentDockerBuildContext_RunnerModulesPresent` 因外网镜像源 EOF 失败,属测试卫生
- 三环境 health:dev/test schema **57**,main **52**;events `:8088`/`:8089`/`:8090` ok
- 四路深潜交叉:IDOR×3、XSS、凭证、迁移空洞均被 ≥2 条路径或本机取证命中
## 非 P0 清单(摘要,详 long-term)
**后端**:XFF 限流可绕过;events `cancelFns` 只增不减;docrevision/docgov 全局锁内 DB I/O;Shutdown 5s vs 长任务;`idemLocks` 无界;SSE query 传消息;C1 缓存不失效;chat 落库非原子等。
**前端**:`useChatWindow` 切会话竞态;PLAN_CONFIRM 无 try/catch;turn Map 只增不减;重置密码死功能;ErrorBoundary 仅顶层;SSE `\r\n`;token localStorage + 无全局 401 登出等。
**基础设施**:容器 root、无资源限制;健康检查路径不一致;main events 挂 shared-net;init 三套;Dockerfile Go 1.23 基镜像;backup 无定时;main 分支对齐晋升专项。
## 开放问题
- capability 分支合入后 00054 重编号为 00058 是否与其他未合并旁支再撞号?(当前仅该分支占用 54)
- main 分支对齐晋升时 00057 会对存量项目做不可逆改名——晋升前需预演清单
+19
View File
@@ -13,6 +13,22 @@
## 核心文档(按阅读顺序推荐)
### 模块耦合现状(2026-09-20)
**文件**: [2026-09-20-module-coupling-audit.md](./2026-09-20-module-coupling-audit.md)
**结论**: 模块化单体与事件总线已在;残留扩散点是 server 具体类型装配、chat/app/coordinator 逻辑环、docgov 词汇泄漏,以及 2026-09-28 到期的 sql_write/path 例外。不改 `production_ready`。
**整改**: [分批计划](../remediation/2026-09-20-module-decoupling-batch-plan.md) · [开发规范](../system-design/2026-09-20-module-development-standards.md)
### 系统全量体检(2026-09-20)
**文件**: [2026-09-20-system-triage-audit.md](./2026-09-20-system-triage-audit.md)
**结论**: 迁移 00054 断链 + 三项 IDOR + taskrun channel panic + 凭证硬编码/暴露为 P0;main 分支与生产 schema 脱节记 backlog。
**整改**: [P0 热修方案](../remediation/2026-09-20-p0-remediation-plan.md) · [short-term](../ops/short-term/2026-09-20-p0-hotfixes.md)
### 可选职责空审核人 CreateOrGetDocument FK(2026-09-17)
**文件**: [2026-09-17-docgov-optional-duty-null-fk.md](./2026-09-17-docgov-optional-duty-null-fk.md)
@@ -472,3 +488,6 @@ Day 4-5: Phase C 完善与发布准备(20h)
---
*本索引最后更新于 2026-09-12 15:05 UTC*
- 2026-09-17:[系统全面体检](2026-09-17-system-health-check.md)(任务收口 / 缺陷 / 未启用功能;配套 [整改方案](../remediation/2026-09-17-system-health-remediation-plan.md) Wave0–7)。
- 2026-09-17:[首次加载性能诊断与改进](2026-09-17-initial-load-performance-audit.md)(三入口重启首访;U2 已验收,主 JS ~624 KB;U1/U3–U7 待实施)。
+7 -7
View File
@@ -43,7 +43,7 @@ AuthN column is **heuristic**; negative-test pointers filled where known.
| POST | `/api/v1/auth/register` | `s.handleAuthRegister` | `server.go` | handler | see suite |
| GET | `/api/v1/auth/sessions` | `s.handleAuthSessions` | `server.go` | handler | see suite |
| DELETE | `/api/v1/auth/sessions/{id}` | `s.handleAuthSessionByID` | `server.go` | handler | see suite |
| POST | `/api/v1/chat` | `s.handleChat` | `server.go` | session+project | see suite |
| POST | `/api/v1/chat` | `s.handleChat` | `server.go` | session+project (ERR_NO_PROJECT if unbound + zero memberships) | see suite |
| GET | `/api/v1/chat/categories` | `s.handleListChatCategories` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/dates` | `s.handleListChatDates` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/digests` | `s.handleListDailyDigests` | `server.go` | session+project | see suite |
@@ -60,8 +60,8 @@ AuthN column is **heuristic**; negative-test pointers filled where known.
| GET | `/api/v1/chat/search` | `s.handleChatSearch` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/sessions` | `s.handleListChatSessions` | `server.go` | session+project | see suite |
| POST | `/api/v1/chat/sessions` | `s.handleUpsertChatSession` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/stream` | `s.handleChatStream` | `server.go` | session+project | see suite |
| POST | `/api/v1/chat/stream` | `s.handleChatStream` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/stream` | `s.handleChatStream` | `server.go` | session+project (ERR_NO_PROJECT if unbound + zero memberships) | see suite |
| POST | `/api/v1/chat/stream` | `s.handleChatStream` | `server.go` | session+project (ERR_NO_PROJECT if unbound + zero memberships) | see suite |
| GET | `/api/v1/chat/turns/{client_turn_id}` | `s.handleGetChatTurn` | `server.go` | session+project | see suite |
| GET | `/api/v1/chat/unread` | `s.handleChatUnread` | `server.go` | session+project | see suite |
| GET | `/api/v1/context/cases/recommend` | `s.handleRecommendCases` | `server.go` | handler | see suite |
@@ -131,10 +131,10 @@ AuthN column is **heuristic**; negative-test pointers filled where known.
| GET | `/api/v1/tasks/run/stream` | `s.handleRunTaskStream` | `server.go` | session+project | see suite |
| POST | `/api/v1/tasks/run/stream` | `s.handleRunTaskStream` | `server.go` | session+project | see suite |
| POST | `/api/v1/tasks/runs` | `s.handleCreateTaskRun` | `server.go` | session+project | see suite |
| GET | `/api/v1/tasks/runs/{run_id}` | `s.handleGetTaskRun` | `server.go` | session+project | see suite |
| POST | `/api/v1/tasks/runs/{run_id}/cancel` | `s.handleCancelTaskRun` | `server.go` | session+project | see suite |
| GET | `/api/v1/tasks/runs/{run_id}/events` | `s.handleTaskRunEvents` | `server.go` | session+project | see suite |
| POST | `/api/v1/tasks/runs/{run_id}/resume` | `s.handleResumeTaskRun` | `server.go` | session+project | see suite |
| GET | `/api/v1/tasks/runs/{run_id}` | `s.handleGetTaskRun` | `server.go` | session+project member (view) | see suite |
| POST | `/api/v1/tasks/runs/{run_id}/cancel` | `s.handleCancelTaskRun` | `server.go` | session+run owner or project owner | see suite |
| GET | `/api/v1/tasks/runs/{run_id}/events` | `s.handleTaskRunEvents` | `server.go` | session+project member (view) | see suite |
| POST | `/api/v1/tasks/runs/{run_id}/resume` | `s.handleResumeTaskRun` | `server.go` | session+run owner or project owner | see suite |
| GET | `/api/v1/workflow-instances/{id}` | `s.handleGetWorkflowInstance` | `server.go` | session+project | see suite |
| POST | `/api/v1/workflow-instances/{id}/stages/{stage}/advance` | `s.handleAdvanceStage` | `server.go` | session+project | see suite |
| GET | `/api/v1/workflow-instances/{id}/stages/{stage}/readiness` | `s.handleGetStageReadiness` | `server.go` | session+project | see suite |
@@ -0,0 +1,75 @@
# rdev 研发工作流二期增强 Backlog
> 来源:[07-研发工作流rdev接入-设计与实施计划](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md) §8 决策 3——首期 N/A 采用「激活规划期关闭」,以下增强项不阻塞首期交付,**用户要求记录以便随时续推进**。
> 创建:2026-09-17。每项建议独立 short-term 任务认领。
## 优先级排序(建议)
### R1 N/A 不适用页生成模式(对齐参考项目行为)
- 现状:skippable 任务在激活规划期由创建者关闭 = 不适用;
- 目标:保留任务但可生成「不适用说明页」(完整论述理由而非一句话),仍走审核/批准,再进入下一阶段(参考项目 rdev_software overlay 语义);
- 涉及:manifest 不适用模式标记、bizdev 执行 N/A 生成路径、squad N/A 编排、前端规划 UI「保留但声明不适用」选项;
- 验收:软件类任务声明不适用 → 生成完整不适用页 → 审批通过 → 阶段可推进。
### R2 UR/RS 结构化质量门禁(复用 PM requirements.json 模式)
- **状态**:✅ **done**(2026-09-19)— `rd_user_needs` / `rd_system_reqs` 在 `QualityGate.Validate` 中检查连续编号、禁止随机抽取、验证准则与正文/JSON 一致。`pm` 的 `system_reqs` 仍走原有检查。
- 范围:`rd_user_needs`、`rd_system_reqs`(及 `pm_system_reqs`)输出结构化需求集合;确定性门禁:ID 唯一连续、不随机抽取、缺验证准则拒绝、正文/JSON 不一致拒绝;
- 参考先例:`quality.system_reqs.v2`。
### R3 review_minutes / upload_index 专用确定性门禁
- **状态**:✅ **done**(2026-09-19)— 评审记录拒绝空洞「同意通过」;附件清单要求索引表与影响分析。`TestRDevQualityGates`。
- review_minutes(6 个评审记录):问题-决议-行动项闭环检查(拒绝空洞「同意通过」、行动项无责任人/期限);
- upload_index(7 个附件清单):附件索引表存在性、缺失影响分析存在性检查;禁止伪造附件内容靠 Accept 纪律 + 门禁抽查「待上传后更新」结论。
### R4 depends_on 精确血缘与 stale 传播
- 现状:rd 任务 prior docs 全量注入 + 摘要级血缘;
- 目标:per-task upstream 声明表(对齐参考项目 rdev.yaml depends_on:rd_planning_review ← rd_proposal+rd_design_plan、rd_verification_review ← rd_design_vv+rd_risk_report_v 等),上游新版本批准 → 下游 stale 且不能完成;
- 参考先例:test_manager 对 approved SR 的 stale 传播(projectworkflow/service.go)。
### R5 DMR 双记录归档
- 参考项目 `records: [dhf, dmr]` 的设计输出/转换文档在本仓库无对应物;需评估文档「记录归属」字段扩展 + 归档/导出按 DHF/DMR 分类(本仓库无云盘,先落 docgov 元数据与导出分类)。
### R6 软件工作流任务键 `sw_` 前缀盘点(并入 P4 或其后)
- `software_bootstrap`/`software_delivery`(executor `software.doc.v1`)任务键盘点并纳入统一命名空间规约(D12 的遗留尾巴)。
### R7 高复杂度 regulatory 步注入策略
- 现状:D7 中 regulatory 按任务清单静态注入;目标:接 `complexity_tier`(complexity_high/medium 分层)动态注入,对齐参考项目 `when: complexity_tier=high`。
## 依赖关系
- R2/R3 可并行;R4 依赖 manifest 落地后的 upstream 声明表;R1 独立;R5/R6/R7 低优先级。
---
## 模板深度与运行时续批(S1 续批 / S2 / S3)
> 来源:Kimi 分析方案 + [2026-09-17-rdev-template-depth](../archive/ops/2026-09-17-rdev-template-depth.md) 收口。S0 + S1 首批(14 份)已交付;以下不阻塞本轮合并候选。
### S1 续批 — 剩余模板专业章节
- **状态**:✅ **done**(2026-09-17)— 46 份全部同等深度补强;allowlist 60/60;真 PI `rd_planning_review` + `rd_design_vv` PASS
- **证据**:[测试报告](../test-reports/2026-09-17-rdev-template-depth-s1-continued-test-report.md);[short-term](../ops/short-term/2026-09-17-rdev-template-depth-s1-continued.md)
### S2 — 运行时编排与配置化
- **状态**:✅ **done**(2026-09-19,`fix/audit-remainder-closeout`)
- per-stage 步骤覆盖(相对默认 organize→engineer→draft→review 的阶段差异)
- regulatory 步接 `complexity_tier`(与 R7 可合并认领)
- 模型去硬编码(配置/环境驱动)
- manifest hint + aliases 元数据补齐
- **证据**:`TestRDevRegulatoryFollowsComplexityTier`、`TestRDevModelFromEnv`、`TestRDevStageOverrideAndAliases`
### S3 — overlay 与质量门禁扩面
- **状态**:部分(2026-09-19)。overlay 与 R2/R3 已落地;P3 真 PI 未做
- 轻量 overlay 机制(模板管结构;overlay/运行时管纪律与粒度下限)— done,`configs/overlays/`,`TestRDevWorkspaceWritesOverlay`
- R2/R3 专用确定性门禁落地 — done,`TestRDevQualityGates`
- P3:三样本真 PI E2E 报告 + CI 四工作流门禁挂钩 — 未做
+2 -2
View File
@@ -5,6 +5,6 @@
- **B5** 报价模块接入轻量复核与输入范围校验(`internal/quote/`)
- **A5/A6** 小队工作流支持非关键步骤降级;并行 trace 序号改单次加锁读-算-写(`internal/squad/`)
- **A7** 将中文注释中的已知限制迁移为正式 issue
- **D3** 摘要引擎替换为语义摘要(依赖模型接入,需单独评估)(`internal/ctxmgr/summarizer.go`)
- **D3**(已实现,shadow)摘要引擎语义摘要能力已落地:`SEMANTIC_SUMMARY_SHADOW` 默认 off,见 [FEATURE-MATRIX「语义摘要(D3)」行](../status/FEATURE-MATRIX.md)、[PU6 契约](../ops/long-term/2026-09-16-pu6-semantic-summary-contract.md)(`status: done`)、[W2 真 PI 报告](../test-reports/2026-09-17-w2-semantic-summary-shadow-test-report.md)。`SEMANTIC_SUMMARY_REPLACE` 仍未接线(红线,需独立授权)。本行状态转入 FEATURE-MATRIX 常态跟踪,不再作为独立 backlog 开放项
- **D5** 知识库按环境隔离方案评估(当前三环境共享 KB 为 intentional 架构)
- **D7** 对话数据留存期限与敏感字段加密(先对齐合规再定技术方案)
- **D7** 对话数据留存期限与敏感字段加密——草案 ADR [2026-09-17-d7-chat-data-retention.md](../adr/2026-09-17-d7-chat-data-retention.md)(`compliance: pending-compliance-signoff`);[W7 只读盘点](../audit/2026-09-17-d7-data-inventory.md) 未发现基线违规,见 [报告](../test-reports/2026-09-17-w7-d7-inventory-test-report.md)。签字前禁止按 365/180/30 物理删除;本行继续跟踪合规签字进度
@@ -0,0 +1,22 @@
---
title: "dev 试点:开放编制人兼任总开关"
status: done
created: 2026-09-17
updated: 2026-09-17
---
# dev 试点:开放编制人兼任总开关
## 结论
在运行中的 `agent-dev`(`:8080`,schema 52)经 admin CAS 将 `workflow.allow_author_only_approval` 设为 `true`(revision `0 → 1`)。**未**改默认迁移值;**未**晋升 test/main;test/main 仍保持默认 off。
## 证据(脱敏)
- [before-enable.json](../../test-reports/assets/2026-09-17-author-only-pilot/before-enable.json)
- [put-enable.txt](../../test-reports/assets/2026-09-17-author-only-pilot/put-enable.txt)
- [after-enable.json](../../test-reports/assets/2026-09-17-author-only-pilot/after-enable.json)
## 关联
- author-only 收口:[../handoffs/2026-09-17-document-author-only-closeout.md](../handoffs/2026-09-17-document-author-only-closeout.md)
+61 -10
View File
@@ -1,19 +1,65 @@
# 当前焦点
**更新**: 2026-09-17
**production_ready**: yes(门禁 B1–B4 已签;dev/test `schema_version=48`;main `schema_version=47`;goose 00048 已在 test 迁移。不把 fallback change report 写成完整 PI)
**更新**: 2026-09-20
**production_ready**: yes(门禁 B1–B4 已签;dev/main schema **58**、test **57**。P0 热修 done;见 [报告](../test-reports/2026-09-20-p0-hotfixes-test-report.md)。不把 fallback change report 写成完整 PI)
## 焦点
1. **promote null-fk → test**:`rc-v1.0.0-beta.4`(docgov optional-duty FK 修复)
2. **partial/deferred 全量收口**:W1–W4 **done**;W5a **done**(矩阵自举行仍 partial);W6 **shadow done**(矩阵 FAV 仍 partial);W7 **盘点 done**(矩阵 D7 仍 deferred)。已晋升:`rc-v1.0.0-beta.3` → 本轮 `beta.4`
3. **红线**:禁止整支 merge FAV;不默认升 `MULTI_INTENT_PLAN_TIER=full`(升 `confirm` 须 W4 闭环后独立授权);`SEMANTIC_SUMMARY_REPLACE` 不随 W2 开启;FAV live 顺序 staging→artifact→publication、每级观察窗证据驱动(下限 ≥7 天)、`FAV_DEGRADED_READ=false`;flag 默认 off;项目 143 只读
1. **2026-09-20 rdev 种子热修 in_progress**:dev 库 rdev 停在 `retired`;test 库因 `publishedBy=1` 外键失败未发布 rdev。见 [short-term](./short-term/2026-09-20-rdev-seed-hotfix.md)。
2. **2026-09-20 模块解耦规范与审计 done(仅文档)**:耦合审计、开发规范、批次 A–G 计划已写;不改业务代码,不改 `production_ready`。见 [审计](../audit/2026-09-20-module-coupling-audit.md) · [规范](../system-design/2026-09-20-module-development-standards.md) · [批次](../remediation/2026-09-20-module-decoupling-batch-plan.md)。
3. **红线**:禁止整支 merge FAV;不默认升 `MULTI_INTENT_PLAN_TIER=full`;`SEMANTIC_SUMMARY_REPLACE` 不随 W2 开启;FAV live 观察窗证据驱动;`FAV_DEGRADED_READ=false`;项目 143 只读;SWBOOT-10 保持 fail-closed stub;D7 待合规签字;**P0 期间不改 `production_ready`**;模块解耦批次 A–G 未单独认领前保持 `planned`。
## 并行认领
| owner | task | branch | worktree | mutex | status |
|-------|------|--------|----------|-------|--------|
| Cursor | 2026-09-17-promote-null-fk-to-test | feature/promote-null-fk-to-test | - | infra | in_progress |
| Cursor | 2026-09-20-rdev-seed-hotfix | fix/workflow-seed-bootstrap-2026-09-20 | - | workflow-def | in_progress |
| Cursor-Auto | 2026-09-20-module-decoupling-spec-audit | docs/module-decoupling-spec-2026-09-20 | - | module-decoupling-spec | done |
| Cursor-Auto | 2026-09-20-p0-closeout | docs/p0-closeout-2026-09-20 | - | docs | done |
| Cursor-Auto | 2026-09-20-p0-hotfixes(Wave 0 文档) | docs/p0-triage-2026-09-20 | - | docs | done |
| Cursor-Auto | 2026-09-20-p0-capability-00058 | fix/capability-merge-00058-2026-09-20 | - | infra+chat | done |
| Cursor-Auto | 2026-09-20-p0-idor | fix/authz-idor-hotfixes-2026-09-20 | - | authz | done |
| Cursor-Auto | 2026-09-20-p0-runtime-stability | fix/runtime-panic-races-2026-09-20 | - | taskrun+chat+web | done |
| Cursor-Auto | 2026-09-20-p0-credentials | fix/credential-hardening-2026-09-20 | - | ops+infra | done |
| Cursor-Auto | 2026-09-20-proposed-authoritative-reports | feature/capability-enablement-impact-plan | - | docgov | done |
| Cursor-Auto | 2026-09-20-pi-narrative-clipped-diff | feature/capability-enablement-impact-plan | - | docgov | done |
| Cursor-Auto | 2026-09-20-pi-reasoning-profile | feature/capability-enablement-impact-plan | - | pi-agent | done |
| Cursor-Auto | 2026-09-20-semantic-summary-persistence | feature/capability-enablement-impact-plan | - | chat+lineage-version | done |
| Cursor-Auto | 2026-09-20-feature-readiness-and-lineage-authz | feature/capability-enablement-impact-plan | - | sysadmin+lineage | done |
| Codex | 2026-09-20-capability-enablement-impact-plan | feature/capability-enablement-impact-plan | - | capability-impact-research | done |
| Cursor-Auto | 2026-09-20-post-activation-duty-reassign-member-chat | fix/post-activation-duty-reassign-member-chat | - | projectworkflow+authz+web | done |
| Cursor-Auto | 2026-09-20-test-env-triage-fixes | fix/test-env-triage-2026-09-20 | - | projectworkflow+chat+assets | done |
| Cursor-Auto | 2026-09-20-test-env-beta6-verification | docs/test-env-beta6-verification | - | infra+docs | done |
| Cursor-Auto | 2026-09-20-bug-hunt-permissions-uploads | fix/bug-hunt-2026-09-20-permissions-and-uploads | - | authz+web+projectworkflow | done |
| Cursor | audit-b1-data-consistency | fix/audit-b1-data-consistency | - | docgov+workflow+chat | done |
| Cursor | audit-b2-authz-hardening | fix/audit-b2-authz-hardening | - | authz | done |
| Cursor | audit-b3-sse-events | fix/audit-b3-sse-events | - | chat+events | done |
| Cursor | audit-b4-frontend | fix/audit-b4-frontend | - | web | done |
| Cursor-Auto | 2026-09-19-audit-remainder-closeout | fix/audit-remainder-closeout | - | audit-remainder | done |
| Antigravity | 2026-09-20-dev-deep-test-and-promotion | feature/dev-deep-test-and-promotion | - | integration | done |
| Cursor-Auto | 2026-09-19-remove-control-center | fix/remove-control-center | - | controlcenter | done |
| Cursor-Auto | 2026-09-17-control-center-server | feature/control-center-server | - | controlcenter | cancelled |
| Kimi | 2026-09-18-user-manual | feature/user-manual | .worktrees/feature-user-manual | docs | done |
| Cursor-Auto | 2026-09-18-wave7-roadmap-orchestration | docs/wave7-roadmap-orchestration | - | roadmap-orchestration | done |
| Cursor-Auto | 2026-09-18-wave6-doc-drift | docs/wave6-doc-drift | - | doc-drift | done |
| Cursor-Auto | 2026-09-18-wave5-deadcode-decisions | fix/wave5-deadcode-decisions | - | deadcode-cleanup | done |
| Cursor-Auto | 2026-09-18-wave4-hardening-r1-r8 | fix/wave4-hardening-r1-r8 | - | hardening | done |
| Cursor-Auto | 2026-09-18-wave3-test-debt-blindspots | fix/wave3-test-debt-blindspots | - | test-debt | done |
| Cursor-Auto | 2026-09-18-wave2-config-flag-align | fix/wave2-config-flag-align | - | infra | done |
| Cursor | 2026-09-18-wave1-main-env-fix | fix/wave1-main-env-fix | - | infra | done |
| Cursor | 2026-09-18-wave0-p0-bug-fixes | fix/wave0-p0-sse-chat-cache-bugs | - | chat + web | done |
| Kimi | 2026-09-17-system-health-check(只读审计,未实施) | - | - | audit | done |
| Cursor | 2026-09-17-docgov-modification-proposal-http | feature/docgov-modification-proposal-http | - | docgov | done |
| Cursor | 2026-09-17-document-author-only-closeout | feature/document-author-only-plan | - | document-duty-policy | done |
| Cursor | 2026-09-17-rdev-template-depth-s1-continued | feature/rdev-template-depth-s1-continued | .worktrees/feature-rdev-template-depth-s1-continued | rdev-templates | done |
| Cursor | 2026-09-17-rdev-workflow-integration | feature/rdev-core | - | workflow-def | done |
| Cursor | 2026-09-17-rdev-template-depth | feature/rdev-template-depth | .worktrees/feature-rdev-template-depth | rdev-templates | done |
| Codex | 2026-09-17-document-author-only-plan | feature/document-author-only-plan | - | document-duty-policy-plan | done |
| Cursor | 2026-09-17-initial-load-perf-u2 | feature/initial-load-perf-u2 | - | web + static-delivery | done |
| Codex | 2026-09-17-initial-load-performance-plan | feature/initial-load-performance-plan | .worktrees/feature-initial-load-performance-plan | loading-performance-audit | done |
| Kimi | 2026-09-17-system-admin-console | feature/system-admin-console | - | web + sysadmin | done |
| Cursor-Auto | 2026-09-17-engineering-dashboard | feature/engineering-dashboard | .worktrees/feature-engineering-dashboard | engineering-dashboard | done |
| Cursor | 2026-09-17-promote-null-fk-to-test | feature/promote-null-fk-to-test | - | infra | done |
| Cursor | 2026-09-17-docgov-optional-duty-null-fk | fix/docgov-optional-duty-null-fk | - | docgov | done |
| Cursor | 2026-09-17-leftover-hygiene | chore/leftover-hygiene-2026-09-17 | - | ops | done |
| Cursor | 2026-09-17-w2-semantic-summary-shadow | feature/w2-semantic-summary-shadow-live | - | chat | done |
@@ -121,7 +167,7 @@
| holder | phase | since | scope | queue |
|--------|-------|-------|-------|-------|
| Cursor | merging | 2026-09-17 | promote null-fk → test (rc-v1.0.0-beta.4) | - |
| Cursor | merging | 2026-09-20 | fix/workflow-seed-bootstrap-2026-09-20:rdev 种子 publishedBy 回落与 retired 自愈 | - |
**phase**: `idle` | `merging` | `smoke` | `e2e`
@@ -131,20 +177,25 @@
| 环境 | 端口 | schema | 状态 |
|------|------|--------|------|
| dev | 8080 | **48** | healthy(`pi-agent` typed-result-v1;events worker `:8088`;notify/advance/projection live、fav off;health+ready PASS;demo 6001–6010 retired) |
| test | 8081 | **48** | healthy(`rc-v1.0.0-beta.3`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS;goose 00048 已迁移) |
| main | 8000 | **47** | healthy(app + events + runner + DB;与 dev/test 对齐) |
| dev | 8080 | **58** | healthy(`chat_summaries` 已落地;`pi-agent`;events `:8088`) |
| test | 8081 | **57** | healthy(待下次晋升补 00058;events `:8089`) |
| main | 8000 | **58** | healthy(P0 Wave3 rebuild 已追平 schema;分支树对齐仍记 backlog;口令已轮换;events `:8090`) |
## SSOT
| 类型 | 路径 |
|------|------|
| 2026-09-20 模块解耦 | [审计](../audit/2026-09-20-module-coupling-audit.md) · [规范](../system-design/2026-09-20-module-development-standards.md) · [批次 A–G](../remediation/2026-09-20-module-decoupling-batch-plan.md) · [short-term](./short-term/2026-09-20-module-decoupling-spec-audit.md) |
| 文档总地图 | [../README.md](../README.md) |
| 模块完成度 | [FEATURE-MATRIX](../status/FEATURE-MATRIX.md)(Wave 0 已校准契约与冻结边界) |
| 发布缺口 | [gap-matrix](../remediation/gap-matrix.md)(`production_ready=yes`;Wave 0 IAM 只读未发现旁路) |
| 2026-09-20 系统体检 | [audit](../audit/2026-09-20-system-triage-audit.md) · [P0 整改](../remediation/2026-09-20-p0-remediation-plan.md) · [short-term](./short-term/2026-09-20-p0-hotfixes.md) |
| 连续性审计/计划 | [audit](../audit/2026-09-16-feature-matrix-production-readiness-audit.md) · [remediation](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md) · [Wave 0 任务](./short-term/2026-09-16-feature-matrix-wave0-calibration.md) |
| 测试报告 | [test-reports/](../test-reports/) |
| dev→test 晋升前复核 | [research](./research/2026-09-19-pre-test-promotion-review.md)(2026-09-19 只读;静态门禁过,容器未 rebuild,暂不合并) |
| D7 盘点(W7) | [audit](../audit/2026-09-17-d7-data-inventory.md) · [报告](../test-reports/2026-09-17-w7-d7-inventory-test-report.md) · ADR 仍 `pending-compliance-signoff` |
| 功能启用与文档影响分析 | [调研](./research/2026-09-20-capability-enablement-impact-research.md) · [整改方案](../remediation/2026-09-20-capability-enablement-impact-plan.md) · [方案审阅](./research/2026-09-20-capability-enablement-impact-plan-review.md)(2026-09-20;未启用开关、未改业务代码) |
| Wave 7 编排确认 | [决策记录](./short-term/2026-09-18-wave7-roadmap-orchestration.md) |
| Agent 手册 | [AGENTS.md](../../AGENTS.md) |
| 意图双标签 busy 交接 | [./handoffs/2026-09-15-conversation-intent-dual-tab.md](./handoffs/2026-09-15-conversation-intent-dual-tab.md) |
| 受控正文 hash 漂移 W1–W6 | [../ops/handoffs/2026-09-14-controlled-content-canonical-hash.md](../ops/handoffs/2026-09-14-controlled-content-canonical-hash.md) |
@@ -65,3 +65,13 @@ curl -sf http://127.0.0.1:8080/ready
- CURRENT: [CURRENT.md](../CURRENT.md)
- Task: [../short-term/2026-09-13-conversation-intent-runtime-state.md](../short-term/2026-09-13-conversation-intent-runtime-state.md)
- Test report: [../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md](../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md)
## 回标(2026-09-18,Wave 6 文档漂移修复)
上方「未完成」与「认领 / 槽位状态」两节是 2026-09-15 交接时刻的快照,**已在同一提交(`8a8f64a`)内被后续证据覆盖**:
- 浏览器双标签刷新恢复 / busy 租约可见性:项目 6275、`sess-p6275-u10` 真实 PI + Docker 截图(`dual-tab-live.py`、`live.json`、`window-before-refresh.json`、`window-after-refresh.json`、`screenshots/tab-b-after-reload.png` 等,均在同一提交归档)。
- `CHAT-INTENT-STATE` 已在 [gap-matrix](../../remediation/gap-matrix.md) 标记 **PASS**(「双标签活验项目 6275 / `sess-p6275-u10`」)。
- mutex 已释放:CURRENT.md 当前无该任务 `in_progress` 行;集成槽位 holder 为 `idle`。
**结论**:本 handoff 无待办事项,`status: closed` 生效,仅为历史记录保留原文,不删除。
@@ -0,0 +1,40 @@
---
title: "document-author-only U1–U6 收口交接"
status: done
created: 2026-09-17
updated: 2026-09-17
from: Cursor
to: integrator
---
# document-author-only U1–U6 收口交接
## 结论
实现与验收任务已全部收口:U1–U6 short-term 已迁入 `archive/ops/`;FEATURE-MATRIX / remediation DoD(除发布末条)已更新;U6 报告已归档。
**远端**:已 `git-push-dev.sh` 推送 `origin/dev`(含 author-only merge);**未**晋升 test/main。
**dev 试点**:`workflow.allow_author_only_approval=true`(revision 1);证据见 [pilot assets](../../test-reports/assets/2026-09-17-author-only-pilot/) 与 [ops 笔记](../2026-09-17-author-only-pilot-toggle.md)。
## 分支
- `feature/document-author-only-plan` — 已合入并清理 worktree/本地分支
- 续作:`feature/docgov-modification-proposal-http`(变更提案 HTTP)
## 合入 `dev`(已完成)
- `merge --no-ff feature/document-author-only-plan` → 后续推送至 `origin/dev@ba92a8b` 一带
- 冒烟:`go vet` / `go test -short` 相关包 PASS;`./scripts/env-service.sh dev rebuild`;`GET /health` → `schema_version=52`、`status=ok`
- 总开关默认迁移值仍为 off;**dev 运行态**已 CAS 试点开启;**未**晋升 test/main
## 明确不在本期(已转入续作)
- ~~变更提案 HTTP 路由~~ → [short-term](../short-term/2026-09-17-docgov-modification-proposal-http.md) / [audit resolved](../../audit/2026-09-17-docgov-modification-proposal-http-gap.md)
- test/main 晋升仍另授
## 证据
- [U6 报告](../../test-reports/2026-09-17-document-author-only-u6-test-report.md)
- [方案 DoD](../../remediation/2026-09-17-document-author-only-plan.md)
- [pilot](../../test-reports/assets/2026-09-17-author-only-pilot/)
@@ -63,6 +63,8 @@ L1(SWBOOT-00…09 契约/迁移/目录钩子 + SWBOOT-10 stub)**已合入 `d
L1 已合 `dev`。W5a 从 `dev` 开 `feature/w5a-software-bootstrap-ui-pi`(mutex `workflow-design`)。W5b 受控执行器未启动,SWBOOT-10 保持 fail-closed stub。
**Wave 5 X-3(2026-09-18)**:goose 00048 三表(`project_types` / `compliance_profiles` / `project_type_workflows`;另含零读者的 `project_source_bindings` / `repo_path_allowlist`)消费方接线评估结论 = **deferred → SWBOOT-10/W5b**。不改 schema;API 继续硬编码目录。决策落点:[wave5-deadcode-decisions.md#x-3](../short-term/2026-09-18-wave5-deadcode-decisions.md#x-3)。不阻塞 W5b 立项。
## 相关链接
- [详细设计](../../system-design/2026-09-14-software-project-bootstrap-workflow.md)
@@ -1,8 +1,8 @@
---
title: "PU8-U10 mutate — 获批后任务契约"
status: in_progress
status: done
created: 2026-09-16
updated: 2026-09-17
updated: 2026-09-18
owner: Cursor
branch: feature/w4-u9-segment-live
mutex: intent-plan
@@ -1,8 +1,8 @@
---
title: "PU8-U11 docgov action — 获批后任务契约"
status: in_progress
status: done
created: 2026-09-16
updated: 2026-09-17
updated: 2026-09-18
owner: Cursor
branch: feature/w4-u9-segment-live
mutex: intent-plan
@@ -1,8 +1,8 @@
---
title: "PU8-U12 workflow/run-control — 获批后任务契约"
status: in_progress
status: done
created: 2026-09-16
updated: 2026-09-17
updated: 2026-09-18
owner: Cursor
branch: feature/w4-u9-segment-live
mutex: intent-plan
@@ -1,8 +1,8 @@
---
title: "PU8-U9 segment proposal — 获批后任务契约"
status: in_progress
status: done
created: 2026-09-16
updated: 2026-09-17
updated: 2026-09-18
owner: Cursor
branch: feature/w4-u9-segment-live
mutex: intent-plan
@@ -0,0 +1,119 @@
---
title: "2026-09-19 审计剩余项(medium/low,不挡已合入批 1–4)"
status: planned
created: 2026-09-19
updated: 2026-09-19
---
# 2026-09-19 审计剩余项
## 动机
[系统深度体检](../../audit/2026-09-19-system-deep-audit.md) 的 C1–C4 与 H1–H10 已按四批合入 `dev`。下列 medium/low 仍真实存在,但不进入本轮发布回退。
## 成功标准
- 每条有独立 short-term、负例测试或明确关闭理由后再标 done
- 不把本清单自动写成 gap-matrix blocker
## 依赖
- 批 1–4 已在 `dev`:`844f757`、`08f4e0b`、`a2a49a6`、`d73bc79`
## 暂不启动原因
本轮范围只到 critical + high。下列项要么是加固、要么需要产品/合规决策,要么改动面大于收益。
## 进展(2026-09-19,`fix/audit-remainder-closeout`)
| ID | 结果 |
|----|------|
| M1 | done。`nosniff` / `DENY` / `Referrer-Policy` / 本站 CSP。`TestP0_SecurityHeaders` |
| M2 | done。TTL 钳到人工 15 分钟、小队 30 分钟;人工租约前 `CheckHumanCanEdit`。`TestAcquireLeaseClampsHumanTTL` |
| M3 | done(本项可落地部分)。低置信度才做关键词改道;称呼取用户名。高置信度意图层改造不在本项把模板整段搬走 |
| M4 | done。`parseDecimalID` 拒绝 `u_sess_*`。`TestParseDecimalIDRejectsSessionTokens` |
| M5 | done。`Server.Start` 不再二次启动并吞错。`main` 仍调用 `Runtime.Start`,该方法本身已幂等 |
| M6 | done(上限)。硬上限 4096,淘汰最久未访问。会话 id 仍由客户端提供,因为历史恢复按该 id 查找;改成只接受服务端签发会打断现有对话协议 |
| M9 | done。dev compose 不再声明 `SEMANTIC_SUMMARY_REPLACE`。dev=`MiniMax-M2.7-highspeed`、test/main=`MiniMax-M3` 确认为有意分叉,已写在 compose 注释 |
| M10 | done(写明路径,不放开门闩)。`OpsCutoverPromotionPath`:dev 观察后用晋升回执写 test,再写 main。`ValidateOpsCutover` 仍拒绝 test/main |
| M13 | done。SQL 迁到 `deploy/postgres/archive/pre-goose/`。代码与脚本无引用 |
| M14 | done。冻结计划找不到职责行则报错;显式空三权仍为 0。`TestResolveDocTask_NoneDutiesStayZero` |
| L1 | done。健康检查 2 秒缓存 + 2 秒 DB 超时 |
| L2 | done。SSE marshal 失败写 `event: error` 帧 |
| L3 | done。`ReplayPlan.Digest` 含 `DryRun`;dry-run 摘要不能授权 apply |
| M15 | done。生产 `claimSQL` 与 `MemoryBus` 共用 `VersionClaimable`:版本 0 可领,版本化事件不能跳过 checkpoint。checkpoint 只前进。`TestVersionClaimableMatchesMemoryBusGap`、`TestGapDoesNotSkipVersion` |
| H3 负例 | done。`TestListChatSessions_CrossUserIs403` |
| FE 缓存 | done(版本字段)。窗口缓存写入 `{schema,data}`,无 schema 的旧载荷丢弃。`window cache: 无 schema` |
| FE lucide | 关闭理由:`package-lock.json` 锁定 `lucide-react@1.42.0`,来源 `registry.npmjs.org`,带 integrity。`^1.16.0` 是合法的 1.x 范围,不是来源不明的包 |
| M7 | done(出站意图 + 同键重放)。`document_content_projections` 与账本同一事务写入;投影成功才销账。`TestDocRevision_PatchOrder_RetryProjectsWithoutSecondLedgerCommit`。账本库与正文库仍不是一个 SQL 事务,进程退出后靠未投影行重放,不靠客户端记忆 |
| FE App.tsx | 部分收口。登录壳不再静态引用重模块。本地缓存、登录同步、文档补水、服务端文档同步、生命周期、发送消息、块编辑、对话流/任务流重试、卡片动作、立项和成员写操作已分别抽出。文档栏在 `DocumentPane`,聊天栏在 `ChatColumn`,`AppShell` 与工作台弹窗在 `WorkbenchView`。`App.tsx` 仍持有会话状态,不再挂 `<AppShell` |
| H1-del | 关闭理由:`allowLegacyTestPrincipal` 仍被 `AllowInMemory && ContextDbHost==""` 的 dev/test 内存测试使用。删除会把这批测试变成未登录 401。保留告警,删除另开、先改测试夹具 |
仍开放:`rd_proposal` 终稿未对齐模板标题(没有新的真 PI)。U7 登录表单可见未测(本机无头 Chromium 缺 `libatk`),也不把 1.4 秒模块图写成「较十几秒基线下降 50%」。见 [U7 报告](../test-reports/2026-09-19-initial-load-u7-restart-test-report.md)。工作台壳已挪到 `WorkbenchView`。dev schema 53。U6 仍不加索引。`TestArchitectureBoundaries` 仍有 6 条新 import(intent/squad/template → workflowdef),不是本轮容器改动。test/main 仍是 schema 52。评审门禁的法规表误伤已修,保存的 P3 终稿不再报「问题行缺少」。
红线关闭(不是实现):
- SWBOOT-10:保持 fail-closed stub。未获独立授权前不接真实仓库写入。
- FAV live:禁止整支 merge;`FAV_DEGRADED_READ=false`;live 需要各阶段至少 7 天观察窗,本轮不放量。
- D7:合规签字前禁止按留存口径物理删除。盘点已完成,口径仍 `pending-compliance-signoff`。
## 清单
| ID | 项 | 位置 | 说明 |
|----|----|------|------|
| M1 | 安全响应头 | `internal/server/server.go` CORS 中间件 | 补 `nosniff` / `X-Frame-Options` / `Referrer-Policy` / 收敛 CSP |
| M2 | 租约 TTL 无上限 | `handlers.go` AcquireLease | clamp 到 `DefaultHumanLeaseTTL`,Acquire 前校验编辑权 |
| M3 | 关键词改写意图 + 硬编码「张工」 | `internal/coordinator/engine.go` | 移到意图层并加置信度;称呼取用户名 |
| M4 | `fmt.Sscanf` 解析 `u_sess_*` 得到 UserID=0 | 同上 | 统一数字 ID |
| M5 | `Runtime.Start` 双调用且吞错 | `cmd/server/main.go` 与 `server.go` | `sync.Once` 或删 Server.Start 内调用 |
| M6 | sessions 无硬上限 | `server.go` cleanStaleSessionsLocked | LRU + 服务端发 session id |
| M7 | 修订三阶段写无事务 | `document_revision_handlers.go` | 已落地:`00053` 投影意图与账本同事务;成功后销账。见进展表 |
| M9 | `SEMANTIC_SUMMARY_REPLACE` 只在 dev compose 声明;dev/test 默认模型不一致 | compose | 删未接线 flag 并钉死测试;确认 M3 是否刻意 |
| M10 | cutover 只允许 `dev` | `internal/events/cutover.go` | 写明 test/main 切换路径 |
| M13 | `deploy/postgres/migrations/` 死目录 | 与 goose 重复 | 确认无外部依赖后归档 |
| M14 | ResolveDocTask 静默 0 值三权 | `orchestrator.go` | 找不到 duties 应报错 |
| M15 | PG 投递允许乱序,MemoryBus 有 gap | `dispatcher.go` vs `bus.go` | 对齐测试替身与生产顺序语义 |
| L1 | health 每次打两次 DB | `handlers.go` | 短缓存 + 超时 |
| L2 | SSE marshal 错误被吞 | `task_run_handlers.go` | 失败写 error 帧 |
| L3 | ReplayPlan digest 不含 DryRun | `replay.go` | 纳入 digest |
| H1-del | 删除 legacy user-id=1 兜底 | `auth_middleware.go` | 已加日志;删除前盘点调用方 |
| FE | App.tsx 巨石、localStorage 无版本、lucide 版本确认 | `web/` | 拆 hook;缓存加 version;确认包来源 |
## 相关链接
- 审计:[../../audit/2026-09-19-system-deep-audit.md](../../audit/2026-09-19-system-deep-audit.md)
- 批 1–3 报告:`.doc/test-reports/2026-09-19-audit-b*.md`
## 2026-09-20 系统体检增补(非 P0,不挡本轮热修)
> 来源:[../../audit/2026-09-20-system-triage-audit.md](../../audit/2026-09-20-system-triage-audit.md)。P0 项走 [../../remediation/2026-09-20-p0-remediation-plan.md](../../remediation/2026-09-20-p0-remediation-plan.md),不写入本表为「已关闭」。
| ID | 项 | 位置 | 说明 |
|----|----|------|------|
| T20-B1 | 登录限流信任 XFF 首跳 | `login_rate_limit.go` | 仅在可信代理后启用;否则用 RemoteAddr |
| T20-B2 | events `cancelFns` 只增不减 | `events/worker.go` | claim 完成后从切片移除 |
| T20-B3 | docrevision/docgov 全局锁内 DB I/O | `docrevision/*` `docgov/lease.go` | 锁外 hydrate / 按文档分锁 |
| T20-B4 | 主库连接池无 statement_timeout | `bizdev/service.go` | 对齐 kb 池调优 |
| T20-B5 | chat 消息与 turn 非原子 | `chat/session.go` | 同事务或补偿明确 |
| T20-B6 | `idemLocks` map 永不清理 | `taskrun/manager.go` | TTL 或终态回收 |
| T20-B7 | Shutdown 5s vs 长任务 | `cmd/server/main.go` | 拉长优雅退出或拒绝新任务 |
| T20-B8 | `hasMessageScopeColumns` 无缓存 | `message_scope_io.go` | 启动缓存一次 |
| T20-B9 | C1 记忆写入不失效缓存 | `chat_memory.go` | upsert 后 Invalidate |
| T20-B10 | SSE 头先写再 Subscribe | `task_run_handlers.go` | 对齐 sse.go 顺序 |
| T20-B11 | GET chat/stream 消息走 query | `sse.go` | 改 POST body |
| T20-F1 | `useChatWindow` 切会话竞态 | `useChatWindow.ts` | loadOlder 等加 generation/abort |
| T20-F2 | PLAN_CONFIRM 无 try/catch | `useCardActions.ts` | 失败复位 executing |
| T20-F3 | turn Map 只增不减 | `useTurnRuntime.ts` | removeTurn 接线 |
| T20-F4 | 重置密码死功能 + 硬编码文案 | `UsersSection.tsx` | 接真实 API 或隐藏按钮 |
| T20-F5 | ErrorBoundary 仅顶层 | `main.tsx` | 栏级边界 |
| T20-F6 | SSE 帧不兼容 `\r\n` | `chatStream.ts` | 规范 CRLF |
| T20-F7 | token 存 localStorage + 无全局 401 | `auth.ts` | HttpOnly cookie 专项 |
| T20-F8 | blob URL / 轮询叠加 / 统计迟到 | 多处 | 加固批 |
| T20-I1 | 容器 root、无 mem/cpu 限制 | compose / Dockerfile | 非 root + resources |
| T20-I2 | 健康检查路径三环境不一致 | compose | 统一 `/ready` |
| T20-I3 | main events 挂 shared-net | `docker-compose.main.yml` | 对齐 dev/test |
| T20-I4 | init 策略三套分叉 | compose volumes | 统一 extensions_init |
| T20-I5 | Dockerfile Go 1.23 基镜像 | `deploy/app/Dockerfile` | 钉 1.27.1 |
| T20-I6 | backup 无定时调度 | ops | systemd/cron;RPO 60m |
| T20-I7 | **main 分支对齐晋升专项** | git main vs schema 52 | 独立授权;含 00057 改名预演 |
| T20-I8 | 默认 short 测依赖外网 docker 镜像 | `pi_runner_image_test.go` | Short 跳过或本地 fixture |
@@ -0,0 +1,93 @@
---
title: "参考项目 weichen-agent-system 研发工作流(rdev)文档关系与阶段组成梳理"
created: 2026-09-17
status: done
confidence: high
---
# 调研:参考项目 weichen-agent-system 研发工作流(rdev)文档关系与阶段组成梳理
## 结论
参考项目 `.refs/weichen-agent-system` 中的「研发流程」(`key: rdev`)是与商务对接(bizdev)、测试经理(test_manager)、产品经理(product_manager)并列的第 4 个工作流,`kind: followon`、`after: bizdev`:商务对接末阶段 CDO 报价批准后才可启动。rdev 共 **60 个阶段(文档任务)**,按 **13 个 phase(01–13)** 组织成 ISO 13485 设计控制链(策划 → 输入 → 输出 → 验证 → 转换 → 确认),每阶段恰好对应 `templates/docs/<stage_key>.md` 一份自描述模板,并有 overlays(工作流级 `rdev.md` + 阶段簇 `rdev_phNN.md` + 文档类型 `kind_*.md`)与 `configs/squads/rdev.yaml` 五步小队编排三层配套。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 工作流定义 | `.refs/weichen-agent-system/configs/workflows/rdev.yaml` | 1473 行;`key: rdev` `kind: followon` `after: bizdev`;60 个 stage |
| 阶段齐套校验 | `.refs/weichen-agent-system/scripts/e2e-rdev.sh` | 脚本内置断言 `want 60 rdev stages`,逐 stage 校验 `templates/docs/<key>.md` 存在且非空,末模板须含「签署」 |
| 小队编排 | `.refs/weichen-agent-system/configs/squads/rdev.yaml` | `default_steps`:organizer → engineer(+regulatory 可选并行)→ writer → leader;关键 stage 覆盖专属 steps |
| 任务叠加 | `.refs/weichen-agent-system/configs/overlays/rdev.md`、`rdev_ph01…ph13.md`、`rdev_software.md`、`kind_review_minutes.md`、`kind_upload_index.md`、`kind_design_record.md` | 工作流级 / 阶段簇 / 文档类型三层叠加,`### role:` 按专员过滤 |
| 研发负责人人设 | `.refs/weichen-agent-system/configs/agents/rdev_leader.md` | 「研发/设计控制小队负责人…按 ISO 13485 把本阶段做成可追溯的 DHF 记录」 |
| 插件 | `.refs/weichen-agent-system/plugins/rdev/plugin.go` | 不注册生成意图,启动走生命周期 `start_workflow`(说法「启动研发流程」) |
| 官方说明 | `.refs/weichen-agent-system/docs/workflows.md` §研发流程、`docs/handoff.md` §研发流程(followon) | 约 60 阶段、每阶段一份 Word(RD-…)、不适用须完整理由并仍走审核/批准 |
| Canonical 归档 | `docs/cloud-drive.md` | `archive/dhf/{NN-阶段名}/{nn-产出}`;`records` 含 `dmr` 且已批准再拷 `archive/dmr/` |
## 研发工作流的文档关系(五层结构)
```text
configs/workflows/rdev.yaml ← 阶段 SSOT:key/标题/phase/records/artifact_kind/docx 元数据/fields/depends_on/skippable
│ 一一对应(stage key = 模板文件名)
▼
templates/docs/<stage_key>.md ← 自描述模板:文件编号 RD-…、记录归属 DHF(/DMR)、阶段 NN、
│ 结论/适用性/正文/追溯表/材料摘要/待确认清单/签署 固定骨架
▼
configs/squads/rdev.yaml ← 小队编排:default_steps + 个别 stage 覆盖(五步编制流水线)
▼
configs/overlays/*.md ← 任务叠加(注入 TASK 的阶段级撰写指导,多层):
① rdev.md(工作流级全员质量红线)
② rdev_phNN.md(阶段簇,ph01–ph13)
③ kind_review_minutes / kind_upload_index / kind_design_record(文档类型)
④ rdev_software.md(软件类阶段专项)+ 个别 stage 特例 overlay
▼
plugins/rdev/plugin.go ← 运行时入口:启动走生命周期 start_workflow(followon 门禁),
不注册生成意图;启动时从 bizdev 拷贝已填字段(产品类型/预期用途/目标市场等)
```
- **模板即文档**:每份模板头部自带「文件编号 / 记录归属 / 版本 / 阶段」元数据,与 rdev.yaml 中 stage 的 `docx.code`(RD-…)和 `phase` 一致;`scripts/e2e-rdev.sh` 强制校验 60 个 key 与模板一一对应。
- **记录归属双轨**:`records: [dhf]`(设计历史文件)为主;设计输出/转换类文档 `records: [dhf, dmr]`(同时属器械主记录),批准后额外拷贝到 `archive/dmr/`。
- **追溯链**:每份模板含固定「追溯」表(本文件 ID ↔ 上游输入 ↔ 下游验证/确认),需求类要求 UR→RS 追溯主表(见 `kind_design_record.md`)。
- **评审依赖**:评审记录类 stage 用 `depends_on` 显式声明上游(如 `verification_review` depends_on `design_vv`、`risk_report_v`)。
- **不适用机制**:每 stage 都有 `applicability` / `na_rationale` 字段;软件类/动物试验/临床等 15 个 stage 标 `skippable: true` + `skip_hint`,不适用仍须生成完整不适用页并走审核/批准。
## 工作流阶段组成(13 个 phase / 60 个 stage)
| Phase | 阶段簇 overlay | Stage(key → 文档) | 数量 |
|-------|--------|--------------------|------|
| 01 策划 | rdev_ph01 | `proposal` 项目建议书、`design_plan` 设计开发计划任务书 | 2 |
| 02 策划评审 | rdev_ph02 | `planning_review` 策划评审记录(depends: proposal, design_plan) | 1 |
| 03 设计输入 | rdev_ph03 | `user_needs` 用户需求规格书(UN)、`regs_stds` 法规和标准清单、`adverse_events` 同类产品不良事件、`system_reqs` 系统需求规格书(SR)、`risk_plan` 风险管理计划、`hazard_analysis` 危险分析、`sw_plan`*/`sw_reqs`*/`sw_config`* 软件三件套、`design_input_spec` 设计输入规格书、`design_input_list` 设计输入清单、`system_design` 系统设计方案 | 12 |
| 04 需求评审 | — | `req_review` 需求评审记录(depends: user_needs, system_reqs) | 1 |
| 05 输入阶段评审 | — | `input_phase_review` 阶段3和4评审记录(depends: design_input_spec/list, req_review) | 1 |
| 06 设计输出 | rdev_ph06 | `drawings_3d` 图纸3D、`product_bom` BOM、`ee_bom`*/`pcba`*/`electrical_sys`* 电气三件套、`sw_arch`*/`sw_ui`* 软件、`purchase_spec` 采购规范、`process_flow` 工艺流程、`packaging` 包装、`ifu` 说明书、`incoming_iqc`/`ipqc`/`fqc` 三级检验、`tech_req` 产品技术要求、`risk_report` 风险管理报告、`design_output_list` 设计输出清单 | 17 |
| 07 输出评审 | — | `output_review` 阶段6评审(depends: design_output_list) | 1 |
| 08 验证 | rdev_ph08 | `prototype_photos` 样机照片、`design_vv` 设计验证方案、`shelf_life` 货架寿命、`lifetime` 使用期限、`biocompatibility` 生物学、`cleaning` 清洁消毒、`emc_safety`* EMC安规、`risk_report_v` 验证风险报告、`sw_release`*/`sw_unit_test`*/`sw_sys_test`* 软件三件套、`qualified_suppliers` 合格供方 | 12 |
| 09 验证评审 | — | `verification_review`(depends: design_vv, risk_report_v) | 1 |
| 10 转换 | — | `dmr_list` DMR文件清单、`pack_ship` 包装运输、`risk_report_t` 转换风险报告 | 3 |
| 11 转换评审 | — | `transfer_review`(depends: dmr_list, pack_ship, risk_report_t) | 1 |
| 12 确认 | — | `validation_plan` 设计确认方案、`use_error` 使用错误、`animal_study`* 动物试验、`sw_quality`* 软件质量、`clinical`* 临床试验报告、`risk_report_val` 确认风险报告、`user_test` 用户测试 | 7 |
| 13 设计确认报告 | — | `design_validation_report` 设计确认报告(末阶段,批准后项目 done) | 1 |
合计 60,与 `e2e-rdev.sh` 的 `want 60 rdev stages` 断言一致。(`*` = `skippable: true`,实测 grep 共 15 个:软件 9 个(sw_plan/sw_reqs/sw_config/sw_arch/sw_ui/sw_release/sw_unit_test/sw_sys_test/sw_quality)+ 电气 3 个(ee_bom/pcba/electrical_sys)+ emc_safety + animal_study + clinical)
**artifact_kind 三类**(grep 实测):`document`(常规成文,47 个)、`review_minutes`(评审记录,6 个)、`upload_index`(附件清单/上传索引,7 个,只建索引不伪造内容)。各 kind 有独立 overlay 质量要求。
## 小队与治理机制
- **小队编制**:复用整理(organizer)/技术(engineer)/撰写(writer)/法规(regulatory)/检索(searcher)专员,种子化「研发流程负责人」(rdev_leader);市场与财务不进研发小队。
- **默认五步**:organizer(抽材料事实+回填字段+blackboard facts/gaps/implications)→ engineer(技术内容与追溯,可并行)→ regulatory(仅 complexity_tier=high,可选并行)→ writer(按模板成稿)→ leader(二审完整性/粒度/不适用理由/有无编造,不达标退回)。
- **门禁**:启动前必须 bizdev CDO 已批准(e2e 脚本专门验证「CDO 前启动应被拒绝」);启动时从商务对接拷贝产品类型/预期用途/目标市场等字段。
- **状态机**:与 bizdev 同一套编制/审核/批准 FSM;末阶段批准后项目标 `done`。
## 开放问题
- 本仓库(Agent-System)当前尚无 rdev 工作流模块;若要移植,需评估 60 stage × 模板 × overlay × 小队步骤的落地范围与分期(bizdev 已有移植先例)。
- 参考项目 `records: [dhf, dmr]` 双归属与云盘 canonical 归档机制在本仓库尚无对应物,移植时需决策是否引入。
- `complexity_tier=high` 才注入 regulatory 步;本仓库复杂度分层(complexity_high/medium overlay)如何对齐需另调研。
## 建议动作
- 若立项移植 rdev:在 `ops/short-term/` 新建任务,按「工作流定义 → 模板 → 小队 → overlays → 生命周期门禁」顺序分批实施,先做 phase 01–03(策划/输入)切片。
- 移植时保留「stage key = 模板文件名」一一对应约束,并复刻 e2e 齐套校验(60 stage、模板非空、末模板含签署)。
@@ -0,0 +1,151 @@
---
title: "dev→test 晋升前复核:功能权限、合并可行性、已知缺陷"
created: 2026-09-19
updated: 2026-09-19
status: done
confidence: high
---
# 调研:dev→test 晋升前复核
只读复核。不改业务代码、不 rebuild 容器、不合入 `test`/`main`、不修复 [medium/low backlog](../long-term/2026-09-19-audit-remainder.md)。
## 结论
1. **规划内的功能、权限与流程已按声明范围接入。** [FEATURE-MATRIX](../../status/FEATURE-MATRIX.md) 主表里,除明确标成 `partial` / `deferred` 的行以外,其余能力均为 `done`,并有测试报告或 commit 证据。没有发现「规划了但完全未实现」的模块。未完成项是主动延后,且 [gap-matrix](../../remediation/gap-matrix.md) 已判定不挡首发。
2. **`dev` 的静态质量达标,但现在不建议直接合并入 `test`。** `go vet` 与 `go test -short` 全绿,2026-09-19 深度审计的 critical/high 已合入 `dev`。合并前仍缺三件事:dev 容器 rebuild 冒烟、治理 PG 集成与前端构建、批 2 越权负例的自动化覆盖。
3. **critical/high 已关闭;medium/low 仍在,且本轮不修。** 新发现的观察项是文档漂移和 `test` 分支上 9 个晋升提交,不是新的代码缺陷。
## 一、功能、权限、流程
对照 [FEATURE-MATRIX](../../status/FEATURE-MATRIX.md)(更新 2026-09-19)与 [gap-matrix](../../remediation/gap-matrix.md)(`production_ready=yes`,门禁 B1–B4 已签)。
### 已关闭(声明范围内 `done`)
| 能力 | 接入情况 |
|------|----------|
| 意图识别 L1、多意图 U1–U8、多意图扩面 U9–U12 | 代码与报告齐全;`MULTI_INTENT_PLAN_TIER` 仍为 `legacy`,未默认升 `confirm`/`full` |
| 对话 / ctxmgr、语义摘要 D3、PI change-report 叙事 | 刷新恢复门禁已签;摘要与叙事 flag 默认 off,REPLACE 未启用 |
| 工作流治理 | 三正式工作流、动作级鉴权、真实 PI E2E |
| 文档治理、文档版本 baseline | 法定生命周期、租约、受控正文、运行时 UI |
| IAM / 鉴权 | 项目级 API + RBAC;路由清单见 [authorization-matrix-v3](../../audit/authorization-matrix-v3-full.md) |
| 前端工作台、PI Runner、三环境运维、CI/E2E、Artifact 同 digest、可靠事件核心、系统管理台 | 各自行有报告;系统管理台二期(Playwright、细粒度 `system:*`、设置审计)不在本行关闭条件内 |
| 文档编制人兼任(U1–U6) | 已合入 `dev`;总开关默认 off |
2026-09-19 审计批 2 已把鉴权缺口接到主链:H1 给 dev/test legacy 兜底加了告警(未删除兜底)、H2 批注/认领 actor 取 principal 且读类端点校验项目成员、H3 会话查询跨用户 403、H4 登录限流、H8 compose 口令改为必填。证据:[批 2 报告](../../test-reports/2026-09-19-audit-b2-authz-hardening-test-report.md)。
### 明确未完成(不是遗漏)
| 行 | 状态 | 剩余 | 是否挡首发 |
|----|------|------|------------|
| 研发设计控制(rdev) | partial | S2/S3、P2 前端、P3 三样本 E2E、P4 键名空间化 | 否 |
| 纯软件项目自举 | partial | SWBOOT-10 仍 fail-closed stub | 否 |
| Final Artifact Vault | partial | live 未放量;禁止整支 merge;`FAV_DEGRADED_READ=false` | 否 |
| 对话数据治理(D7) | deferred | `pending-compliance-signoff`;禁止按口径物理删除 | 否(违规则才升 blocker) |
| 首次加载性能 | partial(矩阵外专项) | U2 已验收;U1/U3–U7 未做 | 否 |
红线与代码/compose 对齐(深度审计已核实,本轮未再改 flag):`MULTI_INTENT_PLAN_TIER=legacy`、`SEMANTIC_SUMMARY_REPLACE` 未接线、`FAV_DEGRADED_READ=false`、SWBOOT-10 fail-closed stub、项目 143 只读。
## 二、`dev` 能否合入 `test`
**判断:静态门禁通过,运行态与回归门禁未补齐,暂不合并。**
### 已满足
- `dev` 工作树在复核时干净;`dev` HEAD 为 `66421b1`(含审计批 1–4:`844f757`、`08f4e0b`、`a2a49a6`、`d73bc79`)。
- `go vet ./...` 零告警。
- `go test -short ./...` 全包 PASS(`internal/server` 本轮实测约 14s,非缓存)。
- 三环境 `GET /api/v1/health` 均为 `status=ok`、`schema_version=52`、`schema_ready=true`。goose 最新文件为 `00052`。迁移版本本身不阻塞晋升。
- `internal/`、`cmd/` 生产代码中无 `TODO`/`FIXME`/`XXX`。
### 合并前必须处理
1. **dev 容器仍是旧二进制。** 批 1–3 报告写明未执行 `./scripts/env-service.sh dev rebuild`。`:8080` 健康只证明旧镜像在跑,不能证明审计修复已部署。按 [AGENTS.md](../../../AGENTS.md) §6.3,合入共享环境前要占集成槽位并冒烟。
2. **`dev` 领先 `test` 225 个 commit。** 差异覆盖 rdev 模板、系统管理台、docgov 加固、Control Center 移除等。`-short` 不够。晋升前至少再跑:`TEST_DATABASE_URL` 下治理 PG 集成,以及 `cd web && npm test && npm run build`。
3. **批 2 的越权负例仍是人工兜底。** [批 2 报告](../../test-reports/2026-09-19-audit-b2-authz-hardening-test-report.md) 写明:非项目成员访问 docgov 应 403 的 HTTP/Playwright 负例未补,目前靠既有鉴权测试不回退加 code review。
### `test` 上多出来的 9 个提交
`git rev-list --count dev..test` = 9。这些提交是历次 `release-candidate` / 晋升文档同步(含 `rc-v1.0.0-beta.2` 至 `beta.4`),不是 `dev` 上缺失的产品代码。下次晋升应把 `dev` **merge 进** `test`,不要把 `test` reset 到 `dev`,否则这 9 个提交的晋升记录会丢。
`CURRENT.md` 文首仍写 test `schema_version=48`,同文「环境快照」表与本次 health 实测已是 52。这是文档漂移,不是运行时缺陷。更正留给下次晋升文档,本笔记不改那一行。
## 三、缺陷
### 已修复(2026-09-19 深度审计 critical/high)
来源:[系统深度体检](../../audit/2026-09-19-system-deep-audit.md)。四批均已合入 `dev`。
| 批 | 项 | merge |
|----|----|-------|
| 1 数据一致性 | C1 docgov 吞错与 fencing 读回;C2 Session 竞态与跨项目污染;C4 计划保存事务与 `completed_by`;H10 请求 ctx | `844f757` |
| 2 鉴权 | H1–H4、H8、M8 | `08f4e0b` |
| 3 SSE/事件 | C3 心跳与写超时;H5 任务 SSE 幂等;H6 stale fencing 日志;H7 迁移注释(历史 SQL 不能补 down) | `a2a49a6` |
| 4 前端 | H9 占位符 XSS;未读回滚;Excel 预览上限 | `d73bc79` |
H1 的 legacy user-id=1 兜底只加了日志,删除仍在 backlog(`H1-del`)。H7 的 00001–00009 无 down 不能改已应用文件,只加了注释。
### 已知未修(维持 backlog,本轮不启动)
清单 SSOT:[2026-09-19-audit-remainder.md](../long-term/2026-09-19-audit-remainder.md)。均为 medium/low,不回写 gap-matrix。
| ID | 项 |
|----|----|
| M1 | 缺 `nosniff` / `X-Frame-Options` / `Referrer-Policy`,CSP 未收敛 |
| M2 | 租约 TTL 无上限;Acquire 前未校验编辑权 |
| M3 | 关键词改写意图;硬编码「张工」 |
| M4 | `u_sess_*` 解析失败得到 UserID=0 |
| M5 | `Runtime.Start` 双调用且吞错 |
| M6 | sessions 无硬上限 |
| M7 | 修订三阶段写无事务 |
| M9 | `SEMANTIC_SUMMARY_REPLACE` 只在 dev compose 声明;dev/test 默认模型不一致 |
| M10 | cutover 只允许 `dev` |
| M13 | `deploy/postgres/migrations/` 与 goose 重复 |
| M14 | ResolveDocTask 静默 0 值三权 |
| M15 | PG 投递允许乱序,MemoryBus 有 gap |
| L1 | health 每次两次 DB |
| L2 | SSE marshal 错误被吞 |
| L3 | ReplayPlan digest 不含 DryRun |
| H1-del | 删除 legacy user-id=1 兜底前须盘点调用方 |
| FE | `App.tsx` 巨石、localStorage 无版本、lucide 来源待确认 |
M8(测试 flag 名 `FAV_PUBLISHER_ENABLE` 少一个 D)已在批 2 修复,不在上表。M11/M12 的未读回滚与 Excel 行数上限已在批 4 处理;批 4 报告写明浏览器端到端未覆盖这两条,单测已钉住 XSS 主路径。
### 本轮新观察(不单独立项)
- 文首 schema 数字与实测不一致,见第二节。
- `test` 独有 9 个晋升提交,合并时用 merge,不要 reset。
## 证据
复核时间:2026-09-19。工作区当时在 `docs/audit-remediation-backlog`(树与 `dev@66421b1` 一致),随后本笔记落在 `docs/pre-test-promotion-review`。
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 工作树 | `git status` | clean |
| dev 领先 test | `git rev-list --count test..dev` | 225 |
| test 领先 dev | `git rev-list --count dev..test` | 9(晋升/文档提交) |
| 静态检查 | `go vet ./...` | 零告警,exit 0 |
| 短测 | `go test -short ./...` | 全包 PASS;`internal/server` 14.044s |
| dev health | `curl -s http://127.0.0.1:8080/api/v1/health` | `env=dev` `schema_version=52` `status=ok` |
| test health | `curl -s http://127.0.0.1:8081/api/v1/health` | `env=test` `schema_version=52` `status=ok` |
| main health | `curl -s http://127.0.0.1:8000/api/v1/health` | `env=main` `schema_version=52` `status=ok` |
| 迁移文件 | `deploy/postgres/goose/` | 52 个 SQL,最新 `00052_2026-09-17-document-duty-locked.sql` |
| worktree | `git worktree list` | 主仓 + `dev-rdev-merge` + `feature-initial-load-performance-plan` + `fix-dev-runtime-data-root-guard`(检出 `feature/final-artifact-vault`) |
| 待办标记 | `grep TODO\|FIXME\|XXX` 于 `internal/` `cmd/`(排除 `_test.go`) | 0 |
| 容器 | `docker ps` | dev/test/main app+events+pi-agent 均为 healthy;dev app 已运行约 5 小时,早于批 1–4 合入后的 rebuild(未做) |
## 开放问题
- dev 与 test/main 默认模型不一致(M2.7-highspeed vs M3)是否刻意?深度审计已记,本轮无新证据。
- `deploy/postgres/migrations/` 是否仍有外部工具依赖?无则再归档(M13)。
- H2/H3 越权负例补到哪一层才算晋升门禁:HTTP 集成即可,还是必须 Playwright?
## 建议动作
按顺序,全部另开任务,不在本笔记内执行:
1. 占集成槽位,`./scripts/env-service.sh dev rebuild`,`curl -sf http://127.0.0.1:8080/health`(或 `/api/v1/health`)确认 schema 52 且二进制含批 1–4。
2. `TEST_DATABASE_URL` 下跑治理 PG 集成;`cd web && npm test && npm run build`。
3. 为 H2/H3 补至少一条跨用户/非成员 403 负例。
4. 通过后再把 `dev` merge 入 `test`(保留 test 上 9 个晋升提交),打 rc tag,并顺手更正 `CURRENT.md` 文首的 test schema 表述。
@@ -0,0 +1,47 @@
---
title: "功能启用与文档影响整改方案审阅记录"
created: 2026-09-20
status: done
confidence: high
---
# 功能启用与文档影响整改方案审阅记录
## 审阅范围
- 文档:[2026-09-20-capability-enablement-impact-plan.md](../../remediation/2026-09-20-capability-enablement-impact-plan.md)
- 类型:实施整改方案
- 模式:非交互审阅;在既定目标内直接修正方案和验收条款
- 视角:coherence、feasibility、security、scope guardian、product、design、adversarial
- Compound Pack:无
## 已落地修正
1. 候选必须生成持久 `proposed` 报告;候选和正式提交事件分流,并补失效生命周期和 successor report。
2. 人工关系确认/拒绝进入不可变决定账本;可重建投影不再承担唯一治理事实。
3. 规范 report 与当前主体的 ReportView 分层,按 report revision、可见集 digest 和 narrative protocol 隔离及失效。
4. `no_known_dependencies` 增加项目覆盖 epoch 和可见文档集合屏障。
5. PI 消费者共用 R13 输入信封;纯推理 no-tool 必须由 Runner 强制。
6. 多意图复用已有 intent plan 步骤、claim、receipt 和事件内核,仅补生产 dispatcher 和真实 owner。
7. 实施顺序改为共享基座 + 多意图/摘要/影响追踪三条独立轨道。
8. 显式无类型 ID 只形成候选;补无键、重复键、改名和历史映射身份契约。
9. 数据模型明确为五张表;迁移门覆盖空库、schema 52 和 schema 53。
10. 管理台补先读后改、预览、生效和回退流程;项目追踪页补信息架构。
11. 建议动作和异步分析补完整状态、恢复路径和跨入口一致性。
12. 增加键盘、焦点、动态播报、关系图等价列表和窄屏契约。
13. 多意图增加采用率、确认放弃率和主动拆单率止损门。
14. 索引报告状态与 adapter readiness 分字段,消除 `pending/degraded` 歧义。
## 待用户审核决策
### 1. 关系候选治理职责
方案推荐项目本地 `trace_reviewer` 动作能力,绑定既有编制/审核职责,由项目创建者在项目成员内指派;跨文档候选由两端各一名符合条件者确认,全局管理员不自动取得项目或文档权限。未批准前相关端点保持关闭。
### 2. 派生追踪数据留存
T2 开始前,需要确定条目修订、模型候选、确认/拒绝决定的留存类别,以及源文档删除或依法清除时如何传播。D7 未签前不执行物理删除,也不允许用“不可变历史”绕过后续合规决定。
## 审阅结论
方案已具备实施拆分、数据模型、授权边界、状态机、灰度、回退和验收合同。上述两项治理决策不会阻塞 Foundation 0、lineage API 鉴权、摘要持久化和 T1 的非 PI 工作;它们会阻塞关系候选确认端点和 T2/T3 正式放量。
@@ -0,0 +1,165 @@
---
title: "功能启用现状与项目文档修改影响分析调研"
created: 2026-09-20
status: done
confidence: high_for_source_and_runtime_configuration
---
# 功能启用现状与项目文档修改影响分析调研
## 1. 结论
用户观察基本成立,但“已实现未启用”包含三种不同情况:已有可运行能力被关闭、只有组件或测试链路而未接入生产入口、只有设置或适配器占位。不能统一通过打开开关解决。
建议先补真实执行链路、摘要持久化和工具权限约束,再分阶段启用。文档影响分析应建立**项目级、版本化的需求与关联索引**,工作流作为其中的归属和筛选维度。复用现有文档账本、变更报告和可靠事件,以增量抽取和关联查询代替每次全项目全文处理。
本轮交付调研与[整改方案](../../remediation/2026-09-20-capability-enablement-impact-plan.md)。未修改业务代码、未启用开关、未重启容器、未操作真实会话。下文的源码风险是静态发现,不冒充已复现的事故;历史测试不冒充本轮验收。
## 2. 调研范围与证据等级
- 基线:本地 `dev@8fdcd98`;开始时工作区干净,`git pull --ff-only` 返回 Already up to date。调研分支 `feature/capability-enablement-impact-plan`。
- 核查:`internal/intent`、`internal/app/intentflow`、`chat`、`ctxmgr`、`docrevision`、`projectworkflow`、`projectcontext`、`sysadmin`、PI Runner、相关前端、三环境 Compose、Goose 迁移。
- 实时只读证据:三环境 app 容器白名单环境变量、image ID、`/health`、`/ready`;各环境 PostgreSQL `BEGIN READ ONLY` 元数据和聚合计数。未输出密码、业务正文或用户数据。
- 历史证据:W2/W3/W4 测试报告、Wave5 封存决策、FEATURE-MATRIX。它们说明当时测了什么,不能证明当前聊天入口已打通。
- 外部研究:NASA 需求追踪方法、PostgreSQL 16 递归查询文档,仅用于设计依据,不代表本项目满足任何外部合规认证。
- 本轮没有运行 Go/前端测试或真实 PI/浏览器验收;没有证明运行镜像与源码逐字一致。运行开关是容器实际配置,接线结论基于当前检出源码。
## 3. 运行环境核查
2026-09-20 本轮读取结果:
| 项 | dev | test | main |
|---|---|---|---|
| health / ready | ok / ok | ok / ok | ok / ok |
| schema | 53 | 53 | 52 |
| AGENT_BACKEND | pi-agent | pi-agent | pi-agent |
| MULTI_INTENT_ENABLED | true | true | true |
| MULTI_INTENT_PLAN_TIER | legacy | legacy | legacy |
| U9 / U10 / U11 / U12 | 全 false | 全 false | 全 false |
| INTENT_V2_SHADOW / DECISION / TIER | false / false / none | 同左 | 同左 |
| SEMANTIC_SUMMARY_SHADOW | false | false | false |
| SEMANTIC_SUMMARY_REPLACE | 未注入;源码默认 false | 同左 | 同左 |
| PI_CHANGE_REPORT_NARRATIVE | false | false | false |
| FAV_PUBLISHER_ENABLED / DEGRADED_READ | false / false | false / false | false / false |
| document_lineage 行数 | 10 | 0 | 10 |
| document_change_reports 行数 | 487 | 0 | 0 |
| intent_plans 行数 | 2 | 0 | 0 |
| public.chat_summaries | 不存在 | 不存在 | 不存在 |
| public.chat_daily_digests | 存在 | 存在 | 存在 |
行数包含既有测试/种子可能性,不能据此推断活跃用户、覆盖率或业务采用率。
本轮 app image ID:dev `sha256:de2c8802eb544cddef157d23d8731cd66b04b85bc6b120a070e08b9b234428df`;test `sha256:f7ad7d2427bbca4d0f6fb3bc9128aa86de546e7d7e3f4f7ebedbbe072776d66d`;main `sha256:0ffe0550461c2b75c783292994d75e71083f7c20c7e4a9a52ad9e5959580c2eb`。这是本机镜像标识,不是远端 registry 发布凭据。
数据库核查先尝试 count(chat_summaries) 得到 relation does not exist;随后以 `to_regclass('public.chat_summaries')` 在三库重新确认。`internal/bizdev/service.go:115` 用业务 pool 构建 ContextManager;仓库 SQL 搜索也未找到该表的建表迁移。`/ready` 正常不能证明这项摘要持久化可用。
## 4. 功能分类与启用判断
| 能力 | 当前实际完成边界 | 判断与建议 |
|---|---|---|
| 基础多意图识别 | `intent/flags.go:35` 默认开;旧协调器执行有限只读组合 | 已启用,不应标为“全部关闭” |
| 新多意图持久计划 | 表、策略、卡片、决定接口存在;生产查询 owner 是 Fake,确认后未发现 worker 调度 | 必须先整改,不能直接升 auto_read/confirm |
| U9 LLM 分段 | PI proposer 组件已注入;生产未调用 ActiveSegmentProposer | 需接真实聊天链路,不是单纯 flag 问题 |
| U10 变更 / U11 治理 / U12 运行控制 | flag 开后注册 DryRunAdapter | 真实动作仍需实现;full 不是全功能开关 |
| 意图 V2 决策 | 有独立灰度 flags,运行环境均 off | 与多意图计划分开验收,避免同时切两套路由无法归因 |
| 语义摘要 shadow | 有 PI 实现,成功后仍服务确定性摘要 | 可作为第一阶段观测能力,但先补工具限制、持久化和异步隔离 |
| 语义摘要 REPLACE | 明确封存未接线;true 也不替换 | 新实施项;需完整滚动、授权、质量、失效和回退设计 |
| PI 变更报告叙事 | 有开关/Fetcher/摘要合并;输入仅统计数 | 接线存在但表达能力不足,先补具体差异与证据 |
| 文档修改影响 | 账本、报告、面板、lineage 已有 | 依赖覆盖窄;应扩展项目追踪索引 |
| 系统设置六项 | 可写白名单,但无业务消费方 | 管理台须显示“尚未生效”,逐项接线后开放 |
| 编制人兼任 | 有独立策略消费方 | 不随本次智能功能一并全局开启;保留项目逐文档配置和冻结职责 |
| FAV | 当前仅有限 shadow/骨架,生产消费者未放量 | 不纳入首批;维持独立观察窗和关闭降级读 |
| 软件项目自举受控执行 | 部分数据库表/allowlist/执行器仍 deferred | 不因“已有表”认定可用,独立完善 |
| D7 删除/留存治理 | 历史资料仍待合规决策 | 不与智能功能启用混合实施 |
### 4.1 多意图的具体缺口
1. `internal/app/app.go:247-249` 将 `QueryGuard{Inner: NewFakeActionOwner()}` 注入生产。`intentflow/owner.go` 的 Fake 返回 receipt,不查询真实业务。
2. `internal/server/intent_plan_handlers.go:68-82` 决定接口调用 DecidePlan 后返回。非测试 AdvanceEligible 调用只发现 `intentflow/turn.go:98` 自动只读路径;缺少确认后的可靠执行调度。
3. `internal/chat/session.go:397-406` 对新计划只清除旧 IntentPlan,忽略 planErr;后面仍走 Coordinator.Process。存在双路径处理及确认前副作用风险,须用真实聊天负例验证;本轮未制造真实副作用证明该风险。
4. `internal/app/plan_owner.go:97-122` 的 live starter 将 task.run 固定到 intake;`turn.go:55-61` 只持久化 key/digest/summary,没有完整类型化参数和目标版本,不能可靠表达“修改 A 后生成 B”。
5. U9 注入位在 `app.go:141`,生产 HandleTurn 仍直接使用规则 Recognize;`ActiveSegmentProposer` 调用只见测试。
6. `intentflow/expansion.go:301-313` 为 U10–U12 注册 dry-run;返回 `dryrun:`/`validated_only:`。新领域写不是“开后就可执行”。
7. 三个 Compose 已声明 PLAN_TIER。旧文档中“没有传进容器”的结论已过时,本轮不沿用。
### 4.2 语义摘要不仅缺一个开关
- `ctxmgr/summary_flags.go:10-20`、`semantic_summary.go` 明确 REPLACE 未接线;现有测试故意令 Replace=true 并验证叙事不变。
- `ctxmgr/summarizer.go:64-115` 读写 chat_summaries;数据库缺表时写错误被忽略、返回成功并存内存。因此重启持久化是前置整改,不能用内存测试当通过。
- Source、Shadow、FreshnessNote 不在现有保存 SQL 中,即使补表也需设计完整 provenance 持久化。
- `MinimizeAuthorizedMessages` 仅取最后 40 条、每条约 240 字符;shadow 输入没有旧摘要。直接把它赋给 Narrative 会丢更早的上下文;不能宣称覆盖全部 CoveredCount。
- `chat/session.go:177-212` 同步计算滚动摘要,并将当前 early 全量与旧摘要再合并;缺稳定消息水位去重契约,有覆盖计数/重复压缩风险。
- `app/chatflow/chatlog.go:324` 存在授权包装,但 Session 直接调用 ContextManager。旧摘要复用仅按 session_id;撤权、阶段可见范围变化后是否仍安全,必须补真实链路复核与可见集绑定。
- shadow 与服务请求同步执行,PI 默认 timeout 3 分钟(`app/semantic_summarizer.go:18`),Session 外层约 30 秒。开启可能增加等待;应移至可观察的后台任务并立即提供确定性结果。
- `PiSemanticSummarizer` 只检查输出非空,未验证返回 digest、证据引用和长度等完整质量契约。
### 4.3 “no-tool”目前不是运行时强约束
`app/semantic_summarizer.go:64-69` 与 `app/pi_narrative.go:60-67` 通过 Instructions 声明 zero tool,但 `deploy/pi-agent/runner.mjs:151-154` 固定使用 `read,write,edit,tavily_search,web_search` 和 approve。本轮没有验证攻击利用;源码足以证明提示词声明不等价于禁用工具。
建议增加专用纯推理请求 profile:材料直接作为输入,结构化结果通过协议返回,由服务端保存;Runner 不加载搜索扩展、不提供文件/网络工具。若底层 CLI 不支持该 profile,能力应显示 unavailable 并回退,而不是继续标记 no-tool。摘要、叙事和 U9 一并覆盖。
### 4.4 管理台的显示不能当作功能已生效
`internal/sysadmin/features.go` 返回 value/source/requiresRestart,没有 adapter readiness 或 rollout 覆盖信息。`settings.go:68-87` 明示六项无消费方:维护公告、只读模式、默认会话职责、任务默认自动修复、KB 默认返回数、阶段推进提醒。
因此需要拆分“配置值”“实际生效值”“实现成熟度”“失败/阻断原因”。尤其只读模式必须服务端阻断写操作,不能只让前端按钮变灰;默认会话职责不能升级授权。维护公告等低风险项可单独接线,不能把六项保存成功当作六项功能完成。
## 5. 修改影响分析已有什么、缺什么
| 现有资产 | 证据 | 复用方式与限制 |
|---|---|---|
| 快照、版本、块映射、事件、报告 | `docrevision/types.go:96-168`;迁移 00028 | 唯一文档事实来源;索引不另存可独立修改的正文 |
| 变更报告面板 | `web/src/components/doc/ChangeReportPanel.tsx:94-165` | 已有摘要/影响/推荐动作;增加覆盖状态、文档名、证据定位、聊天卡复用 |
| 下游 lineage | `bizdev/service.go:1169-1193` | 主要为 test_manager 引用 system_reqs;下游 version 写死 1,不能扩面沿用 |
| ImpactResolver | `bizdev/service.go:132-156` | 一跳查下游;查询错误和无关联都返回 nil,必须区分未知与无影响 |
| 风险规则 | `docrevision/impact.go:18`、`risk.go:49-54` | 任意 lineage 均变 stale_candidate 并升 critical;扩大关系前先分清存在依赖和实际受影响 |
| 可靠事件 | `app/docflow/commands.go:285-312` | 复用提交后事件、投影和重放;不新增第二套消息基础设施 |
| 需求/用例 JSON | `squad/quality_gate_v2.go:34-101` | 已校验 requirements.json/test_cases.json;是工作区产物,不是需求实体数据库 |
| 上下文快照 | `projectcontext/service.go:167-184,216-242` | 来源用 DocKey、版本用 Stage,且 approved 文档全选;需改为真实快照/版本/片段 |
| 材料装配 | `projectcontext/service.go:126-145` | 截到 12 项、正文约 4000 字节;减少输入但不能证明召回完整 |
| 块业务键 | `docrevision/blockmap.go:13` | 仅覆盖 REQ-*;需要兼容 UR/RS 等并维护稳定身份 |
另发现 lineage GET 的权限缺口:`server/project_handlers.go:280-322` 只校验 URL 项目,然后接受任意 query doc_id 查询;应核验文档属于项目、逐文档可见性、关联端点可见性。当前为静态确定的缺少检查,未对真实项目做越权请求。
PI 叙事并不能补这些关系:`app/pi_narrative.go:40-48` 只传 SHA、风险与 hunk/impact 数量,没有具体 Hunks/Impacts。已有 `BuildNarrativePromptInput` 可以提供差异,但未发现生产调用。仅开启 flag 更可能得到“修改了若干处、存在若干影响”这种泛化说明。
还需统一报告可信边界:新 narrative 路径以服务端 impacts 为准;旧 `ValidateChangeReportJSON` 仍通过 mergeImpacts 合并模型提供的关联。新增设计应将模型推测单独列为候选,经文档定位、权限与证据校验后才进入确定关联。
## 6. 是否建立需求清单等表
**需要建立;建议项目级统一条目索引,而不是每个工作流各建一套孤立需求表。** 同一需求可以贯穿需求、设计、风险、验证多个工作流;逐工作流复制会产生重复编号、版本不一致和跨工作流断链。
建议首期三类核心表:稳定条目身份、不可变条目修订、版本化关系;再保存索引构建状态。需求清单、风险清单、接口清单、测试覆盖表是同一索引的不同视图。已有 document_lineage 保留“实际消费了哪个文档版本”的事实,条目关系解释“为什么影响哪一处”。
| 路线 | 优点 | 局限 | 建议 |
|---|---|---|---|
| 每次全文处理 | 无建模启动成本 | 输入随项目增长、重复成本高、结果不稳定 | 仅初始化/明确修复,不作常规路径 |
| 仅摘要/向量检索 | 查找相似内容方便 | 相似不等于依赖,不能可靠证明未受影响 | 用于补充候选 |
| 仅文档级 lineage | 可快速覆盖实际引用 | 无条目粒度,易误报全篇影响 | 第一阶段复用并修版本 |
| PostgreSQL 条目+关系+片段 | 版本、事务、双向查询与审计可落在现有栈 | 需持续维护抽取/关系质量 | 推荐主路线 |
| 独立图数据库/完整 GraphRAG | 可支持更复杂关系探索 | 新基础设施、一致性/授权/运维成本 | 当前无规模证据,不先引入 |
NASA 需求管理资料强调双向追踪及需求变更影响管理,可作为需求—设计—验证关联建模的参考。[NASA Requirements Management](https://www.nasa.gov/reference/6-2-requirements-management/)
PostgreSQL 16 支持递归 CTE 和循环检测,现有数据库可承担首期受限关系遍历。这支持“先用现有 PG”的设计选择,但不能替代本项目性能基准。[PostgreSQL 16 WITH Queries](https://www.postgresql.org/docs/16/queries-with.html)
## 7. 预期用户体验
示例仅说明设计,不是本轮真实项目结果:用户把某需求的响应时间从 2 秒改为 1 秒,提交成功后,助手返回:
> 已修改《系统需求》REQ-017 的响应时间:2 秒 → 1 秒。直接相关的《性能设计》§3.2 和测试用例 TC-017 需要复核;《验收方案》通过测试追踪关系可能受影响。建议先确认实现预算,再更新测试阈值,最后复核验收标准。当前索引覆盖已提交版本,另有一个关联尚待核实。
每条结论可点开证据、旧/新版本和相关片段。明确区分“确定影响”“可能影响”“尚未覆盖”。不因一句影响说明自动修改其他文档;用户选择建议后,仍走目标文档权限、租约、版本校验和审批。
消息、文档面板和项目清单共用一个 report_id。刷新、重开、重启后仍可查阅,并显示后续处理进度。候选尚未提交时只能说“拟修改的预估影响”,不能说已经修改完成。
## 8. 推荐推进顺序与研究局限
1. 修复阻断:真实多意图 owner/确认调度/路由隔离、摘要表和持久化、纯推理工具隔离、lineage 权限和错误状态。
2. 快速形成用户价值:所有提交路径都产生基础影响报告,聊天主动展示;补完整差异输入后灰度启用 PI 叙事。
3. 项目需求索引:先覆盖结构化需求和用例,再扩展文档章节、风险和接口;精确关系先行,模型候选后置。
4. 多意图按 shadow → auto_read → confirm 扩面;U9/领域动作逐个接线、验收。
5. 语义摘要按 shadow → 质量评估 → 项目级替换推进,保留硬事实和确定性回退。
尚未实测:运行镜像内上述源码接线、真实浏览器旗标开启后的端到端行为、PI工具调用实际执行情况、索引规模/性能、需求关系准确率。报告中的源码缺口已足以阻止盲目放量;验收方案负责关闭这些未验证项。详见[实施方案](../../remediation/2026-09-20-capability-enablement-impact-plan.md)。
@@ -0,0 +1,53 @@
---
title: "首次加载 U2:字体自托管与静态资源交付"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Cursor
branch: feature/initial-load-perf-u2
worktree: "-"
mutex: web + static-delivery
---
# 首次加载 U2:字体自托管与静态资源交付
## 目标
登录页不再依赖 Google Fonts 阻塞 CSS;8080/8081 静态资源支持 gzip/br 协商与分层缓存;缺失 `/assets`/`/fonts` 返回 404 而非 HTML。
## 范围
- 自托管 Inter / JetBrains Mono(latin + latin-ext 可变 WOFF2)
- 构建期预压缩 `.br` / `.gz`
- Go `serveSPA` 压缩协商、Cache-Control、Vary、assets 404
- 单元测试与 rebuild 后 curl/浏览器验收
## 非目标
- U1 完整 Playwright 性能套件
- U3 拆包懒加载 / katex 入口 CSS
- U4–U6 初始化扇出、认证、SQL
- U7 完整重启归因(本轮仅借 rebuild 采集起点证据)
## 步骤
1. [x] 诊断/方案文档落盘并合入 `dev`
2. [x] 自托管字体 + 移除外链
3. [x] 预压缩脚本接入 build
4. [x] Go 静态交付修复
5. [x] 测试与 rebuild 验收
6. [x] 测试报告与文档同步
## 验收标准
- [x] 登录页无 `fonts.googleapis.com` / `fonts.gstatic.com` 请求
- [x] 主 JS 响应带 `Content-Encoding: br` 或 `gzip`,体积显著下降
- [x] `/assets/missing.js` → 404 且非 HTML
- [x] HTML `Cache-Control: no-cache`;哈希资源 `immutable`
- [x] SSE / API 缓存行为未回归
## 相关链接
- 方案: [../../remediation/2026-09-17-initial-load-performance-plan.md](../../remediation/2026-09-17-initial-load-performance-plan.md)
- 审计: [../../audit/2026-09-17-initial-load-performance-audit.md](../../audit/2026-09-17-initial-load-performance-audit.md)
- Test report: [../../test-reports/2026-09-17-initial-load-perf-u2-test-report.md](../../test-reports/2026-09-17-initial-load-perf-u2-test-report.md)
@@ -0,0 +1,58 @@
---
title: "系统管理台(System Admin Console)一期"
status: done
created: 2026-09-17
updated: 2026-09-17
owner: Kimi
branch: feature/system-admin-console
worktree: "-"
mutex: web + sysadmin
---
# 系统管理台(System Admin Console)一期
## 目标
为管理员提供独立的系统级管理界面(全屏视图,`workbench | admin` 顶层切换),覆盖总览状态、知识库、功能与特性开关、角色权限、工作流、用户审批、文档治理;吸收下线 AdminSettingsModal;系统设置只读为主 + SettingSpec 白名单少量可写。
## 范围
- 后端:新包 `internal/sysadmin`(薄聚合层,ports/settings/overview);迁移 `deploy/postgres/goose/00049`(`system_settings` 表);路由 `/api/v1/admin/system/{overview,kb,features,settings}`;`internal/server/admin_system_handlers.go`;`internal/app/app.go` 装配。
- 前端:`web/src/api/systemAdmin.ts` + `web/src/types/systemAdmin.ts`;`web/src/components/admin/console/AdminConsoleView.tsx` + `sections/`;`App.tsx` 顶层视图切换;LeftRail 入口语义改为进入管理台;吸收 `AdminSettingsModal` 六 tab 并删除旧模态。
## 非目标
- 不做全量 DB feature-flag 层(env 开关保留,标注「需重启」)。
- 不改项目级设置(`projectinstance.ProjectSettings` 与项目设置模态保持原样)。
- 不引入 react-router / 新前端依赖;不改 `tokens.css` 之外的全局样式。
- 不做 KB 重建/索引管理等运维动作(一期只读)。
## 步骤
1. [x] 后端 sysadmin 包 + goose 00049(commit `f1404d5`)
2. [x] 后端路由/handler/装配 + 单测(commit `f1404d5`)
3. [x] 前端 API 模块与类型(commit `0eaca61`)
4. [x] AdminConsoleView 骨架与 8 个分组 sections(commit `0eaca61`)
5. [x] 吸收 AdminSettingsModal 并下线(commit `0eaca61`)
6. [x] go vet / go test -short / web npm test + build(全绿)
7. [x] 占集成槽位:dev rebuild + /health + admin overview 冒烟(merge commit `dc7c31e`;schema 48→49;PASS)
## 验收标准
- [x] admin 从 LeftRail 入口进入全屏管理台,八个分组可渲染(UI 人工抽检由 Playwright spec 兜底,见报告后续项 1)
- [x] 非管理员无入口且 `/api/v1/admin/system/*` 返回 403(server 单测真实 mux + 内存 IAM)
- [x] 白名单可写设置 PUT 后 GET 生效;env 项只读并标注需重启(写读回环 PASS)
- [x] `go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿
- [x] dev 容器冒烟 PASS
## 相关链接
- 方案:会话计划(全屏独立视图 / 吸收旧模态 / 只读+少量可写,用户已批准)
- Test report: [2026-09-17-system-admin-console-test-report.md](../../test-reports/2026-09-17-system-admin-console-test-report.md)
- FEATURE-MATRIX 行:系统管理台
## 证据 / 备注
- commit:`f1404d5`(后端)、`0eaca61`(前端)、`dc7c31e`(merge dev)
- 冒烟:health `schema_version=49`;overview/kb/features(22)/settings(6) 200;PUT 写读回环 PASS;匿名 401、未知 key 400、非 admin 403(单测)
- 遗留(二期):Playwright 实跑、`system:*` 细粒度权限、设置审计日志、KB 运维动作、白名单项接消费方、403 自动退回
@@ -0,0 +1,58 @@
---
title: "系统使用说明书(含真实截图,md/word/pdf/html 四格式)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Kimi
branch: feature/user-manual
worktree: .worktrees/feature-user-manual
mutex: docs
---
# 系统使用说明书(含真实截图,md/word/pdf/html 四格式)
## 目标
产出覆盖「从 0 进入系统 → 登录/注册 → 管理员角色权限配置 → 日常使用 → 审批全流程」的终端用户说明书,配 dev 环境真实操作截图(含真实 PI 对话),交付 Markdown / HTML / PDF / Word 四种格式于 `docs/user-manual/`。
## 范围
- dev 环境(127.0.0.1:8080)Playwright 实操截图约 30 张(登录、工作台、立项、对话、文档、审批链、管理台 8 分组)
- `docs/user-manual/manual.md` 十章中文说明书(内容以代码为准)
- `docs/user-manual/scripts/`(截图与格式生成脚本,可重跑)
- `docs/user-manual/dist/`(html/pdf/docx 产物)
## 非目标
- 不合入 dev、不 push(用户未要求)
- 不改动任何产品代码
- 不覆盖产品手册范围外的工程内部工具(`engineering-dashboard` 当时为工程内部,其后已移出本仓库)
## 步骤
1. [x] 分支 + 登记
2. [x] 环境预检(健康、登录凭证、中文字体、chromium)
3. [x] 截图脚本 `capture-screenshots.mjs` 并采集
4. [x] 真实 PI 对话截图
5. [x] 三责审批链 + 阶段门禁截图(zhanggong/lizhuguan/wangzong)
6. [x] 撰写 manual.md
7. [x] build-formats.mjs 生成 html/pdf/docx(pandoc 缺失时 .doc 兜底)
8. [x] 校验(图片引用、PDF 渲染抽查、docx 媒体嵌入)
9. [x] 提交 + 更新 CURRENT
## 验收标准
- [x] 四种格式文件齐备且可打开
- [x] manual.md 图片引用全部存在,无孤图
- [x] PDF 中文无乱码、图片正常嵌入
- [x] 说明书章节覆盖:进入系统/登录/注册/管理员配置角色权限/项目使用/对话/文档/审批/FAQ
## 相关链接
- Checklist: -
- Handoff: -
- Test report: -
## 证据 / 备注
- 演示账号(dev 种子,密码 123456):zhanggong / lizhuguan / wangzong / guest;管理员 admin(密码取 configs/.env.dev)
@@ -0,0 +1,55 @@
---
title: "Wave 0:P0 确认 bug 修复(SSE/缓存/run-stream)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor
branch: fix/wave0-p0-sse-chat-cache-bugs
worktree: "-"
mutex: chat + web
---
# Wave 0:P0 确认 bug 修复(SSE/缓存/run-stream)
## 目标
修复体检确认的 P0 bug:SSE 120s 断流(B-1/B-2)、run/stream 解析与时序(B-3/B-4)、前端会话窗口缓存 key 不一致(B-5)、IndexedDB 恢复覆盖(B-6)。
## 范围
- `internal/server/sse.go`:chat/run stream 心跳 + WriteDeadline;Decode 400;CreateAndStart/Subscribe 前置 Flush
- `web/src/hooks/useChatWindow.ts` + `web/src/data/storage.ts`:缓存 key / LRU 一致
- `web/src/App.tsx` + `web/src/data/fileStore.ts`:恢复合并
- 对应单测与测试报告
## 非目标
- E-1(main ENV 不一致)及 Wave 1–7 其余项
- FAV / MULTI_INTENT_PLAN_TIER / SEMANTIC_SUMMARY_REPLACE 放量
## 步骤
1. [x] 从 dev 开 `fix/wave0-p0-sse-chat-cache-bugs`,CURRENT 认领
2. [x] B-1/B-2 心跳与 deadline
3. [x] B-3/B-4 run/stream
4. [x] B-5 缓存 key
5. [x] B-6 恢复合并
6. [x] 单测 + 全量回归 + 合入 dev 冒烟
## 验收标准
- [x] `go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿
- [x] 畸形 body → 400;Flush 前失败非 200 SSE
- [x] 缓存 key / LRU 单测 PASS;恢复合并不丢新增 deliverable
- [x] dev rebuild + health/ready;真 PI 聊天心跳证据(见测试报告)
## 相关链接
- Audit: [../../audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- Remediation: [../../remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Test report: [../../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md](../../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md)
## 证据 / 备注
- Commits:`64efaa3` docs · `54244ed` server · `2620d80` web;合入 `dev` merge `810fb96`
- Assets:`.doc/test-reports/assets/2026-09-18-wave0-p0-bug-fixes/chat-stream-long.sse.txt`
@@ -0,0 +1,53 @@
---
title: "Wave 1:main 环境 ENV/schema 修正(E-1/E-2/E-5)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor
branch: fix/wave1-main-env-fix
worktree: "-"
mutex: infra
---
# Wave 1:main 环境 ENV/schema 修正(E-1/E-2/E-5)
## 目标
统一 main 环境 app/events 的 `ENV=main` 语义,用 compose 依赖强制 events 先迁移再启 app,并关闭 `Env==""` 视同 dev 的导入门禁漏洞。
## 范围
- `docker-compose.main.yml`:app `ENV: main`;`depends_on.events` healthy;events 补生产校验所需口令
- `configs/.env.main`(本机)/ `.env.main.example`:`ENV=main`
- `internal/server/chat_window_api.go`:去掉空 Env 视同 dev
- 回归测试 + 真实 main rebuild 验证
## 非目标
- Wave 2+;不改 `event_consumer_modes` 的 mode 值;不触碰 FAV / MULTI_INTENT / SEMANTIC_SUMMARY_REPLACE
## 步骤
1. [x] 从本地 `dev` 开分支并 CURRENT 认领
2. [x] E-1 ENV 对齐
3. [x] E-2 depends_on events
4. [x] E-5 空 Env fail-closed
5. [x] 单测 + 合入 + main rebuild 冒烟
## 验收标准
- [x] app/events health 均报 `env=main`
- [x] main schema 已升(health `schema_version=52`,goose `version_id=52`)
- [x] `event_consumer_modes` 中 main 四行仍为 `off`
- [x] 导入端点空 Env → 403;compose ENV 对齐单测 PASS
## 相关链接
- Audit: [../../audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- Remediation: [../../remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Test report: [../../test-reports/2026-09-18-wave1-main-env-fix-test-report.md](../../test-reports/2026-09-18-wave1-main-env-fix-test-report.md)
## 证据 / 备注
- 合入本地 `dev`:`merge: fix/wave1-main-env-fix` + events secrets unblock
- Assets:`.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/`
@@ -0,0 +1,57 @@
---
title: "Wave 2:配置与灰度入口对齐(E-3/E-4/E-6/E-7/E-9)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: fix/wave2-config-flag-align
worktree: "-"
mutex: infra
---
# Wave 2:配置与灰度入口对齐
## 目标
三环境 compose 显式声明封存 flag(值保持 legacy/false);移除死 `CURSOR_RUNNER`;main 显式 `SEED_DEMO_USERS=false`;`INTENT_V2_DECISION_TIER` 非法值 fail-closed 到 `none`;E-9 仅记录评估结论。
## 范围
- E-3 / A-4:三环境补 `MULTI_INTENT_PLAN_TIER` + U9–U12 + SHADOW/NARRATIVE 声明
- E-4:删除 `CURSOR_RUNNER_URL` 与 `cursor-agent` 占位服务
- E-6:main `SEED_DEMO_USERS: "false"`
- E-7:`parseV2DecisionTier` default → `none`
- E-9:评估记录,不改 initdb
## 非目标
- 不升 `MULTI_INTENT_PLAN_TIER`;不接线 `SEMANTIC_SUMMARY_REPLACE`
- 不改 FAV modes;不改 E-9 initdb 挂载
- Wave 3+ 范围项
## 步骤
1. [x] Sonnet 5 产出实施计划(默认决策:删 cursor-agent;不补 REPLACE;E-9 不改代码)
2. [x] E-7 代码 + 单测
3. [x] E-3 / E-4 / E-6 compose
4. [x] compose flag 声明回归测试
5. [x] go vet/test;三环境 rebuild + env 抽检 + 冒烟
6. [x] 合入本地 dev;文档闭环
## 验收标准
- [x] 三环境 `docker compose config` 可见目标 flag;`CURSOR_RUNNER` 零匹配
- [x] 容器内 env 抽检 PASS;health/ready PASS
- [x] `go test -short ./...` 全绿
- [x] test-report 归档;remediation Wave 2 done
## 相关链接
- Remediation: [.doc/remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Audit: [.doc/audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- Test report: [.doc/test-reports/2026-09-18-wave2-config-flag-align-test-report.md](../../test-reports/2026-09-18-wave2-config-flag-align-test-report.md)
## 证据 / 备注
计划作者:[Wave 2 Sonnet 计划](5b8c8c73-c3e4-4947-b0c4-91822859ff4a)
commits:`07fc0ec` `e0aabec` `55a539c` `8d97dd6` + docs closeout
@@ -0,0 +1,46 @@
---
title: "Wave 3:测试债与盲区(S-1/S-2/S-4/S-5)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: fix/wave3-test-debt-blindspots
worktree: "-"
mutex: test-debt
---
# Wave 3:测试债与盲区
## 目标
关闭 `TestReconcile_LegacyRepair_PG` 工程测试债;清理永久跳过死代码;统一 E2E 脚本入口;推广 409/结构化错误信封复用。
## 范围
- S-1 / S-2 / S-4 / S-5(按 Sonnet 计划默认决策)
## 非目标
- 不升 MULTI_INTENT_PLAN_TIER;不接线 REPLACE;不改 FAV;项目 143 只读
- 不改后端 httpx 信封整体迁移;不统一 INTENT_DUAL_TAB
## 步骤
1. [x] Sonnet 5 计划
2. [x] S-1 隔离 PG 5436 跑一次并归档
3. [x] S-2 删死跳过 + plan_owner 说明
4. [x] S-4 e2e scripts + 退役 document-revision.spec
5. [x] S-5 信封复用 + 单测
6. [x] 文档闭环 + 合入本地 dev
## 验收标准
- [x] reconcile PG PASS 证据
- [x] playwright --list = 29 tests / 8 files
- [x] npm test / go test -short 全绿
- [x] gap-matrix 测试债关闭;remediation Wave 3 done
## 相关链接
- Plan agent: [Wave 3 Sonnet 计划](51987049-b338-41a7-84f4-2c97e3655d85)
- Test report: [.doc/test-reports/2026-09-18-wave3-test-debt-blindspots-test-report.md](../../test-reports/2026-09-18-wave3-test-debt-blindspots-test-report.md)
@@ -0,0 +1,49 @@
---
title: "Wave 4:隐患加固(R-1~R-8)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: fix/wave4-hardening-r1-r8
worktree: "-"
mutex: hardening
---
# Wave 4:隐患加固(R-1~R-8)
## 目标
按 Wave 4 Sonnet 计划默认决策关闭体检高风险隐患 R-1~R-8。
## 范围
- R-1~R-8 全项(含 D-1 扩大范围:upsert + COALESCE)
## 非目标
- D-4/D-5;不升 tier;不接线 REPLACE;不改 FAV;项目 143 只读;不 push
## 步骤
1. [x] R-1c/R-1a/R-1b + Memory/PG 负例
2. [x] R-2 rows.Err()
3. [x] R-3 RWMutex / R-4 memTurns / R-5 hydrate / R-6 Shutdown
4. [x] R-7/R-8 前端 + 单测
5. [x] 全量验收 + test-report + 合入本地 `.worktrees/dev-rdev-merge` dev
## 验收标准
- [x] R-1~R-8 按计划验收项 PASS
- [x] `go vet` / `go build` / `go test -short ./...` / `npm test` / `npm run build`
- [x] 相关 `-race` 绿
- [x] 文档闭环
## 相关链接
- Remediation: [.doc/remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Test report: [.doc/test-reports/2026-09-18-wave4-hardening-r1-r8-test-report.md](../../test-reports/2026-09-18-wave4-hardening-r1-r8-test-report.md)
- Assets: [.doc/test-reports/assets/2026-09-18-wave4-hardening-r1-r8/](../../test-reports/assets/2026-09-18-wave4-hardening-r1-r8/)
## 证据 / 备注
基线 tip:`32932e4`。合入本地 `dev` 见 merge commit。
@@ -0,0 +1,98 @@
---
title: "Wave 5:死代码与机制收口(X-1~X-5)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: fix/wave5-deadcode-decisions
worktree: "-"
mutex: deadcode-cleanup
---
# Wave 5:死代码与机制收口(X-1~X-5)
## 目标
按系统体检整改方案 Wave 5,对 X-1~X-5 逐项决策并收口:删除真死 flag/组件、封存 REPLACE、标记 00048 deferred、保留 system_settings 二期键。
## 范围
- X-1~X-5 全项(含级联删除 `patchNotification`)
## 非目标
- X-6(`useTaskRunStream` 伪 ref);不接线 REPLACE;不升 MULTI_INTENT_PLAN_TIER;不改 FAV;项目 143 只读;不改 goose 00048/00049 schema;不 push
## 步骤
1. [x] 决策记录落盘(本文件「决策记录」段)
2. [x] X-1 删除 `SEMANTIC_FALLBACK_ENABLED` + 回归测试
3. [x] X-2 封存注释回链
4. [x] X-3 00048 deferred 注释 + long-term
5. [x] X-4 system_settings 6 键注释
6. [x] X-5 删除死组件/死 API
7. [x] 全量验收 + test-report + 合入本地 `.worktrees/dev-rdev-merge` `dev`
## 验收标准
- [x] X-1~X-5 每项有决策记录(本文件)
- [x] `go vet ./...` / `go test -short ./...` / `cd web && npm test && npm run build`
- [x] remediation Wave 5 行改 done;勾选「X-1~X-5 每项有决策记录」
- [x] 文档闭环 + merge `--no-ff`
## 相关链接
- Remediation: [.doc/remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Audit: [.doc/audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- Test report: [.doc/test-reports/2026-09-18-wave5-deadcode-decisions-test-report.md](../../test-reports/2026-09-18-wave5-deadcode-decisions-test-report.md)
- Assets: [.doc/test-reports/assets/2026-09-18-wave5-deadcode-decisions/](../../test-reports/assets/2026-09-18-wave5-deadcode-decisions/)
## 决策记录
### X-1:`SEMANTIC_FALLBACK_ENABLED` — 删除
- **现状证据**:字段仅在 `internal/intent/flags.go` 解析、`internal/app/app.go` 注入 sysadmin 视图、`internal/sysadmin/features.go` 目录展示;全仓无业务消费方。三环境 compose + `.env.example` 均声明该死变量。
- **决策**:删除(不接线)。
- **理由**:零读者、无设计文档描述预期语义;接线需独立产品设计,保留只会继续污染配置面。
- **影响范围**:`flags.go` / `app.go` / `features.go` / 三 compose / `.env.example`;新增 `TestComposeNoDeadSemanticFallbackConfig` 防复活。
- **验收**:`go vet ./...`;`go test ./internal/intent/... ./internal/app/... ./internal/sysadmin/... ./internal/config/...`;`rg SEMANTIC_FALLBACK_ENABLED` 除 `.doc/` 历史外无匹配。
### X-2:`SEMANTIC_SUMMARY_REPLACE` — 维持封存
- **现状证据**:env 可读但 `semantic_summary.go` 明确 `_ = SemanticSummaryReplaceEnabled()` 且不替换 `sum.Narrative`;负例 `TestSemanticSummary_ShadowOKKeepsDeterministic` 已覆盖 `Replace: true`。
- **决策**:维持不接线;补强注释回链本决策记录。
- **理由**:与 CURRENT 红线及 remediation Wave 5 一致;启用需独立授权 + fail-closed 灰度设计。
- **影响范围**:仅 `summary_flags.go` / `semantic_summary.go` 注释。
- **验收**:`go test ./internal/ctxmgr/... -run Semantic`;diff 仅注释。
### X-3:goose 00048 三表 — deferred → SWBOOT-10/W5b
- **现状证据**:`project_types` / `compliance_profiles` / `project_type_workflows` 已建表有种子,但 API 走硬编码 `swboot.ProjectTypesCatalog()` / `ComplianceProfilesCatalog()`;`project_source_bindings` / `repo_path_allowlist` 零运行时读写;`RepoAllowlist` 仅 stub + 单测。
- **决策**:标记 deferred,归 W5b/SWBOOT-10;**不改 schema**。
- **理由**:FEATURE-MATRIX 明确 SWBOOT-10 仍 stub;DB 化消费方与受控执行器需独立安全评审。
- **影响范围**:`catalog.go` / `repo_allowlist.go` 注释;long-term 软件自举文档追加一行。
- **验收**:`go test ./internal/swboot/...`;diff 仅注释与 long-term 文档。
### X-4:`system_settings` 6 未接线键 — 保留待二期
- **现状证据**:白名单 7 键中仅 `workflow.allow_author_only_approval` 有消费方;其余 6 键(`ui.maintenance_notice`、`ui.read_only_mode`、`chat.default_session_role`、`tasks.default_auto_repair`、`kb.default_search_limit`、`notifications.stage_advance_reminder`)零业务读取。FEATURE-MATRIX 系统管理台「白名单项接消费方」列为二期。
- **决策**:保留白名单 + 逐键注释说明预期消费方;不删。
- **理由**:删除需改写多处白盒测试且收益低;机制先行符合一期设计,二期再接线。
- **影响范围**:仅 `internal/sysadmin/settings.go` 注释。
- **验收**:`go test ./internal/sysadmin/...`;diff 仅注释。
### X-5:前端死组件/死 API — 删除
- **现状证据**(`web/` 全目录扫描,排除自身):
- `DocumentNotificationList` / `WorkflowPrerequisiteBanner` / `SettingsModal`:仅自身文件命中;`App` 使用 `UserSettingsModal`。
- `activateWorkflow`(`api/projectWorkflow.ts`):仅定义处;实际用 `activateWorkflowInstance`。
- `saveMessages`:已 `@deprecated` no-op,仅定义处。
- 级联:`patchNotification` 唯一调用方为 `DocumentNotificationList`。
- **决策**:删除上述 3 组件 + `activateWorkflow`(及类型)+ `saveMessages` + `patchNotification`;同步 import。后端 `PATCH /api/v1/notifications/{id}` 保留。
- **理由**:真死代码;删除降低误挂载与维护噪音;后端路由未经本波审计故不删。
- **影响范围**:见删除清单;无 barrel / 无专用单测。
- **验收**:`cd web && npm test && npm run build`;`rg` 无残留(`activateWorkflowInstance` 除外)。
## 证据 / 备注
基线 tip:`a12c947`(Wave 4 已合入本地 `.worktrees/dev-rdev-merge` `dev`)。
@@ -0,0 +1,51 @@
---
title: "Wave 6:文档漂移修复(D-1~D-6)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: docs/wave6-doc-drift
worktree: "-"
mutex: doc-drift
---
# Wave 6:文档漂移修复(D-1~D-6)
## 目标
按系统体检整改方案 Wave 6,逐项关闭文档漂移 D-1~D-6,使 SSOT(audit/INDEX、remediation/INDEX、FEATURE-MATRIX、PROJECT.md、backlog、ADR、handoff、PU8 契约)口径一致。
## 范围
- D-1(含附带的 short-term 归档)、D-2、D-3(复核)、D-4、D-5、D-6
## 非目标
- Wave 5(X-1~X-5)及其涉及的任何代码;不升 tier;不接线 REPLACE;不改 FAV;项目 143 只读;不删除 D7 对话数据
## 步骤
1. [x] D-1 契约状态回标 + 归档两份 short-term 任务文件
2. [x] D-2 ADR 状态改 accepted
3. [x] D-3 复核 INDEX 末行(无改动)
4. [x] D-4 handoff 回标闭环
5. [x] D-5 backlog D3/D7 同步
6. [x] D-6 PROJECT.md §9 对齐
7. [x] remediation/CURRENT 收口 + test-report + 合入本地 `dev`
## 验收标准
- [x] D-1~D-6 每项均有落盘证据或复核记录
- [x] `go build ./...` / `go vet ./...` / `npm run build` 全绿(无代码改动,防误伤)
- [x] remediation Wave 6 行改 done;勾选「D-1~D-6 全部回链关闭」
- [x] CURRENT 焦点/认领表/集成槽位三处一致
## 相关链接
- Remediation: [../../remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Audit: [../../audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- Test report: [../../test-reports/2026-09-18-wave6-doc-drift-test-report.md](../../test-reports/2026-09-18-wave6-doc-drift-test-report.md)
## 证据 / 备注
基线 tip:`2ce2625`(`merge: fix/wave5-deadcode-decisions`)。mutex=`doc-drift`,未复用 `architecture-docs`。FEATURE-MATRIX 交叉检查无改动(D3 done/shadow、D7 deferred、U9–U12 done、`production_ready=yes` 与本次回标一致)。
@@ -0,0 +1,101 @@
---
title: "Wave 7:既有 roadmap 收口(编排确认)"
status: done
created: 2026-09-18
updated: 2026-09-18
owner: Cursor-Auto
branch: docs/wave7-roadmap-orchestration
worktree: "-"
mutex: roadmap-orchestration
---
# Wave 7:既有 roadmap 收口(编排确认)
## 目标
对照 FEATURE-MATRIX 剩余工作列,为 T1/W5、T1/W6、T1/W7、T2、T4、T5/T6/T8 各写一条编排确认;不改变任何能力实现状态。
## 范围
- 六条编排确认文案落盘(见「确认记录」)
- remediation Wave 7 行改 done 并回链本记录
- CURRENT 焦点改为 Wave 0–7 done,并记录 Control Center 双实现发现
## 非目标
- 不实施 SWBOOT-10;不升 FAV live / 不改 `FAV_DEGRADED_READ`;不按 D7 物理删除数据;不升 `MULTI_INTENT_PLAN_TIER`;不接线 `SEMANTIC_SUMMARY_REPLACE`;项目 143 只读
- 不改 FEATURE-MATRIX 状态列;不改 gap-matrix 发布门禁
- **不补 Wave 6 D-5**:D-1~D-6 已在 `a88ed85` PASS,backlog D3/D7 已同步;本波不改 `.doc/backlog/chat-agent-p6-backlog.md`,不把 Wave 6 再标一遍
- 不决定 Control Center 两套实现的取舍:不合并、不删除 `feature/control-center-server`
## 步骤
1. [x] 跳过步骤 0(Wave 6 D-5 已完成)
2. [x] 六条编排确认落盘(本文件)
3. [x] remediation Wave 7 行改 done + 回链本记录
4. [x] CURRENT 焦点改为「Wave 0–7 done」+ 记录 Control Center 分支冲突发现
## 验收标准
- [x] 六项编排确认均含:当前状态、关闭条件、是否需用户授权、建议下一触发点
- [x] 无一项被伪装为已实现;FAV/D7/tier 升级仍标注「需用户显式授权」
- [x] Wave 6 保持已关闭,未重复改写
## 相关链接
- Remediation: [../../remediation/2026-09-17-system-health-remediation-plan.md](../../remediation/2026-09-17-system-health-remediation-plan.md)
- Audit: [../../audit/2026-09-17-system-health-check.md](../../audit/2026-09-17-system-health-check.md)
- 总控: [../../remediation/2026-09-16-partial-deferred-completion-plan.md](../../remediation/2026-09-16-partial-deferred-completion-plan.md)
- Test report: [../../test-reports/2026-09-18-wave7-roadmap-orchestration-test-report.md](../../test-reports/2026-09-18-wave7-roadmap-orchestration-test-report.md)
## 确认记录
### T1/W5:SWBOOT-10
- **当前状态**:SWBOOT-00~09(契约、迁移、目录、UI、docs_only 真实 PI)已合入 `dev`([long-term](../long-term/2026-09-14-software-project-bootstrap-implementation.md)、[W5a 报告](../../test-reports/2026-09-17-w5a-software-bootstrap-ui-pi-test-report.md))。SWBOOT-10(受控工程执行:repo allowlist、worktree、patch/test/merge 分段批准)仍为 **stub only**,保持 fail-closed,归 W5b,本轮未启动。goose 00048 三张关联表(`project_source_bindings` / `repo_path_allowlist` / `project_type_workflows`)已在 Wave 5 X-3 标记 deferred。
- **关闭条件**:独立安全评审通过 + SWBOOT-10 非 stub 真实实现 + 真实 PI 全链路证据 + UI 二次验收(见 [partial-deferred-completion-plan §W5](../../remediation/2026-09-16-partial-deferred-completion-plan.md))。
- **是否需用户授权**:**需要**。独立安全评审本身即用户授权门槛;红线明确「不实施 SWBOOT-10 真实执行器」。
- **建议下一触发点**:用户就 W5b 受控执行器单独立项、批准安全评审范围后,从 `dev` 开 `feature/swboot-10-w5b`(mutex `workflow-design`)按 long-term 拆分实施。本波不动代码,fail-closed stub 原样保持。
### T1/W6:FAV live 放量
- **当前状态**:W6 shadow 已合入 `dev`([short-term](2026-09-17-w6-fav-subscriber-shadow.md)、[报告](../../test-reports/2026-09-17-w6-fav-subscriber-shadow-test-report.md)):`ObserveShadow` 只计算 intended outcome、不写业务副作用;负例覆盖 degraded read 拒绝 / `HandleLease` / `Register(fav)` fail-closed。三环境 compose 既有声明为 `FAV_DEGRADED_READ` 默认 false、`FAV_PUBLISHER_ENABLED` 默认 false。**live 未放量**。本波未改 compose。
- **关闭条件**:按固定顺序 staging → artifact → publication 逐 consumer live,每级 shadow → drain → live,观察窗 ≥7 天或 ≥N 终态样本(取更严);`FAV_DEGRADED_READ` 全程保持 false;崩溃/重启幂等证据;**禁止整支 merge** `feature/final-artifact-vault`(见 [partial-deferred-completion-plan §7.4](../../remediation/2026-09-16-partial-deferred-completion-plan.md))。
- **是否需用户授权**:**需要**。红线明确「不升 FAV live / 不改 `FAV_DEGRADED_READ`」。
- **建议下一触发点**:用户批准 staging 级观察窗起点后,从 `dev` 开独立 flag 分支(mutex `events`),先跑 staging ≥7 天观察窗并归档证据报告,再评估升 artifact/publication。本波不推进放量。
### T1/W7:D7 对话数据治理
- **当前状态**:ADR 草案([2026-09-17-d7-chat-data-retention.md](../../adr/2026-09-17-d7-chat-data-retention.md),`compliance: pending-compliance-signoff`)已落地;只读数据分类盘点已完成([audit](../../audit/2026-09-17-d7-data-inventory.md),`status: done`),**未发现**当前基线违反已确认合规/安全约束,因此**未**写入 gap-matrix blocker。合规签字前禁止按 365/180/30 天草案数字执行物理删除或备份清除。Wave 6 已把该现状同步进 backlog D7 行,本波不改该文件。
- **关闭条件**:合规签字或改数 → ADR 状态改 `accepted`/`signed` → 按签字口径落地整改(soft-delete 写路径 → 观察窗 → 物理清理;备份二次批准 + delete manifest)→ FEATURE-MATRIX D7 行升 `done`;若盘点期间发现违规则立即升 gap-matrix(本轮未触发)。
- **是否需用户授权**:**需要**。合规签字是产品/法务决策,非工程可自行拍板;红线明确「不按 D7 物理删除数据」。
- **建议下一触发点**:用户/合规负责人对 ADR 草案数字表签字或提出修改意见;签字后开独立 short-term 任务按 ADR 决策落地。
### T2:Control Center 前端 SPA 七页人工走查
- **当前状态**:2026-09-17 审计结论已过期,不能按「仅剩前端走查」收口。FEATURE-MATRIX「个人工程中控台」行已通过 `engineering-dashboard`(CLI `serve`/`export`,四轴模型)达到 **done** 一期,已合入 `dev`([报告](../../test-reports/2026-09-17-engineering-dashboard-test-report.md))。审计 T2 所指「后端 P0–P6 已签,仅剩前端 SPA 七页人工走查」实为 Kimi 的 `feature/control-center-server`:自身 11 commits(P0 skeleton → P6 design spec + LAN bind + agent-integration),**从未合入 `dev`**。2026-09-18 相对 `dev@a88ed85` 实测:merge-base `adb48c8`,落后 **136** commits(研究快照曾记 128,以本次 `rev-list` 为准),缺失 Wave 0–6。提交 `b5bacee`(`refactor(control-center): remove legacy engineering-dashboard, superseded by control-center`)试图删除已合入并验收的 `engineering-dashboard`,与 canonical 实现冲突。该分支的任务声明与 CURRENT 认领只存在于分支本身,未反映在 `dev` 主线。实现范围(pgvector 文档向量库、P3 SPA、P5 定期审计 + LLM 复核)超出已批准设计一期边界。
- **关闭条件**:FEATURE-MATRIX 该行**已经 done**(通过 engineering-dashboard)。若要转向「复活/合并 Kimi 实现」,需先有独立决策与重新规划,不属于「仅剩一次前端走查」。
- **是否需用户授权**:**是**。授权对象是「两套实现如何取舍」,不是「批准做前端走查」。本波只读编排确认,不能代为废弃或合并该分支。
- **建议下一触发点**:请用户明确二选一:(a) 维持现状——`engineering-dashboard` 为唯一 canonical 实现,`feature/control-center-server` 由用户决定归档或保留(推荐:已 done 且范围经批准);或 (b) 要求评估合并该分支的增量能力(SPA / pgvector / 定期审计)。触发后再开对应短期任务。本波只记录事实与建议,**不合并、不删除**该分支。
- **后续裁决(2026-09-19)**:用户决定进度管理由独立项目承担。本仓库已删除 Control Center 代码与文档,不恢复 `engineering-dashboard`。见 [移除任务](./2026-09-19-remove-control-center.md)。
### T4:首次加载性能 U1/U3–U7
- **当前状态**:仅 U2(静态资源交付)done——自托管字体、构建期 br/gzip、`/assets/*` 404 修正;主 JS 传输 2.82 MB → ~624 KB,登录冷缓存可见 ~205ms([报告](../../test-reports/2026-09-17-initial-load-perf-u2-test-report.md))。U1(完整性能基线)、U3(登录壳按需加载)、U4(初始化扇出收敛)、U5(认证请求去重)、U6(列表/租约按证据优化)、U7(重启后首访链路)**均未开始**。
- **关闭条件**:按 [方案](../../remediation/2026-09-17-initial-load-performance-plan.md) Definition of Done——R1–R6 逐项有前后对比 + 真实 UI 证据;未覆盖项明确列残余,不因 health PASS 关闭;完成后更新任务/CURRENT/FEATURE-MATRIX/test-report。
- **是否需用户授权**:不需要额外专项授权(方案已 planned 且范围已批准);需要工程排期认领(估算 U1–U5 约 3.5–7 人日,U6 另需 2–4 日,U7 另需 0.5–1.5 日,非承诺)。
- **建议下一触发点**:任一 Agent 从 `dev` 开分支认领 U1(P0,是后续单元的前置依赖)即触发;建议顺序 U1 → U2(done)/U3 与 U7 → U4/U5 → 按数据选 U6。
### T5/T6/T8:backlog 类(按收益触发)
- **T5 选择性模块解耦 M4–M6**:**当前状态** `planned`,owner=TBD,未开始([long-term](../long-term/2026-09-14-selective-module-decoupling.md))。触发条件中「M1–M3 test report 全部 PASS」已满足(文档可靠性试点 / 可靠事件核心均 done),但「同类缺陷触达文件数和运行故障率表明继续解耦具有收益」证据尚未出现,暂不触发。**关闭条件**与是否授权见该文档触发条件段。**是否需用户授权**:无需专项授权,按收益证据 + owner 认领即可开工。**建议下一触发点**:出现同类缺陷证据或 owner 主动认领。
- **T6 产品 backlog(B5/A5/A6/A7/D5)**:[backlog](../../backlog/chat-agent-p6-backlog.md) 仍列 B5(报价复核)、A5/A6(小队降级 + trace)、A7(注释迁移)、D5(KB 按环境隔离评估)为纯 backlog,无任务文件、无 owner。**D3、D7 已由 Wave 6 同步**(D3 标已实现 shadow 并回链;D7 回链 ADR 草案与只读盘点,合规签字前不整改)。本波不改该文件。**关闭条件**:开放项按产品收益单独排期开短期任务。**是否需用户授权**:开始评估不需要专项授权;D3 REPLACE 灰度、D7 整改分别仍受各自红线约束。**建议下一触发点**:产品侧提出具体收益诉求;无固定时间表。
- **T8 IAM 收尾开放项**:410 退役策略已冻结为「保留,非缺口」([决策](../../audit/2026-09-16-bug11-410-retire-decision.md),gap-matrix BUG-11 PASS);R13 数据安全清单 7 项全部 PASS,仅「完整红队注入矩阵」标记为开放增强、不挡基线;IAM 全路由 inventory 仍标记「开放」([handoff](../handoffs/2026-09-16-phase3-leftover-closeout.md)),fail-closed 核心已签。均为**加固类,非发布 blocker**。**是否需用户授权**:不需要专项授权,可按运维遥测随时另开 audit/任务。**建议下一触发点**:410 路由遥测证明零流量后可另开退役任务;或需要更强出站安全保证时另开红队 audit。
## 新发现(需用户后续裁决,不阻塞本波收口)
- **Control Center 双实现冲突**:当时未合入。2026-09-19 用户裁决为移出本仓库,代码与专属文档已删除,不恢复旧工程中控台。见 [移除任务](./2026-09-19-remove-control-center.md)。
## 证据 / 备注
基线 tip:`a88ed85`(`merge: docs/wave6-doc-drift`)。mutex=`roadmap-orchestration`。零 Go/TS/SQL/compose 改动。FEATURE-MATRIX 状态列未改。
@@ -0,0 +1,56 @@
---
title: "移除 Control Center,本仓库回到智能体系统"
status: done
created: 2026-09-19
updated: 2026-09-19
owner: Cursor-Auto
branch: fix/remove-control-center
worktree: "-"
mutex: controlcenter
---
# 移除 Control Center
## 目标
项目进度管理已由独立项目承担。从本仓库删除 Control Center 的代码、部署、规范和专属文档,不恢复旧 `engineering-dashboard`。
## 范围
- 删除 `cmd/control-center`、`internal/controlcenter`、`control-center/web`、`deploy/control-center`、`scripts/control-center.sh`
- 删除专属设计、任务、测试报告与截图
- 更新 AGENTS、FEATURE-MATRIX、CURRENT、模块边界与断链引用
- 停掉 `control-center-db` 与 `127.0.0.1:8790`
## 非目标
- 不恢复 `engineering-dashboard`
- 不 push
- 不改产品 `internal/server`、产品前端或三环境 compose
## 步骤
1. [x] 从本地 dev 开 `fix/remove-control-center`
2. [x] 删除代码与文档并更新引用
3. [x] 停运行时
4. [x] `go vet` / `go test -short` / 产品前端 build / archtest
5. [x] 合入本地 dev 并做健康检查
6. [x] 删除未跟踪的 `control-center/web/node_modules` 与本地分支 `feature/control-center-server`
## 验收标准
- [x] 仓库内不再有 Control Center 源码或专属文档
- [x] `go vet ./...`、`go test -short ./...`、`go test ./internal/archtest/`、`web` 的 `npm run build` 通过
- [x] 本地 dev 健康检查 200
## 相关链接
- Checklist:
- Handoff:
- Test report: [../../test-reports/2026-09-19-remove-control-center-test-report.md](../../test-reports/2026-09-19-remove-control-center-test-report.md)
## 证据 / 备注
用户确认:只移除 Control Center,副本已在别处实现,合入本地 dev。
2026-09-19 复查:产品代码、模块边界、AGENTS 规范、容器与端口均无残留。另删除未跟踪目录 `control-center/`(仅 `node_modules`)和本地分支 `feature/control-center-server`(`55fa8dd`)。未删除 `origin/feature/control-center-server`。`go build ./...` 通过。
@@ -0,0 +1,50 @@
---
title: "系统深度体检审计(独立审查潜在缺陷与未完善点)"
status: done
created: 2026-09-19
updated: 2026-09-19
owner: Cursor
branch: docs/audit-remediation-backlog
worktree: "-"
mutex: audit
---
# 系统深度体检审计(2026-09-19)
## 目标
在不改业务代码的前提下,对当前 dev(e8ed33b)做一次独立深度审查,输出 `.doc/audit/` 审计笔记,列出潜在 bug 与未完善项并给出严重度分级。
## 范围
- Go 静态验证:`go vet ./...` + `go test -short ./...`
- 后端:server 路由/chat SSE/docgov/events 错误处理与并发风险
- 前端 web:错误处理、SSE 重连、竞态
- 配置:flag 默认值一致性、死代码、环境差异(dev/test schema 漂移)
- 安全:IAM 旁路、密钥泄露面
- DB:goose 迁移一致性与回滚风险
## 非目标
- 不修改业务代码(docs-only 分支)
- 不验证已明确 deferred 的事项本身(FAV live 放量、D7 签字、SWBOOT-10)——仅核对声明与代码是否一致
## 步骤
1. [x] 创建 docs 分支、登记 CURRENT
2. [x] go vet + go test -short
3. [x] 并行子代理深潜后端/前端/配置/DB/安全
4. [x] 汇总撰写 audit 笔记并提交
## 验收标准
- [x] 每个发现均有代码路径 + 行号证据
- [x] 严重度分级(critical/high/medium/low)
- [x] 与 FEATURE-MATRIX 已声明的 partial/deferred 项对齐,不重复申报
## 证据 / 备注
- go vet 零告警;go test -short 55 包全 PASS(dev@e8ed33b)
- 审计笔记:[.doc/audit/2026-09-19-system-deep-audit.md](../../audit/2026-09-19-system-deep-audit.md)
- 五路并行只读深潜全部完成;四条红线核实一致;新发现 4 critical(C1 docgov 吞错 / C2 Session 竞态 / C3 SSE 超时 / C4 工作流竞态)+ 10 high
- 整改:critical/high 已分四批合入 `dev`(`844f757` / `08f4e0b` / `a2a49a6` / `d73bc79`)。medium/low 见 [long-term](../long-term/2026-09-19-audit-remainder.md)。
@@ -0,0 +1,58 @@
---
title: "修复系统权限设置与项目协作多项缺陷"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: fix/bug-hunt-2026-09-20-permissions-and-uploads
worktree: "-"
mutex: authz+web+projectworkflow
---
# 修复系统权限设置与项目协作多项缺陷
## 目标
修复两轮排查确认的 12 处后端/前端缺陷(CSP/PDF、系统设置 CAS、任务错误误分类、task-run 403、成员管理 RBAC、注册吞错、强制改密复发、项目重名、无项目可对话、右侧栏不记忆等)。
## 范围
- CSP `frame-src` + PDF blob 预览
- 系统设置 `expected_revision` 全链路
- `ProjectSettingsApiError` httpStatus/errorCode 别名
- task-run 查看放宽为项目成员;前端 403/404 停轮询
- `project:manage_members` 权限位(迁移 00055)
- memStore 成员可见性
- CreateUser 吞错 / 400·500 分类 / LooksInternal
- 强制改密 session 嵌套字段 OR 复活
- CreateProject `client_key` 幂等 + `(creator, name)` 唯一(迁移 00056)
- 无项目禁止对话 + 发送按钮置灰
- 右侧工具栏默认收起并持久化
## 非目标
- 全局项目名唯一(仅同创建人内唯一)
- 放宽 `frame-ancestors` / `X-Frame-Options`
## 步骤
1. [x] 后端 CSP / authz / auth / projectworkflow / chat 入口
2. [x] 前端 PDF / settings / 错误别名 / 轮询 / RBAC UI / 改密 / 建项幂等 / InputArea / AppShell
3. [x] 迁移 00055 / 00056 + 单测
4. [x] `go vet` / `go test -short` / `npm test` / `npm run build`
5. [x] 占集成槽位合回 `dev`
## 验收标准
- [x] 代码与契约补齐(见 audit 笔记)
`- [x] 短测与前端构建通过
`- [x] 合入 `dev`
## 相关链接
- Audit: `.doc/audit/2026-09-20-bug-hunt-permissions-uploads.md`
- Plan: `.cursor/plans/修复系统权限设置与项目协作多项缺陷_ff3242f7.plan.md`
## 证据 / 备注
分支:`fix/bug-hunt-2026-09-20-permissions-and-uploads`
@@ -0,0 +1,57 @@
---
title: "能力就绪度与 lineage 鉴权"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: sysadmin+lineage
---
# 能力就绪度与 lineage 鉴权
## 目标
管理台把配置值与实现成熟度、适配器就绪度分开;lineage 读取必须落在 URL 项目内,并按逐文档可见性裁剪,跨项目或不可见文档不泄漏标识。
## 范围
- Foundation 0:功能目录增加 `implementationState`、`adapterReadiness`、`configuredValue` / `effectiveValue`、`rolloutScope`。
- lineage GET:`project_id` 约束、查询文档属于该项目、两端文档可见性过滤;空结果与“不可见”使用同一空列表,不区分存在性。
## 非目标
- 不打开 test/main 开关,不升 `full`,不接 `SEMANTIC_SUMMARY_REPLACE`。
- 不实现 `trace_reviewer` 端点(待审核)。
- 不建项目追踪五表,不决定 D7 留存与源文档删除传播。
- 不占用集成槽,不重启共享容器。
## 步骤
1. [x] 能力目录与管理台展示成熟度,配置值不能冒充可用。
2. [x] lineage 查询按项目与文档可见性过滤,并补跨项目负例。
3. [x] `go test` 覆盖上述契约。
## 验收标准
- [x] `SEMANTIC_SUMMARY_REPLACE=true` 时实现状态仍为 `placeholder`,适配器 `unavailable`。
- [x] 用项目 A 的 URL 查询项目 B 的 `doc_id` 得到空列表,响应体不含 B 的上游文档 ID。
- [x] 项目 B 自己的 URL 仍能读到已登记且两端都可解析的血缘。
## 相关链接
- 整改方案: [2026-09-20-capability-enablement-impact-plan.md](../../remediation/2026-09-20-capability-enablement-impact-plan.md)
- 调研: [2026-09-20-capability-enablement-impact-research.md](../research/2026-09-20-capability-enablement-impact-research.md)
## 证据 / 备注
2026-09-20 本地 `go test`(未占集成槽、未重启容器):
- `TestFeatures_ConfiguredValueDoesNotImplyReadiness` PASS
- `TestGetLineageForProjectDownstream_ExcludesOtherProject` PASS
- `TestProjectLineage_ForeignDocDoesNotLeak` PASS
- `TestProjectWorkflow_TestManagerAndLineageStale` PASS
- `TestFilterLineageEdges_DropsForeignAndHiddenEndpoints` PASS
管理台表格改在 `web/src/components/admin/console/sections/FeaturesSection.tsx`。本波未重建 dev 容器,页面验收留到占槽冒烟。
@@ -0,0 +1,64 @@
---
title: "模块解耦规范与耦合审计"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: docs/module-decoupling-spec-2026-09-20
worktree: "-"
mutex: module-decoupling-spec
---
# 模块解耦规范与耦合审计
## 目标
在不改业务代码、不推翻模块化单体 ADR 的前提下,交付三份可执行文档:当前耦合审计、模块开发规范(通信契约 / 输入输出接口 / 故障隔离)、分批整改计划。
## 范围
- 盘点 2026-09-14 / 2026-09-15 解耦基线之上的剩余耦合热点。
- 把既有契约(窄端口、领域事件、wire DTO、表唯一写者)收成开发者入口规范。
- 把整改拆成独立批次 A–G,各自带 mutex、分支示例、验收门与回滚点。
- 同步 CURRENT 认领与 FEATURE-MATRIX 规范行。
## 非目标
- 不改 `internal/`、`web/`、`module-boundaries.yaml` 或迁移。
- 不把单体内端口改成 RPC,不拆微服务。
- 不修改 Cline 占用的 `partial-deferred-completion-plan.md`(只引用)。
- 不占用 `architecture-docs` mutex。
- 不把 planned 批次标成进行中或完成。
## 步骤
1. [x] 登记 short-term 与 CURRENT 认领。
2. [x] 写耦合审计。
3. [x] 写模块开发规范。
4. [x] 写分批整改计划。
5. [x] 同步 FEATURE-MATRIX 与 CURRENT 焦点。
6. [x] 分批 `docs(...)` 提交,占集成槽位后 `--no-ff` 合回 `dev`,文档-only 冒烟。
## 验收标准
- [x] 审计覆盖 7 个热点,并给出文件路径证据与严重度。
- [x] 规范明确三种通信契约、端口 checklist、故障隔离红线、新增模块/表/事件流程。
- [x] 整改计划 A–G 各自可独立认领,互不把对方写成已完成。
- [x] 文档落入 taxonomy,不在 `.doc/` 根新建文件。
## 相关链接
- 架构: [../../system-design/2026-09-14-module-decoupling-architecture.md](../../system-design/2026-09-14-module-decoupling-architecture.md)
- 本轮审计: [../../audit/2026-09-20-module-coupling-audit.md](../../audit/2026-09-20-module-coupling-audit.md)
- 本轮规范: [../../system-design/2026-09-20-module-development-standards.md](../../system-design/2026-09-20-module-development-standards.md)
- 本轮批次: [../../remediation/2026-09-20-module-decoupling-batch-plan.md](../../remediation/2026-09-20-module-decoupling-batch-plan.md)
- ADR: [../../adr/2026-09-14-modular-monolith-decoupling.md](../../adr/2026-09-14-modular-monolith-decoupling.md)
- Phase 2: [../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- 影响面守则: [../../remediation/2026-09-16-partial-deferred-completion-plan.md](../../remediation/2026-09-16-partial-deferred-completion-plan.md) §2
- 边界清单: [../../system-design/module-boundaries.yaml](../../system-design/module-boundaries.yaml)
## 证据 / 备注
只读盘点(2026-09-20):生产 Go 约 7.8 万行;`archtest` import/event 已 block 且 baseline import=0、event=0;剩余例外为 sql_write 5 + path 16。
合入 `dev`:`133ceb45`(`merge: docs/module-decoupling-spec-2026-09-20`)。冒烟:`go vet ./...` 通过。`go test -short ./...` 除 `TestPiAgentDockerBuildContext_RunnerModulesPresent` 与 `TestDockerBuildContext_TemplatesDocsReadable` 外均为 ok;这两例失败原因是拉取 `debian:bookworm-slim` 时镜像源 EOF,不是本批文档改动。槽位在记录该结果后释放。
@@ -0,0 +1,49 @@
---
title: "2026-09-20 P0 热修(迁移 / 越权 / 稳定性 / 凭证)"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: docs/p0-closeout-2026-09-20
worktree: "-"
mutex: docs
---
# 2026-09-20 P0 热修
## 目标
关闭系统体检发现的 P0 critical:迁移断链、三项 IDOR、进程 panic/race、凭证泄漏与生产口令轮换。
## 范围
- Wave 0–4(见 [整改方案](../../remediation/2026-09-20-p0-remediation-plan.md))
- 后续实现分支:`fix/capability-merge-00058-2026-09-20`、`fix/authz-idor-hotfixes-2026-09-20`、`fix/runtime-panic-races-2026-09-20`、`fix/credential-hardening-2026-09-20`、`docs/p0-closeout-2026-09-20`
## 非目标
- main 分支对齐晋升
- FAV / SWBOOT-10 / D7 / MULTI_INTENT full
## 步骤
1. [x] Wave 0:审计与整改文档、CURRENT 认领、long-term 增补
2. [x] Wave 1:capability 合入 + 00058 + rebuild
3. [x] Wave 2:三项越权
4. [x] Wave 2b:panic/race/recover/XSS
5. [x] Wave 3:凭证 + 口令轮换
6. [x] Wave 4:测试报告与收口
## 验收标准
- [x] 见 [测试报告](../../test-reports/2026-09-20-p0-hotfixes-test-report.md)
## 相关链接
- Audit: [../../audit/2026-09-20-system-triage-audit.md](../../audit/2026-09-20-system-triage-audit.md)
- Remediation: [../../remediation/2026-09-20-p0-remediation-plan.md](../../remediation/2026-09-20-p0-remediation-plan.md)
- Test report: [../../test-reports/2026-09-20-p0-hotfixes-test-report.md](../../test-reports/2026-09-20-p0-hotfixes-test-report.md)
## 证据 / 备注
(各波次合入 commit 与健康输出)
@@ -0,0 +1,51 @@
---
title: "PI 变更叙事只读事实带上截断差异"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: docgov
---
# PI 变更叙事只读事实带上截断差异
## 目标
`PI_CHANGE_REPORT_NARRATIVE` 仍默认关闭时,叙事请求的 `facts.json` 已包含有长度上限的差异片段和影响说明,而不是只有 SHA、风险和计数。
## 范围
- `NarrativeModelInput`:最多 8 条 hunk、8 条影响,前后文/原因各 240 个字符,超出记 `truncated` 与 `hunks_omitted` / `impacts_omitted`,同时保留完整计数。
- `PiChangeReportNarrator.Fetch` 改写这份最小化输入。
- 成熟度说明与 FEATURE-MATRIX 改为「输入已含截断差异,开关与运行中 runner 仍未就绪」。
## 非目标
- 不打开 `PI_CHANGE_REPORT_NARRATIVE`。
- 不把整篇 Markdown 或未截断正文放进模型输入。
- 不改变 `NarrativeInputDigest`(摘要仍只绑 hunk id/kind/section 与影响 doc/type/reason)。
- 不重启容器,不占集成槽位,不实现 trace_reviewer 或 T2 物理删除。
## 步骤
1. [x] 增加截断后的模型输入,并让 Fetch 使用它
2. [x] 单测覆盖正文出现、超长截断、digest 原样保留
3. [x] 同步成熟度说明、FEATURE-MATRIX、CURRENT
## 验收标准
- [x] `go test` 覆盖 `TestNarrativeModelInput_IncludesClippedChangeText` 与 `TestPiChangeReportNarrator_NoTools`
- [x] 开关默认仍关闭;成熟度仍是 shadow / degraded
## 相关链接
- Checklist:
- Handoff:
- Test report: 本切片为契约单测,未做真实 PI 容器验收
## 证据 / 备注
- `internal/docrevision/narrative.go` `NarrativeModelInput`
- `internal/app/pi_narrative.go` Fetch
@@ -0,0 +1,53 @@
---
title: "PI 纯推理 profile"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: pi-agent
---
# PI 纯推理 profile
## 目标
语义摘要、变更叙事和 U9 分段请求的实际 argv 不再包含读写或搜索工具。文档生成保持原工具集。
## 范围
- `tool_profile=reasoning` 使用 `--no-tools`,不加载 tavily 扩展。
- 未知 profile 拒绝启动,不退回读写工具。
- 三个只读消费者传 `reasoning`。空 profile 仍是 workspace。
## 非目标
- 不重启容器,因此正在运行的 runner 进程还是旧 argv。
- 不打开 shadow、叙事或 U9 开关。
- 不把具体 diff 补进叙事输入。
## 步骤
1. [x] runner 与本地 bridge 按 profile 组装 argv。
2. [x] 三个消费者传 reasoning。
3. [x] node 与 Go 测试覆盖 argv 和请求体。
## 验收标准
- [x] reasoning argv 不含 read、write、edit、search,且含 `--no-tools`。
- [x] 默认 profile 仍带 workspace 工具名单。
- [x] 未知 profile 抛出 `UNKNOWN_TOOL_PROFILE`。
## 相关链接
- 整改方案: [2026-09-20-capability-enablement-impact-plan.md](../../remediation/2026-09-20-capability-enablement-impact-plan.md)
## 证据 / 备注
2026-09-20 本地测试(未重启容器):
- `node --test deploy/pi-agent/tests/pi-args.test.mjs` 3 PASS
- `TestRunnerPayload_ReasoningDoesNotBecomeWorkspace` PASS
dev compose 已挂载 `pi-args.mjs`,Dockerfile 已 COPY。正在运行的 runner 进程仍是旧 argv。
@@ -0,0 +1,50 @@
---
title: "激活后职责改派 + 成员可对话"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: fix/post-activation-duty-reassign-member-chat
worktree: "-"
mutex: projectworkflow+authz+web
---
# 激活后职责改派 + 成员可对话
## 目标
工作流激活后可随时改派文档三职(小队任务运行中除外);项目成员无需文档职责即可阶段对话。
## 范围
- U1:放宽 `AllowedStageKeys`(对话/历史);`AllowedTaskKeys` 仍职责门禁
- U2:`PATCH .../doc-tasks/{taskKey}/duties` 受控改派
- U3:冻结态设置页可改派 UI
- U4:单测 + test 环境验收报告
## 非目标
- 不放开 `PUT /workflow-plan` 全量规划编辑
- 不放行已结束实例的聊天
## 步骤
1. [x] U1 成员阶段对话
2. [x] U2 改派 API
3. [x] U3 前端
4. [x] U4 验收
## 验收标准
- [x] 无职责项目成员 live 下可 chat/stream
- [x] 激活后可改派;squad running 时 409(单元)
- [x] PUT workflow-plan 仍 PLAN_FROZEN
## 相关链接
- Test report: [../../test-reports/2026-09-20-post-activation-duty-reassign-member-chat-test-report.md](../../test-reports/2026-09-20-post-activation-duty-reassign-member-chat-test-report.md)
- Merge: `9d98f1ae`
## 证据 / 备注
- test `:8081` rebuild 后陈威 `sess-p5-u35` 对话 PASS;intake author 改派至 35 PASS
@@ -0,0 +1,53 @@
---
title: "候选变更报告与正式提交报告分开"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: docgov
---
# 候选变更报告与正式提交报告分开
## 目标
Agent 候选只持久化 `proposed` 预估报告,不发下游影响或正式提交事件。正式提交才生成 authoritative 后继报告,并让版本指向后继而不是预估。
## 范围
- 报告增加 `authority`、`lifecycle`、`successor_report_id`,并写入已有 `deterministic_facts`,避免在未占集成槽时改表。
- 新的有效候选把上一份仍 active 的预估标为 superseded。
- 拒绝标 rejected;提交时基线已变则标 expired。这两种以及 superseded、已提交的预估都不能再出建议。
- 正式提交复制一份 authoritative 报告;下游影响通知使用这份报告。`document.agent_version_committed` 仍只由 docflow 的 EventSink 在提交命令里发出。
## 非目标
- 不把人工修订、恢复、导入改成先预估再提交。
- 不打开 `PI_CHANGE_REPORT_NARRATIVE`,不实现 trace_reviewer,不做 T2 物理删除。
- 不新增 `document.committed` 事件名,避免和现有投影消费者分叉。
- 不重启容器,不占集成槽位。
## 步骤
1. [x] 候选写入 proposed,提交写入 authoritative 后继
2. [x] 单测覆盖替代、拒绝、版本不指向预估、候选阶段不发下游事件
3. [x] 同步 FEATURE-MATRIX 与 CURRENT
## 验收标准
- [x] `go test ./internal/docrevision/` 通过
- [x] 预估报告在替代或拒绝后 `AllowsSuggestedActions` 为 false
## 相关链接
- Checklist:
- Handoff:
- Test report: 本切片为账本单测,未做真实聊天或浏览器验收
## 证据 / 备注
- `internal/docrevision/report_disposition.go`
- `TestProposedReportStaysInactiveUntilCommit`
- `TestRejectedProposedReportCannotSuggest`
@@ -0,0 +1,52 @@
---
title: "修复工作流种子:publishedBy 外键与 retired 不自愈"
status: in_progress
created: 2026-09-20
updated: 2026-09-20
owner: Cursor
branch: fix/workflow-seed-bootstrap-2026-09-20
worktree: "-"
mutex: workflow-def
---
# 修复工作流种子:publishedBy 外键与 retired 不自愈
## 目标
dev 与 test 启动后,正式工作流目录包含「研发设计控制流程」(`rdev`),且数据库 `status=active`、已发布版本外键有效。
## 范围
- `BootstrapSeeds`:`publishedBy` 用户不存在时回落到库内最小 id;无用户则跳过并记日志
- `UpsertPublishedSeed` / `RetireNonOfficialDefinitions`:白名单 key 幂等更新时把 `status` 恢复为 `active`
- `bizdev` 启动 seed 失败改为 `slog.Warn`,不再静默丢弃
## 非目标
- 不改 rdev manifest / 60 份模板内容
- 不改 `production_ready`
- 不启用 FAV / 语义摘要 REPLACE
## 步骤
1. [x] 从 dev 切 `fix/workflow-seed-bootstrap-2026-09-20` 并登记认领
2. [ ] 修复 seed actor 回落与 retired 自愈
3. [ ] `go vet` / `go test -short` / PG 集成
4. [ ] 合入 dev 后 rebuild;晋升 test(`rc-v1.0.0-beta.7`)并 rebuild
## 验收标准
- [ ] dev/test catalog 均含 rdev,DB `status=active`
- [ ] test 库 `workflow_versions` 无 `created_by` 外键错误
- [ ] `go vet` / `go test -short` 通过
## 相关链接
- Checklist: -
- Handoff: -
- Test report: `.doc/test-reports/2026-09-20-rdev-seed-hotfix-test-report.md`
## 证据 / 备注
- test PG `2026-09-20 09:49:51`:`workflow_versions_created_by_fkey`(`publishedBy=1`,test 用户最小 id=4)
- dev 库 rdev v3 `status=retired`,`project_selectable=true`(元数据更新不恢复 status)
@@ -0,0 +1,57 @@
---
title: "语义摘要持久化与 lineage 版本"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: feature/capability-enablement-impact-plan
worktree: "-"
mutex: chat+lineage-version
---
# 语义摘要持久化与 lineage 版本
## 目标
`chat_summaries` 有迁移;数据库写失败必须返回错误,不能再被当成保存成功。test_manager 血缘使用文档上的版本号。
## 范围
- goose `00058` 建 `chat_summaries`。
- `SaveChatSummary` 在有连接池时把 INSERT 错误返回给调用方,并标记仅本进程可见。
- 确定性摘要写入 revision 与消息区间。不接 `SEMANTIC_SUMMARY_REPLACE`,不计算授权可见集 digest。
- lineage 下游/上游版本不再写死 1。
## 非目标
- 不重启 dev/test/main,因此运行中的库仍停留在 schema 53,直到下次占槽迁移。
- 不打开 shadow/replace 开关。
- 不实现 trace_reviewer 与 D7 删除传播。
## 步骤
1. [x] 迁移与保存错误语义。
2. [x] lineage 版本改读文档版本。
3. [x] `go test` 覆盖写失败与版本选择。
## 验收标准
- [x] 无法连接数据库时 `SaveChatSummary` 返回错误,且结果 `Persisted=false`。
- [x] 无连接池的测试存储仍可读写摘要。
- [x] 文档版本为 4 时 lineage 版本为 4;缺失时仍为 1。
## 相关链接
- 整改方案: [2026-09-20-capability-enablement-impact-plan.md](../../remediation/2026-09-20-capability-enablement-impact-plan.md)
## 证据 / 备注
2026-09-20 本地 `go test`(未占集成槽、未执行迁移):
- `TestSaveChatSummary_DatabaseFailureIsNotSuccess` PASS(连接拒绝时返回错误,`Persisted=false`)
- `TestGenerateRollingSummary_RecordsRevisionAndMessageSpan` PASS
- `TestRollingSummarizer_LifecycleAndFactPreservation` PASS
- `TestLineageVersion_UsesDocumentVersion` PASS
- `TestMigrationGate_ExpectedFiles` PASS
goose `00058` 仅入库。dev/test 进程仍是 schema 53,要等下次占槽启动才会建表。
@@ -0,0 +1,39 @@
---
title: "test 环境 beta.6 晋升与助手/小队验证"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: docs/test-env-beta6-verification
worktree: "-"
mutex: infra+docs
---
# test 环境 beta.6 晋升与助手/小队验证
## 目标
手工晋升 `dev`→`test` 打 `rc-v1.0.0-beta.6`,schema 56,完成助手/小队 C 级验收与 12 项回归,恢复 S1,落盘报告。
## 范围
- merge+tag on `test`(无在主干直接开发 commit)
- test 容器重建与 C 级验证
- docs 分支报告与 CURRENT 更新后合回 `dev`
## 非目标
- 不碰 main;不改项目 143;不启用 FAV_DEGRADED_READ / MULTI_INTENT_PLAN_TIER=full
## 步骤
1. [x] S0 快照 + merge/tag beta.6
2. [x] rebuild → schema 56 + CSP
3. [x] S1 快照
4. [x] 助手 / 小队 / 回归
5. [x] restore S1 + 清理 workspace
6. [x] test-report + CURRENT → merge dev
## 验收
- [报告](../../test-reports/2026-09-20-test-env-beta6-assistant-squad-test-report.md)
@@ -0,0 +1,55 @@
---
title: "test 环境三问题整改(重名/成员可见/文档预览)"
status: done
created: 2026-09-20
updated: 2026-09-20
owner: Cursor-Auto
branch: fix/test-env-triage-2026-09-20
worktree: "-"
mutex: projectworkflow+chat+assets
---
# test 环境三问题整改(重名/成员可见/文档预览)
## 目标
修复 test 环境实测发现的三项缺陷:全局项目名唯一、成员拉入后可见项目/会话、上传文档可服务端回退预览。
## 范围
- 迁移 `00057`:全局唯一项目名索引 + 存量改名
- 应用层创建项目校验改为全局查重
- 拉人入项目后自动建成员私有会话;upsert 允许项目管理员代注册
- 资产 raw 下载端点 + 前端预览服务端回退
- test 库数据修复(退役项目 4、修会话归属、补陈威会话)
## 非目标
- 不改项目 143 / SWBOOT / FAV
- 不物理删除项目 4(仅 `demo_retired`)
- 不改变跨环境数据隔离
## 步骤
1. [x] 迁移 00057 + 应用层全局重名校验
2. [x] 会话归属修复(拉人建会话 + upsert 代注册)
3. [x] 资产 raw 端点 + 前端预览回退
4. [x] 单测 / vet / npm test
5. [x] 合入 dev 冒烟
6. [x] test 库数据修复 + 端到端验证 + 报告
## 验收标准
- [x] test 库无重名项目;跨用户创建重名返回 409
- [x] 陈威登录可见项目 5 与会话 `sess-p5-u35`
- [x] 刷新后 PDF 可通过服务端 raw 回退预览
- [x] `go vet ./...` + `go test -short ./...` + `cd web && npm test` 全绿
## 相关链接
- Test report: [.doc/test-reports/2026-09-20-test-env-triage-fixes-test-report.md](../../test-reports/2026-09-20-test-env-triage-fixes-test-report.md)
- Data fix: [scripts/fix-test-env-triage-data.sql](../../../scripts/fix-test-env-triage-data.sql)
## 证据 / 备注
- merge: `213ad015`;test schema 57;E2E ALL_PASS(见报告)
@@ -0,0 +1,347 @@
---
title: 文档编制人兼任审核批准 - Plan
type: feat
date: 2026-09-17
status: planned
artifact_contract: ce-unified-plan/v1
product_contract_source: ce-plan-bootstrap
execution: code
---
# 文档编制人兼任审核批准 - Plan
## Goal Capsule
在系统管理员授权后,项目创建者可以为项目工作流中的每份文档单独启用「编制人兼任审核、批准」,只选择一位编制人即可完成该文档的全部人工职责。
本次交付为设计方案,尚未授权业务实现。已确认的需求是两级授权和逐文档配置。R9(激活前配置/激活后冻结)与 R10(关总开关后存量按冻结继续、不提供紧急熔断)已于 2026-09-17 审核批准,并补强 Heal 三入口投影稳定性为硬性验收项。实现与发布须分别提供源码、数据库、真实产品 PI 和浏览器证据。
基线为本地 `dev@adb48c8`,2026-09-17 源码核查;不代表正在运行的镜像已具备本能力。远端已 fetch,本地 dev 领先 origin/dev 44 个提交、落后 0。本方案不修改正式工作流定义,不将兼任等同于免审批。
---
## Product Contract
### Summary
新增管理员总开关,默认关闭;新增逐文档职责模式,默认沿用当前规则。创建者开启某份文档的兼任模式后,只填写编制人,审核人与批准人由服务端派生为同一人。仍执行送审、审核和批准,保留每一步身份、意见和时间。
### Problem Frame
当前系统仅允许可选文档三职全空或三职完整指定,且完整指定时要求三人不同。用户需要小团队或个人也能执行完整的文档治理流程,并由管理员控制这一例外是否可用。
当前权限、文档人员投影和前端角色识别使用不同数据路径。因此仅放宽三职分离校验不足以支持本需求,还必须保证配置、生成、查看、修改、审批和阶段推进使用同一份职责来源。
### Requirements
**权限与配置**
- R1. 仅系统管理员可开启或关闭系统级「允许编制人兼任审核、批准」权限,默认关闭。
- R2. 仅权威项目创建者可为自己创建的项目逐文档选择兼任模式;普通成员、项目角色管理员和其他项目创建者不能设置。系统管理员如果不是该项目创建者,也不因此获得逐文档配置权。
- R3. 每份文档独立选择,管理员开启总权限不自动修改任何项目或文档;新文档、新实例和复制产生的文档默认不继承兼任授权。
- R4. 兼任文档必须指定一名有效、在任的项目成员为编制人;可以不是创建者。审核与批准由该人承担,不能再指定其他审核人或批准人。
**审批与可见性**
- R5. 兼任模式属于纳入人工审批:保留送审→审核→批准三个动作、现有内容锁和驳回要求;不得生成完成后自动批准或通过阶段门禁。
- R6. 未开启兼任的文档继续遵守当前三职分离与可选免审批规则;必需文档不得借兼任模式省去编制人或审批。
- R7. 设置页、冻结快照、文档详情、操作按钮、签署展示与日志一致显示兼任关系;同一个人能在正确状态执行对应职责动作。
- R8. 兼任不授予系统管理员、创建者或其他成员代审权,也不扩大跨项目读取、非当前阶段写入和已结束实例写入权限。
**生命周期与持久化(已审核批准,2026-09-17)**
- R9. 首期仅在工作流激活前配置;激活时冻结该文档模式和职责,运行中的实例不直接改规划。已激活的存量项目不自动转换。若用户要求运行中转换,必须先扩展本方案的受控职责变更单元,不可悄悄放开现有 PUT。
- R10. 管理员关闭总开关后,禁止新启用、保存仍含兼任的规划和激活兼任规划;允许清除兼任后保存。已激活的兼任实例按冻结授权继续执行,历史日志不变。界面必须解释该开关是「授权新配置」,不是紧急停用所有存量审批;本期不提供针对已激活实例的紧急撤销/熔断能力。
- R11. 模式、编制人、授权依据、配置版本及各步骤日志需持久化,刷新、重登和服务重启不得丢失。
- R12. 编制人离任或账号停用后,不得继续执行三项职责;阻断尚未完成动作并展示原因,不自动找替代人,不重写历史签署。
### Permission Matrix
| 操作 | 系统管理员但非项目创建者 | 当前项目创建者 | 普通项目成员 | 其他项目用户 |
|---|---|---|---|---|
| 修改系统总开关 | 允许 | 仅同时为系统管理员时 | 禁止 | 禁止 |
| 查看本项目可用模式 | 沿用当前项目读取权限 | 允许 | 沿用项目读取权限 | 禁止 |
| 规划期逐文档启停兼任 | 禁止 | 总开关开启才可启用;可关闭 | 禁止 | 禁止 |
| 指定编制人 | 禁止 | 规划期按 R4 | 禁止 | 禁止 |
| 送审、审核、批准 | 仅自己是该文档指定职责人时 | 同左 | 同左 | 禁止 |
| 已激活实例直接改职责 | 禁止 | 禁止(R9) | 禁止 | 禁止 |
### Mode Matrix
「文档启用」「纳入人工审批」「编制人兼任」是不同含义,不能复用一个开关。
| 文档状态/配置 | 输入 | 有效职责 | 审批与门禁 |
|---|---|---|---|
| 文档禁用 | 不设置职责 | 无 | 沿用 skipped_disabled |
| 可选文档免审批 | 三职全空,兼任关闭 | none | 沿用既有免审批规则 |
| 标准人工审批 | 三职齐全且三人不同 | full | 保留正常人工审批 |
| 兼任人工审批 | 兼任开启,仅编制人 A | author_only;有效三职为 A/A/A | 与标准审批同样要求最终批准 |
| 未开兼任却只填 A | 缺审核和批准 | partial | 拒绝 |
| 标准模式填 A/A/A | 三职同人 | 非法 | 继续拒绝职责分离违规 |
| 兼任开启但无 A | 缺编制人 | 非法 | 拒绝 |
| 兼任开启又填不同审核人 B | 矛盾输入 | 非法 | 拒绝,不能静默吞掉 B |
### User Flows
1. 管理员进入「系统管理台→系统设置→工作流治理」,开启总授权;页面显示保存结果、修改人和修改时间。
2. 创建者进入项目设置,展开某个阶段,在文档行开启「由编制人兼任审核、批准」。只保留编制人选择器,其余两项显示「同编制人(自动承担)」。其他文档保持原配置。
3. 保存并预览:摘要列出标准审批、兼任审批、免审批的份数,列出每份兼任文档及编制人。确认后冻结。
4. 编制人完成内容后送审,在审核中以审核人身份确认,在批准中以批准人身份确认;日志展示同一人对应三个职责,而非三个虚构人员。
5. 页面刷新、重新进入项目后仍显示同样配置;最终批准后才按现有阻塞条件满足阶段门禁。
### Scope Boundaries
本期覆盖所有通过项目工作流实例管理的文档,不针对某个任务名写白名单;freeform 文档与未绑定工作流的旧文档不提供此开关。不新增批量全选、不改项目成员全局 `document_duty` 为多角色,不自动改已发布工作流模板或历史签署。
**生命周期口径(已审核批准,2026-09-17):** R9 首期仅激活前配置、激活后冻结职责;R10 关闭总开关后禁止新启用/保存仍含兼任的规划/激活兼任规划,已激活实例按冻结授权继续执行。总开关是「授权新配置」,**不提供**已激活实例的紧急撤销/熔断能力;若业务需要合规级紧急止损,应作为独立后续方案,不在本期 Definition of Done 范围内。
---
## Planning Contract
### Current Implementation Evidence
以下为源码确认事实,不是运行验收结果。
| 位置 / 符号 | 当前行为 | 对本需求的影响 |
|---|---|---|
| `internal/projectinstance/types.go`:DocTaskPlan / DocDuty | 仅 enabled、approval_configurable 和三职 ID,无逐文档兼任标记 | 增加显式职责模式 |
| `internal/projectinstance/duty_mode.go` | none/partial/full;partial 拒绝;三职重复报 SEPARATION_OF_DUTY_VIOLATION | 不能只填作者或仅关闭分离校验 |
| `internal/projectinstance/validator.go`:validateActivationPlan / previewSummary | 激活至少 countFullDutyDocs>0;预览统计 full/none | 必须把合法兼任计为受治理文档 |
| `internal/projectinstance/service.go` | 创建者可保存/预览/激活;active 后 ErrPlanFrozen;已有 revision、plan hash、token | 复用规划流程,补全授权版本和事务检查 |
| `internal/projectworkflow/service.go`:IsProjectCreator | 权威项目创建者检查 | 不使用 UI 当前角色或项目 manager 代替 |
| `internal/projectinstance/store.go`:sync 子实例逻辑 | 从规划写 project_doc_task_instances 和三职 assignment | 兼任需派生三项实际职责,不能只存作者而漏审批归属 |
| `internal/projectinstance/duty_action.go` / `stage_access.go` / `gate.go` | 按动作校验单一职责;阶段可见性有 full 判定;门禁依赖 approved | 校验与阶段可见性都需认识新模式 |
| `internal/sysadmin/settings.go` / `store.go` | 白名单设置、DB 持久化;无该 key;只记录最后修改人时间 | 可复用管理入口,新增策略消费与历史审计 |
| `internal/server/admin_system_handlers.go` | 所有系统设置写入 requireSystemAdmin | 复用该入口,不开放管理列表给普通成员 |
| `internal/docduty/store.go`:HealProjectDocuments | 按项目成员默认职责扫描并回填所有 task_key 非空文档 | 可能覆盖逐文档三职,必须区分实例绑定与旧默认 |
| `internal/bizdev/service.go` / `internal/docgov/project_docs.go` | 生成后、列表读取时调用 HealProjectDocuments | 重开页面即可触发回填,必须验证刷新后仍一致 |
| `internal/docduty/revoke.go` | 成员职责变化撤销审核/批准槽位,随后参与 heal | 不能把项目默认职责变化误当成逐文档兼任变更 |
| `internal/server/handlers.go`:三个 DocGov 决议 handler | 使用登录身份及动作固定 author/reviewer/approver;先执行工作流鉴权 | 服务端已有按动作身份模型,应保留 |
| `internal/docgov/state_machine.go` | drafting/reviewing/approving/approved;检查对应职责 ID;无额外三人不同判断 | 复用状态机,测试身份一致和锁定边界 |
| `web/src/lib/currentDocRole.ts` | author 命中后立即返回,不支持同时三职 | A/A/A 会一直被当成 author |
| `web/src/lib/docGovActionVisibility.ts` / `DocGovActionBar.tsx` | 按单一 currentRole 显示送审/审核/批准 | 必须改为动作能力或多职责判断 |
| `web/src/lib/projectSettingsDuties.ts` / `ProjectSettingsModal.tsx` | 重复服务端 full/none 校验,人工审批默认要求至少三人 | 单成员兼任会被前端提前挡住 |
| `deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql` | assignment 唯一键是任务实例+职责,无跨职责用户唯一限制 | 同一用户可有三条职责记录,不必拆用户身份 |
| `deploy/postgres/goose/00049_2026-09-17-system-settings.sql` | system_settings 已存在 | 采用增量迁移,不重建设置机制 |
相关历史边界参见 `.doc/test-reports/2026-09-14-governance-action-level-authz-test-report.md` 与 `.doc/test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md`。它们说明已有验收意图,本次未重跑其测试。
IDE 所列 rdev 设计、short-term 和 backlog 当前位于 `feature/rdev-template-depth` 的独立工作区,不在本方案 dev 基线;已读取作兼容输入。rdev 的关闭文档/N/A、阶段前置、任务键命名空间化保持原语义。本方案按实例+阶段+任务身份绑定;待 rdev 合入后增加对应回归,不宣称其已在 dev 发布。
### Key Technical Decisions
- KTD1. 新增 `duty_policy`,值为 `separated` / `author_only`,属于 DocTaskPlan 的逐文档配置。缺省按 separated 解读;none/partial/full 仍是职责完整度,不能把「免审批」和「兼任」混为一谈。统一提供按任务解析模式、有效职责、是否受治理的领域能力;原 ClassifyDocDuty 保留给旧调用,治理调用迁到新解析器。(R3–R6)
- KTD2. 配置快照保存用户意图:author_only 的 duties 规范形式只含 author_user_id。服务端通过唯一解析器派生有效 A/A/A,写三条 document_duty_assignments,并投影到 document_records 的三个 ID/名称。读接口区分配置职责与有效职责,客户端不得把有效 A/A/A 原样误写成标准配置。(R4、R11)
- KTD3. 新设置 key 建议 `workflow.allow_author_only_approval`,类型严格 bool,默认 false,无环境变量绕过,保存无需重启。projectinstance 通过窄的策略读取接口消费,由 app 装配注入;不从领域服务调用 HTTP,不让 projectinstance 成为 sysadmin 设置表的第二写入 owner。(R1)
- KTD4. 配置写入、预览和激活都复核总授权;真正激活必须在事务内对授权版本复核,并与关闭总开关串行化。token 绑定 plan hash、项目/规划版本、授权 revision。总开关 false→true 后旧 token 仍作废,不能以「当前又是 true」放行。(R10、R11)
- KTD5. 实例绑定文档的职责权威是冻结 DocTaskPlan,经解析生成 assignments 和文档投影。项目成员 document_duty 只供旧无实例文档的默认分配。heal/revoke/生成/通知不得再次用项目默认人员覆盖实例文档。(R3、R7、R12)
- KTD6. 运行时按具体动作检查有效职责和当前在任状态;状态机仍按 author/reviewer/approver 记录实际动作角色。前端采用服务端动作能力集驱动按钮,可同时拥有多个职责,保留 viewer fail-closed,不新增一个可以绕过所有检查的万能角色。(R5、R7、R8)
- KTD7. 遵守 R9 的冻结边界;未知 mode、缺失授权来源或绑定不唯一时拒绝写动作。历史缺字段只代表旧 separated,不自动解释为兼任;不能全库 A/A/A 回填。(R6、R9、R11)
### Data Model
以下是设计契约,字段落位按 owner 边界实现,不是现有字段清单。
| 数据 | 建议新增/扩展 | 用途与兼容 |
|---|---|---|
| system_settings | 目标 key;monotonic revision(默认 0) | 总权限 CAS、token 失效;目标行在迁移时初始化 false,避免无行锁问题 |
| 系统设置审计 | 仅本策略必需的 before/after、revision、actor、时间、request ID | 与设置更新同一事务提交;不把整站审计改造扩大到本期 |
| DocTaskPlan JSON | duty_policy,可选且旧值缺省 separated | 逐文档意图,纳入 plan hash;兼容 old hash 的序列化须有固定样本 |
| workflow instance 授权快照 | policy key、revision、允许状态、activated_by/at | 记录激活时获准的依据;由服务端生成,拒绝客户端伪造 |
| activation token | policy revision(新字段或令牌存储的版本化元数据) | 防预览后管理员撤销授权;旧 token 含兼任无 revision 必须重新预览 |
| document_records | doc_task_instance_id 可空外键 | 对新实例创建文档强制绑定;旧文档仅唯一匹配才回填,不修改历史职责 |
| document_duty_assignments | 复用三角色,兼任三行 user_id 相同 | 无需放宽角色唯一约束;author 必须有效且正数 |
| 文档视图 | duty_policy、effective_duties、allowed_actions、blocked_reason | 以服务端计算值展示;读参数不能切换权限 |
| 文档审计 details | duty_policy、instance/task ID、授权 revision | 送审/审核/批准均记录真人身份及该次 action role |
不预占 Goose 序号:实施时根据 dev 与并行 rdev 分支最新迁移取下一个空闲序号。迁移需覆盖 PG store 与 memStore 的字段 round-trip。兼容旧数据时禁止把 NULL 改成 0 外键。
### High-Level Technical Design
职责解析链:
```mermaid
flowchart TB
A[管理员总授权] --> B[创建者逐文档配置]
B --> C[保存与预览校验]
C --> D[事务内复核授权并激活]
D --> E[冻结实例配置与授权依据]
E --> F[统一解析有效三职]
F --> G[职责表与文档人员投影]
F --> H[动作鉴权和阶段可见性]
H --> I[前端能力与操作按钮]
G --> J[文档状态机与审计]
```
兼任保留原审批状态机:
```mermaid
stateDiagram-v2
drafting --> reviewing: A以编制身份送审
reviewing --> approving: A以审核身份通过
reviewing --> drafting: A审核驳回并填写原因
approving --> approved: A以批准身份通过
approving --> drafting: A批准驳回
approving --> reviewing: 现有配置允许时退回审核
```
新授权和冻结授权的判断路径:
```mermaid
flowchart TB
A[请求] --> B{规划配置或激活?}
B -->|是| C{权威创建者且planning?}
C -->|否| X[拒绝]
C -->|是| D{含author_only?}
D -->|否| E[原职责规则]
D -->|是| F{总授权有效且版本一致?}
F -->|否| X
F -->|是| G[检查作者与输入一致性]
B -->|运行时动作| H[查冻结策略及实例任务绑定]
H --> I[检查成员有效性 当前阶段 状态和租约]
I --> J[按动作职责执行]
```
激活事务与设置撤销都以策略行锁形成先后顺序,再按统一顺序获取项目职责锁和实例相关行锁。策略 owner 提供事务兼容读取/锁定适配;不能照搬在事务外重查布尔值的方式。原则:关闭先提交则激活失败;激活先提交则成为 R10 中可继续的存量实例。并行成员移除与激活也必须在同一项目职责锁语义下判定,不能在事务开始前检查后直接信任。
### API Contract
| 接口 | 变更 | 服务端强制条件 |
|---|---|---|
| GET/PUT `/api/v1/admin/system/settings[/{key}]` | 注册总开关;目标 key 增加 expected_revision,返回新 revision | requireSystemAdmin;严格拒绝 null、字符串布尔;审计与值同事务 |
| GET `/api/v1/projects/{id}/settings` | 返回精简 governance_policy capability、revision 与 blocked_reason | 保留项目访问校验;不泄露其他系统设置 |
| PUT `/api/v1/projects/{id}/workflow-plan` | 每个文档可传 duty_policy;兼任只传 author ID;沿用规划版本 | 创建者、planning、总授权、有效成员、输入无矛盾 |
| 激活 preview / activate 现有接口 | 预览分列兼任文档;token 绑定策略 revision | 保存成功不等于已获激活授权;提交时重新事务校验 |
| 文档详情和项目文档列表 | 返回模式、有效三职与允许动作 | 统一来源;任务身份、实例身份须匹配 |
| docgov 送审/审核/批准接口 | URL不变,增加模式审计上下文 | 登录用户+对应 action,不信任请求的 user_id/user_name |
建议新增错误码:`AUTHOR_ONLY_POLICY_DISABLED`(403)、`AUTHOR_ONLY_POLICY_CHANGED`(409)、`AUTHOR_ONLY_AUTHOR_REQUIRED` / `AUTHOR_ONLY_DUTY_CONFLICT` / `UNKNOWN_DUTY_POLICY`(400 validation issue)、`DUTY_BINDING_AMBIGUOUS`(409)、`DUTY_ASSIGNEE_INACTIVE`(403)。总权限存储不可用返回 503;缺失目标配置采用默认关闭,但数据库故障不能伪装成正常缺项。保留已有 PLAN_FROZEN、PLAN_REVISION_CONFLICT 与 SEPARATION_OF_DUTY_VIOLATION。
`author_only` 写入审核/批准 ID:省略或 0 为规范输入;若为与作者相同的正数,可规范化为省略以兼容回显,但若不同则拒绝。关闭兼任时清除派生审核/批准,要求重新选择符合分离规则的人员;旧选择可仅作为未保存草稿提示,不自动恢复为真实授权。
### UX Details
系统设置开关说明写明 R10,并展示预计受影响的待激活兼任文档数量及存量继续执行说明。保存失败保留用户输入和错误,不在本地假装开启成功。多管理员同时修改返回版本冲突,不自动覆盖。
项目设置按文档行提供兼任选项;总权限关闭时禁用并解释来源;非创建者只读。兼任只能在文档已启用且纳入人工审批时选择。兼任文档仅需一位成员;混合方案只要仍存在标准人工审批文档,才继续提示至少三位有效人员。
总开关在页面打开期间被关闭时,保存失败展示定位到文档的原因,提供关闭兼任选项;不丢弃整份未保存规划,不自动重试激活。预览和冻结视图同时展示「角色指派数」和「实际人数」,避免 A/A/A 被误认为三个人。
文档正文签署区显示真实姓名及兼任标记,但未发生审核/批准时不得显示签署时间或声称已通过。按钮随状态变化,审阅阶段即使当前人也是作者也不能编辑锁定正文;驳回后恢复编辑。查看/认领按当前状态或明确动作记录相应角色,不能打开一次页面就伪造三次履责。
### Risks and Compatibility
1. **回填覆盖(硬性门禁,非偶然安全):** `HealProjectDocuments` / `ApplySlotRevocations` 与 `ConfigSnapshot` 是独立职责写路径,当前不区分实例绑定文档。实现必须在 heal/revoke 增加「实例绑定文档跳过项目默认覆盖」显式分支,禁止依赖「只填缺失槽位、碰巧不覆盖」的偶然安全。U3 必须对三入口(文档生成、列表 GET、成员变更)及 author 被误判非在任时的 healSlot 分别证明投影不变;未通过不得开放 UI。
2. **历史身份混淆:** 不以 project_id+task_key 跨实例盲绑;旧文档匹配多实例则保持原记录并报可定位问题。新生成文档必须携带 task instance ID,无法绑定应停止受控写入。
3. **成员退出:** runtime 复核在任资格覆盖 author_only;保留冻结快照用于历史展示。普通成员默认职责改变不得影响冻结文档;真实退出/停用应阻断动作。暂不新增运行中换人 UI。
4. **并发审批:** 同一人可打开多个标签,服务端仍需保证状态比较/版本检查;重复请求不能重复创建批准事件、版本封存或推进通知。延迟到达的审核请求不能作用于后续修订版本。
5. **通知与事件:** 审核待办发给同一人是有效业务,不可因发送者=接收者一概过滤。按事件+接收者去重,不把审核与批准两项待办合并成一个动作。
6. **回滚:** 关闭开关只停止新配置,不能安全地把已存在兼任实例交给完全不识别新模式的旧二进制。上线后若需回退代码,保留模式识别与冻结策略读取兼容补丁;不得通过清空审核/批准人员回滚。
7. **总开关非紧急熔断(R10):** 关闭总授权不会阻断已激活兼任实例的剩余送审/审核/批准。界面与运维说明必须写明这一点,避免被误解为「关总开关=紧急止损」。存量紧急撤销不在本期范围。
---
## Implementation Units
### U1. 策略存储与总授权
目标:提供管理员可写、项目治理可可靠消费的总授权。覆盖 R1、R10、R11,采用 KTD3、KTD4。
文件:`internal/sysadmin/settings.go`、`store.go`、`internal/server/admin_system_handlers.go`、`internal/app/` 装配、增量 Goose 迁移;必要时新增 sysadmin 内的策略审计存储文件。
实现重点:默认关闭;严格 bool;目标设置 revision 与 CAS;事务内审计;窄接口可参与激活事务。仅本 key 要求的新协议不破坏其他设置键调用。
测试场景:管理员开关成功;普通用户伪造 PUT 被拒;null/字符串拒绝;DB断开不放行;并发修改只一个版本成功;审计写失败时设置回滚;重启读回。
### U2. 逐文档模式、规划校验与激活
依赖 U1。覆盖 R2–R6、R9–R11,采用 KTD1、KTD2、KTD4、KTD7。
文件:`internal/projectinstance/{types,duty_mode,validator,service,store,hash,tx,errors}.go`、`internal/server/project_settings_handlers.go`。
实现重点:新增模式解析;所有 full-only 分支改为正确的受治理判断;保存、预览、激活一致;任务禁用/免审批清除模式;有效成员检查;规划 hash/授权 revision 和确认 token 一致。保存快照与提升 plan revision 应原子化,失败不能留下可读取的新规划配旧版本。
测试场景:一位成员、至少一份合法兼任文档可激活;只填作者但未开模式仍拒绝;混合 full/none/author_only;其他项目创建者、非创建者管理员拒绝;修改总授权后旧 token 拒绝;激活与撤销并发的两种提交顺序;旧 separated snapshot/hash 兼容。
### U3. 文档绑定与职责投影一致性
依赖 U2;这是开放 UI 前的必要门禁。覆盖 R3、R4、R7、R11、R12,采用 KTD2、KTD5。
文件:`internal/docduty/{store,resolve,revoke}.go`、`internal/docgov/{types,engine,project_docs,repository}.go`、`internal/bizdev/service.go`、`internal/projectinstance/store.go`、任务执行请求与 app 适配、增量迁移。
实现重点:新文档绑定具体任务实例;受治理实例职责优先;统一有效职责映射用于创建、读取、heal、memStore;legacy fallback 仅在明确无实例时可用。`HealBinding`/`healSlot`/`ApplySlotRevocations` 对已绑定 `doc_task_instance_id` 的文档必须显式跳过项目默认覆盖,不得因 author 被误判非在任而重新分配默认人。旧已批准文档不因新功能读取被改写签署人员。
测试场景:同项目两份兼任文档由不同作者承担;第三份标准审批三人;第四份 none;反复 GET/成员默认角色调整/重启后四份职责均不串;未知或歧义绑定阻断;旧无实例文档仍按既有规则;NULL外键正常。**硬性投影稳定性(开放 UI 前门禁):** 已激活 author_only 文档在以下三入口触发 `HealProjectDocuments` 后,`document_records` 与 assignments 投影必须保持 A/A/A——(1) 仅刷新文档列表(`ListWorkflowDocumentsByProject`);(2) 文档生成完成(bizdev);(3) 成员变更后 heal。另测:author 被误判为非在任成员时,healSlot 不得把审核/批准槽位改写为项目默认人;真实离任仍按 R12 阻断写动作且不自动替人。
### U4. 动作鉴权、文档状态机与事件
依赖 U3。覆盖 R5、R7、R8、R12,采用 KTD6。
文件:`internal/projectinstance/{duty_action,document_access,stage_access,gate}.go`、`internal/server/{stage_access_helpers,handlers,document_revision_access}.go`、`internal/app/docflow/`、`internal/docgov/`、相关通知订阅与审计视图。
实现重点:有效三职与在任状态统一判定;三个动作使用不同 action role;归档/修订账本与事件沿用既有事务机制;审核、批准不能跳状态,租约和内容 hash 不因同人而失效。Audit details 增加模式及来源。
测试场景:A顺序三动作成功且三份日志身份真实;其他成员/创建者/管理员越权失败;作者退出后全部写动作拒绝;审核中改正文失败;驳回原因必填;跨标签重复批准只产生一次有效终态事件;审批针对旧版本内容被拒;阶段直到最终批准才可推进。
### U5. 系统设置与逐文档 UI
依赖 U1、U2,可与 U3/U4 开发隔离进行,联调必须等待后端完整。覆盖 R1–R4、R7、R9–R11。
文件:`web/src/components/admin/console/sections/SettingsSection.tsx`、`web/src/components/project/ProjectSettingsModal.tsx`、`web/src/lib/projectSettingsDuties.ts`、`web/src/types/projectSettings.ts`、`web/src/api/projectSettings.ts`。
实现重点:按 UX Details 配置、错误定位、人数要求、预览和冻结展示;策略 capability 来自项目 settings,而非向普通用户开放 admin settings。文档模式在不同阶段展开折叠后不串行。
测试场景:单成员可配置兼任;混合标准模式仍提示三人要求;非创建者只读;系统开关关闭时禁用及保存失败保留草稿;切换文档、刷新、重新登录后模式不变;已激活项目仍冻结。
### U6. 多职责动作展示和真实闭环验收
依赖 U3–U5。覆盖 R5–R8、R11、R12,采用 KTD6。
文件:`web/src/lib/{currentDocRole,docGovActionVisibility,controlledDocHydrate,deliverableSync}.ts`、`web/src/components/doc/DocGovActionBar.tsx`、`web/src/App.tsx`、文档 API/types、相关 UI/PG/真实 PI 测试与报告。
实现重点:消费服务端动作能力,多职责不再被 author-first 短路;认领、提案、修订、按钮与日志一致;受控文档不按名字提权。证明刷新及重启保持一致后再开启真实项目配置。
测试场景:真实产品 PI 生成→A打开文档→送审→审核→批准→版本/日志→阶段门禁;标准和免审批文档并存;不同用户负例;两标签并发、刷新重开、重启;rdev 合入后复验 rd_ 文档及旧键兼容,不改 N/A 行为。
---
## Verification Contract
本方案阶段未运行业务测试,以下为实现阶段必须提交的证据。
| 层级 | 覆盖 | 通过标准 |
|---|---|---|
| Go 单元 | 策略值、模式解析、权限矩阵、状态、门禁、hash | 所有模式边界及错误路径可重复验证 |
| PostgreSQL 集成 | 设置审计原子性、并发撤销/激活、成员退出、三职责落库、投影绑定;HealProjectDocuments 三入口对实例绑定 author_only 文档投影不变 | 实际事务交错结果符合 KTD4;失败不留下半成品;列表 GET/生成/成员变更均不得覆盖冻结 A/A/A |
| 前端单元/构建 | 单成员配置、双层开关、多职责按钮、错误恢复 | 测试与构建通过,无同人只见作者按钮 |
| HTTP 负例 | 修改请求身份、跨项目、非创建者、未知模式、关闭总授权 | 服务端拒绝,不能依赖隐藏按钮 |
| 浏览器 E2E | 管理员开关→创建者逐文档设置→A全部动作→其他人被拒 | 真页面操作、日志可见;无 API 直写替代关键步骤 |
| 产品 PI E2E | 正式生成及既有修订/租约流程 | 使用仓库要求的真实产品 PI + MiniMax;stub 仅作前期定位 |
| 持久化 | 刷新、重开、重登、服务重启 | 模式、职责、审核状态、版本和审计一致 |
| 回归 | 既有 full/none、标准三人分离、freeform、legacy、终止实例 | 原有权限和生命周期边界不退化 |
实现时执行 PROJECT 规定的 `go vet ./...`、`go test -short ./...`、前端 `npm test` 与 `npm run build`,以及使用隔离测试库的 PG 集成和明确启用的真实 PI 测试。不得把 skip 当 pass。共享容器重建验证必须在主仓占 CURRENT 集成槽位后执行;worktree 不启停共享容器。
重点验收样例:
- AE1(R1–R4):管理员开启后,创建者在文档甲选择 A,在文档乙选择 B;甲/乙有效三职分别为 A/A/A、B/B/B,互不影响。
- AE2(R5–R8):A只能按状态依次送审、审核、批准;未批准前门禁阻塞;另一个管理员无该文档职责仍被拒。
- AE3(R6):总开关开启但文档未勾选,A/A/A仍拒绝;三职空仅对原来允许免审批的文档合法。
- AE4(R10、R11):预览后总开关关闭再打开,旧 token 409;已先完成激活的实例刷新后仍可按冻结策略办理。关闭总开关不得阻断已激活实例的剩余审批动作(非紧急熔断)。
- AE5(R7、R11):项目成员默认审核人改为 C 后,读取兼任文档仍显示 A/A/A,不改历史签署;列表、正文及按钮一致。
- AE5a(R7、KTD5):已激活 author_only 文档在仅刷新文档列表(触发 `ListWorkflowDocumentsByProject` → `HealProjectDocuments`)后,投影仍为 A/A/A,不被项目默认职责覆盖。
- AE5b(R7、KTD5):文档生成完成与成员变更后 heal 两入口分别复测 AE5a;author 被误判为非在任时,healSlot 不得把审核/批准槽位改写为项目默认人。
- AE6(R12):A离任后保持历史名字,但所有新动作拒绝,不能被 heal 自动替换或按名字回退提权。
---
## Definition of Done
- [x] R9、R10 的生命周期口径经过用户审核(2026-09-17):批准「激活前配置 + 激活后冻结」与「关总开关仅停新配置、存量按冻结继续」;明确总开关不提供存量紧急熔断,该能力如需另立方案。Heal 三入口投影稳定性已升为 U3/Verification 硬性验收项。
- [x] U1–U6 全部完成且证据覆盖对应需求;管理员和创建者两个权限层级均在服务端生效。(short-term U1–U6 均为 `done`;U6 报告回链)
- [x] 配置、快照、assignments、document_records、前端、审计在同一任务身份下对齐。(U2–U4 + U6 闭环证据;规范存储仅 Author + 有效 A/A/A 投影)
- [x] 单成员兼任完整链与三人标准链均通过;不得只提交设置页截图。(U4 矩阵 + U6 HTTP/浏览器证据;标准分离回归见 U4/U2 单测)
- [x] PostgreSQL、真实产品 PI、浏览器、重启与跨用户负例分别标明结果及限制;AE5a/AE5b 必须有证据。(U3:`TestHealProjectDocuments_SkipsDutyLocked_PG` 等 duty_locked 过滤;U6:既有 PI 生成文档 + Playwright 徽标 + lizhuguan 403。限制:U6 未单独跑「刷新/重登/重启」专轮,依赖 schema 持久化与 rebuild 后复测)
- [x] `.doc/test-reports/` 有验收报告并回链任务和 FEATURE-MATRIX;无新增已确认发布 blocker 才保持 gap-matrix 原结论。([U6 报告](../test-reports/2026-09-17-document-author-only-u6-test-report.md);变更提案 HTTP 另记 [audit](../audit/2026-09-17-docgov-modification-proposal-http-gap.md),不升为发布 blocker)
- [x] 发布先迁移与部署识别新模式的服务,再开放总授权;默认 off,试点后扩面。推送、dev集成与环境晋升状态分别报告。(**dev 已合入并 rebuild**:`merge: feature/document-author-only-plan` @ `09a9921`,health `schema_version=52`,总开关默认 off。**未做**:push origin/dev、test/main 晋升、开放总授权试点——需另授)
@@ -0,0 +1,214 @@
---
title: "首次加载与工作台初始化性能改进方案"
status: planned
created: 2026-09-17
updated: 2026-09-17
artifact_contract: ce-unified-plan/v1
product_contract_source: ce-plan-bootstrap
execution: code
---
# 首次加载与工作台初始化性能改进方案
## Goal Capsule
让用户首次访问就能快速看到并操作登录页,登录后优先恢复当前项目与会话,避免下载无关工具或等待所有项目初始化。
采用静态交付优化、按功能加载和请求去重,之后按测量结果优化认证与数据库读取(KTD1–KTD5)。本轮仅交付诊断和方案,业务代码尚未修改;用户授权实施后执行以下单元。
遵守 AGENTS.md/PROJECT.md、现有权限和文档治理契约。若优化要求改变授权、新增跨用户缓存、跳过职责正确性或删除历史数据,停止该单元并回报。每单元独立 feature/fix 分支与模块 mutex;合 dev/容器重建占集成槽。默认不推送,不晋升 test/main。
## Product Contract
### Problem Frame
[诊断](../audit/2026-09-17-initial-load-performance-audit.md) 已确认:8080 首屏 2.86 MB,CDP 10 Mbps 冷缓存登录可见 2.64 秒、2 Mbps 11.78 秒;再次访问约 60 ms。字体 CSS 外链阻塞首屏;3100 Vite 首访 207 请求/12.24 MB。登录后存在全项目成员扇出与会话重复同步,服务端认证、文档列表和会话统计有重复工作。
这些数字是单样本实验,不是用户实际公网体验或 p95。用户已确认 3100/8080/8081 在系统重启后首访约十数秒。现有容器启动到打印监听仅约 166/142 ms,不代表整机重启就绪;必须补齐重启矩阵再签优化收益。
### Requirements
- R1. 首次登录页只加载认证与基础样式所需资源,外部字体不可阻塞登录表单。
- R2. 登录后先显示可用工作台骨架,优先恢复当前项目/会话;其他项目成员、管理台、导出、文件预览在需要时加载。
- R3. 相同身份和查询键的初始化请求去重;慢响应、快速切换项目、登出/换人不会写回旧状态。失败必须有局部错误与重试入口。
- R4. 所有服务端授权和文档治理保持正确,权限撤销/停用不得因缓存继续放行。计数、摘要与正文沿用相同可见性语义。
- R5. 发布后旧页面仍可打开延迟模块;缓存不得导致 HTML 长期陈旧,也不得泄露用户 API 数据;SSE 流式延迟不能回退。
- R6. 优化收益用可复现冷/热缓存、慢网、字体不可达、多项目和大历史场景证明,结果与镜像/资源 hash 绑定。
### Success Criteria
以下是**拟定验收预算**,不是当前已达标数据。表中静态资源体积及绝对首屏时间预算适用于 8080/8081 构建入口;3100 保留 Vite 开发模式,不套构建产物压缩体积预算,其保留/空依赖缓存与预热状态分别由 U1 固定加载时间预算,U7 检查重启改善;U1 固定机器、Chromium 版本、样本与网络条件,预算不得在看到失败后悄悄放宽。
| 指标 | 目标/口径 |
|---|---|
| 未登录关键 JS 总传输量 | 开启压缩后 ≤250 KiB;按首屏实际请求总和而非只看入口文件 |
| 普通工作台首次可用前 JS 总量 | ≤600 KiB;不含用户明确打开的文档预览/导出模块 |
| 冷缓存登录可操作 | 10 Mbps / 80 ms、CPU 4 倍减速下 p75 ≤1.5 s;2 Mbps 同配置 p75 ≤3 s |
| 登录态热刷新 | 10 Mbps / 80 ms、CPU 4 倍减速下工作台可操作 p75 ≤1.5 s;前提必要 API 达下行预算 |
| 登录态冷刷新/登录提交成功后恢复 | 冷刷新自 navigationStart 起、登录自成功响应起,当前会话历史及输入区就绪 p75 ≤3 s;仅骨架不算完成 |
| 必要首屏 API | 同宿主 app↔DB 网络下 p95 ≤300 ms;列表大数据场景 p95 ≤500 ms,接口错误率不增加 |
| 首屏初始化请求 | 项目成员初始化从 N 次降为当前项目最多 1 次;静止初始化每个会话列表查询键最多 1 个在途请求且成功后不被成员更新重触发 |
| 字体故障 | Google 域名完全阻断或延迟 10 秒时,仍满足登录预算,不发首屏外部字体 CSS 请求 |
| 无回归 | 同数据/设备各阶段 p95 不劣化超过 10%;无新增跨用户暴露、错误循环、重复写任务 |
浏览器每场景 ≥20 次,报告 p50/p75/p95 与原始样本;接口每场景 ≥100 请求、并发 1/10/30。浏览器 p95 仅小样本诊断,不能冒充线上 SLO;稳定发布后再累计真实用户分位数。
### Scope Boundaries
包括浏览器入口、静态资源交付、当前工作台数据初始化、与首屏相关的查询。没有业务语义变更,不调整 PI 模型、Prompt、文档租约时长、授权范围或工作流门禁。
Deferred to Follow-Up Work:Redis/CDN、新 SSR 框架、全面 App.tsx 重写、全站统一数据框架、数据库分库、文档全文缓存。只有 U1 的证据表明必要时另开任务;目前不需要先增加基础设施。
### Outstanding Questions
- 待补测:已知端口 3100/8080/8081,重启涵盖宿主机/应用/Vite 的具体范围、慢发生阶段、真实网络与设备;不会阻止可独立证明的 U2/U3,但阻止宣称用户现场问题已经彻底解决。
- 待补测:登录态瀑布、真实数据规模、SQL/连接池等待;U6 的查询改写/索引必须由这些证据选择。
## Planning Contract
### Key Technical Decisions
- KTD1. 保留 React/Vite + Go 架构。正式体验使用构建产物入口;3100 保留开发热更新用途,不把开发模块请求数量当生产目标。先确认真实反代 upstream,不盲改 FRP。
- KTD2. 首屏用系统字体栈;需要保留 Inter/JetBrains Mono 时仅选必需 WOFF2 并同源部署、按需加载。保留 KaTeX 渲染所需字体,但不要求登录页加载数学资源。
- KTD3. 按功能边界动态 import,登录壳与工作台隔离;管理台、DOCX/XLSX 导出、Word/Excel 预览、Mermaid 按使用加载。仅 manualChunks 拆文件不能减少关键路径下载,必须验证依赖图没有静态回引。
- KTD4. 现有 Go serveSPA 作为默认静态交付修复点,构建期生成 gzip/br(若工具链已支持)而非每请求高压缩。若真实统一代理已负责压缩,则由它单层处理并记录;不得重复编码。哈希资源 `public,max-age=31536000,immutable`;HTML `no-cache`;压缩变体 `Vary: Accept-Encoding`;用户 API 不共享缓存。保留 identity、HEAD、条件请求、Range 正确性。
- KTD5. 将请求状态按身份/项目/会话/过滤器键管理,先用局部 hook/loader 和在途合并解决,不强制引入新数据框架。身份切换清空缓存与取消在途请求,成员更新不作为会话获取的依赖。未知成员/权限不靠全量成员预取推导:使用服务端明确的当前用户权限摘要,未就绪保持 fail-closed。
- KTD6. 请求内复用已认证 principal,授权不跨请求长期缓存。减少 session 续期写入须明确 idle TTL/绝对过期/撤销语义后再落地,保留停用与撤销实时检查。
- KTD7. 文档列表先保留治理正确性;先补齐所有写路径与历史修复,再移出 GET 同步 heal。轮询保持原有租约新鲜度,优先复用 SSE/可见性控制与单请求在途,不能直接延长租约或无限延迟 busy 显示。
### High-Level Technical Design
```mermaid
flowchart LR
A[HTML与同源基础样式] --> B[轻量认证壳]
B --> C[认证结果与工作台模块并行准备]
C --> D[当前用户可见项目与会话]
D --> E[当前项目权限与聊天窗口]
E --> F[可操作工作台]
F --> G[按需管理台/导出/预览]
```
有保存会话时,可在校验期间预加载不含用户数据的工作台代码;受保护 API 与用户内容显示仍由认证门禁控制。无会话时不加载工作台代码。项目/会话列表在认证后并行,解析有效当前项目后再发其范围内请求;不是让全站等待所有项目成员。
```mermaid
sequenceDiagram
participant UI as 浏览器
participant API as Go API
participant DB as PostgreSQL
UI->>API: 首屏必要请求(按查询键去重)
API->>DB: 验证当前会话/用户状态
API->>API: 请求内复用 principal / 权限解析
API->>DB: 当前页/当前项目数据
API-->>UI: 权限范围内的结果
UI->>UI: 核对身份与查询代次后更新
```
## Implementation Units
### U1. 固定完整性能基线(P0,约 0.5–1 天)
**Requirements:** R6;后续全部单元的依赖。
**Files:** 新增 `web/e2e/initial-load-performance.spec.ts`、诊断指标辅助模块;更新 `.doc/test-reports/`。本轮探针与结果可作为起点。
**Approach:** 固定真实入口、部署 hash、登录角色、项目数/历史量,捕获资源瀑布、FCP/LCP、长任务、输入区与历史就绪、必要 API TTFB。用专用验收账号/夹具测登录,不在真实会话发送诊断消息。先检查 GET 副作用,文档列表暂有 heal,数据库分析使用只读事务和 statement_timeout。分别测空缓存、热缓存、10/2 Mbps、CPU 4x、字体失联、1/30/100 项目与大历史。本轮不重启共享服务;实施时 U7 在隔离环境重现应用/依赖/宿主启动过程,记录 ready 与第一次导航的时间关系。
**Test scenarios:** 新浏览器、保存有效/过期会话、无项目、普通成员与管理员、慢 API/失败、项目快速切换;每份结果保留参数与原始样本但无 token/用户正文。
**Verification:** 形成基线报告,能回答耗时在哪一阶段,并确认性能指标可重复。登录态测量缺失不得用未登录测试代替。
### U2. 修复字体与静态资源交付(P0,约 0.5–1 天) — **done 2026-09-17**
**Dependencies:** U1 的未登录基线;**Requirements:** R1、R5、R6;**Files:** `web/index.html`、`web/src/styles/index.css`、`web/vite.config.ts`、`internal/server/server.go`、新增 `internal/server/static_assets_test.go`;必要时实际 Docker 构建文件。
**Approach:** 按 KTD2/KTD4 去除外部阻塞 CSS、提供压缩变体与明确缓存头。缺失 `/assets/*` 返回 404,不回退 HTML;客户端路由仍允许 SPA fallback。发布资源保留至少当前与上一版本并明确旧标签页支持窗口;窗口外加载失败提示用户保留编辑后刷新,不自动刷新丢失草稿。
**Test scenarios:** gzip/br/identity 协商、q=0 禁用、Vary、GET/HEAD、304、Range、未知资源 404、客户端路由回退;字体域名黑洞仍出现表单;SSE 首事件/持续事件不缓冲;受保护 API 无 public 缓存;部署后旧标签页首次打开尚未加载的模块。
**Verification:** curl 与浏览器确认真正压缩响应,JS 传输量下降;HTML 不被长期缓存。此单元不宣称已达到拆包预算。
**交付证据:** [U2 测试报告](../test-reports/2026-09-17-initial-load-perf-u2-test-report.md);`dev` merge `feature/initial-load-perf-u2`;8080 主 JS br 传输 623,898 B;登录冷缓存可见 ~205 ms。U1/U3–U7 仍未完成。
### U3. 登录壳与重功能按需加载(P0,约 1–2 天)
**Dependencies:** U1;可与 U2 分开开发,合入仍串行。**Requirements:** R1、R2、R5;**Files:** `web/src/main.tsx`、`web/src/App.tsx`、新增认证壳组件、`web/src/components/doc/preview/FilePreviewPanel.tsx`、`web/src/features/replyExport/download.ts`、`web/src/engine/docxRenderer.ts`、`web/src/components/doc/blocks/MermaidBlockView.tsx`、U1 浏览器用例。
**Approach:** 按 KTD3 建立真实 lazy 边界;将工作台 hooks/缓存初始化移入工作台挂载周期。导出按钮点击才 import 引擎;预览根据文件类型加载;Mermaid 只在存在图块时加载。每边界提供局部加载/失败重试与错误边界。限定此重构服务于加载,保留既有文档编辑状态机。
**Test scenarios:** 未登录资源中不出现导出/预览/管理台/图表重模块;登录成功恢复当前会话;失效会话不展示缓存敏感数据;首次导出 DOCX/XLSX 内容有效;Word/Excel 预览、数学公式与 Mermaid 正确;动态 chunk 失败可以重试且不重复提交业务动作;首次打开功能耗时同时记录。
**Verification:** 满足 R1 首屏预算及功能按需请求证据,不把延迟全部转移成首次按钮不可用。检查 gzip 后所有首屏 chunks 总和。
### U4. 收敛初始化扇出与重复同步(P1,约 1–2 天)
**Dependencies:** U1、U3;**Requirements:** R2、R3、R4;**Files:** `web/src/App.tsx`、`web/src/api/projectWorkflow.ts`、`web/src/api/chatSessions.ts`、`web/src/data/storage.ts`、新增初始化 loader/hook 及其测试;必要时项目列表 DTO/服务端 handler 补当前用户成员摘要。
**Approach:** 当前项目成员优先,其他完整成员按打开面板加载;会话 fetch 依赖稳定身份/查询键,项目名称映射与网络获取分离;查询代次 + AbortController + 在途合并;每次成员响应不再全量写 projects/持久化。只有实测长任务证明需要时增加去重/批量保存,不把权威服务器文档写入延迟缓存作为成功。
**Test scenarios:** 1/30/100 项目首次请求数量稳定;成员结果乱序不会重复请求会话;快速切项目/登出/换用户不串状态;普通成员看到的项目/会话范围与改动前一致;错误后手动重试;成员增删后局部失效刷新;离线缓存不绕过权限验证。
**Verification:** 达到初始化去重预算,记录必要 API 次数与工作台就绪时间;跨用户负例、当前会话恢复、文档编辑刷新持久性通过。
### U5. 认证请求去重与续期写入收敛(P1,约 0.5–1 天)
**Dependencies:** U1 的认证测量;**Requirements:** R3、R4、R6;**Files:** `internal/server/auth_handlers.go`、`internal/server/auth_middleware.go`、`internal/auth/service.go`、`internal/auth/pg_store.go` 及相邻测试。
**Approach:** `/auth/me` 复用 middleware principal;合并会话及用户读取,避免重复查同一用户。先度量 session UPDATE 锁/连接等待;只有证明其成本且明确既有过期语义后采用有界续期/last_seen 写入策略。鉴权失败不缓存成成功,撤销/停用每请求生效。
**Test scenarios:** 同 token 1/10/30 并发;me 请求中只验证一次;撤销/停用后的下一请求拒绝;idle 边界/绝对过期/并发续期;DB 异常 fail-closed;匿名静态资源仍可访问。
**Verification:** 展示改前/后 DB 操作数、锁等待和 p95;身份安全回归通过。若节流会改变过期语义,则只交付请求内复用,将节流留待独立决定。
### U6. 按测量优化列表与租约读取(P2,约 2–4 天;按证据选子项)
**Dependencies:** U1、U4;**Requirements:** R2、R4、R6;**Files:** `internal/docgov/project_docs.go`、`internal/docduty/store.go`、成员/职责写路径、`internal/ctxmgr/chat_history.go`、`internal/projectworkflow/store.go`、`web/src/App.tsx` 及相邻 PG/浏览器测试;确需索引时新增 Goose migration。
**Approach:** (a) 先验证成员创建/转交/退出/撤销各路径事务内同步职责,并以显式受控任务修复历史,之后去掉列表读时 heal;(b) 租约查询避免每次全量文档修复,单请求在途、隐藏页暂停并在可见时立即同步,复用现有 SSE 失效事件;(c) 会话先按原可见性/排序选页,再仅统计页内数据,项目列表视数据量分页。维持 COUNT/latest 内容授权规则与排序稳定性,不能把当前全量总计改为页内总计却不告知调用方。
**Test scenarios:** 文档 GET 零 UPDATE/advisory lock,重复读不变 updated_at;成员变动职责立即正确;两标签 busy/释放不晚于原可见性基线、断 SSE 可恢复;慢查询轮询不重叠;分页无重复/丢项且计数不泄漏;EXPLAIN 对照现有索引与扫描行数;项目 143 不做写入修复测试。
**Verification:** PG 真库夹具 + 真实页面操作证明治理与编辑/刷新链路无回归;SQL 扫描、锁等待和 p95 确实改善。没有对应瓶颈时不为“优化”增加索引/摘要/新接口。
### U7. 重启后首访链路与开发预热(P0 诊断 / 按证据修复,约 0.5–1.5 天)
**Dependencies:** U1;**Requirements:** R1、R2、R6;**Files:** `web/vite.config.ts`、`cmd/server/main.go`、`internal/app/app.go`、`internal/bizdev/service.go`、`scripts/env-service.sh`、实际入口健康检查配置与启动测试。
**Approach:** 重启矩阵覆盖:仅 Vite 重启(保留/空依赖缓存)、仅 app 重启、依赖服务一起启动。每项再分浏览器保留缓存/清缓存与保存登录态/未登录;记录启动命令、DB healthy、app listen、ready、首次 HTML、首 API、UI ready。共享重启须占槽并避开正在执行任务,在隔离环境优先验证。Go 初始化分段计时;Vite 确认无缓存编译主导后,使用锁定 Vite 版本支持的 server.warmup/clientFiles 预热关键入口并保留 node_modules/.vite 缓存,禁止为暖机触发聊天或文档生成。
若 DB/迁移/seed 才是主耗时,先将重复扫描与种子写入改为有版本依据的幂等增量;必需迁移和授权数据未完成时 ready 必须失败。不要为看起来快而提前假报就绪。若是健康探测/代理等待,优化实际就绪探测与放流时序,不能把 start_period 直接当固定延时删除。对于后端暂时不可用,登录壳给出服务准备中和有限重试,不能无提示白屏或把瞬时不可达误当身份失效清空会话。
**Test scenarios:** 同版本无迁移重启、首次/有迁移启动、DB延迟就绪/不可用、依赖缓存失效、warmup 失败、过期登录态、保存有效登录态但网络暂时中断;多环境隔离保持。
**Verification:** 无待执行迁移且 DB 已就绪时 app restart→ready p95 ≤3 s;完整依赖启动单列,不承诺未测硬件的整机开机时间。8080/8081 ready 后首次访问须符合 Success Criteria 绝对预算;3100 分别符合 U1 在实施前固定的 Vite 冷/暖预算,不套生产压缩体积预算。三个入口在各自匹配的真实重启场景首访耗时均较基线下降至少 50%,同时记录从启动命令到 UI ready 总耗时,防止仅把等待搬到后台预热而宣称消失。若实测无法达到,保留未达标项与原因,不伪报完成。
## Verification Contract
- 前端:`cd web && npm test && npm run build`;单独运行 U1 的 Playwright 性能用例与现有文档修订/历史恢复相关浏览器回归。检查构建依赖与实际请求,不能只检查构建日志大小。
- Go:`go vet ./...`、`go test -short ./...`;认证/文档/会话修改补相关真实 PG 集成,覆盖撤销、跨用户、分页和职责同步。
- 合入/运行验证:占 CURRENT 集成槽,在主仓 merge 后 `./scripts/env-service.sh dev rebuild`,验证 `/health`、`/ready` 与资源 hash;健康不代表性能通过。禁止 worktree 启停共享服务。
- 真实 UI:登录、刷新当前会话、切项目、首开预览、首导出、文档编辑保存后刷新/重开、双标签 busy。涉及文档治理改变时按 PROJECT 补真实 PI + MiniMax 全链路,stub 不可替代交付。
- 证据:报告记录 commit/image/资源 hash、浏览器与硬件、网络/CPU 设置、缓存状态、数据规模、样本数/分位数、失败样本、请求数和 SQL 变化。脱敏,不保存登录 token、会话正文或原始授权头。
## Definition of Done
1. R1–R6 与性能预算有前后对比和真实 UI 证据;未覆盖项明确列残余,不因 health PASS 关闭。
2. 字体不可达仍可操作,首次登录无重功能模块;初始化不随全部项目成员返回重复发会话请求。
3. 授权/文档职责/租约/保存持久性不回退,分页可见性一致,SSE 不缓冲,旧版本 chunk 失效有恢复路径。
4. 更新任务、CURRENT、FEATURE-MATRIX、test-report,完成后任务归档;明确本地分支/提交、是否合 dev、是否推送。
## Rollout and Rollback
顺序:U1 → U2/U3 与 U7 → U4/U5 → 按数据选择 U6,每波独立复测并归档,预计核心 U1–U5 约 3.5–7 工程日,U7 另需 0.5–1.5 日,U6 另需 2–4 日(估算,含回归,非交付承诺)。先 dev,再按项目既有授权晋升 test/main。
压缩/缓存只作用静态资产,发现编码/缓存问题可回退独立提交;保留对应完整 HTML+资源集,避免仅回滚 HTML。拆包可回滚组件边界,但禁止强制刷新正在编辑的用户。认证和查询优化各独立提交;职责修复迁移必须可重入,停用新读路径时保留既有安全修复,不删除数据/索引作为临时回滚。若 p95 回退超过 10%、401/403 异常、文档职责偏差或租约不可见,停止晋升并回退相应单元。
## Appendix
- [审计与数值证据](../audit/2026-09-17-initial-load-performance-audit.md)
- [诊断测量报告](../test-reports/2026-09-17-initial-load-performance-baseline.md)
- HTTP 压缩协商与 `Vary`:[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Compression)。缓存版本化资源与 HTML 策略:[MDN HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching)。
- 外部字体与阻塞 CSS:[web.dev 字体实践](https://web.dev/articles/font-best-practices)。Vite 开发请求瀑布:[Vite performance](https://vite.dev/guide/performance)。这些资料用于原则核验;具体配置以仓库锁定的 Vite 7.1.x 为准,不照搬官网当前版本构建 API。
## Plan Review
已完成同模型的 coherence、feasibility、design、security、scope、adversarial 六视角只读复核(3 个代理分别承担两视角,不作为6份模型独立验证)。修正1项:明确3100开发入口与8080/8081构建入口使用不同资源预算;保留三入口真实重启与总耗时验证。未进行外部跨模型复核,不声称具有跨模型验证。置信度:资源/字体机制高,用户重启现场主因中等,须U1/U7闭环。
@@ -0,0 +1,57 @@
---
title: "系统体检整改与完善实施方案(2026-09-17)"
status: planned
created: 2026-09-17
updated: 2026-09-18
---
# 系统体检整改与完善实施方案
> 配套审计:[../audit/2026-09-17-system-health-check.md](../audit/2026-09-17-system-health-check.md)(编号 B-x 确认 bug、R-x 隐患、E-x 环境缺陷、T-x 任务、X-x 死代码、S-x 测试盲区、D-x 文档漂移)。
> Wave 0–7 已实施收口。Wave 7 仅为编排确认,未改变能力实现状态。
## 背景
体检确认质量门禁全绿、发布门禁口径属实;但发现 1 项 critical 环境缺陷(main ENV 不一致,E-1)、2 项 high 级 SSE 断流 bug(B-1/B-2)、1 项 high 级前端缓存 bug(B-5)、一批「机制先行无消费方」与测试盲区。本方案按风险优先分波次收口。
## 目标
1. main 环境事件链路语义唯一、无双写/空转风险(E-1)。
2. SSE 长任务不再被 120s WriteTimeout 强杀(B-1/B-2),错误语义对齐(B-3/B-4)。
3. 前端会话窗口缓存一致、恢复不丢数据(B-5/B-6)。
4. 封存功能的灰度入口在 compose 层就绪(E-3),死配置/死代码有明确处置(E-4、X-*)。
5. 测试债与 E2E 门禁入口收敛(S-1/S-2/S-4)。
6. 文档 SSOT 无漂移(D-1~D-6)。
## 分波次计划
| 波次 | 内容 | 验收 |
|------|------|------|
| **Wave 0:P0 确认 bug** | B-1/B-2:`handleChatStream` 与 `handleRunTaskStream` 接 `extendSSEWriteDeadline` + 心跳(复用 sse.go:52-64 既有机制);run/stream 支持 `after_seq` 续订(重连走既有 `GET .../events?after_seq=`)。B-3:Decode 失败返回 400。B-4:CreateAndStart/Subscribe 前置到 Flush 之前(对齐 chat 路径)。B-5:useChatWindow 全部写入统一带 `userId` 前缀,LRU 驱逐完整 cache key。B-6:`applyRestoredFileRaw` 函数式合并 | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md);合入 `dev` merge `fix/wave0-p0-sse-chat-cache-bugs`;dev rebuild + health/ready PASS;真 PI SSE 心跳证据归档 |
| **Wave 1:main 环境修正(critical)** | E-1:app/events 统一 `ENV=main`。E-2:app `depends_on events: service_healthy`(events 同步迁移后再启 app)。E-5:`Env==""` 不再视同 dev。附带:events 补齐 `validateProductionSecrets` 所需口令以免 Restarting | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave1-main-env-fix-test-report.md);main health `env=main` + `schema_version=52`;consumer modes 仍 off |
| **Wave 2:配置与灰度入口对齐** | E-3:三环境声明 `MULTI_INTENT_PLAN_TIER`+U9–U12(legacy/false);A-4:test/main 补 SHADOW/NARRATIVE。E-4:删除 `CURSOR_RUNNER_URL`+cursor-agent。E-6:main `SEED_DEMO_USERS=false`。E-7:非法 `INTENT_V2_DECISION_TIER`→`none`。E-9:评估不改 initdb | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave2-config-flag-align-test-report.md);三环境 env 抽检 + health/ready PASS |
| **Wave 3:测试债与盲区** | S-1:隔离 PG(5436) 跑 `TestReconcile_LegacyRepair_PG`。S-2:删 taskstream 死跳过;plan_owner 重定向说明。S-4:每 spec npm 脚本;退役 `document-revision.spec`(消灭 DOCREV_E2E_BASE_URL)。S-5:`projectSettingsError` 复用到 members/freeform/taskRuns/chatSessions | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave3-test-debt-blindspots-test-report.md);playwright list 29/8;reconcile PG PASS |
| **Wave 4:隐患加固(可与 Wave 0–3 并行认领,mutex 不冲突时)** | R-1:`getOrCreateSession` 增 owner 绑定校验(session 创建时记录 owner,后续请求校验,不匹配 403)。R-2:18 处 `rows.Next()` 循环补 `rows.Err()` 检查。R-3:dispatcher Handlers 读路径加 RLock(或注释冻结「仅启动期注册」并加 archtest 约束)。R-4:`memTurns` 加 TTL/容量淘汰。R-5:pg_store JSONB 反序列化错误改为显式报错。R-6:后台 ticker 纳入 Shutdown;vault Drain 错误上报告警。R-7/R-8:SSE 重连 401/404 fail-fast、逐帧容错;登出 abort 在途流 | **done**(2026-09-18):[test-report](../test-reports/2026-09-18-wave4-hardening-r1-r8-test-report.md);Memory+PG 跨用户负例 PASS;`go test -short` / `npm test` 全绿 |
| **Wave 5:死代码与机制收口(需逐项决策,不擅自删)** | X-1:删除 `SEMANTIC_FALLBACK_ENABLED`。X-2:`SEMANTIC_SUMMARY_REPLACE` 维持未接线并封存注释。X-3:00048 三表 deferred → SWBOOT-10/W5b。X-4:system_settings 6 键保留并注释二期。X-5:删除 DocumentNotificationList、WorkflowPrerequisiteBanner、SettingsModal、activateWorkflow、saveMessages 及级联 patchNotification | **done**(2026-09-18):[决策](../ops/short-term/2026-09-18-wave5-deadcode-decisions.md) · [test-report](../test-reports/2026-09-18-wave5-deadcode-decisions-test-report.md) |
| **Wave 6:文档漂移修复** | D-1:PU8 四份契约文件状态改 done 并归档。D-2:modular-monolith ADR 状态更新为 accepted。D-3:两个 INDEX 末行已在本审计修正(复核即可)。D-4:handoff 回标已被覆盖。D-5:backlog D3/D7 同步最新状态。D-6:PROJECT.md §9「剩余 blocker」段与 gap-matrix 对齐或删除 | **done**(2026-09-18):[short-term](../ops/short-term/2026-09-18-wave6-doc-drift.md) · [test-report](../test-reports/2026-09-18-wave6-doc-drift-test-report.md);D-3 INDEX 复核 PASS、零改动 |
| **Wave 7:既有 roadmap 收口(不改优先级,仅确认编排)** | T1/W5:SWBOOT-10 安全评审后实施(保持 fail-closed 直至授权)。T1/W6:FAV live 放量 staging→artifact→publication,每级 ≥7 天观察窗,`FAV_DEGRADED_READ=false` 不动。T1/W7:D7 待合规签字后按 ADR 整改。T4:首次加载性能 U1/U3–U7。T5/T6/T8:backlog 类按收益触发。T2(Control Center)已于 2026-09-19 移出本仓库 | **done**(2026-09-18):[决策记录](../ops/short-term/2026-09-18-wave7-roadmap-orchestration.md)。六项编排确认已记录;T2 后来由用户裁决为独立项目,本仓库不再保留 Control Center;FAV/D7/tier 升级红线未动 |
## 验收标准
- [x] Wave 0 完成后:`go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿;dev 容器 rebuild + health/ready PASS([报告](../test-reports/2026-09-18-wave0-p0-bug-fixes-test-report.md))
- [x] main 环境:ENV 语义统一核验记录 + schema 已升(实测 52)+ 事件链路无双写证据(modes 仍 off)(Wave 1,[报告](../test-reports/2026-09-18-wave1-main-env-fix-test-report.md))
- [x] SSE 长回合心跳接线:真 PI 静默期 `: heartbeat` + 短 WriteTimeout 单测跨越(Wave 0)
- [x] Wave 2 配置声明对齐:三环境 compose diff 复核 + 容器 env 抽检 + go test 全绿(E-3/E-4/E-6/E-7 完成;E-9 评估结论已记录,不改代码)([报告](../test-reports/2026-09-18-wave2-config-flag-align-test-report.md))
- [x] `TestReconcile_LegacyRepair_PG` 报告归档,gap-matrix 测试债行关闭(Wave 3)
- [x] `playwright test --list` 与门禁文档一致(Wave 3)
- [x] 跨用户会话挂靠负例测试入库(Wave 4)
- [x] X-1~X-5 每项有决策记录(Wave 5)
- [x] D-1~D-6 全部回链关闭(Wave 6)
- [x] Wave 7 六项编排确认已记录(T1/W5、T1/W6、T1/W7、T2、T4、T5/T6/T8);FAV/D7/tier 升级红线未变(Wave 7)
- [x] 不触碰红线:FAV_DEGRADED_READ=false、MULTI_INTENT_PLAN_TIER 默认 legacy、SEMANTIC_SUMMARY_REPLACE 不接线、项目 143 只读、禁止整支 merge FAV
## 相关链接
- Audit: [../audit/2026-09-17-system-health-check.md](../audit/2026-09-17-system-health-check.md)
- gap-matrix: [./gap-matrix.md](./gap-matrix.md)(本方案不改动发布门禁结论;E-1 若核验确认 main 事件链路异常,再评估是否升 blocker)
- 既有收口总控:[./2026-09-16-partial-deferred-completion-plan.md](./2026-09-16-partial-deferred-completion-plan.md)
@@ -0,0 +1,447 @@
---
title: "功能启用与项目文档修改影响分析整改方案"
status: in_progress
created: 2026-09-20
updated: 2026-09-20
---
# 功能启用与项目文档修改影响分析整改方案
## 1. 背景与目标
本方案依据[源码与运行态调研](../ops/research/2026-09-20-capability-enablement-impact-research.md)。目标不是一次性打开全部 flag,而是使系统能够回答并证明四件事:功能是否真正接入生产入口、当前在哪个灰度阶段、失败时如何回退、用户如何看到可靠结果。
第二个目标是让助手在每次文档候选或提交后提供:本次修改内容、项目及相关文档影响、证据和不确定性、下一步建议。常规分析只读取变更片段和已登记关联;首次建索引、索引损坏或明确重建时才允许后台全量扫描。
本方案不直接授权启用 test/main 开关,也不授权 FAV、D7 删除策略、软件自举受控执行或全局编制人兼任。每个波次在 feature/fix 分支实施,合 dev 和共享容器验证继续占用 CURRENT 集成槽。
## 2. 总体判断
### 2.1 能力分组
| 组别 | 能力 | 当前动作 |
|---|---|---|
| 已在用 | legacy 有限只读多意图、确定性摘要、确定性文档 diff/风险/report | 保持运行,补观测,不改变默认行为 |
| 整改后可灰度 | 多意图 shadow/auto_read、语义摘要 shadow、PI change-report narrative | 完成各自前置项后只在 dev 小范围开放 |
| 仍需实现 | confirm 后可靠调度、U9 真实入口、U10–U12 live、语义摘要 replace、项目追踪索引 | 按波次开发和验收,不能用开关代替实现 |
| 继续关闭 | full 一键放量、FAV live/degraded read、D7 物理删除、SWBOOT-10 stub 绕过 | 保持现状,另立授权与验收 |
### 2.2 核心架构
```mermaid
flowchart TB
Candidate[文档候选] --> Preview[proposed 预估报告]
Commit[正式提交] --> Ledger[文档快照和版本账本]
Ledger --> Outbox[可靠事件]
Outbox --> Indexer[增量追踪投影器]
Indexer --> Items[项目追踪条目和修订]
Indexer --> Edges[版本化关系]
Items --> Analyzer[影响分析器]
Edges --> Analyzer
Ledger --> Analyzer
Analyzer --> Report[持久变更报告]
Preview --> Chat
Report --> Chat[聊天影响卡]
Report --> DocUI[文档版本面板]
Report --> ProjectUI[项目追踪视图]
Chat --> Suggested[用户选择建议动作]
Suggested --> Auth[重新鉴权、租约、版本检查]
Auth --> Workflow[目标文档工作流]
```
确定性事实始终由服务端账本、项目追踪关系和权限判定生成。PI 只生成解释、候选关系和建议,不能降低风险、扩大可见集或直接修改其他文档。
## 3. 功能就绪与灰度契约
管理台需要把一个“开关”拆成以下字段,避免 `value=true` 被误解成可用:
| 字段 | 含义 |
|---|---|
| configured_value | 配置声明值 |
| effective_value | 当前进程实际值 |
| implementation_state | placeholder / dry_run / shadow / live |
| adapter_readiness | ready / unavailable / degraded,以及原因 |
| rollout_scope | 环境、项目、用户或百分比 |
| requires_restart | 是否需要重启 |
| evidence | 最近一次验收报告和镜像 digest |
| metrics | 调用量、成功率、回退率、P95、最近错误 |
开关变更需写审计记录并支持按项目 allowlist。关闭时,已有计划和报告仍可读取;执行中的任务进入可解释终态,不能静默遗弃。
管理台采用“先读后改”的能力详情流。`effective_value`、成熟度、adapter readiness、证据和指标始终只读;管理员编辑 configured value 和允许的 rollout scope 时,页面即时展示未满足门禁和是否需要重启。提交前预览旧值、新值、作用范围和预期实际效果;提交后明确显示待重启、部分生效、成功或失败,并提供基于上一审计 revision 的回退动作。保存配置成功不等于能力已经生效。
### 3.1 多意图状态机
```mermaid
stateDiagram-v2
[*] --> Legacy
Legacy --> Shadow: 只生成和对账计划
Shadow --> AutoRead: 只读指标达标
AutoRead --> Confirm: 生成动作验收通过
Confirm --> DomainLive: 单一领域适配器验收
DomainLive --> WiderRollout: 观察窗达标
Shadow --> Legacy: 错误率或成本超阈值
AutoRead --> Legacy: 权限、重复或恢复异常
Confirm --> Legacy: 确认前副作用或调度异常
```
- `shadow` 必须从真实聊天入口生成持久但不可执行的计划,并与 legacy 结果对账;当前 legacy/no-op 语义不足以充当完整 shadow。
- `auto_read` 只允许真实查询 owner;receipt 必须包含查询类型、授权范围 digest、结果版本和恢复标识,禁止 Fake owner。
- `confirm` 在用户确认前零业务写。决定事务复用现有 `intent_plan_steps`、`ClaimStep`、`ExecuteClaimed`、`RecoverReceipt` 和 `intent.plan` 事件作为唯一执行事实源;新增生产 dispatcher 领取已有步骤,重新鉴权、检查 expected resource version,再调用幂等领域 owner。禁止另建第二套决定队列和步骤状态机。
- U9 仅在规则分段低置信时提出候选 span;所有候选仍进入相同策略、鉴权和确认链。
- U10、U11、U12 分别接真实领域端口和独立 allowlist;不使用 `full` 同时开放。
### 3.2 语义摘要状态机
```mermaid
stateDiagram-v2
[*] --> Deterministic
Deterministic --> Shadow: 后台生成语义候选
Shadow --> ReplacePilot: 质量与数据安全门禁通过
ReplacePilot --> ProjectRollout: 项目白名单观察窗通过
ProjectRollout --> EnvironmentRollout: 环境级批准
Shadow --> Deterministic: 超时、校验失败或撤权
ReplacePilot --> Deterministic: 事实丢失或陈旧
```
语义叙事只替换 Narrative,Facts 和 OpenQuestions 由服务器合并保护。每份摘要绑定 session、授权可见集 digest、from/to message ID、上个摘要 revision、模型/协议版本和生成时间。授权变化或消息修订使其失效。
摘要生成放到可靠后台任务;用户请求先返回确定性摘要。PI 返回必须包含 input digest、覆盖水位和结构化字段,服务端严格校验。失败继续提供确定性结果并记录 fallback,不阻断聊天。
## 4. 项目追踪数据模型
### 4.1 设计原则
1. 项目级统一身份,工作流、文档和阶段作为归属,不为每个工作流复制需求。
2. 正文仍由 document snapshot/version 账本管理;追踪表只存结构化字段、定位和 hash。
3. 条目修订不可变,删除使用 tombstone;关系有生效和失效版本。
4. 确定关系、人工确认关系、规则抽取关系、模型候选关系分开存放。
5. 所有读取先经过项目与逐文档可见性过滤;不可通过标题、数量、错误或候选泄漏隐藏文档。
### 4.2 建议表
#### project_trace_items
稳定项目条目身份。
| 字段 | 说明 |
|---|---|
| id / project_id | 主键和项目边界 |
| business_key | 项目内稳定键,如 UR-001、REQ-017、TC-017 |
| kind | requirement / risk / interface / test / decision / deliverable |
| lifecycle_state | draft / active / superseded / retired |
| current_revision_id | 当前修订指针 |
| created_at / created_by | 审计字段 |
约束:`unique(project_id, kind, business_key)`;business_key 变更使用 alias 或 supersedes 边,不直接改写历史身份。
条目身份契约:合规且项目内唯一的显式业务键可直接绑定;无键条目分配不可变内部身份;重复键阻断投影并进入人工消歧;改名必须通过旧键映射和 expected revision 显式确认,未确认时按“删除候选 + 新增候选”处理。历史回填保留可审计映射,不能靠标题相似度静默合并身份。
#### project_trace_item_revisions
不可变条目版本。
| 字段 | 说明 |
|---|---|
| item_id / revision_no | 条目和单调修订号 |
| source_doc_id / source_snapshot_id | 权威文档版本 |
| block_id / heading_path / anchor | 精确片段定位 |
| content_hash | 规范化片段 hash |
| title / statement | 结构化标题和陈述 |
| acceptance_criteria / verification_method | 需求和验证字段 |
| attributes | 类型专属 JSONB;需 schema_version |
| evidence_kind | declared / extracted / imported |
| review_state | confirmed / candidate / rejected |
| extractor_version | 重建和兼容依据 |
| tombstone | 在该快照已删除 |
唯一幂等键建议为 `(source_snapshot_id, block_id, extractor_version, content_hash)`。
#### project_trace_edges
版本化关系边。
| 字段 | 说明 |
|---|---|
| project_id | 事务与鉴权边界 |
| from_item_id / to_item_id | 有向关系两端 |
| relation_type | refines / satisfies / verifies / mitigates / depends_on / conflicts_with / supersedes |
| from_revision_id / to_revision_id | 关系成立时的证据版本 |
| evidence_doc_id / snapshot_id / block_id | 可点击证据 |
| provenance | explicit_reference / workflow_consumption / rule / human / model_candidate |
| confidence | 仅候选使用,不覆盖事实状态 |
| review_state | confirmed / candidate / rejected;由决定账本投影 |
| valid_from / valid_to | 关系历史 |
| created_by / reviewed_by | 审计字段;reviewed_by 由决定账本投影 |
禁止用向量相似度直接生成 confirmed edge。模型候选不能触发自动写文档或把风险降级。
#### project_trace_edge_decisions
人工关系治理的不可变权威账本,避免重建投影时丢失已经确认、拒绝或撤销的决定。
| 字段 | 说明 |
|---|---|
| id / project_id / edge_key | 决定身份、项目和稳定关系键 |
| candidate_revision_id | 决定针对的候选版本 |
| decision | confirm / reject / revoke |
| reason / evidence_refs | 原因和当时可见证据引用 |
| expected_revision | CAS 版本 |
| decided_by / decided_at | 操作者和时间 |
`project_trace_edges` 是文档事实、抽取结果与此决定账本的联合投影。重建必须重放决定账本;旧候选不得因 extractor 重跑而绕过既有拒绝,关系两端或证据实质变化时才产生新候选 revision。
#### project_trace_index_state
保存 `project_id + doc_id + source_snapshot_id + extractor_version`、status、indexed_at、覆盖条目数、失败原因、retry_count。只有状态为 complete 且 source snapshot 与当前基线一致,UI 才能显示“已分析且未发现影响”。
每次影响报告另记录项目覆盖 epoch、当前可见文档集合 digest,以及集合内各文档的 current snapshot 和 extractor version。只有集合全部 complete 且仍与当前基线一致,才可返回 `no_known_dependencies`;任一缺失、陈旧或失败分别返回 `index_pending`、`partial` 或 `failed`。
### 4.3 与现有 document_lineage 的关系
`document_lineage` 保留文档级的实际消费事实,但改用真实 snapshot/version,修复写死 version=1,并支持有效期。条目级 edge 解释被消费内容及其具体影响。静态工作流先后顺序不能自动当作真实依赖;没有实际引用时只可作为“建议检查”候选。
## 5. 增量索引与影响分析
### 5.1 提交链路
```mermaid
sequenceDiagram
participant U as 用户/Agent
participant D as 文档命令
participant L as 版本账本
participant O as Outbox
participant I as 追踪投影器
participant A as 影响分析器
participant R as 报告/UI
U->>D: 保存候选
D->>D: 权限、租约、expected revision
D->>A: 生成 proposed 预估报告
A->>R: 保存 proposed report,不写 stale/通知
R-->>U: 展示预估影响和下一步
U->>D: 正式提交
D->>L: 原子写 snapshot/version
D->>O: 写 document.committed
O-->>I: 至少一次投递
I->>I: 按 snapshot+extractor 幂等增量抽取
I->>A: trace.indexed 或 trace.failed
A->>A: 授权过滤后有界反向遍历
A->>R: 持久 report + coverage status
R-->>U: 修改、影响、证据、建议
```
所有候选来源必须生成并持久化标识为 `proposed` 的预估报告:Agent 生成、人工块编辑、恢复历史版本、导入和修复迁移。候选报告不能写 stale、触发正式通知或发出 `document.committed`。正式提交后才写账本、发出 `document.committed` 并生成 authoritative report。
### 5.2 增量算法
1. 对比前后 block map 和 business key,识别新增、修改、删除、移动、改名。
2. 只重新抽取变化块及必要父标题;未变 block 沿用已确认条目修订。
3. 只有 schema 明确给出关系类型的结构化引用和已记录的实际工作流消费可自动写 confirmed 边。普通正文中的无类型 ID 提及只生成带上下文证据的 candidate;否决方案、历史引用和否定语境不得自动确认。模型只为未覆盖条目产生候选。
4. 后台以受审计的项目服务身份从变化条目反向遍历 confirmed 边;默认深度 3、节点数和时间有上限,并启用 cycle detection。规范结果只保存结构化条目、关系、文档标识和证据定位,不保存可直接向普通用户展示的隐藏正文。
5. 对命中的目标读取对应片段和邻接上下文,不读全部文档;首次索引或修复任务在后台全量读取,并显示状态。
6. 将 diff、条目变化、直接/间接影响、证据路径、索引覆盖和建议保存到规范 report revision。每次读取按当前主体重新执行逐文档策略,过滤 source、target 和 evidence 后重算数量、覆盖状态和展示文案。
7. 乱序事件不能将索引回退到旧 snapshot;重复事件返回同一投影结果。
### 5.3 影响状态与风险
必须区分:
| 状态 | 含义 | UI 文案方向 |
|---|---|---|
| confirmed_impact | 确定关系和内容变化证明影响 | 需要复核/更新 |
| possible_impact | 候选关系或语义不确定 | 建议核实,不自动写 |
| dependency_unchanged | 存在关系,但相关片段未受影响 | 已检查,无需动作 |
| no_known_dependencies | 索引完整,未登记关系 | 未发现已知关联 |
| index_pending | 新版本尚未分析完 | 分析中,不能判断无影响 |
| partial | 达到查询上限或部分目标不可分析 | 结果不完整 |
| failed | 投影/查询失败 | 分析失败,保守处理 |
风险计算应按变更内容、关系类型、目标基线状态和证据确定性合成。纯格式变化不因存在 lineage 自动升 critical;删除已批准安全需求、关键数值变化、冲突关系或已批准下游失效继续保持 high/critical 下限。
## 6. 影响报告与用户交互契约
报告至少包含:
- report_id、project_id、source doc/snapshot、from/to SHA、状态和生成时间。
- 本次修改:业务键、位置、旧值→新值、变更类型;无业务变化时明确说明。
- 项目影响:工作流、阶段、风险、交付物和阻塞条件。
- 文档影响:可见文档名称、状态、直接/间接、确定/候选、证据路径。
- 覆盖说明:索引 snapshot、extractor/version、complete/partial/pending/failed。
- 建议动作:action key、原因、目标、前置条件、责任职责、是否需要确认。
- PI 说明 provenance:deterministic / pi_enriched / fallback,模型、协议、input digest。
同一 report_id 指向服务端规范事实,由聊天卡、文档版本面板和项目“需求与影响”页共同引用。每次规范结果更新生成单调 `report_revision`。面向用户的 `ReportView` 以 `report_id + report_revision + authorization_visibility_digest + narrative_protocol_version` 为键:先按当前主体过滤文档、条目、证据和数量,再生成确定性文案或 PI 叙事。`trace.indexed`、`trace.failed`、关系决定、规范报告更新和授权变化都失效旧视图;刷新、重登和重启后,同一主体看到一致结果,不同权限主体不会共享自由文本叙事。
`proposed` 报告具有 `active`、`superseded`、`rejected`、`expired`、`committed` 生命周期,绑定 candidate revision、base snapshot 和 expected head。候选被拒绝/取消、新候选替代、基线推进或版本冲突时,旧报告不可再创建建议动作;正式提交时写入 authoritative successor report_id。
助手应在候选生成后展示 `proposed` 预估影响,并在正式提交后展示 authoritative 结果。两种状态均主动说明:
1. 本次实际改了什么。
2. 对当前项目或工作流的影响。
3. 还可能涉及哪些文档及证据。
4. 哪些关系尚不确定或索引尚未完成。
5. 建议的有序下一步。
用户点击“按建议修改”只创建明确的动作草案;随后重新检查权限、职责、租约、expected revision 和审批规则。总结、查询、分析类意图保持只读,不自动启动修改。
每个建议动作使用统一可见状态:`available`、`checking`、`draft_created`、`confirmation_required`、`executing`、`completed`、`forbidden`、`stale_or_conflict`、`failed`、`cancelled`。三个入口共用状态和按钮语义;目标文档显示草案入口,冲突要求刷新后重新预览,失败可重试,取消和完成都回写原 report_id 时间线。
异步分析状态也必须给出恢复路径:`index_pending` 自动刷新并显示最近更新时间;`partial` 展示已覆盖和未覆盖范围;`failed` 仅展示安全的失败分类、重试状态和管理员联系/重建入口。恢复后在原 report_id 上更新状态并通知,不覆盖历史时间线。
项目“需求与影响”页的信息架构固定为:首屏先显示索引覆盖健康和待处理影响;随后是按 requirement、risk、interface、test、decision、deliverable 分类并可搜索筛选的条目清单。条目详情集中展示当前修订、上下游关系、证据片段、历史版本和关联报告;聊天卡与文档影响项直接深链到该详情。
跨界面验收包含可访问性和窄屏行为:报告和管理动作可全键盘完成;弹层聚焦标题并在关闭时归还焦点;pending/failed/completed 使用 `aria-live`;关系图提供等价的可筛选关系列表和证据链接;窄屏使用全宽抽屉和分组列表,主要动作满足触控操作要求。
## 7. API 与授权边界
建议增加或扩展以下资源,命名可在实施时按现有路由规范调整:
| 资源 | 用途 | 关键约束 |
|---|---|---|
| 项目追踪条目列表/详情 | 需求、风险、接口、测试清单 | 项目成员 + 文档可见性;分页、过滤 |
| 条目关系图 | 直接和有界多跳关系 | 服务端过滤后计算数量,防侧信道 |
| 文档影响报告 | 获取 report 和进度 | source/target 均按可见性裁剪 |
| 关系候选确认/拒绝 | 人工治理模型候选 | 默认关闭;治理政策批准后才开放;CAS、决定账本、审计 |
| 索引状态/重建 | 管理索引健康 | 普通用户只读状态;重建为管理员操作 |
| 建议动作创建 | 从 report 生成动作草案 | 再鉴权、幂等、明确目标版本 |
现有 lineage API 先修复:doc_id 必须属于 URL project,且每个返回端点都通过逐文档策略;错误不得把不可见对象存在性泄漏给调用方。影响总数只能按调用者可见集统计。
关系候选治理的推荐政策是新增项目本地 `trace_reviewer` 动作能力,并把它嵌入现有文档职责:项目创建者只能在两端文档已有编制人或审核人中显式指派;全局系统管理员不会自动获得该项目、文档或候选的查看和确认权限。确认或拒绝时,同一 CAS 事务必须验证 route project、candidate、两个 item 和两个 source document 都属于同一项目,操作者当前可见两端文档且持有该能力。跨文档候选需要源端和目标端各一名符合条件者确认;同一人同时承担两端职责时可合并一次决定。每次变更限制候选数量并生成待办;未处理候选只产生 `possible_impact`,积压超过 Foundation 0 冻结门槛时停止扩大模型候选范围。此政策需用户审核通过后实施;未批准前端点保持关闭。
### 7.1 PI 输入安全门
Foundation 1 建立所有 PI 消费者共用的 R13 输入信封。服务端绑定 tenant/project、主体授权可见集 digest 和输入 digest;每个消费者只接收字段白名单和必要片段,执行敏感字段脱敏,并限制 runner 凭证、workspace 和日志留存。门禁不可用时 `adapter_readiness=unavailable`,立即走确定性回退。
语义摘要、变更叙事、U9 分段和关系候选都必须经过同一门禁;不得把“完整 diff/impact”解释为无裁剪全文。Track I、S、T 各阶段的进入条件均包含跨项目、撤权、提示注入、敏感字段泄漏和日志留存负例。
## 8. 分轨实施计划
先完成共享基座,再让三条能力轨道独立晋级、验收和回退,避免语义摘要被多意图或追踪索引阻塞,也避免用户最关心的影响定位排在多意图之后。
### 8.1 共享基座
| 波次 | 内容 | 主要产物 | 关闭条件 |
|---|---|---|---|
| Foundation 0:状态校准 | 校准 FEATURE-MATRIX 和管理台成熟度;新增运行时 readiness/metrics;开关审计、项目 allowlist、放量阈值登记 | 准确能力目录和管理流程 | 配置值不再冒充可用性;阈值预先冻结 |
| Foundation 1:安全与持久化 | lineage API 鉴权;chat_summaries 迁移和严格错误;授权水位;纯推理 Runner profile;共用 R13 PI 输入信封 | 通用安全和恢复基础 | PG、权限/泄漏负例、重启恢复、工具隔离通过 |
### 8.2 Track I:多意图
| 阶段 | 内容 | 进入下一阶段条件 |
|---|---|---|
| I1 生产接线 | 真实 query owner;单轮接管;typed payload/version;复用现有步骤领取、receipt 恢复和 intent.plan 事件;新增生产 dispatcher | 确认前零写、确认后一次执行、崩溃与刷新恢复通过 |
| I2 shadow / auto_read / confirm | 按状态机逐级开放项目 allowlist | 精度、安全、P95、采用率和放弃率达到冻结阈值 |
| I3 逐域扩面 | U9、U10、U11、U12 分别接真实 adapter | 每域真实 UI+PG+PI 长链单独通过;禁止 full 一次放量 |
### 8.3 Track S:语义摘要
| 阶段 | 内容 | 进入下一阶段条件 |
|---|---|---|
| S1 shadow 生产化 | 后台任务、旧摘要融合、input/watermark 校验、持久 provenance、确定性即时回退 | 事实保持、撤权、陈旧、性能、重启和 R13 门通过 |
| S2 replace 项目试点 | 只替换 Narrative;Facts/OpenQuestions 由服务端保护;项目 allowlist | shadow 标注数据达到冻结质量阈值,回退演练通过 |
| S3 环境扩面 | test/main 分别授权 | 各环境观察窗和真实页面验收通过 |
### 8.4 Track T:文档影响与追踪
| 阶段 | 内容 | 进入下一阶段条件 |
|---|---|---|
| T1 基础影响闭环 | 修 lineage 版本;统一提交事件;proposed/authoritative 报告;聊天卡;PI narrative 接最小化 diff/impact | 人改/Agent/恢复/导入一致;未知不伪装无影响 |
| T2 项目追踪索引 | 五表迁移;结构化需求/用例投影;UR/RS/REQ/TC 键;决定账本;项目页面 | D7 确认派生条目/候选/决定的留存类别和源文档删除传播规则;双向追踪、授权、决定重放、增量幂等通过 |
| T3 多跳与候选 | 有界递归、循环检测、语义候选、两端人工确认、片段装配 | 准确率、候选积压和成本门槛达标;候选不污染事实 |
推荐先并行启动 Foundation 0、lineage API 鉴权和 T1 的非 PI 部分。Foundation 1 完成后,I、S、T 各自推进;任何轨道都不能以另一轨道“尚未完成”为由跳过自身门禁。
## 9. 验收方案
### 9.1 静态与单元门
- 迁移从空库、与当前 main 一致的 schema 52 夹具、schema 53 三种基线升级均成功;main 晋升前保存升级与回退演练证据,down migration 按项目规范评估。
- config 测试保证默认值和 Compose 声明一致;未知 tier fail closed。
- 每个状态转换、CAS、幂等键、乱序事件、循环关系和查询上限有测试。
- `rg` 证明生产组合根无 Fake owner,live adapter 无 dry-run receipt。
- PI 纯推理 profile 的实际 argv 不包含 read/write/edit/search 或扩展,不能仅断言 prompt 文案。
- 所有 PI 消费者的 R13 输入信封校验 tenant/project、授权可见集 digest、字段白名单、脱敏和日志留存;门禁失败时能力 unavailable。
### 9.2 PostgreSQL 与授权门
- 两项目、两用户、项目管理员、普通成员、非成员和文档级不可见对象。
- 任意 project_id + 他项目 doc_id 不能读取 lineage、条目、边、report 或总数。
- 索引事务中断、重复和乱序事件,最终只指向最新快照。
- 删除、改名、supersede、循环、多跳、旧版本边、候选拒绝均保留历史。
- 摘要和影响报告重启后恢复;数据库写失败不得伪装持久化成功。
- 高权限提交者与低权限查看者共用 report_id 时,ReportView、PI 叙事、数量和覆盖状态按各自 visibility digest 隔离;撤权后旧视图失效。
### 9.3 真实聊天与浏览器门
- 用户从真实页面发起“两项查询”“查询+指定文档生成”“两项生成”“先查询再总结”“模糊指代”。
- 确认前数据库零业务写;确认后只执行所选步骤一次。覆盖双标签、重复点击、取消、超时、撤权和版本冲突。
- 在 dispatcher 领取后、领域写后/receipt 前杀进程并重启,卡片恢复且无重复副作用。
- 人工修改一条数值需求后,页面显示 old→new、相关设计/用例、证据和建议;纯格式修改不滥升 critical。
- 索引 pending/partial/failed 时禁止展示“无影响”。隐藏文档不泄漏标题、ID、摘要或数量。
- 聊天、文档版本面板和项目追踪页共用 report_id,刷新/重登/重启一致。
### 9.4 真实 PI 门
- 固定提交和镜像 digest,记录实际 feature state、模型、input digest、工具 profile 和耗时。
- semantic shadow、change narrative、U9 各有正常、timeout、畸形、注入和撤权用例。
- PI 不能降低服务端风险、添加 confirmed impact、扩大可见集或绕过确认。
- 不以 stub、直接 adapter 单测或 API 直调替代最终真实页面验收。
### 9.5 度量与放量门槛
首次 shadow 观察期至少采集:
- 多意图:segment precision/recall、写意图漏判、错误动作率、fallback、P95、计划采用率、确认放弃率、主动拆单回退率。
- 摘要:事实保持率、旧事实召回、幻觉/矛盾率、撤权失效率、fallback、P95、token/成本。
- 影响:confirmed 关系 precision/recall、候选接受率、漏报、误报、平均读取文档数/块数/字节、索引滞后、P95。
- 运行:任务重复副作用为 0,未授权读取/写入为 0,pending/failed 误报 no-impact 为 0。
具体阈值由 Foundation 0 用标注数据集登记后冻结,禁止事后按结果降低。没有代表性样本时,只能保持 shadow。多意图采用率、确认放弃率或主动拆单回退率未达阈值时,停止 confirm 后写动作和 U9–U12 扩面,只保留明确告知与已验证的只读路径。
## 10. 回退与数据兼容
- 每个能力可按项目降级到上一层;停止创建新任务,不删除已有计划、report、条目或审计。
- 多意图关闭后,执行中的步骤完成到安全终态或明确 cancelled;禁止回落到 legacy 后重复执行同一句写操作。
- 摘要 replace 关闭后立即使用最后一次确定性摘要;语义候选保留用于审计,不注入 prompt。
- 索引器关闭后文档提交继续成功;报告影响状态显示 `index_pending`,索引器的 `adapter_readiness` 显示 `degraded`;恢复后从 outbox/checkpoint 重放。
- 条目、修订、关系和索引状态是可重建投影;人工关系决定由 `project_trace_edge_decisions` 权威账本保存并备份,重建不能丢失确认、拒绝或撤销。
- test/main 放量需独立变更记录、环境级验收和回退演练,不因 dev 通过自动继承。
## 11. 任务拆分建议
实施时为每项建立独立 short-term 与 mutex:
1. `fix/feature-readiness-and-lineage-authz`:Foundation 0 + lineage 鉴权。
2. `fix/semantic-summary-persistence`:chat_summaries、watermark、授权 digest、失败语义。
3. `feature/pi-reasoning-profile`:Runner 纯推理协议和三个消费者迁移。
4. `fix/intent-plan-production-wiring`:真实 query owner、单轮接管、现有步骤内核的生产 dispatcher 和恢复。
5. `feature/document-impact-report`:统一提交事件、文档级影响与聊天卡。
6. `feature/project-traceability-index`:表、投影、项目需求/验证视图。
7. `feature/trace-impact-candidates`:有界多跳、候选治理和片段装配。
8. `feature/semantic-summary-replace-pilot`:独立授权后的替换试点。
9. U9/U10/U11/U12 各自独立任务,禁止合成一个 full 放量任务。
## 12. 完成定义
- [ ] 管理台准确区分配置、实际值、实现成熟度、adapter 状态和 rollout。
- [ ] 多意图不存在生产 Fake receipt;confirm 后由复用现有步骤内核的可恢复 dispatcher 执行,确认前零写。
- [ ] 摘要 PostgreSQL 持久化、授权可见集、水位、provenance、重启恢复和确定性回退闭环。
- [ ] PI 的 no-tool 由 Runner 能力强制,而非只靠 Instructions。
- [ ] 所有文档提交来源生成持久影响报告;未知、失败和无影响语义分开。
- [ ] 项目需求/风险/接口/测试清单来自统一版本化索引,可双向追踪到文档快照与块。
- [ ] 无类型正文 ID 仅形成候选;条目无键、重复键和改名均按身份契约处理,历史映射可审计。
- [ ] 助手在修改后主动展示本次修改、项目影响、相关文档、证据、不确定性和下一步建议。
- [ ] 每个候选都有持久 `proposed` 报告,正式提交才产生 authoritative report、stale 和通知;两条路径不混用事件。
- [ ] `proposed` 报告在取消、替代、冲突和基线推进后不可执行,正式提交回链 successor report。
- [ ] T2 开始前完成派生条目、候选和关系决定的 D7 留存分类与源文档删除传播决策。
- [ ] 常规分析有证据证明只读取命中片段;全量重建是可见、可审计的后台状态。
- [ ] 真实浏览器 + PostgreSQL + 产品 PI 长链通过,报告归档并回链 FEATURE-MATRIX。
- [ ] dev→test→main 分别批准和验收;任一失败可回退且不丢历史或重复副作用。
## 13. 相关链接
- Research: [2026-09-20-capability-enablement-impact-research.md](../ops/research/2026-09-20-capability-enablement-impact-research.md)
- Archived task: [2026-09-20-capability-enablement-impact-plan.md](../archive/ops/2026-09-20-capability-enablement-impact-plan.md)
- Feature matrix: [FEATURE-MATRIX.md](../status/FEATURE-MATRIX.md)
- Gap matrix:本轮未新增发布 blocker;实现阶段若发现当前默认路径存在真实安全/数据破坏问题,再按证据更新。
@@ -0,0 +1,110 @@
---
title: "模块解耦分批整改(A–G)"
status: planned
created: 2026-09-20
updated: 2026-09-20
---
# 模块解耦分批整改(A–G)
## 背景
[耦合审计](../audit/2026-09-20-module-coupling-audit.md) 确认:模块化单体、窄端口和 PG 事件总线已经在运行。本计划只清除仍会让故障跨模块扩散的残留,不推翻 [ADR](../adr/2026-09-14-modular-monolith-decoupling.md),不引入 RPC,不合入 FAV,不改 `production_ready`。
通信规则以 [模块开发规范](../system-design/2026-09-20-module-development-standards.md) 为准。每一批开工前另建 short-term,并在 CURRENT 认领;本文件把批次保持 `planned`。
## 目标
每一批合并后,该批声明的依赖边消失,且 `./scripts/arch-check.sh --mode block`、`go vet ./...`、`go test -short ./...` 通过。不要求七批同一周做完。
## 分波次计划
| 波次 | 内容 | 验收 |
|------|------|------|
| A | server 只依赖用例端口,不再持有领域具体服务与 pool 写路径 | 见批次 A |
| B | 拆掉 chat → app 子包的反向 import | 见批次 B |
| C | docgov 状态/角色/错误不再被当跨包协议 | 见批次 C |
| D | workflow 定义、目录、实例、运行时的依赖改成单向 | 见批次 D |
| E | 先拆 `coordinator/engine.go`,再按审计清单处理其余超 1000 行文件 | 见批次 E;依赖 B |
| F | 前端 api 共用一个 fetch 封装 | 见批次 F |
| G | 清零 YAML 里 21 条例外,U3/U4 优先 | 见批次 G |
A、B、C、D、F 互不阻塞,可并行,但 mutex 不得重叠,合入 `dev` 必须串行占集成槽位。E 等 B 合并后再动 `coordinator`。G 按例外自己的里程碑走,其中到期日为 2026-09-28 的条目优先于其余 path 例外。
### 批次 A — server 装配收口
- **问题**: `Server` 持有 `*bizdev.Service`、`*docgov.GovernanceEngine`、`*pgxpool.Pool` 等具体类型(`internal/server/server.go`)。
- **做法**: handler 改为调用已有 `internal/app` 用例。领域错误到 HTTP code 的映射收进一个适配函数。新增路由不得再给 `Server` 加具体服务字段,也不得在 handler 里写非本适配层的 SQL。
- **分支 / mutex**: `refactor/server-port-assembly` / `server-assembly`(与进行中的 `web`、`authz` 冲突时等待)。
- **验收**: 生产 `internal/server` 不再出现 `*pgxpool.Pool` 字段;`handlers.go` 不再直接引用 `docgov.Err*`(映射函数除外,且该函数不 import 领域 SQL)。既有 HTTP 特征测试保持状态码。
- **回滚**: 单批 revert。不改表。
### 批次 B — chat / app / coordinator 解环
- **问题**: `internal/chat/session.go` 与 `action_executor.go` import `app/chatflow`、`app/intentflow`、`app/stageflow`;`chatflow/ports.go` 又嵌入 `coordinator` 类型。
- **做法**: 动作执行所需能力改成 chat 或 chatflow 拥有的窄端口,具体 `docgov` / `taskrun` / `coordinator` 指针留在组合根。`AssembleRequest` 不再使用 `coordinator.UserInfo` 这类对方具体结构。
- **分支 / mutex**: `refactor/chatflow-dependency-inversion` / `chat` + `coordinator`。开工前确认这两把 mutex 没有别的 `in_progress`。
- **验收**: `go list -f '{{.ImportPath}} {{.Imports}}'` 下 `internal/chat` 生产文件不再 import `internal/app/...`。一轮对话的现有短测试仍通过。
- **回滚**: 单批 revert。不改事件名。
### 批次 C — docgov 词汇收敛
- **问题**: `StateDrafting`、`RoleAuthor`、`ErrDocumentBusy` 以及字符串 `"docgov.review_approve"` 出现在 coordinator、bizdev、server、chat。
- **做法**: 跨包需要的无行为枚举进稳定词汇或调用方自己的端口错误。领域包保留不变量实现。server 只映射 typed error。禁止把 canonical 哈希或路径函数放进词汇包。
- **分支 / mutex**: `refactor/docgov-vocabulary-boundary` / `docgov`。
- **验收**: 审计热点 3 列出的生产引用点改为端口或词汇;`docgov` 测试仍覆盖原状态机。不改变 HTTP 错误 code。
- **回滚**: 单批 revert。
### 批次 D — 工作流定义与实例单向化
- **问题**: `workflowdef/catalog.go` import `projectworkflow`,`validator_v2.go` import `workflow`,`projectinstance` import `workflowdef`,`workflow/runtime/orchestrator.go` import `projectinstance`。
- **做法**: 共享的无行为定义类型留在 `workflowdef` 或词汇;catalog 与 runtime 通过端口读定义,不反向 import 实例包。先画允许的依赖方向再改 import,避免为解环再套一层子包。
- **分支 / mutex**: `refactor/workflow-definition-direction` / `workflow-def`。若 rdev 模板任务占用同一 mutex,本批等待。
- **验收**: 依赖方向写成 YAML allowlist 的收紧(只删边,不放开新边)。工作流校验与门禁短测试通过。
- **回滚**: 单批 revert。不改已发布工作流 JSON 的键。
### 批次 E — 巨型文件拆分
- **依赖**: 批次 B 已合并。否则拆 `engine.go` 会把逻辑环复制到新文件。
- **顺序**: `internal/coordinator/engine.go`(1844 行)→ `internal/bizdev/service.go` → `internal/server/handlers.go`。其余超过 1000 行的文件各一批,不在同一次提交里“全部拆完”。
- **做法**: 按用例搬文件,不改行为。新文件 ≤ 800 行。不借拆分改 SQL 或事件。
- **分支 / mutex**: `refactor/split-coordinator-engine` 起,mutex 与被拆包一致。
- **验收**: 搬迁前后该包 `go test -short` 同绿;无新的跨模块 import。
- **回滚**: 按文件批次 revert。
### 批次 F — 前端统一 API client
- **问题**: `web/src/api/` 各文件自行 `fetch`,错误处理与鉴权头重复。
- **做法**: 一个小封装负责 base URL、鉴权头、typed error envelope 解析和有限重试。各域文件改为调用它,不改路径与请求体。预览器里的 `fetch` 若只取静态资源,可以后迁,但要在本批 short-term 里点名留下的文件。
- **分支 / mutex**: `refactor/web-api-client` / `web`。
- **验收**: `web` 下 `npm test` 与 `npm run build` 通过。抽一条 chat 与一条 docgov 请求,失败时仍走到现有错误卡,而不是未捕获 rejection。
- **回滚**: 单批 revert。无后端变更。
### 批次 G — 例外清零
不在本计划里改 `module-boundaries.yaml`。开工时按到期日处理,禁止只改 `expires` 而不迁代码。
| 组 | 到期 | 内容 | mutex |
|----|------|------|-------|
| G1 | 2026-09-28 | 4 条 U3 `sql_write`(`docduty`/`docrevision` 写 `document_records` 与 `freeform_documents`)+ 2 条 U4 `path`(server / docrevision 的 `output.md`) | `docgov` |
| G2 | 2026-10-12 | 14 条 U5 `path`(agent、bizdev、coordinator、docgov、storage) | 按文件所属包,一次一个包 |
| G3 | 2026-10-26 | `projectinstance` 写 `task_runs` | `taskrun` + `projectinstance` |
G1 若在到期日前无法合并,必须另写 audit:要么延长并给出新的移除里程碑,要么让 arch-check 在到期后失败并停写。两种选择都要留在 ops,不能沉默。
- **验收**: 对应 exception 从 YAML 删除,`baseline_counts` 下降,`arch-check --mode block` 通过,行为测试覆盖原来那条写入或读路径。
- **回滚**: 恢复 exception 条目的提交必须与代码回滚成对,避免门禁与代码错位。
## 验收标准
- [ ] 每一批有独立 short-term、CURRENT 认领、测试记录;本文件不代替那些记录。
- [ ] 未开始的批次在 FEATURE-MATRIX 保持 `planned`。
- [ ] 任一批不得把 FAV live、`production_ready` 或 RPC 拆分写进自己的完成定义。
- [ ] 合入 `dev` 时集成槽位为该批 holder,冒烟包含 `arch-check`、`go vet`、`go test -short`。
## 相关链接
- Audit: [../audit/2026-09-20-module-coupling-audit.md](../audit/2026-09-20-module-coupling-audit.md)
- Short-term(本轮文档任务): [../ops/short-term/2026-09-20-module-decoupling-spec-audit.md](../ops/short-term/2026-09-20-module-decoupling-spec-audit.md)
- 规范: [../system-design/2026-09-20-module-development-standards.md](../system-design/2026-09-20-module-development-standards.md)
- gap-matrix 行: 无。本计划不是发布 blocker,不新增 gap 行。
@@ -0,0 +1,51 @@
---
title: "2026-09-20 P0 热修整改方案"
status: done
created: 2026-09-20
updated: 2026-09-20
---
# 2026-09-20 P0 热修整改方案
## 背景
链到 [audit](../audit/2026-09-20-system-triage-audit.md)。`production_ready=yes` 不变;本方案关闭现场 critical,不自动回退门禁。
## 目标
1. 迁移链连续:capability 分支合入,`00054`→`00058`,dev schema=58,`chat_summaries` 可持久化
2. 三项 IDOR 负例 403;真实双用户 curl PASS
3. taskrun channel 竞态不再 panic;同步 chat 取 `execMu`;关键 goroutine 有 recover;math XSS 转义
4. backup/push 脚本不再硬编码/暴露凭证;main DB 口令已轮换且健康
## 分波次计划
| 波次 | 分支 | 内容 | 验收 |
|------|------|------|------|
| Wave 0 | `docs/p0-triage-2026-09-20` | 审计/整改/short-term/CURRENT/long-term | 文档入库 |
| Wave 1 | `fix/capability-merge-00058-2026-09-20` | merge capability + 重编号 00058 + rebuild | health schema=58;表存在 |
| Wave 2 | `fix/authz-idor-hotfixes-2026-09-20` | 三项越权 + 负例测试 | curl 403 ×3 |
| Wave 2b | `fix/runtime-panic-races-2026-09-20` | panic/race/recover/XSS | `-race` + npm test |
| Wave 3 | `fix/credential-hardening-2026-09-20` | 脚本加固 + main 口令轮换 | 旧口令失败、新口令成功;ps 无 token |
| Wave 4 | `docs/p0-closeout-2026-09-20` | 测试报告 + gap-matrix 收口 | 报告七段齐全 |
## 验收标准
- [x] `curl :8080/health` → `schema_version=58`;`chat_summaries` 存在
- [x] 偏好跨用户写 / 他人 session 读 / 空 session 重分类 → 403 或 400
- [x] `go test -race` taskrun/chat/server short PASS;math XSS 单测 PASS
- [x] backup 脚本无硬编码口令;push 不把 token 放 URL
- [x] main health 恢复;旧口令无法登录
- [x] 测试报告归档;CURRENT 槽位 idle;不改 `production_ready`
## 非目标
- 不做 dev→test→main 晋升 / main 分支追平(backlog)
- 不升 `MULTI_INTENT_PLAN_TIER` / 不启用 FAV live / 不启 SEMANTIC_SUMMARY_REPLACE
- medium/low 约 25 项仅记 long-term
## 相关链接
- Audit: [../audit/2026-09-20-system-triage-audit.md](../audit/2026-09-20-system-triage-audit.md)
- Short-term: [../ops/short-term/2026-09-20-p0-hotfixes.md](../ops/short-term/2026-09-20-p0-hotfixes.md)
- gap-matrix 行: 收口时追加「2026-09-20 P0 现场问题」
+7
View File
@@ -2,6 +2,11 @@
| 文档 | 说明 |
|------|------|
| [2026-09-20-module-decoupling-batch-plan.md](./2026-09-20-module-decoupling-batch-plan.md) | 耦合残留分批 A–G(server 装配、逻辑环、docgov 词汇、工作流依赖、巨型文件、前端 client、例外清零);保持 planned,不改代码。配套 [审计](../audit/2026-09-20-module-coupling-audit.md) · [规范](../system-design/2026-09-20-module-development-standards.md) |
| [2026-09-20-p0-remediation-plan.md](./2026-09-20-p0-remediation-plan.md) | 系统体检 P0:迁移 00058、三项 IDOR、panic/race/XSS、凭证与口令轮换;配套 [审计](../audit/2026-09-20-system-triage-audit.md) |
| [2026-09-20-capability-enablement-impact-plan.md](./2026-09-20-capability-enablement-impact-plan.md) | 多意图、语义摘要、PI 变更叙事等能力的真实启用门槛,以及项目级需求/风险/接口/测试追踪索引和文档修改影响闭环方案;配套 [调研](../ops/research/2026-09-20-capability-enablement-impact-research.md) |
| [2026-09-17-system-health-remediation-plan.md](./2026-09-17-system-health-remediation-plan.md) | 系统体检整改:Wave0–7(SSE/缓存 P0 → main ENV → 配置对齐 → 测试债 → 隐患 → 死代码决策 → 文档漂移 → roadmap);配套 [审计](../audit/2026-09-17-system-health-check.md) |
| [2026-09-17-document-author-only-plan.md](./2026-09-17-document-author-only-plan.md) | 编制人兼任审核/批准:两级授权、`duty_policy=author_only`、U1–U6 实现已收口;默认 off;变更提案 HTTP 另立([audit](../audit/2026-09-17-docgov-modification-proposal-http-gap.md)) |
| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT |
| [2026-09-16-partial-deferred-completion-plan.md](./2026-09-16-partial-deferred-completion-plan.md) | FEATURE-MATRIX 6 partial + 1 deferred 全量收口:通信机制确认(模块化单体,不新增 RPC 层)、7 项关闭条件、W1–W7 波次;§7 四项决策已确认(2026-09-17) |
| [2026-09-16-feature-matrix-production-readiness-plan.md](./2026-09-16-feature-matrix-production-readiness-plan.md) | 能力状态与发布门禁解耦、证据校准、剩余 partial 收口和 production-ready 防回退计划([审计](../audit/2026-09-16-feature-matrix-production-readiness-audit.md)) |
@@ -31,3 +36,5 @@
| [2026-09-12-three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 三工作流严格治理 |
审计入口:[../audit/INDEX.md](../audit/INDEX.md)
- 2026-09-17:[首次加载性能诊断与改进](2026-09-17-initial-load-performance-plan.md)(三入口重启首访;U2 已验收,主 JS ~624 KB;U1/U3–U7 待实施)。
+15 -1
View File
@@ -63,7 +63,7 @@
| ID | 描述 | 状态 | 证据 | 计划动作 |
|---|---|---|---|---|
| WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES | active 项目仍展示可编辑职责表单,409 提示在长表单视口外;现有规划又不支持非必需文档“三权全空”,且后端缺少职责人在任成员复核 | **PASS(设置页)** | [audit](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md);[test-report](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md)。项目 143 只读 frozen、A full+none 激活、B partial 不发 PUT、C 零治理拒绝、双标签转 frozen、成员无配置入口、刷新后 143 仍 frozen | 设置页矩阵 PASS;真实 PI full/none 长链已另签 [Wave2 报告](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) |
| DOC-CONTENT-CANONICAL-HASH-DRIFT | 旧受控文档 bootstrap 裁剪 Markdown 双空格硬换行并将 canonical SHA 写入账本/DocGov,但未同步文件;正文读取把完整性冲突误报 404,lease/list sync 又放大并制造刷新后加载死锁 | **PASS(真实 UI)** | [audit](../audit/2026-09-14-project143-controlled-content-404.md);[UI report](../test-reports/2026-09-14-controlled-content-ui-acceptance.md)。代码已合 dev、schema 32、项目 143 定向 `migration_repair`;项目 143 `clean-run3` 与新项目 `full-chain-final` 主链及 restart 全部纯页面 PASS,目标 404=0 | [remediation](./2026-09-14-controlled-content-canonical-hash-remediation.md)。隔离 `TestReconcile_LegacyRepair_PG` 未执行,按用户“本轮只允许页面测试”的边界保留为工程测试债,不作为本轮 UI PASS 的替代证据 |
| DOC-CONTENT-CANONICAL-HASH-DRIFT | 旧受控文档 bootstrap 裁剪 Markdown 双空格硬换行并将 canonical SHA 写入账本/DocGov,但未同步文件;正文读取把完整性冲突误报 404,lease/list sync 又放大并制造刷新后加载死锁 | **PASS(真实 UI)** | [audit](../audit/2026-09-14-project143-controlled-content-404.md);[UI report](../test-reports/2026-09-14-controlled-content-ui-acceptance.md)。代码已合 dev、schema 32、项目 143 定向 `migration_repair`;项目 143 `clean-run3` 与新项目 `full-chain-final` 主链及 restart 全部纯页面 PASS,目标 404=0 | [remediation](./2026-09-14-controlled-content-canonical-hash-remediation.md)。Wave 3(2026-09-18)已在隔离 docker PG(5436)执行 `TestReconcile_LegacyRepair_PG` 一次并 PASS,工程测试债关闭,见 [test-report](../test-reports/2026-09-18-wave3-test-debt-blindspots-test-report.md) |
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);活验 [live.json](../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 闲聊刷新已补。发布门禁「激活后文档任务 + 重登/重启」仍开放,不回退本 gap |
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **PASS** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);[test-report](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);双标签活验项目 **6275** / `sess-p6275-u10`(`live.json` + Docker 截图)。**不**删除 `sess-p143-u9` 历史探针 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.md)。Wave 3–4 浏览器门已签;诊断污染消息仍不擅自删除 |
| ENV-RESTART-SOURCE | `docker compose restart` 只重启旧镜像,健康检查无法证明合入代码已部署 | **PASS** | `env-service.sh rebuild` + 真实摘要重测 | 集成冒烟统一使用 `dev rebuild` |
@@ -94,3 +94,17 @@
```
**结论**: 发布门禁四框已签。文档账本运行时 UI Round20 **PASS**;`CHAT-INTENT-STATE` 双标签 busy **PASS**;`DEMO-DB-SEED` **PASS**;BUG-08 **PASS**。`-race` TempDir flake 与 U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发。不得把 fallback change report 写成完整 PI 叙事。
---
## 2026-09-20 P0 现场问题(同日收口)
| ID | 描述 | 状态 | 证据 |
|---|---|---|---|
| P0-MIG | 00054 空洞 + chat_summaries 静默失败 | **PASS** | 重编号 `00058`;dev/main health schema=58;[报告](../test-reports/2026-09-20-p0-hotfixes-test-report.md) |
| P0-IDOR | 偏好写 / session 项目读 / 重分类越权 | **PASS** | 单元 + 真实 curl 403/400;同上报告 |
| P0-PANIC-RACE | taskrun closed-channel panic + 同步 chat 无锁 | **PASS** | 持锁 fanout;`WithExecLock`;`-race` Subscribe 测试 |
| P0-XSS | math 错误分支未转义 | **PASS** | BlockEditorModal/MathBlockView + escapeHtml 单测 |
| P0-CRED | backup 硬编码口令 + push URL token + 生产口令轮换 | **PASS** | 脚本无硬编码;docker 网旧口令 FATAL、新口令 OK;main health ok |
> 不改 `production_ready`。main **git 分支**对齐仍为 backlog(T20-I7);环境库已随 rebuild 至 schema 58。
+24 -9
View File
@@ -1,6 +1,6 @@
# 模块与功能完成度(SSOT)
**更新**: 2026-09-17(W3 PI 叙事 done;W4 多意图扩面 done)
**更新**: 2026-09-20(模块开发规范与耦合审计已合入文档;批次 A–G 仍为 planned,不改 `production_ready`)
**production_ready**: yes(权威来源:[gap-matrix](../remediation/gap-matrix.md);本表不推导发布门禁)
**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
@@ -8,6 +8,8 @@
**整改计划**: [../remediation/2026-09-16-feature-matrix-production-readiness-plan.md](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md)
> 本表描述**能力成熟度**;上线 blocker 见 gap-matrix。二者正交:能力行不必全部 `done` 才能发布;`partial`/`deferred` 不得自动回退 `production_ready`。
>
> 2026-09-19 深度审计的 critical/high 已分四批合入 `dev`(数据一致性、鉴权、SSE/事件、前端 XSS)。不改 `production_ready`。未做项在 [long-term](../ops/long-term/2026-09-19-audit-remainder.md)。
---
@@ -16,7 +18,7 @@
| 字段 | 含义 |
|------|------|
| **声明范围** | 本行冻结的能力边界;`done` 只对该边界负责 |
| **状态** | `done` \| `partial` \| `planned` \| `deferred` \| `blocked` |
| **状态** | `done` \| `partial` \| `planned` \| `deferred` \| `blocked` \| `removed`(已下线,仅留历史证据) |
| **发布关系** | 与当前首发/已签门禁的关系:`non_blocker` / `补证` / `加固` / `deferred_enhancement` |
| **关闭条件** | 何时可将本行升为 `done`(或关闭 `partial`);stub/SKIP/fallback 不得冒充 |
| **证据** | 可追溯到报告/commit/环境/schema;代码或 artifact 变化后须重验 |
@@ -48,25 +50,30 @@
| 模块 | 声明范围 | 状态 | 发布关系 | 证据 | 剩余工作 / 关闭条件 | mutex |
|------|----------|------|----------|------|---------------------|-------|
| 意图识别 L1 | 18 类 Intent、三分支消解、写/只读分流、双标签 `DOC_BUSY`、intent 纯依赖边界 | done | non_blocker | [intent-recognition](../system-design/intent-recognition/);[审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[报告](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/live.json);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U3](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | **边界 before**:含 U9–U12 叙事混入 → **after**:U9–U12 迁至「多意图扩面」行。关闭:纯依赖边界回归即重开 | `intent` |
| 多意图持久计划(U1–U8 基线) | app/intentflow 生命周期、HITL、默认 `legacy`、U1–U8 代码与安全基线 | done | non_blocker(默认 legacy) | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U8](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md);[Wave2 真 PI](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) | U8 已签。**Playwright 双标签**:真浏览器 PASS 已合入([报告](../test-reports/2026-09-16-intent-plan-playwright-dual-tab-test-report.md));升 `confirm/full` 另开 | `intent-plan` |
| 多意图扩面(U9–U12) | U9 LLM 分段实验;U10 mutate;U11 docgov;U12 workflow/run-control | done | deferred_enhancement | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[脚手架](../test-reports/2026-09-16-pu8-u9-u12-flags-test-report.md);[U9](../test-reports/2026-09-17-w4-u9-segment-test-report.md);[U10](../test-reports/2026-09-17-w4-u10-mutate-test-report.md);[U11](../test-reports/2026-09-17-w4-u11-docgov-test-report.md);[U12](../test-reports/2026-09-17-w4-u12-run-control-test-report.md) | **before**:独立 flag 脚手架。**after**:U9 可开 flag 走产品 PI proposer(规则已切则不出 proposal);U10–U12 分 flag dry-run→confirm 证据。**未升** `MULTI_INTENT_PLAN_TIER`(升 `confirm` 另开授权;永不默认 `full`)。U10–U12 领域 live 写仍须专项批准 | `intent-plan` |
| 多意图持久计划(U1–U8 基线) | app/intentflow 生命周期、HITL、默认 `legacy`、U1–U8 代码与安全基线 | partial | non_blocker(默认 legacy) | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U8](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md);[Wave2 真 PI](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md) | legacy 有限只读多意图仍默认启用;新持久计划生产组合根仍使用 Fake query owner,confirm 后缺可靠调度,typed 参数/目标版本不足。原 U1–U8 测试证据保留,但不足以证明升 `auto_read/confirm` 可用。关闭条件见[整改方案](../remediation/2026-09-20-capability-enablement-impact-plan.md) Foundation 1 与 Track I | `intent-plan` |
| 多意图扩面(U9–U12) | U9 LLM 分段实验;U10 mutate;U11 docgov;U12 workflow/run-control | partial | deferred_enhancement | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[脚手架](../test-reports/2026-09-16-pu8-u9-u12-flags-test-report.md);[U9](../test-reports/2026-09-17-w4-u9-segment-test-report.md);[U10](../test-reports/2026-09-17-w4-u10-mutate-test-report.md);[U11](../test-reports/2026-09-17-w4-u11-docgov-test-report.md);[U12](../test-reports/2026-09-17-w4-u12-run-control-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md) | U9 proposer 已实现和注入但未进入生产聊天分段调用;提议请求已带 reasoning profile。U10–U12 当前为 dry-run/validated-only adapter。历史直接调用/PI 测试继续有效,不代表 live 接线。逐域实现和验收,禁止以 `full` 一次放量 | `intent-plan` |
| 对话 / ctxmgr baseline | 多轮上下文、刷新/重登/重启恢复、授权同集正文与计数、U10 端口化停止扩面 | done | non_blocker | [multi-turn](../system-design/multi-turn-dialogue/);[刷新审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md);[门禁 B3](../test-reports/2026-09-16-chat-refresh-gate-test-report.md)(项目 6359) | **before**:语义摘要误标 D5 混入 → **after**:摘要迁「语义摘要 D3」;D7 数据治理独立。U10 停止扩面 | `chat` |
| 语义摘要(D3) | 授权后可见集合上的语义摘要;shadow → 可选替换 deterministic | done | deferred_enhancement | [chat-agent-p6-backlog](../backlog/chat-agent-p6-backlog.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu6](../ops/long-term/2026-09-16-pu6-semantic-summary-contract.md);[脚手架](../test-reports/2026-09-16-pu6-semantic-summary-test-report.md);[W2 真 PI](../test-reports/2026-09-17-w2-semantic-summary-shadow-test-report.md) | **before**:flag 脚手架 + heuristic。**after**:dev 可开 `SEMANTIC_SUMMARY_SHADOW` 走产品 PI no-tool summarizer(默认 off)。**REPLACE 未启用**(独立后置,不在本行关闭条件内) | `chat` |
| 语义摘要(D3) | 授权后可见集合上的语义摘要;shadow → 可选替换 deterministic | partial | deferred_enhancement | [chat-agent-p6-backlog](../backlog/chat-agent-p6-backlog.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu6](../ops/long-term/2026-09-16-pu6-semantic-summary-contract.md);[脚手架](../test-reports/2026-09-16-pu6-semantic-summary-test-report.md);[W2 真 PI](../test-reports/2026-09-17-w2-semantic-summary-shadow-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md) | shadow 默认 off。`00058` 增加 `chat_summaries`,写入失败不再伪装成功;运行中的库仍是 schema 53。摘要请求已带 `tool_profile=reasoning`(argv 为 `--no-tools`),当前容器要等镜像或 dev 挂载更新后才生效。授权可见集 digest 仍空。`SEMANTIC_SUMMARY_REPLACE` 未接线。 | `chat` |
| 对话数据治理(D7) | 留存/删除口径、库·备份·日志控制、敏感字段加密边界 | deferred | deferred_enhancement(违规则升 blocker) | [计划](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md) Scope Boundaries;[收口 §7.1](../remediation/2026-09-16-partial-deferred-completion-plan.md);[D7 ADR 草案](../adr/2026-09-17-d7-chat-data-retention.md);[W7 盘点](../audit/2026-09-17-d7-data-inventory.md);[报告](../test-reports/2026-09-17-w7-d7-inventory-test-report.md) | **after W7**:只读盘点完成(sessions/messages/KB/日志/备份/event)。**未发现**已确认基线违规,未写 gap-matrix。口径仍 `pending-compliance-signoff`;禁止按 365/180/30 物理删除。本行不升 done | `chat` |
| 智能体小队 | 角色-任务-工作区-黑板 | done | non_blocker | [agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6)属 backlog | `squad` |
| 工作流治理 | 三正式工作流、设置页/DutyMode、动作级鉴权、真实 PI 三工作流 E2E、full/none 混合长链 | done | non_blocker | [三工作流整改](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[409/职责](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md);[鉴权](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[PI E2E](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2 full/none](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) | full 跨用户审批 + none 免审批不阻塞已签。纯软件自举仍独立 planned | `workflow` |
| 研发设计控制(rdev) | 医疗第 4 工作流:13×60 manifest/模板、`squad.rdev_doc.v1` kind 编排、main-completed 硬 precheck、StageKey 动态化;不含前端/真 PI/键名空间化 | partial | deferred_enhancement | [设计](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md);[short-term](../archive/ops/2026-09-17-rdev-workflow-integration.md);[模板深度](../archive/ops/2026-09-17-rdev-template-depth.md);[S0+S1 首批报告](../test-reports/2026-09-17-rdev-template-depth-test-report.md);[S1 续批报告](../test-reports/2026-09-17-rdev-template-depth-s1-continued-test-report.md);[写作规范](../system-design/project-workflow/08-rdev模板写作规范.md);[backlog](../backlog/2026-09-17-rdev-phase2-backlog.md) | **P0+P1 done**。**模板深度 S0+S1 首批 + S1 续批 done**:60/60 模板已补强;真 PI 抽样 PASS(含 `rd_planning_review` + `rd_design_vv`,项目 6446)。剩余:S3 overlay 与 R2/R3 已接。P2 名称匹配、阶段折叠、批量审批已接。选中 rdev 时显示与服务端相同的 CDO 前置说明(`workflowPrerequisite.test.ts`)。P4 键名空间化已接:发布清单用 `bd_`/`pm_`/`tm_`/`sw_`,旧键仍走同一套步骤和模板,旧 doc_id 仍可查(`keyspace_test.go`)。P3 三样本已在 dev 真 PI 上跑过(项目 6533):`rd_sw_plan` 规划期关闭;`rd_proposal` completed 但未对齐模板标题;`rd_planning_review` 当时质量门禁 score 20,是把同节后一张法规表算进问题行。门禁已只读第一张表;保存的终稿不再报「问题行缺少」。建议书标题仍未对齐模板。没有新的真 PI。见 [P3 报告](../test-reports/2026-09-19-rdev-p3-real-pi-test-report.md)。nightly 未扩成四工作流。 | `workflow-def` / `rdev-templates` |
| 纯软件项目自举 | 软件项目创建、Bootstrap、Delivery、受控工程交接 | partial | deferred_enhancement(明确不挡首发) | [设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[ADR](../adr/2026-09-16-software-project-bootstrap-keys.md);[L1 报告](../test-reports/2026-09-16-software-project-bootstrap-test-report.md);[W5a](../test-reports/2026-09-17-w5a-software-bootstrap-ui-pi-test-report.md) | **before**:L1 + UI 仍克隆医疗模板。**after W5a**:catalog 驱动创建、软件不挂医疗 key、docs_only 真 PI 建议 delivery 且不自动激活。**SWBOOT-10 仍 stub**(W5b);本行不升 done | `workflow-design` |
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC;会话/阶段授权 | done | 加固 | [v3 full inventory](../audit/authorization-matrix-v3-full.md);[session 中断](../test-reports/2026-09-16-iam-route-inventory-test-report.md);[fail-closed](../test-reports/2026-09-16-wave1-iam-fail-closed-test-report.md);[410 策略](../audit/2026-09-16-bug11-410-retire-decision.md);[R13](../audit/2026-09-16-r13-data-safety-checklist.md) | 全路由 inventory + session 中断负例 + 410 冻结 + R13 基线已签 | `authz` |
| 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | non_blocker | [docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[正文 UI](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[canonical hash](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md) | 项目 143 只读;不终止 | `docgov` |
| 文档版本 baseline | 账本、人工修订、确定性 diff+lineage、运行时 UI、负责人通知 | done | non_blocker | [管理](../test-reports/2026-09-13-document-revision-management-test-report.md);[Round20 UI](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[ADR](../adr/2026-09-13-document-version-boundary.md) | **before**:完整 PI narrative 混入 → **after**:迁「PI change-report 叙事」。fallback 报告是本行内显式行为,不是缺口 | `docgov` |
| PI change-report 叙事 | 只读消费 diff+lineage 的 PI 叙事;失败全量降级 fallback | done | deferred_enhancement | [Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu7](../ops/long-term/2026-09-16-pu7-pi-narrative-contract.md);[脚手架](../test-reports/2026-09-16-pu7-pi-narrative-test-report.md);[W3 真 PI](../test-reports/2026-09-17-w3-pi-change-report-narrative-test-report.md) | **before**:flag 脚手架 + 仅 fallback。**after**:dev 可开 `PI_CHANGE_REPORT_NARRATIVE` 走产品 PI no-tool narrator(默认 off)。digest 绑定;畸形/超时全量 fallback。**不把 fallback 写成完整 PI** | `docgov` |
| 文档版本 baseline | 账本、人工修订、确定性 diff+lineage、运行时 UI、负责人通知 | done | non_blocker | [管理](../test-reports/2026-09-13-document-revision-management-test-report.md);[Round20 UI](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[ADR](../adr/2026-09-13-document-version-boundary.md);[proposed/authoritative](../ops/short-term/2026-09-20-proposed-authoritative-reports.md) | **before**:完整 PI narrative 混入 → **after**:迁「PI change-report 叙事」。fallback 报告是本行内显式行为,不是缺口。lineage GET 已按 URL 项目和文档可见性裁剪。test_manager 血缘的下游/上游版本改读文档版本,不再写死 1。Agent 候选报告为 `proposed`,正式提交才写 authoritative 后继并挂到版本;拒绝、替代后旧报告不能再出建议。人工修订、导入和聊天卡仍未分开预估与正式报告。项目追踪索引见整改方案 Track T | `docgov` |
| PI change-report 叙事 | 只读消费 diff+lineage 的 PI 叙事;失败全量降级 fallback | partial | deferred_enhancement | [Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu7](../ops/long-term/2026-09-16-pu7-pi-narrative-contract.md);[脚手架](../test-reports/2026-09-16-pu7-pi-narrative-test-report.md);[W3 真 PI](../test-reports/2026-09-17-w3-pi-change-report-narrative-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md);[最小化输入](../ops/short-term/2026-09-20-pi-narrative-clipped-diff.md) | flag 默认 off。`facts.json` 含截断后的 hunk 前后文和影响说明,以及完整 hunk/impact 计数与省略数;摘要 digest 仍不含正文。叙事请求已带 `tool_profile=reasoning`。运行中的 runner 尚未切到 `--no-tools`。不打开开关 | `docgov` |
| 前端工作台 | 三栏 + 块文档 + SSE;错误卡/进度/busy;版本冲突信封;demo seed 默认关;终止 preview | done | non_blocker | [workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md)(项目 6363) | **before**:空「缺口」却 partial → **after**:本行 done。其他 409 消费方信封复用另列 hardening backlog | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax + typed-result-v1 | done | non_blocker | [piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md);[typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | — | `pi-agent` |
| PI Runner / 配置链 | pi-agent + MiniMax + typed-result-v1 | done | non_blocker | [piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md);[typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | 文档生成仍使用读写和搜索工具。`tool_profile=reasoning` 的 argv 是 `--no-tools` 且不加载搜索扩展;未知 profile 拒绝启动。dev 挂载了 `pi-args.mjs`,但本轮未重启容器 | `pi-agent` |
| 三环境运维 | dev/test/main + 共享 KB;对话/业务库隔离 | done | non_blocker | [PROJECT.md](../../PROJECT.md) §4;CURRENT 环境快照 dev/test schema **48**、main **47** | — | `infra` |
| CI / E2E | PR CI、PG 集成、治理 PG、已签真实 PI 门禁;**nightly** schedule/`workflow_dispatch` + infra/product 分类 receipt | done | 加固(阻止**下一次**晋升,不自动否定已发布) | [BUG-08](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md);[PI 三工作流](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md);[W1 green](../test-reports/2026-09-17-w1-ci-e2e-green-nightly-test-report.md) + [receipt `6e2476f0…`](../assets/promotion-receipts/6e2476f0f2e408e111fe06ca7c31a38294a340b3.json) | **before**:partial(FullNone product_fail / secrets 文案过时)→ **after**:secrets 已配;duplicate goose 00048 已清;FullNone+U8 nightly `verdict=pass` | `ci` |
| Artifact 同 digest 晋升 | 候选 commit 一次构建、按 digest 晋升、promotion receipt | done | 加固 | [计划 PU5B](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md) | **关闭**:same-image pin(`candidate-images-*` + `PINNED_IMAGE_MODE` + promote `--require-digests`)。**声明**:单机 retag/digest pin;远程 registry 推送另立任务 | `infra` |
| 可靠事件核心 | PG dispatcher、notify/advance/projection live、生产闭包 hook 退出、Phase2 选择性解耦已合入 | done | non_blocker | [E0A–E2](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md) 等;[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[shared live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[phase2 closeout](../test-reports/2026-09-15-phase2-closeout-test-report.md) | **before**:与 FAV off 混成 partial → **after**:FAV 独立行。选择性后续解耦按收益触发 | `architecture-docs` / `events` |
| 模块开发规范 | 窄端口、领域事件、wire DTO 三种契约;故障隔离红线;新增模块/表/事件流程。不含批次 A–G 的代码整改 | done | non_blocker | [规范](../system-design/2026-09-20-module-development-standards.md);[审计](../audit/2026-09-20-module-coupling-audit.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md) | 文档入口已立。代码整改不在本行 | `module-decoupling-spec` |
| 模块解耦批次 A–G | server 端口装配、chat 解环、docgov 词汇、工作流单向依赖、巨型文件、前端 api client、21 条例外清零 | planned | non_blocker | [分批计划](../remediation/2026-09-20-module-decoupling-batch-plan.md);[审计](../audit/2026-09-20-module-coupling-audit.md) | 各批独立 short-term 与验收后另拆行升 `done`。G1 例外 2026-09-28 到期,到期前须迁走或书面延期。禁止把本行标成进行中来代表七批都已开工 | `module-decoupling-spec` |
| Final Artifact Vault(FAV) | 不可变终态制品库;`FAV_DEGRADED_READ=false` | partial | deferred_enhancement | [Track E 复盘](../ops/research/2026-09-15-track-e-retrospective.md);[U7 报告](../test-reports/2026-09-16-fav-u7-incremental-test-report.md);[W6 shadow](../test-reports/2026-09-17-w6-fav-subscriber-shadow-test-report.md);[short-term](../ops/short-term/2026-09-17-w6-fav-subscriber-shadow.md) | **after W6**:subscriber `ObserveShadow` 只计算 intended outcome,不写副作用。仍**禁止**整支 merge;`FAV_DEGRADED_READ` 默认 false;**live 未放量**(staging→artifact→publication 各 ≥7 天观察窗) | `events` |
| 系统管理台 | 全屏系统级管理视图(总览/KB/特性开关/系统设置/工作流/角色/用户/文档 8 分组);`/api/v1/admin/system/*`;`system_settings` 白名单可写;吸收下线 AdminSettingsModal | done | non_blocker | [short-term](../ops/short-term/2026-09-17-system-admin-console.md);[测试报告](../test-reports/2026-09-17-system-admin-console-test-report.md);commit `f1404d5`/`0eaca61`、merge `dc7c31e`(dev);dev 冒烟 schema 49 + 四端点 + 写读回环 PASS | 二期:Playwright 实跑、细粒度 `system:*` 权限、设置审计日志、KB 运维动作、白名单项接消费方 | `web` + `sysadmin` |
| 个人工程中控台(已移出) | 原本地只读看板与后来的 Control Center 都不再属于本仓库 | removed | 进度管理改由独立项目承担 | [历史设计](../archive/design/2026-09-17-personal-engineering-control-center-plan.md);[历史报告](../test-reports/2026-09-17-engineering-dashboard-test-report.md) | 2026-09-19 删除 `cmd/control-center`、`internal/controlcenter`、`control-center/web`、`deploy/control-center`。不恢复 `engineering-dashboard` | — |
---
@@ -77,7 +84,7 @@
| Intent L1 | partial(混入 U9–U12) | done | U9–U12 → 多意图扩面 | 是(双标签 + 分流 + U1–U3) |
| Chat/ctxmgr | partial(混入语义摘要 D5 误标) | done | D3 摘要行;D7 治理行 | 是(B3 项目 6359) |
| Document revision | partial(混入完整 PI 叙事) | done | PI change-report 叙事行 | 是(Round20;fallback 为声明行为) |
| Frontend workbench | partial(缺口栏已空) | done | 其他 409 信封复用 → backlog | 是(B4 项目 6363) |
| Frontend workbench | partial(缺口栏已空) | done | Wave 3 已收口 projectMembers/freeformDoc/taskRuns/chatSessions 结构化错误信封复用 | 是(B4 项目 6363) |
| 可靠事件 | partial(与 FAV 混行) | done | FAV 独立 deferred | 是(E0–E2 + shared live) |
---
@@ -88,3 +95,11 @@
2. 同一 `mutex` 同时仅一个 Agent `in_progress`(见 CURRENT)
3. 新能力行:复制 [../ops/templates/feature-matrix-row.md](../ops/templates/feature-matrix-row.md)
4. 拆行/收口须保留 before/after 与义务迁移(见上表);禁止缩口径假完成
## 2026-09-17 首次加载性能专项
首次加载与重启首访性能优化:**partial**(U2 静态交付已验收;U3 只做了登录壳拆包,未关闭)。[审计](../audit/2026-09-17-initial-load-performance-audit.md) · [方案](../remediation/2026-09-17-initial-load-performance-plan.md) · [U2 报告](../test-reports/2026-09-17-initial-load-perf-u2-test-report.md)。U2:自托管字体 + br/gzip。U3 进展(`fix/audit-remainder-closeout`):导出、预览、管理台、块编辑器、Mermaid/公式改为点击或出现时再加载。入口包 `index-*.js` 由 2.83 MB / br 626 KB 降到 737 kB / br 170 KB(`index-j0BIrjIR.js`,包内无 katex)。公式在气泡或正文里出现时才加载,富文本复制同样延后。U3 的浏览器资源瀑布还没测,本行不关。U5:`/auth/me` 复用本请求已核过的用户,不再第二次解析会话;会话与用户状态合成一次 JOIN。没有锁等待证据,所以不节流 `last_seen`。`TestAuthMe_LogoutNextRequestIs401`。U1、U6、U7 未做。U4 进展:登录不再按项目数拉成员名册,只同步当前项目;其他项目先种入当前用户以保持会话可见,完整名册在打开成员面板时取。会话列表不再因项目数组变化而重拉,迟到响应用代次丢弃,同一项目的在途成员请求合并。`src/data/initFanout.test.ts`。2026-09-19 浏览器证据(`e2e/initial-load-performance.spec.ts`,n=20,本仓 Vite `:3100` 代理 `:8080`):每次登录成员项目数 1、会话列表 GET 1,匿名与登录后资源路径均无 katex/mermaid/docx。同一探针在重建后的 `:8080`(`index-DOO0-Yh7.js`,schema 53,n=5)成员项目 1、会话列表 GET 1,匿名 JS 传输 172,417 B,首屏路径无 katex/mermaid/docx。重建前旧包 n=1 曾是 704/30。慢网 n=3、CPU 4 倍:10 Mbps 表单可见 558–604 ms,2 Mbps 1279–1296 ms,样本不足 20,U1 不关。U6 不加索引:测到的瓶颈是已消失的成员扇出,没有慢 SQL 证据。U7 已测未关:[报告](../test-reports/2026-09-19-initial-load-u7-restart-test-report.md)。Vite 监听约 0.3 s;314 个模块冷/热 1.45/1.11 s,不是历史十几秒。postgres+app 到 `/ready` 1.0–1.2 s。无头浏览器缺系统库,登录表单可见未测;不宣称较基线下降 50%。mutex `web + static-delivery`(U2 done)/ `loading-performance-audit`。
## 2026-09-17 文档编制人兼任方案
新增能力 **done(U1–U6,已合入 `dev@09a9921`)**:[方案](../remediation/2026-09-17-document-author-only-plan.md) · [源码核查](../audit/2026-09-17-document-author-only-analysis.md) · [U6 验收](../test-reports/2026-09-17-document-author-only-u6-test-report.md) · [收口交接](../ops/handoffs/2026-09-17-document-author-only-closeout.md)。任务归档:`archive/ops/2026-09-17-document-author-only-u{1..6}.md`。总开关默认 off;test/main 晋升与开放授权另授。变更提案 HTTP 仍缺([audit](../audit/2026-09-17-docgov-modification-proposal-http-gap.md))。mutex `document-duty-policy`。
@@ -0,0 +1,150 @@
---
title: "模块开发规范:通信契约、接口与故障隔离"
status: active
created: 2026-09-20
updated: 2026-09-20
---
# 模块开发规范:通信契约、接口与故障隔离
> 本文件是开发者入口,不是新的架构 SSOT。
> 决策仍以 [模块化单体 ADR](../adr/2026-09-14-modular-monolith-decoupling.md) 为准。
> 机器强制仍以 [module-boundaries.yaml](./module-boundaries.yaml) 与 `./scripts/arch-check.sh --mode block` 为准。
> 影响面守则不在此重复,见 [partial-deferred 计划 §2](../remediation/2026-09-16-partial-deferred-completion-plan.md)。
2026-09-20 确认:继续模块化单体。模块之间用进程内窄端口或 PostgreSQL 领域事件通信。不新增通用 IPC/RPC,不拆微服务。跨进程只允许两类既有边界:HTTP(Web↔server、server↔PI Runner)和 `cmd/events` 经 PG lease 消费。
## 1. 问题必须停在本模块
一次故障只允许表现为下面之一,不允许连带改第二个领域包才能编译或才能回滚数据:
| 故障位置 | 允许看见的影响 | 禁止 |
|----------|----------------|------|
| 领域不变量 | 本包返回 typed error;同一 UnitOfWork 回滚 | 别的领域包 import 本包实现后自行改表 |
| 用例编排 | 组合根换一个端口实现 | handler 直接 new 领域服务或拿 `*pgxpool.Pool` 写别人的表 |
| 异步副作用 | 该消费者 delivery 重试、死信或 quarantine | 一个消费者失败卡住其他消费者,或在持锁时调用 LLM/HTTP |
| 对外协议 | server 把领域错误映射成固定错误信封 | 把 SQL、路径、prompt、正文放进 HTTP message |
静态底线已经在门禁里:领域实现互不 import(消费端口和稳定词汇除外)、每张表一个写者、每个事件名有生产者/消费者 allowlist。
## 2. 三种通信契约
只允许这三种。新增第四种(包括模块间 gRPC、进程内全局 bus 单例、跨包直接调未导出帮助函数)先写 ADR。
### 2.1 进程内窄端口
消费者拥有接口,组合根注入实现。参照 `internal/app/chatflow/ports.go`:接口只表达这一个用例要的能力。
| 规则 | 说明 |
|------|------|
| 谁定义 | 调用方包,不放在被调用的领域包里“顺便导出” |
| 宽度 | 一个用例一组方法。三个以上消费者语义相同时才提升为公共端口 |
| 禁止万能接口 | 不得出现聚合所有模块方法的 `Store` / `Engine` 门面 |
| 禁止传输细节 | 端口结构体不带 JSON tag,不返回 `http.Response`、SQL 行、`pgx.Tx` |
| 身份 | `Principal` 只来自已认证会话或服务身份,不从请求体覆盖 UserID/ProjectID |
| 装配 | 只有 `internal/app` 与 `cmd/*` 构造实现。`internal/server` 只拿用例或端口 |
### 2.2 领域事件(跨进程总线)
生产路径是 PostgreSQL outbox + `cmd/events` worker(`FOR UPDATE SKIP LOCKED`),不是内存 `MemoryBus`。`MemoryBus` 只用于 dispatcher 特征测试。
契约只有一处运行时副本:`internal/events/registry.go` 的 `StaticContracts()`,并且必须与 YAML 的 event 段 parity。未登记的事件名或消费者在构建期失败。`fav.artifact_staged` 保持 `Enabled: false`,直到独立 FAV 计划放量。
信封至少包含:`event_id`、`event_name`、`schema_version`、`environment`、`project_id`、aggregate 标识与版本、`actor_ref`、`correlation_id` / `causation_id`、`idempotency_key`、`payload_digest`、`occurred_at`。
事件不得携带 secret、token、prompt、正文或绝对路径。大 payload 先冻结为不可变引用,事件只留 digest。
投递是至少一次。消费者用唯一键或 inbox receipt 保证对外只看见一次结果。副作用与 receipt 能进同一数据库事务的必须同事务。永久失败进 dead letter,不得阻塞其他订阅者。
### 2.3 对外 wire DTO
HTTP/SSE 的请求响应只存在于 `internal/server`(及 `internal/stream` 的传输类型)。领域包不 import server。
错误信封沿用已合入的 typed envelope:`code` / `message` / `request_id` / 可选 `details`。`message` 用固定安全文案;`details` 只允许该 code 的公开字段。授权拒绝不得泄露资源是否存在。
PI Runner 继续 typed-result-v1。typed 字段存在但校验失败必须 fail closed,不得降级成旧解析。
## 3. 输入与输出
### 3.1 新增或修改端口时的 checklist
- [ ] 接口放在消费者用例包,方法名是业务动作而不是表操作。
- [ ] 入参是该动作的命令/查询结构;出参是结果或本用例的 typed error。
- [ ] 无 JSON tag,无 `pgx` 类型,无物理路径,无另一领域包的具体 struct(稳定词汇除外)。
- [ ] 错误值留在领域包或用例包;server 只做 `errors.Is` 到 HTTP code 的映射,映射表集中在一处,不散落在每个 handler。
- [ ] 组合根测试用假实现替换端口,不 import 对方的 SQL。
### 3.2 新增事件时的 checklist
- [ ] `event_name` 形如 `<aggregate>.<fact>`,表达已发生的事实,不是命令。
- [ ] `schema_version` 从 1 起;破坏性字段变更升版本,未知 major fail closed。
- [ ] payload 字段写入 `StaticContracts().PayloadFields`,并同步 YAML allowlist。
- [ ] 生产者、消费者包名写入同一条契约;运行时注册必须是静态清单的子集。
- [ ] 领域提交、envelope、delivery 行在同一个 UnitOfWork。缺 `environment` 或 `project_id` 时 fail closed,禁止写死 `"dev"` / `0`。
- [ ] 消费者有幂等键;重复投递测试证明只有一个可见结果。
- [ ] `./scripts/arch-check.sh --mode block` 与 registry parity 测试通过。
### 3.3 稳定词汇
无行为的枚举和值对象才可以进共享词汇。带解析、哈希、路径拼接的函数留在所属模块(现例:`internal/doccontent`),禁止塞进 vocabulary。
在批次 C 完成前,不要新增对 `docgov.State*` / `docgov.Role*` / `docgov.Err*` 的跨包引用。已有引用记在 [耦合审计](../audit/2026-09-20-module-coupling-audit.md),按整改批次收敛。
## 4. 故障隔离红线
1. **表唯一写者**。`INSERT/UPDATE/DELETE` 只能出现在 YAML `table_owners` 指定的包。跨表原子性由用例打开的 UnitOfWork 提供,不是每个模块各开事务。
2. **解包事务的包有名单**。只有登记过的属主可以从 `uow.TxScope` 取出 `pgx.Tx`。server 与 chat 不在此列。
3. **领域实现互不 import**。需要对方能力时定义端口,由 `internal/app` 注入。用子包绕开编译环但保留反向 import,视为未解耦。
4. **持锁期间不做外部 IO**。LLM、PI Runner、对象存储、HTTP、SSE、大文件复制放在提交之后,由 outbox 驱动。
5. **事件消费者 fail closed**。授权失败、环境不符、schema 未知 → quarantine,不当成瞬时错误重试。FAV 消费者保持禁用。
6. **HTTP 不修投影**。GET 不得写数据库或覆盖 head。修复是独立命令并写审计。
7. **单文件变更面**。新生产 Go 文件不超过 800 行。已有超过 1000 行的文件(见审计热点 5)只允许在对应整改批次里拆,不借无关功能 PR 顺手重排。
## 5. 新增功能怎么落
按顺序做。跳过门禁视为未完成,即使功能在本地可用。
### 5.1 新模块
1. 在 short-term 写明唯一写入所有权(表、文件或无)。
2. 在 `module-boundaries.yaml` 的 `imports` 里只放允许依赖的包。默认可依赖 config、稳定词汇、本模块 repository。不可依赖另一个领域实现。
3. 组合根负责构造。server 若需要该能力,只能通过已有用例端口。
4. FEATURE-MATRIX 加行,mutex 与 CURRENT 认领一致。
### 5.2 新表
1. Goose 迁移只 additive。
2. YAML `table_owners` 登记唯一写者。
3. 跨表不变量写在用例的一个 UnitOfWork 里,并写明锁顺序:project/workflow → 聚合根 → version/turn → task run → outbox。
4. 不允许 server handler 出现该表的 SQL。
### 5.3 新事件或新消费者
走 §3.2。消费者状态是 `off | shadow | live`,按环境 + 消费者配置,不靠单个进程的环境变量偷偷打开。shadow 只写对账,不写业务副作用。FAV 不在此流程里放量。
### 5.4 改已有模块
1. 先看 [耦合审计](../audit/2026-09-20-module-coupling-audit.md) 该包是否已有 P1/P2。有则优先缩小依赖,而不是再增加一个具体类型字段。
2. 影响面守则(partial-deferred §2.2)仍然有效:深模块、禁止新增跨模块 import、schema additive、一能力一 flag、事件双登记、改声明范围要留 before/after。
3. 例外若必须保留,写入 YAML `exceptions` 时带 owner、原因、范围、到期日和移除里程碑。禁止无到期日的例外。本轮不新增例外来掩盖热点 1–4。
## 6. 与现有文档的分工
| 问题 | 读这里 | 不要在本文件找 |
|------|--------|----------------|
| 为什么是模块化单体 | ADR | 实施波次 |
| 事务、锁、FAV、授权模型 | [架构设计](./2026-09-14-module-decoupling-architecture.md) | 今日残留热点 |
| 事件状态机与 Track E/S/P | [Phase 2 计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md) | 新批次 A–G |
| 改功能时如何收敛影响面 | [partial-deferred §2](../remediation/2026-09-16-partial-deferred-completion-plan.md) | 端口字段清单 |
| 今天还有哪些耦合 | [耦合审计](../audit/2026-09-20-module-coupling-audit.md) | 发布门禁 |
| 接下来哪一批先改 | [分批整改](../remediation/2026-09-20-module-decoupling-batch-plan.md) | 代码 |
## 7. 提交前自检
```bash
./scripts/arch-check.sh --mode block
go vet ./...
go test -short ./...
```
改了事件契约时,额外确认 `TestRegistryParityWithYAML` 在跑到的包里通过。文档-only 变更也跑上述命令,防止索引或生成物被误改。
+9
View File
@@ -105,6 +105,8 @@
|-----|------|
| 主报告 | [2026-09-14-module-decoupling-architecture.md](2026-09-14-module-decoupling-architecture.md) |
| ADR | [../adr/2026-09-14-modular-monolith-decoupling.md](../adr/2026-09-14-modular-monolith-decoupling.md) |
| 开发规范(入口) | [2026-09-20-module-development-standards.md](2026-09-20-module-development-standards.md) |
| 耦合审计 | [../audit/2026-09-20-module-coupling-audit.md](../audit/2026-09-20-module-coupling-audit.md) |
| 整改计划 | [../remediation/2026-09-14-module-decoupling-refactor-plan.md](../remediation/2026-09-14-module-decoupling-refactor-plan.md) |
| 一句话总结 | 先以文档可靠性纵向试点验证事务、锁、授权、事件与 FAV,再按证据扩展模块边界 |
@@ -138,6 +140,12 @@
---
### 8. 个人中控台(已移出本仓库)
项目开发进度由独立的统一管理系统负责,不再是本仓库功能。本仓库只保留智能体系统。旧只读工程中控台的历史设计仍在 [../archive/design/2026-09-17-personal-engineering-control-center-plan.md](../archive/design/2026-09-17-personal-engineering-control-center-plan.md),代码不恢复。
---
## 🏗️ 在整体架构中的位置
```
@@ -201,6 +209,7 @@
├── 05-Phase0-基线确认与契约冻结.md
└── 06-Phase7-全链路验收与发布基线.md
├── 2026-09-14-module-decoupling-architecture.md ← 模块化单体解耦
├── 2026-09-20-module-development-standards.md ← 开发者入口:契约 / 接口 / 故障隔离
.tmp/ ← 中间分析文件
├── intent-recognition/
+10 -1
View File
@@ -90,6 +90,7 @@ imports:
- taskrun
- workflowdef
- workspace
- sysadmin
app/chatflow:
- coordinator
- ctxmgr
@@ -147,6 +148,7 @@ imports:
httpx: []
intent:
- maturity
- squad
kb:
- config
maturity: []
@@ -202,6 +204,7 @@ imports:
- workflowdef
- workspace
- artifactvault
- sysadmin
squad:
- agent
- config
@@ -209,6 +212,7 @@ imports:
- stream
- template
- workspace
- workflowdef
storage: []
stream: []
stream/transport:
@@ -223,7 +227,8 @@ imports:
- projectworkflow
- stream
- workspace
template: []
template:
- workflowdef
upload: []
workflow: []
workflow/runtime:
@@ -244,6 +249,8 @@ imports:
dataset:
- artifactvault
- app/uow
sysadmin:
- config
table_owners:
document_records:
@@ -326,6 +333,8 @@ table_owners:
- app/intentflow
intent_plan_shadow:
- app/intentflow
system_settings:
- sysadmin
path_owners:
output.md:
@@ -0,0 +1,254 @@
# 07 研发工作流(rdev)接入——设计与实施计划
- **版本**: v1.1(四项关键决策已由用户确认,2026-09-17;见 §8)
- **日期**: 2026-09-17
- **来源**: 用户需求「在系统中加入研发工作流」;参考项目调研见 [research/2026-09-17-rdev-workflow-reference-analysis.md](../../ops/research/2026-09-17-rdev-workflow-reference-analysis.md)
- **范围**: 在现有 5 个正式工作流(医疗三 + 软件两)之外,新增医疗第 4 工作流「**研发设计控制流程**」(key: `rdev`,**13 阶段 / 60 文档任务一次到位**,ISO 13485 DHF/DMR 设计控制链);并随后对现有工作流任务键做统一命名空间化(D12,P4)
- **分支建议**: `feature/rdev-workflow`(从 dev 切出);键名空间化独立分支 `feature/workflow-key-namespace`
---
## 1. 结论摘要
参考项目的 rdev 工作流与本系统的「workflowdef 版本化定义 + projectinstance 冻结实例 + bizdev/squad 执行链」架构高度同构,接入以**数据与配置为主、代码为辅**:
1. **一个新 manifest**(`rdev.v2.json`,13 stage × 60 doc task)+ **60 份模板** + **一个通用执行器键** `squad.rdev_doc.v1` + **一个数据驱动的 rdev 任务目录表**(squad 包内)即可跑通主链;
2. **两处前置修复**:docgov 文档 Stage 字段去硬编码(现为写死 `V0.5_feasibility`);rdev 启动前置门禁(main 实例 completed,即 CDO 已批准)按 test_manager 先例做**执行器级 precheck**,不恢复流程级依赖(遵循 [WF-DEF-06 整改](../../remediation/2026-09-12-three-workflows-strict-governance-remediation.md));
3. **一个关键命名决策**:60 个任务键统一加 `rd_` 前缀(含模板文件名),避免与既有任务键 `system_reqs` 在 doc_id(`doc_proj{id}_{taskKey}`)、模板加载(`GetDocTemplate(taskKey)` 平铺目录)两层冲突;
4. 分四期实施(P0 前置修复 → P1 核心接入 → P2 治理与体验 → P3 真实 PI 验收),预估 2–3 周(单人)。
## 2. 参考项目 rdev 要点(回顾)
见 [调研笔记](../../ops/research/2026-09-17-rdev-workflow-reference-analysis.md)。核心结构:
- **13 phase / 60 stage**:01 策划(2) → 02 策划评审(1) → 03 设计输入(12) → 04 需求评审(1) → 05 输入阶段评审(1) → 06 设计输出(17) → 07 输出评审(1) → 08 验证(12) → 09 验证评审(1) → 10 转换(3) → 11 转换评审(1) → 12 确认(7) → 13 设计确认报告(1);
- **15 个 skippable**(软件 9 + 电气 3 + EMC + 动物试验 + 临床);
- **三种 artifact_kind**:`document` 47 / `review_minutes` 6 / `upload_index` 7;
- **记录归属**:`dhf` 为主,设计输出/转换类 `dhf+dmr`;
- **followon 门禁**:商务对接 CDO 批准后才可启动;启动时拷贝 bizdev 已填字段;
- **质量纪律**:模板写满、结论先行、UR→RS 追溯、缺项「待确认」、不适用须完整理由仍走审批、不编造数据/签字。
## 3. 现系统机制盘点(与本任务相关)
| 机制 | 现状 | 对 rdev 的影响 |
|------|------|----------------|
| 工作流定义 | `internal/workflowdef`:Definition + Version(schema v2 JSONB 快照、definition_hash、published);正式 key 白名单 `catalog_policy.go`;seed 走 `manifests/*.json` 内嵌 + `BootstrapSeeds` 幂等发布 | 新增第 6 个正式 key;manifest/seed/白名单/目录顺序同步 |
| 模板资产 | `templates/docs/*.md` 启动时全量上传(asset_key=文件名);运行时 `template.GetDocTemplate(taskKey)` 平铺读 `templates/docs/<taskKey>.md` | **平铺命名 → 必须无碰撞**;rd_ 前缀方案 |
| 项目实例 | `projectinstance`:planning→live 冻结 ConfigSnapshot;阶段线性 position;`AdvanceStage` 要求全部 blocking doc task approved;末阶段完成 → InstanceDone | 13 stage 线性推进天然匹配 phase 序;depends_on 语义由阶段序覆盖 |
| 执行链 | server `task_run_handlers` → `taskrun.Manager`(单一 Executor = `bizdev.ExecuteTask`)→ `squad.ExecuteTask`(AdaptivePlanner 按 taskKey 出步骤)→ PI Agent Runner | executor_key 目前是**发布校验元数据**,运行时统一走 bizdev;新增任务主要是 squad 侧编排数据 |
| squad 编排 | `SupportedTasks` 白名单(9 个);`DefaultWorkflowSteps`/`DefaultSquadAgents` 按 taskKey **硬编码 switch**;非白名单任务回落 autonomous adhoc | 60 任务若逐个 switch 不可维护 → 改为按 artifact_kind 三套通用编排 + rdev 数据目录表 |
| 文档账本 | docgov:`doc_id = doc_proj{pid}_{taskKey}`;**Stage 字段写死 `V0.5_feasibility`**(bizdev/service.go:483,489 + docgov/repository.go:28 兜底) | **P0 必修**:改为从冻结实例解析 StageKey |
| 前置依赖 | 无流程级依赖(WF-DEF-06 已移除);test_manager 用执行器级 precheck(approved SRS)+ `WorkflowPrerequisiteBanner` | rdev 同模式:precheck「main 实例 completed」 |
| 血缘 stale | `projectworkflow/service.go` MarkDownstreamStale;test_manager 记录单一上游 hash | 首期统一项目上下文注入;精确 depends_on 血缘列二期 |
| 意图 | L1 `extractDocName` 硬编码 9 个文档名;U8 多意图 task-generate 从 live 实例数据驱动 | rd 文档名匹配需增补或实例驱动化 |
| 前端 | `ProjectWorkflowSwitcher`(目录 API 驱动)+ 激活规划 UI + StageAdvance/Prerequisite Banner | 13×60 规划 UI 需折叠分组与批量三权指派 |
## 4. 关键设计决策
### D1 工作流标识与目录
- `OfficialKeyRDev = "rdev"`;对外名称建议 **「研发设计控制流程」**(与「商务对接流程」命名风格一致;备选「研发流程」);
- `product_domains: ["medical_device"]`(软件域不可选);
- `catalog_order = 40`(排在 test_manager 之后、software_bootstrap 之前);`medicalWorkflowKeys` 扩为四个;
- validator 文案「仅允许选择正式工作流(医疗三或软件自举/交付)」同步更新;审计口径「项目选择页只见 N 个工作流」从 5 → 6。
### D2 任务键与模板命名(关键决策)
**问题**:`doc_id`、模板加载、docgov task_key 三层都以 taskKey 平铺命名。rdev 的 `system_reqs`(SR)与现有 PM 任务 `system_reqs` 直接冲突;且未来任何工作流任务键都共享同一命名空间。
**推荐:60 个任务键统一加 `rd_` 前缀**(`rd_proposal`、`rd_design_plan`、`rd_system_reqs`…),模板文件同步 `rd_*.md`:
- 彻底消除 doc_id/模板/任务键三层冲突,跨工作流血缘清晰;
- 转换机械:从参考项目 `rdev.yaml` 逐行映射生成(可写一次性生成脚本,人工复核);
- manifest 中 `title`/`output_doc_title` 保留中文文档名,用户可见名称不变;
- 模板头部「文件编号 RD-…」保留参考项目编号(RD-PROPOSAL 等),不受键名影响。
**备选**:仅 `system_reqs` 一键改名、其余保持原键。缺点:命名空间纪律弱,未来再加工作流仍会踩。
### D3 manifest 结构(rdev.v2.json)
13 个 StageDef 对应 13 个 phase(键名风格沿用本仓库 `V0.1_triage` 惯例)。示例(完整 60 任务 = 参考项目 rdev.yaml 逐行映射):
```json
{
"schema_version": 2,
"workflow_key": "rdev",
"product_domains": ["medical_device"],
"stages": [
{"key": "RD01_planning", "name": "01 设计和开发策划", "position": 10, "optional": false,
"doc_tasks": [
{"key": "rd_proposal", "title": "项目建议书", "default_enabled": true, "creator_configurable": true,
"blocking_when_enabled": true, "executor_key": "squad.rdev_doc.v1", "quality_gate_key": "quality.generic.v1",
"template_asset_key": "rd_proposal", "output_doc_type": "rd_proposal", "output_doc_title": "项目建议书"},
{"key": "rd_design_plan", "title": "设计开发计划任务书", "default_enabled": true, "creator_configurable": true,
"blocking_when_enabled": true, "executor_key": "squad.rdev_doc.v1", "quality_gate_key": "quality.generic.v1",
"template_asset_key": "rd_design_plan", "output_doc_type": "rd_design_plan", "output_doc_title": "设计开发计划任务书"}
]},
{"key": "RD02_planning_review", "name": "02 策划评审", "position": 20,
"doc_tasks": [{"key": "rd_planning_review", "title": "设计和开发策划评审记录", "...": "同上模式"}]},
{"key": "RD03_design_input", "name": "03 设计输入", "position": 30, "doc_tasks": ["12 个任务"]},
{"key": "RD04_requirements_review", "position": 40, "doc_tasks": ["rd_req_review"]},
{"key": "RD05_input_phase_review", "position": 50, "doc_tasks": ["rd_input_phase_review"]},
{"key": "RD06_design_output", "position": 60, "doc_tasks": ["17 个任务"]},
{"key": "RD07_output_review", "position": 70, "doc_tasks": ["rd_output_review"]},
{"key": "RD08_verification", "position": 80, "doc_tasks": ["12 个任务"]},
{"key": "RD09_verification_review", "position": 90, "doc_tasks": ["rd_verification_review"]},
{"key": "RD10_transfer", "position": 100, "doc_tasks": ["3 个任务"]},
{"key": "RD11_transfer_review", "position": 110, "doc_tasks": ["rd_transfer_review"]},
{"key": "RD12_validation", "position": 120, "doc_tasks": ["7 个任务"]},
{"key": "RD13_validation_report", "position": 130, "doc_tasks": ["rd_design_validation_report"]}
]
}
```
- 全部任务 `default_enabled/creator_configurable/blocking_when_enabled = true`(与本仓库 normalize 惯例一致);
- **skippable 语义**:参考项目的 15 个可声明不适用任务与本仓库「激活规划期可关闭」语义等价(creator 在规划时关闭 = 不适用);「生成完整不适用页仍走审批」列为二期增强(D9);
- `output_doc_type` = 任务键(本仓库惯例 doc type = task key)。
### D4 执行器与质量门禁
- 新增唯一执行器键 **`squad.rdev_doc.v1`**(`workflow/registry.go`),运行时仍统一由 bizdev.ExecuteTask 按 taskKey 分派——与 `squad.test_manager.v1` 模式一致,避免 60 个注册项;
- 质量门禁首期 **`quality.generic.v1`**(全部 60 任务);kind 专用门禁列二期(D9)。
### D5 启动前置门禁(followon 语义)
遵循 WF-DEF-06:**不做流程级 RequiredUpstreamWorkflow**,改为执行器级 precheck(先例:test_manager 查 approved SRS):
- `bizdev.ExecuteTask` 对 `rd_` 前缀任务启动前校验:本项目 **main 工作流 live 实例 `completed`**(即 CDO 报价已批准)。查不到/未完成 → 明确错误文案(「请先完成商务对接流程(CDO 报价批准)后再启动研发设计控制流程」);
- 激活 rdev 实例时(planning 允许,运行由 precheck 兜底):`WorkflowPrerequisiteBanner` 增加 rdev 文案;目录推荐逻辑「main 完成后推荐 PM」扩展「main 完成后推荐 rdev」;
- 启动时拷贝 bizdev 字段:现有 `TaskRunRequest` 已带 project 字段(device_type/intended_use/target_market 来自项目实体),无需额外拷贝机制。
### D6 docgov Stage 字段动态化(P0 必修)
- `bizdev/service.go:483/489` 与 `docgov/repository.go:28` 写死 `V0.5_feasibility` → 改为从请求/冻结实例解析 StageKey 传入(`workflow/runtime/orchestrator.go` 的 `TaskResolution.StageKey` 已具备;`server/task_run_request_build` 把 stage key 带进 `bizdev.TaskRunRequest` 新增的 `StageKey` 字段并透传);
- 兜底策略:解析不到时回落 main 三阶段映射,再回落原值(兼容历史数据,不做历史迁移);
- `maturity` 包的 V0.1/V0.5/V1.0 成熟度映射仅对 main 任务生效,rd_ 任务首期跳过成熟度标签。
### D7 squad 编排(数据驱动重构)
新增 `internal/squad/rdev_catalog.go`:60 项任务目录表(taskKey → title/phase/kind/docCode/skippable/描述),生成来源 = 参考项目 rdev.yaml(一次性转换 + 齐套测试锁定):
- `SupportedTasks` 合并 rdev 目录(`isStandardTask` 命中,避免回落 adhoc);
- `DefaultWorkflowSteps`/`DefaultSquadAgents` 增加 `rd_` 前缀分支,**按 artifact_kind 三套通用编排**(对齐参考项目 squads/rdev.yaml 的 default_steps + 覆盖逻辑):
| kind | 步骤 | 小队 |
|------|------|------|
| document(47) | organizer → engineer(可并行)→ regulatory(可选)→ writer → leader | organizer/engineer/writer/leader;regulatory 注入软件/法规风险类(`rd_sw_*`、`rd_regs_stds`、`rd_adverse_events`、`rd_biocompatibility`、`rd_clinical`、`rd_animal_study`、`rd_risk_*`、`rd_emc_safety`) |
| review_minutes(6) | organizer → writer → leader | organizer/writer/leader(对齐参考项目评审阶段三步) |
| upload_index(7) | organizer → engineer → writer → leader | organizer/engineer/writer/leader |
- leader 角色名「研发设计控制负责人」(对应参考项目 rdev_leader);角色提示复用现有 `configs/agents/*.md`(organizer/engineer/writer/leader/regulatory 已有),rdev 语境差异放进步骤 `Accept` 与 TASK 说明;
- 参考项目 overlays 的核心纪律(写满、结论先行、追溯表必填、缺项「待确认」、不编造数据/签字/附件)合并进:a) 三套 kind 步骤的 `Accept`;b) `configs/shared/writing.md` 增补 DHF 纪律段(GetAgentInstruction 已自动附加该文件,rd 任务天然注入)。
### D8 上游文档注入与血缘
- 首期:`bizdev.ExecuteTask` 对 `rd_` 任务注入 **项目上下文快照**(`projectcontext.BuildSnapshot`,先例 test_manager)+ **同项目已批准文档清单**(bizdev 七件 + 已批准 rd_ 文档,作为 prior_docs 全量注入,交小队自行引用);
- 血缘:沿用 test_manager 模式在 finalize 时记录上游 hash(首期摘要级);精确 `depends_on`(如 rd_verification_review ← rd_design_vv + rd_risk_report_v)列二期(见 [backlog](../../backlog/2026-09-17-rdev-phase2-backlog.md));
- `rd_system_reqs` 与 PM `system_reqs` 的关系:PM 输出若已批准,作为 prior doc 优先注入(不强制、不独占)。
### D9 不适用(N/A)与二期增强
- 首期:N/A = 激活规划期关闭任务(creator_configurable),推进语义由 readiness 门禁保证;
- 二期增强(参考项目行为):保留任务但生成「不适用说明页」(完整理由、走审批);UR/RS 结构化门禁(复用 PM `requirements.json` 模式于 rd_user_needs/rd_system_reqs);review_minutes/upload_index 专用确定性门禁。
### D10 意图与聊天
- U8 多意图 task-generate 从 live 实例 doc tasks 数据驱动——rd 任务应自动可用(P2 验证 60 任务名消歧与澄清卡);
- L1 `extractDocName` 硬编码名表:增补 rd 高频文档名(项目建议书、设计开发计划、风险管理计划、设计验证方案、设计确认报告 等),并**评估改为从 live 实例任务标题动态匹配**(推荐,彻底消除硬编码)。
### D11 前端
- `ProjectWorkflowSwitcher`:rdev 名称/顺序/描述来自目录 API(数据驱动)+ 本地 label 常量增补;
- 激活规划 UI:13 阶段 × 60 任务 × 三权指派是大列表——需按阶段折叠分组、三权「按阶段批量指派 / 继承上一阶段」操作、15 个 skippable 任务预设关闭建议;
- 文档工作台:展示 doc Stage 为 RD 阶段键(依赖 D6);`WorkflowPrerequisiteBanner` rdev 文案;
- 前端测试:workflow 相关既有断言(工作流数量/名称)同步更新。
## 5. 资产与代码改动清单
### 5.1 数据/配置资产
| 资产 | 说明 |
|------|------|
| `internal/workflowdef/manifests/rdev.v2.json` | 13 stage / 60 doc task(D3) |
| `templates/docs/rd_*.md` × 60 | 从参考项目 `templates/docs/*.md` 转换:改名 rd_ 前缀、保留 RD 编号/DHF 归属骨架;核对模板变量(`{{project_name}}/{{generated_at}}/{{snapshot_id}}/{{applicability}}/{{na_rationale}}/{{materials}}` 均为 RenderDoc 可用变量,缺失自动「待确认」) |
| `configs/shared/writing.md` 增补 | DHF 设计控制纪律段(rd 任务注入) |
| `internal/squad/rdev_catalog.go` | 60 项任务目录(title/phase/kind/docCode/skippable) |
### 5.2 Go 代码(按包)
| 包 | 改动 |
|------|------|
| `internal/workflowdef` | catalog_policy.go(常量/名称/顺序/域/医疗四键)、manifest_loader.go(V2ManifestFiles)、bootstrap.go(officialSeedMeta)、validator 文案、publish/catalog 测试更新 |
| `internal/workflow` | registry.go 注册 `squad.rdev_doc.v1` |
| `internal/squad` | rdev_catalog.go 新增;service.go SupportedTasks 合并;workspace.go rd_ 分支(按 kind 三套 DefaultWorkflowSteps/DefaultSquadAgents) |
| `internal/bizdev` | TaskRunRequest 增加 StageKey;ExecuteTask:rd_ precheck(main completed)、prior docs 注入、CreateOrGetDocument 传动态 Stage、ListStages/maturity 对 rd_ 的处理 |
| `internal/server` | task_run_request_build 透传 stage key;workflow_catalog_handlers 名称;齐套校验 Go test(60 manifest 任务 ↔ 模板文件存在非空 ↔ 末模板含「签署」,对齐参考 e2e-rdev.sh 断言 + 「rd_ 键与既有任务键集合不相交」断言) |
| `internal/docgov` | repository.go stage 兜底改为入参优先 |
| `internal/intent` | extractDocName 增补/实例驱动(D10) |
| `web/` | D11 各项 |
### 5.3 文档
- `.doc/ops/short-term/2026-09-17-rdev-workflow-integration.md`(任务条目,随本方案创建)
- FEATURE-MATRIX 新增行(planned → done 演进);验收报告归档 `.doc/test-reports/`
## 6. 分期实施计划
| Phase | 内容 | 分支/PR | 验收标准 |
|-------|------|--------|----------|
| **P0 前置修复** | D6 docgov Stage 动态化 + stage key 透传 + 回归 | `fix/docgov-stage-dynamic` | 现有三工作流全链路 PG 回归 PASS;新文档 Stage 字段 = 实例阶段键 |
| **P1 核心接入** | manifest + catalog/seed + registry + 60 模板 + squad 数据目录与 kind 编排 + rd_ precheck + 齐套 Go test + stub PG 全链路(激活 13 阶段 → rd_proposal 生成/审/批 → 推进 → N/A 关闭路径 → precheck 拒绝路径) | `feature/rdev-core` | `go vet`/`go test -short` PASS;PG 集成测试 PASS;齐套断言 60/60;main 未完成时 rd 任务启动被拒且文案正确 |
| **P2 治理与体验** | 前端(规划 UI 折叠分组/批量三权/PrerequisiteBanner/文档 Stage 展示)+ intent 名称匹配 + prior docs 注入与摘要级血缘/stale + web 测试 | `feature/rdev-web-governance` | web `npm test`/`npm run build` PASS;Playwright 抽检激活与推进;聊天「生成项目建议书」命中 rd_proposal |
| **P3 真实验收** | 真实 PI Agent + MiniMax 全链路:rd_proposal(document)+ rd_planning_review(review_minutes)+ rd_sw_plan 软件类 N/A 三样本;报告归档;CI「PI 三工作流」门禁扩为四 | — | `.doc/test-reports/` rdev 真实 PI E2E 报告;CI green receipt |
| **P4 键名空间化**(决策 4 扩展,D12) | main/pm/tm(+软件两)任务键改 `bd_`/`pm_`/`tm_`(`sw_`)前缀:manifest 新版本 + doc_id 归一映射 + 模板 alias + squad 旧键兼容 + 双路径回归 | `feature/workflow-key-namespace`(**独立验收,不与 P1–P3 合并**) | 旧 live 实例(旧键)与新建实例(新键)双路径 stub 全链路 PASS;全工作流任务键集合无交集断言 PASS;存量文档旧 doc_id 仍可读 |
依赖:P0 → P1 → P2 → P3;P1 与 P2 可部分并行(先冻结前后端契约);P4 在 P3 验收后启动(也可与 P2 并行,但合入 dev 须占集成槽串行)。
## 7. 风险与缓解
| 风险 | 影响 | 缓解 |
|------|------|------|
| 60 任务三权指派 UI 负担 | 激活体验差、误配 | 批量指派 + 阶段继承 + 三权默认创建人兜底(现状) |
| generic 质量门禁误杀评审记录/附件清单类 | 任务被错误打回 | P1 用 stub 对 6+7 个 kind 任务逐一回归;必要时豁免清单 |
| U8/意图对 60 文档名消歧 | 生成错任务 | P2 实例驱动匹配 + 澄清卡;高频名称抽检 |
| 命名空间遗漏 | doc_id/模板冲突回归 | 齐套 test 增加「rd_ 键不与既有任务键相交」断言 |
| CI 门禁与审计口径过时 | nightly 误报 | 同步「PI 三工作流」→ 四;审计 checklist 引用本方案 |
| 大 manifest / 冻结快照体积 | 性能 | 60 任务 JSONB 量级小,P1 PG 测试观察即可 |
## 8. 决策记录(已与用户确认,2026-09-17)
| # | 决策 | 结论 |
|---|------|------|
| 1 | 对外名称 | **「研发设计控制流程」**(key: `rdev`) |
| 2 | 首期范围 | **manifest 一次到位 60 任务 / 13 阶段**,不切试点 |
| 3 | N/A 语义 | 首期「激活规划期关闭」;「生成完整不适用页走审批」等二期增强**记入 backlog**:[2026-09-17-rdev-phase2-backlog](../../backlog/2026-09-17-rdev-phase2-backlog.md) |
| 4 | 任务键前缀 | rdev 60 键统一 `rd_` 前缀;且**现有工作流(main/pm/tm)任务键、模板、阶段等同样做键名空间化处理**(见 D12,独立分期 P4,避免与 rdev 接入耦合) |
### D12 现有工作流键名空间化(决策 4 扩展,P4 实施)
**目标**:全系统任务键命名规约统一为 `<工作流前缀>_<任务>`,杜绝跨工作流 doc_id/模板/任务键冲突:
| 工作流 | 现键(9 个) | 新键 |
|--------|-------------|------|
| main(商务对接) | intake / research / feasibility_dev / feasibility_reg / user_requirements / prelim_design / cdo_quote | `bd_intake` / `bd_research` / `bd_feasibility_dev` / `bd_feasibility_reg` / `bd_user_requirements` / `bd_prelim_design` / `bd_cdo_quote` |
| product_manager | system_reqs | `pm_system_reqs` |
| test_manager | test_manager | `tm_system_verification` |
| rdev(新) | — | `rd_*`(P1 落地,60 个) |
| software_* | (另行盘点 `software.doc.v1` 任务键后纳入 `sw_` 前缀,P4 一并处理) |
**兼容策略(alias 兼容式改名,不破坏存量数据)**:
1. **manifest 版本升级**:main/pm/tm manifest 任务键改为新键 → `UpsertPublishedSeed` 按内容 hash 发布新版本;**冻结实例不迁移**——存量 live 实例继续持有旧键直至 completed(冻结快照是 SSOT,禁止改写);
2. **doc_id 兼容**:`bizdev/doc_id.go normalizeDocID` 增加旧→新映射表(`doc_proj{pid}_intake` → `doc_proj{pid}_bd_intake`),读路径旧 ID 自动归一;**文档账本不批量迁移**,新文档用新键,旧文档旧 ID 保留可查(已有 legacy pattern 归一先例);
3. **模板**:`templates/docs/` 文件改名(bd_intake.md 等),template loader 增加旧名→新名 alias(旧 live 实例运行仍按旧 taskKey 取模板→alias 命中新文件);
4. **squad 白名单**:`SupportedTasks`/`DefaultWorkflowSteps`/`DefaultSquadAgents` 增加旧键 alias 分支(存量实例执行路径不动),新键为主实现;
5. **intent/前端**:`extractDocName` 按文档名匹配不涉键名(无改动);前端断言与 label 按新键更新;
6. **回归**:旧 live 实例(旧键)+ 新规划实例(新键)双路径 stub 全链路回归;齐套断言扩展为「全工作流任务键集合无交集 + 各自前缀正确」。
**风险控制**:P4 独立分支 `feature/workflow-key-namespace`、独立验收,**不与 rdev P1–P3 合并**;若 P4 验收发现存量实例兼容缺口,允许只回退 manifest(DB seed 幂等)。
### 二期 backlog(决策 3,随时可续推进)
见 [2026-09-17-rdev-phase2-backlog](../../backlog/2026-09-17-rdev-phase2-backlog.md):N/A 不适用页生成模式、UR/RS 结构化门禁、review_minutes/upload_index 专用确定性门禁、depends_on 精确血缘与 stale 传播、DMR 双记录归档、软件工作流 sw_ 键盘点等。
@@ -0,0 +1,59 @@
# rdev 模板写作规范
> 适用范围:`templates/docs/rd_*.md`(研发设计控制 / ISO 13485 DHF)
> 更新日期:2026-09-17
## 1. 分工红线(强制)
| 层 | 负责 | 不负责 |
| --- | --- | --- |
| **模板**(`templates/docs/rd_*.md`) | 章节结构、表头、逐节写作指令、示例「待确认」行、治理骨架(编号/适用性/追溯/签署) | 运行时角色口吻、模型选择、粒度下限的强制执行 |
| **overlay / 运行时**(`configs/agents/*`、`configs/shared/writing.md`、未来 overlays) | 写作纪律、DHF 粒度下限、禁止编造、角色边界 | 替代模板定义专业章节结构 |
一句话:**模板管结构与占位;overlay/运行时管写作纪律与粒度下限。**
## 2. 八条基准(源自商务模板实践)
1. **结论先行**:文首结论句完整;后文不得与结论打架。
2. **四段式展开**:结论句 → 表格或列表 → 解读段落 → 出处/支撑;禁止通篇只有列表。
3. **括号指令可执行**:每节括号内写清覆盖范围、缺项规则、禁止项;禁止只写「按本阶段专业结构写」。
4. **表不交空壳**:至少一行「待确认」示例行;禁止空表头。
5. **缺项显式**:统一标「待确认」,并在「待确认清单」汇总。
6. **不做疗效宣称**:设计控制文档禁止疗效/临床效果绝对化用语。
7. **禁止残留提示**:终稿不得留下括号写作提示原文。
8. **追溯可填**:`| RD-` 行存在;上游/下游未知写「待确认」不留空白无说明。
## 3. 治理骨架(每份 rd_ 模板保留)
- 文首元数据:项目 / 生成时间 / 快照 / 文件编号 / 记录归属:DHF / 版本 / 阶段
- `## 结论` / `## 适用性`
- 专业正文各节(≥4 个 `## ` 专业或治理章节合计满足 lint)
- `## 追溯`(含 `| RD-` 行)
- `## 已有材料摘要` / `## 待确认清单` / `## 签署` / `## 说明`
## 4. 补强清单与批次
| 批次 | 范围 | 状态 |
| --- | --- | --- |
| S0 样例 | `rd_design_input_spec` | 本轮 |
| S1 批 1 | `rd_proposal` / `rd_design_input_list` / `rd_system_design` / `rd_regs_stds` / `rd_adverse_events` | 本轮 |
| S1 批 2 | `rd_sw_plan` / `rd_sw_reqs` / `rd_sw_config` / `rd_risk_plan` | 本轮 |
| S1 批 3 | `rd_design_plan` / `rd_user_needs` / `rd_hazard_analysis` / `rd_system_reqs`(SRS 深度移植) | 本轮 |
| S1 续批批1 | 评审记录 6 份(`rd_planning_review` 等) | done |
| S1 续批批2 | 阶段06 硬件/工艺 8 份 | done |
| S1 续批批3 | 阶段06 软件/检验/技术要求+清单 9 份 | done |
| S1 续批批4 | 阶段08 验证 12 份 | done |
| S1 续批批5 | 阶段10–13 转换/确认 11 份 | done |
| S1 续批合计 | 剩余 46 份全部同等深度;allowlist 60/60;真 PI 抽样 PASS | done([报告](../../test-reports/2026-09-17-rdev-template-depth-s1-continued-test-report.md)) |
| S2 / S3 | per-stage 步骤、overlay 机制、专用门禁 | follow-up |
## 5. Lint 门禁
`internal/workflowdef/rdev_template_lint_test.go` 对「已补强 allowlist」断言:
- 不含「按本阶段专业结构写」
- 正文 `## ` 章节 ≥ 4
- 含追溯表行 `| RD-`
- 含 `## 待确认清单` 与 `## 签署`
未列入 allowlist 的模板不参与断言;随批次增长扩大 allowlist。
@@ -0,0 +1,37 @@
# docgov 变更提案 HTTP 测试报告
## 一、 测试背景 (Background)
- 引擎已有 Propose/Decide,但缺少 propose HTTP;前端 pendingProposal 为本地模拟。
- author-only 收口后补齐变更提案闭环。
## 二、 测试目标 (Test Objectives)
- `POST /api/v1/docgov/proposal` 写库成功
- `POST /api/v1/docgov/proposal/decide` 批准写库
- 前端 client 单测覆盖路径
## 三、 测试方案与环境 (Test Plan & Environment)
- OS: Linux;后端:agent-dev `:8080` schema 52;真实 `pi-agent` 环境(本用例不触发任务跑批)
- 层级:Go handler 单测 + 前端 client 单测 + 真实 HTTP
## 四、 预期结果 (Expected Results)
- claim 已认领文档 → propose → status=`pending_author_approval` → decide approve → `approved_by_author`
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### TC-HTTP-01 claim → propose → decide
- **测试输入**: doc `doc_proj6425_rd_design_input_spec`(author=admin/9,已认领)
- **实际输出**: 见 assets `01`–`05`;proposal `prop_rd_design_input_spec_1789654256551680649` → `approved_by_author`
- **评价判定**: PASS
- **性能与耗时**: 全链路 <1s(不含 rebuild)
### TC-UNIT-01
- `go test -run TestServer_DocGovProposeAndDecideHTTP ./internal/server/` PASS
- `node --test web/src/api/docgov.test.ts` 6/6 PASS
## 六、 自动化测试套件汇总 (Test Suite Execution)
- 合入后冒烟:`go vet ./...`;`go test -short ./internal/server/ ./internal/docgov/` PASS
- `./scripts/env-service.sh dev rebuild`;`GET /health` → status=ok schema=52
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- 达到合入/推送标准;**未**晋升 test/main
- 后续:批准后自动应用受控正文 diff(非本期)
@@ -0,0 +1,128 @@
# 文档编制人兼任 U6 多职责动作与真实闭环 测试报告
## 一、 测试背景 (Background)
U1–U5 已落地管理员总开关、逐文档 `duty_policy=author_only`、ABAC 门禁与设置页 UI。交付验收时发现两处前端缺口:
1. 审批动作条从未调用已存在的 `docgov` HTTP(claim / submit-review / review-decision / approver-decision),仅本地改 `lifecycleState`;
2. `resolveCurrentDocRole` 的 author-first 短路使 A/A/A 用户永远只解析为 `author`,审核/批准按钮与快捷指令不可见。
U6 修复可见性与真实 API 接入,使编制人兼任完整闭环第一次可验收。
## 二、 测试目标 (Test Objectives)
- author_only(三职同一人)下 A 可见送审/审核/批准动作;非 A 不可见且直连接口 403;
- 点击认领→送审→审核通过→终审批准走真实后端,写 `document_records` / `document_audit_logs`(含 `duty_policy`);
- 动作条展示「编制人兼任」徽标;`duty_policy` 从 summary 透传到 AST;
- 前端单测与 `tsc --noEmit` 回归通过。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|---|---|
| OS | Linux |
| 环境 | dev `:8080`(feature worktree rebuild,`schema_version=52`,`agent_backend=pi-agent`) |
| 前端 | worktree Vite `:5173` 代理 API |
| 被测文档 | `doc_proj6425_rd_design_input_spec`(项目 6425,`rdev-s0-fresh-*`,既有真实 PI 生成正文) |
| 配置 | 实例快照 `duty_policy=author_only`,有效职责 A/A/A(user_id=9 系统管理员) |
| 负例用户 | `lizhuguan`(id=11) |
分层:
1. 前端单元:`docGovActionVisibility` + `docgov` API client;
2. HTTP 真实闭环:claim → submit → review → approve;
3. HTTP 负例:非职责人 403;
4. 浏览器:Playwright(官方 image)打开 Vite,断言徽标与送审按钮。
## 四、 预期结果 (Expected Results)
| 用例 | 预期 |
|---|---|
| AE-UI | A 打开 author_only 文档见「编制人兼任」+ 送审按钮 |
| AE-API | A 依次 claim/submit/review/approve → `current_state=approved`,审计含 `duty_policy=author_only` |
| AE-NEG | 李主管 review/approve → `DOC_DUTY_FORBIDDEN` HTTP 403 |
| AE-UNIT | author_only 三动作对 A 全 true、对非 A 全 false;分离三人矩阵不变 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 前端单元
**输入**:`npm test` + `npx tsc --noEmit`(worktree `web/`)
**实际输出**:`ℹ tests 390` / `pass 390` / `fail 0`;含 `docgov lifecycle API client` 4 例与 `docGovActionVisibility` author_only 矩阵;`tsc --noEmit` 无错误。
**判定**:PASS
### 5.2 HTTP 真实闭环(author_only)
**输入**:admin Bearer 调用四接口(证据:`assets/2026-09-17-document-author-only-u6/api-lifecycle-author-only.txt`)
**实际输出(摘要)**:
- `POST /docgov/review-decision` → HTTP 200,`current_state=approving`,`duty_policy=author_only`
- `POST /docgov/approver-decision` → HTTP 200,`current_state=approved`
- 审计:`submit_review` / `review_approve` / `approver_approve` 的 `details.duty_policy=author_only`(`db-final-author-only.txt`)
**判定**:PASS
### 5.3 HTTP 负例
**输入**:`lizhuguan` 对同一文档 review/approve(`api-negative.txt`)
**实际输出**:
```text
{"error":"DOC_DUTY_FORBIDDEN","message":"当前用户不是该文档的对应职责人"}
HTTP 403
```
(审核与批准各一次)
**判定**:PASS
### 5.4 浏览器(Vite + Playwright)
**输入**:注入 admin 会话 → 打开 `rdev-s0-6425` → 《设计输入规格书》
**实际输出**:
- `browser-visibility.json`:`hasBadge=true`,`hasClaim=true`,`hasSubmit=true`
- 截图 `screenshots/04-action-bar.png`:明确显示「编制人兼任」徽标与「提交送审」按钮
**判定**:PASS(可见性与徽标);按钮逐级点击以 API 闭环为准(浏览器侧状态机与网络时序未作为唯一证据)。
### 5.5 性能与耗时
| 步骤 | 耗时量级 |
|---|---|
| Vite npm test | ~2s |
| tsc --noEmit | ~3s |
| API 四步闭环 | <1s |
| Playwright 全流程 | ~25s(含容器内 npm i playwright) |
## 六、 自动化测试套件汇总 (Test Suite Execution)
```text
web: npm test → 390 pass / 0 fail
web: npx tsc --noEmit → clean
```
Go 侧 U1–U4 既有矩阵本轮未重跑全量;dev 容器已含 `allow_author_only_approval` 二进制与 goose 00050–00052。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
**结论**:U6 达到合并前验收标准——author_only 多职责动作可见、真实 docgov 闭环与负例 403、兼任徽标透传均有证据。回链 U1–U6 与 FEATURE-MATRIX。
**限制说明**:
- 本轮闭环基于已激活实例快照补丁为 `author_only` + 既有 PI 生成文档;管理员总开关→创建者设置→激活的产品配置链路由 U1–U5 覆盖,本报告不重复。
- 变更提案 HTTP 路由仍缺失(独立缺口,见 audit 笔记),不在 U6 范围。
**后续**:合入 `dev` 后按集成槽位正式冒烟;可补 Playwright 选择器精化使浏览器点击与 DB 状态强一致。
## 相关链接
- Remediation: `.doc/remediation/2026-09-17-document-author-only-plan.md` U6
- Short-term: `.doc/ops/short-term/2026-09-17-document-author-only-u6.md`
- Assets: `.doc/test-reports/assets/2026-09-17-document-author-only-u6/`
- 变更提案缺口: `.doc/audit/2026-09-17-docgov-modification-proposal-http-gap.md`
@@ -0,0 +1,109 @@
# 个人工程中控台(engineering-dashboard)测试报告
## 一、 测试背景 (Background)
仓库需要独立于产品后台的本地只读工程中控台,避免把文档 `done` 误读为已合并或已部署。方案见 [设计](../archive/design/2026-09-17-personal-engineering-control-center-plan.md)。本报告验收一期 `serve` / `export` 实现。
## 二、 测试目标 (Test Objectives)
- 实时 HTML、离线 HTML、JSON 共用 `generation_id` / `revision_id`
- 计划 / Git 实施 / 验证 / 实装四轴独立
- rdev、dev ahead、main events 分叉样本(单元夹具)按方案输出
- 单源失败可 degraded;loopback / token / Host / 只读方法防护生效
- 导出 HTML `0600`、可离线阅读 Markdown、不嵌 assets
## 三、 测试方案与环境 (Test Plan & Environment)
- OS: Linux;Go module `chat-agent-system`
- 工作树:`.worktrees/feature-engineering-dashboard`(`feature/engineering-dashboard`)
- 层级:包单元/集成测试 + CLI 真实 `serve`/`export` 冒烟(只读观察,未启停共享 compose)
## 四、 预期结果 (Expected Results)
| 用例 | 预期 |
|------|------|
| 模型四轴 | doc done 不改 Git/部署 facets |
| rdev 夹具 | planned / unclaimed / 实装 unknown |
| dev ahead | ahead>0 且备注含未确认远端 |
| main fork | readiness ok + containers partial + conflict |
| HTTP | POST 405;无 token 401;坏 Host 403;非 loopback bind 拒绝 |
| export | 权限 0600;含 identity;无 script breakout |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 单元与包测试
- **测试输入**: `go test ./internal/engineeringdashboard/ ./cmd/engineering-dashboard/ -count=1`
- **实际输出**:
```text
ok chat-agent-system/internal/engineeringdashboard 0.009s
? chat-agent-system/cmd/engineering-dashboard [no test files]
```
- **判定**: PASS
- **耗时**: ~0.01s(包测)
### 5.2 go vet
- **测试输入**: `go vet ./internal/engineeringdashboard/... ./cmd/engineering-dashboard/...`
- **实际输出**: (无输出)
- **判定**: PASS
### 5.3 真实 export
- **测试输入**: `go run ./cmd/engineering-dashboard export --repo <worktree> --output /tmp/engdash-export.html`
- **实际输出**: 文件权限 `600`;体积可离线打开;含 CSP 与 snapshot identity
- **判定**: PASS(`stat -c '%a'` → `600`)
### 5.4 真实 serve 冒烟
- **测试输入**: `engineering-dashboard serve --repo <worktree> --addr 127.0.0.1:8799`,随后 curl
- **实际输出**:
```text
{"ok":true}
generation gen_1
revision rev_3378ee42f645c4ab1af69cf691c00103
tasks 50
docs 452
sources [('docs', 'ok', 'fresh'), ('git', 'ok', 'fresh'), ('runtime', 'ok', 'fresh')]
POST_reject HTTPError 405
no_token=401
bad_host=403
```
- **判定**: PASS(HTML/JSON 同源 identity;安全负例符合预期)
- **说明**: 工作树上尚未合入未跟踪的 rdev 文档树;rdev/dev-ahead/main-events **样本契约由包内 fixture 单测覆盖**(`TestModel_*` / `TestReconcile_*`)。
### 5.5 夹具验收样本(单元)
| 样本 | 测试 | 判定 |
|------|------|------|
| rdev 已计划未实施 | `TestReconcile_RDevPlannedUnclaimed` / `TestModel_AcceptanceSamplesAxes` | PASS |
| local ahead origin | `TestReconcile_DevAheadSample` / `TestGit_AheadDoesNotClaimRemoteAvailable` | PASS |
| main ready vs events restarting | `TestReconcile_MainEventsForkConflict` / `TestRuntime_ReadyOKAndEventsRestarting` | PASS |
| Herdr vs 产品 PI Runner | `TestModel_ClaimedWithoutRuntimeKeepsActivityUnknown` | PASS |
## 六、 自动化测试套件汇总 (Test Suite Execution)
对本工具包:
```text
go test ./internal/engineeringdashboard/ ./cmd/engineering-dashboard/ -count=1
# ok engineeringdashboard
go test -short ./internal/engineeringdashboard/... ./cmd/engineering-dashboard/... -count=1
# ok
go vet ./internal/engineeringdashboard/... ./cmd/engineering-dashboard/...
# clean
git diff --check
# clean
```
全仓 `go test -short ./...` 在合入 `dev` 占槽时于主仓执行(本工具未改产品包)。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- **结论**: 一期达到合并标准(独立 CLI、同源快照、四轴、安全边界、导出)。
- **后续**: 跨快照历史、远端 CI/Gitea、受限 Markdown/Mermaid、Agent 查询 API(设计附录已列,不在本期)。
## 相关链接
- 任务: [../archive/ops/short-term/2026-09-17-engineering-dashboard.md](../archive/ops/short-term/2026-09-17-engineering-dashboard.md)
- 设计: [../archive/design/2026-09-17-personal-engineering-control-center-plan.md](../archive/design/2026-09-17-personal-engineering-control-center-plan.md)
@@ -0,0 +1,113 @@
# 首次加载 U2:字体自托管与静态资源交付 测试报告
## 一、 测试背景 (Background)
诊断确认 8080 登录页下载约 2.82 MB 未压缩 JS,且 Google Fonts 外链 CSS 可阻塞首屏;Go `serveSPA` 无压缩协商、无明确缓存头,且缺失 `/assets` 会回退 HTML。本轮实施 U2(自托管字体、构建期预压缩、静态交付协商与 404 修复),不包含 U3 拆包。
## 二、 测试目标 (Test Objectives)
- 登录页无 `fonts.googleapis.com` / `fonts.gstatic.com` 请求;阻断该域名仍可出现登录表单
- 主 JS 响应带 `Content-Encoding: br` 或 `gzip`,传输体积显著下降
- `/assets/missing.js` → 404 且 body 非 HTML
- HTML `Cache-Control: no-cache`;`/assets`/`/fonts` `immutable`;API 无 public 长缓存
- 单元测试与 `go test -short` / `npm test` 通过
## 三、 测试方案与环境 (Test Plan & Environment)
- OS:Linux;Go 1.27.1;dev 容器 `shuimu-agent-app-dev`(镜像 `agent-dev-app@sha256:2d74fe18…`)
- 入口:`http://127.0.0.1:8080`(构建产物)
- 层级:Go 单元测试(`static_assets_test.go`)、前端断言、curl 协商验收、Playwright Docker(`mcr.microsoft.com/playwright:v1.63.0-noble`)浏览器探针
- 代码:`dev@bc01781`(merge `feature/initial-load-perf-u2`);无缓存重建后镜像含 `/fonts` 与 `.br/.gz`
## 四、 预期结果 (Expected Results)
| 场景 | 预期 |
|------|------|
| `Accept-Encoding: gzip, br` | `Content-Encoding: br`,主 JS ~624 KiB |
| 仅 `gzip` | `Content-Encoding: gzip` |
| identity / `gzip;q=0` | 无 `Content-Encoding`,原始体积 |
| `/assets/missing-hash.js` | 404,非 HTML |
| HTML / SPA fallback | `Cache-Control: no-cache` |
| 字体域名阻断 | 登录输入框仍可见 |
| API 未认证 | 401,无 `immutable` |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 单元测试
- **Input**: `go test -short ./internal/server/ -run 'TestStaticAssets_|TestParseAcceptEncoding'`
- **Actual**: `ok`
- **Verdict**: PASS
- **Duration**: ~0.66 s
- **Input**: `npx tsx --test src/styles/noExternalFonts.test.ts`;`npm test`
- **Actual**: 字体断言 2/2 PASS;前端套件 380 + vitest 32 PASS
- **Verdict**: PASS
### 5.2 curl 协商(8080,无缓存重建后)
证据:`.doc/test-reports/assets/2026-09-17-initial-load-perf-u2/after-curl-nocache.txt`
| 检查项 | 实际 | 判定 |
|--------|------|------|
| HTML | `Cache-Control: no-cache`,`Vary: Accept-Encoding`,无 Google Fonts | PASS |
| JS + `gzip, br` | `Content-Encoding: br`,下载 **623,898 B**(原 2,820,055 B,−77.9%) | PASS |
| JS + `gzip` | `Content-Encoding: gzip`,`immutable` | PASS |
| JS identity | 无 encoding,`Content-Length: 2820055`,仍有 `Vary` | PASS |
| `/assets/missing-hash.js` | **404** `404 page not found` | PASS |
| `/fonts/inter-v20-latin.woff2` | 200,`immutable`,48256 B,无 Content-Encoding | PASS |
| `/sessions/demo` | 200 + index,`no-cache` | PASS |
| `/api/v1/chat/sessions` | 401 JSON,无 immutable | PASS |
### 5.3 浏览器探针
证据:`assets/2026-09-17-initial-load-perf-u2/browser-u2.json`
| 场景 | 登录可见 | transferBytes | 外链字体请求 | 判定 |
|------|----------:|------------:|-------------:|------|
| login-cold | **205 ms** | **681,964** | 0 | PASS |
| login-font-domain-blocked | **213 ms** | 681,964 | 0 | PASS |
对比诊断 before(同机冷缓存登录页):可见 ~662 ms,transferSize 2,857,761 B;主 JS 未压缩 2,820,055 B。本轮未登录首屏传输量下降约 **76%**。
主 JS Resource Timing:`transferSize=624198`,`decodedBodySize=2820055`(确认浏览器实际收到 br 变体)。
### 5.4 重启时间线(U7 起点证据,非 U7 完成)
| 事件 | 时刻 (UTC) |
|------|------------|
| 容器 StartedAt | 2026-09-17T08:22:48.548Z |
| goose no migrations / kb online | 08:22:48.660–.676 |
| 日志「监听地址」 | ~08:22:48.7 |
| health=200 | ≤08:22:50(重建后首次探测) |
app restart → listen ≈ **150–200 ms**(DB 已就绪、无迁移)。**不能**据此宣称用户「整机重启十几秒」已解决。
首次 `env-service.sh dev rebuild` 曾因并行 Agent 切走工作树导致镜像装入旧 `web/`;随后在 `dev` 上 `docker compose build --no-cache app` 后验收通过。证据见 `rebuild-nocache-log.txt`。
### 5.5 SSE
未认证 `GET /api/v1/chat/stream` 立即 401 JSON;静态压缩路径不触及 API/SSE。PASS(静态层无缓冲回归迹象)。
## 六、 自动化测试套件汇总 (Test Suite Execution)
```text
go test -short ./internal/server/ -run 'TestStaticAssets_|TestParseAcceptEncoding' → ok
npm test (web) → 380 + 32 PASS
npm run build → precompress 49 .br / 49 .gz
```
未在本报告将 stub 输出当作交付证据;浏览器与 curl 均打真实 8080 容器。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- **U2 达到合并/dev 验收标准**:字体去阻塞、压缩协商、缓存头、assets 404 均有真实证据。
- **不宣称** Success Criteria 全表达标(U1 登录态套件未建;U3 拆包未做,首屏 JS 解码体仍约 2.8 MB)。
- 后续:U3 懒加载;U1/U7 补齐重启与登录态预算;并行 Agent 占用主仓时,合入容器重建须 `--no-cache` 或锁定工作树以免 BuildKit 读到脏上下文。
### 提交与环境
- 分支:`feature/initial-load-perf-u2` → 已 `merge --no-ff` 入 `dev@bc01781`
- 镜像:`agent-dev-app` sha256:2d74fe184585ec0d0d24a051cd6bbc0cfb5b2ef050a376a32027c8e442703cd1
- 资源:`/assets/index-Bu0CqZB_.js` + `.br`
- 未推送、未晋升 test/main
@@ -0,0 +1,49 @@
---
title: "首次加载性能诊断测量(非优化验收)"
status: done
created: 2026-09-17
updated: 2026-09-17
---
# 诊断测量报告
## 范围与结论
只读未登录浏览器基线、静态资源响应与受控网络实验完成;没有业务代码修改,不是优化 PASS 或完整重启验收。用户补充现象为 3100/8080/8081 系统重启后第一次进入约十数秒。
[审计](../audit/2026-09-17-initial-load-performance-audit.md) 包含数值、因果链、源码定位和限制;[方案](../remediation/2026-09-17-initial-load-performance-plan.md) 含重启矩阵、性能预算与治理回归。
## 环境与步骤
- 2026-09-17;源码读取主仓 `feature/rdev-core@52f0fbc`,文档 worktree 基线 `dev@d0ef696`。
- 实际 app-dev image `sha256:355ec1af39c5233ac7e710c6c4300779681edd96d5da85258a9dde71a1698af2`;app-test `sha256:ee7df995c59eb0faf8e26160113d36fcdb57844b4e96989709f8b6edc2f00395`。未证明这些镜像与源码 commit 相同。
- 主 JS hash 分别为 8080 `index-BLnmtk_3.js`、8081 `index-Dk3TnkZv.js`、8000 `index-BT80OB_W.js`。
- 浏览器采用现有 `mcr.microsoft.com/playwright:v1.63.0-noble`、headless Chromium;不登录、不调用写接口、无截图/正文保存。基线未加 CPU 限速。
- 宿主 Playwright 因缺 libatk 启动失败;隔离浏览器容器成功,不安装/修改宿主库。
- 新 context 冷缓存 → 同 context 第二次导航;页面 input 可见后等 1.5 秒采集 Resource Timing。每场景 n=1,未报告分位数。
- 受控场景包括 CDP 10/2 Mbps + 80ms、字体立即失败、字体延迟 5 秒后失败。CDP document RTT 未精确达到设置值,因此是带宽敏感性实验,不是公网仿真认证。
- 3199 隔离 Vite 使用主仓源码、独立 `/tmp` 空 cacheDir,不清理原有 3100 依赖缓存,不更改 Vite 配置;结束后停止临时实例。
- 日志仅提取启动时间和固定事件标记,不保存原始日志。现有 app start→打印监听 dev 166 ms/test 142 ms,不等同真正 ready 或整机重启耗时。
## 结果
| 检查 | 结果 | 限制 |
|---|---|---|
| 三容器主 JS 未压缩 | 确认,约 2.80–2.82 MB | 用户上游代理压缩未知 |
| 8080 冷/热差异 | 662/62 ms | n=1,本机未登录 |
| 带宽敏感性 | 10 Mbps 2.64 s;2 Mbps 11.78 s | 模拟,不是用户网络 |
| 外部 CSS 阻塞 | 人为延迟5s → 登录5.16s | 不能称自然延迟5s |
| 3100资源成本 | 207 请求/12.24 MB | 当时 Vite 服务已运行 |
| 隔离 Vite 空缓存 | 首访1.58s/再次171ms,首访14.45MB | 启动早于浏览器连接,非完整冷启动总耗时 |
| 登录态/整机重启 | 未覆盖 | U1/U7必须补齐 |
| 功能/真实PI/优化收益验收 | 未执行 | 本轮无实现 |
## 原始数据与复现
证据目录:[assets](assets/2026-09-17-initial-load-performance/)。`browser.json`、`controlled.json`、`vite-cold.json` 为浏览器结果;`assets.json` 为静态头/体积摘要。对应 `*.cjs` 是诊断探针,不是业务测试。
复现普通浏览器基线可使用已有 Playwright 镜像,挂载本仓到 `/repo:ro`、证据临时输出目录到 `/out`,执行 `/out/probe.cjs`。脚本假设 `/repo/web/node_modules/playwright` 存在;运行前复制脚本到临时输出目录,不覆盖既有证据。字体拦截会禁用该 context 缓存,不得拿其 warm 结果与正常 warm 作性能比较。
## 交付状态
方案及证据仅在独立本地 worktree,未合 dev、未 push;无共享服务重启/镜像重建。后续实施按 CURRENT 认领与集成槽规约执行。
@@ -0,0 +1,51 @@
# 晋升 optional-duty null FK → test(rc-v1.0.0-beta.4)
## 一、 测试背景 (Background)
dev 已验证 `CreateOrGetDocument` 可选职责 `reviewer_id=0` FK 修复。同一缺陷会波及 test;需合入 `test` 并重建服务。
## 二、 测试目标 (Test Objectives)
- 本地 `test` 合入含修复的 `dev`,tag `rc-v1.0.0-beta.4`
- `./scripts/env-service.sh test rebuild` 后 `:8081` 健康,二进制含 `DOC_LEDGER_ERROR`
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|---|---|
| 合入 | `git checkout test && git merge --no-ff dev`(手工;跳过缺 receipt 的 `promote-to-test.sh`) |
| Tag | `rc-v1.0.0-beta.4` |
| HEAD | `d73d2e8` |
## 四、 预期结果 (Expected Results)
- health/ready:`env=test`、`schema_version=48`
- `/app/server` 含 `DOC_LEDGER_ERROR` / 「文档职责账本写入失败」
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 合入与 tag
- **输入**: merge `dev` → `test`;annotated tag
- **输出**: `test@d73d2e8`;`rc-v1.0.0-beta.4`
- **判定**: PASS
### rebuild + 冒烟
- **输入**: `./scripts/env-service.sh test rebuild`;`curl :8081/health` `/ready`;`:8089/health`
- **输出**:
```json
{"status":"ok","env":"test","schema_version":48,"schema_ready":true,"task_store_ready":true}
```
`FIX_PRESENT=yes`(`grep -a DOC_LEDGER_ERROR /app/server`)。events:`{"env":"test","status":"ok"}`。
- **判定**: PASS
## 六、 自动化测试套件汇总 (Test Suite Execution)
本波为环境晋升冒烟;根因修复证据见 [2026-09-17-docgov-optional-duty-null-fk-test-report.md](./2026-09-17-docgov-optional-duty-null-fk-test-report.md)。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
test 已更新至 `rc-v1.0.0-beta.4` 并 rebuild。未推远端、未合 `main`。
@@ -0,0 +1,93 @@
# rdev 模板深度补强 S1 续批(剩余 46 份)测试报告
## 一、 测试背景 (Background)
S0+S1 首批已将阶段 01–05 共 14 份 `rd_*` 模板补强并合入;剩余 46 份(评审记录、阶段 06–13 硬件/软件/检验/验证/转换确认)仍为占位或中等档深度。本轮按用户确认范围全部按技术类同等深度补强,并抽样真 PI 打样收口。
## 二、 测试目标 (Test Objectives)
- 46 份模板按写作规范补强:四段式章节、ID 表、「待确认」、`| RD-` 追溯、签署骨架;无「按本阶段专业结构写」
- `rdevTemplateDepthAllowlist` 扩至全 60 份;`TestRDevTemplateDepthLint` PASS
- 真 PI 抽样:评审记录类 `rd_planning_review` + 验证协议类 `rd_design_vv` 终稿实质论证、无占位残留
- `go vet ./...` 与 `go test -short ./...` 全绿
- 附带修复:`UpsertPlanningInstance` 分配下一 `instance_no`(避免 main 已完成后无法再存 rdev 计划)
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|---|---|
| OS | Linux |
| 分支 / worktree | `feature/rdev-template-depth-s1-continued` / `.worktrees/feature-rdev-template-depth-s1-continued` |
| 后端 | `pi-agent` + MiniMax-M2.7-highspeed(shuimu-pi-agent-dev) |
| HTTP | `http://127.0.0.1:8080`(agent-dev) |
| 层级 | 模板 lint + 包回归 short + 真 PI 抽样 E2E |
资产目录:[assets/2026-09-17-rdev-template-depth-s1-continued/](./assets/2026-09-17-rdev-template-depth-s1-continued/)
### 用例矩阵
| 批 | 范围 | 份数 | 验证 |
|---|---|---|---|
| 1 | 评审记录 | 6 | lint |
| 2 | 阶段06 硬件/工艺 | 8 | lint |
| 3 | 阶段06 软件/检验/清单 | 9 | lint |
| 4 | 阶段08 验证 | 12 | lint + 真 PI `rd_design_vv` |
| 5 | 阶段10–13 转换/确认 | 11 | lint |
| 抽样 | 评审记录 | 1 | 真 PI `rd_planning_review` |
## 四、 预期结果 (Expected Results)
| 用例 | 预期 |
|------|------|
| lint 全量 | 60 key allowlist 无占位、章节≥4、含追溯/待确认/签署 |
| `rd_planning_review` | 完成态;含「评审范围与对象 / 问题与决议 / 评审结论」;无占位;chars>400 |
| `rd_design_vv` | 完成态;含「目的与范围 / 方法与判定标准 / 风险与残余风险关联」;无占位;chars>400 |
| short 回归 | 全绿 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 模板 lint(全 60 份 allowlist)
- **测试输入**:`go test ./internal/workflowdef/ -run TestRDevTemplateDepthLint -v -count=1`
- **实际输出**:`--- PASS: TestRDevTemplateDepthLint (0.00s)`
- **评价判定**:PASS
- **性能与耗时**:<1s
### 5.2 真 PI — `rd_planning_review`(评审记录类)
- **测试输入**:项目 `6446`(`rdev-s1c-pi-1789657210`),rdev 实例 `313`,阶段 `RD02_planning_review`,backend=`pi-agent`
- **实际输出**(摘自 [summary-s1-continued.json](./assets/2026-09-17-rdev-template-depth-s1-continued/summary-s1-continued.json) / [console.log](./assets/2026-09-17-rdev-template-depth-s1-continued/console.log)):
- `status=completed`,elapsed≈290s,chars=7958
- `no_placeholder=true`,`has_review_sections=true`
- **终稿取样**:[rd_planning_review-final.md](./assets/2026-09-17-rdev-template-depth-s1-continued/rd_planning_review-final.md)
- **评价判定**:PASS
- **性能与耗时**:约 290s
### 5.3 真 PI — `rd_design_vv`(验证协议类)
- **测试输入**:同项目推进至 `RD08_verification` 后启动
- **实际输出**:
- `status=completed`,chars=10970
- `no_placeholder=true`,`has_protocol_sections=true`
- **终稿取样**:[rd_design_vv-final.md](./assets/2026-09-17-rdev-template-depth-s1-continued/rd_design_vv-final.md)
- **评价判定**:PASS
- **性能与耗时**:整段抽样脚本约 704s(含评审审批与阶段推进)
### 5.4 运行时修复备注
worktree 重建后若缺少根 `.env`,会导致 `MINIMAX_API_KEY` / `PI_AGENT_RUNNER_AUTH_TOKEN` 为空,表现为 PI 空跑或 `typed result rejected`。本轮通过 symlink 根 `.env` 并 `--force-recreate` app/pi-agent 恢复;另提交 `instance_no` 递增修复以支持 main 完成后另存 rdev 计划。
## 六、 自动化测试套件汇总 (Test Suite Execution)
```text
go test ./internal/workflowdef/ -run TestRDevTemplateDepthLint -v -count=1
--- PASS: TestRDevTemplateDepthLint (0.00s)
go test -short ./...
# 全包 PASS(含 internal/server、workflowdef、projectinstance 等)
```
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- **结论**:S1 续批达到合入标准——46 份模板深度补强完成,lint 覆盖 60/60,真 PI 双抽样 PASS。
- **后续**:S2(per-stage 编排/配置化)、S3(overlay/专用门禁)、P2 前端、P3 三样本全量 E2E、P4 键名空间化仍属 backlog;本轮**不晋升** test/main。
@@ -0,0 +1,118 @@
# rdev 模板深度补强(S0 + S1 首批)测试报告
## 一、 测试背景 (Background)
`rdev` 60 份模板多数仍含「按本阶段专业结构写」通用占位;且 `rdevLeaderAgent` 虽注册了角色,但 `buildSubWorkspaces` 按角色名加载 `configs/agents/leader.md`,导致研发终审全部回落商务口吻。本轮按计划交付 B1 leader 注入修复、阶段 01–05 共 14 份模板专业章节补强,并以 dev 真实 PI 打样收口。
## 二、 测试目标 (Test Objectives)
- rdev leader 子工作区 `AGENTS.md` 含「设计控制 / 研发设计控制负责人」,且不含「商务对接负责人」「CDO」
- intake leader 回归仍含「商务对接负责人」
- 14 份已补强模板 lint 绿灯(无通用占位、章节≥4、含追溯/待确认/签署)
- 真实 PI:`rd_design_input_spec` 终稿五节有实质论证;账本 `stage=RD03_design_input`
- `go vet ./...` 与 `go test -short` 全绿
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|---|---|
| OS | Linux |
| 分支 / worktree | `feature/rdev-template-depth` / `.worktrees/feature-rdev-template-depth` |
| 后端 | `pi-agent` + MiniMax(shuimu-pi-agent-dev) |
| HTTP | `http://127.0.0.1:8080`(agent-dev) |
| 层级 | 单元(prompt 注入 / lint)+ 包回归 short + 真 PI 端到端 |
资产目录:[assets/2026-09-17-rdev-template-depth/](./assets/2026-09-17-rdev-template-depth/)
## 四、 预期结果 (Expected Results)
| 用例 | 预期 |
|------|------|
| S0.1 PrepareWorkspace(rd_design_input_spec) | leader AGENTS 设计控制口径,无商务串味 |
| S0.1 PrepareWorkspace(intake) | leader AGENTS 仍含商务对接负责人 |
| S0.2 / S1 lint allowlist 14 份 | 无「按本阶段专业结构写」;`## `≥4;含 `\| RD-`、待确认、签署 |
| S0.3 main-only intake | 真 PI completed;文档 `stage=V0.1_triage`;实例 completed |
| S0.3 rdev-only DI | 真 PI completed;五节实质;`stage=RD03_design_input`;leader 无商务串味 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 S0.1 leader prompt 注入(单元)
- **测试输入**: `go test -short ./internal/squad/ -run 'RDevLeader|LeaderPrompt|InstructionsFile' -count=1`(及全包 short)
- **实际输出**: `ok chat-agent-system/internal/squad`(见第六节汇总)
- **判定**: PASS — `GetAgentInstructionFile` + `InstructionsFile` 优先注入已覆盖;商务回归保留
### 5.2 模板 lint(S0.2 + S1 14 份)
- **测试输入**: `go test -short ./internal/workflowdef/ -run RDevTemplateLint -count=1`
- **判定**: PASS — allowlist 覆盖 `rd_design_input_spec` + 批 1/2/3 共 14 份
### 5.3 真实 PI:main 仅 intake(项目 6424)
- **测试输入**: 新建 medical_device 项目;规划期仅保留 `intake`;`backend=pi-agent`;异步 `POST /api/v1/tasks/runs`
- **实际输出**(摘自 [pi-intake-meta.json](./assets/2026-09-17-rdev-template-depth/pi-intake-meta.json)):
```text
run_id=run_1789635054471569201
Status=completed
WorkflowStageKey=V0.1_triage
WorkspaceID=/app/data/workspaces/bizdev/intake_1789635054485631143
duration_ms=220109
```
- 终稿取样:[intake-final.md](./assets/2026-09-17-rdev-template-depth/intake-final.md)
- intake leader(商务回归):[intake-leader-AGENTS.md](./assets/2026-09-17-rdev-template-depth/intake-leader-AGENTS.md) 含「商务对接负责人」
- 实例推进至 completed:[main-instance-final.json](./assets/2026-09-17-rdev-template-depth/main-instance-final.json)
- **判定**: PASS
- **耗时**: ~220 s
### 5.4 真实 PI:rdev 仅 rd_design_input_spec(项目 6425)
- **测试输入**: 激活 `rdev`;规划期仅保留 `rd_design_input_spec`;推进至 RD03;同项目插入 completed `main` 实例以满足硬 precheck;真 PI 生成
- **实际输出**(摘自 [summary-rdev.json](./assets/2026-09-17-rdev-template-depth/summary-rdev.json) / [pi-rd_design_input_spec-meta.json](./assets/2026-09-17-rdev-template-depth/pi-rd_design_input_spec-meta.json)):
```text
run_id=run_1789635960880707641
Status=completed
WorkflowStageKey=RD03_design_input
di_chars≈15988
has_five_sections=true(## 一、功能要求 … ## 五、法规与标准符合性)
no_placeholder=true
agents_ok=true(研发设计控制负责人)
no_business_in_agents=true
no_business_in_final=true
wall≈450s(09:06–09:13Z)
```
- 终稿:[rd_design_input_spec-final.md](./assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md)
- leader AGENTS:[rdev-leader-AGENTS.md](./assets/2026-09-17-rdev-template-depth/rdev-leader-AGENTS.md) 开篇为「研发/设计控制小队的负责人…不做报价核算与商务承诺」
- 账本 stage:[rd_design_input_spec-docgov.json](./assets/2026-09-17-rdev-template-depth/rd_design_input_spec-docgov.json) → `"stage":"RD03_design_input"`
- **判定**: PASS(五节均有结论句 + 事实表 + 缺口标注;无通用占位;无商务/CDO 串味)
- **耗时**: ~450 s(小队墙钟);squad 产出约 5 min(organize→review)
- **备注**: 终稿章节标题为「## 一、功能要求」等形式(带中文序号),语义覆盖模板五节。
## 六、 自动化测试套件汇总 (Test Suite Execution)
```text
$ go vet ./...
(无输出,exit 0)
$ env -u DATA_DIR go test -short ./internal/squad/ ./internal/template/ ./internal/workflowdef/
ok chat-agent-system/internal/squad 0.030s
ok chat-agent-system/internal/template 0.810s
ok chat-agent-system/internal/workflowdef 0.004s
$ env -u DATA_DIR go test -short ./...
# 全包 PASS(exit 0;约 59s)。说明:宿主若 export 了 DATA_DIR=./data/dev,
# 会覆盖 bizdev-cli 测试 -env 内的临时目录,导致相对路径读不到 squad.json;门禁以 unset DATA_DIR 为准。
# 另:本分支自带的 engineeringdashboard 包已补入 module-boundaries.yaml allowlist(随 rebase 丢弃 eng-dashboard 重复提交后可再收敛)。
```
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- **结论**: S0 + S1 首批达到合并候选标准(代码+真 PI 取样+门禁)。leader 错配已修;14/60 模板已补强。
- **后续**(见 [backlog](../backlog/2026-09-17-rdev-phase2-backlog.md)):
- S1 续批:阶段 06–13 剩余模板 + 中等档补指令
- S2:per-stage 步骤 / regulatory×complexity_tier / 模型去硬编码 / manifest hint
- S3:轻量 overlay + R2/R3 门禁 + P3 三样本 E2E
- **合 dev 提示**: 依赖 `feature/rdev-core`;合入前对 rdev-core `rebase dev`,丢弃已进 dev 的 engineering-dashboard 重复提交。
@@ -0,0 +1,87 @@
# 系统管理台(System Admin Console)一期 测试报告
## 一、 测试背景 (Background)
系统级管理能力此前散落在 `AdminSettingsModal`(用户/审批/策略/角色/工作流/状态六 tab 模态框),且系统状态、KB、特性开关无统一查看入口;feature flag 全部 env 驱动、无 DB 持久化设置。本任务落地独立的系统管理界面:后端新包 `internal/sysadmin`(薄聚合层)+ `/api/v1/admin/system/*` + `system_settings` 表(goose 00049);前端全屏 `AdminConsoleView`(八分组),吸收并下线旧模态。
- 分支:`feature/system-admin-console`;merge commit:`dc7c31e`(dev)
- 代码 commit:`f1404d5`(后端)、`0eaca61`(前端)
## 二、 测试目标 (Test Objectives)
1. admin 可从 LeftRail 入口进入全屏管理台,八分组可用;
2. `/api/v1/admin/system/{overview,kb,features,settings}` 契约正确、脱敏、仅 admin 可访问;
3. 白名单设置 PUT 写后读生效,未知 key 400,匿名 401;
4. goose 00049 在 dev 容器自动迁移(schema_version 48→49);
5. `go vet` / `go test -short` / archtest / `web npm test` / `npm run build` 全绿。
## 三、 测试方案与环境 (Test Plan & Environment)
- 环境:Linux,dev 容器栈(`env-service.sh dev rebuild` 后),app `agent-backend=pi-agent`(真实 PI Runner 容器在线),PG `:5433`,共享 KB `:5432`
- 层级:
- Go 单元/集成:`internal/sysadmin`(读优先级、写校验、聚合、脱敏)+ `internal/server`(真实 mux + 内存 IAM 的 401/403/200/400/503)
- 前端:`npm test`(node:test 378 + vitest 32)+ `npm run build`
- 容器冒烟:health、四个 GET 端点、PUT 写读回环、负例(匿名 401、未知 key 400)
- 架构约束:`go test ./internal/archtest/...`(module-boundaries.yaml 已登记 sysadmin)
## 四、 预期结果 (Expected Results)
- health `schema_version=49`;overview 字段 camelCase 且与 health 信号一致;kb 响应不含任何密码字段;features 覆盖主要功能开关;settings 6 项白名单;PUT 后 GET 持久化;匿名 401;非 admin 403(单测覆盖);未知 key 400。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 用例 1:dev 容器冒烟(rebuild 后真实环境)
- **Input**:`./scripts/env-service.sh dev rebuild` → `curl /health`
- **Actual Output**:
```json
{"status":"ok","env":"dev","agent_backend":"pi-agent","kb_ready":true,"database_ready":true,"schema_version":49,"schema_ready":true,"task_store_ready":true}
```
- **Verdict**:PASS(goose 00049 实跑,48→49)
### 用例 2:admin 四端点契约
- **Input**:admin 登录(compose 默认种子账号)→ Bearer 调四端点
- **Actual Output**:
```
overview: {"status":"ok","env":"dev","agentBackend":"pi-agent","databaseReady":true,"schemaVersion":49,"taskStoreReady":true,"kbOnline":true,"uptimeSeconds":170}
kb: {"online":true,"host":"shuimu-kb-shared","port":5432,"database":"regulations","user":"regkb","embeddingModel":"bge-m3","rerankerEnabled":true,"sslMode":"disable"}
features: 22 项;groups=[agent, artifact-vault, auth, ctxmgr, docrevision, intent, intentflow, system]
settings: 6 项 [ui.maintenance_notice, ui.read_only_mode, chat.default_session_role, tasks.default_auto_repair, kb.default_search_limit, notifications.stage_advance_reminder]
```
- **Verdict**:PASS(kb 无密码字段,单测另断言响应体不含 "assword")
### 用例 3:设置写读回环 + 负例
- **Input**:`PUT settings/ui.maintenance_notice {"value":"slot-smoke-2026-09-17"}` → GET → `PUT no.such.key` → 匿名 GET overview → 复位为空
- **Actual Output**:
```
PUT 200 → value= slot-smoke-2026-09-17 updatedBy= 9
GET 持久化 → persisted value= slot-smoke-2026-09-17
PUT no.such.key → 400
匿名 overview → 401
复位 → reset-ok
```
- **Verdict**:PASS
### 用例 4:非 admin 403
- **Actual**:`internal/server/admin_system_handlers_test.go` 真实 mux + 内存 IAM:普通注册用户访问全部 5 端点 → 403;未认证 → 401。PASS
## 六、 自动化测试套件汇总 (Test Suite Execution)
- `go vet ./...`:通过
- `go test -short ./...`:全部 ok(含 `internal/sysadmin` 12 用例、`internal/server` 新增 6 用例;PG 用例 TEST_DATABASE_URL 守卫 skip)
- `go test ./internal/archtest/...`:ok
- `cd web && npm test`:node:test 378/378 + vitest 32/32 通过
- `cd web && npm run build`:✓ built in 7.58s(仅既有 chunk 体积警告)
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
一期达到合并/验收标准:管理台骨架与八个分组、system_settings 写读机制、权限门禁、迁移实跑均验证通过。
后续(二期候选):
1. Playwright 冒烟 `web/e2e/admin-console.spec.ts` 需真实 dev 栈 + `RUN_UI_ACCEPTANCE=1` + ADMIN 凭据执行(本次未跑,默认 skip);
2. 细粒度 `system:view`/`system:manage` 权限与设置变更审计日志;
3. KB 运维动作(连接测试/重建索引);白名单设置项接入真实消费方;
4. 403 自动退回工作台(当前为提示 + 手动返回,便于验收截图)。
@@ -0,0 +1,135 @@
# Wave 0 P0 Bug 修复测试报告
## 一、 测试背景 (Background)
系统体检(2026-09-17)确认 SSE 聊天/任务流被全局 `WriteTimeout=120s` 强杀、`run/stream` 畸形 body 误启任务与 Flush 后失败、前端会话窗口缓存 key 不一致、IndexedDB 恢复覆盖新增交付物。本波次按整改方案 Wave 0 实施 B-1~B-6。
## 二、 测试目标 (Test Objectives)
- B-1/B-2:`handleChatStream` / `handleRunTaskStream` 心跳 + `extendSSEWriteDeadline`,长静默不因 WriteTimeout 断流
- B-3:畸形 JSON → HTTP 400,不开 SSE
- B-4:`CreateAndStart`/`Subscribe` 在 Flush 前;失败为普通 JSON 错误
- B-5:`saveSessionWindowCache` 一律带 `userId`;LRU 驱逐完整 cache key
- B-6:`applyRestoredFileRaw` 函数式合并,不丢 mount 后新增 deliverable
- 质量门禁:`go vet` / `go test -short` / `npm test` / `npm run build` 全绿;dev rebuild + health/ready
## 三、 测试方案与环境 (Test Plan & Environment)
- OS:Linux;Go 模块全量 `-short`;前端 `tsx --test` + vitest
- 后端 Stub 单测 + 真实 dev 容器(`pi-agent` + MiniMax-M2.7-highspeed)
- 分支:`fix/wave0-p0-sse-chat-cache-bugs` → 合入本地 `dev@810fb96`(后随 docs 再合)
- 资产:`.doc/test-reports/assets/2026-09-18-wave0-p0-bug-fixes/`
## 四、 预期结果 (Expected Results)
| 用例 | 预期 |
|------|------|
| 畸形 run/stream body | 400,非 `text/event-stream` |
| CreateAndStart 注入失败 | 非 SSE Content-Type,正文含 start failure |
| 短 WriteTimeout + 心跳 | 流时长 > WriteTimeout 仍可读到 done |
| 缓存写路径 | 全部调用含 `userId`;超 LRU 驱逐带前缀 key |
| restore 合并 | prev 新增条目保留,仅补丁 fileRaw |
| 真实 PI 聊天 | 静默生成期出现 `: heartbeat`,最终 `event: done` |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 后端单测(`internal/server/sse_wave0_test.go`)
**测试输入**:`go test -short -count=1 ./internal/server/ -run 'TestRunTaskStream_InvalidJSON|TestRunTaskStream_CreateAndStartFails|TestSSEHeartbeat_Helpers|TestRunTaskStream_ValidBody' -v`
**实际输出(摘要)**:
```
--- PASS: TestRunTaskStream_InvalidJSON_Returns400 (0.14s)
--- PASS: TestRunTaskStream_CreateAndStartFails_BeforeSSEFlush (0.12s)
--- PASS: TestSSEHeartbeat_HelpersSurviveShortWriteTimeout (0.70s)
--- PASS: TestRunTaskStream_ValidBody_OpensSSEWithHeartbeatPath (0.17s)
PASS
```
**评价判定**:PASS
**性能与耗时**:约 1.1s 包级
### 5.2 前端单测
**测试输入**:
```
npx tsx --test src/hooks/useChatWindow.cacheKey.test.ts \
src/data/storage.windowCache.test.ts src/data/fileStore.test.ts
```
**实际输出**:
```
✔ applyRestoredFileRaw: 以 prev 为权威…
✔ applyRestoredFileRaw: 无可用 fileRaw 时返回同一引用
✔ window cache LRU: 驱逐带 userId 前缀的完整 cache key…
✔ window cache: 读写同一 userId 前缀,跨用户不串读
✔ useChatWindow: 所有 saveSessionWindowCache 调用必须传入 userId
ℹ tests 5 / pass 5
```
**评价判定**:PASS
### 5.3 全量回归
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `go test -short -count=1 ./...` | 全包 ok(含 server) |
| `cd web && npm test` | 397 + 32 vitest PASS |
| `cd web && npm run build` | PASS(含 precompress) |
### 5.4 dev 容器冒烟
**测试输入**:`./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/health` 与 `/ready`
**实际输出**:
```json
{"status":"ok","env":"dev","agent_backend":"pi-agent","schema_version":52,"schema_ready":true,...}
```
**评价判定**:PASS
### 5.5 真实 PI 聊天 SSE(心跳接线证据)
**测试输入**:admin 登录后 `POST /api/v1/chat/stream`,长合规分析提示词;资产见 `assets/2026-09-18-wave0-p0-bug-fixes/chat-stream-long.sse.txt`
**实际输出(关键片段)**:
```
event: phase
...
: heartbeat 1789663534
: heartbeat 1789663549
: heartbeat 1789663564
: heartbeat 1789663579
event: delta
...
event: done
data: {...,"done":{"duration_ms":70164,"status":"completed",...}}
```
**评价判定**:PASS(真 PI 回合约 70s;静默生成期 4 次心跳,流完整收尾)。
**说明**:绝对墙钟 >120s 的真 PI 未再压测(二次加长提示触发 `SECURITY_FORBIDDEN` 快速返回);WriteTimeout 跨越由 `TestSSEHeartbeat_HelpersSurviveShortWriteTimeout`(WriteTimeout=200ms,流 700ms)覆盖,与线上心跳机制同源。
## 六、 自动化测试套件汇总 (Test Suite Execution)
- Go:`go vet ./...` + `go test -short -count=1 ./...` → 全绿
- Web:`npm test`(397 node:test + 32 vitest)+ `npm run build` → 全绿
- 新增:`sse_wave0_test.go`、`useChatWindow.cacheKey.test.ts`、`storage.windowCache.test.ts`、`fileStore.test.ts`
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- Wave 0(B-1~B-6)达到合入与冒烟标准,可关闭 short-term 任务。
- 后续:Wave 1(E-1 main ENV)仍待决策;可选补一次刻意 >120s 的受控长任务(例如阻塞 executor 的 task run events)作为额外证据。
- 红线未触碰:FAV / MULTI_INTENT_PLAN_TIER / SEMANTIC_SUMMARY_REPLACE / 项目 143。
## 相关链接
- Audit: [../audit/2026-09-17-system-health-check.md](../audit/2026-09-17-system-health-check.md)
- Remediation: [../remediation/2026-09-17-system-health-remediation-plan.md](../remediation/2026-09-17-system-health-remediation-plan.md)
- Short-term: [../ops/short-term/2026-09-18-wave0-p0-bug-fixes.md](../ops/short-term/2026-09-18-wave0-p0-bug-fixes.md)
- Assets: [./assets/2026-09-18-wave0-p0-bug-fixes/](./assets/2026-09-18-wave0-p0-bug-fixes/)
@@ -0,0 +1,100 @@
# Wave 1:main 环境 ENV/schema 修正测试报告
## 一、 测试背景 (Background)
体检确认 main 环境 app `ENV=prod` 与 events `ENV=main` 不一致(E-1 critical),schema 落后且晋升缺强制顺序(E-2),以及 `Env==""` 视同 dev 放开导入端点(E-5)。
## 二、 测试目标 (Test Objectives)
- app/events health 均报 `env=main`
- events 先 healthy 后启 app;goose 迁移后 `schema_ready=true`(实测 schema_version=52)
- `event_consumer_modes` 中 main 四行仍为 `off`
- 空 Env 导入端点 403;compose app/events ENV 一致单测 PASS
## 三、 测试方案与环境 (Test Plan & Environment)
- 分支:`fix/wave1-main-env-fix` → 合入本地 `dev`
- 真实 main:`./scripts/env-service.sh main rebuild`(注意:执行前须清掉 shell 内残留的 `source .env.dev` 覆盖变量,否则端口会串到 8080/18865)
- 单测:`internal/config/compose_env_consistency_test.go`、`TestServer_ChatWindow_ImportGuard_EmptyEnvFailsClosed`
## 四、 预期结果 (Expected Results)
| 项 | 预期 |
|----|------|
| events `/health` | `env=main` |
| app `/health` `/ready` | `env=main`,`schema_ready=true` |
| consumer modes | main 四行 `off` |
| settings / projects | HTTP 200,无 SQL 缺列错误 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 单测
```
--- PASS: TestComposeAppEventsENVAligned
--- PASS: TestComposeMainAppDependsOnEventsHealthy
--- PASS: TestServer_ChatWindow_ImportGuard
--- PASS: TestServer_ChatWindow_ImportGuard_EmptyEnvFailsClosed
```
**判定**:PASS
### 5.2 main rebuild 启动顺序
日志摘要(`/tmp/wave1-main-rebuild3.txt`):
```
Container shuimu-agent-events-main Started
Container shuimu-agent-events-main Waiting
Container shuimu-agent-events-main Healthy
Container shuimu-agent-app-main Starting
Container shuimu-agent-app-main Started
```
**判定**:PASS(E-2 depends_on 生效)
### 5.3 health / schema / modes
**events**:`{"env":"main","owner":"events-1","status":"ok"}`
**app**:`{"status":"ok","env":"main",...,"schema_version":52,"schema_ready":true}`
**modes**:main 的 fav/notify/projection/workflow_advance 均为 `off` revision=1
**goose**:`version_id=52`
资产:`.doc/test-reports/assets/2026-09-18-wave1-main-env-fix/`
**判定**:PASS(E-1 对齐;schema 由 47 升至 52;红线未改 mode)
### 5.4 冒烟
| 调用 | 结果 |
|------|------|
| POST `/api/v1/auth/login` | login_ok |
| GET `/api/v1/admin/system/settings` | 200(system_settings 可读) |
| GET `/api/v1/projects` | 200 `[]` |
| GET `/api/v1/admin/system/overview` | 200,`env=main`,`schemaVersion=52` |
**判定**:PASS
### 5.5 附带修复说明
main `events` 在 `ENV=main` 下原先因 `validateProductionSecrets` 缺 KB/admin 口令而持续 Restarting(Wave 1 前已存在)。为使 `depends_on events healthy` 可落地,向 events 注入 `POSTGRES_SHARED_KB_DSN` / `ADMIN_PASSWORD` / `ALLOW_IN_MEMORY=false` 并挂入 `shared-net`。
## 六、 自动化测试套件汇总 (Test Suite Execution)
- `go vet ./...` PASS
- `go test -short ./internal/config/`、`./internal/server/` Wave 1 相关用例 PASS
- 全量 `go test -short ./...`:`cmd/bizdev-cli` 因本机 `mkdir data/dev/data: permission denied` 失败(环境权限,与本波次无关);其余包 ok
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
Wave 1(E-1/E-2/E-5)达到关闭标准。建议后续:
1. Wave 2 配置声明对齐
2. `env-service.sh` 在调用 compose 前 unset 易串扰的端口类变量,避免 shell 污染
3. 评估是否把 events 的生产密钥注入同步到文档 checklist
## 相关链接
- Short-term: [../ops/short-term/2026-09-18-wave1-main-env-fix.md](../ops/short-term/2026-09-18-wave1-main-env-fix.md)
- Remediation: [../remediation/2026-09-17-system-health-remediation-plan.md](../remediation/2026-09-17-system-health-remediation-plan.md)
- Assets: [./assets/2026-09-18-wave1-main-env-fix/](./assets/2026-09-18-wave1-main-env-fix/)
@@ -0,0 +1,104 @@
# Wave 2:配置与灰度入口对齐测试报告
## 一、 测试背景 (Background)
体检确认封存 flag(`MULTI_INTENT_PLAN_TIER`、U9–U12、SHADOW/NARRATIVE)未写入 compose `environment`,`--env-file` 无法传入容器(E-3);`CURSOR_RUNNER_URL`/cursor-agent 零消费占位(E-4);main 未显式关闭 demo 播种(E-6);`INTENT_V2_DECISION_TIER` 非法值激进回退 `query`(E-7);main initdb 与 test 脚本形态差异需评估(E-9)。
## 二、 测试目标 (Test Objectives)
- 三环境 compose 渲染与容器 env 均可见目标 flag,默认 `legacy`/`false`
- `CURSOR_RUNNER*` 与 `cursor-agent` 容器消失
- main `SEED_DEMO_USERS=false`
- 非法 `INTENT_V2_DECISION_TIER` fail-closed 到 `none`
- E-9:记录评估结论,不改 initdb
- `go vet` / `go test -short` 全绿;dev/test/main health+ready PASS
## 三、 测试方案与环境 (Test Plan & Environment)
- 分支:`fix/wave2-config-flag-align`(自本地 `dev@e35f106`)
- 单测:`internal/config/compose_flag_declaration_test.go`、`TestUnknownV2DecisionTierFailsClosedToNone`
- 真实环境:`./scripts/env-service.sh {dev,test,main} rebuild`(执行前 unset shell 泄漏端口变量)
- 证据目录:`.doc/test-reports/assets/2026-09-18-wave2-config-flag-align/`
## 四、 预期结果 (Expected Results)
| 项 | 预期 |
|----|------|
| compose config | 三环境 `MULTI_INTENT_PLAN_TIER=legacy` + U9–U12/SHADOW/NARRATIVE=false;无 CURSOR_RUNNER |
| 容器 env | 同上;main 另有 `SEED_DEMO_USERS=false` |
| cursor-agent | `docker ps` 无匹配 |
| health/ready | 三环境 ok,schema_ready=true |
| 行为 | 不升 tier、不接线 REPLACE、不改 FAV |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 单测
```
ok chat-agent-system/internal/intent
ok chat-agent-system/internal/config
--- PASS: TestComposeAppDeclaresMultiIntentPlanTierAndExpansionFlags
--- PASS: TestComposeAppDeclaresSemanticSummaryAndNarrativeShadowFlags
--- PASS: TestComposeMainSeedDemoUsersExplicitFalse
--- PASS: TestComposeNoDeadCursorRunnerConfig
--- PASS: TestUnknownV2DecisionTierFailsClosedToNone
```
**判定**:PASS
### 5.2 compose config 渲染
见 `assets/.../compose-config-flags.txt`。三环境均含目标 flag;`CURSOR_RUNNER` 零匹配。
**判定**:PASS
### 5.3 容器 env 抽检
| 环境 | 关键输出 | 判定 |
|------|----------|------|
| dev | `MULTI_INTENT_PLAN_TIER=legacy` … `SEMANTIC_SUMMARY_SHADOW=false`(无 CURSOR_RUNNER) | PASS |
| test | 同上 + `SEED_DEMO_USERS=false` | PASS |
| main | 同上 + `SEED_DEMO_USERS=false` | PASS |
### 5.4 冒烟 health/ready
| 环境 | health | ready | 判定 |
|------|--------|-------|------|
| dev `:8080` | env=dev schema=52 | ok | PASS |
| test `:8081` | env=test schema=52 | ok | PASS |
| main `:8000` | env=main schema=52 | ok | PASS |
main rebuild 日志确认 `events` Healthy 后才 Starting `app`(E-2 依赖仍生效)。
### 5.5 cursor-agent 清理
```
cursor-agent 容器已清理,符合预期
```
**判定**:PASS
### 5.6 E-9 评估结论(本波次不改代码)
| 环境 | initdb 挂载 | 结论 |
|------|-------------|------|
| dev | `deploy/postgres/context_init.sql` | 与 main baseline 内容一致(仅差 goose 头注释) |
| test | `deploy/postgres/extensions_init.sql` | 仅扩展,表全靠 goose |
| main | `deploy/postgres/goose/00001_baseline.sql` | 与 dev 实质一致;无「落后」 |
**决策**:不收敛 initdb(零行为变化波次);双文件漂移风险记入后续 backlog,需空卷冷启动专项验证后再改。
**判定**:评估完成 / 不改代码 — PASS(按计划)
## 六、 自动化测试套件汇总 (Test Suite Execution)
```
go vet ./... # 通过
go test -short -count=1 ./... # 全绿(见 assets/go-test-short.txt)
```
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- Wave 2 达到合并标准:声明对齐完成,默认行为不变。
- 下一波 Wave 3:测试债与盲区(S-1/S-2/S-4/S-5)。
- E-9 结构性收敛(dev/main → extensions-only)另开任务。
@@ -0,0 +1,82 @@
# Wave 3:测试债与盲区测试报告
## 一、 测试背景 (Background)
体检确认 `TestReconcile_LegacyRepair_PG` 从未在隔离 PG 上执行(S-1);两处永久跳过(S-2);E2E 9 个 spec 仅 1 个有 npm 脚本且存在 `DOCREV_E2E_BASE_URL` 双口径(S-4);前端多处 API 对 409/结构化错误裸抛 Error(S-5)。
## 二、 测试目标 (Test Objectives)
- 隔离 PG(5436) 跑通 LegacyRepair 一次并归档
- 删除死跳过;plan_owner 重定向说明补齐
- `playwright test --list` = 29 tests / 8 files;每 spec 有脚本
- projectMembers/freeformDoc/taskRuns/chatSessions 复用 `projectSettingsError` 并有负例单测
## 三、 测试方案与环境 (Test Plan & Environment)
- 分支:`fix/wave3-test-debt-blindspots` ← 本地 `dev@423f7e7`
- 隔离 PG:`pgvector/pgvector:pg16` 映射 5436,测完销毁并 `unset TEST_DATABASE_URL`
- 前端:`npm test` / `npm run build` / `npx playwright test --list`
- 证据:`.doc/test-reports/assets/2026-09-18-wave3-test-debt-blindspots/`
## 四、 预期结果 (Expected Results)
| 项 | 预期 |
|----|------|
| S-1 | goose→52 + `PASS: TestReconcile_LegacyRepair_PG` |
| S-2 | TaskStream 3 PASS 0 SKIP;plan_owner 仍 SKIP 但注释说明导入环 |
| S-4 | 29 tests / 8 files;无 `DOCREV_E2E_BASE_URL` |
| S-5 | 相关 API 单测 PASS;`npm test` 全绿 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 S-1 隔离 PG
见 `assets/.../go-test-reconcile-pg.txt`:
```
goose: successfully migrated database to version: 52
--- PASS: TestReconcile_LegacyRepair_PG (0.37s)
```
**判定**:PASS
### 5.2 S-2
```
--- SKIP: TestTaskGenerateRealPIStopGate(redirect 说明已补)
--- PASS: TestTaskStream_TransientInjection_DeadPiAgent
--- PASS: TestTaskStream_SoftFailure_ClassifiedResumable
--- PASS: TestTaskStream_MaterialsInjection
```
**判定**:PASS
### 5.3 S-4
```
Total: 29 tests in 8 files
```
**判定**:PASS(退役 `document-revision.spec.ts`)
### 5.4 S-5
`npm test`:402 pass + vitest 32 pass;含 DOC_BUSY / CONCURRENCY_CONFLICT / members / chatSessions 负例。
**判定**:PASS
### 5.5 全量回归
`go vet ./...` + `go test -short ./...` 全绿(见 `go-test-short.txt`)。
## 六、 自动化测试套件汇总 (Test Suite Execution)
- Go short:全绿
- Web:`npm test` 全绿;`npm run build` 成功
- Playwright list:29/8
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- Wave 3 达到合并标准;gap-matrix DOC-CONTENT 工程测试债关闭。
- 下一波 Wave 4:隐患加固 R-1~R-8。
- 后端 `error_code`→统一 `httpx.Write` 仍属独立 remediation,不在本波。
@@ -0,0 +1,118 @@
# Wave 4:隐患加固(R-1~R-8)测试报告
## 一、 测试背景 (Background)
系统体检(2026-09-17)确认高风险隐患 R-1~R-8:会话跨用户挂靠、`rows.Err()` 漏检、dispatcher 无锁读、`memTurns` 全局只增不删、JSONB 静默零值化、后台 ticker 无 Shutdown、SSE 401/404 盲目重连与登出未 abort 在途流。Wave 0–3 已合入后按 Sonnet 计划默认决策实施本波。
## 二、 测试目标 (Test Objectives)
- R-1:跨用户 chat / chat/stream / chat/sessions 全部 403;受害者续用 200;Memory + PG 双实现
- R-2:18 文件补齐 `rows.Err()`;B 类 slog.Warn
- R-3:`-race` 下 events 无竞态
- R-4:实例隔离 + TTL/容量淘汰测试 PASS
- R-5:损坏/类型错误 JSONB 显式报错
- R-6:Shutdown 可停止 reminder/vault;Drain 可告警;bizdev 心跳超时
- R-7/R-8:401/404 fail-fast(calls===1);单帧容错;abortAllSessions
- 全量:`go vet` / `go build` / `go test -short` / `npm test` / `npm run build`
## 三、 测试方案与环境 (Test Plan & Environment)
- 分支:`fix/wave4-hardening-r1-r8` ← 本地 tip `32932e4`
- 隔离 PG:`pgvector/pgvector:pg16` → `127.0.0.1:5436`,测完 `unset TEST_DATABASE_URL` + `docker stop wave4-pg`
- OS:Linux;Go 模块本仓;前端 Vite/Node test runner
- 证据:`.doc/test-reports/assets/2026-09-18-wave4-hardening-r1-r8/`
## 四、 预期结果 (Expected Results)
| 项 | 预期 |
|----|------|
| R-1 Memory/PG | attacker 403 SESSION_FORBIDDEN;stream 非 SSE;victim 续用 OK |
| R-2 | `go vet` 绿;18 文件循环后可见 `rows.Err()` |
| R-3 | `go test -race -short ./internal/events/...` 绿 |
| R-4 | ChatTurn 四测 PASS;无全局 `memTurns` 重置 |
| R-5 | hydrate 错误含 `hydrateDocLocked` + `block_map` |
| R-7 | 401/404 各仅 1 次 fetch;畸形帧跳过后仍解析下一帧 |
| 全量 | short/npm/build EXIT:0 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 R-1 跨用户会话挂靠
**输入**:受害者建立 `sess-hijack-*` 后攻击者同 session_id 调 chat / stream / upsert。
**实际输出**(`ownership-pg.txt`):
```
--- PASS: TestChatSessionOwnership_CrossUserHijackDenied_PG
--- PASS: TestChatSessionOwnership_CrossUserHijackDenied_Memory
```
**判定**:PASS(附带清除 NewSession `ProjectID=1` 占位,避免 PG 误走项目鉴权)
### 5.2 R-2 rows.Err()
**实际输出**:`go-vet.txt` EXIT:0;静态补齐 18 文件。
**判定**:PASS
### 5.3 R-3 / R-4 race
**实际输出**(`go-race.txt`):
```
ok chat-agent-system/internal/events
ok chat-agent-system/internal/ctxmgr
EXIT:0
```
含 `TestAcquireChatTurn_StaleEntriesPruned` PASS。
**判定**:PASS
### 5.4 R-5 hydrate JSONB
**实际输出**(`hydrate-corrupt-pg.txt`):
```
--- PASS: TestHydrateDocLocked_CorruptJSONBFailsExplicitly_PG
```
**判定**:PASS
### 5.5 R-6
代码级:`Shutdown` close `reminderStop`/`vaultStop`;vault Drain → `vault_drain_failed`;bizdev 心跳/释放 10s timeout。随 `go test -short ./internal/server/... ./internal/bizdev/...` 回归。
**判定**:PASS
### 5.6 R-7 / R-8 前端
**实际输出**(`npm-test.txt`):tests 406 pass;vitest 32 pass;含 401/404 fail-fast 与畸形帧容错、abortAllSessions。
**判定**:PASS
### 5.7 全量回归
- `go-vet.txt` / `go-build.txt` / `go-test-short.txt`:EXIT:0
- `npm-build.txt`:EXIT:0
**判定**:PASS
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `go build ./...` | PASS |
| `go test -short -count=1 ./...` | PASS |
| `go test -race -short ./internal/events/... ./internal/ctxmgr/...` | PASS |
| `cd web && npm test` | PASS(406 + 32) |
| `cd web && npm run build` | PASS |
| 隔离 PG R-1/R-5 | PASS 后销毁容器 |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- Wave 4 R-1~R-8 达到合入本地 `dev` 标准。
- 未改 D-4/D-5(`handleGetProject` 鉴权、`handleRunTaskStream` 归属);记入后续 backlog。
- 红线自查:未触碰 FAV modes / MULTI_INTENT_PLAN_TIER / SEMANTIC_SUMMARY_REPLACE / 项目 143。
- 下一波:Wave 5 死代码决策(X-1~X-5)。
@@ -0,0 +1,85 @@
# Wave 5 死代码决策(X-1~X-5)测试报告
## 一、 测试背景 (Background)
系统体检整改 Wave 0–4 已合入本地 `dev@a12c947`。Wave 5 对死 flag、封存 REPLACE、00048 三表、system_settings 未接线键、前端死组件做逐项决策并收口。决策落点:[short-term](../ops/short-term/2026-09-18-wave5-deadcode-decisions.md)。
## 二、 测试目标 (Test Objectives)
- X-1:删除 `SEMANTIC_FALLBACK_ENABLED` 且回归测试防复活。
- X-2:`SEMANTIC_SUMMARY_REPLACE` 维持不接线,注释回链决策记录。
- X-3:00048 三表 deferred → SWBOOT-10/W5b(不改 schema)。
- X-4:6 个未接线 system_settings 键保留并注释二期。
- X-5:删除死组件/死 API 后前端构建与测试全绿。
- 门禁:`go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build`。
## 三、 测试方案与环境 (Test Plan & Environment)
- OS:Linux;Go `go1.27.1 linux/amd64`;Node `v26.8.2`;npm `11.19.1`。
- 层级:单元/包测试(`-short`)+ 前端 `tsx --test` / vitest + `tsc && vite build`。
- 未做容器 rebuild / 真 PI E2E(本波为死代码删除与注释,无运行时行为变更)。项目 143 只读,未触碰。
- 证据目录:`.doc/test-reports/assets/2026-09-18-wave5-deadcode-decisions/`。
## 四、 预期结果 (Expected Results)
| 项 | 判定 |
|----|------|
| X-1 | compose/代码无 `SEMANTIC_FALLBACK_ENABLED`(回归测试字符串除外);`TestComposeNoDeadSemanticFallbackConfig` PASS |
| X-2 | REPLACE 仍不替换 narrative;diff 仅注释 |
| X-3 | schema 不变;swboot 测试绿 |
| X-4 | 白名单键仍在;sysadmin 测试绿 |
| X-5 | `npm run build`(含 tsc)绿;死符号无引用 |
| 全量 | vet 无输出;`go test -short` 无 FAIL;npm test 0 fail |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 X-1 回归测试
- **测试输入**:`go test -short ./internal/config/...`(含于全量 `-short`)
- **实际输出**:`ok chat-agent-system/internal/config`(见 assets `go-test-short.txt`)
- **评价判定**:PASS。`SEMANTIC_FALLBACK_ENABLED` 仅剩回归测试断言字符串。
- **性能与耗时**:config 包约 0.x s(全量 short 合计约 16s)
### 5.2 X-2 / X-3 / X-4 包测试
- **测试输入**:`go test -short ./internal/ctxmgr/... ./internal/swboot/... ./internal/sysadmin/...`(含于全量)
- **实际输出**:
- `ok chat-agent-system/internal/ctxmgr`(cached/ok)
- `ok chat-agent-system/internal/swboot 0.002s`
- `ok chat-agent-system/internal/sysadmin 0.003s`
- **评价判定**:PASS
- **性能与耗时**:毫秒级
### 5.3 X-5 前端
- **测试输入**:`cd web && npm test && npm run build`
- **实际输出**:
- tsx:`tests 406 / pass 406 / fail 0`(`duration_ms 903.526321`)
- vitest:`Test Files 3 passed (3)` / `Tests 32 passed (32)` / `Duration 533ms`
- build:`tsc && vite build` → `✓ 4123 modules transformed`;`precompress: wrote 49 .br and 49 .gz`
- **评价判定**:PASS
- **性能与耗时**:npm test + build 合计约 18s
### 5.4 全量 Go
- **测试输入**:`go vet ./...`;`go test -short ./...`
- **实际输出**:vet 空文件(exit 0);short 测试 `ok` 计数 56,无 `FAIL`/`panic`
- **评价判定**:PASS
- **性能与耗时**:vet ~2s;short ~16s
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 | 证据 |
|------|------|------|
| `go vet ./...` | PASS(exit 0,无输出) | [go-vet.txt](./assets/2026-09-18-wave5-deadcode-decisions/go-vet.txt) |
| `go test -short ./...` | PASS(56 ok,无 FAIL) | [go-test-short.txt](./assets/2026-09-18-wave5-deadcode-decisions/go-test-short.txt) |
| `cd web && npm test` | PASS(406+32,fail 0) | [npm-test.txt](./assets/2026-09-18-wave5-deadcode-decisions/npm-test.txt) |
| `cd web && npm run build` | PASS | [npm-build.txt](./assets/2026-09-18-wave5-deadcode-decisions/npm-build.txt) |
时间:2026-09-18T04:01:27Z。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
达到合入本地 `dev` 标准。红线未触碰:REPLACE 不接线、不升 `MULTI_INTENT_PLAN_TIER`、不改 FAV、项目 143 只读。
后续:Wave 6 文档漂移(D-1~D-6);SWBOOT-10/W5b 与 system_settings 二期接线仍 deferred,不在本波。

Some files were not shown because too many files have changed in this diff Show More