Compare commits

...
Author SHA1 Message Date
weichen 8c9a12d996 release-candidate: 汇集 dev 功能至 test 分支,准备长期实测 [Tag: rc-v1.0.0-beta.2] 2026-09-16 05:19:59 +00:00
weichen 50f800a409 merge: feature/matrix-deep-test-promote-test
Matrix deep-test evidence and CURRENT slot claim prior to test promote.
2026-09-16 05:18:52 +00:00
weichenandCursor 0743fb90ec docs(ops): advance integration slot to merging for test promote
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:18:52 +00:00
weichenandCursor 895d5f002a test(ops): capture matrix deep-test Wave 1–3 evidence artifacts
Automated short/module/governance-PG outputs plus live :8080 smoke and
PI typed-result sample for promote gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:18:52 +00:00
weichenandCursor 4f997a9438 docs(ops): register matrix deep-test claim on CURRENT
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:14:00 +00:00
weichenandCursor ef84d1d8f7 docs(ops): claim infra slot for matrix deep test and test promote
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:13:38 +00:00
weichen 4298701b2a merge: docs/archive-production-ready-gates 2026-09-16 04:16:03 +00:00
weichenandCursor 28d1512e6e docs(ops): archive completed production-ready gates short-term task
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:16:03 +00:00
weichen 4d048cc4a3 merge: docs/production-ready-flip
Flip SSOT production_ready=yes after release gates and main schema align.
2026-09-16 04:15:55 +00:00
weichenandCursor 1027026e7a docs(ops): flip production_ready=yes after B1–B4 gates and schema 47
Align FEATURE-MATRIX, gap-matrix, and CURRENT; main rebuilt to schema 47
with dev/test. Release blockers closed; backlog items remain partial/planned.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:15:55 +00:00
weichen 8dae227f8c merge: feature/pi-three-workflow-e2e
Release gates B2–B4 evidence, PI E2E harness fixes, and settings conflict recovery.
2026-09-16 04:14:07 +00:00
weichenandCursor 05a84e6677 fix(web): include nested error field in VERSION_CONFLICT unwrap typing
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:13:35 +00:00
weichenandCursor 23a5f6f589 docs(ops): claim integration slot for production-ready gate merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:12:09 +00:00
weichenandCursor 1f35593dcd docs(test): archive B2–B4 release-gate evidence and check gap boxes
PI three-workflow E2E, chat refresh+restart, and frontend conflict/
termination-preview reports; mark corresponding gap-matrix gates done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 736857a292 fix(web): unwrap nested VERSION_CONFLICT business codes for settings recovery
HTTP envelope wraps PLAN_FROZEN/ERR_CONCURRENT_SWITCH; reload settings on
conflict so operators refresh instead of blind retry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 64ac437a90 fix(test): upsert project members before SavePlan in chat-refresh live
Duty assignees must be active members or activation path returns 400.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 3b80582123 fix(pi-agent): stabilize real PI three-workflow E2E harness
Use shared DATA_DIR permissions (umask/chmod) and drop obsolete sync
notify asserts so governance PG PI chains can complete on MiniMax runner.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichen 3b56816f4e merge: fix/ci-governance-pg-members 2026-09-16 03:20:32 +00:00
weichenandCursor 56c85bba11 fix(ci): green governance PG on isolated TEST_DATABASE_URL
Add duty holders as project members, drop sync notification assert
after outbox cutover, and add an explicit CI governance PG step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:20:32 +00:00
weichen eaffe3eb31 merge: docs/demo-seed-merge-closeout 2026-09-16 03:17:37 +00:00
weichenandCursor c8052c8882 docs(ops): close DEMO-DB-SEED after schema 47 migrate and smoke
Record npm/go gates, empty project 6357 docs=0, and release the
integration slot; gap-matrix DEMO-DB-SEED → PASS.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:17:37 +00:00
weichen 511012cede merge: fix/demo-chat-sessions-retire-00047 2026-09-16 03:14:59 +00:00
weichenandCursor c741d26eeb fix(db): add goose 00047 to retire demo project chat sessions
Dev already applied 00046 (projects only) before session retirement
was folded into that file; 00047 closes the gap idempotently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:14:59 +00:00
weichen 0917f39f80 merge: fix/demo-data-pollution-web
Gate demo seeds, retire goose demo projects/sessions, reject stub in
main/prod, and respect SEED_DEMO_USERS=false.
2026-09-16 03:13:51 +00:00
weichenandCursor 765a418df1 docs(ops): claim integration slot for demo-data-pollution merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:13:51 +00:00
weichenandCursor 66c56324ad docs(ops): backlink 2026-09-15 audit and record review P0/P1 evidence
Cherry-picked SEED_DEMO_USERS separately; document npm test gate,
session retire in 00046, and P2 follow-ups.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:13:25 +00:00
weichen 53bb71adae fix(auth): respect SEED_DEMO_USERS=false to prevent re-seeding demo users 2026-09-16 03:12:31 +00:00
weichenandCursor fbda195b7f fix(db): retire demo chat sessions with projects in 00046
Extend unapplied migration to mark 6001–6010 sessions demo_retired
and filter them (and retired projects) out of ListChatSessions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:12:25 +00:00
weichenandCursor a44df9280c fix(web): rewrite demoSeedIds tests for node:test npm gate
Vitest-style suite was caught by tsx --test and broke npm test.
Align with storage.test.ts and narrow vitest include to chat suites.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:11:36 +00:00
weichenandCursor 1e19f5c52f docs(test): archive demo seed pollution remediation evidence
Record systemic audit, wave plan status, gap-matrix blockers, and unit/
bundle scan results for the demo-data pollution fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor 8a8197a4f2 fix(taskrun): reject stub backend in main/prod
Require ResolveBackendInEnv to deny stub (and empty stub fallback) when
env is main/prod so production cannot request simulated agent output.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor bdc6415944 fix(db): retire goose-seeded demo projects from lists
Mark projects 6001–6010 as demo_retired and exclude them from default
project list queries so demo seeds no longer pollute real workspaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor 855363fd60 fix(web): gate demo seeds and reclaim mock deliverables
Stop shipping hard-coded demo docs/projects into production builds,
drop local mock items on authoritative empty server lists, and purge
stale demo seed residue from localStorage on boot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichen 2005a4ca0c merge: chore/release-multi-intent-u8-slot 2026-09-16 02:26:03 +00:00
weichenandCursor 8b228e2101 chore(ops): release the U8 integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:26:03 +00:00
weichen 50cf271b53 merge: feature/multi-intent-u8-task-generate 2026-09-16 02:24:39 +00:00
weichenandCursor bf55278740 docs(test): record U8 task generate adapter report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:24:23 +00:00
weichenandCursor 2e99ee3661 feat(intentflow): route confirmed generate steps through a task adapter
Persist ComboNeedsConfirm plans at confirm tier without executing writes, then run task.run via OwnerMux and a stable idempotency key.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:24:23 +00:00
weichen aec374c5dc merge: chore/release-multi-intent-u7-slot 2026-09-16 01:42:42 +00:00
weichenandCursor ad3d10b72d chore(ops): release the U7 integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:42:42 +00:00
weichen 276ceb42b3 merge: feature/multi-intent-u7-auto-read 2026-09-16 01:40:07 +00:00
weichenandCursor fb19b63baf docs(test): record U7 auto_read query execution report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:40:07 +00:00
weichenandCursor 702cf6f949 feat(intentflow): execute auto_read query plans from HandleTurn
Default legacy stays a no-op; QueryGuard refuses generate keys until U8.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:40:07 +00:00
weichen 5c4caa375e merge: chore/release-multi-intent-u6-slot 2026-09-16 01:11:28 +00:00
weichenandCursor c7677b09f6 chore(ops): release the U6 integration slot
Restore the U5 SSOT rows dropped during the U6 docs commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:11:28 +00:00
weichen b94873ab18 merge: feature/multi-intent-u6-web-cards 2026-09-16 01:09:05 +00:00
weichenandCursor ba713c266b docs(test): record U6 plan card web report
Keep Playwright dual-tab behind RUN_UI_ACCEPTANCE.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:09:05 +00:00
weichenandCursor 29bb63f766 feat(web): render PLAN_CONFIRM from PlanView without local AST writes
Plan actions post to the decision API and reconcile on 409 instead of mutating documents.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:09:05 +00:00
weichen 4044b68c9e merge: chore/release-multi-intent-u5-slot 2026-09-16 01:02:19 +00:00
weichenandCursor 0dd7a412c2 chore(ops): release the U5 integration slot
Drop accidental pycache from the docs commit and ignore Python bytecode.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:02:19 +00:00
weichen 741089eca3 merge: feature/multi-intent-u5-decision-api 2026-09-16 01:01:39 +00:00
weichenandCursor e16fb7eff2 docs(test): record U5 decision API and authorization report
Close the U5 checklist with HTTP scope negatives and same-nonce receipts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichenandCursor 3d444fa5e4 feat(api): mount authenticated intent plan decision routes
Principal comes from the session and query scope; body identifiers are ignored and admins cannot skip membership.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichenandCursor 08aa56b16c feat(intentflow): re-authorize steps before confirm and execute
Confirmation stays a command receipt; FakeActionOwner now fail-closes on revoke and resource version drift.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichen f35d265721 merge: chore/release-multi-intent-u4-slot 2026-09-16 00:52:59 +00:00
weichenandCursor 131c86a919 chore(ops): release the U4 integration slot
U4 smoke (go vet + go test -short) passed; no shared-env rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:52:59 +00:00
weichen 839368198a merge: feature/multi-intent-u4-outbox-projection 2026-09-16 00:50:32 +00:00
weichenandCursor 46ee9fe647 chore(ops): occupy the U4 integration slot
Remove accidental promote-dev and pycache files from the U4 docs commit and hold the merge slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:50:26 +00:00
weichenandCursor 2755d916f4 docs(test): record U4 outbox projection report
Close the U4 checklist with golden payload and only-forward projection evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor c36d891b05 feat(intentflow): emit plan facts onto Track E outbox
Append awaiting/step/completed envelopes in the command UoW and project them without changing dispatcher leases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor cf063f5727 feat(db): add intent plan projection shadow tables
Store idempotent event outcomes and an only-forward shadow without replacing plan SSOT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor 1afd39c9e8 docs(ops): claim U4 intent plan outbox projection
Register the events mutex before appending intent.plan facts onto Track E.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:40:57 +00:00
weichen 0f656638eb merge: chore/release-multi-intent-u3-slot 2026-09-15 23:47:19 +00:00
weichenandCursor 223b2841d7 chore(ops): release the U3 integration slot
Smoke already passed on the feature branch; shared env stays on schema 43 until a planned rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:47:19 +00:00
weichen 26f1632a21 merge: feature/multi-intent-u3-intentflow-pg 2026-09-15 23:46:55 +00:00
weichenandCursor 4cfe6ff59d chore(ops): occupy the U3 integration slot
Hold the shared merge slot for the no-ff merge of the intentflow PG owner.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:46:55 +00:00
weichenandCursor b6956003d5 docs(test): record U3 intentflow PG CAS lease report
Close the U3 checklist with CAS/lease/fencing evidence while leaving chat routing on legacy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:46:34 +00:00
weichenandCursor 1385002350 feat(app): assemble intentflow plan owner
Wire the composition root without letting chat or coordinator call CreatePlan yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:46 +00:00
weichenandCursor da0b3d812b feat(intentflow): persist plans with CAS lease and fencing
Own plan/step/decision writes behind UoW so two workers cannot both execute the same step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:46 +00:00
weichenandCursor 7dfd6d6f33 feat(db): add intent plan tables in goose 00044
Persist plans, steps, and append-only decisions with typed CAS, lease, and nonce columns.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:37 +00:00
weichenandCursor a75aa45129 docs(ops): claim U3 intentflow PG CAS lease
Register the intent-plan mutex and freeze U3 scope before schema or repository work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:33:15 +00:00
weichen 53c0722925 merge: chore/release-multi-intent-u2-slot 2026-09-15 23:18:37 +00:00
weichenandCursor 86f25b26c4 chore(ops): release the U2 integration slot
Smoke already passed on the feature branch; U2 has no schema or container change.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:18:37 +00:00
weichen 53d4077f06 merge: feature/multi-intent-u2-segmenter 2026-09-15 23:18:10 +00:00
weichenandCursor 91edeccb26 chore(ops): occupy the U2 integration slot
Hold the shared merge slot for the no-ff merge of the rule-segmenter shadow proposal.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:18:10 +00:00
weichenandCursor c2e79c8a1d docs(test): record U2 rule segmenter shadow proposal report
Close the U2 checklist with golden/hard-negative evidence while keeping production routing unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:17:45 +00:00
weichenandCursor 932ba87daf feat(intent): add rule segmenter and shadow PlanProposal
Generate 2–4 step L1 proposals with stable digests while leaving TopIntent and the legacy IntentPlan router unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:14:29 +00:00
weichenandCursor 9005766b62 test(intent): lock legacy multi-intent plan routing
Keep write combos and internal-chain summaries on the current TopIntent path so U2 shadow proposals cannot silently change production.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:07:46 +00:00
weichenandCursor 475134802b docs(ops): claim U2 multi-intent rule segmenter
Register the independent U2 short-term on the intent mutex so shadow proposals can land without touching production routing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:06:29 +00:00
weichen 8ac3d3fbc6 merge: chore/release-multi-intent-u1-slot 2026-09-15 16:28:07 +00:00
weichenandCursor 3171e4f0e5 chore(ops): release the U1 integration slot
Smoke already passed on the feature branch; U1 has no schema or container rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:28:07 +00:00
weichen 29d9c65603 merge: feature/multi-intent-u1-contracts 2026-09-15 16:27:29 +00:00
weichenandCursor 42c8ae2ccd chore(ops): occupy the integration slot for U1 merge
Serialize the local --no-ff merge of multi-intent U1 contracts onto dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:27:29 +00:00
weichenandCursor 3d326ad81e docs(status): record U1 multi-intent contract freeze
Archive the arch/parity/short evidence and mark the U1 claim done so U2 can take the intent mutex next.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:27:03 +00:00
weichenandCursor 9364da4974 feat(intentflow): freeze plan lifecycle contracts and batch policy
Add the app/intentflow skeleton so HITL state, error codes, REST shapes, and BatchActionPolicy live outside intent and default to the legacy tier.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:22:52 +00:00
weichenandCursor aefb1e45a6 feat(events): register intent.plan contracts and table owners
Freeze the three fact events, intentflow allowlist, and plan table ownership so later units cannot invent producers or write paths outside app/intentflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:20:19 +00:00
weichenandCursor bdccb4dbfe docs(ops): claim U1 multi-intent HITL contract freeze
Register the independent U1 short-term, checklist, and CURRENT mutex so architecture-docs and events stay serial while contracts land.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:19:12 +00:00
weichen dd30e061d8 merge: sync test promotion notes from local dev 2026-09-15 16:04:59 +00:00
weichen 987423794f merge: feature/test-env-smoke-notes 2026-09-15 16:04:59 +00:00
weichenandCursor 8919ca9842 docs(ops): record the test promotion smoke and release the slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:04:59 +00:00
weichen 2e826e7f58 merge: promote local dev to test for Phase 2 actual testing 2026-09-15 16:02:46 +00:00
weichen 5a79752ebe merge: feature/promote-dev-to-test-2026-09-15 2026-09-15 16:02:38 +00:00
weichenandCursor 68755862f1 docs(ops): occupy the integration slot for the test promotion
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:02:38 +00:00
weichen 067cf8be18 merge: feature/phase2-session-close 2026-09-15 15:58:47 +00:00
weichenandCursor 035d8594a6 docs: sync multi-intent review index with the parked plan
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:58:47 +00:00
weichenandCursor fa5955be07 docs(design): tighten multi-intent confirm UI and accessibility gates
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:58:26 +00:00
weichenandCursor 69d1203593 docs(ops): close Phase 2 session and park multi-intent HITL plan
Archive the shared-live short-term, refresh CURRENT foci, and check in the reviewed multi-intent design so it no longer sits uncommitted on dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:57:40 +00:00
weichen c1a2bcc26b merge: feature/current-env-snapshot 2026-09-15 15:27:50 +00:00
weichenandCursor 05550f3558 docs(ops): record typed-result and live consumer modes in CURRENT
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:27:50 +00:00
weichen 3d39ee0589 merge: feature/pi-typed-result 2026-09-15 15:27:16 +00:00
weichenandCursor ecba6f3b14 chore: release the pi-typed-result integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:27:16 +00:00
weichenandCursor a3fa7c137b docs(test): record PI typed-result-v1 dual-track evidence
Archive Track P tasks and point FEATURE-MATRIX at the live MiniMax runner report.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:25:34 +00:00
weichenandCursor 0a61cfbe90 feat(agent): add typed-result-v1 and fail-closed remote parser
Remote /v1/run now emits additive result_v1; Go validates run_id, digest, and paths before materializing, and only accepts missing typed payloads with an explicit legacy handshake.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:25:18 +00:00
weichen 4dbe6a431c merge: feature/http-error-envelope 2026-09-15 14:41:09 +00:00
weichenandCursor f6813cc272 feat(api): add additive HTTP/SSE error envelopes
Public errors now emit code, safe message, and request_id while keeping the legacy error field. Raw SQL, paths, tokens, and XSS payloads are stripped; the frontend branches on code instead of substring matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:40:56 +00:00
weichen 39dc68d15c merge: feature/event-shared-live-cutover 2026-09-15 14:24:17 +00:00
weichenandCursor 7a9d0d850d chore: ignore pycache and release the live-cutover integration slot
Shared live rebuild passed health/ready; keep Python bytecode out of test-report assets.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:24:17 +00:00
weichenandCursor ad9027fe8f docs(test): record shared event live cutover and close the reliability pilot
Notify, workflow_advance, and projection completed shadow/live/rollback on agent-dev; authorized 6275 digest matches; project 143 stays non-leaking.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:23:07 +00:00
weichenandCursor 9b1a94c5bc feat(app): drop production outbox and approval hook registration
Durable notify/advance/projection are live on shared dev, so composition roots must not assign OnOutbox or AddOnApprovedHook. Bind helpers remain for tests and a rollback window.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:23:07 +00:00
weichenandCursor 4a662ec2d3 feat(events): gate shared-dev consumer mode changes
Add ValidateOpsCutover, eventmode CLI, and a host script that pin agent_system_dev and refuse FAV plus test/main before any cluster mode write.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:11:44 +00:00
weichen a20760953a merge: feature/phase2-closeout-inventories 2026-09-15 13:26:50 +00:00
weichenandCursor 8400427c24 docs: close Phase 2 isolation tracks and file H0/P0 inventories
Archive completed Track E/S short-terms, record HTTP/PI compatibility matrices, and defer shared live plus protocol implementation to long-term tasks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:26:20 +00:00
weichenandCursor 1c04f17c8c test(events): reject replay apply without approval ref
ReplayPlan two-person apply already required digest match; this pins the missing ApprovalRef negative so dry-run tickets cannot skip the ticket field.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:26:20 +00:00
weichen 3a6d4f45dd merge: fix/chatflow-orchestration-boundary 2026-09-15 13:15:57 +00:00
weichenandCursor 9811ae3841 docs(test): record D7b chatflow orchestration boundary
S4b report and archive; chat production allowlist no longer includes bizdev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:15:48 +00:00
weichenandCursor 425c8ba776 feat(chat): drop production bizdev import from action executor
Pending-action task runs now use stageflow request aliases and Server ports, so chat no longer reaches through the orchestration root.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:15:48 +00:00
weichen 20fc82c485 merge: fix/bizdev-locator-removal 2026-09-15 13:11:10 +00:00
weichenandCursor 6a9e3fb51a docs(test): record D4 bizdev locator removal
S1 report, archive the short-term task, and mark the getter contract closed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:10:47 +00:00
weichenandCursor 2a75abb39e refactor(bizdev): delete eight locator getters
Composition roots already hold Snapshot ports; the interface and archtest now forbid putting Pool/DocGov/DocRevision/ContextManager/CAS/ProjectWorkflow/FreeformDoc/KB back on Service.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:08:25 +00:00
weichenandCursor 3f42149457 feat(bizdev): snapshot collaborators onto Runtime and Server ports
Composition roots copy Parts once so HTTP/CLI handlers stop calling locator getters on every request.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 13:00:33 +00:00
weichen 92a9c6783d merge: fix/stageflow-type-ownership 2026-09-15 11:13:17 +00:00
weichenandCursor acb443e949 docs(test): record D5 stageflow type ownership and chatflow first batch
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 11:13:17 +00:00
weichenandCursor 110c2e810c feat(stageflow): own task/stage types so coordinator drops bizdev
Coordinator now takes a StageTaskRunner and injected context/KB ports.
Chatflow assembler reads maturity tokens instead of the orchestration root.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 11:13:17 +00:00
weichen 6f541feac0 merge: fix/intent-bizdev-boundary 2026-09-15 10:29:38 +00:00
weichenandCursor 23d0cfb10f docs(test): record D7a intent-bizdev boundary
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:29:38 +00:00
weichenandCursor 525047b841 feat(intent): depend on maturity vocabulary instead of bizdev
Intent only needed the three official stage tokens. Moving them to a
leaf package lets the recognizer compile without the orchestration root.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:29:38 +00:00
weichen 0a2ea2477d merge: fix/doccontent-canonical-boundary 2026-09-15 10:24:24 +00:00
weichenandCursor 7728339d08 docs(test): record D6 doccontent canonical boundary
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:24:24 +00:00
weichenandCursor 9ddc673eb8 feat(doccontent): extract shared markdown canonicalization and SHA
docgov saves content hashes through the new leaf module so it no longer
imports docrevision. Existing docrevision exports stay as thin wrappers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:24:24 +00:00
weichen 2771a1ed04 merge: fix/event-e2-hook-guard 2026-09-15 10:17:47 +00:00
weichenandCursor 71502c7ce0 docs(test): record E2 hook live-guard and Track E retrospective
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:17:26 +00:00
weichenandCursor a1316e39cb test(events): prove WriterLive off/shadow/live hook matrix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:17:26 +00:00
weichenandCursor 97028c33b5 feat(events): skip in-process writers when a consumer is live
Keep OnOutbox and approval hooks registered while dispatcher mode is
off, but no-op them as soon as the matching durable consumer owns the
visible write so a later switch cannot dual-write.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:17:09 +00:00
weichen 51bf791ef0 merge: fix/event-projection-cutover 2026-09-15 10:00:38 +00:00
weichenandCursor dab3e1a355 docs(test): record E1C projection no-replace and worker restart evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:00:11 +00:00
weichenandCursor d645eaa1f7 docs(test): record E1C projection no-replace and worker restart evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:59:55 +00:00
weichenandCursor aa2f31dc0f test(docproject): prove projection shadow, uniqueness, and no-replace
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:59:55 +00:00
weichenandCursor 92f31ffa6a feat(events): apply version-committed projections only forward
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:59:55 +00:00
weichenandCursor 21d7692c94 feat(db): record unique projection outcomes per envelope version
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:59:54 +00:00
weichen 1b1d0a1cba merge: fix/event-workflow-advance 2026-09-15 09:43:09 +00:00
weichenandCursor 7d1b7e736b docs(test): record E1B workflow-advance shadow/live/rollback evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:43:09 +00:00
weichenandCursor 0ebaaaed87 test(docadvance): prove workflow advance shadow, uniqueness, and rollback
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:43:09 +00:00
weichenandCursor 965e288d36 feat(events): apply approved events onto workflow advance in one fenced transaction
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:43:09 +00:00
weichenandCursor 28bb0b8356 feat(db): correlate stage-ready requests to envelope event_id
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:43:09 +00:00
weichen ebf16aa094 merge: fix/event-notify-cutover 2026-09-15 09:26:45 +00:00
weichenandCursor ff713ff790 docs(test): record E1A notify shadow/live/rollback evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:26:36 +00:00
weichenandCursor a5e46eeb5f test(docnotify): prove notify shadow, live uniqueness, and rollback on isolated PG
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:26:36 +00:00
weichenandCursor 16a31f8aa5 feat(events): run notify side effects and ack on one fenced transaction
Shadow dry-runs the same handler then rolls back, writing only the intended digest.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:26:36 +00:00
weichenandCursor 6702b16249 feat(db): correlate notifications to envelope event_id for unique visible outcomes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:26:36 +00:00
weichen 06b824ad7c merge: feature/events-dispatcher-pg 2026-09-15 09:08:25 +00:00
weichenandCursor d926f64c2e docs(test): record E0B dispatcher PG, race, and default-off evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:08:15 +00:00
weichenandCursor 6bee7630bd feat(service): run the event dispatcher as an independent cmd/events process
HTTP Runtime does not start the worker. Each compose environment gets its own events service, health port, and bounded pool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:08:15 +00:00
weichenandCursor d5968ad4ba feat(events): replace SELECT-only claim with fenced atomic leases
Workers claim with SKIP LOCKED, heartbeat by token, and ack/fail only when the fencing token still matches. Shadow scans without acking live deliveries.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:08:15 +00:00
weichenandCursor 5fd5588a3f feat(db): add dispatcher attempts, consumer modes, and checkpoints
E0B needs an additive lease audit trail and a cluster-level off/shadow/live table before any worker can claim. FAV remains constrained to off.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 09:08:15 +00:00
weichen 5f3b117c00 merge: fix/event-production-scope-contract 2026-09-15 08:53:10 +00:00
weichenandCursor 0f2f8d30e5 docs(test): record E0A producer-contract gate and checkpoint ADR
Archive isolated-PG evidence, 7-day read-only inventory, and the decision to bootstrap consumers from the first safe event instead of gap-waiting.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:52:59 +00:00
weichenandCursor 0f2057765a test(docflow): prove three production chains share one Postgres transaction
Isolated-library coverage checks approved/candidate/impact envelopes, empty-env rollback, and zero FAV staging rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:52:48 +00:00
weichenandCursor 504058debf feat(app): inject unique docflow Commands and isolate FAV from production events
HTTP adapters now reuse the composition-root instance. Candidate-ready, downstream impact, and approved envelopes share the domain unit of work, and missing env/project fail closed without defaulting to dev/0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:52:40 +00:00
weichenandCursor bcb122ac53 feat(events): fail-closed scope, static registry, inventory, and replay digest
Reject empty environment/project, disable FAV consumers at register time, and keep historical classification/repair/replay as audited application use cases with no raw SQL entrypoint.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:52:30 +00:00
weichenandCursor 97305d699e feat(db): add event inventory, repair audit, replay plans, and service principals
E0A needs additive tables for classification and per-consumer identities before any dispatcher can claim work. FAV principals are rejected at the schema check.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:52:19 +00:00
weichen 3d2a1defd8 merge: feature/module-decoupling-phase2-docs 2026-09-15 08:12:47 +00:00
weichenandCursor 15af018734 docs(ops): close architecture-docs mutex after Phase 2 plans land
The next claim is Track E E0A; dispatcher stays off until that gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:12:21 +00:00
weichenandCursor 7647215513 docs(ops): land Phase 2 Track E/S/P plans onto a legal feature branch
Move the reviewed durable-event, HTTP envelope, and PI typed-result
designs off the docs/ prefix so Track E can start from latest dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 08:11:29 +00:00
weichen 5cef85670a docs(remediation): add module decoupling phase-2 remediation plan and index gap-matrix rows 2026-09-15 07:03:39 +00:00
weichen a3392e3e06 docs(research): add module decoupling and IPC/RPC interaction assessment 2026-09-15 06:57:08 +00:00
weichen 9edd6c8190 merge: chore/leftover-branch-cleanup 2026-09-15 06:44:46 +00:00
weichenandCursor edb7411474 docs(ops): record leftover branch cleanup and short smoke evidence
Local merged side branches and their worktrees are gone; FAV/herdr/diagnosis/old-linear stay unmerged on purpose.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 06:44:39 +00:00
weichen 347c5f54a6 merge: docs/conversation-intent-dual-tab 2026-09-15 06:22:58 +00:00
weichenandCursor 8a8f64a931 docs(test): close intent dual-tab busy gate and release the mutex
Record project 6275 PI 409 DOC_BUSY plus Docker screenshots, mark CHAT-INTENT-STATE PASS, and archive the short-term so CURRENT has no in_progress rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 06:22:58 +00:00
weichen f5d32cddd1 merge: docs/u11-u12-slot-close 2026-09-15 05:55:34 +00:00
weichenandCursor 111ab6786e docs(test): close U11–U12 after dev rebuild and archive the app mutex
Record schema 38 health/ready plus the new agent-dev-app digest, then mark the composition-root slice done so intent dual-tab can take the idle slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:55:25 +00:00
weichen bf59cceef2 merge: feature/app-composition-u11-u12 2026-09-15 05:51:32 +00:00
weichenandCursor 934c0596ea docs(ops): occupy the integration slot for U11–U12 merge
Serial slot is required before --no-ff into local dev and agent-dev rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:51:32 +00:00
weichenandCursor 717162e701 docs(test): record U11–U12 composition root and transport gate evidence
Contract tests, target-package race, and arch-check --mode block passed; merge to dev still needs the integration slot rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:40:15 +00:00
weichenandCursor 84c0841acb feat(app): add composition root, stageflow, ContextUpdate, and SSE transport
Move construction and document OnOutbox out of server, give HTTP/CLI a shared task use case, and block already-cleared import/event arch rules.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:40:15 +00:00
weichenandCursor 652cea1605 docs(ops): claim M5/M6 U11–U12 composition and transport gate
User authorized continuing past U10 stop-ship; register app mutex on feature/app-composition-u11-u12.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:40:00 +00:00
weichen ef9a162314 merge: feature/chatlog-contextasm-u10
M4 U10 ChatLog/ContextAssembler 原地端口化。停止扩面,禁止 U11–U12。
2026-09-15 05:05:27 +00:00
weichenandCursor 6601583cbe docs(test): record U10 occupy-slot rebuild into agent-dev
health/ready schema 38;镜像已含 ChatLog 端口。停走结论仍是停止扩面。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:05:27 +00:00
weichenandCursor 3c9e6d214d docs(ops): occupy the integration slot for M4 U10 merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:04:15 +00:00
weichenandCursor 6e744d3717 docs(test): record U10 ChatLog ports and live chat refresh evidence
Archive the finished chat mutex tasks, attach PI idle-chat refresh same-set evidence for project 6252, and stop expansion after in-place ports without a package split.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 04:11:40 +00:00
weichenandCursor 65bdda8aae feat(api): route chat history reads through ChatLog
Ignore request user_id as identity, authorize from the session Principal, and hydrate restore/memory from the same visible set so HTTP, SSE, and prompt assembly cannot amplify hidden messages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 04:11:27 +00:00
weichenandCursor 18d40fa8a9 feat(chatflow): add ChatLog and ContextAssembler ports
Keep ctxmgr as table owner and filter the authorized visible set in-process so window, stats, restore, digest, and prompt assembly share one Principal-scoped collection without a package move.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 04:11:16 +00:00
weichen 3944856b0a merge: feature/dataset-lifecycle-u9
M3 U9 存量回填、migration corpus 与数据生命周期。
2026-09-15 03:01:49 +00:00
weichenandCursor af51e74076 docs(test): M3 U9 dataset lifecycle 验收报告
隔离库 SKIP LOCKED、八轨、arch-check、web 与 rebuild 证据齐全;真实 PI 未测。最后一句:继续 U10。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 03:01:49 +00:00
weichenandCursor 42f356ccd7 docs(ops): occupy the integration slot for M3 U9 rebuild
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:41:06 +00:00
weichenandCursor be0c1e843f feat(dataset): registry, pause/resume backfill, destroy gates, eight tracks
批准 dataset 分类入库;SKIP LOCKED 分批;销毁默认 fail closed。restore 演练拒绝共享 env DSN。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:40:12 +00:00
weichenandCursor b5337d5c77 feat(artifactvault): checkpoint backfill without scanning workspace
只枚举 snapshot、agent_commit、approved 与 completed chat turn;hazard 进 quarantine,禁止工作区路径。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:40:12 +00:00
weichenandCursor 5ac14d649b feat(db): add goose 00038 dataset lifecycle tables
Registry、checkpoint queue 与 destroy 请求表属主 dataset;必须可 Down,不改历史 Goose。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:31:34 +00:00
weichenandCursor e81e7a1bcc docs(ops): claim M3 U9 dataset lifecycle mutex
U8 已签继续 U9。本轮 mutex=dataset,禁止 U10–U12 与共享库销毁。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:30:45 +00:00
weichen 367473730b merge: feature/taskrun-runmanifest
M3 U8 TaskRun 终态与 RunManifest。
2026-09-15 02:17:37 +00:00
weichenandCursor f4dfada9ae docs(test): M3 U8 TaskRun RunManifest 验收报告
隔离库双 pool、目标包 race、arch-check、web 与 rebuild 证据齐全;真实 PI 未测。最后一句:继续 U9。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:17:37 +00:00
weichenandCursor ac302fb78f docs(ops): occupy the integration slot for M3 U8 merge
Serialize merge and container rebuild so other agents wait while RunManifest lands on dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:07:42 +00:00
weichenandCursor 3997a04bdb test(taskrun): cover duplicate finalize, cancel race, and SSE
Use an isolated dual-pool database so idempotent finalize, cancel CAS, commit-fail SSE, and receipt-gated cleanup are proven without a process mutex.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:06:21 +00:00
weichenandCursor 2ddaf769ca feat(workspace): gate cleanup on verified receipts
Hash deliverables through Capability.ReadArtifact, resolve backends on the server, and refuse workspace removal until frozen members match FAV receipts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:06:10 +00:00
weichenandCursor 7be873073c feat(taskrun): finalize RunManifest in one unit of work
CAS the unique terminal status with the assistant turn, frozen manifest, envelope and FAV staging, and join ctxmgr writes through the same UoW instead of a process mutex.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:05:58 +00:00
weichenandCursor eb75f855a5 feat(db): add goose 00037 task_run_manifests
Persist typed RunManifest bytes and SHA per run, and allow a finalizing status so U8 can freeze a unique terminal without sharing env databases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:05:33 +00:00
weichenandCursor 2234af476a docs(ops): claim M3 U8 TaskRun RunManifest mutex
Register feature/taskrun-runmanifest on the taskrun mutex so U8 can start without occupying chat/intent or writing U9–U12.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 01:04:32 +00:00
weichen b8f33b5c55 merge: refactor/document-reliability-pilot
M2 test report and integration-slot release.
2026-09-14 16:07:37 +00:00
weichenandCursor da21911e30 docs(ops): restore the original M1 stop-the-line report link
CURRENT SSOT must keep the unmodified 停止扩面 report alongside the live and M2 reports.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 16:07:37 +00:00
weichenandCursor b1ce9b5c41 docs(test): record document reliability M2 go-no-go
U5–U7 passed isolation-db, race, goose Down, and schema-36 rebuild. The report last sentence is 继续 M3; the integration slot is idle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 16:07:05 +00:00
weichen 0872d8fbb3 merge: refactor/document-reliability-pilot
M2 WorkspaceRef, durable events, and audited FAV (goose 00034–00036).
2026-09-14 16:00:57 +00:00
weichenandCursor 425338be9e docs(ops): occupy the integration slot for M2 merge
U5–U7 need a main-repo rebuild so schema 00034–00036 is not validated from a worktree docker.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 16:00:42 +00:00
weichenandCursor c7e3e99303 feat(artifactvault): extract audited FAV with union-deny reads
Goose 00036 is a renumbered copy of the vault tables. Degraded read stays off by default and only runs after authorization; tombstones and unpublished artifacts fail closed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:59:36 +00:00
weichenandCursor f27059b453 feat(events): add durable envelope delivery and drop commit OnOutbox
Agent commits append a validated envelope inside the command unit of work. SKIP LOCKED is only used to claim, and stale fencing plus integrity failures go to quarantine or dead-letter.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:59:24 +00:00
weichenandCursor 18ddd0f862 feat(workspace): add WorkspaceRef fencing and hide physical paths
Cross-module callers get an opaque ref plus rotating lease tokens so stale writers fail closed, and file I/O is refused inside a unit of work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:59:14 +00:00
weichenandCursor b0d9153e52 docs(test): record document reliability M1 live sign-off
Rebuild, real PI, browser reload, and two-pool sessions all passed, so
the live report's last sentence is 继续 M2 and the integration slot is idle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:46:53 +00:00
weichenandCursor 88b37b60da test(e2e): refresh admin directory before new-project member pick
Create-project candidates come from the in-session user directory, so a
fresh admin page never saw B/C unless the console refresh ran first.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:38:50 +00:00
weichenandCursor 3e4abc51cd test(e2e): cover 143 reload, fail-closed GET, and new-project compile
Live M1 sign-off needs browser proof that missing projection is not 404,
outsiders share DOCUMENT_NOT_FOUND, and a real PI compile survives reload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:34:37 +00:00
weichenandCursor f34bec40f5 test(docgov): replay same-digest across two pools and four sessions
Cross-pool idempotency is same key plus same digest; a stale in-memory
head from the seeder hid the one-winner four-session lock.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:34:30 +00:00
weichen cb8eacac61 merge: refactor/document-reliability-pilot
Occupy the integration slot to rebuild dev for M1 live sign-off of document reliability U1–U4.
2026-09-14 14:24:56 +00:00
weichenandCursor 7f8ad76d12 test(docgov): add two-pool races and ledger-first live spec
Occupy the integration slot for M1 live sign-off, cover two pgx pools plus four sessions, and add a Playwright spec that treats projection consistency as 200 rather than 404.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:24:46 +00:00
weichenandCursor 3772193747 docs(test): attach M1 suite transcripts
Keep the short and isolated PostgreSQL/race outputs next to the stop-the-line report so the unsigned PI/browser/rebuild columns stay auditable.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:11:52 +00:00
weichenandCursor 9d6594a31c docs(test): record document reliability M1 stop-the-line
Unit, isolated PostgreSQL, and target-package race passed, but real PI, browser, and rebuild were not signed, so the report concludes 停止扩面 and keeps U5–U12 closed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:11:26 +00:00
weichenandCursor f0f57a0755 fix(docflow): avoid mutating shared Commands.Auth
Concurrent HumanEdit/Approve used to assign the default authorizer on the shared Commands value, which raced under -race. Read a local authorizer instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:11:26 +00:00
weichenandCursor c754f7743d feat(docquery): serve ledger when projection is missing
Authorize first, then return immutable ledger markdown with typed consistency so a missing or drifted projection is no longer a 404/409. GET stays read-only and FAV degraded read stays off.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:07:05 +00:00
weichenandCursor ade618b854 feat(docflow): own document commands in one UnitOfWork
Lock the document row and re-authorize duty before edit, agent commit, approve, or reject share a single transaction. Characterization tests pin ETag races, one legal approve/reject terminal, and same-key digest conflicts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:02:21 +00:00
weichenandCursor ec22843297 docs(ops): mark U2 UnitOfWork complete on the pilot task
Record that cross-owner rollback is implemented so U3 can take document commands next.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:54:33 +00:00
weichenandCursor f8b21ecd7c feat(app): add UnitOfWork and owner-bound repositories
Give each document command one postgres transaction and only let table owners unwrap the scope, so cross-owner writes can roll back together.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:54:27 +00:00
weichenandCursor 158ce2586d docs(audit): record U1 architecture baseline
Capture the replayable import/sql/path/event counts and the owned exceptions that later milestones must shrink.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:49:54 +00:00
weichenandCursor 312578ccd1 chore(arch): classify production writers and path rules
Replace whole-repo grep with four production-only gates so Goose and tests stop looking like writer debt, and so new SQL, path, or event crossings fail immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:49:54 +00:00
weichenandCursor 2269cabf43 docs(arch): archive document reliability pilot plan and claim docgov
Land the revised modular-monolith scheme on the implementation branch so U1–U4 can proceed against a frozen design, and register the docgov mutex without occupying the integration slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:43:54 +00:00
weichen a8f9451410 merge: fix/governance-action-level-authz (G5 acceptance docs) 2026-09-14 08:46:57 +00:00
weichenandCursor 05d2154d66 docs(test): archive governance action-level authz acceptance
Record the real-page and API matrix, release the workflow mutex, and point FEATURE-MATRIX / gap-matrix at the report.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:46:45 +00:00
weichen 68640e4de1 merge: fix/governance-action-level-authz (blocked status + canonical duty check) 2026-09-14 08:40:01 +00:00
weichenandCursor 1d366fd38e test(web): stabilize governance authz page matrix locators
Avoid matching the blocked-run hint when opening settings, and close leftover modals before project 143.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:39:44 +00:00
weichenandCursor aec166ea41 feat(api): duty-check canonical docs before they are persisted
Template doc_proj ids were skipping CheckDocTaskAccess and returning 400 not-found.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:39:44 +00:00
weichenandCursor 68fee06da4 feat(db): allow blocked_pending_governance task run status
Pre-activation 202 runs must persist without hitting chk_task_run_status.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:39:44 +00:00
weichen 1dcffb7d11 merge: fix/governance-action-level-authz
G1–G4 duty-action authz, blocked pre-activation runs, and create-time
planning stay; G5 smoke follows on the shared dev stack.
2026-09-14 08:06:37 +00:00
weichenandCursor 5ee898e2e4 docs(ops): occupy integration slot for governance authz
G5 starts merging and smoke on the shared dev stack; Playwright matrix
is ready for the real page pass after rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:04:34 +00:00
weichenandCursor c048060bae docs(audit): classify planning projects with leftover workflow keys
Read-only dev query shows 83 planning rows with a leftover key; all are
paired PROJ_MGR/TEST_PROJ fixtures, none are live business projects.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:01:46 +00:00
weichenandCursor ab9fccded4 feat(web): disable unmanaged approval actions
Hide submit/review/approve on none docs, surface the blocked-run hint in
chat, and warn that unmanaged duties cannot be added after activation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:00:21 +00:00
weichenandCursor 9baf3c83f8 test(web): cover duty-gated actions and blocked-run copy
Pin unmanaged-doc button visibility and treat blocked_pending_governance
as a governance hint, not a successful generation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 08:00:21 +00:00
weichenandCursor 22f65e5f24 feat(projectworkflow): keep create in planning when key provided
Validate the catalog key only and stop writing lifecycle=active so
activation stays on the settings DutyMode path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:55:51 +00:00
weichenandCursor 2e586c99b8 test(projectworkflow): reject create-time active bypass
Creating with initial_workflow_key must stay in planning with an empty
active key while the catalog still mounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:55:51 +00:00
weichenandCursor 295ad89860 feat(api): block pre-activation runs without starting squads
Keep 202 for unactivated document runs, persist blocked_pending_governance,
and refuse submit/review/approve/edit until a live workflow exists.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:54:43 +00:00
weichenandCursor 8384136989 feat(projectinstance): map document actions to duties
Route run/edit/submit/review/approve to a single duty, drop full-doc
creator bypass, and keep view listing independent of stage narrowing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:54:43 +00:00
weichenandCursor 66d2a1837f test(projectinstance): pin action-level duty checks
Lock the full/none/pre-activation matrix so creator no longer implies
document-task privilege and unactivated runs stay WORKFLOW_NOT_ACTIVATED.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:54:43 +00:00
weichenandCursor b4699e9cbe docs(ops): start governance action-level authz
Wave 5 is on local dev@19f6df5; claim the workflow mutex and
register the implementation worktree for G1–G5.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:42:48 +00:00
weichen 19f6df58dd merge: fix/workflow-plan-409-frozen-and-optional-duties Wave 5 acceptance 2026-09-14 07:29:27 +00:00
weichenandCursor ed4a3e53de docs(test): archive workflow-plan 409 settings page acceptance
Record the real UI matrix, release the integration slot, and leave
the unrun PI generation/approval path as an explicit residual.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:29:16 +00:00
weichenandCursor bb1927f23b test(web): harden Wave 5 frozen-duties page matrix
Wait for the workflow select step before clicking next, scope duty
dropdowns by role, and finish first-login reset so dual-tab and
member checks reach the real frozen UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:28:56 +00:00
weichen 840b5be94f merge: fix/workflow-plan-409-frozen-and-optional-duties e2e tidy 2026-09-14 07:08:15 +00:00
weichenandCursor 5d40f5938a test(web): drop unused Wave 5 e2e password binding
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:08:06 +00:00
weichen 354e573f37 merge: fix/workflow-plan-409-frozen-and-optional-duties 2026-09-14 07:07:51 +00:00
weichenandCursor f86a44acd4 docs(ops): occupy integration slot for workflow-plan 409 Wave 5
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:07:39 +00:00
weichenandCursor e1ed561917 feat(web): add optional human-approval switch for configurable docs
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:02:11 +00:00
weichenandCursor a0904fdd69 test(web): cover per-document approval toggle
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 07:02:11 +00:00
weichenandCursor 708b735eea feat(projectinstance): apply duty mode to readiness access and snapshots
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:58:06 +00:00
weichenandCursor 1dd1cc039e test(projectinstance): unify gate access and preview for duty modes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:58:06 +00:00
weichenandCursor ea97a658c6 feat(projectinstance): classify optional duties without lowering required gates
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:53:21 +00:00
weichenandCursor de66558736 test(projectinstance): pin duty mode and activation governance
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:53:21 +00:00
weichenandCursor 0689ac77c3 feat(web): show frozen read-only project settings
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:48:14 +00:00
weichenandCursor 1b0f99a455 test(web): add typed project settings errors and frozen mode
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:48:14 +00:00
weichenandCursor 94065976a5 docs(ops): start workflow-plan 409 frozen and optional duties
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 06:43:53 +00:00
weichen b01af96045 docs(workflow): register reviewed remediation worktree 2026-09-14 06:28:02 +00:00
weichen 15f52cb14e docs(workflow): review frozen plan and optional duty design 2026-09-14 06:26:36 +00:00
746 changed files with 48862 additions and 3102 deletions
@@ -0,0 +1,62 @@
# ADR:以纵向绞杀方式实施模块化单体解耦
## 状态
提议(2026-09-14;架构与实施计划已修订,等待用户确认后进入首个实现里程碑)
## 背景
`internal/server`、`internal/bizdev`、共享 `UserProjectContext`、工作区路径和多表写入形成隐式耦合。
历史受控正文 404/409、刷新后投影缺失和任务终态不完整说明,单纯搬包不会修复事实源、事务与恢复边界。
## 决策
1. **保持模块化单体**:不拆微服务;进程内调用使用窄端口,跨进程可靠性只用于持久事件和 FAV。
2. **纵向绞杀**:先在现有包边界插入端口和适配器,迁完一条业务链并验证后再移动或重命名包;禁止“先全量搬包、以后再接口化”。
3. **契约分层**:外部 API DTO 归 `server/api`;持久 schema、公共事件和稳定共享词汇进入按领域划分的 contracts;一对一内部接口由消费者拥有。
4. **命令与事务同属一个应用用例**:一个业务命令只有一个事务 owner;跨表属主通过同一不透明事务作用域协作,业务状态、账本、当前指针、staging 和 outbox 原子提交。
5. **单一写者不等于单独事务**:表属主控制 SQL 和不变量;应用 UnitOfWork 控制跨属主提交边界。属主端口不得私自嵌套提交。
6. **并发正确性以数据库为准**:用户编辑使用乐观版本/ETag;状态转换使用行锁和条件更新;项目级不变量可使用事务级 advisory lock;进程内 mutex 只能优化,不能作为多副本正确性依据。
7. **锁顺序固定**:同一事务按 project/workflow instance → document record → document version/snapshot → task run → outbox/staging 的顺序取锁;事务内禁止 LLM、对象存储、网络调用和长文件 I/O。
8. **可靠事件采用 transactional outbox**:事件按至少一次投递设计,具有稳定 ID、schema version、环境/项目范围、聚合序号、因果链和幂等键;逐消费者记录 delivery、重试、租约和死信。
9. **工作区是可清理投影**:跨模块只传不可伪造 Workspace ID 和受限 artifact key;物理路径只在 workspace/squadrun 适配器内解析和校验。
10. **最终成果进入 FAV**:PostgreSQL 保存业务关系和授权,FAV 只保存已确认终态的精确 payload、manifest、回执和删除状态,workspace 不承担最终成果事实源。
11. **授权逐动作校验**:认证适配器构造不可由请求覆盖的 Principal;HTTP、CLI、后台订阅者和恢复流程都按 action/resource/current state fail closed。
12. **先完成文档可靠性试点**:只有受控正文刷新、重启、并发提交、投影缺失降级和授权负例通过后,才批准 chat、squad、编排层和传输层扩展。
13. **迁移采用 expand/migrate/contract**:允许新增 Goose migration;不得修改已发布迁移;回滚只保证回到最近的兼容阶段,不能任意独立 revert 早期依赖。
14. **协议改造独立立项**:统一错误信封和 PI Runner `result.json` 不作为核心模块解耦前置条件;它们使用独立兼容与 E2E 验收。
## 并发与失败语义
- 普通聚合状态转换默认 `READ COMMITTED` + 明确行锁/条件更新;涉及跨聚合唯一不变量时才使用 Serializable,并对 `40001`/`40P01` 重跑完整事务。
- outbox worker 使用小批次 `FOR UPDATE SKIP LOCKED` 认领,处理发生在事务外;完成、续租和失败回填使用 fencing token 防止过期 worker 覆盖新 owner。
- 每个写命令必须同时有 idempotency key、expected version 或两者;相同 key 不同 payload 返回 typed conflict。
- 锁等待、事务时长、重试次数、队列积压和死信必须可观测;超过预算时失败返回,不无限等待。
## 授权与恢复语义
- Principal 至少携带 actor、环境、认证来源和请求关联 ID;项目、会话、文档、阶段与 duty 从数据库权威关系重新解析。
- 持久事件中的 actor 只用于审计,不能替代订阅者对当前资源状态的授权检查。
- FAV 降级读取要求运行库授权图完整;授权图缺失时禁止面向用户返回内容。
- 恢复只允许进入 scratch identity;promotion 需要系统管理员与数据责任人确认,并通过各属主端口提交,禁止恢复 CLI 直写运行表。
## 后果
- 首个实现里程碑的改动面小于原 Wave 1–6,但会先增加 UnitOfWork、事件投递和授权基础设施。
- “单表唯一写者”检查改为生产 SQL 写权限检查,并允许 migration、测试和经批准运维脚本存在表名。
- `feature/final-artifact-vault` 是候选依赖,不直接假定可合入;必须先按当前 dev 重放测试、迁移和权限审计。
- 包物理移动、错误信封、SSE 和 PI Runner 协议可延后,不阻塞文档一致性整改。
## 替代方案
- **一次性横向搬包**:拒绝。冲突面大,不能先证明用户故障减少。
- **仅增加 arch-check**:拒绝。门禁不能替代事务、锁和授权契约。
- **拆微服务**:拒绝。当前问题是模块边界和数据一致性,不需要引入分布式事务与跨服务部署成本。
- **继续把 workspace 作为恢复来源**:拒绝。工作区属于可清理计算现场,不能成为最终事实源。
## 相关文档
- [模块解耦架构](../system-design/2026-09-14-module-decoupling-architecture.md)
- [模块解耦整改与重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- [方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)
- [文档版本边界 ADR](./2026-09-13-document-version-boundary.md)
@@ -0,0 +1,30 @@
---
title: "事件连续性采用 consumer checkpoint + 首事件 bootstrap"
status: accepted
created: 2026-09-15
updated: 2026-09-15
---
# ADR:事件连续性采用 consumer checkpoint + 首事件 bootstrap
## 状态
接受(E0A)。在独立 FAV 审计或明确的无缺口 event sequence 迁移完成前不得改为 gap blocking。
## 背景
`event_envelopes` 已有 `UNIQUE (aggregate_type, aggregate_id, aggregate_version)`。受控文档的首次持久事件常常从较高 `aggregate_version`(账本 version_no)开始,中间版本从未发事件。若把领域版本号当成无缺口事件序号并在缺号时等待,会永久阻塞 delivery。MemoryBus 的 `TestGapDoesNotSkipVersion` 只是 characterization,不得搬到 PostgreSQL dispatcher。
## 决策
1. Track E 选择 **consumer checkpoint + 首事件 bootstrap**。
2. 每个 `(consumer, aggregate_type, aggregate_id)` 记录已成功处理的 `event_id` 与可选 `aggregate_version`。该 aggregate 上的第一件 **safe** 事件即为 bootstrap,不要求 version=1。
3. 同一版本多个不同类型事件:当前唯一约束禁止。E0A 审计后保持该约束;需要同版本多事件时另立 additive 迁移,把序号改到独立 `event_seq`,不在本 ADR 启用。
4. **禁止** 在 dispatcher 启用 gap wait / `ErrGapWait` 阻塞,直到另有 ADR 选择独立无缺口 event sequence 且完成回填。
5. 未知 schema、project 0、错误 environment、未知 consumer 的记录进入 inventory,不得 live claim。
## 后果
- E0B checkpoint 表随 dispatcher migration 增加。
- Projection 以 `document_id + source_snapshot_id + digest` no-replace,不依赖连续 version。
- poison 事件 quarantine 后不静默跳号;其他 aggregate 继续。
@@ -1,8 +1,8 @@
---
title: "修复对话刷新恢复与授权统计不一致"
status: in_progress
status: done
created: 2026-09-13
updated: 2026-09-13
updated: 2026-09-15
owner: Cursor
branch: fix/chat-history-refresh
worktree: ".worktrees/fix-chat-history-refresh"
@@ -37,7 +37,7 @@ mutex: chat
3. [x] 实现统一会话/消息授权查询及统计同集
4. [x] 实现历史 dry-run/backfill 与对账
5. [x] 完善前端恢复状态及用户隔离缓存
6. [ ] 执行全量门禁、真实 PI 刷新 E2E 和双用户负例(PG/单测已完成;PI 待 dev 容器)
6. [x] 执行全量门禁、真实 PI 闲聊刷新 E2E 和双用户负例(编制任务激活链 save 400 未纳入本轮)
## 验收标准
@@ -55,3 +55,4 @@ mutex: chat
- Audit: [../../audit/2026-09-13-chat-history-refresh-disappears.md](../../audit/2026-09-13-chat-history-refresh-disappears.md)
- Remediation: [../../remediation/2026-09-13-chat-history-refresh-remediation.md](../../remediation/2026-09-13-chat-history-refresh-remediation.md)
- Live: [../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json](../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403)
@@ -1,11 +1,11 @@
---
title: "修复查询误触发写任务与任务状态刷新退化"
status: in_progress
status: done
created: 2026-09-13
updated: 2026-09-13
owner: Codex
branch: fix/conversation-intent-state
worktree: ".worktrees/fix-conversation-intent-state"
updated: 2026-09-15
owner: Cursor
branch: docs/conversation-intent-dual-tab
worktree: "-"
mutex: intent
---
@@ -34,24 +34,26 @@ mutex: intent
3. [x] 收紧写任务动作识别并修复 busy 错误分型
4. [x] 实现任务/租约状态刷新恢复与统一提示
5. [x] 实现命名文档的服务端鉴权只读总结(“总结”不止是不写入)
6. [ ] 执行前端、Go、PG 与真实 PI 双标签页验收
6. [x] 执行前端、Go、PG 与真实 PI 双标签页验收
- [x] Go、前端、构建、dev 重建与真实 PI 只读总结
- [x] 服务端 busy 预检不创建 run,并持久化无重试状态卡
- [ ] 浏览器刷新恢复与双标签页 busy 可见性
- [x] 浏览器刷新恢复与双标签页 busy 可见性(项目 6275;禁止项目 143)
## 验收标准
- [ ] [整改方案](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) 全部验收项有证据
- [ ] `CHAT-INTENT-STATE` 由 FAIL 更新为 PASS
- [ ] test-report 归档并回链
- [x] [整改方案](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) 全部验收项有证据
- [x] `CHAT-INTENT-STATE` 由 FAIL 更新为 PASS
- [x] test-report 归档并回链
## 相关链接
- Checklist: 本任务验收标准
- Handoff: 与 `fix/chat-history-refresh` 合并前复核 `App.tsx/chatWindow.ts`
- Handoff: [../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.md](../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.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)
## 证据 / 备注
- Audit: [../../audit/2026-09-13-conversation-intent-runtime-state.md](../../audit/2026-09-13-conversation-intent-runtime-state.md)
- Remediation: [../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md)
- 双标签活验:项目 **6275** / `sess-p6275-u10` / `run_1789452602295343365`;产物 `.doc/test-reports/assets/2026-09-15-conversation-intent-dual-tab/`
- 未改写项目 143,未删除 `sess-p143-u9` 探针
@@ -0,0 +1,61 @@
---
title: "可靠事件与 FAV 集成 M2–M3"
status: cancelled
created: 2026-09-14
updated: 2026-09-15
owner: TBD
branch: refactor/durable-event-fav-integration
worktree: "-"
mutex: event-delivery
---
# 可靠事件与 FAV 集成 M2–M3
> 2026-09-15:本任务把 durable event 与未审计 FAV 绑成同一关闭条件,且步骤状态已与 U8/U9 后续交付漂移。任务停止使用;持久事件由 [Track E](../../ops/short-term/2026-09-15-durable-event-track-e.md) 接续,FAV subscriber 继续走独立审计,不把本条已勾选步骤视为生产 dispatcher 验收。
## 目标
完成 U5–U9,使投影、通知、RunManifest 和最终成果在多 worker、崩溃、重放和 workspace 清理后仍可恢复且不越权。
## 范围
- opaque workspace capability、lease 和 fencing。
- durable outbox、逐消费者 delivery/inbox、重试和 dead letter。
- 审计并集成 `feature/final-artifact-vault` 的适用实现。
- taskrun finalize、RunManifest 持久化、FAV coverage 和迁移 corpus。
## 非目标
- 不盲目整分支 cherry-pick FAV。
- 不启用跨授权图的 vault 读取。
- 不自动销毁 dev/main 数据。
- 不执行 U10–U12。
## 步骤
1. [x] 读取 M1 test report,确认继续 M2 的 go/no-go 已通过。
2. [x] 重新分配 Goose 序号并审计 U6/FAV schema 组合。
3. [x] 实现 U5–U6,多 app/worker 和 crash matrix 先通过。
4. [x] 逐文件审计 FAV 分支,按 U7 边界迁移合格实现。
5. [ ] 实现 U8,收敛 taskrun terminal finalize 与 RunManifest。
6. [ ] 实现 U9 的 checkpoint backfill、corpus、quarantine 和 cleanup gates。
7. [ ] 完成真实 PI、浏览器、workspace 清理、scratch recovery 和 rebuild 演练。
## 验收标准
- [ ] 多订阅者有独立 delivery,失败者不阻塞其他订阅者。
- [ ] worker crash/retry/replay 不造成重复可见副作用。
- [ ] workspace 清空后,verified 最终文档/回复仍可定位并校验。
- [ ] 授权图缺失、跨项目、tombstone、坏 digest 和 stale fencing 全部拒绝。
- [ ] clean/oldest/previous/hazard/import/reload/rollback/artifact recovery 八轨有独立证据。
- [ ] 任何数据销毁仍需完整备份、corpus、FAV coverage 和用户批准。
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Handoff: 实施时创建
- Test report: 实施后按 M2、M3 分开创建
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
## 证据 / 备注
本任务依赖 M1,不得与 M1 同时修改 docgov/docrevision 的事务主链。
@@ -0,0 +1,81 @@
---
title: "治理鉴权升级:职责-动作严格对应 + 未激活拦截 + 关闭创建直通"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: implementer_cursor
branch: fix/governance-action-level-authz
worktree: ".worktrees/fix-governance-action-level-authz"
mutex: workflow
---
# 治理鉴权升级:职责-动作严格对应 + 未激活拦截 + 关闭创建直通
## 目标
采纳 [MVP 治理规则评审](../../ops/research/2026-09-14-mvp-governance-rules-review.md) 修正版原则:**允许零治理创建与普通对话;禁止零治理激活与执行文档任务(审批流动作)**。文档动作按职责鉴权,创建者不隐式越权,`initial_workflow_key` 不再直通 active。
## 决策记录(已定,不再开放)
- **A(用户拍板 2026-09-14)**:`DutyModeNone` 文档 = 不走人工审批但**可生成**(创建者触发,维持已实施 D4);「不可发起任务」收窄为不可发起**审批流动作**(submit/review/approve)。
- **B(按评审建议采纳)**:pre-activation 保留 202 契约——`POST /tasks/runs` 仍 202 创建 run,但置 blocked 状态、不启动小队、不取文档租约,chat 流内返回自然语言治理提示。
- **C(按评审建议采纳)**:移除 `isCreator` 对 full 文档的隐式全通行;`view` 豁免阶段收窄(项目访问成员可查看);创建者保留:配置成员/职责 + none 文档生成触发。
- **D(按评审建议采纳)**:关闭 `initial_workflow_key` 直通 active(仅挂载目录);后端/前端 types 字段废弃标注;E2E legacy 用例语义更新;dev 库 81 个 planning+with_wf 异态项目**只审计分类,不改库**。
## 采纳版职责-动作矩阵
| 动作 | full 文档 | none 文档 | 未激活(gov==nil) |
|------|-----------|-----------|--------------------|
| view | 项目访问成员 | 项目访问成员 | 项目访问成员 |
| run(首次生成/重生成) | 编制负责人 | **创建者**(无审批链) | 202 + blocked 状态,chat 内提示,不启小队/不取租约 |
| edit/submit(编辑/提交审核) | 编制负责人 | 拒绝(无审批链) | 拒绝 |
| review(审核/退回) | 审核负责人 | 拒绝 | 拒绝 |
| approve(批准/拒绝批准) | 批准负责人 | 拒绝 | 拒绝 |
| 配置成员/文档职责 | 创建者 | 创建者 | 创建者(planning 期配置正是本阶段语义) |
退回后形成「待编制人修订」;审核人不得直接启动重编(由编制负责人发起修订)。
## 范围
- `internal/projectinstance/document_access.go`(动作-职责映射、creator 例外移除、gov==nil 未激活拦截)
- `internal/projectinstance/stage_access.go`(view 豁免语义;`docTaskDutyForUser` 拆分为按职责判定)
- `internal/projectinstance/message_scope.go` + taskrun/chat handler(blocked 状态 + 自然语言提示)
- `internal/projectworkflow/service.go`(关闭 `initial_workflow_key` 直通)+ `types.go` 前后端字段废弃
- 受影响单测重写(`access_governing_pg_test.go` creator 断言、`TestCreateTaskRun_PreActivationAcceptedNot409` 语义细化)与 E2E legacy 用例
## 非目标
- 不改三权互斥与 DutyMode 校验(Wave 2 已完成)
- 不做运行中动态补配职责 / 按文档单独激活(冻结语义维持,激活页提示「留空文档不参与、不可补配」)
- 不做成员 role 枚举演进(MVP 维持创建者=项目管理员;role 演进留 backlog)
- 不改 dev 库存量数据(仅审计)
## 步骤
1. [x] 评审落盘 + 决策 A–D 收敛 + 本任务登记(Wave 5 已合入本地 `dev@19f6df5`,G0 已开工)
2. [x] G1 后端:`CheckDocTaskAccess` 动作-职责映射 + creator 例外移除(保留 none 生成触发)+ gov==nil 未激活拦截(202 契约保留);重写受影响单测
3. [x] G2 关闭 `initial_workflow_key` 直通 + 前后端字段废弃 + E2E legacy 用例更新
4. [x] G3 前端:chat 治理拦截自然语言提示、按钮级职责禁用、激活确认页冻结提示补强
5. [x] G4 dev 库 planning+with_wf 异态审计分类(只读报告,现测 83 条均为测试夹具)
6. [x] G5 集成验证 + 测试报告归档(新项目全链路:零治理创建→对话→配置→激活→职责动作负例)
## 验收标准
- [x] full 文档 API 负例:author 不可 review/approve;reviewer 不可 run/edit/submit;approver 不可 run/edit/review;creator 不可任一审批动作(view 除外)
- [x] none 文档:创建者可触发生成;submit/review/approve 全拒
- [x] 未激活项目编制类输入:消息正常显示、run 202 且 blocked、无小队/租约、chat 内明确治理提示文案(页面用「请编制用户初始需求收集表」命中任务 API)
- [x] `POST /projects` 带 `initial_workflow_key`:不再置 active,工作流目录仍自动挂载
- [x] `go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿
- [x] 异态审计报告与测试报告归档并回链
## 相关链接
- Research(评审与决策记录): [2026-09-14-mvp-governance-rules-review.md](../../ops/research/2026-09-14-mvp-governance-rules-review.md)
- 前序 Remediation(已实施 Wave 1–4): [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- 202 契约来源: [2026-09-13-workflow-access-chat-members-ui01-02.md](../../audit/2026-09-13-workflow-access-chat-members-ui01-02.md)
## 证据 / 备注
- Wave 5 已合入本地 `dev@19f6df5`;本任务 worktree 已从该 `dev` 创建,mutex `workflow` 进入 `in_progress`。
- G4 只读复测:141 active / 209 planning;**83** 个 planning 带非空 `active_workflow_key`,全部为 `PROJ_MGR_*`/`TEST_PROJ_*` 夹具。见 [audit](../../audit/2026-09-14-planning-with-workflow-key-anomaly.md)。
- G5 验收:[2026-09-14-governance-action-level-authz-test-report.md](../../test-reports/2026-09-14-governance-action-level-authz-test-report.md)。
@@ -0,0 +1,55 @@
---
title: "模块解耦架构与重构计划修订"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Codex
branch: feature/module-decoupling-remediation
worktree: .worktrees/feature/module-decoupling-remediation
mutex: architecture-docs
---
# 模块解耦架构与重构计划修订
## 目标
把模块解耦方案修订为可以分段实施、验证和回滚的架构与重构计划,补齐事务、并发互斥、授权、可靠事件、FAV、数据迁移和真实页面验收。
## 范围
- 修订模块化单体架构设计与 ADR。
- 新增详细整改与重构计划。
- 建立首个文档可靠性纵向试点及后续里程碑任务。
- 更新 CURRENT、FEATURE-MATRIX 和相关索引。
## 非目标
- 本任务不修改业务代码、数据库迁移或部署配置。
- 本任务不合并 `feature/final-artifact-vault`,只定义其集成依赖和边界。
- 本任务不执行共享容器验证,也不占用集成槽位。
## 步骤
1. [x] 对照当前源码、已接受 ADR、FAV 分支和外部权威资料复核原方案。
2. [x] 修订架构设计与 ADR。
3. [x] 编写详细整改计划、里程碑任务和验收清单。
4. [x] 更新协作 SSOT 与索引并完成文档一致性检查。
## 验收标准
- [x] 计划明确事务所有权、锁顺序、事件投递语义、授权主体和恢复边界。
- [x] 首个独立交付边界直接覆盖受控文档刷新、重启、投影缺失和授权负例。
- [x] 每个后续里程碑有依赖、文件范围、并发风险、测试矩阵、停走门和回滚边界。
- [x] FAV、迁移语料库和完整备份的职责不重叠,工作区不再承担最终成果事实源。
## 相关链接
- Checklist: [../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Handoff: 不需要;实现阶段使用两个 planned short-term 接续
- Test report: 本任务仅产出计划,不生成业务验收报告
## 证据 / 备注
- 原方案位于主工作区未跟踪文件;本任务在独立 worktree 重建并修订,未覆盖原工作区。
- `feature/final-artifact-vault` 已有实现与测试证据,但尚未合入本任务基线,实施前必须重新审计分支差异。
- 文档校验:本地相对链接、R/KTD/U ID 唯一性、Mermaid fence 和 `git diff --check` 均通过。
@@ -0,0 +1,71 @@
---
title: "workflow-plan 409 冻结态守卫 + 文档职责可选治理"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: implementer_cursor
branch: fix/workflow-plan-409-frozen-and-optional-duties
worktree: ".worktrees/fix-workflow-plan-409-frozen-and-optional-duties"
mutex: workflow
---
# workflow-plan 409 冻结态守卫 + 文档职责可选治理
## 目标
已激活项目的设置页进入明确的冻结只读态;非必需且允许裁剪的文档可选择“不纳入人工审批”,部分职责、必需文档空职责、非成员职责和零治理激活由服务端拒绝;门禁、权限、快照与页面语义保持一致。
## 范围
- `web/src/components/project/ProjectSettingsModal.tsx`:frozen 视图、逐文档审批开关、内联/sticky 错误、并发恢复。
- `web/src/api/projectSettings.ts`:保留 status/code/message/issues 的 typed error。
- `internal/projectinstance/validator.go`:统一 DutyMode、工作流定义约束、结构与成员校验。
- `internal/projectinstance/service.go`:保存/预览/激活重复复核 active members。
- `internal/projectinstance/gate.go`、`stage_access.go`、`document_access.go`:none/full/disabled 一致语义。
- `internal/projectinstance/store.go`、`internal/workflow/runtime/orchestrator.go`:快照清理、零 assignment rows、零职责运行时契约。
- 激活预览统计与相应前后端测试。
## 非目标
- 不修改项目 143 的现有工作流配置,不在验收中终止项目 143。
- 不支持部分指派或自动补齐职责。
- 不允许项目配置降低工作流定义中必需/阻断文档的治理要求。
- 不把“无需人工审批”文档改成无版本、无审计的非受控文档。
- 不迁移历史 active 实例;冻结快照继续作为历史 SSOT。
## 步骤
1. [x] 定位项目 143 的 409 `PLAN_FROZEN` 根因并落盘 audit。
2. [x] 完成方案审核:补齐定义优先、零治理拦截、成员有效性、权限、快照清理和真实 UI 边界。
2b. [x] 用户批准最终方案,开工登记(Wave 0)
3. [x] Wave 1:typed API error + frozen 独立只读视图 + sticky/可访问错误 + 两标签竞态恢复。
4. [x] Wave 2:DutyMode、强制/可选任务策略、partial/成员/零治理校验、服务端规范化。
5. [x] Wave 3:门禁、readiness、阶段/文档访问、运行时和预览统计统一。
6. [x] Wave 4:前端逐文档“纳入人工审批”开关及 full/none/partial 交互测试。
7. [x] Wave 5:合 dev、rebuild、真实浏览器设置页矩阵;项目 143 只读回归;归档 test report。真实 PI 生成/审批长链路未跑,见报告。
## 验收标准
- [x] active 项目设置无编辑控件,页面显示冻结原因、工作流/阶段/职责快照和受控终止影响入口。
- [x] 允许裁剪的非必需文档 full/none 均合法;partial 精确拒绝。
- [x] 必需/阻断/不可裁剪文档全空被服务端拒绝(单测 + 定义优先)。
- [x] 保存和激活均拒绝非 active project member;预览后成员退出也 fail closed(单测)。
- [x] 所有文档 none 时可走预览拒绝「至少一份纳入人工审批」(页面 C)。
- [ ] none 文档仍生成和入账本、项目成员只读可见、创建者可生成/编辑,但无 review/approve 且不阻塞阶段(**本轮未跑真实 PI,单测已覆盖门禁/权限**)。
- [x] disabled/none 的冻结快照、plan hash 和 assignment rows 不残留旧职责(Wave 3 单测)。
- [x] 两标签陈旧保存的 409 在当前视口可见、草稿保留并转 frozen。
- [x] 设置页真实 UI 用例有截图证据并回链;生成/审批长链路另立项。
## 相关链接
- Audit: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- Remediation: [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- Test report: [2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md](../../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md)
## 证据 / 备注
- dev 项目 143:`lifecycle_status=active`、`active_workflow_key=main`、实例 89 active;409 与三名职责人选择内容无关。
- 当前 `parseError` 已读取后端 message;前端改造重点是 typed error、冻结态切换和视口内呈现。
- 当前职责校验只检查正数/互异,数据库只外键到 users;项目成员有效性必须补服务端校验。
- 当前终止实现会取消运行任务、关闭实例并退回 planning;关闭实例访问 fail closed,因此项目 143 不能作为终止测试对象。
- 方案已迁移至基于最新 dev 的 `fix/workflow-plan-409-frozen-and-optional-duties` 独立 worktree;用户已批准实施。
@@ -0,0 +1,63 @@
---
title: "M5/M6 组合根与传输门禁 U11–U12"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/app-composition-u11-u12
worktree: "-"
mutex: app
---
# M5/M6 组合根与传输门禁 U11–U12
## 目标
按整改计划四个子切片完成组合根、文档通知闭包迁出、stageflow 用例、UserProjectContext CAS;再收口 SSE 编码与已清零规则的 arch-check block。用户已明确授权继续 U11/U12(推翻 U10 报告的停止扩面)。
## 范围
- U11a:`internal/app` 唯一 composition root;幂等 Start/Stop
- U11b:文档 `OnOutbox` 通知迁到 `internal/app/docnotify`
- U11c:`internal/app/stageflow` 拥有 ExecuteTask / ExecuteStage
- U11d:`ContextUpdate` 版本 CAS,禁止跨模块字段级直改
- U12:SSE 中性 frame 编码;`import`/`event` 转 block;不改错误信封与 PI Runner 协议
## 非目标
- 不碰 `intent` 包行为(编码阶段 mutex 仍由 Codex 占用;合入后浏览器门另开 handoff)
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不终止或改写项目 143
- 不删除未到期的 sql_write/path 例外(U3/U5 残留)
- 不在 worktree 内 `env-service`
## 步骤
1. [x] 认领 CURRENT + 本任务
2. [x] U11a composition root
3. [x] U11b docnotify
4. [x] U11c stageflow
5. [x] U11d ContextUpdate
6. [x] U12 SSE + arch-check block_kinds
7. [x] 短测 / 目标包 race / 报告
8. [x] 占槽 `--no-ff` 合入 `dev` + 主仓 `dev rebuild`
## 验收标准
- [x] 重复 Start 不重复注册 subscriber;Stop 后再 Start worker 仍在
- [x] server 生产代码不再赋值 `OnOutbox`
- [x] HTTP 与 CLI 走同一 stageflow 用例
- [x] ContextUpdate 并发 stale version 不丢更新赢家
- [x] `arch-check --mode block` 对已清零的 import/event 通过
- [x] 测试报告回链 U11/U12
- [x] 合入后 `/health` `/ready` schema 38、`pi-agent`、新镜像 digest
## 相关链接
- Checklist: [../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- Test report: [../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md](../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md)
## 证据 / 备注
用户口头授权:「继续解耦到 U11、U12」。合入 `dev@bf59cce`。rebuild 镜像 `sha256:a8e3e940f01111c4298c67947ae9f4cd6105f13cf58134672f4a87daa19e27ab`。health/ready:`.doc/test-reports/assets/2026-09-15-app-composition-u11-u12/rebuild-health-ready.txt`。
@@ -0,0 +1,45 @@
---
title: "D4 bizdev locator 最终移除"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/bizdev-locator-removal
worktree: "-"
mutex: bizdev
---
# D4 bizdev locator 最终移除
## 目标
删除 bizdev 上 8 个 locator getter;组合根一次性 Snapshot 后由 Runtime/Server 持有端口。
## 范围
- `Pool` `DocGov` `DocRevision` `ContextManager` `CAS` `ProjectWorkflow` `FreeformDoc` `KB`
- Runtime / Server 字段
- archtest 禁止把 getter 加回去
- 调用方迁移
## 非目标
- 不删 SchemaVersion / DatabaseReady
- 不切事件 live
- 不实现 Track P
## 步骤
1. [x] Snapshot + Runtime 端口
2. [x] 迁移 server/cmd/tests
3. [x] 同批删除 8 getter
4. [x] 报告合入
## 验收标准
- [x] 生产无 8 个 getter
- [x] [S1 报告](../../test-reports/2026-09-15-bizdev-locator-removal-test-report.md)
## 相关链接
- Phase 2 D4
@@ -0,0 +1,39 @@
---
title: "D7b chat 编排剩余批次"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/chatflow-orchestration-boundary
worktree: "-"
mutex: chat
---
# D7b chat 编排剩余批次
## 目标
`internal/chat` 生产代码不再 import bizdev;任务请求走 stageflow 类型别名。
## 范围
- action_executor 去掉 Bizdev 字段
- 收紧 chat import allowlist
- 表征测试保留
## 非目标
- 不搬空测试 import
- 不把 taskrun 签名从 bizdev 别名拷成独立结构
- 不切事件 live
## 步骤
1. [x] action_executor 改 stageflow 类型
2. [x] 收紧 yaml
3. [x] 报告合入
## 验收标准
- [x] chat 生产无 bizdev import
- [x] [S4b 报告](../../test-reports/2026-09-15-chatflow-orchestration-boundary-test-report.md)
@@ -0,0 +1,59 @@
---
title: "U10 chatlog/contextasm 原地端口化"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/chatlog-contextasm-u10
worktree: "-"
mutex: chat
---
# U10 chatlog/contextasm 原地端口化
## 目标
在不物理拆包的前提下,为对话读取与 prompt 装配建立带 Principal 的消费者端口,使正文、分类、计数、导出、摘要和恢复使用同一授权可见集合。
## 范围
- `internal/app/chatflow` ChatLog / ContextAssembler 端口
- ctxmgr 表所有权不变;adapter 内做可见性过滤
- server 历史读取 handler 改走 ChatLog;忽略 query/body 中的 user_id 身份
- 会话 restore / 记忆召回只注入允许集合
- 不碰 `intent` mutex,不物理搬到 `chatlog`/`contextasm` 包
## 非目标
- U11–U12
- 整支 merge `feature/final-artifact-vault`
- 启用 `FAV_DEGRADED_READ`
- 纯搬包
## 步骤
1. [x] 核实 `chat` mutex:`fix/chat-history-refresh` 已是 `dev` 祖先;剩余真实 PI 刷新与 U10 同批收口
2. [x] 从最新 `dev` 开 `feature/chatlog-contextasm-u10` 并登记 CURRENT
3. [x] 定义 chatflow 端口与 ctxmgr adapter
4. [x] 迁移 window/day/stats/search/unread/export/digest/history/restore/memory
5. [x] 合同测试:同集计数、非 owner 403、restore/digest 不放大不可见消息
6. [x] 验收报告;最后一句 **停止扩面**
## 验收标准
- [x] 刷新前后同一授权集合的正文与分类计数一致(adapter 合同测试)
- [x] 跨用户负例 fail closed(guest 非 owner)
- [x] context assembly / digest 只使用允许集合
- [x] 真实 PI 闲聊刷新 E2E 证据(与对话刷新活验同批;编制任务链 save 400 未纳入停走)
- [x] 未物理拆包;DTO 转换为 0,拆包收益不成立
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- Chat refresh: [../../test-reports/2026-09-13-chat-history-refresh-test-report.md](../../test-reports/2026-09-13-chat-history-refresh-test-report.md)
- Test report: [../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md)
## 证据 / 备注
U9 最后一句 **继续 U10** 只批准进入 M4。禁止 U11–U12。`intent` 认领仍 `in_progress`,本单元不改意图分类。活验项目 6252 / `sess-p6252-u10`;产物 `.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`。未占槽 rebuild。
@@ -0,0 +1,59 @@
---
title: "M3 U9 存量回填、migration corpus 与数据生命周期"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/dataset-lifecycle-u9
worktree: "-"
mutex: dataset
---
# M3 U9 存量回填、migration corpus 与数据生命周期
## 目标
只保留可解释的演示/回归数据,并持续验证旧数据迁移、重载和受控恢复。backfill 可暂停续跑,异常进 quarantine;八条轨道可重复;销毁默认 fail closed。
## 范围
- dataset registry(pinned / demo / regression / migration_baseline / ephemeral / quarantine)
- checkpoint 分批 backfill:只枚举 snapshot、approved/commit event、completed chat turn
- SKIP LOCKED 多 worker;禁止扫描 workspace
- 销毁门禁:FAV coverage + 完整备份 restore + corpus + 精确 manifest + 双人批准 + quarantine 观察窗
- restore 拒绝共享 env DSN;只允许 scratch
- 八轨:clean / oldest-supported / previous / hazard / import / reload / rollback / artifact recovery
## 非目标
- U10–U12;不碰 `chat` / `intent` mutex
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不修改历史 Goose;不销毁 `agent_system_dev/test/main`
- 不终止或改写项目 143;worktree 内禁止 `env-service`
## 步骤
1. [x] CURRENT 认领 `mutex=dataset`;从 `dev` 开 `feature/dataset-lifecycle-u9`
2. [x] Goose 00038 + `module-boundaries.yaml`
3. [x] `internal/artifactvault/backfill.go` + `internal/dataset` + `cmd/dataset`
4. [x] 硬化 `scripts/restore-system-db-drill.sh`
5. [x] 隔离库 + 八轨 + 目标包 `-race` + 占槽 rebuild
6. [x] 验收报告;最后一句 **继续 U10**
## 验收标准
- [x] backfill 中断、重复、并发新终态时分母/分子可复算且不重复 artifact
- [x] legacy-v0 / 旧 schema / 高 ID / projection fork / 缺 snapshot → quarantine 或升级
- [x] restore 拒绝共享 DSN、错误 storage identity、篡改 manifest、缺权限
- [x] coverage / backup / corpus 任一失败阻止 destroy
- [x] 批准 dataset 导入后关系、SHA、sequence 可复算
## 相关链接
- Checklist: `.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md`
- Plan: `.doc/remediation/2026-09-14-module-decoupling-refactor-plan.md` U9
- Test report: `.doc/test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md`
## 证据 / 备注
见验收报告。Goose 00038。dev schema 38。
@@ -0,0 +1,46 @@
---
title: "D6 doccontent canonical 边界"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/doccontent-canonical-boundary
worktree: "-"
mutex: docgov
---
# D6 doccontent canonical 边界
## 目标
Markdown canonicalization 与 SHA 抽到 `internal/doccontent`;生产 `docgov` 不再 import `docrevision`。
## 范围
- `internal/doccontent`
- `docgov/lease.go` 改走 doccontent
- `docrevision` 薄封装保持旧调用方
- golden + wrapper 对账
## 非目标
- 不改 hash 语义
- 不碰项目 143 数据
- 不删 `docrevision.CanonicalizeMarkdown` 导出(兼容)
## 步骤
1. [x] 分支与 CURRENT
2. [x] 提取模块与切断 docgov→docrevision
3. [x] golden / arch-check
4. [x] 报告并合入
## 验收标准
- [x] 生产 docgov 不 import docrevision
- [x] project143 hard-break golden 仍过
- [x] [S3 报告](../../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.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)
@@ -0,0 +1,53 @@
---
title: "Track E 持久事件交付"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-e2-hook-guard
worktree: "-"
mutex: events
---
# Track E 持久事件交付
## 目标
按 E0A→E0B→E1A→E1B→E1C 完成 notify、workflow advance、projection 的 PG 持久交付,并用授权页面刷新/重启恢复证据关闭 `DOC-RELIABILITY-PILOT` 的事件部分。
## 范围
- E0A:生产入口/UoW、event contract、runtime registry、历史数据与 sequence 门。
- E0B:PG dispatcher、attempt audit、独立进程、并发与故障注入。
- E1A/B/C:三个消费者独立 shadow、switch、rollback 和真实恢复验收。
## 非目标
- FAV consumer 激活、bizdev/chat/intent 结构重构、HTTP 错误信封、PI typed result。
- 删除或覆盖历史事件;在 E0A 通过前启动 dispatcher。
## 步骤
1. [x] E0A 单独建 short-term/分支,dispatcher 保持 off。
2. [x] E0A 报告通过后再认领 E0B。
3. [x] 依次交付 E1A notify、E1B workflow advance、E1C projection;每步独立 go/no-go。
4. [x] E2 兼容守卫:live 时闭包停写;hook API 待 live 窗口后删除。
5. [x] 同步 test report、CURRENT、FEATURE-MATRIX、gap-matrix、[复盘](../research/2026-09-15-track-e-retrospective.md)。
## 验收标准
- [ ] 满足 [Phase 2 Track E Definition of Done](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md#track-e-definition-of-done)(共享 live 与删除 hook API 仍开放)。
- [x] 每个波次拥有独立 owner、mutex、分支、报告和回滚证据。
- [x] 未把计划、MemoryBus、stub 或日志冒充生产 PG/browser/restart 验收。
## 相关链接
- Checklist: 按每个波次建立
- Audit: [Phase 2 方案审阅](../../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- Remediation: [Phase 2 修订计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Test report: [E2](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
- 复盘: [./research/2026-09-15-track-e-retrospective.md](../research/2026-09-15-track-e-retrospective.md)
## 证据 / 备注
本条只建立执行入口,不代表已批准 E0A 或已认领 mutex。实施前必须按 CURRENT 检查冲突并从当时最新 dev 建分支。
@@ -0,0 +1,49 @@
---
title: "E0A 事件生产、契约与历史数据门"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-production-scope-contract
worktree: "-"
mutex: events
---
# E0A 事件生产、契约与历史数据门
## 目标
组合根注入唯一 `docflow.Commands`;candidate-ready、downstream-impact、approved 三条链在同一 UoW 写 envelope/delivery;缺 env/project fail closed;FAV 不写入;allowlist 与 runtime registry parity;历史 inventory 分类且不删数据;dispatcher 保持 off。
## 范围
- D3 生产入口与作用域
- D10 既有 event allowlist 补全与 registry parity
- D11 inventory、sequence ADR、repair/quarantine/expire、replay 骨架、service principal 表
## 非目标
- 不实现/启动 PG dispatcher
- 不激活 FAV,不写 staging/artifact/publication
- 不删除历史事件
- 不开始 Track S/P
## 步骤
1. [x] 从最新 `dev` 开 `fix/event-production-scope-contract` 并登记 CURRENT
2. [x] 唯一 Commands、三条链同 UoW、FAV 隔离
3. [x] allowlist + registry parity + 动态 FAV 注册失败
4. [x] inventory/repair/replay/principal additive schema 与用例
5. [x] 连续性模型 ADR;gap blocking 关闭
6. [x] 隔离库 PG 证据与 test-report
## 验收标准
- [x] 见 [E0A 测试报告](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md)
## 相关链接
- Remediation: [../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md)
- ADR: [../../adr/2026-09-15-event-consumer-checkpoint.md](../../adr/2026-09-15-event-consumer-checkpoint.md)
@@ -0,0 +1,43 @@
---
title: "E0B PG dispatcher 基座"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/events-dispatcher-pg
worktree: "-"
mutex: events
---
# E0B PG dispatcher 基座
## 目标
原子 lease/attempt/heartbeat/fencing、独立 `cmd/events`、默认 mode=off、1/2/4 worker 与崩溃注入。
## 范围
- Goose 00040、ClaimLeases、cmd/events、compose events 服务
## 非目标
- 不把任何 consumer 切 live
- 不激活 FAV
- 不删除历史
## 步骤
1. [x] 从 E0A 后 `dev` 开 `feature/events-dispatcher-pg`
2. [x] additive schema + atomic claim
3. [x] worker/heartbeat/fencing/shadow scan
4. [x] cmd/events + compose
5. [x] 隔离库 PG + race + 报告
## 验收标准
- [x] [E0B 测试报告](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md)
@@ -0,0 +1,48 @@
---
title: "E1A notify shadow 与切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-notify-cutover
worktree: "-"
mutex: events
---
# E1A notify shadow 与切换
## 目标
notify 消费者具备 shadow 覆盖门、live 唯一可见结果与显式 rollback;生产集群保持 off。
## 范围
- Goose 00041、`EmitVisibleDocumentEvent`、`docnotify.EventConsumer`、Handler 与 Ack 同事务
- cmd/events 注册 notify(mode=off 时不 claim)
## 非目标
- 不把共享环境 notify 切 live
- 不删除 OnOutbox 闭包
- 不激活 FAV / workflow advance / projection live
## 步骤
1. [x] 从 E0B 后 `dev` 开 `fix/event-notify-cutover`
2. [x] additive `source_event_id` 与可见结果唯一索引
3. [x] shadow dry-run + live 同事务 ack
4. [x] fixture N=30、quarantine、correlation、rollback
5. [x] 隔离库 PG + race + 报告
## 验收标准
- [x] [E1A 测试报告](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md)
## 证据 / 备注
隔离库 `agent_rel_e1a` 测完已 DROP。共享 `event_consumer_modes.notify=off`。
@@ -0,0 +1,44 @@
---
title: "E1B workflow advance shadow 与切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-workflow-advance
worktree: "-"
mutex: events
---
# E1B workflow advance shadow 与切换
## 目标
workflow_advance 具备 shadow/live/rollback;并发或重放批准只产生一次阶段可推进可见结果。生产集群保持 off。
## 范围
- Goose 00042、`docadvance.EventConsumer`、`EmitVisibleStageReady`、MarkDocTaskApproved 走 fenced tx
- cmd/events 注册 workflow_advance
## 非目标
- 不把共享环境 workflow_advance 切 live
- 不删除 AddOnApprovedHook
- 不激活 FAV / projection live
## 步骤
1. [x] 从 E1A 后 `dev` 开 `fix/event-workflow-advance`
2. [x] additive source_event_id on stage_advance_requests
3. [x] consumer 重读文档并同事务 ack
4. [x] 隔离库并发/重放/quarantine/rollback
5. [x] 报告
## 验收标准
- [x] [E1B 测试报告](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md)
@@ -0,0 +1,41 @@
---
title: "E1C projection no-replace"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-projection-cutover
worktree: "-"
mutex: events
---
# E1C projection no-replace
## 目标
projection 消费者幂等只前进;共享集群保持 off。
## 范围
- Goose 00043、ProjectHeadNoReplace、docproject.EventConsumer
## 非目标
- 不把共享 projection 切 live
- 不激活 FAV
- 不删除闭包
## 步骤
1. [x] 分支与 additive schema
2. [x] no-replace SQL + consumer
3. [x] 隔离库 + race + worker 重启
4. [x] 报告
## 验收标准
- [x] [E1C 测试报告](../../test-reports/2026-09-15-event-e1c-projection-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
@@ -0,0 +1,48 @@
---
title: "E2 闭包 live 停写与 Track E 复盘"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-e2-hook-guard
worktree: "-"
mutex: events
---
# E2 闭包 live 停写与 Track E 复盘
## 目标
在 dispatcher 仍默认 off 时保留 `OnOutbox` / `AddOnApprovedHook` 接线,使对应消费者切 `live` 后闭包立即停写,避免双写;并写 Track E 复盘。不关闭 `DOC-RELIABILITY-PILOT`。
## 范围
- `events.WriterLive`
- `docnotify.Subscriber.SkipWrite`
- Runtime / 遗留 HTTP hook 在 `workflow_advance` live 时 no-op
- 复盘与 E2 测试报告
## 非目标
- 不删除 hook API(须等 live 发布窗口)
- 不把共享 notify/advance/projection 切 live
- 不激活 FAV
- 不关闭 Track E 发布 blocker
## 步骤
1. [x] 从最新 `dev` 开 `fix/event-e2-hook-guard` 并登记 CURRENT
2. [x] WriterLive + 闭包守卫 + 单测
3. [x] 隔离库 mode 矩阵
4. [x] 复盘与报告
## 验收标准
- [x] live 时闭包不写;off/shadow 仍写
- [x] 生产仍保留 Bind / AddOnApprovedHook(mode=off 必需)
- [x] [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- 复盘: [../research/2026-09-15-track-e-retrospective.md](../research/2026-09-15-track-e-retrospective.md)
@@ -0,0 +1,54 @@
---
title: "共享环境事件消费者 live 切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/event-shared-live-cutover
worktree: "-"
mutex: events
---
# 共享环境事件消费者 live 切换
## 目标
在共享 `agent-dev` 上按 notify → workflow_advance → projection 完成 shadow → drain → live → 回滚演练,再删除生产 hook 注册。
## 范围
- `scripts/event-consumer-mode.sh` + `cmd/eventmode`
- 共享 `agent_system_dev` inventory / quarantine
- 逐消费者 live 与授权页纵切(项目 6275;143 只读)
## 非目标
- FAV live
- test/main 环境
- 编辑 Phase 2 计划原文
- Track P(独立波次)
## 步骤
1. [x] L0 受控 SetMode 与 inventory
2. [x] L1 notify
3. [x] L2 workflow_advance
4. [x] L3 projection + 授权页
5. [x] L4 删除生产 hook 注册
## 验收标准
- [x] fav / test / main 切模式失败
- [x] 每消费者独立 live 报告
- [x] 生产代码无 `OnOutbox =` / `AddOnApprovedHook(`
## 相关链接
- Long-term: [.doc/archive/ops/2026-09-15-event-shared-live-cutover.md](../../archive/ops/2026-09-15-event-shared-live-cutover.md)
- Notify: [.doc/test-reports/2026-09-15-event-notify-shared-live-test-report.md](../../test-reports/2026-09-15-event-notify-shared-live-test-report.md)
- Advance: [.doc/test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md](../../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md)
- Projection: [.doc/test-reports/2026-09-15-event-projection-shared-live-test-report.md](../../test-reports/2026-09-15-event-projection-shared-live-test-report.md)
## 证据 / 备注
已合入 `dev@39dc68d`。生产 hook 注册已删;方法本体保留一个窗口。
@@ -0,0 +1,34 @@
---
title: "共享环境事件消费者 live 切换"
status: done
created: 2026-09-15
updated: 2026-09-15
---
# 共享环境事件消费者 live 切换
## 动机
Track E 已在隔离库证明 notify / workflow_advance / projection 的 exactly-one visible outcome 与 E2 闭包守卫。共享集群仍为 `off`,HTTP 闭包仍是唯一真实写者。未 live 则不能删 hook API,也不能关闭 `DOC-RELIABILITY-PILOT`。
## 成功标准
- 按消费者独立:shadow coverage → drain → 原子 live;E2 守卫使对应闭包停写。
- 授权页刷新/重启正文与 head digest 一致;未授权不泄露。
- 回滚开关保留一个发布窗口后再删 `OnOutbox` / `AddOnApprovedHook`。
- FAV 保持 disabled;项目 143 只读。
## 依赖
- E0A–E2 已合入;隔离库报告已归档。
- 需要明确授权:动共享 `agent-dev` 消费者 mode。
## 暂不启动原因
已完成共享 live 与生产去注册。方法本体保留一个窗口。
## 相关链接
- [Track E 复盘](../research/2026-09-15-track-e-retrospective.md)
- [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
- [gap-matrix DOC-RELIABILITY-PILOT](../../remediation/gap-matrix.md)
@@ -0,0 +1,39 @@
---
title: "D7a intent 与 bizdev 解绑"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/intent-bizdev-boundary
worktree: "-"
mutex: intent
---
# D7a intent 与 bizdev 解绑
## 目标
intent 只依赖成熟度词汇叶子包,不再 import bizdev。
## 范围
- `internal/maturity`
- intent 生产与表征测试
- bizdev 类型别名保持兼容
## 非目标
- 不改识别规则
- 不迁 coordinator / chatflow(D5/D7b)
## 步骤
1. [x] 叶子包与别名
2. [x] intent 切断 bizdev
3. [x] 表征测试与 arch-check
4. [x] 报告
## 验收标准
- [x] intent 生产 import 无 bizdev
- [x] [S4a 报告](../../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md)
@@ -0,0 +1,50 @@
---
title: "清点旁支并收口已合入本地分支"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: chore/leftover-branch-cleanup
worktree: "-"
mutex: ops
---
# 清点旁支并收口已合入本地分支
## 目标
删除 tip 已是 `dev` 祖先的本地旁支与对应 worktree;不整支合入会回归或触红线的 5 条未合并分支;主仓跑一次 short 冒烟。
## 范围
- 拆 7 个已合入 worktree
- `git branch -d` 已 `--merged` 旁支
- CURRENT 记录故意保留的 FAV / herdr-removal / diagnosis / data-root / `dev-old-linear`
- vet / short / arch-check / health+ready
## 非目标
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不合入 `feature/remove-herdr-agent-settings`(会回归 U12 arch-check、删 Herdr 脚本)
- 不合入 `fix/project143-controlled-content-404-diagnosis`(会回退审计关闭结果)
- 不合入 `fix/dev-runtime-data-root-guard`、`dev-old-linear`
- 不 push;不删 `origin/*`;不从 worktree 起 docker;不碰项目 143
## 步骤
1. [x] 占 CURRENT 集成槽
2. [x] 拆已合入 worktree
3. [x] 删除已 merged 本地旁支
4. [x] 冒烟并写报告
5. [x] 槽位 idle + archive
## 验收标准
- [x] 已合入旁支 worktree 只剩 FAV 错名目录
- [x] `--merged dev` 旁支已删(31 条)
- [x] 5 条未合入分支仍在
- [x] 测试报告 + health/ready schema 38
## 相关链接
- Test report: [../../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md](../../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md)
@@ -0,0 +1,57 @@
---
title: "审阅并修订模块解耦 Phase 2 方案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Codex
branch: docs/module-decoupling-ipc-assessment
worktree: "-"
mutex: architecture-docs
---
# 审阅并修订模块解耦 Phase 2 方案
## 目标
以当前代码、migration、ADR 和 Phase 1 计划为证据,修正调研与 Phase 2 方案,并补齐高并发、互斥、权限、历史数据、灰度和回滚设计;不实施业务代码。
## 范围
- 复核调研报告与原 Phase 2 方案的事实、依赖和完成边界。
- 将事件可靠性、结构解耦、HTTP/PI 协议拆成独立轨道。
- 补充 PG 状态机、fencing、幂等、顺序、连接预算、权限、replay、脱敏、迁移和 browser/restart 验收。
- 同步 audit、remediation、CURRENT、FEATURE-MATRIX 与 gap-matrix。
## 非目标
- 不实现 dispatcher、consumer、migration 或协议代码。
- 不合并、部署、重启容器、删除数据或审计/合入 FAV 分支。
- 不把文档完成写成系统能力完成。
## 步骤
1. [x] 完成仓库启动链和上位 ADR/Phase 1 证据复核。
2. [x] 完成一致性、可行性、范围、安全、产品与对抗视角审阅。
3. [x] 修正调研报告中的 PG、依赖方向、allowlist 与进程边界事实。
4. [x] 重写 Phase 2 为 Track E/S/P,补齐详细实施和停走门。
5. [x] 同步索引与状态 SSOT。
6. [x] 执行文档链接、diff、冲突标记和术语检查。
## 验收标准
- [x] 调研不再把 SELECT-only Claim、MemoryBus 测试或 allowlist 基线写成生产闭环。
- [x] Track E 可独立关闭,FAV/D8/D9 不阻塞。
- [x] 方案明确 at-least-once 与 exactly-one visible outcome、最终提交点 fencing、集群级切换和授权模型。
- [x] 历史脏数据只分类/隔离/修复,不授权删除。
- [x] 文档状态一致且没有实施或发布声明。
## 相关链接
- Audit: [方案审阅](../../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- Remediation: [Phase 2 修订计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Research: [IPC/RPC 现状评估](../../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
- Test report: 不适用(文档审阅,无业务实现)
## 证据 / 备注
本任务沿用用户已创建的 `docs/module-decoupling-ipc-assessment` 分支。该分支名早于当前 `feature/*|fix/*` 规则;未改写或重命名用户分支。起点提交为 `a3392e3` 与 `5cef856`,本轮未获授权 commit/push。
@@ -0,0 +1,47 @@
---
title: "PI typed-result-v1 P1–P4"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/pi-typed-result
worktree: "-"
mutex: pi-agent
---
# PI typed-result-v1 P1–P4
## 目标
Runner additive 输出 `result_v1`;Go typed-first fail-closed;共享 dev 真实 PI 双轨对账;去掉 stderr/legacy 明文错误。
## 范围
- `configs/schemas/pi-run-result-v1.json`
- `deploy/pi-agent/result-v1.mjs` + runner 接线
- `internal/agent` parser / 负例 / `RUN_PI_E2E=1` 双轨
## 非目标
- 不把 member 正文搬进 `result_v1`(仍走 `patches[]`)
- 不改 HTTP 状态码;不启用 FAV;不写项目 143
## 步骤
1. [x] Schema + Runner additive
2. [x] Go typed-first + handshake
3. [x] 真实 PI 双轨
4. [x] 删 stderr/隐式 legacy;报告与合入
## 验收标准
- [x] typed-present-invalid 永不 fallback
- [x] handshake downgrade 负例 PASS
- [x] `RUN_PI_E2E=1` 成功/失败/取消/超时对账
- [x] test-report 归档
## 相关链接
- Test report: `.doc/test-reports/2026-09-15-pi-typed-result-v1-test-report.md`
- Remediation: `.doc/remediation/2026-09-15-pi-typed-result-v1-remediation.md`
- P0: `.doc/ops/research/2026-09-15-pi-typed-result-p0-matrix.md`
@@ -0,0 +1,45 @@
---
title: "晋升 dev → test 并部署测试环境"
status: in_progress
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/promote-dev-to-test-2026-09-15
worktree: "-"
mutex: infra
---
# 晋升 dev → test 并部署测试环境
## 目标
把已完成的 Phase 2 代码从本地 `dev` 合入 `test`,重建并冒烟测试环境,供人工实测。不实施多意图 HITL。
## 范围
- `test` 分支 `--no-ff` 合入当前 `dev`
- `./scripts/env-service.sh test rebuild`
- test 库 notify/workflow_advance/projection 切 live(L4 去 hook 后 off 会停写);FAV 保持 off
## 非目标
- 不实施多意图 HITL U1+
- 不合入 `main`、不启用 FAV
- 不写项目 143
## 步骤
1. [x] 确认 Phase 2 已在本地 `dev`
2. [ ] occupy 集成槽并合入 `test`
3. [ ] rebuild 测试服务
4. [ ] health/ready + schema 冒烟
## 验收标准
- [ ] `:8081` health/ready PASS
- [ ] events `:8089` health PASS
- [ ] FAV 仍 off
## 相关链接
- CURRENT: `.doc/ops/CURRENT.md`
@@ -0,0 +1,40 @@
---
title: "D5 stageflow 类型归属与 D7b chatflow 首批"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/stageflow-type-ownership
worktree: "-"
mutex: stageflow
---
# D5 stageflow 类型归属与 D7b chatflow 首批
## 目标
coordinator 生产代码不再 import bizdev;task/stage 请求走 stageflow 类型;chatflow assembler 改用 maturity。
## 范围
- stageflow 类型别名与状态常量
- coordinator 构造改为 StageTaskRunner + ContextServices
- chatflow 去掉 bizdev import
## 非目标
- 不复制行为方法成 DTO(身份别名 + token golden)
- 不删除 bizdev 八个 getter(D4)
- 不搬空 chat 包
## 步骤
1. [x] 类型边界与 coordinator 解绑
2. [x] chatflow assembler
3. [x] 表征测试与 arch-check
4. [x] 报告
## 验收标准
- [x] coordinator 生产 import 无 bizdev
- [x] [S2/S4b 报告](../../test-reports/2026-09-15-stageflow-type-ownership-test-report.md)
@@ -0,0 +1,60 @@
---
title: "M3 U8 TaskRun 终态与 RunManifest"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/taskrun-runmanifest
worktree: "-"
mutex: taskrun
---
# M3 U8 TaskRun 终态与 RunManifest
## 目标
TaskRun 终态在同一 UoW 内 CAS 写入唯一合法状态,并持久化类型化 RunManifest;重复 finalize / cancel race / SSE 断线不得产生第二条助手消息或第二份 artifact;workspace 清理仅在 verified receipt 之后。
## 范围
- Goose 00037 `task_run_manifests` + `finalizing` 状态
- `internal/taskrun` RunManifest 规范字节 / SHA / members
- `taskrun.Commands.Finalize` 唯一 finalize 命令;server 变薄
- `ctxmgr.FinalizeAssistantTaskMessage` 仅此写路径加入 UoW
- workspace 清理门禁;`ReadArtifact` 替代 `Join(workDir, "output.md")`
- BackendRef 服务端 policy;隔离库并发测试;占槽 rebuild;U8 报告
## 非目标
- U9 backfill / corpus / 八轨 / 销毁
- M4–M6;整支 merge FAV;启用 `FAV_DEGRADED_READ`
- 终止或改写项目 143
- 动 `chat` / `intent` 刷新任务
- worktree 内 `env-service`
## 步骤
1. [x] CURRENT 认领 `mutex=taskrun`;从本地 `dev` 开 `feature/taskrun-runmanifest`
2. [x] Goose 00037 Up+Down;`module-boundaries.yaml` 表属主
3. [x] Finalize 同 UoW:CAS + 助手 turn + manifest + envelope/staging
4. [x] 清理门禁与 server 去路径、BackendRef
5. [x] 隔离库双 pool / race;占槽 rebuild;报告最后一句只能「继续 U9」或「停止扩面」
## 验收标准
- [x] 重复 finalize:同一 status、同一 manifest SHA、助手消息 1 条、envelope/staging 不加倍
- [x] finalize ∥ cancel:恰好一个合法终态
- [x] SSE `done` 不出现在 TX 失败路径;commit 前断线重试不第二 turn
- [x] 无 verified receipt 则 cleanup FAIL;有 receipt 则可清 workspace 且 staging 仍能取出原 SHA
- [x] 报告最后一句为「继续 U9」或「停止扩面」;U9 清单项保持未勾
## 相关链接
- Checklist: [2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Remediation: [2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- 权威停走门: [2026-09-14-document-reliability-m2-test-report.md](../../test-reports/2026-09-14-document-reliability-m2-test-report.md)(继续 M3)
- Test report: [2026-09-15-taskrun-runmanifest-u8-test-report.md](../../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md)
## 证据 / 备注
未签字前禁止 U9–U12。合入 + 容器测占集成槽,主仓 `./scripts/env-service.sh dev rebuild`。
@@ -0,0 +1,31 @@
---
title: "Track P 协议实施(信封与 typed-result)"
status: done
created: 2026-09-15
updated: 2026-09-15
---
# Track P 协议实施(信封与 typed-result)
## 动机
H0/P0 盘点后独立实施 HTTP 信封与 PI typed-result,不回退事件 live。
## 成功标准
已关闭:
- [HTTP 信封 H1–H3](../../test-reports/2026-09-15-http-error-envelope-h1-h3-test-report.md)
- [PI typed-result P1–P4](../../test-reports/2026-09-15-pi-typed-result-v1-test-report.md)
## 依赖
mutex `server`/`web`/`pi-agent` 已释放。
## 暂不启动原因
已完成。
## 相关链接
- [Phase 2 计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
@@ -1,9 +1,9 @@
---
title: "对话刷新恢复整改 Checklist"
status: in_progress
status: done
created: 2026-09-13
updated: 2026-09-13
related_task: "../short-term/2026-09-13-chat-history-refresh-remediation.md"
updated: 2026-09-15
related_task: "../2026-09-13-chat-history-refresh-remediation.md"
---
# 对话刷新恢复整改 Checklist
@@ -36,10 +36,10 @@ related_task: "../short-term/2026-09-13-chat-history-refresh-remediation.md"
## Wave 5 — 验收
- [x] `go test -short ./...` — 证据:本机执行输出
- [ ] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:待 test-report 补录
- [x] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`(项目 6252 闲聊刷新同集 + guest 403;编制任务链未通过)
- [x] 测试报告归档 — 证据:`.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md`
## 完成定义
- [ ] 全部勾选且有证据链接
- [ ] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
- [x] 全部勾选且有证据链接
- [x] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
@@ -0,0 +1,47 @@
---
title: "发布门禁闭环 → production_ready"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: docs/production-ready-flip
worktree: "-"
mutex: ci
---
# 发布门禁闭环 → production_ready
## 目标
按 gap-matrix 发布门禁勾选 B1–B4,对齐环境 schema 后翻 `production_ready=yes`。
## 范围
- B1 CI TEST_DATABASE_URL + 治理 PG(已完成)
- B2 真实 PI 三工作流 E2E(已完成)
- B3 对话全链路恢复(已完成)
- B4 版本冲突/终止 preview(已完成)
- B5 SSOT 翻旗 + main schema 对齐(已完成)
## 非目标
- 多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
## 步骤
1. [x] B1 BUG-08
2. [x] B2 PI E2E
3. [x] B3 chat refresh + restart
4. [x] B4 conflict + termination-preview + envelope unwrap
5. [x] B5 merge/smoke、main rebuild 迁库、翻旗
## 验收标准
- [x] gap 门禁四框可勾(含对话与前端)
- [x] FEATURE-MATRIX / gap / CURRENT `production_ready: yes`
- [x] main/dev/test health schema_version=47
## 相关链接
- Test reports: `2026-09-16-ci-governance-pg-bug08`、`pi-three-workflow-e2e`、`chat-refresh-gate`、`frontend-gate-b4`
- gap-matrix / FEATURE-MATRIX / CURRENT
@@ -76,7 +76,7 @@ severity: high
## 关联整改
- Remediation: [../remediation/2026-09-13-chat-history-refresh-remediation.md](../remediation/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
- Gap matrix: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
## 证据
@@ -0,0 +1,64 @@
---
title: "arch-check U1 可重放基线"
status: done
created: 2026-09-14
updated: 2026-09-14
severity: medium
---
# arch-check U1 可重放基线
## 现象
Wave 0 的全仓 grep 会把 Goose、`*_test.go` 和路径字面量一视同仁,无法作为生产写者门禁。U1 用 `go list` + AST/正则拆成四类规则,并给每条既有债写明 owner、原因、截止里程碑和到期日。
## 根因分析
- `document_records` 的生产写者不止 `docgov`:`docrevision.projectRootPointersTX` 与 `docduty` 职责槽位仍直接 `UPDATE`。
- `output.md` / `data/dev` / `workspaces/` 仍被 agent、bizdev、coordinator、docgov、docrevision、server、storage 用 `filepath.Join`、字符串字面量或间接常量构造。
- Goose 与测试夹具大量出现同样表名,不能算生产写者债。
## 严重度
`medium`
## 关联整改
- ADR: [../adr/2026-09-14-modular-monolith-decoupling.md](../adr/2026-09-14-modular-monolith-decoupling.md)
- 设计: [../system-design/2026-09-14-module-decoupling-architecture.md](../system-design/2026-09-14-module-decoupling-architecture.md)
- 边界: [../system-design/module-boundaries.yaml](../system-design/module-boundaries.yaml)
- 任务: [../ops/short-term/2026-09-14-document-reliability-pilot.md](../ops/short-term/2026-09-14-document-reliability-pilot.md)
## 证据
命令(2026-09-14,`refactor/document-reliability-pilot` worktree):
```
./scripts/arch-check.sh --mode warn
go test ./internal/archtest -count=1
```
可重放计数(只含生产 Go;Goose/`*_test.go` 不计):
| 规则 | 计数 | 处理 |
|------|------|------|
| import | 0 | 相对 2026-09-14 production `go list` allowlist,无新边 |
| sql_write | 5 | 例外,U3/U8 到期 |
| path | 17 | 例外,U4/U5/U8 到期 |
| event | 0 | `OnOutbox` 生产者属主为 docrevision,server/notification 为消费者 |
验证:
- `deploy/postgres/goose` 与 `*_test.go` 出现 `document_records` 不报生产写者违规。
- 迷你仓 `internal/server/rogue_write.go` 新增 `UPDATE document_records` 时 `go test ./internal/archtest` 失败并指出文件。
- `filepath.Join`、字符串拼接、间接常量构造 `output.md` 均可检出。
- 无到期日例外、过期例外立即 block。
- `baseline_counts` 锁定现有计数,只能下降。
`--mode block` 在例外清零前会失败,不得挂进集成冒烟。
## 开放问题
- U3 收口 `document_records` / `freeform_documents` 跨属主写。
- U4/U5 收口 handler 与投影路径构造。
- U8 收口 `task_runs` 终止写与 finalize `output.md`。
@@ -0,0 +1,98 @@
---
title: "模块解耦方案复核"
status: done
created: 2026-09-14
updated: 2026-09-14
scope: architecture, transactions, concurrency, authorization, events, artifact recovery
---
# 模块解耦方案复核
## 结论
模块化单体、单一写者、瘦传输层和应用编排层的方向成立,但原方案不能直接批准 Wave 1–6。
原方案把事务、事件、工作区和最终成果四条边界拆开设计,可能在包依赖减少后产生新的数据不一致、跨租户授权旁路和不可恢复投影。
整改应先打通一条真实文档纵向链路,再按证据决定是否扩展到 chat、squad、SSE 和 PI Runner。
## 已确认问题
### A1. 单一写者拆分会破坏跨表原子性
`internal/docrevision/pg_mutate.go` 当前在一个事务中写版本账本并投影 `document_records` 根指针。
原方案要求 docrevision 改调 docgov/freedoc 普通端口,却没有定义跨属主事务或命令所有权。
如果各端口各自提交,会出现版本账本、正文 head、治理状态和 outbox 部分成功。
### A2. 现有 outbox 不是可泛化的可靠事件总线
`internal/docrevision/service.go` 在版本事务完成后调用 `OnOutbox`,并忽略回调错误。
`outbox_events` 只有全局 `published_at`,没有逐消费者确认、租约、重试、死信和幂等收件箱。
拟议的 `Publish(ctx, event)` 也没有事务作用域,不能兑现“与业务同事务”。
### A3. 工作区仍被当成事实源
原 `WorkspaceRef` 暴露 `Root`、`OutputDir` 和 `ManifestPath`,`OutputContract` 继续接受裸路径。
这不能从类型上阻止路径拼接、跨工作区访问或链接逃逸。
docquery 若继续在运行时从 `output.md` 选择正文,会保留导致历史 404/409 的 split-brain 根因。
### A4. 最终成果保险库未进入模块边界
`feature/final-artifact-vault` 已设计并实现终态归档、只读降级和 scratch 恢复,但尚未合入当前 dev 基线。
原解耦方案没有为 artifactvault 分配端口、事件、授权和恢复边界,后续容易由 docquery 或 CLI 重建旁路。
### A5. contracts 可能成为新的高扇入万能包
原方案把内部接口、HTTP DTO、事件、错误码和共享枚举集中到一个包,并要求所有 DTO 版本化。
这会把语义耦合搬到 `contracts` 和 `app`,使普通内部调整承担不必要的 ADR 成本。
### A6. 并发控制只覆盖了进程内互斥
当前代码同时存在 `sync.Mutex`、行锁、乐观 ETag、唯一幂等键和 `pg_advisory_xact_lock`。
原方案没有规定哪些锁用于正确性、锁顺序、超时、重试边界和多副本行为。
进程内锁只能优化单实例竞争,不能作为跨实例正确性条件。
### A7. 授权主体和后台执行边界缺失
“在应用层入口统一授权”没有定义可信 Principal 的来源,也没有覆盖 CLI、事件订阅者、恢复工具和后台任务。
若端口继续接受调用方填写的 `UserID`、`ProjectID` 或裸 `DocRef`,可能形成 confused-deputy 或跨项目访问。
### A8. 横向 Wave 缺少最小可交付边界
原方案先物理搬包,再接口化,最后才处理单写者和事件语义。
这会重复修改高扇出代码,并在真正验证边界之前冻结大量无消费者契约。
错误信封和 PI Runner 协议与文档一致性解耦没有直接依赖,不应阻塞核心路线。
### A9. 迁移与回滚承诺不成立
可靠多消费者 outbox、FAV 集成和必要的状态字段需要增量 migration,因此“数据零迁移”不成立。
后续里程碑会依赖前序契约,不能任意独立 revert;只能按 expand/migrate/contract 阶段和兼容窗口回退。
### A10. 架构检查范围会产生误报
表名和路径字面量合法存在于 Goose migration、fixture、测试和运维脚本。
R5/R6 应检查生产运行时的越权写入和路径解析,不应以全仓 grep 的零出现作为完成条件。
## 外部规则核对
- PostgreSQL 行锁和事务级 advisory lock 会在事务结束时释放,适合短期业务互斥;session 级 advisory lock 不跟随回滚,不用于本方案的业务锁。[PostgreSQL explicit locking](https://www.postgresql.org/docs/17/explicit-locking.html)
- `SKIP LOCKED` 适合多消费者队列表,不适合作为普通一致性查询语义。[PostgreSQL SELECT](https://www.postgresql.org/docs/current/sql-select.html)
- Serializable 或 deadlock 重试必须重跑完整事务,包括决定 SQL 和参数的业务逻辑。[PostgreSQL serialization failure handling](https://www.postgresql.org/docs/16/mvcc-serialization-failure-handling.html)
- 授权必须默认拒绝,并在每次请求或后台动作上重新校验,不能信任客户端传入的身份和资源归属。[OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)
## 整改结论
1. 暂停批准原 Wave 1–6,保留只读架构基线。
2. 先定义事务、锁、授权、事件和持久成果契约。
3. 首个交付只覆盖受控文档读取与终态提交纵向链。
4. FAV、迁移语料和完整备份作为三个互补层接入。
5. 通过真实页面刷新、重启、并发、权限和恢复停走门后,再批准其他模块拆分。
## 证据入口
- `internal/docrevision/pg_mutate.go`
- `internal/docrevision/service.go`
- `internal/workspace/resolver.go`
- `internal/docduty/revoke.go`
- `internal/taskrun/manager.go`
- `deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql`
- `.doc/adr/2026-09-13-document-version-boundary.md`
- `feature/final-artifact-vault` 分支中的 FAV ADR、整改方案与测试报告
@@ -0,0 +1,56 @@
---
title: "planning 项目残留 active_workflow_key 异态审计"
status: done
created: 2026-09-14
updated: 2026-09-14
severity: low
---
# planning 项目残留 active_workflow_key 异态审计
## 现象
dev 库存在 `lifecycle_status='planning' AND active_workflow_key <> ''` 行。评审时记为 81;本轮只读复测为 **83**(相对评审 +2)。这些行看起来像「已选工作流但未走设置激活」。
## 根因分析
关闭 `initial_workflow_key` 直通前,`CreateProject` 在键非空时会写 `lifecycle=active` + `ActiveWorkflowKey`。本异态是 **planning 却带 key**,更符合自动化测试夹具成对插入(`PROJ_MGR_*` / `TEST_PROJ_*`),而不是真实用户走创建旁路后的 active 项目。
本轮 **未** `UPDATE`/`DELETE`。
## 严重度
`low`
创建旁路已在 `fix/governance-action-level-authz` 关闭。存量 83 行全部无 live 实例、无创建人,不影响项目 143,也不阻塞 G1 鉴权矩阵。
## 关联整改
- Short-term: [2026-09-14-governance-action-level-authz](../archive/ops/2026-09-14-governance-action-level-authz.md)
- Research: [2026-09-14-mvp-governance-rules-review](../ops/research/2026-09-14-mvp-governance-rules-review.md)
## 证据
只读查询(`shuimu-context-pg-dev` / `agent_system_dev`,2026-09-14):
| 指标 | 数量 |
|------|------|
| `lifecycle=active` | 141 |
| `lifecycle=planning` | 209 |
| `planning AND active_workflow_key <> ''` | **83** |
分类(禁止改库,仅标注):
| 分类 | 数量 | 判定 |
|------|------|------|
| 测试夹具 | **83** | `code` 为 `PROJ_MGR_YYYYMMDDHHMMSS`(名「智能微创内窥镜」)或 `TEST_PROJ_*`(名「测试内窥镜系统」);`active_workflow_key=main`;`workflow_selection_version=1`;`creator_user_id` 空;`has_live_instance=false`;时间戳成对出现于 2026-09-12~09-14 |
| 历史直通(真实用户创建旁路) | **0** | 无非夹具命名、无创建人、无 live 实例的业务项目 |
| 不明 | **0** | — |
样本 id(完整 83 行均属上表夹具模式,不逐条展开):61–62、122–128、6015–6021、6160–6161、6192/6195。项目 **143 不在此集合**。
相对评审 81 的 +2:`6192` / `6195`,创建于 2026-09-14 07:26 UTC,仍是同一对夹具命名。
## 开放问题
- 是否在后续专项清理夹具行(需单独任务与备份,不在本治理鉴权波次)。
@@ -0,0 +1,104 @@
---
title: "workflow-plan 409 冻结冲突(项目 143)与三权设置粒度调整需求"
status: done
created: 2026-09-14
updated: 2026-09-14
severity: medium
---
# workflow-plan 409 冻结冲突(项目 143)与三权设置粒度调整需求
## 现象
用户在项目设置(`ProjectSettingsModal`)中把项目内所有文档任务的编制/审核/批准指派为「系统管理员 / 李审核 / 王总监」,点击「校验并预览」无反应。控制台报错:
```text
projectSettings.ts:51 PUT https://frp-mix.com:58880/api/v1/projects/143/workflow-plan 409 (Conflict)
```
同时用户提出新需求:**三权设置粒度按文档控制**——对某个允许省略人工审批的文档,一旦设置职责,必须三个职责(编制/审核/批准)都指派负责人;三个职责都未设置时,该文档仍可生成和进入版本账本,但不进入人工审批及阶段批准门禁。它不是“非受控文档”;若不需要生成该文档,应关闭文档任务。
## 根因分析
### 409 的直接原因:项目 143 已激活工作流,规划已冻结(PLAN_FROZEN)
dev 库(`shuimu-context-pg-dev` / `agent_system_dev`)实测:
```text
id | name | lifecycle_status | active_workflow_key | workflow_selection_version | workflow_plan_revision
-----+------+------------------+---------------------+----------------------------+------------------------
143 | 测试 | active | main | 2 | 1
id | project_id | status | config_revision | has_hash | created_at
----+------------+--------+-----------------+----------+-------------------------------
89 | 143 | active | 1 | t | 2026-09-13 01:31:33.212283+00
```
项目 143 于 2026-09-13 已激活 `main` 工作流(实例 89,status=active)。后端保存链路:
- `internal/projectinstance/service.go:131-133`(`SaveWorkflowPlan`):`if lifecycle != LifecyclePlanning { return nil, ErrPlanFrozen }`,冲突检查发生在最前;
- `internal/server/project_settings_handlers.go:164-165`:`ErrPlanFrozen` → HTTP 409 `{"error":"PLAN_FROZEN","message":"工作流已激活,规划已冻结"}`。
前端未能把该语义展示出来,构成「点击无反应」的体验:
- `web/src/api/projectSettings.ts:60-63`:非 2xx 直接抛出普通 `Error`。`parseError`(`projectSettings.ts:200-213`)其实已经能取到后端 `message`,所以“工作流已激活,规划已冻结”并未丢失;真正缺口是错误对象不保留 HTTP status/code/issues,UI 无法按 `PLAN_FROZEN`、版本冲突等类型切换冻结态或执行定向恢复;
- `web/src/components/project/ProjectSettingsModal.tsx:161-162`:catch 后写入 `error` state。弹窗在 `configure` 步骤的「校验并预览」按钮(538-557 行)点击后仅更新顶部 error 区(276-293 行),视口停留在长表单底部时用户看不到顶部横幅,感知即「无反应」。
### 前端缺少冻结态守卫
`ProjectSettingsModal.tsx` 的 `loadSettings`(53-81 行)只要 `s.plan` 存在就 `setStep('configure')`,`handleSelectWorkflow` / `handleSavePlan`(91-166 行)均未检查 `settings.lifecycle_status !== 'planning'` 或 `can_edit_plan === false`。后端 `GetSettings` 已正确返回 `can_edit_plan=false`(`internal/projectinstance/service.go:59-60,78-79`),前端没用它。因此已激活项目仍可一路走到保存,必然撞 409。
### 现行三权校验为「逐文档三职全必填」
- 后端 `internal/projectinstance/validator.go:93-95`:`dt.Enabled` 即调用 `validateDuties`;`validateDuties`(143-179 行)对启用的文档强制 `DUTY_AUTHOR/REVIEWER/APPROVER_REQUIRED` + 互斥校验;
- 前端 `ProjectSettingsModal.tsx:130-145`:成员数 <3 直接拦截;每个启用文档三职任一未指派即报错。
即当前不存在「整文档留空」的合法表达,与用户新需求冲突。门禁侧 `internal/projectinstance/gate.go:23-51` 对 `enabled` 的文档按工作流定义的 `BlocksWhenEnabled()` 计入阶段就绪——若允许留空却不改门禁,阻断型文档会产生永久死锁。因此**留空语义必须同步改门禁,但不能反过来让项目配置绕过工作流定义中不可省略的必需/阻断文档**。
## 方案复核发现的补充风险
1. **必需文档可被绕过**:若简单采用“全空即 `required=false`”,创建者可把定义中 `required/blocking` 且不可关闭的文档职责清空,从而绕过正式工作流门禁。全空只应允许用于工作流定义允许创建者裁剪的非必需文档;必需/阻断文档仍必须三职全满。
2. **零治理工作流**:原方案允许“全部启用文档全空后激活”。这超出“部分文档不设置”的需求,并会产生没有任何审核责任人的 active 工作流。保存草稿可以暂时全空,但激活时必须至少有一份三职完整的受治理文档。
3. **成员有效性未由后端保证**:现有 `validateDuties` 只检查 ID 为正且互异;`document_duty_assignments.user_id` 也只外键到 `users`,没有保证用户属于该项目且仍在任。保存和激活前都必须按服务端成员快照复核。
4. **权限语义缺失**:当前 active 实例中,创建者可操作无职责文档;其他成员的阶段范围会因没有职责而排除该文档。最终方案必须明确:无人工审批文档对有项目访问权的成员可只读可见,创建者可触发生成/编辑,review/approve 始终不可用。
5. **冻结快照可能残留旧 ID**:关闭文档任务或切换为“无需人工审批”时,如果不清空旧职责 ID,冻结 JSON、plan hash 和预览统计仍会携带过期职责。保存前必须服务端规范化,前端也应原子清空三职。
## 严重度
`medium`(既有冻结规则正确,但页面误导用户继续编辑;职责可选属于治理能力扩展,涉及门禁、权限与激活完整性)
## 关联整改
- Remediation: [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- Short-term: [../ops/short-term/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../ops/short-term/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
## 证据
```bash
# dev DB 实测(2026-09-14)
docker exec shuimu-context-pg-dev psql -U app -d agent_system_dev \
-c "SELECT id,name,lifecycle_status,active_workflow_key,workflow_selection_version,workflow_plan_revision FROM projects WHERE id=143;"
docker exec shuimu-context-pg-dev psql -U app -d agent_system_dev \
-c "SELECT id,project_id,status,config_revision FROM project_workflow_instances WHERE project_id=143 ORDER BY id;"
# → lifecycle_status=active / active_workflow_key=main / 实例 89 status=active
# test/main 环境项目 143 不存在(0 rows),现场仅 dev
```
代码引用:
- `internal/projectinstance/service.go:123-180`(SaveWorkflowPlan:冻结/live/选版/乐观锁顺序)
- `internal/projectinstance/store.go:123-134`(BumpPlanRevision 乐观锁)
- `internal/server/project_settings_handlers.go:160-204`(错误码 → HTTP 状态映射)
- `internal/projectinstance/validator.go:9-126,143-179`(validatePlan / validateActivationPlan / validateDuties)
- `internal/projectinstance/gate.go:5-54`(阶段门禁)
- `web/src/components/project/ProjectSettingsModal.tsx:53-81,120-166`(loadSettings / handleSavePlan)
- `web/src/api/projectSettings.ts:45-65,200-213`(saveWorkflowPlan / parseError)
## 审核结论
- 409 根因成立;项目 143 的职责内容合法与否不会改变冻结判定。
- “部分指派”继续明确拒绝;顶层响应为 HTTP 400 `VALIDATION_FAILED`,具体 issue code 为 `DUTY_PARTIAL_ASSIGNMENT`。
- 无职责文档定义为“启用但不纳入人工三权审批”,仍保留生成、正文、版本账本和项目内只读可见性;禁止使用“非受控文档”描述。
- 全空只允许在非必需且允许项目侧裁剪的文档任务上使用;必需/阻断任务仍须三职完整。激活时至少存在一份三职完整文档。
- 项目 143 仅做冻结态只读回归;不得在验收中终止其工作流。若业务上确需改职责,必须先查看终止影响、确认取消运行任务及关闭实例的访问影响,再受控终止并重新规划、激活。
@@ -0,0 +1,85 @@
---
title: "前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: critical
---
# 前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责
## 现象
用户在 **test 环境**(127.0.0.1:8081)新建测试项目「测试项目」(test 库 `projects.id=1`,唯一项目),工作台立即显示 11 份「受控文档」,其中包括与该项目毫无关系的:
- 《4K超高清荧光内窥镜系统立项与可行性报告》
- 《微创外科内窥镜全球竞品技术与临床深度调研报告》
- 神经外科双频超声吸引(NeuroPulse)系列
- CUSA 超声手术吸引系统系列
这些文档:
1. 显示**伪造的生命周期状态**(`reviewing` / `approved`——`DeckDrawer.tsx` 将 `approved` 渲染为「**终审已生效**」),即用户所称「生效区」出现从未经过任何 docgov 生命周期流转的"已生效"文档;
2. 带有**伪造的法定职责人**(author 张工 / reviewer 李主管 / approver 王总监——均非真实用户);
3. 带有伪造版本号(V1.0)、伪造更新时间、伪造正文全文;
4. 在项目成员视角按真实受控文档参与 RBAC 可见性过滤与工作流槽位合并,**与真实服务端文档混排**。
而 test 库 `document_records` 为 **0 行**——服务端受控文档台账完全为空,这 11 份文档**全部来自前端硬编码 mock 数据**。
## 根因分析
### 1. mock 交付物硬编码绑定 projectId 1/2/3/5201/6001–6010
`web/src/App.tsx:267` `INITIAL_DELIVERABLES` 硬编码 7 份 mock 交付物 `projectId: 1`(doc-001~004、doc-shared-001、doc-private-001/002);`P2_INITIAL`(projectId 2)、`CUSA_INITIAL_DELIVERABLES`(projectId 3)、`NEUROPULSE`(5201)、`TEN_PROJECTS`(6001+)同理。`ALL_INITIAL_DELIVERABLES` 聚合后作为 `loadDeliverables()` 的默认值(App.tsx:621),并经 `saveDeliverables` **写入 localStorage 持久化**。
### 2. 项目过滤按数字 ID 匹配,新建项目与 mock 项目 ID 撞车
`App.tsx:1014`:`currentProjectDeliverables = deliverables.filter(doc => doc.projectId === currentProjectId)`。
- test 库为全新库,用户新建的第一个项目得到 `id=1` → 与 mock 的 `projectId: 1` **精确撞车**,7 份幻影文档全部"归属"该项目;
- 新建项目时 `createProjectTemplateDeliverables`(App.tsx:3844)再克隆 7 份模板骨架(`doc-p1-*`,`lifecycleState: 'template'`,合规)→ 7 mock + 4~7 模板/私有,构成用户看到的 11 份;
- **dev 库同样中招**:`agent_system_dev.projects` 存在真实项目 id 1–8(智能微创内窥镜/测试内窥镜系统等),id 1/2/3 的真实项目同样被 mock 文档污染。
### 3. mock 正文与 mock 用户/权限无环境门控,已进生产构建产物
- `mockDocuments.ts` 无任何 `import.meta.env` 门控;`App.tsx` 中 `MOCK_USERS`(含伪造 `projectPermissions: {doc-001: approver...}`)作为 `loadUsers()` 默认值与 `currentUser` 初始身份兜底(App.tsx:610/617);
- **构建产物已验证污染**:`web/dist/assets/index-DogUjae5.js` 中 grep 命中「4K超高清荧光」字符串——dev/test/main 三环境共用同一前端构建,main 生产环境同样受影响。
### 4. 既有防线只挡"正文请求",不挡"清单展示"
团队已知悉 legacy mock ID(`revisionToolbarMount.ts:24 isLegacyLocalMockDocId`:`doc-\d{3}` / `doc-shared-*` / `doc-private-*` / `doc-cusa-*`),并禁止它们发起 content/revision 请求(`controlledDocHydrate.ts:shouldLoadControlledContent` 排除)。但这只防住了「幻影文档冒充服务端正文」,**没有防住幻影文档出现在交付物清单、生命周期徽章(终审已生效)、职责栏与项目文档统计中**——用户看到的正是后者。
### 5. 服务端权威清单未做前端对账
`GET /api/v1/projects/{id}/documents`(`docgov/project_docs.go`,`WHERE project_id=$1 AND task_key<>''`,服务端已正确按项目隔离)返回空数组时,`mergeWorkflowDocumentsFromServer`(`deliverableSync.ts:41`)**直接 `return prev`,不删除本地多余项**——本地幻影文档无任何下架机制。
## 严重度
`critical`:
1. **治理完整性破坏**:空项目展示「终审已生效」受控文档 + 三级法定职责人,在医疗器械合规语境下(ISO 13485 / 21 CFR Part 11 电子记录可靠性)构成"记录失实";
2. **跨环境广泛影响**:dev 真实项目 id 1–8、test 新建项目、main 生产同构建产物全部受影响;
3. **权限视图失真**:伪造职责人/权限映射混入 RBAC 过滤链,用户对"谁可审批什么"产生错误认知;
4. 既有防线(isLegacyLocalMockDocId)证明团队已两次踩坑(本审计为同域第三类症状),说明 mock 数据保留策略系统性不足。
## 关联整改
- Remediation: [2026-09-15-mock-deliverables-pollution-remediation.md](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md)
## 证据
- test 库(`shuimu-system-pg-test`,127.0.0.1:5434):`projects` 仅 id=1「测试项目」(通用医疗器械);`document_records` 0 行;全库 87 张业务表除 projects/users/auth_sessions/chat_sessions/project_workflows 外全部为空
- dev 库(`shuimu-context-pg-dev`,127.0.0.1:5433):真实项目 id 1–8(智能微创内窥镜 / 测试内窥镜系统)→ 与 mock projectId 1/2/3 撞车
- `web/src/App.tsx:267-498`(INITIAL_DELIVERABLES/P2/CUSA/ALL_INITIAL_DELIVERABLES)、`621`(loadDeliverables)、`1014`(projectId 过滤)、`3844`(新建克隆模板)
- `web/src/data/mockDocuments.ts:32-505`(mock 文档全文与伪造 lifecycleState/职责人)、`web/src/data/seeds/neuropulseSeed.json`(projectId 5201)、`tenProjectsSeed.json`(6001–6010)
- `web/dist/assets/index-DogUjae5.js`:grep 命中「4K超高清荧光」(生产构建含 mock 数据)
- `web/src/features/documentRevision/revisionToolbarMount.ts:24-32`(isLegacyLocalMockDocId 既有防线)
- `web/src/lib/deliverableSync.ts:41-45`(serverDocs 空时不回收本地项)
- `web/src/components/doc/DeckDrawer.tsx:87-103`(approved → 「终审已生效」渲染)
- `web/src/api/projectDocuments.ts:46-58`(服务端清单 API,服务端隔离正确)
## 开放问题
- mock 数据的保留意图(demo 演示模式?)需要在整改方案中决策:彻底移除 vs 环境门控(`import.meta.env.MODE` / 构建期注入 `VITE_ENABLE_DEMO_SEEDS`)
- localStorage 中已被 `saveDeliverables` 持久化的 mock 项,需要一次性迁移清理(对齐既有 `dropRecordKeys`/ControlledInvalidationPlan 机制)
- main 环境是否已有真实用户看过幻影文档(`document_access_audit` 为 0 行,无服务端读取痕迹,风险主要在前端展示层)
@@ -0,0 +1,111 @@
---
title: "模块解耦 Phase 2 方案审阅"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: high
---
# 模块解耦 Phase 2 方案审阅
## 结论
模块化单体、消费者端口、组合根和持久事件的方向成立,但原 Phase 2 方案不能直接进入实施。它把事件可靠性、结构整理和两个外部协议绑成一个完成目标,并基于数项不成立的代码事实设计切换门。修订版已把 Track E(持久事件)、Track S(结构解耦)、Track P(外部协议)拆开,Track E 必须先完成生产者与历史数据门,再启动 dispatcher。
## 高优先级发现
### A1. PG delivery 尚未形成生产闭环
`internal/events/pg.go` 的 `ClaimIDs` 只做 SELECT + `FOR UPDATE SKIP LOCKED`,没有在同一事务写 lease owner/token/until;也没有 PG ack/fail/retry/dead-letter 的完整生产实现。`internal/events/dispatcher_test.go` 验证的是 MemoryBus。原方案把这些能力写成“已有”,会低估 D1 的 migration、状态机和故障测试范围。
整改:D1 增加 additive migration、原子 lease、heartbeat、fenced side-effect/ack、retry/dead/quarantine、不可变 attempt 表和独立 `cmd/events` 进程。
### A2. “恰好一次投递”不可由当前算法保证
副作用成功后、ack 前崩溃会导致重放。Fencing 若只拦 ack,也拦不住租约过期的旧 worker 提交副作用。
整改:契约改为 at-least-once delivery + exactly-one visible outcome。Token 进入 consumer command 和最终提交点;数据库副作用与 inbox/token 校验同事务,projection 使用 expected version、digest 和单调 marker。
### A3. 原 shadow 定义会双写,且按天零差异可空跑通过
旧方案同时写闭包和消费者结果,却又称“不产生可见变化”;两者矛盾。三天 dev 流量也可能没有低频文档事件或失败分支。
整改:闭包是 shadow 期间唯一真实写者。消费者只计算 normalized intended outcome 并写 reconciliation。停走门同时要求预登记样本、分支覆盖、最短时间和零未解释 diff;生产入口未证明出事件前不开始计时。
### A4. 文档事件源与作用域尚不可信
部分生产 HTTP 路径临时构造 `docflow.Commands`,没有稳定注入 EventSink/UoW。`Environment:"dev"`、`ProjectID:0` 和 FAV stage project 0 会使跨环境/项目 delivery 失真。
整改:E0A 先由组合根注入唯一命令对象;领域变化、envelope、delivery 同一 UoW;缺 project/env fail closed;旧数据先 inventory。
### A5. AggregateVersion 不能直接当无缺口事件序号
当前只在部分领域转换发事件。历史文档首次事件可能从较高版本开始;按缺号等待会永久阻塞。
整改:D11 在独立 event sequence 与 consumer checkpoint/bootstrap 中二选一,审计现有 aggregate/version 唯一约束并迁移。未决前禁止开启 gap blocking。
### A6. docgov/docrevision 不是双向 import
生产方向为 `docgov → docrevision`,用途集中在 canonical Markdown 与 SHA helper。原方案“提升无行为类型到 vocabulary”不能承载 canonicalization 行为。
整改:D6 改为提取内聚 `doccontent` 行为模块和 golden vectors;D6 可独立执行,不依赖 bizdev/stageflow。
### A7. event allowlist 已存在
`module-boundaries.yaml` 已有 `event_producers`/`event_consumers`。问题是映射稀疏,且运行时注册没有与静态清单做 parity 检查。
整改:D10 提升到 E0A,补 payload schema/version、enabled state 与 registry parity;FAV 标记 disabled。
### A8. FAV、HTTP、PI 不应阻塞核心
FAV 分支未完成独立审计。ADR 已把 HTTP 错误信封和 PI result protocol 定义为独立工作。把三者放入 Track E DoD 会延迟最有价值的刷新恢复闭环。
整改:Track E 只激活 notify、workflow advance、projection。FAV 只预留 disabled 契约;D8/D9 分别另建 remediation。
### A9. Replay、后台权限与日志脱敏不足
延迟事件不能沿用历史用户权限;当前 replay 校验不足以支持生产 apply。Raw payload/error 进入 dead-letter 或 reconciliation 会泄露正文、路径或凭证。
整改:每 consumer 独立 service principal,处理时重读资源和当前权限。Replay 采用 capability + 精确范围 + dry-run digest/apply exact digest + 审计;多项目/批量 apply 两人批准。日志只存 ID/digest/typed code/sanitized summary。
### A10. 滚动切换缺少集群级权威写者
删除新版本 hook 不会阻止旧实例继续执行。若 dispatcher 同时 live,滚动部署会双写。
整改:`off|shadow|live` 使用带 revision 的集群级状态;先部署兼容代码、drain 全部旧实例、记录 backlog 水位,再原子切换。回滚先暂停 claim并核对 receipt/backlog。
### A11. Locator 门禁原文过宽
全局禁止 `*pgxpool.Pool`/`pgx.Tx` 会拦截组合根注入与登记表属主的合法 UoW unwrap。
整改:只禁止领域/用例 API 暴露、返回、转发 pool/tx;明确允许 app/cmd 构造注入和登记属主 unwrap。
## 范围修订
| 轨道 | 内容 | 关闭条件 |
|---|---|---|
| Track E | D1/D2/D3/D10/D11 | PG + browser + restart + auth/replay 证据完成后独立关闭 |
| Track S | D4/D5/D6/D7a/D7b | 各单元独立 go/no-go 与报告 |
| Track P | HTTP error、PI typed result | 各自独立 remediation,不阻塞 Track E/S |
## 关联整改
- [修订后的 Phase 2 计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- [修订后的现状调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
## 审阅方法与证据
- 代码证据:`internal/events/pg.go`、`bus.go`、`dispatcher_test.go`、`replay.go`、`internal/app/docflow/commands.go`、`internal/docgov/lease.go`、`internal/bizdev/service.go`。
- Schema:`deploy/postgres/goose/00035_2026-09-14-durable-event-delivery.sql`。
- 边界:`.doc/system-design/module-boundaries.yaml`。
- 上位决策:模块化单体 ADR 与 Phase 1 U6。
- 审阅视角:一致性、可行性、范围、安全、产品价值、对抗失败预演;外部 reviewer 的有效结论仅用于交叉验证,不替代仓库证据。
## 开放问题
以下问题必须由 E0A 的代码/数据审计回答,不能在计划阶段猜测:
- projection consumer 的最终 owner 与 no-replace 提交接口。
- event sequence 或 checkpoint/bootstrap 的选择及迁移成本。
- 每类事件前 7 天基线流量、shadow 样本 N 和 worker 连接预算。
- 现存错误 scope/schema delivery 的数量和 repair/quarantine/expire 分类。
@@ -0,0 +1,122 @@
---
title: "多意图与 HITL 方案复核"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: high
---
# 多意图与 HITL 方案复核
## 结论
提案方向合理,且可复用现有 IntentFrameV2、ActionRegistry、PendingExpectation、交互卡和可靠事件骨架。但初稿不能直接实施:它会让 LLM backend 进入 `internal/intent`、把跨模块执行继续堆入 coordinator,并以不足以抵御多实例竞态的 PlanID+StepID 代替状态机和动作幂等,存在解耦回退、越权和双执行风险。
已按审阅结果重写[系统设计](../system-design/2026-09-15-multi-intent-hitl-plan.md)与[任务总览](../ops/short-term/2026-09-15-multi-intent-hitl.md)。本次仅修改文档,没有实施业务代码。
## 已确认问题
### P1:原 LLM 接线破坏 intent 纯模块边界
初稿要求在 `internal/intent/segmenter.go` 经既有 `agent.Backend` 分段;当前边界只允许 `intent -> maturity`。照此实施必然新增 intent 到 agent/coordinator 的依赖。
**整改:** 规则分段留在 intent;可选 LLM 仅作为 `app/intentflow` 外围 adapter,返回不可信分段建议,每段重新走确定性识别、安全扫描和 ActionRegistry。任何阶段都禁止 intent import agent、PG、storage 或 coordinator。
### P1:计划持久化缺少权威状态机与并发协议
初稿两表只有宽泛 status/payload,PlanID+StepID 只是标识,不能防重复确认、确认/取消/过期竞态、两个 worker 同时执行,也不能处理业务成功而步骤 receipt 未落库的崩溃窗口。
**整改:** 增加 plan revision/digest、append-only decisions、expected revision、decision nonce、步骤 CAS、lease/fencing、动作级幂等 receipt 和恢复对账。PG 是唯一权威;UserProjectContext/消息只保存 plan 引用。
### P1:确认未与当前授权绑定
持久化 user/role 或用户曾经确认都不能证明执行时仍有权。原稿没有要求恢复、读取和每步执行重新检查当前项目成员、duty、资源生命周期与版本。
**整改:** 确认只记录意愿;所有读取/决策验证 user/session/project 四元作用域;每步由动作 owner 按当前 principal 和 expected resource version 重新授权。失败 fail closed,不以系统身份代执行。
### P1:执行器方案会让 coordinator 再次成为 service locator
初稿拟扩展 `coordinator/action_planner.go` 的分发表来执行写动作,会把 docgov/taskrun/workflow 等具体实现重新聚集到 coordinator,抵消已完成的 chatflow/stageflow/bizdev 解耦。
**整改:** 新增深模块 `internal/app/intentflow` 作为计划生命周期 owner,通过消费者拥有的窄端口调用动作属主;coordinator/chat 仅保留兼容入口,组合根唯一装配。
### P1:事件与 SSE 被混为一条通道
现有 Track E 只处理注册的 PG 事件,不会自动把任意 delivery 变成 SSE。若只发 SSE,刷新丢失;若只写 outbox,浏览器不会自动得到状态。
**整改:** 计划状态同步落库;outbox 只发布版本化状态事实并驱动消息/read model 投影;SSE 是提交后的提示。刷新总是 GET PlanView。事件先登记 YAML、StaticContracts 和 payload allowlist。
### P1:不确定分段会退回单意图执行
“置信下降/指代补全失败就合并回单意图”与“不确定必须澄清、未确认零副作用”矛盾,仍可能执行 TopIntent 并丢弃其余任务。
**整改:** 只有确定为完整单意图连动时才合并;低置信、指代失败或无法证明完整一律澄清,保留候选理解但不执行。
### P1:数据复制与步骤传递缺少信任边界
初稿可能把原文、槽位、结果复制到 JSONB、日志、事件、SSE,再把查询摘要直接注入 task brief,扩大敏感数据面和提示注入路径。
**整改:** 计划保存消息引用/digest/allowlist display snapshot;事件和日志仅传 scope、状态与安全摘要引用;步骤间使用带 provenance/type/digest/sensitivity 的 ResultReference。结果只能进入隔离材料区,不能修改 action、target、tool 或 capability。
### P1:灰度开关顺序错误
现有 MULTI_INTENT_ENABLED 默认 true;初稿到最后一阶段才新增 tier,会让中间合入的行为缺少默认关闭门。
**整改:** U1 先建立默认 legacy 的新 tier;U2 只 shadow;auto_read 先维持两个查询的当前上限;确认和每个动作 adapter 分档开放。回滚必须继续支持已有计划读取/取消/收口。
## 重要产品修订
- 无活动写计划时单意图生成行为保持不变;多意图 generate 的确认/tier/adapter 能力由 intentflow BatchActionPolicy 管理,静态风险仍引用 ActionRegistry;
- 计划卡默认显示一句摘要和主动作,详细风险/步骤折叠展开,降低认知负担;
- 自然语言“确认”只有在当前会话恰有一个活动可见计划时才绑定;多计划或混入新任务时澄清;
- 聚合澄清不承诺一次自由文本必然填满所有槽位;只接受可唯一映射值,槽位依赖/冲突继续追问;
- 部分确认默认是分批批准,未选项保留待确认;只有显式排除才取消,部分完成提供重试/继续/关闭;
- 单意图生成兼容承诺只适用于当前没有活动写计划;有活动计划时统一冲突视图,避免双任务;
- 多意图价值必须用采用率、确认放弃率和拆单回退率证明;价值不足时停止写动作扩面,但保留“不静默丢任务”的安全改进。
- 批量确认、tier 和 adapter 策略归 intentflow 的 BatchActionPolicy;ActionRegistry 只保留动作身份与静态风险,避免编排政策回灌 L1;
- 计划卡折叠态仍显示目标、最高风险、不可撤销副作用和非原子语义;技术元数据才可折叠;
## 并发与权限检查表
- 同 turn 同 digest 返回原计划;同 turn 异 digest 冲突;
- decision 带 expected revision、nonce 与 digest;
- plan/step CAS 与单调 fencing;
- fencing 和幂等占位必须进入动作属主事务,只锁计划行不足以阻止旧 worker 副作用;
- confirm/cancel/expiry/edit 只有一个胜者;
- 部分确认必须依赖闭包;
- 双标签、双实例、worker 接管最多一次副作用;
- 跨 user/project/session 不可读、不可确认且不泄露存在性;
- 确认后成员/职责/资源状态变化仍会拒绝执行;
- SSE 重复、乱序、缺失由 GET reconcile;
- CSRF/Origin 沿用服务端认证策略,nonce 不冒充 CSRF。
- active-plan discovery 是刷新必需入口,不能依赖消息投影中恰好保存 plan_id。
## 范围与任务修订
原 T1–T5 被重拆为核心 U1–U8、可选实验 U9 和属主扩面 U10–U12:契约门禁、纯规则 shadow、持久计划、事件投影、决策/授权、Web、只读执行、task generate 首版、LLM adapter、mutate/docgov/workflow-run 分项扩面。每个单元有独立依赖、文件范围、测试、停走门与真实 mutex。总览不长期占用 `intent`;每个 action 仍需独立 short-term。
## 评审覆盖
- 本地视角:coherence、feasibility、security、scope、product、design、adversarial;
- 独立 cross-model:Claude Opus 5/high 的 security、product、adversarial 与 whole-document sweep;
- cross-model 审的是初稿,其关于 LLM 输入、plan ACL、结果传递、幂等、产品价值和确认负担的有效意见已纳入修订;其余由当前代码与边界事实校正。
## 关联整改
- System design: [2026-09-15-multi-intent-hitl-plan.md](../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Short-term: [2026-09-15-multi-intent-hitl.md](../ops/short-term/2026-09-15-multi-intent-hitl.md)
## 证据
- `internal/intent/plan_builder.go`:首连接词、两段、写意图返回 nil;
- `internal/coordinator/action_planner.go`:pending confirm 仅文字提示;
- `internal/intent/registry.go`:task.run/adhoc 为 medium 且当前不全局 RequiresConfirm;
- `internal/intent/flags.go`:MULTI_INTENT_ENABLED 默认 true;
- `.doc/system-design/module-boundaries.yaml`:intent 只依赖 maturity,Track E/table owners 已登记;
- `internal/events/registry.go`:事件须静态注册;
- `internal/app/uow/uow.go`:不透明 TxScope;
- `web/src/App.tsx`:现有 card action 含前端本地业务状态路径。
## 开放问题
无阻塞性架构问题。各放量阈值必须在 U2 shadow 基线形成后预注册;这属于实施期量化,不授权跳过停走门。
@@ -0,0 +1,44 @@
---
title: Demo/测试数据污染系统性审计
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
---
# Demo / 测试数据污染系统性审计
## 前序
本审计在 [2026-09-15 mock 交付物污染真实项目](./2026-09-15-mock-deliverables-pollute-real-projects.md)(及对应 [整改](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md))之上收敛为全栈系统性排查:前端门控、goose 演示项目/会话、stub API。
## 背景
空项目展示「终审已生效」受控文档 + 伪造三级职责人。初判怀疑 docgov 隔离失败;实锤为前端 mock/seed 与 DB goose 演示种子污染。
## 结论
| 面 | 判定 | 说明 |
|----|------|------|
| 服务端 `document_records` / project_docs | **正常** | 按 `project_id` 隔离;空项目台账为 0 |
| 前端 `ALL_INITIAL_DELIVERABLES` / mockDocuments | **critical** | 无门控进生产包;projectId 1/2/3 撞车 |
| 前端 DEFAULT_PROJECTS / sessions / MOCK_USERS | **critical/high** | NeuroPulse 5201、CUSA id=3、6001–6010 |
| `deliverableSync` 空清单 `return prev` | **critical** | 权威空列表不回收本地 mock |
| `isLegacyLocalMockDocId` 覆盖不全 | **critical** | 未覆盖 neuropulse / ten-projects |
| Goose `00011`/`00012` | **critical** | 全环境写入 6001–6010 + 聊天 |
| API `backend=stub` | **high** | main 仍可请求 stub |
| `BootstrapDevSeedUsers` | **OK** | 已有 env 门控 |
## 证据路径
- `web/src/App.tsx`(整改前 INITIAL_*)
- `web/src/data/mockDocuments.ts` / `neuropulseDemo.ts` / `tenProjectsDemo.ts`
- `web/src/lib/deliverableSync.ts`
- `deploy/postgres/goose/00011_*.sql` / `00012_*.sql`
- `internal/taskrun/backend.go`
- 产物扫描:`scripts/check-prod-bundle.sh`
## 整改回链
- [remediation](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
- [test-report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
+40
View File
@@ -13,6 +13,46 @@
## 核心文档(按阅读顺序推荐)
### 多意图与 HITL 方案复核(2026-09-15)
**文件**: [2026-09-15-multi-intent-hitl-plan-review.md](./2026-09-15-multi-intent-hitl-plan-review.md)
**结论**: 多意图方向可行,但必须以 `app/intentflow` 深模块、PG 权威状态机、逐动作即时授权和分波 mutex 防止 intent/coordinator 再耦合;确认、卡片和 SSE 均不能替代授权或权威状态。
**设计/计划**: [多意图持久计划与 HITL](../system-design/2026-09-15-multi-intent-hitl-plan.md) · [核心 U1–U8 与扩面 U9–U12](../ops/short-term/2026-09-15-multi-intent-hitl.md)
### 模块解耦 Phase 2 方案复核(2026-09-15)
**文件**: [2026-09-15-module-decoupling-phase2-plan-review.md](./2026-09-15-module-decoupling-phase2-plan-review.md)
**结论**: PG delivery 尚未形成生产闭环;原计划把事件、结构和协议三轨绑成一次交付,并误判 docgov/docrevision 依赖方向。修订版先完成事件生产与历史数据门,再以 PG dispatcher、逐消费者 shadow 和真实刷新/重启恢复收口。
**整改**: [Phase 2 持久事件交付与后续解耦路线](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
### arch-check U1 可重放基线(2026-09-14)
**文件**: [2026-09-14-arch-check-baseline.md](./2026-09-14-arch-check-baseline.md)
**结论**: 四类规则(production import / SQL write / path / event)可重放。import=0,sql_write=5,path=17,event=0。Goose 与测试不计生产写者。新违规与过期例外立即 block。
### 模块解耦方案复核(2026-09-14)
**文件**: [2026-09-14-module-decoupling-plan-review.md](./2026-09-14-module-decoupling-plan-review.md)
**结论**: 模块化单体方向成立,但原横向 Wave 缺少跨属主事务、可靠事件、多副本互斥、逐动作授权和 FAV 边界;应先完成受控文档可靠性纵向试点,再按证据扩面。
**整改**: [模块解耦与文档可靠性重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
### 项目 143 workflow-plan 409 与三权全有或全无(2026-09-14)
**文件**: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](./2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
**结论**: 项目 143 已于 2026-09-13 激活 main 工作流(实例 89),`SaveWorkflowPlan` 因 `lifecycle=active` 返回 409 `PLAN_FROZEN`;前端无冻结守卫、错误提示在视口外,表现为「校验并预览无反应」。按文档支持三权全有或全无,但全空仅用于定义允许裁剪的非必需文档,表示“不纳入人工审批”而非“非受控”;必需文档和零治理激活不得被绕过。
**整改**: [workflow-plan 409 + 三权全有或全无整改](../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
### 项目 143 受控正文 canonical hash 漂移(2026-09-14)
**文件**: [2026-09-14-project143-controlled-content-404.md](./2026-09-14-project143-controlled-content-404.md)
+79 -13
View File
@@ -1,24 +1,44 @@
# 当前焦点
**更新**: 2026-09-14
**production_ready**: no(`CHAT-INTENT-STATE` 等无关 blocker 仍开放。文档账本运行时 UI Round20 **PASS**,不把 fallback change report 写成完整 PI,也不把本轮写成全仓可发布)
**更新**: 2026-09-16
**production_ready**: yes(门禁 B1–B4 已签;dev/test/main `schema_version=47`。不把 fallback change report 写成完整 PI)
## 焦点
1. **DOC-CONTENT**: [受控正文 canonical hash 漂移](../audit/2026-09-14-project143-controlled-content-404.md)(真实 UI 验收已 PASS:项目 143 clean-run3 + 新项目 full-chain-final 主链及 restart 均全部通过)
2. **CHAT-INTENT**: [对话意图运行时状态](../audit/2026-09-13-conversation-intent-runtime-state.md)(`fix/conversation-intent-state`;与文档账本运行时无关)
3. **CHAT**: [对话历史刷新](../audit/2026-09-13-chat-history-refresh-disappears.md)(认领仍 `in_progress`;gap 行已 PASS,以代码/handoff 为准收敛)
1. **MATRIX 深度测试 + 晋升 test**:`feature/matrix-deep-test-promote-test` → `rc-v1.0.0-beta.2`
2. **首发后 backlog**:多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
3. **MULTI-INTENT HITL**:核心 U1–U8 已合入;U9–U12 不阻塞首版
## 并行认领
| owner | task | branch | worktree | mutex | status |
|-------|------|--------|----------|-------|--------|
| verifier_antigravity | controlled-content-ui-acceptance | fix/controlled-content-ui-acceptance | .worktrees/fix-controlled-content-ui-acceptance | document-content-ui-acceptance | done |
| implementer_cursor | controlled-content-canonical-hash | fix/controlled-content-canonical-hash | .worktrees/fix-controlled-content-canonical-hash | docgov | done |
| Cursor-Auto | 2026-09-16-matrix-deep-test-promote-test | feature/matrix-deep-test-promote-test | - | infra | in_progress |
| Cursor-Auto | 2026-09-16-production-ready-gates | docs/production-ready-flip | - | ci | done |
| Cursor-Auto | 2026-09-16-demo-seed-pollution | fix/demo-data-pollution-web | - | web | done |
| Cursor | 2026-09-16-multi-intent-u8-task-generate | feature/multi-intent-u8-task-generate | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u7-auto-read | feature/multi-intent-u7-auto-read | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u6-web-cards | feature/multi-intent-u6-web-cards | - | web | done |
| Cursor | 2026-09-16-multi-intent-u5-decision-api | feature/multi-intent-u5-decision-api | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u4-outbox-projection | feature/multi-intent-u4-outbox-projection | - | events | done |
| Cursor | 2026-09-15-multi-intent-u3-intentflow-pg | feature/multi-intent-u3-intentflow-pg | - | intent-plan | done |
| Cursor | 2026-09-15-multi-intent-u2-segmenter | feature/multi-intent-u2-segmenter | - | intent | done |
| Cursor | 2026-09-15-multi-intent-u1-contracts | feature/multi-intent-u1-contracts | - | architecture-docs | done |
| Cursor | app-composition-u11-u12 | feature/app-composition-u11-u12 | - | app | done |
| Cursor | chatlog-contextasm-u10 | feature/chatlog-contextasm-u10 | - | chat | done |
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | done |
| Cursor | dataset-lifecycle-u9 | feature/dataset-lifecycle-u9 | - | dataset | done |
| Cursor | taskrun-runmanifest-u8 | feature/taskrun-runmanifest | - | taskrun | done |
| Cursor | document-reliability-m1-live-and-m2 | refactor/document-reliability-pilot | - | workspace | done |
| Codex | module-decoupling-remediation-plan | feature/module-decoupling-remediation | - | architecture-docs | done |
| Codex | module-decoupling-phase2-plan-review | docs/module-decoupling-ipc-assessment | - | architecture-docs | done |
| Cursor | module-decoupling-phase2-docs | feature/module-decoupling-phase2-docs | - | architecture-docs | done |
| verifier_antigravity | controlled-content-ui-acceptance | fix/controlled-content-ui-acceptance | - | document-content-ui-acceptance | done |
| implementer_cursor | controlled-content-canonical-hash | fix/controlled-content-canonical-hash | - | docgov | done |
| Codex | project143-controlled-content-404-diagnosis | fix/project143-controlled-content-404-diagnosis | - | docgov-content-diagnosis | done |
| Codex | software-project-bootstrap-plan | feature/software-project-bootstrap-plan | - | workflow-design | done |
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | in_progress |
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | .worktrees/fix-conversation-intent-state | intent | in_progress |
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | - | intent | done |
| Cursor | conversation-intent-runtime-state | docs/conversation-intent-dual-tab | - | intent | done |
| Cursor | document-revision-wave1-6-implementation | feature/document-revision-management | - | docgov | done |
| Cursor-Auto | document-revision-runtime-ui03 | fix/document-revision-runtime-ui03 | - | docgov | done |
| Cursor-Auto | document-revision-sse-idempotency | fix/document-revision-sse-idempotency | - | docgov | done |
@@ -46,14 +66,36 @@
| Cursor-Auto | document-revision-evidence-count | fix/document-revision-evidence-count | - | document-revision-evidence-count | done |
| Cursor-Auto | document-revision-session-close | feature/document-revision-session-close | - | document-revision-session-close | done |
| Cursor-Auto | vite-frp-allowed-hosts | fix/vite-frp-allowed-hosts | - | web-devserver | done |
| implementer_cursor | workflow-plan-409-frozen-and-optional-duties | fix/workflow-plan-409-frozen-and-optional-duties | - | workflow | done |
| implementer_cursor | governance-action-level-authz | fix/governance-action-level-authz | - | workflow | done |
| Cursor | leftover-branch-cleanup | chore/leftover-branch-cleanup | - | ops | done |
| Cursor | event-e0a-production-scope-contract | fix/event-production-scope-contract | - | events | done |
| Cursor | event-e0b-dispatcher-pg | feature/events-dispatcher-pg | - | events | done |
| Cursor | event-e1a-notify-cutover | fix/event-notify-cutover | - | events | done |
| Cursor | event-e1b-workflow-advance | fix/event-workflow-advance | - | events | done |
| Cursor | event-e1c-projection-cutover | fix/event-projection-cutover | - | events | done |
| Cursor | event-e2-hook-guard | fix/event-e2-hook-guard | - | events | done |
| Cursor | doccontent-canonical-boundary | fix/doccontent-canonical-boundary | - | docgov | done |
| Cursor | intent-bizdev-boundary | fix/intent-bizdev-boundary | - | intent | done |
| Cursor | stageflow-type-ownership | fix/stageflow-type-ownership | - | stageflow | done |
| Cursor | bizdev-locator-removal | fix/bizdev-locator-removal | - | bizdev | done |
| Cursor | chatflow-orchestration-boundary | fix/chatflow-orchestration-boundary | - | chat | done |
| Cursor | phase2-closeout-inventories | feature/phase2-closeout-inventories | - | architecture-docs | done |
| Cursor | event-shared-live-cutover | feature/event-shared-live-cutover | - | events | done |
| Cursor | pi-typed-result | feature/pi-typed-result | - | pi-agent | done |
| Cursor | promote-dev-to-test-2026-09-15 | feature/promote-dev-to-test-2026-09-15 | - | infra | done |
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
> workflow-plan 409 与治理鉴权 G1–G5 已收口(见 [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md))。禁止终止或改写项目 143。
> `document-reliability-pilot` U11–U12 已合入 `dev@bf59cce` 并 rebuild。`CHAT-INTENT-STATE` 双标签 busy 已 PASS(项目 6275)。禁止 worktree 内 `env-service`。项目 143 只读,禁止终止。
> 2026-09-15 旁支清理:[报告](../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md)。已合入本地旁支 31 条已 `git branch -d`;7 个对应 worktree 已拆。extra worktree 仅余 `.worktrees/fix-dev-runtime-data-root-guard`(目录名是 guard,检出的是 `feature/final-artifact-vault`)。**故意不合入、不删**:`feature/final-artifact-vault`、`feature/remove-herdr-agent-settings`、`fix/project143-controlled-content-404-diagnosis`、`fix/dev-runtime-data-root-guard`、`dev-old-linear`。不删 `origin/*`。不整支 merge FAV;不启用 `FAV_DEGRADED_READ`。
## 集成槽位
| holder | phase | since | scope | queue |
|--------|-------|-------|-------|-------|
| idle | idle | - | - | - |
| Cursor-Auto | merging | 2026-09-16T13:20Z | matrix deep test → promote rc-v1.0.0-beta.2 + test rebuild | - |
**phase**: `idle` | `merging` | `smoke` | `e2e`
@@ -63,9 +105,9 @@
| 环境 | 端口 | schema | 状态 |
|------|------|--------|------|
| dev | 8080 | **32** | healthy(产品代码部署为 `36e4bc3`;真实 UI 主链+restart PASS) |
| test | 8081 | 25→27* | healthy |
| main | 8000 | 25→27* | healthy(app + runner + DB) |
| dev | 8080 | **47** | healthy(`pi-agent` typed-result-v1;events worker `:8088`;notify/advance/projection live、fav off;health+ready PASS;demo 6001–6010 retired) |
| test | 8081 | **47** | healthy(`rc-v1.0.0-beta.1`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS;schema 与 dev 对齐 47) |
| main | 8000 | **47** | healthy(app + events + runner + DB;与 dev/test 对齐) |
## SSOT
@@ -76,11 +118,35 @@
| 发布缺口 | [gap-matrix](../remediation/gap-matrix.md) |
| 测试报告 | [test-reports/](../test-reports/) |
| 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) |
| DOCREV ADR | [../adr/2026-09-13-document-version-boundary.md](../adr/2026-09-13-document-version-boundary.md) |
| DOCREV 管理测试 | [../test-reports/2026-09-13-document-revision-management-test-report.md](../test-reports/2026-09-13-document-revision-management-test-report.md) |
| DOCREV 运行时 UI Round20 | [../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) |
| 纯软件项目自举设计 | [../system-design/2026-09-14-software-project-bootstrap-workflow.md](../system-design/2026-09-14-software-project-bootstrap-workflow.md) |
| 模块化单体解耦架构 | [../system-design/2026-09-14-module-decoupling-architecture.md](../system-design/2026-09-14-module-decoupling-architecture.md) |
| 模块解耦整改计划 | [../remediation/2026-09-14-module-decoupling-refactor-plan.md](../remediation/2026-09-14-module-decoupling-refactor-plan.md) |
| Phase 2 方案审阅 | [../audit/2026-09-15-module-decoupling-phase2-plan-review.md](../audit/2026-09-15-module-decoupling-phase2-plan-review.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) |
| 多意图 HITL 复核方案 | [../system-design/2026-09-15-multi-intent-hitl-plan.md](../system-design/2026-09-15-multi-intent-hitl-plan.md) |
| 多意图 HITL U1 契约 | [../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md) |
| 多意图 HITL U2 分段 | [../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
| 多意图 HITL U3 PG | [../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
| 多意图 HITL U4 投影 | [../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
| 多意图 HITL U5 API | [../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
| 多意图 HITL U6 Web | [../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
| 多意图 HITL U8 generate | [../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md) |
| 多意图 HITL U7 只读 | [../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md](../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md) |
| 文档可靠性 M1 报告 | [../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-test-report.md) |
| 文档可靠性 M1 活验 | [../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md) |
| 文档可靠性 M2 | [../test-reports/2026-09-14-document-reliability-m2-test-report.md](../test-reports/2026-09-14-document-reliability-m2-test-report.md) |
| 文档可靠性 M3 U8 | [../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md) |
| 文档可靠性 M3 U9 | [../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md) |
| 文档可靠性 M4 U10 | [../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) |
| 文档可靠性 M5/M6 U11–U12 | [../test-reports/2026-09-15-app-composition-u11-u12-test-report.md](../test-reports/2026-09-15-app-composition-u11-u12-test-report.md) |
| Track E E2 闭包守卫 | [../test-reports/2026-09-15-event-e2-hook-guard-test-report.md](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md) |
| Track E 复盘 | [./research/2026-09-15-track-e-retrospective.md](./research/2026-09-15-track-e-retrospective.md) |
| 旁支清点收口 | [../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md](../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md) |
| SSE/幂等审计 | [../audit/2026-09-13-document-revision-sse-idempotency.md](../audit/2026-09-13-document-revision-sse-idempotency.md) |
| 质量门禁自污染审计 | [../audit/2026-09-13-document-revision-quality-gate-self-pollution.md](../audit/2026-09-13-document-revision-quality-gate-self-pollution.md) |
| 当前文档路由审计 | [../audit/2026-09-13-document-revision-active-doc-routing.md](../audit/2026-09-13-document-revision-active-doc-routing.md) |
@@ -0,0 +1,74 @@
---
title: "模块解耦重构验收清单"
status: in_progress
created: 2026-09-14
updated: 2026-09-15
owner: Cursor
---
# 模块解耦重构验收清单
## M0 架构与基线
- [x] contracts 分类、事务 owner、表属主、锁顺序、事件信封、Principal 和 FAV 边界均有唯一规范来源。
- [x] arch-check 分离 production import、SQL write、path 和 event registration;例外有 owner 与到期日。
- [x] 当前违规基线可重复生成,新违规立即阻断。
## M1 文档可靠性
- [x] 人工编辑、agent commit、approve/reject 的跨表写入同事务(U3;隔离库双会话编辑已测)。
- [x] fault injection 任一点失败均无部分提交(U2 隔离库)。
- [x] 同 ETag 并发写只有一个赢家(内存 + 双会话)。
- [x] 1、2、4 app replicas 结果一致。
- [x] GET 服务端零写入 + typed consistency(U4 单测)。refresh/reload 真页面 PASS([活验报告](../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md))。
- [x] 项目 143 等价 hazard 与新项目真实页面刷新、重登、restart、rebuild PASS。
- [x] 服务端负例 fail closed;浏览器跨用户 401/404 PASS。
## M2 事件与 FAV
- [x] 业务终态、staging 和 outbox 同事务。
- [x] 每个 consumer 有独立 delivery/inbox/attempt/lease/dead-letter。
- [x] 1、2、4 dispatcher 无重复可见副作用和永久饥饿。
- [x] crash-before/after-side-effect/ack 全部可恢复。
- [x] stale fencing、跨项目事件、错误 producer、坏 digest 均拒绝。
- [x] FAV 中间结果、Prompt、工具轨迹和 secret 准入率为零。
- [x] DB 授权成功后才允许 degraded read;授权图缺失 fail closed。
- [x] tombstone/删除账本 union-deny PASS。
## M3 TaskRun、workspace 与数据生命周期
- [x] RunManifest 规范字节、SHA、成员和 storage identity 持久化。
- [x] 重复 finalize、SSE 断线和 cancel race 不重复消息或 artifact。
- [x] WorkspaceRef 无物理路径,路径遍历和链接逃逸负例 PASS。
- [x] 旧 lease writer 被 fencing token 拒绝。
- [x] workspace 清空后最终成果仍可定位和校验。
- [x] backfill 可暂停、续跑和重放;异常进入 quarantine。
- [x] 八条 migration/reload/recovery 轨道 PASS。
- [x] 数据销毁前完整备份、corpus、FAV coverage 和人工批准全部满足。
## M4–M6 选择性扩展
- [x] 每个子切片在原包边界先获得行为收益,再决定物理搬包。
- [x] chatlog/contextasm 保持授权可见集合和计数一致。
- [x] app 是唯一组合根,subscriber 重复启动不重复注册。
- [x] UserProjectContext 跨模块写路径走类型化 ContextUpdate + 版本 CAS(coordinator 作为 owner 仍可改 Project 字段)。
- [ ] server 无 SQL、路径拼接和业务闭包。(OnOutbox 已迁出;生产 SQL 无新增;path 例外 `workspaces/` / `output.md` 未到期,未删)
- [ ] 对应架构规则全部 block,过期例外和 flags 已删除。(`import`/`event` 已 block;sql_write/path 基线例外仍在)
## 证据分层
- [x] Unit/stub 证据。
- [x] PostgreSQL integration 证据(隔离库,非共享 env 库)。
- [x] race/concurrency 目标包证据(非全仓 race)。
- [x] fault injection 证据(U2)。
- [x] 真实 PI 证据。
- [x] 真实浏览器证据。
- [x] restart/rebuild 证据。
- [x] cross-user/project authorization negative 服务端证据。
- [x] scratch recovery 与完整 DB restore 证据。
## 关闭条件
- [x] test report 回链具体 U-ID、commit、环境 identity 和 fixture/dataset。([U11–U12 报告](../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md);合入 `dev` 后补 rebuild 镜像)
- [x] CURRENT、FEATURE-MATRIX、gap-matrix 与任务状态一致。
- [x] 未实施后续仍为 planned/deferred,不用局部测试冒充全计划完成。
@@ -0,0 +1,22 @@
---
title: "多意图 HITL U1 契约冻结 checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u1-contracts"
---
# 多意图 HITL U1 契约冻结 checklist
## Wave 0
- [x] YAML `app/intentflow` allowlist + 三表 owner + unwrap_owners — 证据:`.doc/system-design/module-boundaries.yaml`
- [x] 三条 `intent.plan.*` YAML ↔ StaticContracts parity — 证据:`go test ./internal/events -run RegistryParity`
- [x] archtest 扫描 `intent.plan.*` — 证据:`go test ./internal/archtest`
- [x] intentflow 状态/错误码/Service/政策/legacy tier — 证据:`go test ./internal/app/intentflow`
- [x] CSRF/Bearer 结论落盘 — 证据:U1 short-term
- [x] `go test -short ./...` — 证据:[U1 报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,22 @@
---
title: "多意图 HITL U2 规则分段 checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u2-segmenter"
---
# 多意图 HITL U2 规则分段 checklist
## Wave 1
- [x] characterization 锁定 legacy IntentPlan — 证据:`internal/intent/plan_builder_test.go`;[报告 §5.1](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
- [x] 分段器 golden(连接词/句号/序号/先再最后) — 证据:[proposal-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/proposal-verbose.txt)
- [x] 查询并总结不拆;写段进入提案;5 段拒绝;红线整体拒绝;指代澄清 — 证据:同上
- [x] digest 稳定;shadow 不改 TopIntent — 证据:`TestPlanProposal_DigestStable` / `TestPlanProposal_WriteNotDroppedAndLegacyUnchanged`
- [x] 反事实 auto_read 错误自动执行 = 0 — 证据:`plan-proposal eval denom=8 false_auto_execute=0`
- [x] `go test -short ./internal/intent ./internal/coordinator ./internal/app/intentflow` — 证据:[unit.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/unit.txt);[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,22 @@
---
title: "多意图 HITL U3 intentflow PG checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u3-intentflow-pg"
---
# 多意图 HITL U3 intentflow PG checklist
## Wave 2
- [x] Goose 00044 三表 + unique/CAS/lease 列 — 证据:`deploy/postgres/goose/00044_2026-09-15-intent-plans.sql`;`TestGooseU3_00044_HasUpAndDown`
- [x] 创建幂等与同 turn 异 digest — 证据:[plans-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/plans-verbose.txt)
- [x] 决策 nonce / revision CAS / 过期 — 证据:同上
- [x] 两 worker 无双 owner;租约接管;旧 fence 拒绝 — 证据:`TestTwoWorkersOneOwnerAndLeaseTakeover`
- [x] receipt 对账不盲跑;环境隔离;legacy HandleTurn 不落盘 — 证据:`TestReceiptWritebackFailureDoesNotRerun` / `TestHandleTurnLegacyDoesNotPersist`
- [x] Assemble 接线且 chat 不调用;arch-check 无新例外 — 证据:[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,19 @@
---
title: "多意图 HITL U4 outbox checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u4-outbox-projection"
---
# 多意图 HITL U4 outbox checklist
- [x] 同 UoW Append intent.plan.* — 证据:[emit-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/emit-verbose.txt)
- [x] golden payload 无敏感字段 — 证据:`testdata/intent-plan-awaiting-v1.json`
- [x] 重复/乱序/伪造 producer — 证据:`TestProjectionOnlyForwardAndForgedRejected`
- [x] 投影只前进;跨用户隔离 — 证据:同上
- [x] dispatcher 语义未改;arch-check 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,20 @@
---
title: "多意图 HITL U5 decision API checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u5-decision-api"
---
# 多意图 HITL U5 decision API checklist
- [x] 冻结 REST 路径挂到认证 mux — 证据:[http-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/http-verbose.txt)
- [x] Principal 不从 body 复制 — 证据:`TestIntentPlanHTTP_IgnoresBodyPrincipalAndSameReceipt`
- [x] 非成员/跨作用域/管理员负例 — 证据:`TestIntentPlanHTTP_ScopeNegatives` / `AdminDoesNotBypassMembership`
- [x] StepAuthorizer 在 confirm 与 execute 前调用 — 证据:[authorize-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/authorize-verbose.txt)
- [x] stale/nonce/edit/非法部分确认 — 证据:同上
- [x] arch-check / short 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,19 @@
---
title: "多意图 HITL U6 Web checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u6-web-cards"
---
# 多意图 HITL U6 Web checklist
- [x] PLAN_CONFIRM 类型与 PlanView 映射 — 证据:`web/src/engine/planCard.test.ts`
- [x] 决策走 REST,不改 AST — 证据:`planCardTouchesLocalAST` + App early-return
- [x] 409/过期/submitting 状态 — 证据:同上
- [x] App early-return — 证据:`web/src/App.tsx`
- [x] 单元测试绿;Playwright 门控 skip — 证据:[npm-test.txt](../../test-reports/assets/2026-09-16-multi-intent-u6-web-cards/npm-test.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,14 @@
---
title: "U7 auto_read checklist"
status: done
created: 2026-09-16
related_task: "2026-09-16-multi-intent-u7-auto-read"
---
# U7
- [x] legacy HandleTurn 不落盘
- [x] auto_read 查询创建并执行
- [x] 写话语不落盘
- [x] QueryGuard 拒绝 task.run
- [x] chat 调用 HandleTurn;arch 绿
@@ -0,0 +1,23 @@
---
title: "U8 task generate checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u8-task-generate"
---
# U8
- [x] confirm 话语落盘 awaiting,确认前不执行 — 证据:`TestHandleTurnConfirmPersistsAwaitingWithoutExecute`
- [x] 第二活动写计划冲突 — 证据:`TestHandleTurnConfirmRejectsSecondActiveWritePlan`
- [x] OwnerMux 路由 + nil Task fail closed — 证据:`TestOwnerMuxRoutesGenerateToTask` / `TestOwnerMuxNilTaskFailClosed`
- [x] 确认后 generate 一次、重放不双跑 — 证据:`TestConfirmThenMuxExecutesGenerateOnce`
- [x] adapter 幂等 / 拒查询 / 撤销 — 证据:`TestTaskRunAdapter*`
- [x] LiveTaskStarter 同键重放 — 证据:`TestLiveTaskStarterReplaysIdempotencyKey`
- [x] QueryGuard 仍拒 task.run;auto_read 写话语不落盘 — 证据:U7 回归 + `TestQueryGuardRejectsGenerate`
- [x] 真实 PI stop-gate — 证据:`TestTaskGenerateRealPIStopGate` SKIP
- [x] arch-check block 绿 — 证据:[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -0,0 +1,67 @@
---
title: "意图 mutex 从 Codex 转 Cursor:仅剩浏览器双标签门"
created: 2026-09-15
from: Codex
to: Cursor
status: closed
---
# 交接:对话意图运行时状态 — 浏览器双标签门
## 目标(下一位 Agent 应完成什么)
在 U11–U12 已合入并 rebuild 的 `:8080` 上,用**新建项目**补齐真实 PI + 双标签 busy / 刷新恢复证据。通过则关 `CHAT-INTENT-STATE` 并 archive;失败则从最新 `dev` 新开 `fix/conversation-intent-dual-tab`,**不要**在已合入的 `fix/conversation-intent-state` 上追加。
## 已完成
- Wave 0–4 服务端/单测已在 `dev`(`fix/conversation-intent-state` 是祖先)。
- 前端 5s 租约轮询:`web/src/App.tsx`。
- `DOC_BUSY` 预检:`internal/server/task_run_handlers.go`(不创建第二 run,`error_info.actions=[]`)。
- UI busy 文案:`BlockRenderer` / `DeckDrawer`「编辑中」。
- 只读总结真实 PI(用例 H)已签;项目 143 诊断污染未删。
## 未完成
- 浏览器刷新恢复与双标签租约可见性(报告用例 E)。
- 整改 Wave 3–4 未勾项:运行中刷新、busy 自动解除、并发写不新增 run 的**活验证据**。
## 认领 / 槽位状态
| 项 | 值 |
|----|-----|
| mutex 已释放 | no(`intent` 转 Cursor `in_progress`) |
| 集成槽位 holder | idle(U11–U12 已释放;本门禁不占槽,除非要合入 UI 补丁) |
| branch | 编码已在 `dev`;活验文档用 `docs/conversation-intent-dual-tab` |
| worktree | `.worktrees/fix-conversation-intent-state` **禁止** `env-service` |
> 用户已要求关掉 CURRENT 两行 `in_progress`,授权 Cursor 接管剩余验收。不覆盖 Codex worktree 未合并代码。
## 关键文件
| 路径 | 说明 |
|------|------|
| `.doc/ops/short-term/2026-09-13-conversation-intent-runtime-state.md` | 任务文 |
| `.doc/test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md` | 用例 E 待补 |
| `.doc/remediation/2026-09-13-conversation-intent-runtime-state-remediation.md` | Wave 3–4 |
| `web/src/App.tsx` | 5s lease 轮询 |
| `internal/server/task_run_handlers.go` | DOC_BUSY 预检 |
## 如何验证
```bash
# 主仓已 rebuild 的 dev,禁止 worktree 内 env-service
curl -sf http://127.0.0.1:8080/ready
# 新建项目 + 隔离 session;禁止项目 143;禁止 sess-p143-u9 探针
```
## 风险 / Blocker
- 项目 143 只读:不终止、不改写、不打探针。
- 客户端在 lease 已投影后会本地拦截写请求(不发 POST);HTTP 409 须在轮询窗口内或走 API 第二通道取证。
- 诊断污染消息仍不擅自删除。
## 相关链接
- 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)
@@ -0,0 +1,47 @@
---
title: "选择性模块解耦 M4–M6"
status: planned
created: 2026-09-14
updated: 2026-09-14
owner: TBD
mutex: architecture
review_cycle: milestone
---
# 选择性模块解耦 M4–M6
## 目标
在文档可靠性、可靠事件和 FAV 已证明收益后,按 U10–U12 分别收敛 chatlog/contextasm、应用组合根、共享上下文和传输层。
## 为什么是长期任务
这些改动不直接修复当前受控正文事实源问题,且会触及仍在进行的 chat/intent 工作。
M1–M3 未通过前执行会扩大冲突面,并提前冻结未经真实消费者验证的契约。
## 触发条件
- M1–M3 的 test report 全部 PASS。
- 同类缺陷触达文件数和运行故障率表明继续解耦具有收益。
- `chat`、`intent`、`bizdev/coordinator`、`server/stream` mutex 按子切片释放。
- 每个子切片有独立 owner、回滚点和行为验收,不批准一个巨型 Wave。
## 候选子任务
1. U10 chatlog/contextasm 原地端口化。
2. U11a 唯一 app composition root。
3. U11b 按事件逐个替换闭包桥。
4. U11c 逐 use case 迁移 ExecuteTask/executeStageInternal。
5. U11d UserProjectContext snapshot/update 收权。
6. U12 server/SSE 边界和架构门禁收口。
## 不包含
- 错误信封统一。
- PI Runner result.json 协议。
- 微服务拆分。
## 相关链接
- [模块解耦整改与重构计划](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- [模块化单体解耦架构](../../system-design/2026-09-14-module-decoupling-architecture.md)
@@ -0,0 +1,86 @@
---
title: "MVP 治理规则方案评审(零治理创建 / 禁止零治理激活与执行 / 职责-动作对应)"
status: done
created: 2026-09-14
updated: 2026-09-14
author: Cline
---
# MVP 治理规则方案评审(零治理创建 / 禁止零治理激活与执行 / 职责-动作对应)
## 评审对象
用户转来的治理原则提案(外部评审稿,自称「仅完成审核判断,尚未修改此前落盘方案或业务代码」),核心主张:
> 允许零治理创建项目和普通对话;禁止零治理激活和执行文档任务。文档任务按动作进行职责鉴权,编制、审核、批准只能由对应文档负责人执行,项目创建者不具有隐式越权能力。
## 结论(先说判断)
**方向合理、证据属实、与已实施的 DutyMode 架构(Wave 1–4)高度兼容,建议采纳为治理总原则;但存在 4 个必须先决策/修正的分歧点,其中 A(none 文档可否生成)与 B(pre-activation 202 契约)若按提案字面实施,会直接推翻刚落地的已验收语义与测试。**
## 证据核实矩阵(提案引用的代码全部属实)
| # | 提案主张 | 核实结果 | 证据位置 |
|---|----------|----------|----------|
| 1 | 无治理实例时文档任务访问直接放行 | ✅ 属实 | `internal/projectinstance/document_access.go:49-51`(`gov == nil → return allow`);`stage_access_test.go:163` 断言该行为 |
| 2 | 创建者可绕过文档职责检查 | ✅ 属实 | `document_access.go:115-117`(`isCreator → allow`);`stage_access.go:65,67,79`(`allow = isCreator \|\| hasDuty`) |
| 3 | 只判断是否三职之一,不区分动作 | ✅ 属实 | `stage_access.go:96-100`(`docTaskDutyForUser` 任意一职即通过;`DocAccessAction*` 常量已存在于 `document_access.go:8-13` 但未与职责绑定) |
| 4 | `initial_workflow_key` 直通 active | ✅ 属实 | `internal/projectworkflow/service.go:57-83`(非空即 `LifecycleStatus="active"`);E2E `project_workflow_api_test.go:101-105` 依赖该旁路 |
| 5 | 创建弹窗默认勾选创建者+推荐审核/批准(成员角色≠文档职责) | ✅ 属实 | `web/src/components/project/CreateProjectModal.tsx:50-69`(creator/reviewer/approver 为项目成员角色) |
| 6 | 启用文档须完整三职(现行 validator) | ✅ 属实(主树) | `internal/projectinstance/validator.go:93-95`;已实施 worktree 已改为 DutyMode none/partial/full |
## 与已实施代码的交叉分析(提案未覆盖的现场)
上一轮整改(409 冻结 + 全有或全无)**已在 `fix/workflow-plan-409-frozen-and-optional-duties` worktree 实施**:Wave 1–4 已提交(`classifyDocDuty`/`DutyMode` 统一校验、门禁/readiness/访问一致语义、前端逐文档「纳入人工审批」开关),Wave 5(dev 真实浏览器验收)进行中(e2e spec 与 test-reports assets 未提交,集成槽位已占用)。dev 库实测:`133 active / 204 planning`,其中 **81 个 planning 项目带非空 `active_workflow_key`**(`initial_workflow_key` 旁路/历史迁移遗留的异态存量)——提案第 4 差距点在 dev 有真实影响面。
### 分歧点 A(最关键):none 模式文档可否生成 —— **已决策(2026-09-14,用户拍板)**
- 提案:「编制、审核、批准全部为空:该文档**不启用,不可发起任务**,也不阻塞阶段」。
- 已实施 D4(remediation 76-78 行):`DutyModeNone` = 文档**启用**、不要求 approved、不阻塞阶段,**项目创建者可触发生成和人工编辑**,其他成员只读。
- **用户决策:保持现实现(none = 不走人工审批但可生成)**。提案的「不可发起任务」正式收窄为「不可发起**审批流**动作(提交审核/审核/批准)」,不推翻 Wave 4/5。后续实施以本决策为准。
### 分歧点 B:pre-activation 202 契约
- 提案:「未激活:不创建任务、不启动小队、不获取文档租约」。
- 已验收契约:`ResolveMessageScopeForTask` 从未激活 → `ScopePreActivation`;`POST /api/v1/tasks/runs` 必须 **202**(`TestCreateTaskRun_PreActivationAcceptedNot409`,`internal/server/task_run_busy_preflight_test.go:75`);E2E UI-02 以 2xx 为硬门禁(409 即 FAIL)。
- 按字面「不创建任务」会推翻该契约并破坏 E2E。**建议**修正表述为:保留 202 创建 run(进入 `blocked_pending_governance` 之类状态、不启动小队、不取租约),chat 流内返回自然语言提示(提案的示例文案即为此设计)。提案意图(不执行)与现状兼容,仅「不创建」三个字必须改。
### 分歧点 C:creator 越权移除的影响面与 view 范围
- 移除 `isCreator` 例外(`document_access.go:115`、`stage_access.go:65,67,79`)方向正确,但大量已验收测试断言 creator allow(如 `access_governing_pg_test.go:140`),需同步重写测试语义,工作量可控但必须列入计划。
- 提案职责表「查看文档 = 具有项目访问权的成员」与 `document_access.go:102-104`(view 全放行)一致;但 `ResolveStageAccess` 的 UI 导航收窄会把无职责成员/创建者限制在职责阶段。需明确:view 豁免 stage 收窄(按提案表格),`AllowedStageKeys` 仅约束非 view 动作与任务发起入口。
### 分歧点 D:initial_workflow_key 旁路的存量处理
- 关闭入口正确(`projectworkflow/service.go:80-83` 改为仅挂载目录、不置 active),但需同步:`CreateProjectInput.InitialWorkflowKey` 字段废弃(`types.go:96`、前端 `web/src/types/projectWorkflow.ts:66`)、E2E legacy 用例(`project_workflow_api_test.go:101-105`)语义更新、以及 dev 库 81 个 planning+with_wf 异态项目的分类处置(至少审计:真 legacy / 测试数据,不得静默改库)。
## 提案其余要点的核实意见
- 三概念分离(创建/激活/执行)优于「创建即治理」:成立。创建者自动入成员已有实现(`CreateProjectModal` 默认勾选 + `ensureCreatedProjectWithMembers` 持久化),无死锁。
- 「至少一个 full 文档才能激活;全部未启用可存草稿禁激活」:与已实施 Wave 2 校验(至少一份 `DutyModeFull` + active member 复核)**完全一致**,无需重复实施。
- 「审核人退回 → 待编制人修订,审核人不得直接启动重编」:与职责-动作对应表一致,合理;现状 `docTaskDutyForUser` 不区分动作是真实缺口。
- 「激活冻结提示留空文档不可补配」:与现有冻结语义一致,属 Wave 1 frozen 视图文案的自然扩展。
- 「项目管理员」概念:现有成员角色枚举(creator/reviewer/approver/viewer)无 admin;提案未定义 role 模型如何演进(谁可配成员/职责目前是创建者,`IsProjectCreator` 权威)。建议 MVP 维持「创建者=项目管理员」,role 枚举演进留 backlog。
## 建议实施时序
1. 等 `fix/workflow-plan-409-frozen-and-optional-duties` Wave 5 验收收敛(验收中途改语义会导致返工与报告失真)。
2. 用户先决策分歧点 A(其次 C 的 view 范围)。
3. 采纳后新开 short-term(建议 `fix/governance-action-level-authz`,mutex=`workflow`),分波次:后端动作-职责映射(`CheckDocTaskAccess` 按动作判 author/reviewer/approver + 移除 creator 例外 + gov==nil 由「放行」改为「未激活拦截」但保留 202 契约)→ 关闭 `initial_workflow_key` 直通 → 前端交互与提示 → 存量异态审计 → E2E 更新。
## 采纳与派生记录(2026-09-14)
- 分歧点 A:用户拍板「保持现实现(none 可生成)」——见上文。
- 分歧点 B/C/D:按本评审建议采纳(B:保留 202 契约 + blocked 状态;C:view 豁免阶段收窄、creator 仅保留配置权与 none 生成触发;D:关闭直通 + 字段废弃 + 存量只审计不改库)。
- 已派生实施任务:[2026-09-14-governance-action-level-authz.md](../short-term/2026-09-14-governance-action-level-authz.md)(status=blocked,等待 Wave 5 收敛;含采纳版职责-动作矩阵与 G1–G5 波次)。
- Wave 5 现状(2026-09-14 实测):`implementer_cursor` 占集成槽位 phase=e2e,worktree 存在未提交 e2e 产物;新任务已排入槽位 queue。
## 相关链接
- Audit: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- Remediation(已实施版): [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- 先例: [2026-09-13-workflow-access-chat-members-ui01-02.md](../../audit/2026-09-13-workflow-access-chat-members-ui01-02.md)(202 契约与三态作用域来源)
## 备注
主树 `.doc/ops/CURRENT.md`(`feature/remove-herdr-agent-settings` 分支)焦点 1 仍写「worktree 尚未创建、blocked」,已过时:worktree 已存在且 Wave 1–4 落地、Wave 5 进行中。该更新属实施分支职责,本评审不跨分支代改,仅在此记录提醒收敛时同步。
@@ -0,0 +1,55 @@
---
title: "H0 HTTP/SSE 公开错误信封盘点"
created: 2026-09-15
status: done
confidence: high
---
# 调研:H0 HTTP/SSE 公开错误信封盘点
## 结论
`Server.Routes()` 现有 **122** 条公开路由。错误响应至少三种并存:纯文本 `http.Error`、`{"error","message"}` JSON、以及 SSE `error_info`(`user_message/code/class/request_id`)。前端设置页已按 `error` code 分支,聊天流走 `error_info`;大量文档/任务路由仍回传 `err.Error()`,H1 必须 additive 统一,不能先改状态码。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 路由清单 | `internal/server/server.go` `Routes()` | 122 条 `mux.HandleFunc` |
| 纯文本/拼接 error | `handlers.go`、`task_run_handlers.go`、`asset_handlers.go`、`sse.go` | `http.Error(w, err.Error(), …)` 会泄露内部原因 |
| JSON `{error,message}` | `project_settings_handlers.go`、`project_members_handlers.go`、`auth_helpers.go`、`chatflow_http.go` | 已有 `ERR_*` / `PLAN_FROZEN` 等稳定 code |
| SSE | `internal/stream/types.go` `ErrorInfo`;`classify.go` 固定 `UserMessage` | 有 `request_id`;`error` 字符串与 `error_info.user_message` 并存 |
| 前端 code 分支 | `web/src/api/projectSettingsError.ts` | `PLAN_FROZEN` / `PLAN_REVISION_CONFLICT` / `ERR_CONCURRENT_SWITCH` |
| 前端文案匹配 | `web/src/App.tsx` `detail.includes('无权访问该项目')` | 未知 code 仍靠 substring |
## 兼容风险
| 家族 | 代表路由 | 现状 | H1 风险 |
|------|----------|------|---------|
| 纯文本 | `POST /api/v1/chat`、`POST /api/v1/tasks/runs` | `Content-Type` 非 JSON,正文即 message | 前端若按 JSON 解析会失败;须 additive 保留旧正文或双写 |
| JSON error+message | 设置/成员/鉴权 | `error` 当 code | 与目标 `code` 字段同义;H1 应同时输出 `code` 与 `error` |
| SSE error_info | `/api/v1/chat/stream`、task stream | 已有 code/class/request_id | 与 HTTP 信封字段名不完全对齐(`user_message` vs `message`) |
| 授权拒绝 | `ERR_UNAUTHENTICATED` / `ERR_FORBIDDEN` | 部分 JSON、部分纯文本 | 统一后仍须不泄露资源存在性 |
## 建议映射(领域 → 目标 wire code)
| 领域情况 | 目标 code | 备注 |
|----------|-----------|------|
| 未登录 | `AUTHZ` | 不区分用户是否存在 |
| 项目/文档无权 | `AUTHZ` | 与 404 策略保持现有授权选择 |
| 参数/校验 | `VALIDATION` | details 只允许公开字段名 |
| 版本/修订冲突 | `VERSION_CONFLICT` | 现 `PLAN_REVISION_CONFLICT` 映射 |
| 幂等/重复提交 | `IDEMPOTENCY_CONFLICT` | 任务 run 已有 idempotency |
| 规划冻结 | `VALIDATION` 或保留 `PLAN_FROZEN` | H3 前不得改状态码 |
| 内部错误 | `INTERNAL` | 仅 `request_id`;禁止 SQL/路径/凭证 |
## 开放问题
- H1 是否把 SSE `user_message` 与 HTTP `message` 做成别名双写,需实施时定,不阻塞立项。
- 状态码 breaking 必须另写 ADR(H3)。
## 建议动作
- H1:envelope registry + request ID 中间件;旧 `error` 字段 additive 保留。
- 负例:XSS、路径、SQL、token、prompt、跨租户 ID 不得进入 `message`/`details`。
- 实施见 [HTTP 信封整改](../../remediation/2026-09-15-http-error-envelope-remediation.md)。
@@ -0,0 +1,149 @@
---
title: "模块解耦与 IPC/RPC 交互现状评估(复核修订版)"
status: done
created: 2026-09-15
updated: 2026-09-15
author: Cline
confidence: high
---
# 调研:模块解耦与 IPC/RPC 交互现状评估
## 结论
1. 系统采用模块化单体,不应把所有模块调用改成 IPC/RPC。当前已运行的外部传输边界有两条:Web 与 server 的 HTTP/SSE、Go server 与 PI Agent Runner 的 HTTP。`cmd/events` 和 FAV worker 是计划中的独立进程,不是已运行事实。
2. 端口、组合根、事件信封、RunManifest、幂等键和 arch-check 提供了可执行的边界基础;`import=0/event=0` 只表示没有超出现有 allowlist/baseline 的新违规,不能证明语义解耦已经完成。
3. 首要可靠性缺口是事件“部分生产、没有生产级消费闭环”。`internal/events/pg.go` 尚无原子 lease、ack/fail、retry/dead-letter 的完整实现;现有 dispatcher 测试覆盖 MemoryBus,不是 PostgreSQL 运行证据。
4. 最大结构扩散源仍是 bizdev service locator。另有 `docgov → docrevision` 单向 canonical/hash 工具依赖、chat/coordinator 扇出和 `intent → bizdev` 依赖。此前“docgov↔docrevision 双向 import”的结论不成立。
5. HTTP 错误信封与 PI Runner typed result 是独立协议债,不应阻塞持久事件链关闭。FAV 分支也不应成为 notify/projection 交付的前置条件。
## 1. 通信边界
| 边界 | 机制 | 当前状态 |
|---|---|---|
| Web ↔ server | `/api/v1/*` HTTP + SSE | 已运行;错误信封仍未统一 |
| Go ↔ PI Agent Runner | HTTP + Bearer;health/run/cancel/search | 已运行;结果仍依赖 legacy stdout/result.json 路径 |
| 单体内模块 | 消费者端口 + `internal/app` 组合根 | 已运行;bizdev locator 和部分直依赖仍扩大改动面 |
| 领域事件 | PG envelope/delivery schema | 写侧部分存在;生产 dispatcher 未闭环 |
| `cmd/events` | 计划中的独立 worker | 尚未实现/部署 |
| FAV worker | 独立审计轨道 | 分支未整支合入;不得作为本轮验收前置 |
不建议把单体内端口改成 RPC。那会增加序列化、延迟、部分失败与运维成本,却不消除当前 locator、授权、幂等和事件消费缺口。
## 2. 已有契约与真实边界
### 已有且可校验
- `.doc/system-design/module-boundaries.yaml` 与 `internal/archtest` 管理 import、SQL write、path 和 event 规则。
- `events.Envelope` schema 1 包含 event/aggregate/correlation/causation/idempotency/digest/producer 等字段,并校验 digest 与敏感字段。
- `taskrun.RunManifest` schema 1 使用 canonical JSON 与 SHA-256。
- TaskRun 同 idempotency key 异 request digest 返回冲突;文档写使用 expected head/ETag。
- backend 选择由服务端 allowlist 控制,出站数据经过 secret stripping。
- `module-boundaries.yaml` 已有 `event_producers` 与 `event_consumers` 段。后续工作是补全并校验 runtime registry parity,不是新建段落。
### 尚未闭合
- `PGSink.Append`/`InsertEnvelope` 已存在,但 `ClaimIDs` 仍是 SELECT-only claim;没有生产级 lease 获取、heartbeat、fenced ack/fail、retry、dead-letter 和 immutable attempt audit 闭环。
- `event_deliveries` 每个 event/consumer 一行,只保存当前状态和累计 attempt;无法还原每次 lease/attempt 历史。
- `internal/events/replay.go` 只检查 dry-run 与 consumer/operator/reason 等基础字段,尚未形成带认证主体、env/project/event scope、plan digest 和 apply 审计的应用用例。
- `docflow` envelope 仍存在 `Environment:"dev"`、`ProjectID:0`,且 `Fav.StageAgentCommit(ctx, 0, ...)` 使用错误项目作用域。
- 部分 server 路径临时构造 `docflow.Commands`,没有稳定注入 EventSink/UoW;不能假设 candidate-ready、downstream-impact、approved 三条链已经产生可供 shadow 的事件。
- 闭包 hook 没有版本、重试、delivery 或 replay 记录。
## 3. 耦合点
### 3.1 bizdev service locator
`bizdev.Service` 暴露 `Pool()/CAS()/DocGov()/DocRevision()/ProjectWorkflow()/FreeformDoc()/KB()/ContextManager()`。调用方可以绕过端口取得数据库池和其他模块实现,令签名或构造变化向多包扩散。
整改应先加 no-new-callers 门禁,再逐调用方迁移,最后在一个 contract 提交删除 8 个 getter。门禁应禁止领域/用例 API 暴露或转发 pool/tx,同时允许 app/cmd 组合根向表属主构造器注入 pool,并允许登记属主从 opaque TxScope 解出 tx。
### 3.2 docgov 到 docrevision 的单向工具依赖
生产依赖方向是 `docgov → docrevision`。直接用途集中在 Markdown canonicalization 与 SHA helper;`docrevision` 不生产 import `docgov`。
目标不是“破双向环”,而是把 canonical Markdown + digest 提取为有行为、内聚、带 golden vectors 的共享模块,例如 `internal/doccontent`。它不应进入只放无行为值对象的 vocabulary。
### 3.3 chat、coordinator 与 intent
- coordinator 仍以 `bizdev.TaskRunRequest/Result` 为词汇。
- chat 编排跨多个模块,需按用例逐批迁入 chatflow。
- intent 与 bizdev 的解绑是较小且独立的迁移,不应和 chat 大迁移绑成一个分支。
### 3.4 闭包桥与未接线事件
当前批准后的推进与通知仍可通过 `docrevision.OnOutbox`、`docgov.AddOnApprovedHook` 及组合根闭包执行。闭包在提交后的进程内调用不能提供 durable delivery、重试、dead-letter、replay 或 attempt audit。
不能直接删除闭包。正确顺序是:
1. 证明生产入口在同一 UoW 写入领域变化、envelope 和目标 delivery。
2. 对历史事件做 dry-run inventory,隔离 scope/schema/sequence 异常。
3. 完成真实 PG dispatcher。
4. shadow 只计算 intended outcome,不执行业务副作用。
5. 以时间、样本和状态分支覆盖作为切换门。
6. 按 notify、workflow advance、projection 独立切换和回滚。
## 4. 并发、数据与权限风险
### 并发
- `FOR UPDATE SKIP LOCKED` 只有在 claim 事务同时更新 lease owner/token/until 并 RETURNING 时才完成所有权转移;当前 SELECT-only `ClaimIDs` 不够。
- Fencing 不能只保护 ack。token 必须进入 consumer command,并在数据库副作用或 projection marker 的最终提交点校验。heartbeat 失败应取消 handler。
- 同一 consumer/aggregate 最多一个 inflight;不同 aggregate 并行。领域版本可能稀疏,不能直接当无缺口事件序号。
- at-least-once delivery 通过 inbox/唯一键/CAS/no-replace 得到 exactly-one visible outcome;不能声称 delivery 本身 exactly once。
### 历史数据
旧记录可能含 project 0、错误 environment、未知 consumer、未知 payload schema 或稀疏 aggregate version。启用 live claim 前必须生成 manifest,并分类 safe/repair/quarantine/expire。任何修复保留 old/new digest、operator、reason、approval;本计划不删历史数据。
### 权限
后台 consumer 使用按 env/consumer/action 约束的 service principal。处理事件时按 ProjectID/DocID 重读资源归属、成员/duty、workflow config revision、活动 stage 和当前状态。事件 actor 只用于审计,不能把历史用户权限带到延迟执行时。
Replay 必须是应用用例:管理员 capability、精确范围、reason/approval、dry-run plan digest、apply exact digest 和不可变审计。多项目或批量 apply 需要操作者与批准人分离。
日志、dead-letter 和 reconciliation 只能保存 ID、digest、typed error code 与字段 allowlist 生成的摘要,不能保存原始 payload、正文、SQL error、绝对路径、token 或 prompt。
## 5. 优先级建议
### P0:Track E 持久事件交付
1. 修正 docflow 生产入口、env/project 作用域和 UoW 原子写。
2. 补全既有 event allowlist 与 runtime registry parity。
3. 审计历史事件、sequence/checkpoint 模型和现有唯一约束。
4. 实现 `cmd/events` 的 PG lease/heartbeat/fencing/attempt/dead-letter。
5. notify、workflow advance、projection 逐个 shadow、live、回滚。
6. 用真实 browser + PG + worker restart 证明刷新后正文恢复,无 projection-missing。
### P1:Track S 结构解耦
- D4:bizdev locator 调用方迁移与最终 getter 原子删除。
- D5:stageflow 自有 use-case 类型,coordinator 解绑 bizdev DTO。
- D6:提取 doccontent canonical 行为模块,移除单向工具依赖。
- D7a:intent 单独解绑 bizdev。
- D7b:chat 按用例迁入 chatflow。
这些单元分别 go/no-go,不作为事件可靠性 blocker 的关闭条件。
### P2:Track P 独立协议
- HTTP/SSE 错误信封另立 remediation;公开 details 必须按 code allowlist 并脱敏。
- PI Runner 任务命名为 typed-result-v1 rollout,不混称“协议 v2”。typed 字段存在但无效时 fail closed;只有字段缺失且握手声明旧 Runner 时才允许 legacy。
## 6. 证据索引
| 事实 | 证据 |
|---|---|
| 模块化单体决策 | `.doc/adr/2026-09-14-modular-monolith-decoupling.md` |
| PG delivery 当前实现 | `internal/events/pg.go`、`deploy/postgres/goose/00035_2026-09-14-durable-event-delivery.sql` |
| MemoryBus 测试边界 | `internal/events/dispatcher_test.go`、`internal/events/bus.go` |
| replay 当前校验 | `internal/events/replay.go` |
| 事件字段硬编码 | `internal/app/docflow/commands.go` |
| 闭包桥 | `internal/app/docnotify/subscriber.go`、`internal/docgov/engine.go`、`internal/app/app.go` |
| bizdev locator | `internal/bizdev/service.go:229-260` |
| 单向 canonical 依赖 | `internal/docgov/lease.go`、`internal/docrevision` canonical helper |
| allowlist 已存在 | `.doc/system-design/module-boundaries.yaml` |
## 建议动作
下一项只立 Track E 的 E0A:事件生产、契约与历史数据门。Dispatcher 必须保持 off,直到 PG 测试证明事件源和旧数据分类正确。完整执行计划见 [Phase 2 持久事件交付与后续解耦路线](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)。
@@ -0,0 +1,54 @@
---
title: "P0 PI Runner typed-result 兼容矩阵"
created: 2026-09-15
status: done
confidence: high
---
# 调研:P0 PI Runner typed-result 兼容矩阵
## 结论
当前 `/v1/run` 远程响应与本地 bridge stdout **都不是** `result_v1`。Go 只解析 `ok/fallback_reason/stderr/retryable/patches[]`;成功路径再 `MaterializeTargets`。仓库里没有 `configs/schemas/pi-run-result-v1.json`。typed 字段一旦出现但非法必须 fail closed;本盘点确认 legacy 窗口仍是默认路径。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 远程调用 | `internal/agent/piagent.go` `executeRemote` | `POST {runnerURL}/v1/run`;Bearer via `ApplyRunnerAuth` |
| 远程解码 | 同上 `remoteResp` | `ok`, `fallback_reason`, `stderr`, `retryable`, `patches[].rel_path/content` |
| 本地 bridge | `PiAgentBackend.Execute` | stdin JSON payload;stdout **最后一行** JSON;失败把 `stderr` 拼进 `ErrorReason` |
| 产物 | `MaterializeTargets(workDir, req.Targets, incoming)` | 默认 target `output.md` |
| 既有 schema | `configs/schemas/` | 仅 `change-report-v1.json`,无 run-result |
| 取消/超时 | `CommandContext` + `http.Client{Timeout}` | 超时进 `ErrorReason`;无单调终态结构体 |
| Handshake | 无 | 未声明 typed capability,故今日全部算旧 Runner |
## 兼容矩阵
| Runner 形态 | 成功输出 | 失败输出 | Go 行为 | P1/P2 约束 |
|-------------|----------|----------|---------|------------|
| 远程 HTTP `/v1/run` | `ok=true` + patches | `ok=false` + fallback/stderr | 解码失败即失败;不读 `result_v1` | P1 additive 加 `result_v1`;P2 typed-present-invalid 禁止 fallback |
| 本地 bridge 二进制 | stdout 末行 `{ok}` | `ok=false` 或进程 err | 整段 stdout 进 `Logs` | Logs 不得含 prompt/token;P1 后 Logs 只留 digest |
| stub | 内存产物 | 分类失败 | 测试夹具 | 不作为真实 PI 证据 |
| 未知 major / 缺 schema | — | — | 今日不会发生 | P2 fail closed |
## 体积与路径风险
- patches `Content` 无 body/member 上限;P1 必须在分配前限制。
- `RelPath` 未在 adapter 层拒绝 `..` / 绝对路径(依赖 `MaterializeTargets`);P1 负例要覆盖 symlink escape。
- `ErrorReason` 拼接 `stderr`,可能带模型/路径;公开日志禁止原样落盘。
## 取消与竞争
- HTTP client timeout 与 context cancel 共用;无独立 cancel token 与 result 的 CAS。
- P3 真实 PI E2E 必须覆盖:成功、typed error、取消、超时、未知 schema。
## 开放问题
- 真实容器内 Runner 镜像版本与是否已能吐 `result_v1` 需 P1 时对一下 pi-agent 镜像,不阻塞立项。
## 建议动作
- P1:共享 JSON Schema `configs/schemas/pi-run-result-v1.json`;Runner additive 输出。
- P2:Go typed-first parser;handshake 声明旧 Runner 才允许 legacy。
- 实施见 [PI typed-result-v1](../../remediation/2026-09-15-pi-typed-result-v1-remediation.md)。
@@ -0,0 +1,35 @@
---
title: "Track E 持久事件交付复盘"
created: 2026-09-15
status: done
confidence: high
---
# 调研:Track E 持久事件交付复盘
## 结论
E0A–E1C 已在隔离库证明:领域变化、envelope、delivery 同 UoW;PG dispatcher 原子 lease/fencing;notify / workflow_advance / projection 各自 exactly-one visible outcome。共享集群消费者保持 **off**,HTTP 闭包仍是唯一真实写者。E2 已部署兼容守卫:消费者 `live` 时闭包停写,`off`/`shadow` 时闭包继续写。删除 `OnOutbox` / `AddOnApprovedHook` 必须等 live 发布窗口;当前删除会让 notify/advance 停写。`DOC-RELIABILITY-PILOT` 保持 OPEN。FAV 保持 disabled。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| E0A | [E0A 报告](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md) | PASS;dispatcher off;FAV 不写入 |
| E0B | [E0B 报告](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md) | PASS;1/2/4 worker;旧 token 失败 |
| E1A | [E1A 报告](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md) | 隔离库 unique notify PASS;共享 off |
| E1B | [E1B 报告](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md) | 隔离库 unique stage-ready PASS;共享 off |
| E1C | [E1C 报告](../../test-reports/2026-09-15-event-e1c-projection-test-report.md) | no-replace PASS;共享 off |
| E2 | [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md) | live 停写;off/shadow 仍写;API 保留 |
## 开放问题
- 共享环境尚未做 notify/advance/projection 的 live 切换与授权页刷新纵切,因此 Track E DoD 中「生产注册无 OnOutbox=」与「授权 UI 三类重启」未关闭。
- 历史 inventory 的 repair/quarantine 真实批量审批未在共享库演练。
- FAV 仍只预留 disabled 契约。
## 建议动作
- 下一窗口:按消费者独立 shadow coverage → drain → live,闭包因 E2 守卫自动停写;确认 backlog 与 receipt 后再删 hook API。
- Track S 从 D6(`internal/doccontent`)开始,不占用 events mutex。
- Track P 保持独立 remediation,不阻塞事件交付。
@@ -0,0 +1,54 @@
---
title: "文档可靠性 M1 活验签字与条件 M2"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Cursor
branch: refactor/document-reliability-pilot
worktree: .worktrees/refactor-document-reliability-pilot
mutex: workspace
---
# 文档可靠性 M1 活验签字与条件 M2
## 目标
占集成槽把试点合入本地 `dev` 并 rebuild,补齐真实 PI / 浏览器 / 跨用户 / 多会话签字。仅当新报告最后一句为「继续 M2」时开工 U5–U7。
## 范围
- A1 占槽、合入、rebuild、health/ready
- A2 143 只读 + 新建项目页面 + fail-closed
- A3 真实 pi-agent 编制后刷新
- A4 隔离库双 pool / 4 会话
- A5 活验 go/no-go
- B 仅 go 后:U5–U7
## 非目标
- 不终止项目 143
- 未 go 不开 outbox/FAV
- 不拆 chat/squad
## 步骤
1. [x] 占集成槽并合入本地 dev rebuild
2. [x] 浏览器 + 跨用户
3. [x] 真实 PI
4. [x] 双 pool/4 会话
5. [x] 活验报告(最后一句:继续 M2)
6. [x] 条件 M2(U5–U7)
## 验收标准
- [x] health + ready 来自本分支镜像
- [x] 143/新项目刷新 404/409/projection-missing = 0 或报告停止扩面
- [x] 报告最后一句只能是继续 M2 或停止扩面
- [x] M2 报告最后一句只能是继续 M3 或停止扩面
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Prior report: [../../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-test-report.md)
- Live report: [../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md)
- M2 report: [../../test-reports/2026-09-14-document-reliability-m2-test-report.md](../../test-reports/2026-09-14-document-reliability-m2-test-report.md)
@@ -0,0 +1,64 @@
---
title: "文档可靠性纵向试点 M0–M1"
status: blocked
created: 2026-09-14
updated: 2026-09-14
owner: Cursor
branch: refactor/document-reliability-pilot
worktree: .worktrees/refactor-document-reliability-pilot
mutex: docgov
---
# 文档可靠性纵向试点 M0–M1
## 目标
在不横向搬包的前提下,完成 U1–U4,使受控文档在并发提交、页面刷新、重登、restart、rebuild 和 projection 缺失后仍从数据库账本返回唯一授权正文。
## 范围
- U1 架构基线与 production writer/path 门禁。
- U2 应用 UnitOfWork 和跨属主事务能力。
- U3 人工编辑、agent commit、批准/驳回事务化。
- U4 授权后的文档统一读模型。
- 项目 143 等价脱敏 hazard 与新项目真实 PI/UI 验收。
## 非目标
- 不启用 FAV degraded read。
- 不拆 chatlog/contextasm/squadrun 包。
- 不统一错误信封,不修改 PI Runner 协议。
- 不清理历史 dev 数据。
## 步骤
1. [x] 从最新 `dev`(`a8f9451`)创建实现分支,登记 CURRENT 并确认 `docgov` mutex 已释放。
2. [x] U1:四类规则 arch-check + archtest + 可重放基线(新违规 block)。
3. [x] 实现 U2,验证任意属主写入/commit 故障整体回滚。
4. [x] 实现 U3,删除提交后 outbox 正确性回调。
5. [x] 实现 U4,保证 GET 零写入和 projection 缺失不再伪装成 404。
6. [x] 隔离库 PG + 目标包 race 已跑;真实 PI / 浏览器 / rebuild **未**签字(未占槽)。
7. [x] 写 test report:结论 **停止扩面**。更新验收清单、FEATURE-MATRIX、CURRENT 和 gap-matrix。
## 验收标准
- [x] 同一 ETag 并发编辑只有一个合法赢家(内存 8 协程 + 隔离库双会话)。
- [x] 任一事务故障点不会留下部分提交(U2 隔离库)。
- [ ] 项目 143 等价 hazard 和新项目刷新/重启目标 404/409/projection missing 为 0(真实页面未测)。
- [x] 服务端匿名/未知文档/跨项目/错误责任人 fail closed;浏览器跨登录未测。
- [ ] 1、2、4 个 app 实例的最终状态一致(仅到双会话)。
- [x] M1 test report 结论:**停止扩面**。
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Test report: [../../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-test-report.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
## M2+ 门(不开工)
U5 WorkspaceRef、U6 outbox、U7 按文件摘 FAV 需要独立审批,且仅当 M1 报告最后一句为「继续 M2」。当前是「停止扩面」,禁止实现 U5–U12。
## 证据 / 备注
隔离库与目标包 race 见 test-report assets。未占槽、未 rebuild。只有真实 PI/浏览器/rebuild 补测并把报告改为「继续 M2」后,才允许启动 durable event/FAV。
@@ -0,0 +1,105 @@
---
title: "多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)"
status: done
created: 2026-09-15
updated: 2026-09-16
owner: Cursor
branch: "-"
worktree: "-"
mutex: "-"
---
# 多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)
## 目标
不回退现有模块解耦、单意图行为和权限边界,交付可持久、可恢复、可并发裁决的 2–4 步计划;所有批量生成/写入/控制确认前零副作用,执行前逐动作重新授权。
## 权威文档
- [详细设计与计划](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- [复核审计](../../audit/2026-09-15-multi-intent-hitl-plan-review.md)
- [模块边界 SSOT](../../system-design/module-boundaries.yaml)
## 强制约束
- `internal/intent` 继续只依赖 `maturity`;新生命周期归 `internal/app/intentflow`;
- 确认不是授权;每步由动作 owner 按当前主体、状态和版本重新鉴权;
- PG plan state 权威,卡片/SSE 仅投影;
- 每步一个业务事务,不做跨模块长事务;
- 中间结果不进 FAV;
- 新行为从 legacy/shadow 开始,回滚不丢已有计划。
## 波次
| 波次 | 单元 | 交付 | 依赖 | 主 mutex | go/no-go |
|------|------|------|------|----------|----------|
| W0 | U1 | 模块/API/状态/事件契约 | 无 | `intent`,`events` | arch/event/table owner 全绿 |
| W1 | U2 | 纯规则提案 shadow | U1 | `intent` | 不改路由,安全错误为 0 |
| W2 | U3 | intentflow + PG/CAS/lease | U1,U2 | `intent-plan` | 两 worker 无双 owner/执行 |
| W2 | U4 | outbox + 投影 | U3 | `events` | projection diff=0 |
| W3 | U5 | decision API + 授权端口 | U3 | `intent-plan`,`server/authz` | 权限负例全绿 |
| W3 | U6 | Web 卡片/刷新/a11y | U4,U5 | `web` | 双标签/reload 无假成功 |
| W4 | U7 | 低风险只读执行 | U4-U6 | `intent-plan`,`chat` | legacy 无回归 |
| W4 | U8 | task generate adapter | U7 | `taskrun`,`intent-plan` | 首版 real PI 闭环 |
| W5 | U9 | 可选 LLM adapter 实验 | U2,U7 | `intent-plan`,`pi-agent` | 不阻塞首版;达阈值才启用 |
| W5+ | U10 | low mutate 逐 action 扩面 | U8 | 实际 owner | 单 action 签署 |
| W5+ | U11 | docgov 逐 action 扩面 | U8 | `docgov`,`intent-plan` | 单 action 签署 |
| W5+ | U12 | workflow/run-control 分项扩面 | U8 | `workflow`/`taskrun` | 分项签署 |
> 本文件仅是总览,不长期占用一个 mutex。实施时每个 U-ID 新建独立 short-term、分支和认领;U10–U12 还必须按 action 拆分。核心首版为 U1–U8,U9 与后续 owner 扩面不阻塞首版关闭。
## 步骤
1. [x] U1 冻结边界、状态机、批量策略、错误码、事件和默认 legacy tier([独立任务](./2026-09-15-multi-intent-u1-contracts.md);[报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md));
2. [x] U2 characterization-first 建 golden/hard-negative 与 shadow 基线([独立任务](./2026-09-15-multi-intent-u2-segmenter.md);[报告](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md));
3. [x] U3 建 intentflow owner、PG schema、CAS/lease/fencing/retention([独立任务](./2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md));
4. [x] U4 接 Track E outbox/dispatcher,只投影状态事实([独立任务](./2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md));
5. [x] U5 建统一 decision command 与动作 owner 授权端口([独立任务](./2026-09-16-multi-intent-u5-decision-api.md);[报告](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md));
6. [x] U6 取消计划动作的前端本地成功路径,以 PlanView 恢复([独立任务](./2026-09-16-multi-intent-u6-web-cards.md);[报告](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md));
7. [x] U7 只开放独立低风险查询([独立任务](./2026-09-16-multi-intent-u7-auto-read.md);[报告](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md));
8. [x] U8 只接 task generate,完成首版闭环(真实 PI 环境缺失记 stop-gate)([独立任务](./2026-09-16-multi-intent-u8-task-generate.md);[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md));
9. [ ] U9 作为独立可选实验接语义分段;
10. [ ] U10–U12 分别按 mutate/docgov/workflow/run-control owner 扩面。
## 验收标准
- [ ] 含写/生成/控制时,确认前相关表、任务、文档和工作流零变化;
- [ ] 两标签确认/取消只产生一个决策和至多一次动作;
- [ ] 服务/worker 重启后 PG 恢复,成功步骤不重跑;
- [ ] 确认后权限或资源版本变化时 fail closed;
- [ ] 跨用户/项目/会话读取和决策被隐藏;
- [ ] 按钮与自然语言确认得到同一服务端 receipt;
- [ ] intent 边界、单一写者、UoW、事件静态契约和组合根无回退;
- [ ] 无活动计划时单意图生成保持;有活动计划时不创建第二任务;多意图生成需确认;
- [ ] 部分确认可稍后处理未选项,只有显式排除才取消;部分完成可重试、继续或关闭;
- [ ] 双标签/刷新/重开/SSE 重连真实页面通过;
- [ ] 适用的真实 PI E2E 通过,stub 不冒充验收。
## 非目标
- >4 步、并行 DAG、多活动写计划自动合并;
- 跨步骤 ACID/自动补偿;
- coordinator/chat 全量重构;
- FAV 启用或中间产物归档;
- 改变单意图生成策略。
## 交付纪律
- 每单元记录精确边界影响、适用测试、go/no-go、回滚、branch/commit/merge/push 状态;
- 每单元独立 test report、CURRENT 认领/集成槽和 FEATURE-MATRIX 回链;
- 安全、越权、双执行或刷新差异任一出现,停止当前 tier;dispatcher 故障只停投影;LLM 故障进入澄清。
## 相关链接
- Checklist: [U1](../checklists/2026-09-15-multi-intent-u1-contracts.md);[U2](../checklists/2026-09-15-multi-intent-u2-segmenter.md);[U3](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md);[U8](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
- Handoff: 每个 U-ID 独立建立
- Test report: [U1](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md);[U4](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md);[U5](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md);[U6](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md);[U7](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md);[U8](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
## 证据 / 备注
- 当前 `plan_builder.go` 最多两段且写意图返回 nil;`action_planner.go` 的确认仍是文字提示。
- 当前 `module-boundaries.yaml` 中 intent 仅依赖 maturity;Track E live,FAV off。
- U1 已冻结 intentflow 契约、事件与 BatchActionPolicy,默认 `MULTI_INTENT_PLAN_TIER=legacy`。
- U2 已落地规则分段与 shadow `PlanProposal`;生产 TopIntent / IntentPlan 不变;反事实 `false_auto_execute=0`。
- U8 已落地 confirm 落盘与 `task.run` adapter;默认 legacy 不落盘。U9–U12 不阻塞核心首版。共享环境 schema 45 待晋升窗口。
@@ -0,0 +1,76 @@
---
title: "多意图 HITL U1:契约冻结"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u1-contracts
worktree: "-"
mutex: architecture-docs
---
# 多意图 HITL U1:契约冻结
## 目标
冻结 `app/intentflow` 边界、状态机、BatchActionPolicy、错误码、事件契约与默认 `legacy` tier;不改识别路由、不建表、不接 HTTP。
## 范围
- `module-boundaries.yaml`:`app/intentflow` allowlist、三表 owner、`unwrap_owners`、三条 `intent.plan.*` 事件
- `events.StaticContracts` 与 YAML 对等;archtest 扫描 `intent.plan.*`
- `internal/app/intentflow` 骨架:状态、错误码、Service 端口、政策、tier 开关
- CSRF/认证结论:现有 Bearer + CORS 对 U5 足够,不是 blocker
## 非目标
- 不修改 `internal/intent` 业务类型或 `MULTI_INTENT_ENABLED`
- 不建 Goose 表、不接线 `app.Assemble`、不改 chat/coordinator/Web
- 不 Append 事件、不实施 U2–U12
## REST(U5 再挂路由)
- `GET /api/v1/intent-plans/active`
- `GET /api/v1/intent-plans/{plan_id}`
- `POST /api/v1/intent-plans/{plan_id}/decisions`
- body:`expected_revision`、`decision_nonce`、`decision_digest`、`kind`、步骤选择
## CSRF / 认证(U5 前置结论,非 blocker)
现有认证是 `Authorization: Bearer` 或 `X-Session-Token` 请求头(`internal/server/auth_handlers.go`),无 cookie 会话,无独立 CSRF 中间件;另有 Origin allowlist CORS。
- 自定义头不会被浏览器跨站表单自动带上,现有模式对 U5 足够
- `decision_nonce` / 幂等键只防重放与并发,**不替代** CSRF 或身份认证
- U5 必须 `requireAuthenticatedUser` + 四元作用域(environment/project/session/user)
- **禁止**为计划 API 改成 cookie 自动提交
- 若未来改 cookie 认证,另立 auth 任务,不得在 intent-plan 端点发明弱 CSRF
## 步骤
1. [x] 从最新 `dev` 检出 `feature/multi-intent-u1-contracts` 并认领 CURRENT
2. [x] 登记边界 YAML、事件契约、archtest regex
3. [x] 落地 intentflow 骨架与 BatchActionPolicy
4. [x] arch/parity/short 测试与 U1 报告
## 验收标准
- [x] `intent -> maturity` 保持;server/chat 不直写计划表
- [x] YAML ↔ StaticContracts parity 绿
- [x] 未知 action/policy key fail closed;ActionRegistry 无 batch/tier 字段
- [x] 默认 `MULTI_INTENT_PLAN_TIER=legacy`
- [x] 单意图生成策略不变(本单元无运行时改动)
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u1-contracts.md](../checklists/2026-09-15-multi-intent-u1-contracts.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
## 证据 / 备注
- 事件登记窗口同时占用 `events` mutex;U1 不改 intent 代码。
- 生产者含 `events`:StaticContracts 字面量落在 `internal/events/registry.go`,与现有 document.* 先例一致。
- CSRF:Bearer / `X-Session-Token` + CORS allowlist,U5 非 blocker。
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U1 无 schema/容器变更,集成槽位保持 idle。
- 提交:`bdccb4d` docs(ops);`aefb1e4` feat(events);`9364da4` feat(intentflow);随后 docs(status)。
@@ -0,0 +1,63 @@
---
title: "多意图 HITL U2:规则分段与 shadow 提案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u2-segmenter
worktree: "-"
mutex: intent
---
# 多意图 HITL U2:规则分段与 shadow 提案
## 目标
在不改变生产路由(TopIntent / 现有 IntentPlan)的前提下,用纯规则分段器生成 2–4 步 `PlanProposal` 与 shadow 指标;写段不再在提案层被静默丢弃。
## 范围
- `internal/intent/segmenter.go`:连接词/句号/分号/换行/序号/先再最后,上限 4
- `PlanProposal` L1 值对象:span、证据、缺槽、依赖建议、稳定 digest
- Recognize 附加提案与 shadow;**不**改 coordinator 执行路径
- golden / hard-negative / 反事实(若处于 auto_read 会如何)
## 非目标
- 不建 PG、不接 HTTP、不改 Web
- 不把 HITL/tier 回灌 ActionRegistry
- 不启用 LLM 分段(U9)
- 不把 shadow 提案当作生产 IntentPlan
## 步骤
1. [x] 认领 CURRENT,characterization 锁定现有 IntentPlan
2. [x] 分段器 + PlanProposal + digest
3. [x] 接入 Recognize(leaf 识别防递归)
4. [x] golden/hard-negative/反事实与报告
## 验收标准
- [x] 「查风险,然后查法规」现有 IntentPlan 仍为 2 步 query
- [x] 「查法规然后生成报价单」生产 IntentPlan 仍为 nil(路由不变),提案含写段且 ComboHint=needs_confirm
- [x] 「查询并总结」不拆
- [x] 指代失败 → needs_clarify
- [x] 红线混入 → rejected
- [x] 5 段 → rejected_batch_size
- [x] 同输入 digest 稳定
- [x] 反事实错误自动执行 = 0
- [x] `intent -> maturity` 保持
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u2-segmenter.md](../checklists/2026-09-15-multi-intent-u2-segmenter.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
## 证据 / 备注
- L1 不 import intentflow;`ComboHint` 只是结构提示,不是授权。
- 单段复用 primary frame,避免二次 Recognize。
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U2 无 schema/容器变更。
- 提交:`4751348` docs(ops) 认领;`9005766` test(intent) characterization;`932ba87` feat(intent) 分段器与 shadow 提案。
@@ -0,0 +1,68 @@
---
title: "多意图 HITL U3:intentflow PG/CAS/lease"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u3-intentflow-pg
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U3:intentflow PG/CAS/lease
## 目标
建立持久计划/步骤/决策与并发协议(CAS revision、decision nonce、lease/fencing、创建幂等、retention);不接真实写动作,不改 chat/coordinator 生产路由。
## 范围
- Goose `00044`:`intent_plans` / `intent_plan_steps` / `intent_plan_decisions`
- `app/intentflow` owner repository + UoW;owner 可 unwrap pgx
- 创建幂等 `(environment, session_id, client_turn_id)`;同 turn 异 digest 冲突
- 决策 CAS + nonce 同/异 digest;确认/取消/过期竞态
- 步骤 lease + 单调 fencing;两 worker 只一个 owner
- 业务成功但 receipt 写回失败时按幂等键对账,不盲跑
- 环境隔离;关闭计划 retention 由 owner 删除
- `app.Assemble` 装配 `*intentflow.Plans`,chat 仍不调用
## 非目标
- 不接 HTTP(U5)、不 Append 事件(U4)、不接真实 action adapter(U7/U8)
- 不把 HITL/tier 回灌 ActionRegistry
- 不改 `internal/intent` 生产 TopIntent / IntentPlan
- 不 rebuild 共享 `:8080`(schema 44 仅隔离库/后续晋升窗口应用)
## 步骤
1. [x] 认领 CURRENT(mutex `intent-plan`)
2. [x] Goose 00044 + migrate gate
3. [x] Store/Engine:Create/Decide/Claim/Receipt/Expire/Purge
4. [x] 内存并发 + 可选 PG 测试;Assemble 接线
5. [x] 报告并合回本地 dev
## 验收标准
- [x] 双创建同 digest 返回同一 plan;异 digest 冲突
- [x] nonce 同 digest 返回 receipt;异 digest 冲突
- [x] 确认/取消/过期只一个 CAS 胜出
- [x] 两 worker 抢 eligible 步骤无双 owner
- [x] 租约过期可接管;旧 fencing token 被动作属主拒绝
- [x] 重启后 succeeded 不重跑;receipt 写回失败按幂等键恢复
- [x] 跨 environment 隐藏
- [x] 默认 legacy 时 HandleTurn 不落盘
- [x] `go test -short ./internal/app/intentflow ./internal/app ./internal/archtest ./internal/db` 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md)
## 证据 / 备注
- HandleTurn 在默认 legacy 下不落盘;CreatePlan 是 U3 测试与后续 U7 入口。
- 动作属主端口仅 FakeActionOwner;真实 adapter 从 U7/U8 按 key 接入。
- PG 活验需隔离 `TEST_DATABASE_URL`;本机 short 门禁跳过。共享 `:8080` 仍 schema 43。
- 提交:`a75aa45` docs(ops) 认领;`7dfd6d6` feat(db);`da0b3d8` feat(intentflow);`1385002` feat(app)。
@@ -0,0 +1,51 @@
---
title: Demo/测试数据污染全面整改
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: fix/demo-data-pollution-web
worktree: "-"
mutex: web
---
# Demo / 测试数据污染全面整改
## 目标
消除前端 mock/seed 与 DB 演示项目对真实项目清单的污染;生产包无演示文案;main 拒 stub。
## 范围
- Wave 0–5 代码 + Wave 6 文档(本分支合并实现)
## 非目标
- 删除合法 `*.test.ts` fixture
- 改写工作流模板骨架
## 步骤
1. [x] Wave 0 止血
2. [x] Wave 1 门控
3. [x] Wave 2 localStorage 迁移
4. [x] Wave 3 UI 语义
5. [x] Wave 4 DB retire
6. [x] Wave 5 stub gate
7. [x] Wave 6 文档
## 验收标准
- [x] `check-prod-bundle.sh` PASS
- [x] deliverableSync / demoSeedIds / ResolveBackend 单测 PASS
- [x] `cd web && npm test` 全绿(审核 P0)
- [x] 00046/00047 retire + ListChatSessions 过滤(审核 P1)
- [x] 合入后共享环境 migrate + 人工空项目/会话抽检(dev schema 47;项目 6357 docs=0;列表无 6001–6010 / sess-wangjing)
## 相关链接
- Audit: [.doc/audit/2026-09-16-demo-seed-pollution-systemic.md](../audit/2026-09-16-demo-seed-pollution-systemic.md)
- 前序 Audit: [.doc/audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
- Remediation: [.doc/remediation/2026-09-16-demo-seed-pollution-remediation.md](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
- Test report: [.doc/test-reports/2026-09-16-demo-seed-pollution-test-report.md](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
- 挑拣:`a91a031` `SEED_DEMO_USERS=false`(自 `fix/clean-test-env-baseline`)
@@ -0,0 +1,49 @@
---
title: "FEATURE-MATRIX 深度测试 + 晋升部署 test"
status: in_progress
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: feature/matrix-deep-test-promote-test
worktree: "-"
mutex: infra
---
# FEATURE-MATRIX 深度测试 + 晋升部署 test
## 目标
按 FEATURE-MATRIX 对已实现模块做分层深度回归,通过后将本地 `dev` 晋升到 `test`(`rc-v1.0.0-beta.2`)并 rebuild/冒烟 `:8081`。
## 范围
- Wave 1:vet/short/arch/npm/bundle + 模块定向 + 隔离治理 PG
- Wave 2:dev `:8080` live API 抽检
- Wave 3:真实 PI 抽样(失败再升格三链)
- Wave 4:`dev` → `test` + rebuild + smoke
- Wave 5:测试报告 + SSOT
## 非目标
- 不实现纯软件项目自举
- 不默认 28min 三工作流 PI;不合 `main`;不改项目 143;不启用 FAV
## 步骤
1. [ ] 认领占槽
2. [ ] 自动化深度回归
3. [ ] live `:8080` 抽检
4. [ ] PI 抽样
5. [ ] 晋升 test 并冒烟
6. [ ] 报告与归档
## 验收标准
- [ ] 矩阵已实现行均有 PASS 证据
- [ ] `:8081` health/ready schema=47;`test-env-smoke.sh` PASS
- [ ] tag `rc-v1.0.0-beta.2`;报告归档
## 相关链接
- Plan: matrix_deep_test_promote
- FEATURE-MATRIX / CURRENT / gap-matrix
@@ -0,0 +1,51 @@
---
title: "多意图 HITL U4:outbox 与计划投影"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u4-outbox-projection
worktree: "-"
mutex: events
---
# 多意图 HITL U4:outbox 与计划投影
## 目标
权威计划在同一 UoW 写入 outbox;投影只应用状态事实;消息/SSE 丢失时 GET PlanView 仍能恢复。不改 dispatcher claim/lease/retry 语义。
## 范围
- Create/Decide/Receipt 同事务 Append `intent.plan.*`
- 最小 payload + golden;伪造 producer 拒绝
- projection consumer 幂等、只前进 revision;跨用户不可见
- ctxmgr 只经 CardProjector 端口(接口在 intentflow,实现可 no-op)
- 复用 Track E LiveConsumers
## 非目标
- 不改通用 dispatcher
- 不挂 HTTP(U5)、不改 Web(U6)、不执行动作(U7)
## 步骤
1. [x] 认领 CURRENT(mutex `events`)
2. [x] emit + golden + 投影只前进
3. [x] cmd/events 接入 multiplex;goose shadow
4. [x] 报告并合回本地 dev
## 验收标准
- [x] 创建计划产生 awaiting_input;payload 无 prompt/slots
- [x] 重复 event_id 不双写投影
- [x] 乱序低 revision 不覆盖高 revision
- [x] 伪造 producer 拒绝
- [x] GET PlanView 不依赖投影成功
- [x] arch-check / short 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- Checklist: [../checklists/2026-09-16-multi-intent-u4-outbox-projection.md](../checklists/2026-09-16-multi-intent-u4-outbox-projection.md)
- Test report: [../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md)
@@ -0,0 +1,54 @@
---
title: "多意图 HITL U5:决策 API 与授权端口"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u5-decision-api
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U5:决策 API 与授权端口
## 目标
按钮与自然语言走同一 `DecidePlan` 命令;GET 发现活动计划不依赖投影;执行前由动作属主重新授权。确认不是授权。
## 范围
- 冻结路径:`GET /api/v1/intent-plans/active`、`GET /api/v1/intent-plans/{plan_id}`、`POST /api/v1/intent-plans/{plan_id}/decisions`
- Principal 只从认证会话 + query 的 project/session 组装,忽略 body 中的 user/project/session
- 四元作用域;非成员 403;跨 session/user 隐藏为 404
- 系统管理员不得绕过项目成员检查
- `StepAuthorizer` 端口 + Fake/dry-run;确认与执行前鉴权
- expected revision、nonce、依赖闭包、edit 升 revision
## 非目标
- 不接真实业务属主 adapter(U7/U8)
- 不改 Web(U6)、不改默认 legacy HandleTurn
- 不 rebuild 共享 `:8080`
## 步骤
1. [x] 认领 CURRENT(mutex `intent-plan`)
2. [x] 授权端口与 confirm/execute 即时鉴权
3. [x] HTTP handlers + 权限负例
4. [x] 报告并合回本地 dev
## 验收标准
- [ ] 投影缺失仍能 GET active
- [ ] 未登录 401;非成员 403;跨项目/会话/用户隐藏
- [ ] stale revision 409;重复 nonce 同 digest 同 receipt
- [ ] 非法部分确认拒绝;edit 使旧 revision 失效
- [ ] 确认前零副作用;权限撤销/资源版本 fail closed
- [ ] 无系统身份绕过
- [ ] `go test -short` 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-16-multi-intent-u5-decision-api.md](../checklists/2026-09-16-multi-intent-u5-decision-api.md)
@@ -0,0 +1,47 @@
---
title: "多意图 HITL U6:Web 卡片、刷新与可访问性"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u6-web-cards
worktree: "-"
mutex: web
---
# 多意图 HITL U6:Web 卡片、刷新与可访问性
## 目标
UI 只呈现 PlanView;计划动作不走本地 AST/资源修改;刷新与双标签以 GET reconcile。
## 范围
- `PLAN_CONFIRM` 卡片类型
- intent-plans API client
- submitting/outdated/expired/conflict;409 看最新版
- App 计划动作 early-return,禁止本地成功路径
- Playwright 门控(无 `RUN_UI_ACCEPTANCE` 则 skip)
## 非目标
- 不接 auto_read 执行(U7)
- 不 rebuild 共享环境
## 步骤
1. [x] 认领 CURRENT
2. [x] 卡片/API/reconcile 与无 AST 路径
3. [x] 单元测试 + 门控 Playwright
4. [x] 报告并合回
## 验收标准
- [ ] 计划确认不修改 DocumentAST
- [ ] GET 可修复缺失投影
- [ ] 409 标 outdated 并带最新 PlanView
- [ ] 默认 Playwright skip
## 相关链接
- Checklist: [../checklists/2026-09-16-multi-intent-u6-web-cards.md](../checklists/2026-09-16-multi-intent-u6-web-cards.md)
@@ -0,0 +1,14 @@
---
title: "多意图 HITL U7:低风险只读执行"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u7-auto-read
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U7:低风险只读执行
HandleTurn 在 auto_read 下执行独立查询;默认 legacy 不变。QueryGuard 拒绝 generate。
@@ -0,0 +1,54 @@
---
title: "多意图 HITL U8:task generate adapter"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u8-task-generate
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U8:task generate adapter
## 目标
`confirm` tier 下查询+生成落盘 awaiting;确认后仅开放 `task.run` / `task.run.adhoc`,稳定幂等键,不改单意图 taskrun HTTP。
## 范围
- HandleTurn:`ComboNeedsConfirm` 且 tier≥confirm 时 WritePlan 落盘,不自动执行
- `OwnerMux` 把 generate 路由到 Task,其余走 QueryGuard
- `TaskRunAdapter` + `LiveTaskStarter`(无 `PI_AGENT_RUNNER_URL` 只占位不启 PI)
- Assemble 接线;默认 `MULTI_INTENT_PLAN_TIER=legacy` 不变
## 非目标
- U9 LLM 分段、U10–U12 owner 扩面
- 不 rebuild 共享环境、不改项目 143
- 真实 PI 闭环若环境缺失记 stop-gate,不冒充验收
## 步骤
1. [x] 从 `dev` 开 `feature/multi-intent-u8-task-generate`
2. [x] confirm 落盘 + mux + adapter
3. [x] 单测与 arch-check
4. [x] 报告并合回
## 验收标准
- [x] 多意图生成确认前零执行
- [x] 活动写计划冲突
- [x] 确认后 mux 执行 generate,重放 starts=1
- [x] QueryGuard 仍拒绝 generate;权限撤销 fail closed
- [x] 真实 PI 无 URL 时 skip(stop-gate)
## 相关链接
- Checklist: [../checklists/2026-09-16-multi-intent-u8-task-generate.md](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
- Test report: [../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
- Parent: [./2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
## 证据 / 备注
默认 legacy HandleTurn 仍不落盘。真实 PI 见报告 stop-gate。
@@ -61,5 +61,5 @@ updated: 2026-09-13
## 相关链接
- Audit: [../audit/2026-09-13-chat-history-refresh-disappears.md](../audit/2026-09-13-chat-history-refresh-disappears.md)
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
- gap-matrix 行: `CHAT-HISTORY-REFRESH`
@@ -1,8 +1,8 @@
---
title: "对话意图、可恢复任务状态与文档占用可见性整改"
status: in_progress
status: done
created: 2026-09-13
updated: 2026-09-13
updated: 2026-09-15
---
# 对话意图、可恢复任务状态与文档占用可见性整改
@@ -30,11 +30,10 @@ updated: 2026-09-13
## 验收标准
- [x] “总结一下用户初始需求表”返回已有文档摘要,不创建 `task_runs`。
- [ ] “开始编写用户初始需求表”只创建一个 run;运行中再次写请求不创建失败 run。
- [ ] 任务失败后刷新,错误码、诊断摘要及允许动作与刷新前一致。
- [ ] 运行中刷新,聊天占位、阶段进度、文档 busy 标识和输入保护均恢复。
- [ ] 租约释放/任务终态后 UI 自动解除 busy,无需用户手动刷新。
- [x] “开始编写用户初始需求表”只创建一个 run;运行中再次写请求不创建失败 run。
- [x] 任务失败后刷新,错误码、诊断摘要及允许动作与刷新前一致。
- [x] 运行中刷新,聊天占位、阶段进度、文档 busy 标识和输入保护均恢复。
- [x] 租约释放/任务终态后 UI 自动解除 busy,无需用户手动刷新。
- [x] 测试使用专用项目/会话并在 teardown 清理;禁止 `debug/test` 探针进入非 fixture 会话。
## 相关链接
@@ -0,0 +1,677 @@
---
title: "模块解耦与文档可靠性重构计划"
status: planned
created: 2026-09-14
updated: 2026-09-14
type: refactor
owner: TBD
deepened: 2026-09-14
---
# 模块解耦与文档可靠性重构计划
## Goal Capsule
- **Objective:** 项目文档、任务最终产物和最终智能体回复在并发写入、页面刷新、服务重启、工作区清理和受控恢复后仍能按权限定位到唯一、可校验的内容。
- **Means:** 采用模块化单体、纵向绞杀、应用 UnitOfWork、数据库互斥、transactional outbox、opaque workspace capability 和 FAV。
- **Authority:** 本计划受 [模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)、[文档版本边界 ADR](../adr/2026-09-13-document-version-boundary.md) 和 [工作流运行时权威 ADR](../adr/2026-09-12-workflow-runtime-authority.md) 约束。
- **Stop condition:** 任一里程碑出现数据不变量无法在单事务维持、授权只能通过放宽实现、旧数据无法安全迁移,或真实页面故障率没有下降时,停止扩面并回到设计评审。
- **Execution profile:** 高风险、跨模块、迁移和授权敏感;characterization-first,逐纵向切片发布。
- **Delivery:** 每个里程碑独立 short-term、独立分支和独立验收报告;本计划本身不授权合并、部署或删数据。
---
## Product Contract
### Summary
重构先解决文档事实源、事务与恢复链,再扩展其他模块。
架构改造必须用用户可见的刷新、重启、并发和授权结果证明价值,不能只用包数量或代码行数证明完成。
### Problem Frame
系统当前同时依赖 PostgreSQL 账本、`document_records` 指针、workspace `output.md` 和若干内存状态。
这些状态在提交、刷新和重启时没有统一事务与恢复协议,导致历史上出现正文 404/409、projection missing、缓存竞争和任务完成后文档仍为空。
原解耦方案提出 contracts、单一写者和事件总线,但没有解释单一写者如何维持现有跨表原子性,也没有为多个 event subscriber、跨实例互斥和 FAV 恢复定义可执行协议。
### Requirements
**事实源与持久成果**
- R1. PostgreSQL immutable ledger 是文档版本与业务关系的权威,workspace 只作为可重建投影。
- R2. FAV 只归档服务端确认的终态文档、终态助手回复、类型化 RunManifest 和必要附件,中间结果准入率为零。
- R3. 数据库授权图完整但正文不可用时,系统可按 feature flag 从已验证 FAV 只读降级;授权图不完整时必须拒绝。
- R4. GET、刷新和重载不得隐式修复数据库、覆盖 head 或创建归档。
**事务与并发**
- R5. 一个业务命令只有一个事务 owner;业务状态、账本、当前指针及该里程碑已启用的 staging/outbox 必须原子提交。
- R6. 单一写者只约束 SQL 和不变量所有权,不允许各属主各自提交导致跨表半完成。
- R7. 多副本正确性必须依赖数据库行锁、事务级 advisory lock、唯一约束、expected version 和 fencing token;进程内 mutex 不能成为唯一正确性条件。
- R8. 所有写命令必须具有 idempotency key、expected version 或两者;相同 key 不同 payload 必须返回冲突。
- R9. 事务不得包含 LLM、PI Runner、对象存储、HTTP/SSE 或长文件 I/O。
**事件与恢复**
- R10. 持久事件采用至少一次投递、逐消费者 delivery、幂等 inbox、租约、fencing token、重试和死信。
- R11. 同一聚合事件按 aggregate version 有序,不同聚合允许并发;失败消费者不阻塞其他消费者。
- R12. 旧 workspace、旧数据库和 FAV 回填必须可断点续跑、可重复、可审计,异常进入 quarantine。
- R13. 恢复只进入 scratch identity,promotion 需要系统管理员和数据责任人确认,并通过属主端口提交。
**授权与隔离**
- R14. HTTP、CLI、worker、event subscriber 和恢复工具必须使用服务端构造的 Principal,并按 action/resource/current state 逐动作授权。
- R15. 客户端或事件 payload 中的 user、project、role、duty、backend 和路径不能作为授权事实。
- R16. WorkspaceRef 只能暴露不可伪造 ID、scope 和 fencing token;物理路径不得跨模块传播。
- R17. 路径解析必须拒绝绝对路径、`..`、跨项目 ID、symlink/hardlink 逃逸和 storage identity 不匹配。
- R18. 事件、日志、metrics、manifest 和 result 文件不得包含 secret、认证材料、Prompt 或不必要正文。
**交付与验证**
- R19. 首个独立交付边界是受控文档可靠性纵向试点,未通过停走门前不启动横向包搬移。
- R20. 每个里程碑必须分别提供 unit、PostgreSQL、并发/故障注入、真实 PI、真实浏览器、restart/rebuild 和跨用户负例证据;不适用项必须说明原因。
- R21. 迁移采用 expand/migrate/contract,允许新的 Goose migration,禁止修改已发布 migration。
- R22. 数据清理必须同时满足完整备份恢复、migration corpus、FAV coverage、精确删除 manifest 和用户批准,不得因“已有最终成果”跳过其他门禁。
### Success Criteria
- 项目 143 等价脱敏 hazard 和新建项目两条链路在刷新、重登、restart 与 rebuild 后正文成功率为 100%,目标 404/409/projection missing 为 0。
- 同一文档并发写只有一个合法赢家;失败请求不产生孤儿 snapshot、错 head、重复消息、重复通知或重复 artifact。
- 每个应发布终态都存在 publish request;已验证 artifact 可在 workspace 删除后按稳定逻辑 ID 定位并校验 SHA。
- 匿名、非成员、跨用户、跨项目、错误 duty、错误 stage、篡改事件和授权依赖失败全部 fail closed。
- 1、2、4 个应用实例和 dispatcher 下,状态与副作用结果一致;性能阈值由基线报告确认后固化,不能通过降低一致性达标。
- 旧 schema corpus、legacy-v0 workspace 和 previous-release corpus 均可升级、重载和回滚到最近兼容点。
### Scope Boundaries
**本计划包含**
- 文档、taskrun、workspace、artifactvault、可靠事件和授权基础设施。
- chatlog/contextasm、squadrun、app 组合根和 UserProjectContext 的后续选择性扩展。
- 数据生命周期、迁移 corpus、回填、quarantine 和 scratch 恢复的集成门禁。
**Deferred to Follow-Up Work**
- HTTP 错误信封统一。
- PI Runner stdout/result.json 协议替换。
- 全量 SSE transport 重写。
- 微服务拆分和跨服务消息基础设施。
- main 数据自动清理和未来 tenant 实体。
---
## Planning Contract
### Key Technical Decisions
- KTD1. **纵向绞杀优先。** 先在原包边界增加窄端口和适配器,迁完消费者并通过行为验收后再物理移动包。
- KTD2. **事务 owner 与表属主分离。** 应用用例拥有事务,领域模块拥有 SQL;同一 `pgx.Tx` 通过不透明 TxScope 绑定 repository。
- KTD3. **显式锁策略。** 普通状态转换使用 `READ COMMITTED`、行锁和条件更新;项目级不变量使用事务级 advisory lock;Serializable 只用于经过证明的复杂不变量。[PostgreSQL explicit locking](https://www.postgresql.org/docs/17/explicit-locking.html)
- KTD4. **固定锁顺序。** project/workflow instance → document root → version/snapshot/turn → task run → staging/outbox/delivery。
- KTD5. **事务外副作用。** 网络、LLM、对象存储、通知和投影由提交后的持久事件驱动。
- KTD6. **至少一次事件。** outbox 不承诺 exactly-once;event ID、consumer inbox 和业务唯一约束共同提供幂等结果。
- KTD7. **opaque workspace capability。** 跨模块不传物理路径,所有读写使用 scope-bound ID、artifact key 和 fencing token。
- KTD8. **三层权威。** PostgreSQL 管业务关系与授权,workspace 管临时现场,FAV 管已验证终态 payload/manifest/receipt/tombstone。
- KTD9. **授权逐动作重算。** Principal 来自受信适配器;状态改变在取得资源锁后重读当前授权事实,subscriber 的 actor 快照只用于审计。[OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)
- KTD10. **依赖感知回滚。** 每个里程碑只保证回到最近兼容点;进入 contract 阶段后须按逆依赖顺序回滚。
- KTD11. **按证据收紧门禁。** arch-check 先记录基线,每条规则在对应纵向切片清零后转 block,不按日历统一切换。
- KTD12. **FAV 分支先审后用。** `feature/final-artifact-vault` 的现有实现作为候选,不直接视为 dev 已有能力;集成前重放迁移、测试、安全和并发审计。
### High-Level Technical Design
#### Component topology
```mermaid
flowchart TB
Transport[HTTP SSE CLI] --> UseCases[application use cases]
Jobs[workers and recovery] --> UseCases
UseCases --> Policy[authorization policy]
UseCases --> Unit[UnitOfWork]
Unit --> DG[docgov owner]
Unit --> DR[docrevision owner]
Unit --> TR[taskrun owner]
Unit --> OB[outbox and staging]
UseCases --> WSC[workspace capability]
OB --> Dispatch[delivery dispatcher]
Dispatch --> Projection[projection subscriber]
Dispatch --> AV[artifactvault subscriber]
Dispatch --> Notify[notification subscriber]
```
#### Write sequence
```mermaid
sequenceDiagram
participant C as Caller
participant A as App use case
participant P as Policy
participant DB as PostgreSQL
participant O as Outbox worker
participant V as FAV
C->>A: command + idempotency + expected version
A->>P: authorize principal/action/resource
P-->>A: allow or deny
A->>DB: begin and acquire locks in canonical order
A->>DB: ledger + root + staging + outbox
DB-->>A: commit
A-->>C: committed result
O->>DB: claim delivery
O->>V: publish immutable artifact
V-->>O: verified receipt
O->>DB: idempotent ack
```
#### Event delivery lifecycle
```mermaid
stateDiagram-v2
[*] --> pending
pending --> leased
leased --> delivered
leased --> retryable_failed
leased --> dead_letter
retryable_failed --> leased
leased --> pending: lease expired
delivered --> [*]
```
#### Migration lifecycle
```mermaid
flowchart TB
Expand[Expand schema and compatible readers] --> Shadow[Shadow validation]
Shadow --> Backfill[Checkpointed backfill]
Backfill --> Switch[Switch writer]
Switch --> Observe[Observe and restart test]
Observe --> Contract{Go or rollback?}
Contract -->|go| Remove[Remove old path]
Contract -->|rollback| Previous[Return to prior compatible point]
```
### Concurrency and Lock Matrix
| Resource/operation | Correctness primitive | Conflict result | Retry policy | Forbidden while held |
|---|---|---|---|---|
| Project duty/heal/revoke | transaction advisory lock keyed by project | wait then typed timeout | whole idempotent tx for deadlock only | network, LLM, filesystem copy |
| Workflow stage advance | instance row lock + expected config revision | stale-state conflict | caller refresh; no blind retry | external execution |
| Controlled document edit | document row + open version row + ETag | version conflict with current head metadata | user/client rebases | projection and notification |
| Agent candidate commit | candidate/document/version locks + idempotency key | stale candidate or idempotency conflict | exact same request may replay | PI/LLM call |
| TaskRun claim/finalize | unique idempotency + conditional status/version update | existing run or state conflict | same digest returns prior result | message/SSE side effect |
| Workspace write | DB lease + fencing token + atomic file commit | stale lease/token | reacquire then re-resolve state | arbitrary path access |
| Outbox delivery | row lease + `SKIP LOCKED` + fencing token | another worker owns item | retry at next schedule | subscriber work inside claim tx |
| FAV publish | artifact idempotency unique key + no-replace object write | existing verified artifact or digest conflict | same digest resumes | reading mutable workspace |
### Authorization Matrix
| Surface | Principal source | Resource facts | Required checks | Failure behavior |
|---|---|---|---|---|
| HTTP/SSE | authenticated session/middleware | DB project/session/document/workflow | membership, owner, duty, stage, action | 401/403/typed conflict; no data |
| CLI ops | service identity + operator session | explicit environment/dataset/resource manifest | capability, exact scope, dry-run where destructive | fail closed and audit |
| Event subscriber | registered service identity; event actor for audit only | DB current aggregate + event scope/digest | producer allowlist, project/resource match, current policy | dead letter/quarantine |
| FAV degraded read | current authenticated Principal | DB relation + vault manifest/tombstone | normal read permission first, then integrity | no fallback if auth graph incomplete |
| Recovery promotion | recovery credential + admin + data steward approval | scratch identity + signed plan + conflict map | two-party approval, no unresolved conflicts | refuse promotion |
| Agent backend | app-resolved BackendRef | project policy + InputBundle sensitivity | backend allowlist, least data, secret injection boundary | reject before dispatch |
### Delivery dependency graph
```mermaid
flowchart TB
M0[M0 baseline and contract correction] --> M1[M1 document reliability pilot]
M1 --> M2[M2 durable events and FAV integration]
M2 --> M3[M3 taskrun and workspace finalization]
M3 --> M4[M4 selective domain decoupling]
M4 --> M5[M5 app composition and context ownership]
M5 --> M6[M6 transport boundary cleanup]
M2 --> D[Data corpus and lifecycle rollout]
D --> M3
```
### Assumptions
- 当前 dev 基线为 schema 33;任何实现分支必须在创建 migration 时重新查询最新序号。
- `feature/final-artifact-vault` 尚未合 dev,现有代码与测试只能作为候选实现和证据来源。
- 当前无独立 tenant 实体,权限范围沿用 environment + project membership/admin;未来 tenant 模型另立 ADR。
- 性能容量目标需要在 M1 压测后固化;本计划先固定正确性和观测项,不伪造吞吐数字。
---
## Phased Delivery
| 里程碑 | 交付边界 | 预计范围 | 进入条件 | 退出/停走门 |
|---|---|---|---|---|
| M0 | 基线与契约纠偏 | 文档/门禁/characterization | 在途 mutex 不冲突 | 事务/锁/授权/事件/FAV 契约评审通过 |
| M1 | 文档可靠性纵向试点 | docflow/docgov/docrevision/docquery | M0 完成,独占 docgov | 刷新、重启、并发、权限和故障注入全 PASS |
| M2 | 持久事件与 FAV | outbox/delivery/artifactvault | M1 数据边界稳定 | 多 worker、重放、归档、降级读取和 tombstone PASS |
| M3 | taskrun/workspace 终态 | taskrun/squadrun/workspace | M2 verified receipt 可用 | 清 workspace 后最终产物仍可定位,重复 finalize 无副作用 |
| M4 | 选择性领域端口化 | chatlog/contextasm/squadrun | M1–M3 复盘证明收益 | 每个子切片独立回归;无纯搬包 |
| M5 | 组合根与上下文收权 | app/chatflow/stageflow/UserProjectContext | M4 稳定 | 每个 use case 单 owner;闭包按事件逐个替换 |
| M6 | 传输收口 | server/SSE | M5 完成 | server 无 SQL/编排/路径;R1–R7 对应规则全 block |
M0–M1 是首个批准范围。
M2–M6 需要在前一里程碑验收报告后重新 go/no-go,不构成一次性整体授权。
---
## Implementation Units
### Unit Index
| ID | 标题 | 主要文件 | 依赖 |
|---|---|---|---|
| U1 | 固化架构基线和门禁 | `scripts/arch-check.sh`, `.doc/system-design/module-boundaries.yaml` | 无 |
| U2 | 建立应用 UnitOfWork | `internal/app/uow`, owner repositories | U1 |
| U3 | 文档命令原子化 | docgov/docrevision/docflow | U2 |
| U4 | 文档授权读模型 | docquery/server/authz | U1, U3 |
| U5 | Workspace capability | workspace/squadrun | U1 |
| U6 | Durable event delivery | outbox/dispatcher/inbox | U2 |
| U7 | FAV 集成与降级读取 | artifactvault/docflow/docquery | U3, U4, U6 |
| U8 | TaskRun/RunManifest 终态 | taskrun/squadrun/workspace | U5, U6, U7 |
| U9 | 数据回填与迁移 corpus | dataset/FAV tooling | U6–U8 |
| U10 | chatlog/contextasm 端口化 | ctxmgr/chat/contextasm | M1–M3 go/no-go |
| U11 | 组合根和 use case 收权 | app/server/bizdev/coordinator | U10 |
| U12 | 传输边界与最终门禁 | server/stream/CI | U11 |
### U1. 固化架构基线和可执行门禁
- **Goal:** 建立不会把现有违规合法化、也不会误报 migration/fixture 的边界基线。
- **Requirements:** R19–R21;KTD1、KTD11。
- **Dependencies:** 无;必须避开 `intent`、`chat` 等在途 mutex,当前只占 `arch`。
- **Files:** `scripts/arch-check.sh`、`.doc/system-design/module-boundaries.yaml`、`internal/archtest/arch_test.go`、`internal/archtest/arch_test_test.go`、`.doc/audit/<date>-arch-check-baseline.md`。
- **Approach:**
1. 分离 production import、production SQL write、path construction、event producer/consumer 四类规则。
2. 表名扫描只识别 production Go 中的写语句;Goose、测试、fixture 和受控运维脚本进入显式类别,不以全仓零出现为目标。
3. 为每项既有违规记录 owner、原因、截止里程碑和到期日;新违规立即 block。
4. 只为已完成纵向切片的规则切换 block,不能以“两周后统一 block”代替清零。
- **Execution note:** 先对当前依赖和 SQL 写者生成可重复 characterization 报告,再改门禁。
- **Patterns to follow:** `go list` 依赖图、现有 AGENTS mutex、Goose 不可改写规则。
- **Test scenarios:**
- 合法的 Goose/fixture 表名不触发生产写者违规。
- 非属主 production 包新增 `UPDATE document_records` 时测试失败并定位文件。
- 路径通过字符串拼接、`filepath.Join` 和间接常量构造时均被检测。
- 无过期日例外、过期例外、新增越权 event producer 均阻断。
- **Verification:** 基线报告可重放;新增违规阻断;现有违规数只能下降。
### U2. 建立应用 UnitOfWork 和事务能力
- **Goal:** 在单一写者边界内维持跨表业务不变量。
- **Requirements:** R5–R9;KTD2–KTD5。
- **Dependencies:** U1。
- **Files:** `internal/app/uow/uow.go`、`internal/app/uow/pg_uow.go`、`internal/app/uow/pg_uow_test.go`、`internal/docgov/repository.go`、`internal/docrevision/repository.go`、`internal/taskrun/repository.go`、`internal/freedoc/repository.go`。
- **Approach:**
1. UnitOfWork 开启、提交和回滚唯一 `pgx.Tx`,向每个属主提供绑定该 transaction 的窄 repository capability。
2. TxScope 不暴露通用 `Exec` 给应用层;只有属主 repository 能执行自己的 SQL。
3. 禁止 repository 在已有 TxScope 内嵌套 transaction 或提前 commit。
4. 实现统一的完整事务重试 wrapper,只重试明确的 serialization/deadlock 错误,并保持 idempotency context。
5. 为锁超时、事务时长、重试和 rollback reason 加结构化指标,不记录业务正文。
- **Test scenarios:**
- 第二个属主写入失败时第一个属主写入回滚。
- outbox/staging 写入失败时业务状态和账本均回滚。
- commit 失败时不会返回成功或执行提交后副作用。
- `40001`/`40P01` 重跑完整事务并最终只产生一个业务结果。
- version conflict、permission denied、payload digest conflict 不进入自动重试。
- 尝试跨属主执行任意 SQL 无法通过类型边界或架构测试。
- **Verification:** fault injection 覆盖 begin、每个 owner write、outbox、commit;无部分提交。
### U3. 文档提交纵向事务化
- **Goal:** 将人工编辑、agent commit、批准/驳回和根指针投影收敛到文档用例事务。
- **Requirements:** R1、R5–R9、R19;KTD2–KTD5。
- **Dependencies:** U2;实施时独占 `docgov` mutex。
- **Files:** `internal/app/docflow/commands.go`、`internal/app/docflow/commands_pg_test.go`、`internal/docgov/engine.go`、`internal/docgov/lease.go`、`internal/docrevision/pg_mutate.go`、`internal/docrevision/service.go`、`internal/docrevision/document_commit_concurrency_pg_test.go`、`internal/server/document_revision_handlers.go`。
- **Approach:**
1. 为每个文档命令明确 aggregate、expected head、idempotency key 和授权 action。
2. 版本账本与 `document_records` 指针先在同一 UoW 写入;M1 保留现有通知兼容适配,但任何核心正确性不得依赖提交后的 `OnOutbox` 回调。
3. 按 KTD4 锁定 document root 与 open version;状态转换采用条件更新。
4. 提交返回 ledger/root 已持久化结果;workspace projection 和通知由提交后事件处理。
5. 保留现有 ETag 语义,统一 agent、人工与批准路径的冲突分类。
- **Execution note:** 先补当前行为的 PG characterization,再移动写入所有权;不得先删除旧事务路径。
- **Patterns to follow:** `internal/docrevision/pg_mutate.go` 当前同事务投影、`internal/docgov/lease.go` expected SHA、现有 document revision idempotency tests。
- **Test scenarios:**
- 同一 ETag 两个用户并发编辑,只有一个成功,另一个得到当前 head。
- 人工编辑与 agent commit 并发,账本 event_no 连续且 head 指向赢家。
- approve 与 reject 并发,只允许一个合法终态。
- candidate commit 在 root/version/outbox 任一故障点整体回滚。
- 相同 idempotency key 和相同 digest 返回原结果;不同 digest 返回冲突。
- 锁超时返回 typed retryable busy,不泄露 SQL 或路径。
- 两个 app 实例执行同一请求,结果与单实例一致。
- **Verification:** 文档四类命令的跨表不变量由 PostgreSQL 测试证明;`OnOutbox` 不再承担正确性。
### U4. 建立授权后的文档统一读模型
- **Goal:** 正文读取不再依赖 handler 拼路径或把一致性错误伪装成 404。
- **Requirements:** R1、R3、R4、R14、R15、R19;KTD1、KTD8、KTD9。
- **Dependencies:** U1、U3;实施时按 CURRENT 排队使用 `docgov` 和 `authz` mutex。
- **Files:** `internal/app/docflow/query.go`、`internal/app/docflow/query_test.go`、`internal/docquery/service.go`、`internal/docquery/service_pg_test.go`、`internal/server/project_doc_handlers.go`、`internal/server/document_revision_authz_test.go`、`web/src/api/projectDocuments.ts`、`web/src/lib/controlledDocHydrate.ts`、`web/e2e/controlled-document-reload.spec.ts`。
- **Approach:**
1. Principal 由认证适配器构造,DocRef 不携带可覆盖 Principal 的 user/role/duty。
2. 先解析数据库 resource→project、workflow、stage 和 duty,再读取 ledger/current pointer。
3. workspace projection 只作为校验缓存;缺失时不阻止读取数据库 immutable content。
4. ledger/root、projection 和 FAV 的差异映射为 typed consistency state,不再统一变成 404。
5. FAV 降级在 U7 接入前保持关闭;接口先保留明确 extension point。
6. 列表和版本查询强制分页,BatchGet 首期上限 100;批量授权按 Principal/project 分组并使用有界并发。
- **Test scenarios:**
- 正常 projection、projection 缺失、projection hash 漂移、ledger 缺失分别返回正确结果或 typed error。
- GET、刷新、重登不产生数据库写入、workspace 文件或归档事件。
- 匿名、非成员、跨用户会话、跨项目、错误 stage/duty 均拒绝且不泄露文档存在性。
- 授权依赖超时/错误时 fail closed。
- BatchGet 的 100/101 边界、重复引用、跨项目混合引用和限流拒绝不泄露资源存在性。
- 项目 143 等价 hazard 和新项目在页面刷新、restart、rebuild 后正文一致。
- **Verification:** 控制台和服务器目标 404/409/projection missing 为零;所有来源分支有服务端与浏览器证据。
### U5. Workspace capability、lease 与文件提交
- **Goal:** 从类型和运行时同时禁止跨模块裸路径与跨租户工作区访问。
- **Requirements:** R1、R7、R9、R16–R18;KTD7。
- **Dependencies:** U1。
- **Files:** `internal/workspace/types.go`、`internal/workspace/resolver.go`、`internal/workspace/capability.go`、`internal/workspace/capability_test.go`、`internal/workspace/lease_pg_test.go`、`internal/squad/workspace_adapter.go`、`internal/bizdev/service.go`、`internal/server/project_doc_handlers.go`。
- **Approach:**
1. WorkspaceRef 删除 Root/OutputDir/ManifestPath,只保留 scope-bound ID、schema version 和 fencing token。
2. workspace service 提供限定 artifact key 的 read、atomic writer、commit projection 和 inspect 能力。
3. ID 与 lease 绑定 environment、project、run 和 storage identity;所有写入校验 fencing token。
4. 使用 realpath/descriptor-based 检查,拒绝 `..`、绝对路径、symlink/hardlink 和根外 rename。
5. legacy-v0 workspace 只读;首次受控 Resume 校验后原子升级 v1,并保留兼容备份一个发布周期。
- **Test scenarios:**
- `..`、绝对路径、编码后的分隔符、空 key、跨 project Workspace ID 全部拒绝。
- symlink 和 hardlink 在校验后替换的 TOCTOU 场景仍不能逃逸。
- 旧 lease writer 在新 lease 签发后因 fencing token 过期而失败。
- 两个 app 实例并发提交同一 projection,reader 只看到完整 marker。
- v0 读取、升级失败回滚、未知 major 版本拒绝。
- **Verification:** production 包中 workspace 物理路径只存在于 workspace/squadrun adapter;多实例测试不依赖 `sync.Mutex`。
### U6. Durable outbox、逐消费者 delivery 与 replay
- **Goal:** 让后台投影、通知和 FAV 发布在崩溃与水平扩容下可恢复。
- **Requirements:** R5、R9–R11、R14、R18、R21;KTD5、KTD6。
- **Dependencies:** U2;需要新的 additive Goose migration。
- **Files:** `deploy/postgres/goose/000xx_*durable_event_delivery.sql`、`internal/events/envelope.go`、`internal/events/outbox.go`、`internal/events/dispatcher.go`、`internal/events/inbox.go`、`internal/events/dispatcher_pg_test.go`、`internal/events/replay.go`、`cmd/events/main.go`。
- **Approach:**
1. 保留业务 outbox record,新增 event envelope、每消费者 delivery/inbox、attempt、lease、next_attempt_at 和 dead-letter 数据。
2. `FOR UPDATE SKIP LOCKED` 只用于小批次 claim;worker 在 claim transaction 外执行 subscriber。
3. ack/fail 使用 delivery version/fencing token,过期 worker 不能覆盖新 lease owner。
4. 同 aggregate 依据 aggregate version 串行,不同 aggregate 并行;缺号进入等待或 quarantine。
5. retry policy 区分 transient、permanent、authorization/integrity failures;后两者默认 dead letter/quarantine。
6. replay CLI 先 dry-run,必须限定 consumer/event/project/time/id 范围并记录 operator、reason 和计划 hash。
7. 逐个迁移并删除 `OnOutbox` 与闭包桥;切换前 shadow 对账,切换后旧回调不再注册。
- **Test scenarios:**
- 两个和四个 worker 并发 claim,没有同一 lease 的双 owner。
- worker 在副作用前、后、ack 前崩溃,重启后最终只有一个可见业务结果。
- 一个 subscriber 永久失败不阻塞其他 subscriber。
- lease 过期后旧 worker ack 被 fencing token 拒绝。
- 相同 event 重放被 inbox 去重;相同 aggregate 乱序事件不越过缺失版本。
- 伪造 producer、跨项目 scope、payload digest 不符进入 quarantine。
- dead-letter replay 未授权、无 dry-run 或范围过宽时拒绝。
- **Verification:** 删除旧单一 `published_at` 语义前完成双读对账;pending age、attempt、lease steal、dead letter 可观测。
### U7. FAV 分支审计、终态发布与授权降级读取
- **Goal:** 将最终成果与 workspace 清理解耦,同时不形成第三套业务真相源。
- **Requirements:** R1–R4、R10–R15、R18、R21、R22;KTD8、KTD9、KTD12。
- **Dependencies:** U3、U4、U6;先审计 `feature/final-artifact-vault` 相对当前 dev 的完整差异。
- **Files:** `internal/artifactvault/`、`deploy/postgres/goose/000xx_*final_artifact*.sql`、`internal/app/docflow/artifact.go`、`internal/docquery/service.go`、`internal/server/vault.go`、`cmd/artifact-vault/`、`internal/artifactvault/*_test.go`。
- **Approach:**
1. 重用通过审计的 FAV eligibility、staging、publisher、manifest、tombstone 和 scratch recovery;不直接 cherry-pick 未复核的组合根/handler 改动。
2. 重新分配最新 Goose 序号,并验证 migration 与 U6 delivery schema 的组合和 Down 边界。
3. 文档终态 transaction 冻结精确 payload/SHA 或 immutable blob ref 并写 publish request;publisher 不重读 workspace 或可变消息行。
4. docquery 只在正常数据库授权成功后使用 FAV;manifest 只做 scope/integrity 交叉校验,不能授予权限。
5. union-deny:运行删除账本或 vault tombstone 任一侧声明删除即拒绝读取/恢复。
- **Execution note:** 现有 FAV 分支包含业务代码和 migration,必须先 rebase/merge audit,再按本计划拆分原子提交。
- **Test scenarios:**
- committed/sealed/approved 文档按准入表归档;ready/rejected/stale/quality_failed 和 workspace 草稿为零。
- publish 重复、对象已存在、每个 fsync/rename/marker 崩溃点都可恢复。
- workspace 删除后,授权用户可读 verified payload;未授权用户看不到 artifact 存在性。
- DB 授权关系缺失、manifest scope 不符、坏 SHA、tombstone、vault 不可用均 fail closed 或返回明确 degraded error。
- GET 零数据库写入、零 workspace 写入、零隐式恢复。
- 跨项目相同 SHA 不共享删除或密钥边界。
- **Verification:** FAV test report 与当前 dev 重放通过;`FAV_DEGRADED_READ` 默认关闭,直到 M2 全部负例通过。
### U8. TaskRun、RunManifest 与 workspace 清理门禁
- **Goal:** 任务终态和最终产物在重复 finalize、SSE 断线和 workspace 清理后保持一致。
- **Requirements:** R1、R2、R5–R12、R16–R18、R22;KTD5–KTD8。
- **Dependencies:** U5、U6、U7。
- **Files:** `internal/taskrun/manager.go`、`internal/taskrun/store.go`、`internal/taskrun/finalize.go`、`internal/taskrun/finalize_pg_test.go`、`internal/squad/manifest.go`、`internal/app/stageflow/execute.go`、`internal/server/task_finalize.go`、`internal/server/task_run_idempotent_sse_test.go`。
- **Approach:**
1. RunManifest 核心字段类型化并持久化规范字节、SHA、workspace/storage identity 和成员列表。
2. taskrun terminal finalize transaction 写状态、assistant terminal turn、manifest、artifact staging 和 outbox。
3. SSE done 只投影已提交状态;客户端断线与重试复用 task run idempotency key。
4. workspace 清理只依赖已冻结 staging 和 policy;需长期保留的最终成果还必须取得 verified receipt。
5. backend 由服务端 BackendRef policy 解析,InputBundle 携带数据分类和最小权限范围。
- **Test scenarios:**
- 同一 finalize 重复调用返回同结果,不重复消息、事件、manifest 或 artifact。
- finalize 与 cancel 并发只有一个合法终态。
- SSE 在 commit 前后断线并重试,历史中只有一个 assistant turn。
- workspace 在 finalize 后立即清理,publisher 仍从 staging 归档原 SHA。
- manifest digest、storage identity、artifact member 不一致阻止 verified/cleanup。
- 未授权 backend、敏感 InputBundle、凭证回显和 result 残留全部拒绝或清理。
- **Verification:** “完成但没有 durable manifest/publish request”和“已显示完成但正文仍模板”两类状态不可产生。
### U9. 存量回填、migration corpus 与数据生命周期
- **Goal:** 只保留可解释的演示/回归数据,并持续验证旧数据迁移、重载和受控恢复。
- **Requirements:** R2、R12、R13、R21、R22;KTD8、KTD10。
- **Dependencies:** U6–U8。
- **Files:** `cmd/dataset/`、`internal/dataset/`、`internal/artifactvault/backfill.go`、`scripts/backup-system-db.sh`、`scripts/restore-system-db-drill.sh`、`.doc/test-fixtures/`、`.doc/test-reports/`。
- **Approach:**
1. 建立 dataset registry,分类 pinned、demo、regression、migration baseline、ephemeral 和 quarantine。
2. backfill 只枚举 immutable document snapshot、approved/commit event 和 completed chat turn,禁止扫描 workspace。
3. 大表按稳定主键 checkpoint 分批处理;多个 worker 使用 `SKIP LOCKED` 或互斥 shard,限速避免挤占在线连接池。
4. 每个 batch 记录 source schema/commit/storage identity、范围、成功、quarantine 和重试水位。
5. dev 先蓝绿建立新数据根,导入 6–10 个批准 dataset;旧库/状态根只读 quarantine 7–14 天后,需用户再次批准才销毁。
6. 每个 release 验证 clean、oldest-supported、previous、hazard、import、reload、rollback 和 artifact recovery 八条轨道。
- **Test scenarios:**
- backfill 中断、重复和并发新终态时分母/分子可复算且不重复 artifact。
- legacy-v0 workspace、旧 schema、高 ID、projection missing/fork、缺 snapshot 分别升级或 quarantine。
- restore 强制 scratch,拒绝 dev/test/main DSN、错误 storage identity、篡改 manifest 和缺权限凭证。
- FAV coverage、完整备份 restore 或 migration corpus 任一失败都阻止 destroy。
- dev 选择性导入后项目关系、文件 SHA、sequence、授权和 reload 一致。
- **Verification:** 数据清理有精确 manifest、可恢复位置、观察窗口和批准记录;不修改历史 Goose。
### U10. chatlog/contextasm 原地端口化
- **Goal:** 在不重复付费搬包的前提下分离对话记录和 prompt 上下文装配。
- **Requirements:** R7、R14、R15、R19、R20;KTD1、KTD9。
- **Dependencies:** M1–M3 go/no-go;必须等待当前 `chat` mutex 释放。
- **Files:** `internal/ctxmgr/`、`internal/chat/`、`internal/app/chatflow/`、`internal/ctxmgr/chat_auth_pg_test.go`、`internal/server/chat_history_auth_test.go`。
- **Approach:**
1. 先定义 chatflow 所需的消费者侧 ChatLog 和 ContextAssembler ports。
2. 在现有 ctxmgr 内提供 adapters,迁移调用者并保持表所有权不变。
3. 统计接口 fan-in、DTO 转换和同类改动触达文件数;收益成立后再物理拆为 chatlog/contextasm。
4. 所有读取携带 Principal/action,不接受请求体 user/project 作为权限事实。
- **Test scenarios:**
- 刷新前后同一授权消息集合的正文、分类和计数一致。
- 跨用户、跨项目、已退出成员和服务端后台导出负例。
- context assembly 只读取允许集合,摘要/缓存不放大不可见消息。
- 原地 adapter 与最终拆包实现的 contract tests 等价。
- **Verification:** 同类对话变更触达面相对基线下降;拆包前已获得独立行为收益。
### U11. 组合根迁移、事件替换和共享上下文收权
- **Goal:** 让每个跨模块业务流程具有唯一应用用例 owner,而不是集中在 server/bizdev 闭包和共享指针。
- **Requirements:** R5、R7、R9–R11、R14、R15、R19、R20;KTD1、KTD5、KTD6、KTD9。
- **Dependencies:** U10;按四个独立子切片执行,不建立一个巨型 Wave。
- **Files:** `internal/app/app.go`、`internal/app/chatflow/`、`internal/app/stageflow/`、`internal/app/docflow/`、`internal/server/server.go`、`internal/bizdev/service.go`、`internal/coordinator/`、对应 contract/integration tests。
- **Approach:**
1. U11a 只把构造和生命周期迁到唯一 app composition root。
2. U11b 一次只替换一种闭包事件;每种事件单独迁移、对账和回滚。
3. U11c 逐个迁移 ExecuteTask/executeStageInternal 用例,不同时修改无关领域。
4. U11d 将 UserProjectContext 改为只读 snapshot + 类型化 ContextUpdate,单一 use case 应用增量。
- **Test scenarios:**
- app start/stop/restart 不丢 worker,重复启动不创建重复 subscriber。
- 每个闭包新旧路径 shadow 结果一致,切换后旧路径无调用。
- ContextUpdate 并发应用使用版本检查,不发生字段级 lost update。
- server、CLI 和 worker 调用同一 use case 得到一致授权和事务结果。
- **Verification:** 每个子切片独立发布、独立回滚;server 不再保存业务闭包,UserProjectContext 不被多方直接修改。
### U12. 传输边界收口和最终架构门禁
- **Goal:** 在领域行为稳定后缩减 server/stream 耦合并全面启用已清零规则。
- **Requirements:** R14、R18–R21;KTD1、KTD11。
- **Dependencies:** U11。
- **Files:** `internal/server/`、`internal/stream/transport/`、`scripts/arch-check.sh`、`.doc/system-design/module-boundaries.yaml`、CI 配置、`web/e2e/`。
- **Approach:**
1. server handler 只保留参数、Principal、use case 调用和 wire serialization。
2. SSE transport 只编码中性 progress/event frame,不拥有业务状态或重试决策。
3. 对已清零的 import、SQL writer、path、producer/consumer 规则逐项转 block。
4. 错误信封和 PI Runner 协议保持独立 follow-up,不进入本单元。
- **Test scenarios:**
- HTTP、SSE 断线重连和 CLI 对同一业务状态观察一致。
- server 新增领域实现 import、SQL 或路径拼接时 CI 失败。
- SSE 慢客户端、断开和重复连接不阻塞业务 transaction 或 dispatcher。
- 全套授权、重启和多实例回归保持通过。
- **Verification:** R1–R7 的修订版规则全 block;server 行数只作观察指标,不作替代行为验收。
---
## Verification Contract
### Evidence layers
| 层级 | 必须证明 | 不得替代 |
|---|---|---|
| Unit | 状态机、错误分类、schema、路径和 policy | PostgreSQL 原子性 |
| PostgreSQL integration | 事务回滚、锁、幂等、migration、并发 | 浏览器用户体验 |
| Fault injection | 每个 commit/delivery/publish 崩溃窗口 | 真实进程 restart |
| Concurrency/load | 多 app/worker、热点与非热点资源、积压和公平性 | 正确性断言 |
| Real PI | 真实 agent 生成、manifest、finalize、归档 | stub 或固定假输出 |
| Browser | 页面创建/打开/编辑/刷新/重登、错误与 degraded 状态 | API 直接调用 |
| Restart/rebuild | app、worker、workspace root、存储 identity 重载 | health 单点检查 |
| Authorization negative | 匿名/跨用户/跨项目/阶段/duty/后台/recovery | 前端隐藏按钮 |
| Recovery | 完整 DB restore、migration corpus、FAV scratch 恢复 | 仅列出 dump 内容 |
### Repository gates
- `go vet ./...`
- `go test -short ./...`
- 目标模块 PostgreSQL 集成和 race 测试;若全包 race 存在已知 TempDir flake,报告必须分离目标模块结果和基建债。
- `scripts/arch-check.sh` 对当前里程碑已收紧规则为 block,对未迁移规则输出基线差异。
- `web` 单元测试与 production build。
- dev 容器必须 rebuild 后检查 `/health` 与 `/ready`,不能用 restart 证明新代码已部署。
- 真实 PI、真实浏览器、post-restart 和多用户负例按独立证据分栏。
### Concurrency test matrix
| 维度 | 场景 | 必须断言 |
|---|---|---|
| App replicas | 1/2/4 | 结果和不变量一致,进程内 mutex 关闭仍正确 |
| Dispatcher replicas | 1/2/4 | 无双 owner ack,无重复可见副作用,无永久饥饿 |
| Resource shape | 同一文档热点/不同文档并行 | 热点正确冲突,非热点不被全局锁串行化 |
| Failure point | before commit/after commit/before ack/after side effect | 无丢事件,重复交付幂等 |
| Lock behavior | timeout/deadlock/serialization | 分类和完整事务重试正确,无无限等待 |
| Lease behavior | expiry/renew/steal/stale fencing | 旧 owner 无法覆盖新 owner |
| Load | steady/burst/backlog recovery | 记录 p50/p95/p99、锁等待、连接池、oldest event age |
### Authorization test matrix
每个状态改变和读取接口至少覆盖:匿名、已登录非成员、错误项目成员、会话非 owner、错误 duty、错误 stage、过期 lease、跨环境 ID、服务身份越权、授权依赖失败和系统管理员合法路径。
FAV 额外覆盖 manifest project 不符、tombstone、删除账本不一致和授权图缺失。
状态改变必须覆盖授权检查后的成员撤销、duty 变化、stage 推进和 lease 失效,证明用例在取得资源锁后重新验证当前事实。
### Migration and rollback matrix
| 阶段 | Forward proof | Rollback proof |
|---|---|---|
| Expand | 新 schema 与旧代码兼容 | migration Down 或旧代码继续运行 |
| Shadow | 新旧读取差异为零或有解释的 quarantine | 关闭 flag 回旧路径 |
| Backfill | checkpoint、幂等、并发新写一致 | 停止 worker,不撤销已安全扩展列 |
| Switch | 新 writer 唯一、旧 writer 只读 | flag 回最近兼容 writer |
| Observe | restart/rebuild/浏览器/PI/指标稳定 | 切回旧 reader/writer 与只读 quarantine 数据 |
| Contract | 引用扫描和用户批准 | contract 后只能逆序部署兼容版本,不能单 commit revert |
---
## Risk Analysis and Mitigation
| 风险 | 触发信号 | 缓解和停止条件 |
|---|---|---|
| contracts 成为新万能包 | fan-in、共享 DTO、ADR 数持续上升 | 消费者侧端口;按域拆公共契约;超过阈值回评边界 |
| 跨属主事务过大 | 锁等待、事务 p99、deadlock 上升 | 缩小原子集合;事务外副作用;固定锁序;停止扩面 |
| advisory lock 形成全局瓶颈 | 非热点资源也排队 | 只对项目级不变量使用;key 分区;检查 `pg_locks` |
| outbox backlog 放大 | oldest age/attempt/dead letter 超阈值 | 独立 worker 连接预算、批次和退避;按 aggregate 并行 |
| poison event 无限重试 | 同 event 高频失败 | typed permanent failure、dead letter、受控 replay |
| FAV 成为授权旁路 | DB 关系缺失仍返回内容 | 正常授权先行、union-deny、默认关闭 degraded read |
| 工作区链接逃逸 | realpath/scope mismatch | opaque ID、descriptor 检查、fencing、负例测试 |
| 回填压垮在线库 | lock wait/replication lag/连接池饱和 | checkpoint、小批次、限速、独立连接预算、可暂停 |
| 双读长期不收口 | exception 数和差异长期不降 | 明确 owner、到期日和 go/no-go;禁止无限兼容 |
| 物理搬包造成大冲突 | import churn 大于行为收益 | 原地端口化;行为稳定后再移动;按 mutex 排队 |
| FAV 分支漂移 | migration 冲突、dev API 已变化 | rebase audit,不整分支盲合;按单元摘取并重测 |
| 数据清理误删 | coverage/backup/corpus 任一未知 | 默认不删;蓝绿迁移;quarantine 观察;用户二次批准 |
---
## Operational and Rollout Notes
### Feature flags
- 新 docquery reader、单写路径、dispatcher consumer、FAV degraded read 和 legacy workspace reader 分别使用独立 flag。
- flag 只选择已兼容路径,不能跳过授权、完整性或终态准入。
- 每个 flag 有 owner、默认值、环境范围、启用前置和删除里程碑。
### Resource budgets
- app transaction、dispatcher、backfill 和 FAV publisher 使用分离的连接池或明确配额,避免后台积压耗尽在线请求连接。
- worker batch、lease、heartbeat、retry 和 concurrency 由配置管理;M1/M2 基线报告确定初值和告警阈值。
- 对同 aggregate 设置最大在途数 1;跨 aggregate 并行度按数据库与 vault 指标调节。
以下是首轮试点的安全起始值,不是产品 SLO;压测报告必须记录调整依据:
| 参数 | 起始值 | 调整约束 |
|---|---|---|
| 写事务 lock wait | 最多 2 秒且不超过请求剩余 deadline | 不允许无限等待;热点冲突优先返回 typed busy |
| serialization/deadlock retry | 最多 3 次,指数退避并带 jitter | 只重跑完整幂等事务 |
| dispatcher claim batch | 50 | claim transaction 只认领,不执行 subscriber |
| delivery lease/heartbeat | 30 秒 / 10 秒 | heartbeat 失败后旧 worker 不得 ack |
| delivery attempts | 12 次后 dead letter | permanent/auth/integrity failure 不做 12 次盲重试 |
| retry backoff ceiling | 15 分钟 | oldest age 仍受告警和人工处置约束 |
| backfill batch | 每批 200 个 aggregate | 按 lock wait、replication lag 和在线池占用自动降速 |
| backfill workers | dev 初始 1,验证后最多 4 | 每个 shard/checkpoint 不重叠 |
### Observability
- Dashboard:transaction/lock、document consistency、outbox delivery、workspace lease、FAV publication、authorization deny、backfill/quarantine。
- Alert:oldest event age、dead letter、storage identity mismatch、projection mismatch、FAV coverage gap、恢复/删除拒绝。
- Trace 使用 correlation/causation ID 串联 HTTP/use case/transaction/event/subscriber,但不得携带正文或 secret。
### Documentation lifecycle
- 每个里程碑开始前新建 short-term 和 CURRENT claim。
- 每个里程碑结束生成 test report,回链本计划 U-ID 和验收清单。
- 完成项移入 archive;未解决问题进入 audit/remediation,不通过口头说明关闭。
---
## Sources and Research
- [模块解耦方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)记录当前源码中的事务、outbox、workspace 和授权缺口。
- `internal/docrevision/pg_mutate.go` 是现有账本与根指针同事务模式,U2–U3 不得降低其原子性。
- `internal/docduty/revoke.go` 已使用事务级 project advisory lock,是 KTD3 的本地先例。
- `internal/taskrun/manager.go`、`internal/taskrun/store.go` 已有进程内幂等锁与数据库唯一键,U8 需要把正确性完全落到跨实例可用的数据库协议。
- `feature/final-artifact-vault` 已实现候选 FAV 能力;U7 必须按当前 dev 重新审计,而不是把分支状态当成当前发布事实。
- [PostgreSQL `SKIP LOCKED`](https://www.postgresql.org/docs/current/sql-select.html)只用于队列式 claim,不用于普通一致性读取。
- [PostgreSQL serialization failure handling](https://www.postgresql.org/docs/16/mvcc-serialization-failure-handling.html)要求 serialization/deadlock 重试覆盖完整事务逻辑。
- [OWASP Business Logic Security](https://cheatsheetseries.owasp.org/cheatsheets/Business_Logic_Security_Cheat_Sheet.html)支持服务端重新推导身份、所有权和安全相关状态。
---
## Definition of Done
- [ ] U1–U9 完成并通过 M0–M3 的逐里程碑 go/no-go;U10–U12 只在收益复盘批准后执行。
- [ ] 文档提交不存在跨表半完成,所有提交后副作用来自持久事件。
- [ ] 多实例、多 worker、崩溃和 lease 过期场景保持相同业务结果。
- [ ] workspace 不再是正文或最终 manifest 的唯一事实源,裸路径不跨模块传播。
- [ ] FAV 只含终态成果,中间结果准入率为零,授权缺失时不可降级读取。
- [ ] 项目 143 等价 hazard 与新项目完成真实 PI、页面刷新、重登、restart/rebuild 和跨用户负例。
- [ ] clean/oldest/previous/hazard/import/reload/rollback/artifact recovery 八条迁移轨通过。
- [ ] arch-check 规则按纵向切片清零后全部 block,例外有 owner 和到期日。
- [ ] CURRENT、FEATURE-MATRIX、gap-matrix、ADR、系统设计、test report 和 checklist 状态一致。
- [ ] 放弃方案、临时代码、双写旁路、过期 flags 和无消费者契约已移除,不留在最终 diff。
## Related Links
- Audit: [模块解耦方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)
- Architecture: [模块化单体解耦架构](../system-design/2026-09-14-module-decoupling-architecture.md)
- ADR: [模块化单体解耦](../adr/2026-09-14-modular-monolith-decoupling.md)
- Planning task: [本次计划修订任务](../archive/ops/2026-09-14-module-decoupling-remediation-plan.md)
- Acceptance: [重构验收清单](../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- FAV dependency: `feature/final-artifact-vault` 中的 `.doc/remediation/2026-09-14-final-artifact-vault-remediation.md`
- Data lifecycle dependency: `feature/final-artifact-vault` 中的 `.doc/remediation/2026-09-14-runtime-data-lifecycle-and-migration-corpus-remediation.md`
@@ -0,0 +1,162 @@
---
title: "workflow-plan 409 冻结冲突整改 + 文档职责可选治理"
status: planned
created: 2026-09-14
updated: 2026-09-14
---
# workflow-plan 409 冻结冲突整改 + 文档职责可选治理
## 背景
- Audit: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- Short-term: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../ops/short-term/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- gap-matrix: [WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES](./gap-matrix.md)
项目 143 已处于 active,后端按设计返回 409 `PLAN_FROZEN`;前端仍展示可编辑表单,错误又只出现在滚动容器顶部,造成“点击无反应”。新增需求是允许部分非必需文档不设置三权,而不是允许项目配置绕过正式工作流的必需文档。
## 最终语义
每个文档任务只有以下三种合法状态:
| 状态 | 表达 | 生成与账本 | 人工审批 | 阶段门禁 |
|---|---|---|---|---|
| 关闭 | `enabled=false` | 不生成 | 无 | 不参与 |
| 启用、无需人工审批 | `enabled=true` 且三职全空 | 仍生成并进入版本账本 | 不创建三权指派;review/approve 不可用 | 不因批准状态阻塞 |
| 启用、纳入人工审批 | `enabled=true` 且三职全满、互异、均为在任项目成员 | 正常生成并进入版本账本 | 完整三权链路 | 按工作流定义的 `BlocksWhenEnabled()` 判定 |
禁止状态:
- 仅填写 1–2 个职责:HTTP 400,顶层 `VALIDATION_FAILED`,issue code=`DUTY_PARTIAL_ASSIGNMENT`。
- 必需、阻断或不可由创建者裁剪的文档三职全空:issue code=`DUTY_ASSIGNMENT_REQUIRED`。
- 激活时没有任何三职完整的受治理文档:issue code=`NO_GOVERNED_DOCUMENT`。
- 职责人不是在任项目成员:issue code=`DUTY_ASSIGNEE_NOT_ACTIVE_MEMBER`。
“三职全空”只能称为“无需人工审批”或“不纳入人工审批”,不得称为“非受控”。正文版本、人工修订、权限审计和来源追踪仍然存在。
## 关键设计决策
### D1:工作流定义优先,项目配置不能降低强制治理
用工作流版本中的任务定义判定是否允许全空。仅当文档任务为非必需、非阻断且允许创建者裁剪时,才允许保持启用但三职全空。至少满足 `Required || Blocking || !IsCreatorConfigurable()` 的任务必须三职完整。
这样既满足“部分文档不设置”,又避免通过清空职责绕过正式工作流门禁。
### D2:统一职责分类函数,禁止 validator/gate/access 各自推断
在 `internal/projectinstance` 建立纯函数,例如:
```go
type DutyMode string
const (
DutyModeNone DutyMode = "none"
DutyModePartial DutyMode = "partial"
DutyModeFull DutyMode = "full"
)
```
`classifyDocDuty`、`docTaskRequiresDuty` 和规范化函数由保存校验、激活校验、预览、门禁、阶段访问共同复用。禁止只在 `gate.go` 临时判断三个 ID 是否为零。
保存前服务端规范化:
- `enabled=false`:清空三职,避免冻结快照和 plan hash 残留旧 ID;
- 用户选择“无需人工审批”:三职一次性全部清空;
- partial 不自动补齐或自动清空,必须明确拒绝。
### D3:保存与激活分层校验
- 保存草稿:允许所有可选文档暂时全空,便于分步配置;仍拒绝 partial、重复人员、非成员及强制文档全空。
- 激活预览与最终激活:除重复执行结构校验外,至少要求一份 `DutyModeFull` 文档,并重新核对三名职责人仍为 active project member。
- 激活令牌不能替代成员复核。成员可能在预览后退出,最终事务必须 fail closed,要求重新预览。
成员校验必须在服务端完成,不能只依赖 `ProjectSettingsModal.members`。如现有 `projectinstance.Service` 无成员查询能力,注入最小只读接口,不允许让 validator 直接访问 HTTP 或前端数据。
### D4:门禁、权限与运行时采用同一模式
- `DutyModeNone`:`DocTaskReadiness.Enabled=true`,但不要求 approved;建议补充 `approval_managed=false`,避免把 `Required=false` 误读为“不生成”。
- `DutyModeFull`:保持当前 `BlocksWhenEnabled()` 逻辑;非阻断文档可以有审批链但不阻塞阶段。
- 无人工审批文档对已有项目查看权限的成员只读可见;项目创建者可触发生成和人工编辑;其他成员不能 run/edit/review/approve。
- `document_duty_assignments` 对 none 模式不写行;运行时 `TaskResolution` 的三个职责 ID 为 0 必须是显式支持的合法状态,不得触发硬编码人员回退。
- 激活预览增加“启用文档、受治理文档、无需人工审批文档、职责数”四类统计,并列出例外文档,用户确认前可见。
### D5:冻结态是独立只读页面状态
`ProjectSettingsModal` 加入 `mode=loading|planning|frozen|error`,由服务端 `can_edit_plan`、`lifecycle_status` 和 `live_instance` 决定:
- frozen 模式展示当前工作流、版本、active stage、冻结职责快照和“为什么不能修改”;
- 不渲染工作流选择、职责下拉框和“校验并预览”按钮;
- 受控终止作为独立的高风险区域,先展示影响预览,不与普通编辑混在一起;
- 所有 mutation handler 在发请求前再次检查 `can_edit_plan`,避免陈旧状态误提交。
前端 API 引入保留 `status/code/message/issues` 的 `ProjectSettingsApiError`。现有 `parseError` 已能读取后端 message,错误码映射的目的不是重复翻译,而是让 UI 能按 `PLAN_FROZEN`、`PLAN_REVISION_CONFLICT`、`ERR_CONCURRENT_SWITCH` 做定向恢复。
错误区域使用 `role=alert` / `aria-live`,放在操作按钮邻近的 sticky 区域并自动聚焦。若两标签页中一页先激活、另一页后保存,第二页收到 409 后应保留未提交草稿、重新读取服务端状态并切换 frozen,而不是静默丢弃。
### D6:项目 143 不作为破坏性测试数据
项目 143 只做页面只读回归:打开设置应直接看到冻结说明和现有快照,不出现可编辑控件,不调用保存接口。不得在验收中终止它。
业务上确需修改项目 143 时,必须先查看终止影响。现有终止实现会取消运行中任务、把旧实例标为 terminated,并将项目退回 planning;关闭实例的文档/阶段访问会 fail closed,直到重新规划并激活。不能把“终止再配置”描述成无影响的普通编辑。
## 分波次计划
| 波次 | 内容 | 完成判据 |
|---|---|---|
| Wave 0 | 冻结现状、补齐本文语义;为新错误码和 DutyMode 建立契约测试 | 文档审核通过;不改项目 143 |
| Wave 1 | 前端 typed API error、frozen 独立视图、sticky/可访问错误、两标签竞态恢复 | active 项目没有编辑控件;陈旧保存 409 可见且转 frozen,草稿不丢 |
| Wave 2 | 后端统一 DutyMode、工作流定义约束、partial/required/zero-governance 校验、服务端 active-member 复核、快照规范化 | focused Go tests、handler tests 与 race tests PASS |
| Wave 3 | 门禁、readiness、阶段/文档访问、运行时解析、激活预览统计统一采用 DutyMode | none/full/disabled 在 gate、access、snapshot、assignment rows 上一致 |
| Wave 4 | 前端逐文档“纳入人工审批”开关;切换为 none 原子清空三职;仅在存在 full 文档时提示需要至少 3 名成员 | 前端 unit/Vitest/build PASS;错误定位到具体文档和字段 |
| Wave 5 | dev 集成与真实浏览器验收;新建专用测试项目,真实页面配置、激活、生成和阶段推进;项目 143 只读回归 | test report 落盘;失败/无效运行如实留档 |
## 工程测试矩阵
### 后端
- `classifyDocDuty`:none/partial/full 边界,0、负数、重复 ID。
- 强制任务全空拒绝;允许裁剪的非必需任务全空通过。
- partial 返回顶层 `VALIDATION_FAILED`,issue 精确到 `task_key.duties`。
- 保存时职责人非 active member 拒绝;预览后成员退出,激活再次拒绝并要求重新预览。
- disabled/none 保存后冻结快照、plan hash、`document_duty_assignments` 不含旧职责。
- 激活计划零 full 文档拒绝;至少一 full + 一 none 成功。
- readiness:none 不要求 approved;full 按定义决定是否阻塞。
- access:项目成员可 view none;仅创建者可 run/edit;任何人均不能对 none 执行 review/approve。
- termination 后旧实例仍 fail closed;重新激活后访问范围来自新快照。
### 前端
- active + `can_edit_plan=false` 直接进入 frozen,不显示 selector/dropdown/save。
- 409 `PLAN_FROZEN`、`PLAN_REVISION_CONFLICT`、`ERR_CONCURRENT_SWITCH` 保留 status/code 并呈现不同恢复动作。
- 错误在长表单底部视口内可见、可聚焦且有 `role=alert`。
- 审批开关由 full→none 时三职原子清空;none→full 时提示完整分配。
- 少于 3 名成员但所有可选文档为 none 时可保存草稿;存在 full/强制任务时给出定向提示。
- 激活预览展示 full/none 数量和具体例外文档。
## 真实 UI 验收矩阵
最终产品验收只通过真实浏览器页面完成;不得用 API/DB 直写项目、成员、计划、助手回复或文档来替代。网络响应只作浏览器操作后的旁证。
1. 项目 143:页面打开设置即显示冻结说明、当前 main/active stage/职责快照;无可编辑表单、无 workflow-plan PUT。
2. 新项目 A:至少一份强制/full 文档 + 一份允许裁剪的 none 文档,页面保存、预览、激活成功。
3. 系统真实执行 full 文档生成与审批;none 文档真实生成、正文和版本账本可见,但不出现审核/批准动作,且不阻塞阶段推进。
4. 新项目 B:只设置编制,页面在对应文档内联拒绝;不得发出保存请求。
5. 新项目 C:尝试所有文档 none,激活预览在页面明确拒绝“至少保留一份受治理文档”。
6. 两个浏览器标签页:A 页激活,B 页保存旧草稿;B 页显示 409、保留草稿并转 frozen。
7. 非创建者项目成员能只读查看 none 文档,但看不到 run/edit/review/approve;项目外用户不可见。
8. 页面刷新、退出重登及 app restart 后,frozen 状态、职责快照、full/none 模式、阶段就绪保持一致。
项目 143 仅做只读验证。所有会改变状态的验收使用新建测试项目。
## 发布门槛
- `go vet ./...`、`go test -short ./...`、相关 `-race`、`cd web && npm test && npm run build` 全绿。
- 保存、预览、激活三条服务端路径都执行同一结构/成员策略,不能只修前端。
- 真实 UI 验收覆盖 frozen、full+none、partial、零治理、并发、权限、刷新/重启。
- 报告归档至 `.doc/test-reports/` 并回链;模块状态只依据有效证据更新。
## 相关链接
- Audit: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- Short-term: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../ops/short-term/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- 关联先例: [duty-etag-overwrite 审计](../audit/2026-09-13-document-revision-duty-etag-overwrite.md)
- gap-matrix 行: [WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES](./gap-matrix.md)
@@ -0,0 +1,58 @@
---
title: "HTTP 与 SSE 公开错误信封整改"
status: planned
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
---
# HTTP 与 SSE 公开错误信封整改
## 背景
Phase 2 复核确认错误信封涉及全部 HTTP 路由、SSE transport 和前端解析,属于独立 wire-contract 改造,不应阻塞持久事件交付。审阅见 [模块解耦 Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)。
## 目标
所有公开 HTTP/SSE 错误使用版本化、可脱敏、可测试的信封;客户端按 typed code 分支,不解析任意后端文案。迁移保持 additive,breaking 状态码变化必须另写 ADR。
## 契约
- 基础字段:`code`、固定安全 `message`、`request_id`、可选 `details`。
- 每个 code 单独维护 `details` 公开字段 allowlist;默认空。
- 禁止输出 raw error、SQL、堆栈、绝对路径、凭证、prompt、正文和跨租户资源 ID。
- 授权失败保持资源存在性不泄露;404/403 选择由现有授权策略决定。
- `VERSION_CONFLICT`、`IDEMPOTENCY_CONFLICT`、`VALIDATION`、`AUTHZ` 先建立领域错误到 wire code 的唯一映射。
- SSE error frame 与 HTTP 使用同一 code registry 和脱敏器,保留 transport 所需 event metadata。
## 分波次计划
| 波次 | 内容 | 验收 |
|---|---|---|
| H0 | 盘点路由、现有状态码、前端文本匹配和 SSE error frame | 路由矩阵与兼容风险签字 |
| H1 | 新增 envelope/code registry/request ID/details allowlist,旧字段 additive 保留 | schema/golden/negative tests |
| H2 | 前端逐 code 迁移,未知 code 显示安全通用错误 | 浏览器覆盖冲突、鉴权、校验、未知 code |
| H3 | 删除文本匹配和旧字段;若改变状态码先 ADR | 全路由 contract test;回滚窗口关闭 |
## 权限与安全验收
- 未授权用户无法从 code/message/details 区分资源存在性、owner 或项目成员。
- 任何 internal error 都只返回 request ID;完整诊断仅在受控服务端日志,且经过字段脱敏。
- 结构化 validation details 只包含公开字段名和稳定错误码,不回显原始输入。
- 日志按 request ID 关联,不把响应脱敏前对象序列化。
## 验收标准
- [ ] HTTP 与 SSE schema/golden 入 CI,所有公开端点有矩阵。
- [ ] 前端不再按 message substring 分支。
- [ ] XSS、路径/SQL/token/prompt/跨租户 ID 泄露负例通过。
- [ ] additive、switch、contract、rollback 各有 test report。
- [ ] 未改变的状态码保持兼容;breaking 变更有 ADR 与同步发布计划。
## 相关链接
- Audit: [Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- 上位路线: [Phase 2 修订计划](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Short-term: 实施前另建;H0 盘点见 [research](../ops/research/2026-09-15-http-error-envelope-h0-inventory.md)
- 实施 backlog: [long-term Track P](../ops/long-term/2026-09-15-track-p-protocol-implementation.md)
- gap-matrix 行: 当前为工程债,不单独作为 Track E 发布 blocker
@@ -0,0 +1,47 @@
---
title: "mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)"
status: planned
created: 2026-09-15
updated: 2026-09-15
---
# mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)
## 背景
[Audit 2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md):前端硬编码 mock 交付物(projectId 1/2/3/5201/6001+)与真实项目数字 ID 撞车,空项目展示「终审已生效」幻影受控文档与伪造法定职责人;mock 数据无环境门控且已进入生产构建产物;服务端权威清单为空时前端不回收本地多余项。
## 目标
1. 任何真实(服务端注册)项目的工作台**只显示**服务端 `document_records` + 该项目新建模板克隆项,永不出现 mock 幻影文档;
2. mock/demo 数据仅在显式开启的 demo 构建中生效(构建期注入,默认关闭);
3. 生产构建产物中不含 mock 文档正文与 mock 用户权限;
4. localStorage 已持久化的 mock 项在升级后一次性回收;
5. 前端对服务端清单做**双向对账**:服务端为权威,本地多余受控项下架(复用 ControlledInvalidationPlan/dropRecordKeys 机制)。
## 分波次计划
| 波次 | 内容 | 验收 |
|------|------|------|
| Wave 0 止血(低风险) | 1) `mergeWorkflowDocumentsFromServer` 增加对账回收:`category=workflow` 且 `isLegacyLocalMockDocId(docId)` 的本地项,在服务端清单返回(含空数组)时一律 drop(走 `dropRecordKeys` + 受控失效计划既有管道);2) 新建项目克隆模板的 docId 命名空间(`doc-p{projectId}-*`)与 mock 命名空间隔离校验测试 | test 环境新建项目后清单只剩 `doc-p1-*` 模板项;单测覆盖空清单回收 |
| Wave 1 demo 门控 | 1) 所有 demo 种子(mockDocuments/neuropulse/tenProjects/MOCK_USERS/MOCK 权限)收口到 `web/src/data/seeds/` 单一入口,导出统一 `DEMO_SEEDS`;2) 入口处 `if (!import.meta.env.VITE_ENABLE_DEMO_SEEDS) return EMPTY`(构建期常量,生产默认 false);3) `npm run build` 产物 grep 验证不含「4K超高清荧光」等特征串(`VITE_ENABLE_DEMO_SEEDS= npm run build`);4) demo 构建单独脚本 `build:demo` | 产物 grep 断言进 CI/前端测试;demo 模式显式 opt-in |
| Wave 2 存量清理 | 1) `loadDeliverables` 加载时一次性迁移:剔除命中 `isLegacyLocalMockDocId` 的持久化项(版本化 storage key bump);2) `loadUsers`/`loadProjects` 同理剔除 mock 用户/mock 项目(保留真实同步数据);3) 迁移写入 `storage.ts` 版本号,幂等可重放 | 升级后 localStorage 无 mock 残留;重复刷新幂等 |
| Wave 3 UI 语义防线 | 1) `DeckDrawer`/`DocGovActionBar` 对非服务端注册文档(无 ledger 事实)禁用生命周期徽章/治理按钮,显示「本地示例(不入账本)」占位标签;2) `visibleDeliverables` 统计口径排除 mock ID(防污染项目文档计数) | 空项目不再出现「终审已生效」徽章;组件测试 |
| Wave 4 验收与归档 | 1) test 环境真实新建项目全链路(新建→清单→刷新→重启容器)回归;2) dev 环境 id 1–3 项目抽检;3) `go vet` / `go test -short` / `cd web && npm test && npm run build` 全绿;4) test-report 归档 + gap-matrix 行 | 报告归档 `.doc/test-reports/`;gap-matrix 更新 |
## 验收标准
- [ ] test 新建项目:交付物清单 0 幻影文档,仅 `doc-p{id}-*` 模板项(lifecycleState=template)
- [ ] dev 项目 id 1/2/3:无 doc-001/doc-cusa-* 等幻影项
- [ ] 生产构建产物 grep 无 mock 特征串;demo 构建仅显式开启时含种子
- [ ] localStorage 升级迁移后无 mock 残留且幂等
- [ ] 服务端清单对账:服务端删除/为空时本地对应受控项下架
- [ ] 幻影文档(若 demo 模式保留)不带「终审已生效」徽章与治理操作
## 相关链接
- Audit: [../audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
- Short-term: [../ops/short-term/2026-09-16-clean-test-env-baseline.md](../ops/short-term/2026-09-16-clean-test-env-baseline.md)
- Test Report: [../test-reports/2026-09-16-clean-test-env-baseline-test-report.md](../test-reports/2026-09-16-clean-test-env-baseline-test-report.md)
- gap-matrix 行: 待补(发布 blocker:治理记录失实 / 跨环境影响)
- 既有同域防线: `web/src/features/documentRevision/revisionToolbarMount.ts`(isLegacyLocalMockDocId)、`web/src/lib/controlledDocHydrate.ts`(shouldLoadControlledContent)、`web/src/lib/deliverableSync.ts`(mergeWorkflowDocumentsFromServer)
@@ -0,0 +1,342 @@
---
title: "模块解耦 Phase 2:持久事件交付与后续解耦路线"
status: planned
created: 2026-09-15
updated: 2026-09-15
type: refactor
owner: TBD
---
# 模块解耦 Phase 2:持久事件交付与后续解耦路线
## 决策摘要
Phase 2 的核心交付只包含持久事件链:修正事件生产、补齐 PostgreSQL 投递实现、用无副作用 shadow 对账替换闭包桥,并以授权用户刷新/重启后的正文恢复作为停走门。
结构解耦(D4–D7)是独立轨道;HTTP 错误信封与 PI Runner typed result 各自单独立项。三条轨道分别验收,不能互相阻塞关闭。
本计划不拆微服务,不引入外部消息基础设施,不合入 FAV 分支,不删除历史数据,也不授权实施、合并或部署。
## 背景与纠偏
- 上位约束:[模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)、[架构设计](../system-design/2026-09-14-module-decoupling-architecture.md)、[Phase 1 计划](./2026-09-14-module-decoupling-refactor-plan.md)。
- 复核结论:[Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)。
- 现状调研:[IPC/RPC 现状评估](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)。
- `internal/events/pg.go` 目前只有信封写入与 SELECT 型 `ClaimIDs`,没有原子 lease、ack/fail、重试、dead-letter 的生产闭环。`internal/events/dispatcher_test.go` 只证明 `MemoryBus` 语义,不能作为 PG 运行证据。
- `docgov` 仅单向依赖 `docrevision` 的 Markdown canonical/hash 工具,不存在生产双向 import 环。
- `module-boundaries.yaml` 已有 `event_producers`/`event_consumers`;缺口是映射不完整、运行时注册未与静态清单校验。
- `docflow.Commands` 在部分生产 HTTP 路径临时构造,事件 sink 未稳定注入;其 envelope 仍写入 `Environment:"dev"`、`ProjectID:0`。未先修生产入口就开始 shadow,会得到虚假的零差异。
## 目标与边界
### Track E:持久事件交付(本计划核心)
目标:让 notify 与 projection 副作用在重复投递、进程崩溃、租约过期和重启后达到“至少一次投递、恰好一个可见结果”,并能从数据库追查每次 attempt。
包含 D1、D2、D3、D10、D11。Track E 完成后即可单独关闭,不等待结构或协议轨道。
### Track S:结构解耦(后续独立 go/no-go)
目标:移除 bizdev locator,收敛 stageflow/chat/intent 依赖,并消除 `docgov → docrevision` 的剩余工具依赖。包含 D4、D5、D6、D7a、D7b。
Track S 只有在 Track E 复盘后重新认领 mutex 才能开始;每个单元独立关闭。
### Track P:外部协议(另立 remediation)
- P1:HTTP/SSE 错误信封。
- P2:PI Runner typed-result-v1 rollout。
D8、D9 在本文件保留设计约束和立项入口,不属于 Track E/S 的 Definition of Done。独立方案见 [HTTP/SSE 错误信封](./2026-09-15-http-error-envelope-remediation.md) 与 [PI typed-result-v1](./2026-09-15-pi-typed-result-v1-remediation.md)。
### 明确排除
- U4/U5 的 path/sql_write 例外清零及其既有 owner。
- `feature/final-artifact-vault` 的审计、合入、subscriber 激活与真实副作用验收。本计划只预留 FAV event schema 和 disabled allowlist 条目。
- 全量 IPC/RPC、服务拆分、分布式事务协调器。
- 破坏性历史清理。旧事件只允许分类、隔离、修复或明确过期;任何删除另走审批计划。
## 需求与可追踪性
| ID | 要求 | 交付单元 | 核心验收 |
|---|---|---|---|
| E1 | PG delivery 状态机可生产运行 | D1 | 真实 PG 多 worker、崩溃点、fencing 测试 |
| E2 | 至少一次投递、一个可见结果 | D1/D2 | 副作用幂等键/事务 receipt;重复投递无重复可见结果 |
| E3 | 每次 attempt 可审计 | D1 | 不可变 attempt 表,日志不代替数据库审计 |
| E4 | 事件作用域真实且授权闭合 | D3/D11 | env/project/service principal/资源复核全部 fail closed |
| E5 | 闭包桥安全下线 | D2 | shadow 覆盖门通过;逐消费者切换;一窗口后删 API |
| E6 | 静态契约与运行注册一致 | D10 | allowlist 已有段补全;构建时 registry parity 门禁 |
| E7 | 历史脏数据不会误消费 | D11 | dry-run 清单;repair/quarantine/expire 决策可审计 |
| E8 | 用户刷新恢复 | D2 | 授权 UI 刷新/重启正文一致,无 projection-missing |
| S1 | bizdev 不再充当 locator | D4 | 8 个 getter 最终同批删除;无新调用方 |
| S2 | 用例类型归属清楚 | D5 | coordinator 不依赖 bizdev DTO |
| S3 | 剩余工具依赖消除 | D6 | docgov/docrevision 互不 import;canonical golden 一致 |
| S4 | intent/chat 可独立迁移 | D7a/D7b | 两条独立分支、mutex、验收与回滚 |
## 关键技术决策
1. **语义不写“exactly once delivery”。** Dispatcher 提供 at-least-once delivery。消费者用唯一键、事务 inbox/receipt、CAS 或 no-replace 提交保证 exactly-one visible outcome。
2. **shadow 不执行业务副作用。** 旧闭包仍是唯一真实写路径;shadow 只计算规范化 intended outcome,并写对账记录。禁止“闭包与消费者双写后比较”。
3. **独立 worker 进程。** 事件消费落在 `cmd/events`,与 HTTP 进程分开扩缩容;`internal/app` 不重复启动 dispatcher。该选择沿用 Phase 1 U6,避免两种拓扑并存。
4. **先证明事件源,再开始计时。** 三条文档链必须在同一 UoW 写入领域变化、envelope 和目标 delivery。PG 测试证明生产入口确实产生事件后,shadow 窗口才有效。
5. **每个消费者独立灰度。** 状态为 `off|shadow|live`,按 environment + consumer 配置。notify、workflow advance、projection 分开切换;FAV 保持 off。
6. **静态 allowlist 与运行 registry 同源。** `module-boundaries.yaml` 现有映射补全后生成或校验只读 registry manifest;生产禁止未登记的动态注册。
7. **历史事件先盘点。** 作用域为 0、环境错误、未知 consumer、序列不连续或 payload schema 未知的旧记录不得自动 live 消费。
8. **结构与协议不绑核心关闭。** Track E、S、P 分别有状态、停走门、测试报告和回滚点。
## 目标拓扑
```mermaid
flowchart LR
HTTP[server/use case] -->|domain change + envelope + deliveries / one UoW| PG[(PostgreSQL)]
WK[cmd/events] -->|atomic lease| PG
WK --> N[notify]
WK --> A[workflow advance]
WK --> P[projection]
N -->|idempotency key| PG
A -->|transactional inbox| PG
P -->|expected head + digest| WS[workspace projection]
F[FAV contract] -. disabled .-> WK
```
## 数据模型与并发协议
### Delivery 状态机
```text
pending -> leased -> acked
|-> pending transient failure / lease expiry
|-> dead max attempts or explicit permanent failure
|-> quarantine scope, schema, integrity or ordering violation
```
- Claim 必须在一个短事务内 `WITH candidates AS (SELECT ... FOR UPDATE SKIP LOCKED LIMIT ...) UPDATE ... FROM candidates ... RETURNING`,同时写 `lease_owner`、递增 `fencing_token`、`lease_until`、`attempt`。现有 SELECT-only `ClaimIDs` 不满足此条件。
- Handler 在 claim 事务外执行。Fencing token 必须随 consumer command 传到最终副作用提交点;数据库副作用在同一事务校验 token,projection marker 使用 expected version + 单调 token。Ack/fail 也必须匹配 `event_id + consumer + lease_owner + fencing_token`。旧 token 的副作用和 ack/fail 都必须失败。
- 长任务按受保护的 token 续租;heartbeat 失败立即取消 handler。停机先停止 claim,再等待 inflight 或安全释放租约。
- 同一 consumer + aggregate 同时最多一个 inflight;不同 aggregate 可并行。不能把领域版本号直接假设为无缺口事件序号。
- D11 必须在以下两种模型中选一并写 ADR/迁移:独立无缺口 event sequence;或 consumer checkpoint + 首事件 bootstrap。未决前禁止启用 gap 阻塞。
### 副作用原子性
| 消费者 | 可见结果契约 | 崩溃窗口处理 |
|---|---|---|
| notify | `event_id + recipient + notification_kind` 唯一键 | 通知写入与 inbox 同一 PG 事务;重放命中唯一键即视为成功 |
| workflow advance | `event_id + transition` 唯一 receipt;重新读取当前状态和权限 | 领域转换、outbox、inbox 同一 UoW;状态已前进时按 receipt 判定 |
| projection | `document_id + source_snapshot_id + digest` no-replace;expected head | 文件先写临时对象并 fsync,再原子提交 marker;重放核对 digest |
| FAV | 本计划不激活 | 由 FAV 审计定义 source-event/digest no-replace 契约 |
副作用完成后、delivery ack 前必须注入崩溃。恢复后可重复调用 handler,但最终只有一个可见结果。
### 审计表
Additive migration 新增不可变 `event_delivery_attempts`,至少记录:event、consumer、attempt、lease owner、fencing token、started/finished、outcome、typed error code、correlation ID。`event_deliveries` 只保存当前游标和状态。
attempt、dead-letter、shadow reconciliation 只存 ID、digest、typed code 和字段 allowlist 生成的摘要。禁止保存原始 payload、SQL error、绝对路径、token、prompt 或正文。
## 权限模型
| 动作 | 主体 | 必须校验 | 禁止 |
|---|---|---|---|
| 普通消费 | 每个 consumer 独立 service principal | environment、project、consumer、action;副作用前重读资源归属和当前状态 | 继承原用户会话、跨项目查询、共享万能 principal |
| shadow | ops service principal | 只写 reconciliation;不持有业务写权限 | 调用真实通知/推进/投影写端口 |
| replay dry-run | 具备事件运维 capability 的管理员 | env/project/consumer/event 范围、reason、approval ref | 无范围全库扫描、原始 payload 回显 |
| replay apply | 同一操作者能力 + 未过期 plan digest | apply 参数必须与 dry-run digest 完全相同 | 现场改范围;绕过资源当前授权 |
| 多项目/批量 replay | 两人批准 | operator 与 approver 分离;不可变审计 | 单人直接执行 |
worker 数据库角色只授予其拥有表和调用端口所需权限。Replay 是应用用例,不提供裸 SQL 运维入口。授权失败、资源已转移、project 不存在或 env 不匹配一律 quarantine,不重试为 transient。
## 分波计划
### E0A:生产者、契约与旧数据门(D3、D10、D11)
进入条件:认领 `events/app/arch` mutex;dispatcher 保持 off。
交付:
1. 组合根构造唯一 `docflow.Commands`,向 server 注入 UoW、PGSink、environment与 project resolver;禁止 HTTP handler 临时漏注入。
2. candidate-ready、downstream-impact、approved 三条链在领域提交同一 UoW 内写 envelope 和目标 delivery。
3. 修正 `Environment/ProjectID`,缺值 fail closed;先清点历史 `0/dev` 记录。
4. 补全现有 event allowlist,校验生产者、消费者、payload schema、运行 registry parity。
5. 生成历史事件 dry-run manifest,逐条分类为 safe、repair、quarantine、expire;不删数据。
6. 决定连续性模型,审计 `(aggregate_type, aggregate_id, aggregate_version)` 唯一约束是否允许同一版本多个事件;必要时 additive migration。
退出门:真实 PG 测试证明每条生产链产生正确 envelope/delivery;历史清单有审批结论;未登记事件和动态 consumer 构建失败。
### E0B:PG dispatcher 基座(D1)
进入条件:E0A 全部通过;旧数据不会进入 live claim。
交付:
1. 完成原子 lease、heartbeat、fenced ack/fail、backoff、dead/quarantine 和 attempt audit。
2. 新建 `cmd/events`;每个环境单独容器、配置和 DB 连接预算。HTTP Runtime 不启动 worker。
3. 增加 readiness(DB、registry、schema)、liveness、queue age、oldest pending、claim/ack/fail/fenced、attempt latency、dead/quarantine 指标。
4. 默认从 Phase 1 基线起步:batch 50、lease 30s、heartbeat 10s、max attempts 12、backoff ceiling 15m;压测报告才能调整。
5. 以 1/2/4 worker 验证无双 lease、跨 aggregate 并行、同 aggregate 串行、连接池有界和公平性。
退出门:PG 集成与 race 测试通过;在副作用后/ack 前、续租前后、停机 drain 等崩溃点均可恢复;资源预算和 p50/p95/p99 基线归档。
### E1A:notify shadow 与切换(D2-notify)
1. 旧闭包产生 canonical outcome;shadow handler 产生 intended outcome。两者经同一规范化器比较收件人、类型、去重键、payload digest。
2. E0A 根据经作用域校验和审批的前 7 天有效事件基线为每个 event type 预登记最小样本 N,N 不低于 30;低流量分支补确定性 replay fixture。窗口不少于 3 个完整日,并覆盖成功、授权拒绝、重复和 permanent failure。
3. 任一未解释 diff、越权、原始 payload 泄露或样本不足均重置窗口。
4. `off|shadow|live` 是带 revision 的集群级受控状态,不是单实例环境变量。先部署同时理解新旧模式的兼容代码,drain 并确认旧实例全部退出,再原子切换权威写者。
5. 先把 notify 置 live;闭包 notify 路径置 off。保留显式回滚开关一个发布窗口。
退出门:重复投递只有一个通知;重启不丢;correlation ID 可查 producer→attempt→receipt;回滚演练通过。
### E1B:workflow advance shadow 与切换(D2-advance)
批准事务必须发布 typed approved event。Consumer 在副作用前重读 document/project/workflow 状态和 service principal 权限。按 E1A 同样的 coverage gate 切换,随后移除批准 hook 注册。
退出门:并发批准只推进一次;陈旧或跨项目事件 quarantine;阶段推进产生的下游事件保持 causation/correlation;回滚演练通过。
### E1C:projection 恢复纵切(D2-projection)
在副作用前、副作用后/ack 前、lease 过期后三个位置终止 worker并重启。授权用户通过真实页面刷新和重新打开文档,正文必须与数据库 head/snapshot digest 一致,不出现 `projection missing`,不产生重复版本。未授权用户仍得到非泄露式拒绝。
退出门:真实 PG + browser + worker restart 报告通过;按 correlation ID 能还原完整链路。FAV 仍为 off。
### E2:核心收口
- 删除 `OnOutbox =`、`AddOnApprovedHook(` 等生产注册点。
- 保留 API 一个发布窗口后,再独立 contract 提交删除字段/方法本体。
- Track E 的 release blocker 关闭;Track S/P 保持各自状态,不拖延此关闭。
## 实施单元明细
### D1:PG dispatcher 与 attempt audit
主要文件:`deploy/postgres/goose/<next>_event_dispatcher.sql`、`internal/events/pg.go`、`internal/events/dispatcher.go`、`cmd/events/main.go`、环境 compose/config。
必须交付 E0B 的状态机、进程拓扑、连接预算、指标和真实 PG 故障注入。MemoryBus 测试只作快速 characterization,不计生产验收。
### D2:闭包迁移
主要文件:`internal/docrevision/service.go`、`internal/docgov/engine.go`、`internal/app/app.go`、`internal/app/docnotify`、projection owner。
拆成 notify、workflow advance、projection 三个 short-term。Shadow 只写 reconciliation;每个消费者都有独立 `off|shadow|live`、停走门和回滚演练。最后一个 live 窗口结束后才能删除 hook API。
### D3:事件生产与作用域
主要文件:`internal/app/docflow/commands.go`、server 注入点、`internal/taskrun/finalize.go`。
修复生产入口漏注入和硬编码。事件构造必须从已授权服务端上下文与持久记录取得 environment/project;客户端字段不可信。FAV staging 调用不属于 Track E;FAV disabled 时,生产链不得写 staging、artifact 或 publication 记录。`Fav.StageAgentCommit(ctx, 0, ...)` 的真实 project scope 修复随独立 FAV 审计实施。
### D10:事件契约与 registry parity
主要文件:`.doc/system-design/module-boundaries.yaml`、`internal/archtest`、registry manifest 生成/校验代码。
不是“新增 allowlist 段”,而是补全已有段并把 payload schema/version、合法 producer、合法 consumer、enabled state 一并校验。运行 registry 必须是静态清单的子集;FAV 条目标记 disabled。
### D11:历史数据与序列安全
主要文件:additive migration、只读 inventory/replay use case、审计报告。
交付历史清单、序列模型、约束审计、repair/quarantine/expire 规则。修复必须保留 old/new digest、operator、reason、approval;禁止原地无审计改值。
### D4:bizdev locator 最终移除
先加 no-new-callers 门禁,再分批把调用方迁移到消费者端口。准备工作可分批;8 个 getter 的最终删除必须在一个 contract 提交完成。规则只禁止领域/用例 API 暴露、返回或转发 pool/tx;允许 app/cmd 组合根向表属主构造器注入 pool,也允许登记属主从 opaque TxScope 解出 tx。
### D5:stageflow 类型归属
`stageflow` 定义 use-case request/result,并在 app 边界适配 bizdev 领域类型。行为方法不能机械复制成 DTO。用 mapping golden 和 characterization 锁定语义;coordinator 最终不 import bizdev。
### D6:移除单向 canonical 工具依赖
当前不是循环。把 Markdown canonicalization 与 SHA 作为一个内聚的共享行为模块(建议 `internal/doccontent`)提取,提供 golden vectors。禁止把带行为的 canonicalizer 塞入 vocabulary。完成后 docgov/docrevision 互不 import。
D6 不依赖 D4/D5,只受 docgov/docrevision mutex 与 U4/U5 排期约束。
### D7a:intent 与 bizdev 解绑
为 intent 注入最小只读消费者端口;单独分支、characterization、mutex 和验收。不得等待 chat 迁移。
### D7b:chat 编排迁入 chatflow
逐用例迁移,保留 handler characterization。只有 D4 提供所需端口后才开始;禁止“一次搬空包”。每批收紧一条 import 规则并可独立回滚。
### D8:HTTP/SSE 错误信封立项约束
另建 remediation。公开 wire 至少为 `code/message/request_id/details?`;`message` 使用固定安全文案,`details` 按 code 维护公开字段 allowlist。不得回传 raw error、SQL、路径、凭证、prompt、正文或跨租户 ID。授权拒绝保持资源存在性不泄露。全路由、SSE 与前端迁移各有 golden/negative test。
### D9:PI typed-result-v1 rollout 立项约束
另建 remediation,不称“协议 v2”。只有 typed 字段完全缺失且握手明确声明旧 Runner 时才允许 legacy;typed 字段存在但 schema/digest/path/run_id/size 校验失败必须 fail closed,禁止降级。真实 PI E2E 覆盖取消、超时、未知 schema、超限输出、secret/prompt 注入与 downgrade attack。
## 迁移、部署与回滚
| 阶段 | 部署顺序 | 可回滚动作 | 禁止 |
|---|---|---|---|
| expand | additive migration → producer 修复 → registry | worker 保持 off;回滚应用不删表 | 旧数据直接 live claim |
| shadow | worker shadow → reconciliation | consumer 置 off;保留记录 | 执行业务副作用;清空 diff |
| switch | 部署兼容代码 → drain 旧实例 → 记录 backlog 水位 → 原子切换单 consumer live/闭包 off | 暂停 claim,核对已执行 receipt 与 backlog,再 live off + 对应闭包 on;只在兼容窗口内 | 滚动部署时同时开启两条真实写路径 |
| contract | 一发布窗口后删 hook API | 通过新提交恢复,不回滚 schema | 删除 delivery/attempt 历史 |
回滚期间禁止同时 replay。恢复 live 前必须重新做 backlog dry-run,并确认旧 lease 已失效。Migration 只 additive;任何表/列删除另立计划。
## 分支、mutex 与交付件
| 单元 | mutex | 分支示例 | 独立报告 |
|---|---|---|---|
| D3/D10/D11 | events + app + arch | `fix/event-production-scope-contract` | E0A |
| D1 | events + deploy | `feature/events-dispatcher-pg` | E0B |
| D2-notify | events + docnotify | `fix/event-notify-cutover` | E1A |
| D2-advance | events + workflow | `fix/event-workflow-cutover` | E1B |
| D2-projection | events + docgov | `fix/event-projection-recovery` | E1C |
| D4 | bizdev | `fix/bizdev-locator-removal` | S1 |
| D5 | stageflow + coordinator | `fix/stageflow-type-ownership` | S2 |
| D6 | docgov + docrevision | `fix/doccontent-canonical-boundary` | S3 |
| D7a | intent | `fix/intent-bizdev-boundary` | S4a |
| D7b | chat + chatflow | `fix/chatflow-orchestration-boundary` | S4b |
每行先建 short-term 并登记 CURRENT。合入 dev 与共享容器验证必须占集成槽位。
## 验收与停走门
### Track E Definition of Done
- [ ] E1–E8 均有证据链接;E0A/E0B/E1A/E1B/E1C 各有独立 test report。
- [ ] PG 状态机、attempt audit、1/2/4 worker、race、崩溃点、fencing、顺序、背压和连接预算通过。
- [ ] notify/workflow/projection 分别完成 shadow coverage、切换和回滚演练;FAV 保持 disabled。
- [ ] 生产注册代码无 `OnOutbox =`、无 `AddOnApprovedHook(`;不存在 HTTP 与 worker 双重接线。
- [ ] 授权 UI 在三类 worker 重启点刷新/重开正文一致;未授权与跨项目负例通过。
- [ ] replay dry-run/apply digest、service principal、字段脱敏、双人批量审批负例通过。
- [ ] arch-check block、`go test -race` 目标包、`go test -short ./...`、PG 集成、browser/restart 全绿。
- [ ] CURRENT、FEATURE-MATRIX、gap-matrix 只关闭事件可靠性 blocker,不把 Track S/P 写成已完成。
### Track S 单元 DoD
D4–D7b 各自满足需求表中的 S1–S4、独立测试报告和 arch rule 收紧即可关闭;无需等待其他结构单元。
### Track P 立项门
D8、D9 各有独立 remediation、owner、范围、兼容矩阵、negative tests 和真实验收计划。本 Phase 2 不要求其实现完成。
## 风险与控制
| 风险 | 控制 |
|---|---|
| shadow 因无事件源虚假通过 | E0A 先证明每条生产入口写 envelope/delivery,之后才开始计时 |
| 领域版本缺号永久阻塞 | D11 明确 event sequence 或 checkpoint/bootstrap,不把 version 当连续事件号 |
| 副作用成功但 ack 丢失 | 每消费者幂等契约;真实崩溃注入;fenced ack |
| 重试覆盖历史 | immutable attempts;delivery 只存当前状态 |
| 脏旧事件跨环境/项目执行 | inventory + quarantine;资源当前授权复核;service principal 最小权限 |
| worker 抢光连接 | 独立 pool 预算、inflight 上限、queue/backpressure 指标、压测后调参 |
| poison event 阻塞 aggregate | quarantine 需显式审批;不静默跳号;其他 aggregate 继续 |
| shadow/replay 泄密 | schema 字段 allowlist、digest 摘要、无 raw payload/error |
| FAV 拖住核心 | 只预留 disabled 契约;激活归独立 FAV 计划 |
| 结构改造扩大爆炸半径 | no-new-callers 先行;小批迁移;最终 getter 原子删除 |
## 相关链接
- [方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- [现状调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
- [Phase 1 计划](./2026-09-14-module-decoupling-refactor-plan.md)
- [模块化单体 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)
- [模块边界清单](../system-design/module-boundaries.yaml)
- [Track E 任务入口](../ops/short-term/2026-09-15-durable-event-track-e.md)
- [HTTP/SSE 错误信封独立方案](./2026-09-15-http-error-envelope-remediation.md)
- [PI typed-result-v1 独立方案](./2026-09-15-pi-typed-result-v1-remediation.md)
- [发布缺口 SSOT](./gap-matrix.md)
@@ -0,0 +1,60 @@
---
title: "PI Runner typed-result-v1 迁移方案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
---
# PI Runner typed-result-v1 迁移方案
## 背景
PI Runner 已有 HTTP/Bearer 传输边界,但结果仍兼容 stdout/result.json。该工作是 Runner、taskrun、agent adapter 和真实 PI E2E 的独立协议迁移,不应称“协议 v2”,也不阻塞持久事件交付。
## 目标
`/v1/run` 返回带 schema version、run identity、member 清单、digest 和 typed outcome 的 `result_v1`。服务端严格校验后持久化;legacy 只在明确的旧 Runner 能力握手下保留一个发布窗口。
## 契约与降级规则
- JSON Schema:`configs/schemas/pi-run-result-v1.json`,canonical JSON 与 digest 规则固定。
- 结果至少包含 `schema_version`、`run_id`、`members[]`、typed success/error、retryable、content digest;member kind 使用 allowlist。
- Runner capability/handshake 明确声明是否支持 typed result,并与响应绑定。
- typed 字段完全缺失且握手声明旧 Runner 时,才允许 legacy。
- typed 字段存在但 schema、digest、run ID、member path、size 或 secret 检查失败时 fail closed,禁止 fallback。
- 文件路径必须落在本次 run 的受控输出根;拒绝绝对路径、`..`、symlink escape 和超限成员。
- error 分类和 retryable 由 allowlist 决定,不接受模型任意字符串控制重试。
## 分波次计划
| 波次 | 内容 | 验收 |
|---|---|---|
| P0 | 盘点 legacy 输出、最大体积、取消/超时语义和真实 Runner 版本 | compatibility matrix 与 schema review |
| P1 | Runner additive 输出 `result_v1`,旧字段保留 | Runner schema/golden、大小/路径/secret 负例 |
| P2 | Go parser typed-first 严格校验,按握手决定 legacy | downgrade、未知 major、digest/run mismatch fail closed |
| P3 | dev 真实 PI 双轨对账一个发布窗口 | `RUN_PI_E2E=1`;取消、超时、成功、失败均一致 |
| P4 | 删除 legacy parser/字段 | contract test 与前滚/回滚说明归档 |
## 高并发与安全
- `run_id`、request id、project/environment 和 backend identity 全链关联;禁止一个 run 接受另一个 run 的结果。
- Parser 在分配大对象前执行 body/member 数量与尺寸上限;压缩输入限制解压比。
- cancel 与 result 竞争使用单调终态:只允许一个 terminal outcome,晚到结果审计后丢弃。
- Runner 输出视为不可信输入;字段、路径、MIME、编码和文本均需验证。不得把 prompt、token 或完整模型 stderr 放入结果或公开日志。
## 验收标准
- [x] Schema/golden 在 Runner 与 Go 两侧共享并入 CI。
- [x] typed-present-invalid 永不 fallback;handshake downgrade attack 负例通过。
- [x] 并发 run/result 串线、cancel/result 竞争、超限与 path escape 负例通过。
- [x] 真实 PI E2E 覆盖成功、typed error、取消、超时与未知 schema。
- [x] legacy 删除前完成一个发布窗口对账和回滚演练。
## 相关链接
- Audit: [Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- 上位路线: [Phase 2 修订计划](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Short-term: 实施前另建;P0 矩阵见 [research](../ops/research/2026-09-15-pi-typed-result-p0-matrix.md)
- 实施 backlog: [long-term Track P](../ops/long-term/2026-09-15-track-p-protocol-implementation.md)
- gap-matrix 行: 当前为工程债,不单独作为 Track E 发布 blocker
@@ -0,0 +1,55 @@
---
title: Demo/测试数据污染整改方案
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: fix/demo-data-pollution-web
mutex: web
---
# Demo / 测试数据污染整改方案
## 目标
生产构建默认无演示文案;权威服务端空清单回收本地 mock;DB 演示项目不进列表;main 拒绝 stub。
## 波次与状态
| Wave | 内容 | 状态 |
|------|------|------|
| 0 | `isDemoSeedDocId` + `mergeWorkflowDocumentsFromServer` 空清单 drop | done |
| 1 | `VITE_ENABLE_DEMO_SEEDS` + `@demo-seeds` alias + `check-prod-bundle.sh` | done |
| 2 | `purgeDemoSeedsFromLocalStorage` 幂等迁移 | done |
| 3 | DeckDrawer「本地示例」徽章;职责人默认值清空 | done |
| 4 | goose `00046` retire projects + `00047` retire sessions + list/`ListChatSessions` 过滤 | done |
| 5 | `ResolveBackendInEnv` main/prod 拒 stub | done |
| 6 | 审计/整改/报告/gap-matrix | done |
## 关键实现
- 判定:[`web/src/data/demoSeedIds.ts`](../../web/src/data/demoSeedIds.ts)
- 门控:[`web/vite.config.ts`](../../web/vite.config.ts) alias `@demo-seeds` → enabled/disabled
- 同步:[`web/src/lib/deliverableSync.ts`](../../web/src/lib/deliverableSync.ts)
- DB:[`deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql`](../../deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql)
- Stub:[`internal/taskrun/backend.go`](../../internal/taskrun/backend.go)
## 验收标准
- [x] 默认 `npm run build` 后 `check-prod-bundle.sh` PASS
- [x] 空 server 清单 drop demo-seed 单测 PASS
- [x] `ResolveBackendInEnv(..., "main")` 拒 stub 单测 PASS
- [x] 共享环境 migrate `00046`/`00047` 后列表无 6001–6010(dev schema 47)
- [x] 新建空项目 UI/API 交付物无伪造 approved(项目 6357 documents=0)
## 启用 Demo(仅本地/评审)
```bash
VITE_ENABLE_DEMO_SEEDS=true npm run dev
```
## Follow-up(P2,不挡合入)
- stub 旁路:`resolveTaskBackend` 双重失败返回 `""` 时 squad 回落 `cfg.AgentBackend`;建议 main/prod 启动 fail-fast 校验 `AGENT_BACKEND≠stub`
- `purgeDemoSeedsFromLocalStorage` 对 projectId 1/2/3 无 serverIds 守卫,可能清掉 test 环境真实本地会话缓存;长期改为按 `sess-neuropulse-*` / `sess-wangjing-*` 前缀或注释权衡
- 姊妹分支 `fix/clean-test-env-baseline` 重叠前端清理已放弃;已挑拣 `a91a031`(`SEED_DEMO_USERS=false`)与 2026-09-15 审计回链
+5
View File
@@ -3,6 +3,11 @@
| 文档 | 说明 |
|------|------|
| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT |
| [2026-09-14-module-decoupling-refactor-plan.md](./2026-09-14-module-decoupling-refactor-plan.md) | 纵向绞杀、UnitOfWork、高并发互斥、可靠事件、逐动作授权、FAV、迁移与恢复的详细重构计划 |
| [2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md) | Phase 2 修订版:Track E 持久事件交付先行;Track S 结构解耦独立 go/no-go;HTTP 与 PI 协议另立 remediation([审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)) |
| [2026-09-15-http-error-envelope-remediation.md](./2026-09-15-http-error-envelope-remediation.md) | HTTP/SSE typed error envelope、公开 details allowlist、前端 additive 迁移与安全负例 |
| [2026-09-15-pi-typed-result-v1-remediation.md](./2026-09-15-pi-typed-result-v1-remediation.md) | PI Runner typed-result-v1 schema、严格降级、并发终态与真实 PI 双轨验收 |
| [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](./2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md) | 项目设置 409 冻结态守卫 + 非必需文档三权全有或全无 + 成员/门禁/权限一致性 |
| [2026-09-14-controlled-content-canonical-hash-remediation.md](./2026-09-14-controlled-content-canonical-hash-remediation.md) | 项目 143 正文 canonical/raw 哈希漂移、错误语义与重复 hydration 整改 |
| [2026-09-13-document-revision-reviewer-duty-sync.md](./2026-09-13-document-revision-reviewer-duty-sync.md) | UI-01 已分配 B=reviewer,受控文档 reviewer_id 硬编码 2,矩阵降为 viewer |
| [2026-09-13-document-revision-duty-cell-assertion.md](./2026-09-13-document-revision-duty-cell-assertion.md) | UI-13a 整行 option 文案误判编制负责人,须读 select value/badge |
+19 -13
View File
@@ -1,10 +1,10 @@
# 整改缺口复核矩阵(SSOT)
**更新**: 2026-09-14
**更新**: 2026-09-16
**分支**: dev
**production_ready**: no(`CHAT-INTENT-STATE` 等无关 blocker、CI 真实 PI 三工作流 E2E / 前端人工抽检未完成;文档账本运行时 UI Round20 已 PASS,不把 fallback 报告当成完整 PI)
**production_ready**: yes(发布门禁 B1–B4 已签;dev/test/main schema=47。U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发)
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md)
**Agent 手册**: [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md)
> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。
@@ -21,7 +21,7 @@
| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 |
| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 |
| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 |
| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` |
| BUG-08 | 测试库隔离 | PASS | `db/testdb.go` Require/Skip;CI `TEST_DATABASE_URL` + governance PG 步骤;[report](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md) | 已完成 |
| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 |
| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 |
| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 |
@@ -41,6 +41,9 @@
| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval |
| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 |
| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 |
| DEMO-DB-SEED | goose 00011/00012 演示项目污染列表 | **PASS** | `00046` retire projects + `00047` retire chat_sessions;`ListProjects*` / `ListChatSessions` 过滤 `demo_retired`;dev migrate schema **47**;抽检项目列表无 6001–6010、user1/2/3 无 `sess-wangjing*`、新建项目 6357 documents=0 | [audit](../audit/2026-09-16-demo-seed-pollution-systemic.md);前序 [2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md);[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
| DEMO-STUB-API | main/prod 仍可请求 stub Agent | **PASS** | `ResolveBackendInEnv`;`TestResolveBackendInEnv_RejectsStubInMain` |
| DEMO-WEB-SEEDS | 前端 mock/seed 进生产包并撞 projectId | **PASS** | `@demo-seeds` 默认关闭;`check-prod-bundle.sh` PASS;[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` |
| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 |
| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 |
@@ -57,9 +60,10 @@
| 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 | 真实 PI 生成 full/none 并走审批/阶段不阻塞未纳入本轮页面矩阵,不作为本 gap 关闭的替代证据,另立项 |
| 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 的替代证据 |
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 真实 PI 刷新 E2E 待 dev 容器补录(自动化/PG 已 PASS) |
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **FAIL** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);dev `sess-p143-u9` / task run / lease 现场 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.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` |
| DOCREV-RUNTIME-404 | revision-state 404;账本内存丢失;块保存/overlay 无效;agent 假报告 | **PASS** | [Round20 报告](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[audit](../audit/2026-09-13-document-revision-runtime-404.md) | 运行时 UI 已闭环。change report 仍为 fallback,不冒充 PI。历史失败目录不删 |
| DOCREV-PG-ID-REMAP | 首次生成 PG 已写 snapshot/candidate,commit 因内存误删 baseline 而 not found | **PASS** | [audit](../audit/2026-09-13-document-revision-pg-id-remap.md);Round19 归档 `schema31-round19-ui03-advisor-briefing-docrevision-not-found`(candidate id=175 / output snapshot 250,禁止写成 candidate 250);Round20 UI-03 V2/r0 | 已合入 `dev@b258ab8`;不忽略 ErrNotFound;不删证据 |
@@ -68,6 +72,8 @@
| DOCREV-QUALITY-SELF-POLLUTE | 自检表引用禁词致 score=40 quality_failed;auto_repair 未启用;UI 映射 completed | **PASS** | [audit](../audit/2026-09-13-document-revision-quality-gate-self-pollution.md);Round20 UI-03 完成 | 不删证据;不删禁词 |
| DOCREV-ACTIVE-DOC-ROUTING | UI-05「当前受控文档」被法规关键词改路由到 `feasibility_reg`,intake 无 pending | **PASS** | [audit](../audit/2026-09-13-document-revision-active-doc-routing.md);Round20 UI-05 pending 停在 intake V2 | **不改弱 E2E**;不删证据 |
| DOCREV-QUALITY-STATUS-FP | 行动计划表状态列「待续」被门禁当敷衍,两轮 repair 后 quality_failed 80 | **PASS** | [audit](../audit/2026-09-13-document-revision-quality-status-false-positive.md);Round20 UI-03 | **不删禁词、不放宽正文**;不删证据 |
| GOVERNANCE-ACTION-AUTHZ | 文档动作按职责鉴权;未激活 202-blocked;关闭创建直通 | **PASS** | [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[audit 异态](../audit/2026-09-14-planning-with-workflow-key-anomaly.md) | 不改 83 条 planning+key 夹具;none 长 PI 审批链另开 |
| DOC-RELIABILITY-PILOT | 受控文档写路径与 PG 事件交付尚未形成生产闭环;闭包副作用在崩溃/重启后不可重试审计,错误 scope 或 projection 缺失仍可能导致刷新失败 | **PASS** | [初审](../audit/2026-09-14-module-decoupling-plan-review.md);[Phase 1](./2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 复核](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[U11–U12 报告](../test-reports/2026-09-15-app-composition-u11-u12-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[notify live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[advance live](../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md);[projection live](../test-reports/2026-09-15-event-projection-shared-live-test-report.md) | 共享 notify/workflow_advance/projection 已 live;生产不再注册 `OnOutbox=` / `AddOnApprovedHook(`。FAV 仍 off。HTTP/PI 实施不纳入本行。项目 143 只读 |
---
@@ -76,13 +82,13 @@
```
☑ go vet ./... 全绿
☑ go test -short ./... 全绿
□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token)
□ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过
☑ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
☑ 真实 PI Agent 三工作流治理 E2E 实录([test-report](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md))
☑ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过([test-report](../test-reports/2026-09-16-chat-refresh-gate-test-report.md);项目 6359)
☑ lifecycle fix SQL 已在 dev 执行
☑ test/dev health schema_version=25
☑ main 环境部署冒烟(本地 8000 health/ready schema 25)
□ 前端:版本冲突刷新、终止 preview 人工抽检
☑ test/dev health schema_version=47
☑ main 环境部署冒烟(本地 8000;schema 对齐见 CURRENT)
☑ 前端:版本冲突刷新、终止 preview 人工抽检([test-report](../test-reports/2026-09-16-frontend-gate-b4-test-report.md);项目 6363)
```
**结论**: 文档账本运行时真实 UI Round20 **PASS**(见 [test-report](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md))。**发布 blocker 仍包括 `CHAT-INTENT-STATE`、CI 真实 PI 三工作流 E2E 与前端人工抽检**;`-race` 全包并行 TempDir flake 为测试基建残留。不得把 fallback change report 写成完整 PI 叙事。
**结论**: 发布门禁四框已签。文档账本运行时 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 叙事。
+10 -8
View File
@@ -1,7 +1,7 @@
# 模块与功能完成度(SSOT)
**更新**: 2026-09-14
**production_ready**: no
**更新**: 2026-09-16
**production_ready**: yes
**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
@@ -15,18 +15,20 @@
| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex |
|------|------|------|------|-----------|-------|
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 明确写动作与只读总结已分流;完整 hard-negative/eval 集仍待补齐 | `intent` |
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | `CHAT-HISTORY-REFRESH`:作用域写入、同集授权统计、历史回填;语义摘要(D5 backlog) | `chat` |
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/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);[多意图复核方案](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1 契约](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2 分段](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3 PG](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | 明确写动作与只读总结已分流;双标签 `DOC_BUSY` 已签(项目 6275)。多意图核心 U1–U8 已完成;U9–U12 不阻塞首版。intent 纯依赖边界不得回退 | `intent` |
| 多意图持久计划 | app/intentflow 生命周期与 HITL 契约 | partial | [设计](../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) | U1–U8 核心首版已完成。U9–U12 不阻塞。默认 tier=legacy。真实 PI generate 待 runner URL。共享环境 schema 45 待晋升 | `intent-plan` |
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10 端口化](../archive/ops/2026-09-15-chatlog-contextasm-u10.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) | `CHAT-HISTORY-REFRESH` 与发布门禁「激活后文档任务 + 重登/重启」已签(项目 6359)。U10 原地端口 **停止扩面**。语义摘要(D5 backlog) | `chat` |
| 智能体小队 | 角色-任务-工作区-黑板 | done | [system-design/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` |
| 工作流治理 | 三正式工作流 + 阶段门禁 | done | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md) | Phase2 设计器 partial | `workflow` |
| 工作流治理 | 三正式工作流 + 阶段门禁 | partial | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md);[冻结态/职责可选整改](../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md);[Wave 5 页面矩阵](../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) | 设置页/DutyMode + 动作级鉴权已落地;真实 PI 三工作流 E2E 已签。后续:none 文档真实 PI 审批长链路;模块可仍 partial | `workflow` |
| 纯软件项目自举 | 软件项目创建、Bootstrap 基线、Delivery 迭代与受控工程交接 | planned | [详细设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[现状调研](../ops/research/2026-09-14-software-project-bootstrap-current-state.md);[验收计划](../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md) | 当前仅完成方案;目录/模板/执行器/创建向导/真实 PI UI 均未实施。受控代码执行单列后续 Epic | `workflow-design` |
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | partial | [audit/authorization](../audit/authorization-matrix-v2.md);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | 历史读取端点补统一会话 owner + 阶段授权;旧 API 410 标注(BUG-11 partial) | `authz` |
| 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[项目 143 正文 404 审计](../audit/2026-09-14-project143-controlled-content-404.md);[受控正文真实 UI 验收报告](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[UI-06 缓存竞争审计](../audit/2026-09-14-document-revision-refresh-cache-race.md);[整改](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md) | 生命周期/租约保留。W1–W6 + 审查修补 + UI hydrate 资格 + 晚到 list sync 修复均已合入 dev。项目 143 纯 UI 回归(clean-run3)与新项目全链路(main + post-restart)已全量真实页面验证通过(PASS) | `docgov` |
| 文档版本与修改认知 | 智能体版本边界、人工修订标记、任意版本比较、变更报告与负责人通知 | partial | [管理测试](../test-reports/2026-09-13-document-revision-management-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[运行时审计](../audit/2026-09-13-document-revision-runtime-404.md);[ADR](../adr/2026-09-13-document-version-boundary.md) | **运行时 UI PASS**(6159 / V3/r2)。仍 `partial`:change report=`fallback`(真实 diff+lineage,非完整 PI 叙事)。系统级 `CHAT-INTENT` 见 gap-matrix | `docgov` |
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 错误卡片/任务进度/文档 busy 状态刷新恢复与人工抽检待完成 | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test 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) | — | `pi-agent` |
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[双标签截图](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo seed 污染整改](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[门禁 B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md) | 错误卡片/任务进度/文档 busy 刷新恢复已有项目 6275 证据。Demo seeds 默认关闭。版本冲突信封解包 + 终止 preview 抽检已签(项目 6363) | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 + typed-result-v1 | done | [test 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-v1](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | — | `pi-agent` |
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | CI `TEST_DATABASE_URL` 隔离库仍缺;文档运行时真实 UI 已按 UI_PHASE 分文件且 post-restart 断言最终 A1 正文。`-race` 全包并行 TempDir flake 为基建残留 | `ci` |
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[治理 PG 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);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | BUG-08 PASS;真实 PI 三工作流 E2E 与前端/对话门禁已签。`-race` TempDir flake 为基建残留;夜间 CI `RUN_PI_E2E=1` 建议 | `ci` |
| 模块解耦与可靠事件 | 文档可靠性纵向试点、PG 持久事件交付与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[Phase 1](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[E0A](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md);[E0B](../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[D6](../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md);[D7a](../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md);[D5](../test-reports/2026-09-15-stageflow-type-ownership-test-report.md);[D4](../test-reports/2026-09-15-bizdev-locator-removal-test-report.md);[D7b](../test-reports/2026-09-15-chatflow-orchestration-boundary-test-report.md);[H0](../ops/research/2026-09-15-http-error-envelope-h0-inventory.md);[P0](../ops/research/2026-09-15-pi-typed-result-p0-matrix.md);[收口](../test-reports/2026-09-15-phase2-closeout-test-report.md);[notify live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[advance live](../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md);[projection live](../test-reports/2026-09-15-event-projection-shared-live-test-report.md);[HTTP 信封](../test-reports/2026-09-15-http-error-envelope-h1-h3-test-report.md);[PI typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | E0A–E2 与共享 live 已过;生产无 hook 注册。D4–D7b 已合入。FAV off。Track P H1–H3 / P1–P4 已实施 | `architecture-docs` |
---
@@ -0,0 +1,422 @@
# 模块化单体解耦架构
> 状态:**设计已修订,首个文档可靠性试点待实施**
>
> 决策:[模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)
>
> 实施:[模块解耦整改与重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
## 1. 目标与边界
本设计把 Agent-System 收敛为模块化单体,使项目文档在刷新、服务重启、并发修改和工作区清理后仍能从稳定逻辑标识定位到正确正文。
模块边界必须同时约束依赖、事务、并发、授权、文件和最终成果;只减少 Go import 或移动目录不算解耦完成。
### 1.1 目标
1. 每个业务命令有唯一应用用例、事务 owner 和幂等语义。
2. 每张运行表和每类文件有唯一写入属主,但跨表不变量仍能在同一事务提交。
3. HTTP、SSE、CLI、worker 和恢复工具经过同一授权决策,不信任调用方填写的身份或资源归属。
4. workspace 只保存计算现场和可重建投影;最终文档、最终回复和 manifest 进入 FAV。
5. 事件在崩溃、重复投递、多订阅者和水平扩容下可追踪、可重试、可隔离。
6. 首个纵向试点直接消除受控正文刷新/重启后 404、409 和 projection missing 类故障。
### 1.2 非目标
- 不拆微服务,不引入分布式事务协调器。
- 不在本轮统一全部 HTTP 错误响应。
- 不在本轮替换 PI Runner stdout/result 协议。
- 不把所有历史数据永久保留,也不把生产数据复制为测试 fixture。
- 不允许 FAV 绕过数据库授权或自动重建活动工作流、lease、pending task。
## 2. 目标架构
```mermaid
flowchart TB
Client[Web or CLI] --> Adapter[server adapters]
Worker[Background workers] --> App[application use cases]
Adapter --> App
App --> Authz[authorization policy]
App --> UoW[UnitOfWork]
App --> ReadModels[read use cases]
UoW --> Owners[domain table owners]
Owners --> PG[(PostgreSQL)]
UoW --> Outbox[(outbox and staging)]
Outbox --> Dispatcher[event dispatcher]
Dispatcher --> Subscribers[idempotent subscribers]
Subscribers --> Vault[artifactvault]
App --> Workspace[workspace capability service]
Workspace --> Scratch[(scratch workspace)]
ReadModels --> PG
ReadModels --> Vault
```
### 2.1 分层职责
| 层 | 职责 | 禁止 |
|---|---|---|
| `internal/server` | 参数解析、认证信息转 Principal、调用应用用例、序列化 HTTP/SSE | SQL、事务、路径拼接、跨模块编排、后台重试 |
| `internal/app/*flow` | 用例编排、授权、UnitOfWork、命令幂等、事件发布 | 领域 SQL、物理路径、传输格式 |
| 消费者侧 ports | 表达一个用例需要的最小能力 | 聚合所有模块方法的万能接口 |
| 领域模块 | 业务不变量、表/文件写入所有权、事务绑定 repository | import 其他领域实现、开启不受控嵌套事务 |
| read model | 授权后的跨模块只读聚合 | 业务状态变更、修复式 GET 写入 |
| 基础设施 | PostgreSQL、CAS、FAV、workspace、事件 dispatcher | 推断业务终态或自行授予权限 |
### 2.2 契约分类
`internal/contracts` 不再作为所有 DTO 的公共仓库。
| 契约 | 所有位置 | 版本规则 |
|---|---|---|
| HTTP/SSE wire DTO | `internal/server/api`、`internal/stream/transport` | 对外兼容,breaking change 走 ADR |
| 一对一调用端口 | 消费者 use case 包内 | 随用例演化,不带 JSON tag,不自动走 ADR |
| 公共领域事件 | `internal/contracts/events/<domain>` | 有 schema version;生产者和多个消费者共同评审 |
| 持久文件/manifest schema | 所属模块,如 `artifactvault`、`workspace` | major/minor 兼容;未知 major fail closed |
| 稳定共享词汇 | `internal/contracts/vocabulary` | 仅无行为枚举和值对象;禁止依赖业务实现 |
| 错误分类 | 领域错误留领域包;wire 映射留 server | 不把数据库/路径/第三方原始错误暴露给客户端 |
接口默认由消费者拥有,应用组合根只注入实现。
只有三个以上消费者确实共享相同语义时,才提升为公共端口。
## 3. 模块边界
| 模块 | 唯一职责与写入所有权 | 可依赖 | 禁止 |
|---|---|---|---|
| `app/docflow` | 文档读取、提交、批准、投影和归档用例;相关事务 owner | 消费端口、authz、uow | SQL、物理路径 |
| `app/stageflow` | 阶段推进和任务执行用例 | 消费端口、authz、uow | bizdev 门面、HTTP DTO |
| `app/chatflow` | 一轮对话识别、协调、消息落账和任务触发 | 消费端口、authz、uow | 直接写共享上下文字段 |
| `docgov` | 文档治理状态、角色、lease、`document_records` 写者 | 自有 repository、稳定词汇 | 直调 docrevision 实现、读 workspace 文件 |
| `docrevision` | immutable snapshot/version/revision/event/report 账本写者 | 自有 repository | 直接写 `document_records`、`freeform_documents` |
| `freedoc` | 自由文档根表和发布状态写者 | 自有 repository | 被 docrevision 反向更新 |
| `docquery` | 授权后文档列表、正文、版本聚合读取 | 只读端口、artifact read fallback | 任何写入、目录扫描、授权推断 |
| `chatlog` | `chat_*` 表族读写和会话/消息/turn 查询 | 自有 repository | prompt 装配、外部导出策略 |
| `contextasm` | 记忆、摘要、召回和 prompt 上下文组装 | 消费者侧 ChatLog/KB read ports | HTTP、SQL 越界写入 |
| `intent` | 纯规则意图分类 | vocabulary | bizdev、server、IO |
| `taskrun` | task run 状态机、claim/finalize、幂等写者 | 自有 repository | server 补协议、workspace 路径 |
| `squadrun` | 在受限 workspace capability 内执行角色与步骤 | agent/template/quote 消费端口 | DB、SSE、业务授权、任意路径 |
| `workspace` | Workspace ID 签发、物理路径解析、projection 生命周期 | fsutil、storage identity | 业务终态、最终归档 |
| `artifactvault` | 终态 payload/manifest/receipt/tombstone 权威 | 独立存储、registry | 活动业务关系、运行授权、workspace 扫描 |
| `notification` | 通知偏好、投递和状态 | 事件消费、repository | 业务状态推进 |
| `app` | 唯一组合根、worker 生命周期、事件订阅注册 | 所有构造函数 | 被 server 反向装配 |
模块“可依赖”只表示通过端口调用,不表示允许 import 对方实现包。
## 4. 事务与单一写者
### 4.1 两种所有权
- **表属主**决定 SQL、约束和单表不变量。
- **事务 owner**决定一个业务命令需要哪些属主共同提交。
两者不能合并为“每个模块各开一个事务”。
应用用例开启 `UnitOfWork`,取得绑定同一 `pgx.Tx` 的 repository capabilities;领域服务只能使用这些 capabilities,不能 commit、rollback 或启动嵌套事务。
### 4.2 文档提交原子集合
一次受控文档提交必须原子包含:
1. 校验 Principal、项目成员、duty、lease 和 expected head。
2. 锁定 `document_records` 与当前 open version。
3. 写 immutable content blob/snapshot/revision/change event。
4. 更新版本 head 与 `document_records` 当前指针/哈希。
5. 冻结应归档 payload 或不可变 blob 引用。
6. 写领域事件和 FAV publish request。
7. 提交后再进行 workspace 投影、通知和外部存储发布。
任一步失败,步骤 2–6 全部回滚。
投影或发布失败不会回滚业务提交,而是进入可重试队列并在 UI 暴露 degraded 状态。
### 4.3 事务隔离选择
| 场景 | 机制 | 原因 |
|---|---|---|
| 单文档编辑/批准/提交 | `READ COMMITTED` + `SELECT ... FOR UPDATE` + expected head | 竞争范围明确,冲突可向用户解释 |
| 同幂等键并发创建 | 唯一约束 + payload digest 校验 | 数据库决定唯一赢家 |
| 跨表项目级 duty/heal | `pg_advisory_xact_lock(project_id)` + 固定行锁顺序 | 复用现有项目级互斥,事务结束自动释放 |
| 复杂跨聚合唯一不变量 | `SERIALIZABLE`,完整事务有限重试 | 仅在显式证明需要时使用 |
| outbox 多 worker claim | `FOR UPDATE SKIP LOCKED` + lease/fencing token | 提高队列吞吐,不作为普通读取语义 |
### 4.4 锁顺序
所有跨属主事务按下列顺序获得锁:
1. project 或 workflow instance 事务级 advisory/row lock;
2. document/freeform/chat aggregate root;
3. version/snapshot/turn;
4. task run;
5. staging/outbox/delivery。
禁止在持锁期间调用 LLM、PI Runner、对象存储、HTTP、SSE 或执行大文件复制。
需要外部工作时采用 prepare → 外部执行 → compare-and-commit;commit 阶段重新验证 expected version。
### 4.5 超时与重试
- 每个写事务设置独立 context deadline 和数据库 `lock_timeout`;初始预算由配置管理,不在 handler 硬编码。
- `40001` 与 `40P01` 只允许重跑完整幂等事务,采用带抖动退避和有限次数。
- expected-version 冲突、权限拒绝、唯一键 payload 不同不是瞬时错误,不自动重试。
- 事务重试期间不得重复发送消息、SSE、通知或对象存储写入;这些副作用只能由提交后的 outbox 驱动。
## 5. 并发协议
### 5.1 文档并发
客户端读取正文时获得 `ETag = head_snapshot_id:head_revision_no`。
PATCH、agent commit、approve 和 projection repair 都必须携带 expected head 或稳定 idempotency key。
旧 ETag 返回 typed `VERSION_CONFLICT`,响应包含当前 head 元数据但不泄露无权正文。
### 5.2 TaskRun 并发
`Claim(idempotency_key, request_digest)` 通过唯一约束保证只创建一个 run。
相同 key、相同 digest 返回既有 run;相同 key、不同 digest 返回 `IDEMPOTENCY_CONFLICT`。
状态迁移使用 `WHERE status = expected AND version = expected_version`,影响行数为零即重新读取并分类冲突。
幂等键按 environment、project、actor、action 和客户端 key 作用域化,并与规范化 request digest 绑定。
幂等记录的保留期不得短于客户端重试窗口、事件重放窗口和对应业务记录的审计期。
### 5.3 Workspace 并发
Workspace ID 由服务端签发并绑定 environment、project、run、storage identity 和生命周期。
同一 workspace 同时只有一个写 lease;续租返回 fencing token,所有写操作校验 token。
本地 `sync.Mutex` 可减少同进程竞争,但跨副本 lease 和 token 才是正确性依据。
文件写入采用同目录临时文件、校验、原子 rename 和目录同步;reader 只读取完整 projection marker。
### 5.4 FAV 并发
逻辑 artifact 的幂等键由终态事件、资源、payload SHA 和 policy version 决定。
对象写入使用 content-addressed key 和 no-replace 语义;blob、manifest 全部校验完成后最后写 commit marker。
重复 publisher 可共享已有 blob,但只有一个 registry 状态迁移为 verified。
### 5.5 查询与背压
docquery 的列表和版本历史必须分页,BatchGet 首期硬上限 100 个引用;超过上限返回 typed validation error,不自动拆成无界并发查询。
批量读取先按 Principal 和 project scope 分组授权,再使用有界并发和数据库 statement deadline。
API 对 actor/project/action 维度限流,后台 backfill 和 dispatcher 使用独立连接预算,不能耗尽在线读写连接池。
SSE 慢客户端只影响传输缓冲;不能持有业务 transaction、数据库锁或阻止事件持久化。
## 6. 可靠事件
### 6.1 事件信封
每个持久事件至少包含:
```text
event_id
event_name
schema_version
environment
project_id
aggregate_type / aggregate_id / aggregate_version
actor_ref
correlation_id / causation_id
idempotency_key
payload_digest
occurred_at
```
事件不携带 secret、认证 token、Prompt、正文或任意文件路径。
大 payload 先冻结到不可变 staging,事件只保存引用和 digest。
### 6.2 投递模型
```mermaid
sequenceDiagram
participant UC as Use case transaction
participant DB as PostgreSQL
participant W as Dispatcher worker
participant S as Subscriber
UC->>DB: business state + staging + outbox
DB-->>UC: commit
W->>DB: claim delivery with SKIP LOCKED
W->>S: deliver event and fencing token
S->>DB: idempotent side effect and inbox receipt in one transaction
S-->>W: success or typed failure
W->>DB: ack, retry schedule, or dead letter
```
- 每个订阅者有独立 delivery 状态,不能共享单一 `published_at`。
- 投递语义为至少一次;消费者以 event ID/inbox 唯一约束幂等。
- 同一 aggregate 按 aggregate version 有序;不同 aggregate 可并行。
- claim 按 `next_attempt_at, event_id` 排序并采用 aging,防止热点失败事件令旧事件永久饥饿。
- 数据库 subscriber 的业务副作用与 inbox receipt 必须同事务;外部副作用使用业务幂等键并在回执落库前允许安全重放。
- transient failure 指数退避;永久失败进入 dead letter,不能阻塞其他订阅者。
- worker 认领带 lease、attempt 和 fencing token;过期 worker 无权提交 ack。
- replay 必须指定事件范围、目标消费者、操作者和原因,并写审计记录。
- delivery/outbox 的清理只能在所有必需消费者完成、重放窗口结束且恢复 checkpoint 已覆盖后执行;审计类事件按独立保留策略处理。
## 7. Workspace、账本与 FAV
### 7.1 三层权威
| 层 | 权威内容 | 清理规则 |
|---|---|---|
| PostgreSQL | 项目、权限、workflow、task、文档关系、版本账本、当前指针 | 依完整备份/PITR 和环境生命周期处理 |
| workspace/state | 执行现场、临时材料、可重建 projection | 终态冻结和归档门禁通过后按 TTL 清理 |
| FAV | 已归档 payload、manifest、receipt、tombstone | 按 retention/legal hold/delete ledger 处理 |
### 7.2 Workspace capability
跨模块 DTO 只包含:
```text
workspace_id
project_scope
run_id
lease_fencing_token
schema_version
```
调用方使用 `ReadArtifact(key)`、`OpenAtomicWriter(key)`、`CommitProjection(key, digest)` 等受限端口。
artifact key 必须是受控相对标识,禁止绝对路径、`..`、空段、跨作用域 ID、symlink 和 hardlink 逃逸。
### 7.3 RunManifest
RunManifest 的规范字节、SHA、workspace ID、storage identity 和输出成员在 taskrun finalize 时持久化。
`Evidence map[string]string` 和 `Gaps []string` 不作为核心协议;核心字段类型化,扩展只能进入带 namespace 和 schema 的 extensions。
workspace 内 manifest 是可重建副本,不是唯一事实源。
### 7.4 FAV 接入
artifactvault 只接收服务端确认的终态文档、终态助手回复和必要附件。
流式 chunk、候选、Prompt、工具轨迹、修复过程、临时报告和 workspace 草稿准入率必须为零。
发布从终态事务的 staging/outbox 驱动,禁止目录扫描。
docquery 的读取优先级为:
1. 校验 Principal 和数据库 resource→project 授权图;
2. 读取数据库 immutable ledger/current pointer;
3. 检查并校验 workspace projection,仅作为缓存;
4. 正文缺失但授权图完整时,可按 feature flag 从 FAV 只读降级;
5. 权限图缺失、vault tombstone、SHA 冲突或来源不一致时 fail closed。
GET 不得修复数据库或覆盖 head。
修复和恢复是独立命令,并产生审计记录。
## 8. 授权架构
### 8.1 Principal
Principal 由 HTTP session、服务身份或恢复凭证适配器构造,至少包含 actor ID、actor type、environment、认证来源、request/correlation ID 和明确 capabilities。
`UserID`、`ProjectID`、role 和 duty 不能直接从业务请求体覆盖 Principal。
### 8.2 决策模型
授权决策输入为 `Principal + Action + Resource + CurrentState`。
| 动作类别 | 强制条件 |
|---|---|
| 文档读取 | 项目成员/管理员 + 分类可见性 + stage/duty 范围 |
| 文档编辑/提交 | 写权限 + 当前 duty + 合法状态 + 有效 lease + expected head |
| 批准/驳回 | 对应 action-level duty + 冻结实例配置 + 当前状态 |
| TaskRun 执行/恢复 | 项目权限 + 合法 workflow/stage + 服务端解析的 backend capability |
| FAV 降级读取 | 正常读取授权已成功 + artifact scope/hash/删除状态一致 |
| replay/backfill | 运维 capability + 精确范围 + dry-run + 审计 |
| scratch recovery promotion | 系统管理员 + 数据责任人确认 + scratch identity + 冲突计划无未决项 |
应用用例可以在事务前做快速拒绝,但状态改变必须在取得资源锁后重新读取授权相关事实并再次判定,防止成员、duty、stage 或 lease 在检查后变化。
授权服务不可用或关系不完整时默认拒绝。
事件携带的 actor 只用于审计;订阅者产生持久或外部副作用前重新读取当前权威状态。
### 8.3 后端与数据最小化
调用方不能提交任意 `Backend string`。
应用层按环境、项目策略和输入敏感级别解析 `BackendRef`,agent 适配器再注入受管凭证。
凭证不得进入 DTO、日志、事件、manifest、result 文件或 FAV。
InputBundle 只包含完成任务必需的材料,并标记来源、分类、允许用途和生命周期。
## 9. 架构门禁
### 9.1 静态规则
| 规则 | 检查对象 | 例外 |
|---|---|---|
| 领域实现互不 import | Go production packages | 消费端口和稳定 vocabulary |
| server 不 import repository/领域实现 | server production packages | app facade、wire DTO |
| 表写入唯一属主 | production SQL 的 INSERT/UPDATE/DELETE/MERGE | Goose、测试 fixture、批准的修复工具 |
| 工作区物理路径唯一属主 | production path construction/open/write | workspace/squadrun adapter |
| 事件发布者 allowlist | event name → producer package | 无运行时动态注册旁路 |
| 订阅者 allowlist | event name → consumer use case | replay 工具需显式 capability |
例外必须记录 owner、原因、范围、到期日和移除里程碑。
warn/block 不按固定“两周”切换;每条规则在对应纵向切片清零后单独转 block。
### 9.2 行为门禁
架构检查不能替代以下测试:
- 同文档并发编辑、批准和 agent commit;
- 任意事务步骤失败时全量回滚;
- worker 崩溃、lease 过期、重复投递和多订阅者部分失败;
- workspace 删除、换根、重启和 projection 重建;
- FAV 降级读取与 scratch 恢复;
- 匿名、非成员、跨用户、跨项目、错误 duty、错误 stage、授权依赖失败;
- 真实浏览器刷新/重登/rebuild 与真实 PI 主链。
## 10. 可观测性与容量
### 10.1 必须指标
- 数据库事务时长、锁等待、deadlock、serialization retry、版本冲突率。
- outbox pending/oldest age、delivery attempts、lease steal、dead letter 数。
- projection missing/mismatch/repair、FAV degraded read、vault verification lag。
- 授权 deny 按 action/reason 计数,不记录正文或敏感资源名。
- workspace active lease、过期清理、fencing rejection、storage identity mismatch。
### 10.2 高并发基线
首个试点必须建立并保存基线,而不是直接承诺未经测量的容量数字:
- 同一文档热点写入与不同文档并行写入分开压测。
- 1、2、4 个 app 实例下验证进程内锁不影响正确性。
- 1、2、4 个 dispatcher 下验证无重复可见副作用、无饥饿和有界积压。
- p50/p95/p99 延迟、锁等待、事务重试、CPU/连接池和队列年龄进入 test report。
- 正确性门禁固定;吞吐阈值在基线评审后写入环境配置与发布 SLO,不能靠降低一致性通过。
## 11. 迁移与兼容
采用 expand → migrate → contract:
1. 新增兼容 schema、端口和读路径,不改变旧写入。
2. 新写路径 shadow/dual-read 验证,禁止无审计双写。
3. 按 checkpoint 幂等回填,异常进入 quarantine。
4. 切主写者,保留旧 reader 一个明确发布窗口。
5. 验证真实刷新/restart/rebuild、FAV coverage 和回滚。
6. 删除旧路径前再次审计引用和数据差异。
旧 workspace 文件缺少 `schema_ver` 时按只读 legacy-v0 解析。
首次受控 Resume 先校验并原子升级到 v1,保留可回滚备份;未知 major 版本 fail closed。
回滚只保证回到最近兼容点。
已被下游里程碑消费的 schema 或契约必须按逆依赖顺序回滚,不能单独 revert 早期提交。
## 12. 首个交付边界
首个里程碑只覆盖受控文档可靠性:
```mermaid
flowchart TB
Read[Authorized content read] --> Ledger[Immutable ledger]
Ledger --> Projection{Projection aligned?}
Projection -->|yes| Return[Return canonical content]
Projection -->|no| Vault{Authorized FAV fallback enabled?}
Vault -->|yes| Degraded[Return verified degraded content]
Vault -->|no| Conflict[Typed consistency error]
Commit[Edit or agent commit] --> Tx[Single UnitOfWork]
Tx --> Ledger
Tx --> Root[Document root pointer]
Tx --> Stage[Artifact staging]
Tx --> Event[Outbox]
```
只有这个切片完成刷新、重启、并发、权限和恢复验收后,才启动其他包的物理拆分。
## 13. 后续扩展顺序
1. 文档可靠性试点。
2. taskrun finalize、RunManifest 持久化和 FAV 集成。
3. 逐个事件替换闭包桥。
4. chatlog/contextasm 原地端口化,再按证据移动包。
5. squadrun capability 化和 backend policy。
6. app 组合根迁移。
7. UserProjectContext 增量收权。
8. server/SSE 收口。
9. 错误信封与 PI Runner 协议作为独立项目实施。
详细依赖、文件和测试场景见整改计划。
@@ -0,0 +1,475 @@
# 多意图多任务识别、持久计划与 HITL 统一确认方案
> 状态: planned(方案已复核,未实施)
> 日期: 2026-09-15
> 作者: Cline(初稿)/ Codex(架构、安全与实施计划复核)
> 关联: [方案审计](../audit/2026-09-15-multi-intent-hitl-plan-review.md);[意图识别深读](./intent-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md);[模块化单体架构](./2026-09-14-module-decoupling-architecture.md);[任务总览](../ops/short-term/2026-09-15-multi-intent-hitl.md)
---
## 一、结论与目标
方向可行,但原稿不能直接实施。需要先闭合计划生命周期、确认回路、授权、并发和模块归属。修订目标是:
1. 一次输入可安全识别 2–4 个候选子任务,并让用户核对系统理解;
2. 只有确定的低风险只读组合可自动执行;批量生成、写入、控制、缺槽、冲突或不确定组合必须进入服务端持久化 HITL;
3. 刷新、双标签页、服务/worker 重启和 SSE 晚到时,计划与卡片从 PostgreSQL 权威状态恢复;
4. 确认只表达用户意愿,不授予权限。每一步执行前按当前主体、成员关系、资源状态和版本重新授权;
5. 不回退已完成的解耦:`internal/intent` 保持纯规则领域模块;跨属主写入继续使用端口、单一写者、`app/uow` 和静态事件契约。
第一版按显式依赖顺序执行,每步独立提交,不承诺跨步骤原子回滚或并行 DAG 调度。
这项能力的直接价值不是替代逐条对话,而是消除当前“用户已经明确给出多个任务,系统却只执行 TopIntent 且不告知”的不可信行为,并让有依赖的“先查再生成”在一次可审计确认中完成。逐条提交仍是低复杂度场景的有效入口;如果 shadow 期显示多意图采用率低、确认放弃率高或用户普遍主动拆单,U7 之后的写动作扩面应停止,而不是为了完成路线图继续建设。
---
## 二、当前事实与缺口
| 能力 | 当前事实 | 证据 |
|------|----------|------|
| 单意图识别 | 18+ Intent、四级漏斗、三分支已实现;FEATURE-MATRIX 仍为 `partial`,不能称“已成熟” | `internal/intent/recognizer.go`、`.doc/status/FEATURE-MATRIX.md` |
| V2 帧/动作表 | `IntentFrameV2`、ActionRegistry、风险、必填槽位、灰度开关已存在 | `internal/intent/types_v2.go`、`registry.go`、`flags.go` |
| 有限多意图 | 默认开启;只按首个连接词拆两段;写意图返回 `nil` | `internal/intent/plan_builder.go` |
| 有限执行 | 只读步骤顺序执行;需确认步骤只有文字提示 | `internal/coordinator/action_planner.go` |
| HITL 基础 | PendingExpectation、四类卡片和 ExpiresAt 已存在;前端仍有本地业务状态修改路径 | `internal/intent/types.go`、`web/src/App.tsx` |
| 可靠事件 | PG dispatcher、delivery、静态契约已 live;FAV 关闭 | `internal/events`、`.doc/ops/CURRENT.md` |
| 模块边界 | `intent` 只允许依赖 `maturity`;chatflow/stageflow/doccontent 等解耦已完成 | `.doc/system-design/module-boundaries.yaml` |
关键缺口:分段不确定时可能退回 TopIntent 并静默丢任务;计划没有 revision、决策凭据、执行账本或可恢复状态机;确认没有统一服务端命令;ActionRegistry 风险容易被误当授权;未处理重复提交、双标签决策、过期竞态和 worker 抢占;卡片/SSE 不是权威状态;原稿把 agent backend 引入 L1 会破坏 intent 边界;T1–T5 全用 `intent` mutex 与实际跨模块范围不符;自由文本结果传递存在提示注入和数据泄露风险;固定样例数不能代替质量门槛。
---
## 三、硬约束与非目标
### 3.1 不可回退的解耦约束
| 约束 | 强制规则 | 验证 |
|------|----------|------|
| L1 纯度 | `internal/intent` 只做确定性分段、识别、帧和计划提案;不得访问网络、PG、文件或 agent backend | arch-check 保持 `intent -> maturity` |
| 应用编排 | 新增 `internal/app/intentflow` 作为计划生命周期唯一编排入口 | chat/server 只依赖深接口,不获得 store/engine |
| 单一写者 | `intent_plans*` 仅由 intentflow repository owner 写;业务动作仍写自己的表 | table owner + SQL write archtest |
| 跨属主一致性 | 计划、决策、投影请求和 outbox 需要一致时使用不透明 `app/uow.TxScope` | 不暴露 pool/pgx.Tx |
| 事件契约 | 新事件先登记 YAML 与 `events.StaticContracts`,再接 dispatcher | registry parity + 未注册 fail closed |
| 授权归属 | intentflow 不复制 docgov/taskrun/workflow 权限,调用动作属主用例端口 | 每个 adapter 有即时授权负例 |
| 组合根 | store、adapter、clock、ID generator、event sink 仅在 `internal/app/app.go` 装配 | server 不重新接线 |
### 3.2 非目标
- 不拆微服务或新增 RPC;不支持 >4 步、并行 DAG、多个活动写计划自动合并;
- 不承诺跨步骤 ACID 或自动补偿;
- 当前作用域没有活动写/生成计划时,不改变单意图生成任务行为;已有活动计划时统一进入冲突/替换流程,禁止启动第二个写计划;
- 不让 LLM 决定风险、权限、槽位真值或执行顺序;
- 不启用 FAV,也不把中间结果归档到 FAV;
- 不借机全量重构 coordinator/chat action executor。
---
## 四、总体架构与权威性
```mermaid
flowchart LR
UI[Web 计划卡] --> API[server HTTP/SSE]
API --> FLOW[app/intentflow\n计划生命周期]
CHAT[chat/chatflow] --> FLOW
FLOW --> L1[intent\n纯规则提案]
FLOW --> STORE[(plan owner store)]
FLOW --> UOW[app/uow]
FLOW --> PORTS[动作属主端口]
FLOW --> EVENTS[events outbox]
EVENTS --> PROJ[projection/notify]
FLOW -.只建议分段.-> SEM[语义 adapter\nagent backend]
```
`app/intentflow` 对外只提供:处理一轮输入、提交计划决策、读取授权后的 PlanView、恢复/推进已有计划。不得向调用者暴露 PlanStore、事务、`docgov.Engine`、`taskrun.Manager` 或 pool。
权威性从高到低:当前认证主体与资源状态 → 动作属主的授权/业务不变量 → PG 计划/步骤/决策 → 消息卡片投影 → SSE/前端内存。下层不得覆盖上层。
### 4.1 端到端流
```mermaid
sequenceDiagram
participant U as 用户
participant W as Web/server
participant F as app/intentflow
participant I as intent
participant D as PG plan store
participant A as 动作属主
U->>W: input + client_turn_id
W->>F: HandleTurn(principal, context, input)
F->>I: 安全扫描、分段、逐段识别
I-->>F: PlanProposal + evidence + digest
alt 独立低风险只读
F->>A: 每步即时授权并执行
F-->>W: 聚合结果
else 需澄清/确认
F->>D: 同事务写 plan/steps/outbox
F-->>W: 权威卡片
U->>W: decision + nonce + expected_revision
W->>F: DecidePlan
F->>D: CAS 状态
F->>A: 每步重新授权、执行
F->>D: CAS step + receipt/ref
F-->>W: PlanView
end
```
---
## 五、领域模型与状态机
- `intent.PlanProposal`:L1 值对象,含规范化分段、候选帧、证据、缺槽和依赖建议;不含授权结论或 DB 状态;
- `intentflow.Plan`:应用实体,含主体/会话/项目作用域、请求摘要、revision、过期、决策与执行账本;
- `PlanView`:脱敏 UI 投影,不回传内部 payload、权限快照或完整中间结果;
- UserProjectContext/消息只保留 `plan_id + revision` 引用,不持久化第二份 PendingPlan。
### 5.1 计划状态
```mermaid
stateDiagram-v2
[*] --> proposed
proposed --> awaiting_clarification
proposed --> awaiting_confirmation
proposed --> executing: 仅低风险只读
awaiting_clarification --> awaiting_confirmation
awaiting_clarification --> executing
awaiting_clarification --> awaiting_clarification: 增量补槽形成新 revision
awaiting_clarification --> superseded
awaiting_confirmation --> executing
awaiting_confirmation --> cancelled
awaiting_confirmation --> expired
awaiting_confirmation --> superseded
executing --> partially_completed
executing --> completed
executing --> failed
executing --> cancelled: 仅未开始步骤
partially_completed --> completed
partially_completed --> failed
partially_completed --> executing: 用户选择重试/继续
partially_completed --> cancelled: 取消全部未开始步骤
```
编辑产生新 revision/digest,旧卡片 `outdated`;取消不能回滚已完成业务副作用;`skip` 只允许独立低风险只读步骤;依赖失败阻塞所有后代;`confirm_retry` 暂停计划并对指定失败步骤重新确认。
### 5.2 步骤、部分确认与幂等
步骤状态:`pending -> eligible -> running -> succeeded | failed | denied | conflicted | blocked_dependency | skipped | cancelled`。
- `eligible -> running` 用条件更新和 fencing token;
- 动作幂等键:`plan_id:plan_revision:step_id:action_digest`;同键同摘要返回既有 receipt,同键异摘要冲突;
- 动作属主端口必须接收 idempotency key、action digest、expected resource version 和 fencing token,并能按同一身份查询 receipt。只有属主事务能原子提交幂等占位与业务副作用,或已证明原生机制等价时,该 action 才能放量;旧 fence 必须被属主拒绝;
- 部分确认必须是依赖闭包;选中步骤进入 eligible,未选独立步骤继续等待确认。只有用户显式“排除未选项”才写 `cancelled_by_user`,其后代取消或阻塞;
- 高风险步骤逐项可见;确认父步骤不自动确认新出现的高风险后代;
- “确认第 1 项并修改第 2 项”拆成决策和新 revision,不混为一个转移。
---
## 六、分段、识别与组合策略
### 6.1 确定性分段
`internal/intent` 内扩展纯规则分段器,支持连接词、句号、分号、换行、序号和“先/再/最后”,上限 4 段。输出包含规范化文本、原文 span、连接证据、结构置信类别和未解析指代。
1. 整句先做 Stage 0 安全扫描;分段规范化、槽位补丁、LLM 建议后再次逐段扫描;原文命中优先,整体拒绝;
2. “查询并总结”“阅读后概括”等单动作内部链不拆;
3. 只有确定为完整单意图时才合并回单意图;低置信、指代补全失败或无法证明完整时进入澄清,禁止退回 TopIntent 执行;
4. 逐段识别后检查同资源冲突、重复动作和依赖;
5. 超过 4 段不创建残缺计划,明确要求分批。
### 6.2 可选语义分段
LLM adapter 位于 intentflow 外围,不放进 `internal/intent`。它只能提出 `text span + connector + reason`,不能输出权限、风险、ActionKey、执行顺序或权威槽位。
- 只发送当前文本和必要的脱敏实体标签;不发送 secrets、完整历史、文档正文或权限表;
- 严格版本化 schema;超时、格式错、span 重叠、越界或安全冲突均 fail closed;
- 每段重新进入确定性 recognizer、ActionRegistry 和安全扫描;护栏优先,无法裁定就澄清;
- 以 `request_digest + segmenter_version + model_contract_version` 固化已展示分段;重试不得因模型漂移改变计划;
- shadow 日志只保留 digest、类别、差异和计数。
### 6.3 组合风险矩阵
ActionRegistry 提供动作身份、目标类别和静态风险提示,但不是授权或批量编排 SSOT。`app/intentflow` 拥有版本化 `BatchActionPolicy`,只记录 action key 的批量确认要求、可开放 tier、adapter 能力和 execution mode,并在启动时校验 key 存在于 ActionRegistry。它不得复制 Risk、RequiredSlots、CapabilityKey 或 AllowedStates。`task.run`/`task.run.adhoc` 的批量策略要求确认,同时保持其单意图 `RequiresConfirm` 不变。
| 条件 | 模式 | 行为 |
|------|------|------|
| 全部独立 RiskLow 查询、槽位齐、无冲突 | `auto_read` | 即时授权后执行 |
| 任一批量生成、mutate/control、中高风险或 BatchActionPolicy 要求确认 | `awaiting_confirmation` | 先持久化并出卡,确认前零副作用 |
| 缺槽、指代/分段/依赖不明 | `awaiting_clarification` | 聚合澄清;有槽位依赖时分组问 |
| 原文或变换结果命中红线 | `rejected` | 整体拒绝,不执行其他段 |
| >4 段 | `rejected_batch_size` | 要求分批 |
V2 灰度不可绕过:只有 ActionRegistry 映射稳定、V2 shadow 达门槛且当前 multi-intent tier 允许的动作可进入 decision;其余走 legacy 或显式澄清。
---
## 七、HITL、授权与并发协议
### 7.1 服务端权威卡片
`PLAN_CONFIRM` 折叠态也必须显示任务数、受影响目标、生成/写入/控制类型、最高风险、不可撤销副作用和“逐步提交、后续失败不回滚”提示;高风险步骤始终逐项可见。只有 action key、revision、digest 等技术元数据和低风险细节可折叠。支持全部确认、依赖闭包内部分确认、编辑、取消。
`CLARIFY_AGGREGATE` 展示逐步缺槽、约束、已知值和冲突。回复形成 slot patch 后必须重新识别、重新计算 digest、风险和授权预检。
用户只回答部分问题时保存可唯一映射的增量 patch,产生新 revision 并继续停留在 awaiting_clarification;新卡同时显示已解决值和剩余问题,旧卡 stale。不会要求重填已经验证的值,也不会在缺槽未闭合时提前执行。
澄清字段按步骤和依赖分组,标记“已验证/待填写/冲突/无效”,显示剩余数量;提交文案为“保存已填写并继续”,提交后保留合法值并聚焦首个未解决字段。
卡片 metadata 是 PG 状态投影。按钮和自然语言“确认/取消/只做第 1 项”统一进入服务端 `DecidePlan`;前端不得本地修改业务资源或先标成功。
部分确认 UI 使用依赖层级列表:选择子步骤时立即勾选并解释必需前置;存在已选后代时不能取消前置;提交按钮显示本次确认的步骤数和目标。未选项标为“继续等待”,显式排除是独立次级动作,并在提交前列出会被取消或阻塞的后代。
自然语言决策采用确定性语法优先:明确 plan/步骤编号或当前会话只有一个活动可见计划时才可绑定;“确认”在多个活动计划、步骤引用不合法或同时包含新任务时不执行,改为定向澄清。聚合槽位优先使用结构化卡片字段;自由文本只把可唯一映射的 `label:value`/已有 PatchSlots 结果写入 patch,冲突值、依赖值无效或多义值保持未解析并再次提问,绝不猜测。
### 7.2 确认不等于授权
执行每一步前,动作属主重新校验当前认证用户与 plan session/project/user、当前成员/duty/capability、资源归属/lifecycle/stage、expected version/ETag、动作允许状态。计划中的角色/权限快照只用于审计。失败进入 `denied/conflicted`,不得换系统身份代执行。
### 7.3 并发规则
- 创建:`(session_id, client_turn_id, request_digest)` 唯一;同 turn 异 digest 冲突;
- 决策:必须带 `expected_revision`、`decision_nonce`、`decision_digest`;同 nonce 同摘要返回 receipt,异摘要冲突;
- 标识:plan_id、step_id、decision_nonce 使用不可预测的随机标识;安全性不依赖其保密,所有访问仍做四元作用域授权;
- 状态:当前 revision 且未过期的等待态才能 CAS;陈旧卡片返回 409 和当前安全视图;
- 过期:服务端 `expires_at` 权威,TTLTurns 只显示;
- 执行:短 lease + owner + lease_until + 单调 fencing;续租失败不再领步骤;
- 竞态:确认/取消/过期、编辑/确认只允许一个 CAS 胜出;
- SSE:允许重复/乱序/丢失,前端按 revision/step version 去重,发现缺口 GET 对账。
同一 user/session/project 同时只允许一个活动写/生成计划。新的低风险查询可独立处理;新的写计划必须让用户完成、取消或显式替换旧计划,不自动合并。计划锁不替代业务资源自己的 lease/version lock。
因此“单意图生成保持现状”仅适用于没有活动写/生成计划的作用域。有活动计划时,无论新输入是单意图还是多意图,都返回同一服务端冲突视图,禁止创建第二个 task/run;真实页面验收分别覆盖无活动计划兼容和有活动计划冲突。
`partially_completed` 必须提供前向收口卡:重试指定失败步骤、继续仍 eligible 的独立步骤、取消所有未开始步骤并关闭计划。已成功 receipt 永不回滚;running 步骤先由 lease/fencing 收口,卡片列明已发生且不可撤销的副作用。
---
## 八、持久化、事务、事件与数据治理
### 8.1 表与所有权
`intent_plans`:plan_id、environment/project/session/user/client_turn、request_digest、segmenter/policy version、status、revision、expires_at、timestamps、last_fencing_token。原始输入沿用 chat message 保留;计划表保存引用、digest 和脱敏展示快照。
`intent_plan_steps`:plan/step、action_key、规范化 slots、依赖、status、expected_resource_version、action_digest、idempotency_key、attempt、result_ref/digest、safe_summary、timestamps、version。
`intent_plan_decisions`:append-only decision id/nonce、plan revision、actor、kind、step selection、patch/request digest、outcome、created_at。关键 CAS、审计和查询字段必须类型化;JSONB 只用于版本化 slots/display snapshot。三表 owner 登记为 `app/intentflow`,其他包只能走端口。
### 8.2 事务与恢复
- 创建:plan + steps + card projection request + outbox 同一 UoW;
- 决策:decision append + plan CAS + eligible steps 同一 UoW;
- 业务副作用由动作属主事务提交,再以 idempotent receipt 更新步骤,不制造跨模块长事务;
- 业务成功但 receipt 写回失败时,通过动作幂等键查既有结果并对账,不盲跑;
- 消息投影失败不回滚权威计划,dispatcher 重试,刷新 GET 修复。
### 8.3 事件与作用域
只发布事实,不发布执行命令。候选事件 `intent.plan.awaiting_input`、`intent.plan.step_changed`、`intent.plan.completed` 必须同时登记 YAML、StaticContracts、schema/golden 和 parity test。
payload 仅含 plan/revision/step/status、environment/project/user/session scope 和安全摘要引用;不含原 prompt、完整 slots、权限快照或完整结果。消费者和 SSE 投递前按当前主体重新读取授权后的 PlanView;同项目不同用户不能互见。
### 8.4 留存与结果传递
- plan/decision 随会话和项目数据政策清理,不早于关联 chat/taskrun 审计窗口;删除由 owner 执行;
- 中间结果仅保存 `ResultReference`:producer、result/artifact ID、digest、类型、敏感级别、允许用途和长度受限 safe summary;
- 不把前序自由文本直接拼入权威槽位或后续指令区。后续生成只能把带来源的数据放入隔离材料区,不能扩大 action/target/tool/capability;
- 若结果导致动作、目标或范围变化,产生新 revision 并重新确认;
- 最终生成物仍归 taskrun/受控文档/FAV(启用后),计划库不充当成果仓。
---
## 九、API、刷新与前端
资源接口必须包括 `GET /api/v1/intent-plans/active`(按当前 principal/environment/project/session/user 发现活动计划)、`GET /api/v1/intent-plans/{plan_id}` 与 `POST /api/v1/intent-plans/{plan_id}/decisions`。页面 bootstrap、刷新和 SSE 缺口恢复先查询 active,再拉 PlanView;消息投影失败时仍能找回计划。
decision API 继承当前服务端认证方式、Origin/CSRF 策略和统一限流;nonce/幂等键只防重放与并发,不替代 CSRF 或身份认证。若当前认证方式不具备适用的 CSRF 防护,U1 必须把它列为 U5 的前置 blocker,而不是在计划端点单独发明一套弱机制。
统一错误码至少包括:`PLAN_NOT_FOUND_OR_HIDDEN`、`PLAN_STALE_REVISION`、`PLAN_EXPIRED`、`PLAN_DECISION_CONFLICT`、`PLAN_DEPENDENCY_INVALID`、`PLAN_ACTION_FORBIDDEN`、`PLAN_ACTION_VERSION_CONFLICT`。无权主体沿用资源隐藏策略,避免枚举 plan_id。
刷新时由 plan 表生成卡片/进度,不从旧按钮或 SSE 推断。页面刷新、重开、SSE 重连均以 GET 覆盖本地缓存。卡片需支持键盘/读屏、依赖说明、错误焦点、过期/陈旧状态;按钮提交后可显示 submitting,但只有服务端 receipt 能变为 executing/resolved。完整结果从 owning API 读取,SSE 只携安全摘要和版本。
状态恢复矩阵:submitting 锁定重复提交并保留选择;outdated/conflict 自动读取最新 PlanView、聚焦状态通知并提供“查看最新版”;expired 禁用原决策,保留只读摘要并提供“按当前上下文重建计划”;服务端字段错误保留未提交输入并聚焦对应字段。会话顶部提供可关闭但可重新发现的活动计划入口,无活动计划返回明确空态。
可访问性契约:步骤用有序列表和带 legend 的选择组;折叠控件暴露 `aria-expanded/aria-controls`;进度用 polite live region,阻断错误用 alert 并聚焦;状态不只靠颜色;键盘顺序为摘要、步骤、主/次动作;窄屏单列、无横向滚动、触控目标至少 44px,并支持 reduced-motion。
---
## 十、灰度、指标与回滚
保留 `MULTI_INTENT_ENABLED` 作为 legacy 开关;在任何行为变更前新增 `MULTI_INTENT_PLAN_TIER=legacy|shadow|auto_read|confirm|full`,默认 `legacy`。
- legacy:保持现有路径,但一旦可靠检测到未处理写/生成段,不得静默只执行 TopIntent,应澄清;
- shadow:只生成提案/指标,不建计划、不改路由;
- auto_read:先保持现状上限,仅开放 2 个低风险只读步骤;3–4 个只读步骤先进入确认/观察,达到单独门槛后再扩大;
- confirm:开放持久卡片;真实 adapter 未启用时只能产生 `validated_only` 预检。Plan、step、receipt 和 PlanView 显式携带 execution mode;`validated_only` 不能写 `succeeded/completed`,UI 必须显示“仅验证,未执行”;
- full:按 action key 逐项开放已验收 adapter。
LLM 分段独立开关且从 shadow 起步。关闭新计划创建后,已有计划仍能读取、取消和收口;不能回滚到无法处理已持久计划的版本。
| 指标 | 停走条件 |
|------|----------|
| 未确认/越权副作用 | 0 |
| 安全红线绕过 | 0 |
| hard-negative 反事实错误自动执行 | 0;shadow 必须计算“若处于 auto_read/confirm 会如何路由”,不能用实际未执行冒充零错误 |
| 重复确认导致重复动作 | 0 |
| refresh/restart 权威状态差异 | 0 |
| split precision/recall、澄清率、放弃率 | U2 先固定数据集与基线,再预注册阈值;未达不切档 |
| 用户采用与确认负担 | 记录多意图采用率、确认放弃率、拆单回退率;若价值不足,停止 U8/U9 而保留“识别后不静默丢弃”的安全改进 |
| projection backlog/dead letter | 不突破 Track E 既有预算 |
观察窗口由样本量和流量决定,不能用固定“一周”代替证据。
---
## 十一、实施计划(核心 U1–U8、按属主扩面 U10–U12、可选实验 U9)
### U1. 契约冻结与架构门禁
**目标:** 冻结 intentflow 边界、状态机、数据字典、错误码、事件和兼容策略。
**依赖:** 无。
**文件:** `.doc/system-design/module-boundaries.yaml`、`internal/events/registry.go`、API/schema 文档、arch/event tests。
**做法:** 注册 app/intentflow allowlist 与 table owner;保持 intent->maturity;冻结 BatchActionPolicy,但不向 intent 回灌 HITL/tier/adapter 字段;先落默认 legacy tier;禁止 server/chat 直写计划表。
**测试:** 新 import/SQL/event 违规 block;YAML/registry parity;未知 action/policy key fail closed;ActionRegistry 不出现批量执行策略;单意图生成策略不变。
**停走门:** 架构测试全绿,授权/状态契约无待实现者猜测。
**mutex:** 纯契约文档用 `architecture-docs`;事件注册变更串行占 `events`。U1 不修改 intent 业务类型,intent 代码变更从 U2 开始。
### U2. 确定性分段、PlanProposal 与 shadow 基线
**目标:** 不改变生产路由地生成 2–4 步提案和差异指标。
**依赖:** U1。
**文件:** `internal/intent/segmenter.go`、`plan_builder.go`、`types_v2.go`、`registry.go`、`internal/intent/testdata/*` 及 tests。
**做法:** characterization-first;规则分段、span、指代/连动护栏、安全复扫、显式依赖、稳定 digest。
**测试:** 连接词/句号/序号;查询并总结不拆;指代失败澄清;红线整体拒绝;5 段拒绝;同输入 digest 稳定;写段不静默丢弃。
**停走门:** shadow 不改响应;对 golden、hard-negative 和真实抽样人工标签做 counterfactual evaluation,报告分母、误拆/漏段/错误自动执行率及置信区间;预注册阈值未达不得切档。
**mutex:** `intent`。
### U3. intentflow、PG 状态机与 repository
**目标:** 建立持久计划/步骤/决策与并发协议,不接真实写动作。
**依赖:** U1、U2。
**文件:** `internal/app/intentflow/*`、`deploy/postgres/goose/*intent_plan*`、`internal/app/app.go`、PG tests。
**做法:** owner repository、UoW、CAS revision、decision nonce、绝对过期、lease/fencing、创建幂等、retention、组合根装配。
**测试:** 双创建;nonce 同/异 digest;确认/取消/过期竞态;两 worker 抢占;租约接管;旧 fencing token 在动作属主处被拒绝;重启恢复;业务成功但 receipt 写回失败;环境隔离。
**停走门:** 无双 owner/双执行,arch-check 无新例外。
**mutex:** 新增 `intent-plan`,迁移窗口协调 `db/app`。
### U4. 事件、卡片与步骤投影
**目标:** 权威计划可靠投影;消息/SSE 丢失不影响恢复。
**依赖:** U3。
**文件:** 新增 intent-plan event registry/schema、intentflow projection subscriber、ctxmgr owner port、对应 parity/dispatcher integration tests。
**做法:** 同 UoW outbox、事实事件、消费者幂等与最小 payload;复用 Track E 已有重试/dead letter/replay。禁止修改通用 claim、lease、delivery、retry 或 replay 语义;若确需修改,另立缺陷任务。
**测试:** 重复/乱序;projection 暂停 replay;消息失败后 GET 修复;worker restart;伪造 producer/字段拒绝;同项目跨用户不可见。
**停走门:** shadow projection 与 DB diff=0,delivery 可查。
**mutex:** `events`;ctxmgr 写入只走 owner 端口。
### U5. 决策 API 与即时授权端口
**目标:** 按钮/自然语言走同一服务端命令,执行前重新授权。
**依赖:** U3。
**文件:** `internal/server/*intent_plan*`、`internal/app/intentflow/*`、授权端口契约、fake/dry-run adapter、auth integration tests。
**做法:** active discovery/GET/decision、错误信封、四元作用域、expected revision、依赖闭包、资源版本;不在本单元接真实业务属主 adapter。
**测试:** 投影缺失仍能发现活动计划;非成员/跨项目/跨 session;角色撤销;资源变更;stale revision;重复点击;非法部分确认;edit 使旧卡失效;按钮/自然语言同 receipt。
**停走门:** 权限负例全绿;确认前零副作用;无系统身份绕过。
**mutex:** `intent-plan` + `server/authz`;动作接入另占 owner mutex。
### U6. Web 卡片、刷新与可访问性
**目标:** UI 只呈现 PlanView,刷新和多标签一致。
**依赖:** U4、U5。
**文件:** `web/src/types/workbench.ts`、`web/src/components/chat/InteractiveCard.tsx`、API client、`web/src/App.tsx`、web/browser tests。
**做法:** 两卡、步骤进度、依赖选择、submitting/outdated/expired/conflict、GET reconcile;计划动作不进入本地 AST/资源修改路径。
**测试:** reload/reopen 与无投影 active discovery;双标签确认/取消;409 查看最新版;过期重建;字段输入保留;键盘/读屏/live-region;窄屏 44px/reduced-motion;SSE 重复乱序;慢请求;validated_only 明示未执行。
**停走门:** 真实浏览器双标签/reload 无本地假成功。
**mutex:** `web`。
### U7. 低风险只读执行与聚合
**目标:** 独立低风险查询从 proposal 安全推进到完成。
**依赖:** U4、U5;可与 U6 并行,开放 auto_read tier 前两者都必须通过。
**文件:** `internal/app/intentflow/*`、query adapters、coordinator/chatflow 兼容入口、integration tests。
**做法:** 每步即时授权、显式依赖、ResultReference、失败/阻塞汇报;旧 executeIntentPlan 仅兼容,不扩成跨模块 switch。
**测试:** 2–4 查询;独立失败继续;依赖失败阻塞;敏感字段脱敏;同 turn 重放;重启续跑。
**停走门:** legacy 单意图无回归,重复执行为 0。
**mutex:** `intent-plan`;触及入口时协调 `chat`。
### U8. 生成任务 adapter
**目标:** 经确认后只开放 `task.run` 与 `task.run.adhoc`,形成第一版生成闭环。
**依赖:** U7。
**文件:** intentflow taskrun adapter、taskrun owner port/tests、real PI/browser tests。
**做法:** shadow/dry-run 后开启;传稳定幂等键,保存 result reference/receipt;不改变无活动计划时的单意图行为。
**测试:** 多意图生成需确认;活动计划冲突;权限撤销;重放;部分完成;receipt 丢失恢复;真实 PI 结果引用。
**停走门:** taskrun owner/PG/auth/browser/real PI 分层证据全绿。
**mutex:** `taskrun` + `intent-plan`。
### U9. LLM 分段 adapter 与全面灰度
**目标:** 仅为规则无法可靠判断的输入提供受控建议。
**依赖:** U2、U7。
**文件:** intentflow segment proposal port/adapter、版本化 schema、eval/real PI tests。
**做法:** 最小输入、严格 schema、固定版本/digest、护栏优先、shadow、超时 fail closed。
**测试:** malformed/timeout;重试稳定;模型改风险/权限无效;红线拆分逃逸失败;敏感内容不出站;冲突澄清。
**停走门:** real PI eval 达预注册阈值且安全错误为 0。
**mutex:** `intent-plan` + `pi-agent`,不得改变 intent imports。
U9 是核心首版之外的独立实验,不参与 U1–U8 的完成判定。未实施或未达阈值时,规则无法裁定的输入继续进入澄清。
### U10. 低风险 mutate adapters
**目标:** 只接入经专项批准的 medium/low mutate action。
**依赖:** U8。
**文件:** 每个动作的 intentflow adapter 与 owner tests。
**做法:** 每个 action 独立 short-term、flag、dry-run、权限负例和回滚;不打包发布。
**停走门:** 单 action 证据齐全后才加入 full tier。
**mutex:** 对应动作 owner + `intent-plan`。
### U11. 文档治理 adapters
**目标:** 按 claim/submit/review/final 等 action 分项接入 docgov,不复制其 duty/lifecycle 规则。
**依赖:** U8。
**文件:** intentflow docgov adapters、docgov owner ports/tests、browser auth negatives。
**做法:** 高风险动作逐个任务、逐个 go/no-go;必须带 expected document version。
**停走门:** 各 action 的跨角色、生命周期和并发负例独立签署。
**mutex:** `docgov` + `intent-plan`。
### U12. Workflow 与 run-control adapters
**目标:** 分别接入 workflow switch/run 与 task run resume/restart/cancel。
**依赖:** U8。
**文件:** intentflow workflow/run adapters、owner ports/tests。
**做法:** workflow 与 run-control 必须拆成独立 short-term,不共用发布开关或回滚点。
**停走门:** 当前 stage/state、权限、幂等和冲突负例分别通过。
**mutex:** `workflow` 或 `taskrun` + `intent-plan`。
---
## 十二、验收矩阵与 DoD
必须覆盖:两个只读查询;查询+生成确认前零副作用;部分确认后未选项仍可稍后确认、显式排除才取消;增量补槽保留已验证值;部分完成可重试/继续/关闭;确认后权限撤销;双标签确认/取消只一方成功;确认/过期竞态;服务/worker 重启不重跑成功步骤;投影停机而 GET 正确;“查法规并总结”不误拆;红线混入整体拒绝;前序结果含提示注入仍只作材料;无活动计划时单意图生成不变、有活动计划时不创建第二任务、批量生成需确认;跨用户/项目/会话隐藏;同 turn/nonce 异摘要冲突;编辑后旧卡 stale。
Definition of Done:
- [ ] 核心首版 U1–U8 按各自停走门独立验收;U9、U10–U12 未实施不阻塞首版,但任何已启用 adapter 必须满足自己的停走门;
- [ ] `intent -> maturity` 保持,intentflow 无 service locator、pool 或跨 owner SQL;
- [ ] 所有写/生成/控制在未确认和越权时副作用为 0;
- [ ] 双标签、刷新、服务/worker 重启、重复/乱序事件下无双执行且可恢复;
- [ ] 按钮与自然语言走同一命令,每步即时授权并校验资源版本;
- [ ] 中间结果不进 FAV,事件不携带敏感正文;
- [ ] arch-check、Go short、PG、web build/test、真实 browser 和适用 real PI 分别有报告;
- [ ] FEATURE-MATRIX、CURRENT、任务与必要时 gap-matrix 一致;
- [ ] 清除废弃实验、旧本地成功路径和临时开关;回滚版本仍能读取/取消已有计划。
---
## 十三、关键决策
1. 采用 `app/intentflow` 深模块,不继续膨胀 coordinator;
2. 单意图生成行为保持;多意图策略由 intentflow 的 BatchActionPolicy 管理并引用 ActionRegistry action key,不把应用编排政策回灌 L1;
3. 同步权威状态 + outbox 投影,不用纯事件驱动 plan state;
4. 服务端绝对过期,不用 TTLTurns 作权威;
5. 逐步骤事务,不制造跨 owner 长事务;
6. LLM 只建议分段且最后实施;
7. 新行为默认 legacy/shadow,现有 `MULTI_INTENT_ENABLED=true` 不是自动放量许可。
不采用:把完整 PendingPlan 塞进 UserProjectContext、扩展前端本地 cardActionEngine 执行业务、用 coordinator switch 持有所有具体 engine、LLM 直接生成可执行计划、跨模块大事务。它们会造成双真相、越权/假成功、service locator 回潮、不可信执行或解耦倒退。
长期维护归属按模块分开:intent owner 维护规则与评测;intentflow owner 维护状态机、schema 和 rollout;web owner 维护卡片交互;events owner 维护投影契约;各 action owner 维护自己的授权 adapter。上线后每次新增 ActionSpec 必须同时给出批量策略、计划适配能力和负例,不能让矩阵靠人工记忆同步。
+40
View File
@@ -99,6 +99,45 @@
---
### 6. 模块化单体解耦架构
| 项 | 链接 |
|-----|------|
| 主报告 | [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) |
| 整改计划 | [../remediation/2026-09-14-module-decoupling-refactor-plan.md](../remediation/2026-09-14-module-decoupling-refactor-plan.md) |
| 一句话总结 | 先以文档可靠性纵向试点验证事务、锁、授权、事件与 FAV,再按证据扩展模块边界 |
**核心要点**:
- 单一写者负责 SQL 和不变量,应用 UnitOfWork 负责跨属主原子提交;
- 数据库行锁、事务级 advisory lock、唯一约束和 fencing token 支撑多副本并发;
- workspace 是可清理投影,FAV 只保存已确认终态成果;
- 事件采用逐消费者 delivery、幂等 inbox、租约、重试和 dead letter;
- HTTP、CLI、worker、subscriber 和恢复工具使用同一逐动作授权模型;
- 先原地端口化,行为稳定后才物理搬包。
---
### 7. 多意图持久计划与 HITL
| 项 | 链接 |
|-----|------|
| 主方案 | [2026-09-15-multi-intent-hitl-plan.md](2026-09-15-multi-intent-hitl-plan.md) |
| 复核 | [../audit/2026-09-15-multi-intent-hitl-plan-review.md](../audit/2026-09-15-multi-intent-hitl-plan-review.md) |
| 任务总览 | [../ops/short-term/2026-09-15-multi-intent-hitl.md](../ops/short-term/2026-09-15-multi-intent-hitl.md) |
| U1 契约 | [../ops/short-term/2026-09-15-multi-intent-u1-contracts.md](../ops/short-term/2026-09-15-multi-intent-u1-contracts.md) |
| U2 分段 | [../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md](../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md);[报告](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
| U3 PG | [../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md](../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
| U4 投影 | [../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md](../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
| U5 API | [../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md](../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md);[报告](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
| U6 Web | [../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md](../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md);[报告](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
| 一句话总结 | intent 保持纯规则,intentflow 持久化计划并统一确认、授权、幂等、恢复和逐动作执行 |
**硬边界**:确认不等于授权;PG 是计划真相,卡片/SSE 是投影;写动作按 owner 端口逐项接入;LLM 只能提出不可信分段建议。
---
## 🏗️ 在整体架构中的位置
```
@@ -161,6 +200,7 @@
├── 04-项目多工作流与智能产品经理-测试经理工作流-实施计划.md
├── 05-Phase0-基线确认与契约冻结.md
└── 06-Phase7-全链路验收与发布基线.md
├── 2026-09-14-module-decoupling-architecture.md ← 模块化单体解耦
.tmp/ ← 中间分析文件
├── intent-recognition/
+600
View File
@@ -0,0 +1,600 @@
# U1 architecture baseline. Import allowlist is a 2026-09-14 production go list snapshot.
# SQL write / path / event rules apply only to production Go (not Goose, *_test.go, or fixtures).
# Existing debt lives in exceptions with owner + milestone + expiry. New findings block immediately.
imports:
agent:
- config
auth:
- config
authz:
- docduty
bizdev:
- authz
- config
- ctxmgr
- db
- docduty
- docgov
- docrevision
- freedoc
- kb
- maturity
- projectcontext
- projectworkflow
- quote
- squad
- storage
- stream
- workflowdef
chat:
- app/chatflow
- app/intentflow
- app/stageflow
- coordinator
- ctxmgr
- docgov
- intent
- projectinstance
- replyexport
- squad
- stream
- taskrun
config: []
coordinator:
- agent
- app/stageflow
- ctxmgr
- docgov
- intent
- kb
- maturity
- projectinstance
- squad
- stream
ctxmgr:
- app/uow
- docgov
- replyexport
- storage
db: []
docduty: []
app:
- agent
- app/chatflow
- app/docadvance
- app/docflow
- app/docnotify
- app/docproject
- app/intentflow
- app/stageflow
- app/uow
- artifactvault
- auth
- authz
- bizdev
- config
- coordinator
- ctxmgr
- docgov
- docrevision
- events
- freedoc
- intent
- kb
- notification
- observability
- projectinstance
- projectworkflow
- storage
- taskrun
- workflowdef
- workspace
app/chatflow:
- coordinator
- ctxmgr
- maturity
- projectinstance
app/docnotify:
- docgov
- docrevision
- notification
- events
app/docadvance:
- docgov
- events
- notification
- projectinstance
- projectworkflow
app/docproject:
- docgov
- events
app/docflow:
- app/uow
- docgov
- docquery
- docrevision
- events
app/intentflow:
- app/uow
- events
- intent
app/uow: []
app/stageflow:
- bizdev
docquery:
- docgov
- docrevision
docgov:
- app/uow
- doccontent
- docduty
- fsutil
docrevision:
- app/uow
- doccontent
- fsutil
doccontent: []
freedoc:
- app/uow
- ctxmgr
- docrevision
- replyexport
fsutil: []
httpx: []
intent:
- maturity
kb:
- config
maturity: []
notification: []
observability: []
projectcontext:
- squad
projectinstance:
- docduty
- docgov
- projectworkflow
- workflowdef
projectworkflow:
- auth
quote: []
replyexport: []
server:
- agent
- app
- app/chatflow
- app/docflow
- app/intentflow
- app/stageflow
- app/uow
- auth
- authz
- bizdev
- chat
- config
- coordinator
- ctxmgr
- docduty
- docgov
- docquery
- docrevision
- events
- freedoc
- httpx
- intent
- kb
- notification
- observability
- projectinstance
- projectworkflow
- replyexport
- storage
- squad
- stream
- stream/transport
- taskrun
- upload
- workflowdef
- workspace
- artifactvault
squad:
- agent
- config
- quote
- stream
- template
- workspace
storage: []
stream: []
stream/transport:
- stream
taskrun:
- app/uow
- artifactvault
- bizdev
- ctxmgr
- events
- projectworkflow
- stream
- workspace
template: []
upload: []
workflow: []
workflow/runtime:
- projectinstance
- workflowdef
workflowdef:
- projectworkflow
- storage
- upload
- workflow
workspace:
- app/uow
events:
- app/uow
artifactvault:
- app/uow
- fsutil
dataset:
- artifactvault
- app/uow
table_owners:
document_records:
- docgov
chat_messages:
- ctxmgr
chat_turns:
- ctxmgr
freeform_documents:
- freedoc
task_runs:
- taskrun
task_run_manifests:
- taskrun
document_versions:
- docrevision
document_snapshots:
- docrevision
document_change_events:
- docrevision
event_envelopes:
- events
event_deliveries:
- events
event_dead_letters:
- events
event_inventory_decisions:
- events
event_repair_audit:
- events
event_replay_plans:
- events
event_service_principals:
- events
event_delivery_attempts:
- events
event_consumer_modes:
- events
event_consumer_checkpoints:
- events
event_reconciliations:
- events
event_projection_outcomes:
- app/docproject
notifications:
- notification
stage_advance_requests:
- notification
final_artifacts:
- artifactvault
artifact_payload_staging:
- artifactvault
artifact_blob_references:
- artifactvault
artifact_publication_attempts:
- artifactvault
artifact_deletion_ledger:
- artifactvault
artifact_quarantine:
- artifactvault
artifact_backfill_exclusions:
- artifactvault
dataset_registry:
- dataset
dataset_backfill_jobs:
- dataset
dataset_backfill_checkpoints:
- dataset
dataset_backfill_queue:
- dataset
dataset_destroy_requests:
- dataset
intent_plans:
- app/intentflow
intent_plan_steps:
- app/intentflow
intent_plan_decisions:
- app/intentflow
intent_plan_projections:
- app/intentflow
intent_plan_shadow:
- app/intentflow
path_owners:
output.md:
- squad
- workspace
data/dev:
- config
- workspace
- artifactvault
workspaces/:
- squad
- workspace
event_producers:
outbox.notify:
- docrevision
- app/docflow
document.agent_candidate_ready:
- docrevision
- app/docflow
- events
document.agent_version_committed:
- docrevision
- app/docflow
- events
- app/docproject
document.downstream_impact_detected:
- docrevision
- app/docflow
- events
document.change_report_degraded:
- docrevision
- app/docflow
- events
document.approved:
- app/docflow
- events
- app/docadvance
taskrun.completed:
- taskrun
taskrun.cancelled:
- taskrun
fav.artifact_staged:
- app/docflow
intent.plan.awaiting_input:
- app/intentflow
- events
intent.plan.step_changed:
- app/intentflow
- events
intent.plan.completed:
- app/intentflow
- events
event_consumers:
outbox.notify:
- app/docnotify
- notification
document.agent_candidate_ready:
- notify
document.agent_version_committed:
- projection
- notify
document.downstream_impact_detected:
- notify
document.change_report_degraded:
- notify
document.approved:
- workflow_advance
- notify
taskrun.completed:
- notify
taskrun.cancelled:
- notify
fav.artifact_staged:
- fav
intent.plan.awaiting_input:
- projection
- notify
intent.plan.step_changed:
- projection
- notify
intent.plan.completed:
- projection
- notify
unwrap_owners:
- docgov
- docrevision
- taskrun
- freedoc
- events
- artifactvault
- ctxmgr
- app/intentflow
exceptions:
- kind: sql_write
package: docduty
file: internal/docduty/revoke.go
symbol: document_records
owner: docduty
reason: duty slot revoke still writes reviewer/approver columns directly; fold into docgov repository during U3
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docduty
file: internal/docduty/store.go
symbol: document_records
owner: docduty
reason: heal/store updates duty columns on document_records; move behind docgov repository in U3
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docrevision
file: internal/docrevision/pg_store.go
symbol: document_records
owner: docrevision
reason: projectRootPointersTX updates controlled root pointers; U3 must keep this inside the shared UnitOfWork
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docrevision
file: internal/docrevision/pg_store.go
symbol: freeform_documents
owner: docrevision
reason: projectRootPointersTX also projects freeform heads; keep atomic in U3 then hand write ownership back
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: projectinstance
file: internal/projectinstance/store.go
symbol: task_runs
owner: projectinstance
reason: workflow terminate cancels task_runs; U8 owns run finalization in the same UoW
milestone: U8
expires: "2026-10-26"
- kind: path
package: agent
file: internal/agent/cursor.go
symbol: output.md
owner: agent
reason: runner still names the deliverable file; U5 replaces this with WorkspaceRef
milestone: U5
expires: "2026-10-12"
- kind: path
package: agent
file: internal/agent/piagent.go
symbol: output.md
owner: agent
reason: PI runner contract still uses output.md; U5 capability must hide the literal
milestone: U5
expires: "2026-10-12"
- kind: path
package: bizdev
file: internal/bizdev/service.go
symbol: data/dev
owner: bizdev
reason: default data-root example string; U5 resolver owns environment roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: bizdev
file: internal/bizdev/service.go
symbol: output.md
owner: bizdev
reason: orchestration still joins workspace output.md; U5 removes Root/OutputDir
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/context.go
symbol: output.md
owner: coordinator
reason: coordinator reads projection path; U4/U5 must go through workspace capability
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/dialogue_llm.go
symbol: data/dev
owner: coordinator
reason: prompt example embeds data/dev; U5 must not leak runtime roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/document_summary.go
symbol: data/dev
owner: coordinator
reason: summary prompt embeds data/dev; U5 must not leak runtime roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/engine.go
symbol: output.md
owner: coordinator
reason: engine joins deliverable path; U5 WorkspaceRef
milestone: U5
expires: "2026-10-12"
- kind: path
package: docgov
file: internal/docgov/lease.go
symbol: output.md
owner: docgov
reason: SaveDocumentContent still writes projection files; U5 capability + U4 ledger-first read
milestone: U5
expires: "2026-10-12"
- kind: path
package: docgov
file: internal/docgov/project_docs.go
symbol: output.md
owner: docgov
reason: project doc helpers still construct output.md; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: docrevision
file: internal/docrevision/projection.go
symbol: output.md
owner: docrevision
reason: InspectProjection reads workspace file; U4 treats this as optional cache only
milestone: U4
expires: "2026-09-28"
- kind: path
package: docrevision
file: internal/docrevision/reconcile.go
symbol: output.md
owner: docrevision
reason: reconcile still repairs projection files; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: server
file: internal/server/document_revision_access.go
symbol: output.md
owner: server
reason: handler still reads workspace files; U4 must use docquery ledger
milestone: U4
expires: "2026-09-28"
- kind: path
package: server
file: internal/server/document_revision_handlers.go
symbol: output.md
owner: server
reason: handler error text mentions output.md; U4/U5 remove path leakage
milestone: U4
expires: "2026-09-28"
- kind: path
package: server
file: internal/server/server.go
symbol: workspaces/
owner: server
reason: server still concatenates workspaces/ roots; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: storage
file: internal/storage/cas.go
symbol: data/dev
owner: storage
reason: CAS default example path; U5 resolver
milestone: U5
expires: "2026-10-12"
baseline_counts:
import: 0
sql_write: 5
path: 16
event: 0
# U12: kinds already at zero production findings fail --mode block.
# sql_write/path keep dated exceptions until their owner milestones clear them.
block_kinds:
- import
- event
@@ -0,0 +1,21 @@
# U9 migration corpus 与八条轨道
八条 release 轨道(clean / oldest-supported / previous / hazard / import / reload / rollback / artifact recovery)的可执行夹具在:
- `internal/dataset/testdata/registry.json`(6–10 个批准 dataset:pinned / demo / regression / migration_baseline / ephemeral;quarantine 类不计入导入分母)
- `go test ./internal/dataset -run TestEightTracksPass`
## 轨道含义
| 轨道 | 验证 |
|------|------|
| clean | 空源 backfill 分母为 0 |
| oldest-supported | schema 28 可升级回填 |
| previous | schema 37(U8 节点)可回填 |
| hazard | 缺 snapshot、fork、高 ID、legacy-v0 → quarantine |
| import | 批准 registry 6–10 条 |
| reload | 重放不重复 artifact |
| rollback | 共享 DSN / 缺备份阻止 destroy;scratch 可过门禁 |
| artifact recovery | FAV recover-as-collection 只写 scratch |
回填枚举 SQL 只读 `document_snapshots` / `document_change_events` / `document_records` / `chat_turns`,禁止 `work_dir` 与 `workspaces/`。
@@ -15,7 +15,7 @@
- OS: Linux;Go 模块测试 + `cd web && npm test`
- PG 集成:`TEST_DATABASE_URL` 可用时执行 `chat_history_refresh_pg_test.go`
- 真实 PI E2E:待 dev `:8080` + pi-agent 人工补录
- 真实 PI E2E:dev `:8080` + 运行中 `pi-agent`(U9 镜像);脚本 `assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py`
## 四、 预期结果 (Expected Results)
@@ -59,11 +59,12 @@
- **Actual Output**: 192 tests PASS
- **Evaluation**: PASS
### 用例 F:真实 PI 刷新 E2E
### 用例 F:真实 PI 闲聊刷新 E2E
- **Input**: dev 环境文档生成 → 浏览器刷新
- **Actual Output**: 本轮未执行(需运行中 pi-agent 容器)
- **Evaluation**: DEFERRED — 合入 dev 后占集成槽位补录
- **Input**: 运行中 dev `:8080` + `pi-agent`;新建项目 6252 / `sess-p6252-u10`;`POST /api/v1/chat` 后 `GET /api/v1/chat/messages/window` 与 `GET /api/v1/chat/categories`;guest 读同一 session。产物:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`
- **Actual Output**: `agent_backend=pi-agent`,schema 38;闲聊 200(3481ms);window_msgs=2 且 category_total=2;guest 403 `SESSION_FORBIDDEN`。`core_overall=PASS`。文档任务 `PUT workflow-plan` 400,未跑 intake。
- **Evaluation**: 闲聊刷新同集与跨用户负例 **PASS**;激活后文档任务刷新仍开放
- **Duration**: 3704ms(core)
## 六、 自动化测试套件汇总 (Test Suite Execution)
@@ -74,5 +75,5 @@ cd web && npm test → PASS (192)
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- 代码与 PG 集成测试达到合并标准;真实 PI 刷新 E2E 需在 dev 容器冒烟后补证据。
- 合入后执行 `./scripts/env-service.sh dev restart` 并对 project 143 样本验证 backfill 效果。
- 自动化、PG 与真实 PI 闲聊刷新同集已补证据;guest 403 成立。
- 发布门禁中的「激活后文档任务 + 重登/重启」仍未勾选。项目 143 只读,未用作活验样本。
@@ -59,9 +59,18 @@
### 用例 E:真实 PI + 浏览器刷新/双标签页
- **Input**: 真实 PI 只读总结已执行;浏览器刷新/双标签页待执行
- **Actual Output**: 只读总结见用例 H;刷新和 busy 可见性尚无浏览器证据
- **Evaluation**: PARTIAL
- **Input**: 新建项目 `INTENT双标签-061002`(id **6275**,**禁止 143**)/ `sess-p6275-u10`;Tab A `POST /api/v1/tasks/runs`「请开始编写用户初始需求表」真实 `pi-agent`;租约出现后 Tab B 再 POST;浏览器双标签打开同一项目
- **Actual Output**:
- health/ready schema **38**、`agent_backend=pi-agent`
- Tab A `202` `run_1789452602295343365` status=running;2ms 内 `lease_holder_type=squad`
- Tab B HTTP **409** `DOC_BUSY`,响应无 `run_id`;PG `task_runs` 仅 1 行
- 聊天窗 assistant `error_info.code=DOC_BUSY` 且 `actions=[]`,另有 `task_status=running` 占位;再次 GET window 同集
- 真实 PI **completed**(约 280s,质量 100);租约在终态探测后 **1ms** 已空(无需客户端刷新)
- 终态后再 GET window:DOC_BUSY 卡仍 `actions=[]`,无重试动作
- 浏览器(Docker Playwright,宿主机缺 libatk):双标签可见「本文档正由【项目助手】编辑/生成中」、聊天 `DOC_BUSY`、发送按钮 disabled、刷新后仍无重试。截图 `assets/2026-09-15-conversation-intent-dual-tab/screenshots/`
- **Evaluation**: **PASS**
- **性能与耗时**: API 活验 281s;Docker UI 4.4s。产物:`assets/2026-09-15-conversation-intent-dual-tab/live.json`、`playwright-docker.json`
- 诊断污染:`sess-p143-u9` **未**写入、未删除历史探针
### 用例 F:dev 集成冒烟
@@ -106,4 +115,4 @@ git diff --check PASS
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
代码级、构建门禁及真实 PI 只读总结已通过;原句不会创建任务或租约。最终 dev 镜像重建后 `/ready` 为 HTTP 200;只读复核确认用户原会话最大消息 ID 仍为 567、隔离 fixture 会话/消息/run 均为 0、project 143 无有效文档租约。尚不能标记发布完成:浏览器刷新恢复、双标签页租约可见性与并发写“不新增第二 run”仍需补录。真实会话中的诊断消息与误启动产物只记录证据,不在未获确认时删除或回滚。
代码级、构建门禁、真实 PI 只读总结与 **新建项目双标签 busy** 已通过。项目 **6275** / `run_1789452602295343365`:并发写 409 `DOC_BUSY` 不新增第二 run;刷新后 `actions=[]`;PI 终态后租约自动解除。浏览器双标签截图见 `assets/2026-09-15-conversation-intent-dual-tab/screenshots/`。真实会话 `sess-p143-u9` 中的诊断消息与误启动产物只记录证据,不在未获确认时删除或回滚。`production_ready` 仍为 no(CI 三工作流 E2E / 前端抽检等其它 blocker)。
@@ -0,0 +1,131 @@
# 文档可靠性 M2(U5–U7)测试报告
## 一、 测试背景 (Background)
M1 活验报告最后一句为 **继续 M2**([2026-09-14-document-reliability-pilot-live-test-report.md](./2026-09-14-document-reliability-pilot-live-test-report.md))。上一份「停止扩面」试点报告保持原句,不改写。本轮只实施并验证 U5 WorkspaceRef、U6 耐久投递、U7 按文件摘取 FAV,并给出能否开工 M3 的停走句。
## 二、 测试目标 (Test Objectives)
- 2/4 dispatcher 无双 owner;crash-before/after-side-effect/ack 可恢复。
- 乱序 aggregate version 不越过缺号。
- 跨项目事件 / 坏 digest / 伪造 producer → quarantine;auth/integrity 立即死信;attempt 12 后死信。
- `SKIP LOCKED` 只用于 claim。
- 业务终态、staging、outbox 同事务;失败回滚无泄漏。
- union-deny;中间态(prompt/tool_trace/scratch)准入率 0。
- `FAV_DEGRADED_READ` 默认 false;授权成功之后才允许 degraded read。
- Goose 00034–00036 重取号;组合 Up+Down;禁止把 FAV 树的 00034 原样合入。
- 占槽后主仓 rebuild;health/ready 为 schema 36,无路径泄漏。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 本机 `go test`;容器 `agent-dev-app` |
| 合入 | 主仓 `dev` `--no-ff` `refactor/document-reliability-pilot` → `0872d8f` |
| 部署 | 主仓 `./scripts/env-service.sh dev rebuild`(禁止 worktree 内 env-service;禁止 `compose restart` 当证据) |
| Compose | 项目 `agent-dev`,HTTP `:8080` |
| Agent | `agent_backend=pi-agent` |
| Schema | **36**(00034 fencing + 00035 envelopes + 00036 FAV) |
| `FAV_DEGRADED_READ` | 宿主与容器均 unset / 默认 false |
| PostgreSQL | 隔离库 `agent_rel_m2`(`shuimu-system-pg-test:5434`),另建 `agent_rel_m2_goose` 做 Down;测完 `DROP`;禁止 `agent_system_dev/test/main` |
| 项目 143 | **只读**;本轮未 terminate,未改 workflow-plan |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-m2/` |
镜像身份:`app_image=sha256:8ab9f63a05274e08d55322e162f8fec3f5822bd3e14375376df856308329b511`。见 `rebuild-health-ready.txt`。
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit | WorkspaceRef 无物理路径;旧 fencing 被拒;事务内禁止文件 I/O;2/4 dispatcher 单 owner;gap 不跳号;中间态准入 0 |
| PostgreSQL | 00034–00036 Down 到 33 后再 Up;outbox+staging 同 TX,失败零泄漏 |
| 故障注入 | crash-before/after ack 无双副作用;attempt 12 死信 |
| 真实 PI | 本轮不重跑编制;rebuild 后 ready 仍为真实 `pi-agent` |
| 真实浏览器 | 本轮不重跑 Playwright;web 单测 + production build 必须绿 |
| restart/rebuild | health/ready `status=ok`,`schema_version=36`,无路径泄漏,vault 未配置不假绿 |
| 跨用户 / 授权 | 授权失败不碰 vault;tombstone union-deny |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `unset TEST_DATABASE_URL; go test -short ./...`;目标包 `go test -race -short`;`./scripts/arch-check.sh --mode warn`
- **实际输出**: 全仓 short 包 `ok`。目标包 race:`TestTwoAndFourWorkersNoDoubleOwner`、`TestCrashBeforeAfterAck`、`TestGapDoesNotSkipVersion`、`TestQuarantineBadDigestForgedProducerCrossProject`、`TestAttempt12GoesDeadLetter`、`TestStaleFencingRejected`、`TestEvaluateEligibility_IntermediateAdmissionZero`、`TestTombstoneUnionDeny`、`TestFavDegradedReadDefaultOff` 均为 PASS。`arch-check warn: production gate passed`。`--mode block` 仍会因既有 path/sql_write 例外基线失败(U1 设计;本里程碑新增 import 已清零)。
- **评价判定**: **PASS**
- **性能与耗时**: 全仓 short 约 13s;目标包 race 约 3–4s。日志:`go-test-short.txt`、`go-test-m2-packages-race.txt`、`arch-check-warn.txt`
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `TestGooseM2_00034to00036_DownThenUp`、`TestOutboxAndStagingSameTxRollback`
- **实际输出**:
```
--- PASS: TestGooseM2_00034to00036_DownThenUp (0.36s)
--- PASS: TestOutboxAndStagingSameTxRollback (0.01s)
```
00034–00036 Up 到 36,Down 到 33 后 `event_envelopes`/`final_artifacts`/`lease_fencing_token` 消失,再 Up 回 36。同 UoW 写入 envelope + FAV staging 后故意 `boom`,回滚后两表计数为 0。测完 `DROP DATABASE agent_rel_m2`(goose 子库随测试 Cleanup DROP)。
- **评价判定**: **PASS**
- **性能与耗时**: goose 组合约 0.36s。日志:`goose-00034-36-down-up.txt`
### 5.3 故障注入
- **测试输入**: 内存 dispatcher crash/lease 过期/重放;attempt 12;目标包 `-race`
- **实际输出**: 过期 worker ack 为 `ErrStaleFencing`;后到 worker 副作用恰好 1;inbox 去重。12 次瞬时失败后 status=`dead`。
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒。日志:`go-test-m2-packages-race.txt`
### 5.4 真实 PI
- **测试输入**: 本轮不新编制文档。检查 rebuild 后 `/api/v1/ready` 的 `agent_backend`
- **实际输出**: `agent_backend=pi-agent`,不是 stub。编制活验仍以 M1 报告为准。
- **评价判定**: **PASS**(继承 M1 活验;本轮验证后端身份与 schema 36 ready)
- **性能与耗时**: health/ready 亚秒
### 5.5 真实浏览器
- **测试输入**: 本轮未重跑 Playwright(项目 143 只读约束仍在)。`web`:`npm test` + `npm run build`
- **实际输出**: tsx **365 passed / 0 fail**;vitest **30 passed**;production build `✓ built in 8.07s`(容器 rebuild 内 web build 同样成功)。
- **评价判定**: **PASS**(页面回归以 M1 活验为准;本轮前端门禁绿)
- **性能与耗时**: 单测约 1.4s + vitest 0.5s;本地 build 约 8s。日志:`web-unit.txt`、`web-build.txt`
### 5.6 restart / rebuild
- **测试输入**: 占集成槽后主仓 `./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/api/v1/health` 与 `/api/v1/ready`
- **实际输出**: 两者 HTTP 200,body 均为
```
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":36,"schema_ready":true,"task_store_ready":true}
```
无文件系统路径字段。vault 未配置时 ready 仍按 DB/schema/task_store 判定。
- **评价判定**: **PASS**
- **性能与耗时**: rebuild 约 27s。日志:`rebuild-health-ready.txt`、`health.json`、`ready.json`
### 5.7 跨用户 / 授权负例
- **测试输入**: `TestFavDegradedReadOnlyAfterAuthorize`;`TestTombstoneUnionDeny`;跨项目 envelope Apply
- **实际输出**: 授权失败时 vault `calls=0`;tombstone 读为 `ErrUnionDeny`;跨项目 delivery 为 `quarantine`
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `go test -short ./...` | PASS |
| 隔离库 goose Down/Up + 同事务回滚 | PASS,随后 `DROP DATABASE` |
| 目标包 `-race` | PASS |
| `arch-check --mode warn` | PASS |
| `arch-check --mode block` | 仍因既有例外基线失败(预期;非本里程碑新增违规) |
| web `npm test` | 365 + 30 PASS |
| web production build | PASS |
| 占槽 rebuild + health/ready | PASS,`schema_version=36` |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
U5–U7 的停走项在本轮全部观测为 PASS:dispatcher 无双 owner,崩溃与过期 fencing 可恢复,缺号不跳过,坏 digest/伪造 producer/跨项目进入 quarantine,FAV 中间态准入为 0,union-deny 生效,outbox 与 staging 同事务回滚,Goose 00034–00036 可 Down。`document.agent_version_committed` 已从 `OnOutbox` 正确性路径摘除,改由 `events.EventSink` 在 UoW 内追加。剩余 agent/coordinator 的 `output.md` 字面量仍是 U1 例外基线,属 M3 Workspace 清理范围,不构成本轮扩面失败。未把 `feature/final-artifact-vault` 整支 merge,未启用 `FAV_DEGRADED_READ`。
继续 M3
@@ -0,0 +1,137 @@
# 文档可靠性试点 M1 活验签字测试报告
## 一、 测试背景 (Background)
上一份 [M1 试点报告](./2026-09-14-document-reliability-pilot-test-report.md) 在 Unit/隔离库通过后,因未占槽 rebuild、无真实 PI/浏览器/4 会话而把最后一句写成 **停止扩面**。本轮不改写那份结论句;只补活验签字,决定能否开工 U5–U7。
## 二、 测试目标 (Test Objectives)
- A1:占集成槽,本地 `dev` `--no-ff` 合入试点分支,`env-service.sh dev rebuild`,health+ready 来自本分支镜像。
- A2:项目 143 只读打开/刷新/重登;新建项目打开/刷新/重登;`GET .../content` 为 200 且带 `consistency`;禁止把 missing 当 404。
- A3:真实 `pi-agent` + MiniMax 编制一条受控文档,刷新不丢正文。禁止 stub 当终态。
- A4:隔离库两个 pgx pool + 4 会话同 ETag 一赢,同 key+digest 跨 pool 重放。测完 `DROP DATABASE`。
- A5:分栏签字;最后一句只能是「继续 M2」或「停止扩面」。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 本机 `go test`;容器 `agent-dev-app` |
| 合入 | 主仓 `dev` `--no-ff` `refactor/document-reliability-pilot` → `cb8eaca` |
| 部署 | 主仓 `./scripts/env-service.sh dev rebuild`(禁止 `compose restart` 当证据) |
| Compose | 项目 `agent-dev`,HTTP `:8080` |
| Agent | 真实 `pi-agent`(`AGENT_BACKEND=pi-agent`),模型 `MiniMax-M2.7-highspeed`(云端 API,非 stub) |
| Schema | **33** |
| `FAV_DEGRADED_READ` | unset / 默认 false |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host --ipc host` |
| PostgreSQL | 隔离库 `agent_rel_itest`(`shuimu-system-pg-test:5434`),测完 `DROP`;禁止 `agent_system_dev/test/main` |
| 项目 143 | **只读**;未 terminate,未 `PUT /143/workflow-plan` |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-pilot-live/` |
镜像身份(rebuild 后):`app_image=sha256:251fa99d5de47d452b7f099304aa34b1e2aacf1b4e9d2d23d1cb4b850084910e`;随后把 `pi-agent` force-recreate 到 rebuild 所打的 `sha256:21fc9b64066c33e94d8db83695b4ff64ea5e49f6d65661f8ccab11ead083042d`。见 `rebuild-health-ready.txt`。
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit / stub | `go test -short` 全绿;hydrate 把 `missing` 当正文 |
| PostgreSQL | 双 pool 同 ETag 一赢;同 key+digest 跨 pool 重放;4 会话同 ETag 一赢 |
| 故障注入 | 与上一份隔离库 U2 一致,本轮 `-race` 再跑目标包 |
| 真实 PI | 新建项目激活后编制,账本 head 可读 |
| 真实浏览器 | 143 与新项目刷新/重登 200 + markdown;页面无「加载失败」;无 PROJECTION 409 |
| restart/rebuild | health/ready `status=ok`,`agent_backend=pi-agent`,`schema_version=33`;ready 不因 vault 未配置假绿,响应无路径泄漏 |
| 跨用户 | 匿名 401;非成员/跨项目/错误 stage-duty 同一 404 `DOCUMENT_NOT_FOUND` |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `unset TEST_DATABASE_URL; go test -short ./...`;`npx tsx --test src/lib/controlledDocHydrate.test.ts`;`./scripts/arch-check.sh --mode warn`
- **实际输出**: 全仓 short 包 `ok`;hydrate **17 passed**;`arch-check warn: production gate passed`
- **评价判定**: **PASS**
- **性能与耗时**: `internal/server` 约 9.6s。日志:`go-test-short.txt`、`hydrate-unit.txt`、`arch-check-warn.txt`
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `./internal/docrevision -run 'TestDocumentCommitConcurrencyPG|TestDocumentCommitTwoPoolsAndFourSessionsPG'`
- **实际输出**:
```
--- PASS: TestDocumentCommitConcurrencyPG (0.03s)
--- PASS: TestDocumentCommitTwoPoolsAndFourSessionsPG (0.03s)
```
两个独立 `pgxpool` 打同一 ETag 仅一赢;赢家 key+digest 跨 pool 重放 head 一致;随后 4 个会话同 ETag 仅一赢。测完 `DROP DATABASE agent_rel_itest`。
- **评价判定**: **PASS**(不是 4 个 OS 进程,是计划要求的双 pool 模拟两进程 + 4 会话;未使用进程内全局 mutex)
- **性能与耗时**: 62ms。日志:`go-test-pg-two-pool.txt`
### 5.3 故障注入
- **测试输入**: `go test -race ./internal/app/uow ./internal/app/docflow ./internal/docquery`(同一隔离库,DROP 前)
- **实际输出**: 三包 `ok`(含 cached)
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒到约 1.8s
### 5.4 真实 PI
- **测试输入**: Playwright 新建项目 → 未激活编制被 202 `blocked_pending_governance` → 配置并激活 → 发送「请基于本项目编制首轮《用户需求》摸底文档…」→ 等待小队终态 → 打开 `doc_proj*` intake
- **实际输出**: 编制用例 **4.2min PASS**。`GET /api/v1/docgov/documents/{id}/content` **200** 且 `markdown` 非空;刷新与重登正文相同。截图 `07-new-doc.png` / `08-new-doc-reload.png` / `09-new-doc-relogin.png`
- **评价判定**: **PASS**(真实 `pi-agent`,非 stub)
- **性能与耗时**: 编制+打开约 4.2min
### 5.5 真实浏览器
- **测试输入**: `RUN_UI_ACCEPTANCE=1 BASE_URL=http://127.0.0.1:8080`;`web/e2e/controlled-document-reload.spec.ts`(官方 Playwright 镜像)
- **实际输出**:
```
✓ project 143 content is 200 with consistency; anonymous is 401; unknown is 404 (4.6s)
✓ non-member GET of project 143 is the same 404 as unknown (7.4s)
✓ new project PI compile then reload keeps ledger markdown (4.2m)
✓ cross-project and wrong-stage GET stay DOCUMENT_NOT_FOUND (3.8s)
4 passed (4.5m)
```
143 打开/刷新/重登均为 200 + markdown + typed `consistency`,无 `PROJECTION` 409,页面无「加载失败」。未对 `/143/` 发 `PUT workflow-plan`,未 terminate。
- **评价判定**: **PASS**
- **性能与耗时**: 整套 4.5min。日志:`playwright-controlled-reload.txt`;截图 `screenshots/01`–`10`
### 5.6 restart / rebuild
- **测试输入**: 占槽后 `./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/api/v1/health` 与 `/api/v1/ready`
- **实际输出**: 两者 HTTP 200,body 均为
```
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":33,"schema_ready":true,"task_store_ready":true}
```
无文件系统路径字段。vault 未配置时 ready 仍按 DB/schema/task_store 判定,不是假绿。
- **评价判定**: **PASS**
- **性能与耗时**: rebuild 约 79s。日志:`rebuild-health-ready.txt`、`health.json`、`ready.json`
### 5.7 跨用户负例
- **测试输入**: 匿名 GET 143;局外人 D GET 143 与新项目文档;审核人 B GET 143 与伪造 `_design_control` stage
- **实际输出**: 匿名 **401**;其余均为 **404** `DOCUMENT_NOT_FOUND`,不泄露存在性
- **评价判定**: **PASS**
- **性能与耗时**: 3.8s。截图 `10-fail-closed.png`
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS(合入后、rebuild 前) |
| `go test -short ./...` | PASS |
| 隔离库双 pool / 4 会话 | PASS,随后 `DROP DATABASE` |
| 目标包 `-race` | PASS |
| `arch-check --mode warn` | PASS |
| hydrate 单测 | 17/17 PASS |
| Playwright 活验(官方镜像) | **4 passed** |
| 宿主 `npx playwright` | 因缺 `libatk-1.0.so.0` 无法启动;改走已验证的 `mcr.microsoft.com/playwright:v1.63.0-noble` |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
活验补齐了上一份报告缺的 rebuild、真实 PI、真实浏览器、双 pool/4 会话与 HTTP 跨用户负例。hazard 真页面 404/409/projection-missing 本轮观测为 0;授权未靠放宽;4 会话赢家来自数据库锁而非进程内 mutex。M1 签字通过,允许按计划实施 U5–U7。上一份「停止扩面」报告保持原句,不改写。
继续 M2
@@ -0,0 +1,132 @@
# 文档可靠性纵向试点(M0–M1 / U1–U4)测试报告
## 一、 测试背景 (Background)
受控文档写路径曾把账本、root pointer 与通知拆到提交后回调;读路径在 ledger 已存在时仍被 `InspectProjection` 绑架成 409。刷新、重登或 projection 缺失会被前端当成 404 再 hydrate。本轮只批准 M0–M1(U1–U4):门禁纠偏、UnitOfWork、文档命令同事务、授权后账本读。明确不授权 FAV 降级读、拆 chat/squad、占槽 rebuild。
## 二、 测试目标 (Test Objectives)
- U1:四类生产规则可重放;新违规 block;Goose/`*_test.go` 不记生产写者债。
- U2:跨属主同事务;第二属主/staging/commit 失败零残留;仅 `40001`/`40P01` 整事务重试。
- U3:人工编辑 / agent commit / approve / reject 锁后重鉴权;同 ETag 一赢一输。
- U4:projection missing/drift/empty 仍返回账本正文 + typed `consistency`;GET 零写入。
- 分栏必须各自签字。未占集成槽不得把 `:8080` 旧镜像或 `docker compose restart` 写成 rebuild 证据。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 1.27.1 |
| 分支 / worktree | `refactor/document-reliability-pilot` / `.worktrees/refactor-document-reliability-pilot` |
| 实现基线 | `dev@a8f9451` → `c754f77`(另含本报告前的 `fix(docflow)` 竞态修复) |
| Unit / stub | `go test -short ./...`(**未**设置 `TEST_DATABASE_URL`) |
| PostgreSQL | 隔离库 `agent_rel_itest`(`shuimu-system-pg-test:5434`),测完 `DROP DATABASE`;禁止 `agent_system_dev/test/main` |
| 目标包 race | `./internal/app/uow ./internal/app/docflow ./internal/docquery ./internal/archtest` |
| 前端 | `npx tsx --test src/lib/controlledDocHydrate.test.ts`(17 passed) |
| 真实 PI / 浏览器 / rebuild | **未执行**。集成槽 idle;CURRENT 禁止 M1 未签字 rebuild;`:8080` 仍是治理鉴权旧镜像,不能当本分支证据 |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-pilot/` |
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit / stub | 全绿;arch-check `--mode warn` 过门;characterization 同 ETag 一赢、approve/reject 唯一终态 |
| PG 事务与并发 | U2 故障注入绿;同 ETag 双会话 HumanEdit 仅一赢;head revision=1 |
| 故障注入 | 第二属主失败 / staging 失败 / commit 失败零行;`40001` 整事务重跑一条结果 |
| 真实 PI | 本分支容器内真实 `pi-agent` 全链路。**本轮不做** |
| 真实浏览器 | 项目 143 等价 hazard + 新建项目打开/刷新/重登正文 100%,404/409/projection-missing=0。**本轮不做** |
| restart/rebuild | 占槽后 `env-service.sh dev rebuild`。**本轮不做** |
| 跨用户负例 | 匿名/未知文档/授权拒绝 → `docquery.ErrClosed`,不泄露存在性 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `go test -short ./...`
- **实际输出**: 38 个有测试包 `ok`,无 `FAIL`。摘录:
```
ok chat-agent-system/internal/app/docflow
ok chat-agent-system/internal/app/uow
ok chat-agent-system/internal/archtest
ok chat-agent-system/internal/docquery
ok chat-agent-system/internal/docrevision
ok chat-agent-system/internal/server 9.796s
```
- **评价判定**: **PASS**
- **性能与耗时**: `internal/server` 约 9.8s,其余亚秒到数秒。日志:`assets/2026-09-14-document-reliability-pilot/go-test-short.txt`
`./scripts/arch-check.sh --mode warn` → `arch-check warn: production gate passed`。`--mode block` 仍会因既有例外基线失败(U1 设计如此)。
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `./internal/app/uow`、`./internal/app/docflow`、`./internal/docquery`;`./internal/docrevision -run TestDocumentCommitConcurrencyPG`
- **实际输出**:
```
ok chat-agent-system/internal/app/uow 0.065s
ok chat-agent-system/internal/app/docflow 0.003s
ok chat-agent-system/internal/docquery 0.003s
ok chat-agent-system/internal/docrevision 0.024s
```
- **评价判定**: **PASS**(1–2 会话级)。**未**跑 4 个独立 app 进程。
- **性能与耗时**: UoW 包 65ms;并发编辑 24ms。日志:`go-test-pg-race.txt`
### 5.3 故障注入
- **测试输入**: `internal/app/uow` PG 用例(第二属主失败、staging/outbox 失败、commit 失败、`40001` 重试、version/permission/digest 不重试)
- **实际输出**: `ok chat-agent-system/internal/app/uow 0.065s`
- **评价判定**: **PASS**
- **性能与耗时**: 与 5.2 同一次隔离库运行
### 5.4 真实 PI
- **测试输入**: 未切本分支容器,未跑真实 `MiniMax-M2.7-highspeed` 编制链路
- **实际输出**: 无
- **评价判定**: **FAIL(未测)** — 禁止用 stub 冒充终态
- **性能与耗时**: n/a
### 5.5 真实浏览器
- **测试输入**: 未对项目 143 / 新建项目做本分支页面打开、刷新、重登
- **实际输出**: 仅前端单测 17/17(`hydrate treats projection missing as ledger content, not 404`)
- **评价判定**: 单测 **PASS**;真实页面 **FAIL(未测)**
- **性能与耗时**: hydrate 套件 149ms
### 5.6 restart / rebuild
- **测试输入**: 未占集成槽,未执行 `./scripts/env-service.sh dev rebuild`
- **实际输出**: 无。`:8080` 仍为既有 dev 镜像(治理鉴权 G5),不得当作本分支部署证据
- **评价判定**: **FAIL(未测)**
- **性能与耗时**: n/a
### 5.7 跨用户负例
- **测试输入**: `TestGetFailClosed`(匿名、Authorize 拒绝、未知 doc_id);`TestReauthDeniesWrongAuthor`;`TestBatchGetLimitsAndCrossProject`(101 条 / 跨项目)
- **实际输出**: 均失败关闭;未知文档与拒绝同一 `ErrClosed`
- **评价判定**: 服务端单测 **PASS**。HTTP 跨登录浏览器负例 **未测**
- **性能与耗时**: 亚秒
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS(U4 提交前) |
| `go test -short ./...` | PASS,38 ok |
| 隔离库 `go test ./internal/app/uow ./internal/app/docflow ./internal/docquery` | PASS |
| `go test ./internal/docrevision -run TestDocumentCommitConcurrencyPG` | PASS |
| `go test -race` 目标包 | PASS(修复 `Commands.Auth` 并发写入后) |
| `arch-check --mode warn` | PASS |
| `tsx --test controlledDocHydrate.test.ts` | 17 passed |
| 全仓 `go test`(带 `TEST_DATABASE_URL` 且无 `-short`) | 未作为本报告门禁;会把无关 workflow PG 和「5434=共享 test 口」拒绝用例搅在一起 |
`-race` 初跑曾在 `run()` 里给共享 `Commands.Auth` 赋值,判定为数据竞争;已改为只读 `authorizer()`。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
U1–U4 代码已在实现分支落地,Unit/stub、隔离库事务/故障注入、目标包 race 与前端 hydrate 单测通过。用户可感知的主修复(ledger-first GET)**没有**真实 PI、真实浏览器、restart/rebuild 签字;1/2/4 进程一致性只验证到双会话。按计划停走门,不得用「部分通过」打开 U5–U12。
停止扩面
@@ -0,0 +1,172 @@
# 治理鉴权升级(职责-动作 + 未激活 202-blocked)测试报告
## 一、 测试背景 (Background)
Wave 5 已收口冻结态与 DutyMode,但 full 文档仍因创建者隐式全通行、未激活 run 仍可能拉起小队、`initial_workflow_key` 仍可能直通 active。本轮按已锁定矩阵落地动作-职责鉴权、未激活 202-blocked、关闭创建直通,并在真实 `pi-agent` 开发栈做页面 + API 负例验收。项目 143 **只打开设置/文档做只读回归,未终止、未改规划**。
## 二、 测试目标 (Test Objectives)
- 零治理新项目可普通对话;编制类文档任务 202 + `blocked_pending_governance`,chat 出现固定治理提示,无 workspace / 小队。
- 一份 full + 其余 none 可激活;激活确认页提示「不纳入人工审批的文档激活后不可补配三职」。
- 负例:author/creator 不可审核或批准 full;reviewer 不可 run/submit full;none 无送审/审核/批准;创建者可对处于当前阶段的 none 触发生成。
- `POST /projects` 带 `initial_workflow_key` 仍 `planning`、空 `active_workflow_key`,目录仍挂上;旧切换 API 不能直切 active。
- 项目 143 设置页仍 frozen,不点终止。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host --ipc host`,`BASE_URL=http://127.0.0.1:8080` |
| 服务 | 开发环境 `:8080`;rebuild 后 `GET /api/v1/health` → `status=ok`,`env=dev`,`agent_backend=pi-agent`,`schema_version=33` |
| Agent | 真实 `pi-agent`(闲聊走对话后端;未激活编制走 202-blocked,不启小队) |
| 分支 / worktree | `fix/governance-action-level-authz` / `.worktrees/fix-governance-action-level-authz` |
| 合入 | 独立 merge worktree `/tmp/as-dev-wf409-merge` 对本地 `dev` `--no-ff`;编码 worktree **未**执行 `env-service.sh` |
| 脚本 | `web/e2e/governance-action-level-authz.spec.ts`(`RUN_UI_ACCEPTANCE=1`);API 旁证 `assets/.../g5_api_matrix.py` |
| 末次页面矩阵 | **1 passed / 12.9s**(用例墙钟 12.3s) |
| 本轮页面项目 | `GOVAUTH-mu0z*`(管理员新建立项 + 两名协作者;口令不入库) |
| API 旁证项目 | `6209` planning keyed create;`6210` full+none 激活;`6211` 首阶段 none 生成 |
| 对照项目 | 143「对话协同会话」(只读) |
| 证据 | `.doc/test-reports/assets/2026-09-14-governance-action-level-authz/screenshots/` 与 `api-matrix.json` |
未在编码 worktree 内执行 `env-service.sh`。
### 用例矩阵
| ID | 输入 | 期望 |
|----|------|------|
| UI-01 | 零治理创建 | 顶栏可见新项目,可配置工作流 |
| UI-02 | 「今天天气如何,先闲聊一句。」 | 用户消息 + 助手回复,不走任务 run |
| UI-03 | 「请编制用户初始需求收集表」 | 202 blocked、固定治理提示、「待激活工作流」 |
| UI-04 | 首份 full + 其余关审批 → 预览 | 冻结提示「不可补配三职」后激活成功 |
| UI-05 | 打开非编制文档 | 无送审/审核/批准(none 隐藏审批条) |
| UI-06 | 打开 143 设置 | frozen + 「确认终止当前实例」可见但**未点击** |
| API-01 | `POST /projects` + `initial_workflow_key=main` | 201 `planning`,空 key;`PUT /active-workflow` 410 |
| API-02 | 未激活 `POST /tasks/runs` intake | 202 `blocked_pending_governance`,空 workspace |
| API-03 | 未激活 submit/review/approve | 403 `WORKFLOW_NOT_ACTIVATED` |
| API-04 | 激活一份 full + 其余 none | `lifecycle=active` |
| API-05 | 职责负例 + 创建者 run none | 403 `DOC_DUTY_FORBIDDEN`;none 生成 202 running(随即 cancel) |
| API-06 | `GET /projects/143/settings` | live instance,`can_edit_plan=false` |
页面编制话术使用「请编制用户初始需求收集表」:产品里「帮我生成立项文档」会走私密草稿捷径,不会 `POST /tasks/runs`。
## 四、 预期结果 (Expected Results)
未激活:view/闲聊放行;run 建 blocked run 并写固定文案;审批流动作 4xx。激活后 full 只认对应职责,创建者不再越权;none 无审批按钮;当前阶段 none 允许创建者 run。创建带 key 不升 active。项目 143 保持运行中冻结。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### UI-01 零治理创建
- **测试输入 (Input)**:管理员开通两名协作者后立项 `GOVAUTH-mu0z*`。
- **实际输出 (Actual Output)**:顶栏「当前项目」为新项目;侧栏出现该会话。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `01-zero-gov-created.png`。
### UI-02 普通对话
- **测试输入 (Input)**:`今天天气如何,先闲聊一句。`
- **实际输出 (Actual Output)**:用户气泡与助手闲聊回复可见;未出现治理拦截条。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `02-casual-chat.png`。
### UI-03 未激活编制 → 202 blocked
- **测试输入 (Input)**:`请编制用户初始需求收集表`
- **实际输出 (Actual Output)**:助手气泡为「当前项目尚未激活工作流,文档任务不会启动。请先在设置中配置并激活至少一份纳入人工审批的文档。」;状态「待激活工作流」。`POST /api/v1/tasks/runs` 捕获 202 + `blocked_pending_governance`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `03-blocked-generate.png`。
首轮页面跑曾因 `chk_task_run_status` 拒收新状态而 500 / `NETWORK_ERROR`。补 `00033` 后复测通过。
### UI-04 激活一份 full + 其余 none
- **测试输入 (Input)**:配置工作流:首份纳入审批并填三职,其余关闭;校验并预览 → 确认激活。
- **实际输出 (Actual Output)**:预览含「不纳入人工审批的文档激活后不可补配三职」;激活后顶栏「运行中」。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `04-activation-confirm.png`、`05-activated-full-none.png`。
### UI-05 按钮级职责门禁
- **测试输入 (Input)**:打开调研/法规等非编制文档。
- **实际输出 (Actual Output)**:无「提交送审」;截图见文档栏与动作条。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `06-duty-gated-actions.png`。
### UI-06 项目 143 只读
- **测试输入 (Input)**:侧栏打开「对话协同会话」→「查看工作流设置」。
- **实际输出 (Actual Output)**:「当前工作流已冻结,只读查看」;「确认终止当前实例」可见,**未点击**。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `07-project-143-readonly.png`。
### API-01 创建不再直通 active
- **测试输入 (Input)**:`POST /api/v1/projects` `{"name":"GOVAUTH-API-KEYED-*","initial_workflow_key":"main"}`;再 `PUT /active-workflow`。
- **实际输出 (Actual Output)**:201,`id=6209`,`lifecycle=planning`,`active_workflow_key=""`,workflows HTTP 200;切换 410 `WORKFLOW_SWITCH_API_RETIRED`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:26ms。
### API-02 / API-03 未激活 run / 审批
- **测试输入 (Input)**:对 6209 发 intake run;对 `doc_proj6209_intake` 发 submit/review/approve。
- **实际输出 (Actual Output)**:run 202 `run_1789375353946456022` / `blocked_pending_governance`;GET 无 workspace。库:`status=blocked_pending_governance`,`workspace_id` 空。审批三接口 403 `WORKFLOW_NOT_ACTIVATED`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:run 13ms。
### API-04 / API-05 激活与职责负例
- **测试输入 (Input)**:6210 激活 intake=full、其余 none;审核人 run/submit;创建者 review/approve;再对 6211(intake=none + 后续 full)由创建者 run intake。
- **实际输出 (Actual Output)**:6210 `lifecycle=active`。审核人/创建者审批 403 `DOC_DUTY_FORBIDDEN`。后期 none 的 submit 403 `DOC_TASK_NOT_IN_ACTIVE_STAGE`(当前 `V0.1_triage`)。6211 创建者 run none → 202 `running`(随即 cancel,避免长 PI)。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:激活 461ms;负例合计 43ms。
### API-06 项目 143
- **测试输入 (Input)**:`GET /api/v1/projects/143/settings`
- **实际输出 (Actual Output)**:`lifecycle=active`,`has_live_instance=true`,`can_edit_plan=false`。未调用终止。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:7ms。
## 六、 自动化测试套件汇总 (Test Suite Execution)
在 feature worktree(合入前):
```text
go vet ./...
go test -short ./...
go test -short -race ./internal/projectinstance ./internal/projectworkflow ./internal/server
cd web && npm test && npm run build
```
G5 复测(rebuild 后,2026-09-14):
```text
$ curl -sf http://127.0.0.1:8080/api/v1/health
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":33,"schema_ready":true,"task_store_ready":true}
$ go test -short -count=1 -timeout 180s ./internal/projectinstance ./internal/projectworkflow ./internal/server
ok chat-agent-system/internal/projectinstance 0.003s
ok chat-agent-system/internal/projectworkflow 0.002s
ok chat-agent-system/internal/server 9.957s
$ npx playwright test e2e/governance-action-level-authz.spec.ts --project=chromium
✓ 1 [chromium] › e2e/governance-action-level-authz.spec.ts:57:3 › governance action-level authz › real page matrix G5 (12.3s)
1 passed (12.9s)
$ python3 g5_api_matrix.py
wrote .../api-matrix.json verdict=PASS cases=6
```
通过率:页面 1/1;API 6/6;上述 Go 包 short 全绿。未用 stub 输出充当验收。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
**结论**:G1–G5 达到合入标准。动作级职责已落地;未激活编制保持 202 且不启小队;创建带 key 不再直通 active;项目 143 只读回归通过。
**后续(不阻塞本任务)**:
- 不把 Wave 5 未跑的「none 文档真实 PI 审批长链路」算进本报告。
- 规划话术「帮我生成立项文档」仍走私密草稿捷径;若产品要它走 intake,需另开 templateMatch 任务。
- `GET /tasks/runs/{id}` 响应仍是 Go 导出字段 PascalCase,前端创建接口用 snake_case;建议后续统一 JSON tag。
- 83 条 planning+残留 key 夹具只审计、未改库。
@@ -0,0 +1,150 @@
# workflow-plan 409 冻结态 + 可选职责 测试报告
## 一、 测试背景 (Background)
已激活项目(现场样本:项目 143 / 侧栏「对话协同会话」)对 `PUT /workflow-plan` 正确返回 409 `PLAN_FROZEN`,但设置页仍渲染职责下拉与「校验并预览」,错误落在长表单视口外,表现为「点击无反应」。同时规划校验把「三职全空」一律当成非法,无法表达「启用文档但不纳入人工审批」。
本轮按整改方案 Wave 1–4 落地 typed error、frozen 只读页、`DutyMode`、门禁/权限/快照/预览统计与逐文档开关;Wave 5 在真实 `pi-agent` 开发栈上做页面矩阵验收。项目 143 **只打开设置页做只读回归,未终止、未改规划**。
## 二、 测试目标 (Test Objectives)
- 项目 143 打开即 frozen:无编辑控件、无 workflow-plan PUT、不点终止。
- 新项目 A:一份纳入人工审批 + 其余不纳入 → 保存、预览、激活成功;激活后再打开为 frozen。
- 新项目 B:只填编制 → 内联/sticky 拒绝「不能只指派部分职责」,**不发出** PUT。
- 新项目 C:全部不纳入 → 预览拒绝「至少一份文档必须纳入人工审批」。
- 双标签:C 在另一页激活后,原标签陈旧草稿保存见冻结文案,草稿策略按 Wave 1 保留本地 plan。
- 非创建者成员打开 A:无「配置工作流」。
- 刷新后项目 143 仍 frozen。
- 质量门禁:相关 Go 短测与 `web` 单测全过。
明确未宣称:本轮 **未** 用真实小队把 full 文档走完审批、也 **未** 对 none 文档做生成 + 版本账本 + 阶段不阻塞的长链路 PI 实测;该项留作后续,不以 stub 或 API 旁证冒充。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host`,`BASE_URL=http://127.0.0.1:8080` |
| 服务 | 开发环境 `:8080`;`GET /api/v1/health` → `status=ok`,`env=dev`,`agent_backend=pi-agent`,`schema_version=32` |
| Agent | 真实 `pi-agent`(本轮页面矩阵未再触发长文档生成) |
| 分支 / worktree | `fix/workflow-plan-409-frozen-and-optional-duties` / `.worktrees/fix-workflow-plan-409-frozen-and-optional-duties` |
| 脚本 | `web/e2e/workflow-plan-409-frozen-duties.spec.ts`,`RUN_UI_ACCEPTANCE=1` |
| 末次页面矩阵 | **1 passed / 11.4s**(用例墙钟 10.7s) |
| 本轮项目(仅用户名/标题,无口令) | `WP409-A-mu0x38jh` / `WP409-B-mu0x38jh` / `WP409-C-mu0x38jh`;成员 `wpb_*` / `wpc_*` |
| 对照项目 | 143「对话协同会话」(只读) |
| 证据 | `.doc/test-reports/assets/2026-09-14-workflow-plan-409-frozen-and-optional-duties/screenshots/` |
未在 worktree 内执行 `env-service.sh`。合入与 rebuild 在独立 `dev` worktree / 主仓 compose 完成,编码 worktree 只跑单测与 Playwright。
### 用例矩阵
| ID | 输入 | 期望 |
|----|------|------|
| UI-01 | 打开 143 设置 | frozen 说明 + 无下拉/预览/激活;无 PUT `/143/` |
| UI-02 | A:首份开审批并填三职,其余关审批 | 预览可见不纳入统计,确认激活后「运行中」 |
| UI-03 | 再开 A 设置 | frozen,无「纳入人工审批」/「校验并预览」 |
| UI-04 | B:开审批后只选编制 | sticky「不能只指派部分职责」,PUT 计数不增加 |
| UI-05 | C:全部关审批后预览 | sticky「至少一份文档必须纳入人工审批才能激活工作流」 |
| UI-06 | 另一标签激活 C,原标签再预览 | 见「工作流已激活,规划已冻结」并转 frozen 只读 |
| UI-07 | 成员 B 进 A | 无「配置工作流」 |
| UI-08 | 刷新后开 143 | 仍 frozen |
## 四、 预期结果 (Expected Results)
- 三个合法配置态:关闭文档 / 启用但不纳入人工审批 / 启用并纳入人工审批。
- partial、强制空职责、零治理激活、非在任成员由客户端和/或服务端拒绝。
- 已激活项目 `can_edit_plan=false` 或存在 live instance → 只读快照 + 独立受控终止区。
- 409 `PLAN_FROZEN`:保留本地草稿并 `fetchProjectSettings` 后切 frozen。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### UI-01 项目 143 只读冻结
- **测试输入 (Input)**:管理员登录,侧栏点「对话协同会话」,点「查看工作流设置」。
- **实际输出 (Actual Output)**:标题「当前工作流已冻结,只读查看」;工作流 `main` / 版本 v2 / 阶段 `V0.1-triage`;无「纳入人工审批」、无「校验并预览」、无「确认激活」;有受控终止区(文案含 pending documents / 将取消任务)。快照区显示「当前没有启用的文档任务。」(历史冻结 JSON 在本页未展开出文档行;**未改 143**)。监听未出现 `PUT` 含 `/143/`。
- **评价判定 (Evaluation / Verdict)**:**PASS**。未点击「确认终止当前实例」。
- **性能与耗时 (Duration & Latency)**:含在 10.7s 总矩阵内;截图 `01-project-143-frozen.png`。
### UI-02 / UI-03 新项目 A 一份 full + 其余 none
- **测试输入 (Input)**:立项 `WP409-A-mu0x38jh`,加入两名协作者;首份「用户初始需求收集表」勾选纳入人工审批,三职分别为系统管理员 / 王总监 / 测试工程师;其余文档开关关闭。
- **实际输出 (Actual Output)**:预览步出现「激活预览」且可见「不纳入」统计;确认后顶栏「商务对接流程 / 运行中」。再次打开设置为 frozen,无开关与预览按钮。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `02-project-a-full-none.png`、`03-project-a-activated.png`、`03b-project-a-frozen.png`。
### UI-04 新项目 B 部分职责
- **测试输入 (Input)**:立项 `WP409-B-mu0x38jh`;勾选首份纳入人工审批,只选编制「系统管理员」,点「校验并预览」。
- **实际输出 (Actual Output)**:文档下内联「文档「用户初始需求收集表」不能只指派部分职责」;底部 sticky 同文案;该步 `PUT /workflow-plan` 计数为 0。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `04-project-b-partial.png`。
### UI-05 新项目 C 零治理激活
- **测试输入 (Input)**:立项 `WP409-C-mu0x38jh`(含协作者);全部「纳入人工审批」关闭后点「校验并预览」。
- **实际输出 (Actual Output)**:sticky「至少一份文档必须纳入人工审批才能激活工作流」。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `05-project-c-no-governed.png`。
### UI-06 双标签 409 → frozen
- **测试输入 (Input)**:标签 2 登录后打开 C,将首份纳入审批并填满三职,预览并激活;标签 1 仍停在 C 的全空草稿上再点「校验并预览」。
- **实际输出 (Actual Output)**:标签 1 转为「当前工作流已冻结,只读查看」;sticky「工作流已激活,规划已冻结」;无编辑下拉。本地快照仍显示激活前全空三职(Wave 1:保留 draftPlan)。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `06-dual-tab-frozen.png`。
### UI-07 非创建者成员
- **测试输入 (Input)**:`协作者B-mu0x38jh` 首次改密后进入工作台,点开 `WP409-A-mu0x38jh`。
- **实际输出 (Actual Output)**:顶栏为「商务对接流程 / 运行中」,**没有**「配置工作流」按钮。成员侧栏仅见自己加入的项目。
- **评价判定 (Evaluation / Verdict)**:**PASS**(本步只断言配置入口;未再点审核/批准动作)。
- **性能与耗时 (Duration & Latency)**:截图 `07-member-no-settings.png`。
### UI-08 刷新后 143
- **测试输入 (Input)**:管理员页 `reload`,再开「对话协同会话」设置。
- **实际输出 (Actual Output)**:仍为「当前工作流已冻结,只读查看」。
- **评价判定 (Evaluation / Verdict)**:**PASS**(页面刷新;**未**再做 app 容器 restart)。
- **性能与耗时 (Duration & Latency)**:截图 `08-reload-frozen.png`。
### 未执行:真实生成 / 审批 / 阶段不阻塞
- **测试输入 (Input)**:无(本轮 Playwright 未发送编制任务、未走审核/批准、未推进阶段)。
- **实际输出 (Actual Output)**:无页面证据。
- **评价判定 (Evaluation / Verdict)**:**未测**。门禁/权限/none 不阻塞的契约由 Wave 3 单测覆盖,不能代替真实 PI 页面。
- **性能与耗时 (Duration & Latency)**:—
## 六、 自动化测试套件汇总 (Test Suite Execution)
在 feature worktree:
```text
go vet ./internal/projectinstance/... ./internal/server/... ./internal/workflow/runtime/...
go test -short ./...
# 全部包 ok / no test files,无 FAIL
cd web && npm test -- --run
# 361 passed + vitest 30 passed,fail 0
```
真实页面:
```text
npx playwright test e2e/workflow-plan-409-frozen-duties.spec.ts --project=chromium
# 1 passed (11.4s)
```
Playwright 原始 output/report 按 `.gitignore` 不入库(`playwright-output-*` / `playwright-report-*`);可复核截图已入库。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
**设置页与激活治理:达到合入标准(页面矩阵 PASS)。** 项目 143 只读回归通过且未被改写/终止。新项目证明了 full+none 激活、partial 不发 PUT、零治理拒绝、双标签转 frozen、成员无配置入口、刷新后 frozen。
**未达到计划中的「真实执行」全链路。** 后续应单独立项:在已激活的 A 上用真实小队生成首份 full 文档并走审批,生成一份 none 文档确认入账本且无审核/批准、不阻塞阶段;必要时再做一次 `dev` app restart 后的 frozen/快照一致性。
**观察(不修 143)**:143 frozen 快照区写「当前没有启用的文档任务」,与现场仍有受控文档并行存在。若要展示历史职责,需另开任务读冻结 JSON,禁止在本任务回写 143。
回链:
- short-term:[2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../archive/ops/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- FEATURE-MATRIX:工作流治理行
- gap-matrix:`WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES`
@@ -0,0 +1,103 @@
# M5/M6 U11–U12 组合根与传输门禁 测试报告
## 一、 测试背景 (Background)
权威停走门是 U10 报告最后一句 **停止扩面**([2026-09-15-chatlog-contextasm-u10-test-report.md](./2026-09-15-chatlog-contextasm-u10-test-report.md))。用户于 2026-09-15 明确授权「继续解耦到 U11、U12」,推翻该停止扩面。本轮按整改计划四个子切片落地组合根、文档通知闭包迁出、stageflow 用例、UserProjectContext CAS,以及 SSE 中性编码与已清零规则的 arch-check block。
## 二、 测试目标 (Test Objectives)
- U11a:`internal/app.Runtime` 是唯一 composition root;重复 Start 不重复注册 subscriber;Stop 后再 Start worker 仍在。
- U11b:文档 `OnOutbox` 从 `internal/server` 迁到 `internal/app/docnotify`;Bind 幂等。
- U11c:HTTP / CLI / coordinator 走同一 `stageflow.UseCase`。
- U11d:`ApplyContextUpdate` 版本 CAS,并发同版本恰好一个赢家。
- U12:SSE 只编码中性 frame;`import`/`event` 进入 `--mode block`;不改错误信封与 PI Runner 协议。
- 不碰 `intent`;不终止项目 143;不启用 `FAV_DEGRADED_READ`。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| 分支 | `feature/app-composition-u11-u12` → `--no-ff` 合入 `dev@bf59cce` |
| 本机合同测试 | `unset TEST_DATABASE_URL; go test -short ./internal/app ./internal/app/docnotify ./internal/app/stageflow ./internal/coordinator ./internal/stream/transport ./internal/archtest` |
| 架构门 | `./scripts/arch-check.sh --mode warn` 与 `--mode block` |
| 目标包 race | `go test -race -short` 上述包(不含全仓 race) |
| 全仓 short | `unset TEST_DATABASE_URL; go test -short -count=1 ./...` |
| 真实 PI / 浏览器 / rebuild | 主仓占槽后 `./scripts/env-service.sh dev rebuild`;`:8080` health/ready schema 38 |
| 证据 | `.doc/test-reports/assets/2026-09-15-app-composition-u11-u12/` |
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Start 幂等 | 连续两次 Start,`StartCount==1` 且 `SubscriberCount==1` |
| Restart | Stop 后再 Start,`StartCount==2` 且 subscriber 不加倍 |
| OnOutbox | 生产 `internal/server` 无 `OnOutbox =`;`docnotify.Bind` 第二次为 no-op |
| stageflow | HTTP 与 CLI 均调用 `stageflow.UseCase`,同一 stub 计数共享 |
| CAS | 两 goroutine 同 `ExpectedVersion` → 1 成功 / 1 `ErrStaleContext` |
| SSE | frame 含 `event:`/`data:`,不含 `retry:` |
| arch-check block | `import`/`event` 计数为 0;sql_write/path 既有例外仍允许 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 U11a composition root
- **测试输入**: `go test -short -count=1 ./internal/app -run TestStartStopRestartIdempotent -v`
- **实际输出**: `TestStartStopRestartIdempotent` PASS;`cmd/server` 改为 `app.New` + `Runtime.Start` + `server.NewFromRuntime`
- **评价判定**: **PASS**
- **性能与耗时**: 0.014s。日志:`assets/2026-09-15-app-composition-u11-u12/go-test-u11-packages.txt`
### 5.2 U11b 文档通知闭包
- **测试输入**: `go test -short -count=1 ./internal/app/docnotify -v`;`rg OnOutbox internal/server`
- **实际输出**: `TestBindOnce` / `TestHandleCandidateReady` / `TestHandleSkipsUnknownAndNoRecipient` PASS。生产 server 包无 `OnOutbox`。`event_consumers.outbox.notify` 属主改为 `app/docnotify`
- **评价判定**: **PASS**
- **性能与耗时**: 0.002s
### 5.3 U11c stageflow
- **测试输入**: `go test -short -count=1 ./internal/app/stageflow -v`
- **实际输出**: `TestUseCaseDelegates` PASS(HTTP/CLI 两个 UseCase 共享同一 stub,task=1 stage=1);`handlers` / `task_run_handlers` / `cmd/bizdev-cli` / coordinator `SetStageTaskRunner` 均走该用例
- **评价判定**: **PASS**
- **性能与耗时**: 0.004s
### 5.4 U11d ContextUpdate CAS
- **测试输入**: `go test -race -short -count=1 ./internal/coordinator -run TestContextUpdateConcurrentNoLostUpdate -v`
- **实际输出**: 两 goroutine 同版本写 blackboard:1 赢家、1 `ErrStaleContext`,`Version==2`。`-race` PASS(零值 `sync.Mutex`,无懒初始化竞态)
- **评价判定**: **PASS**
- **性能与耗时**: 约 1.0s(race)。日志:`assets/2026-09-15-app-composition-u11-u12/go-test-u11-packages-race.txt`
说明:`UserProjectContext` 字段仍导出供读取。跨模块写路径(server 会话组装、chatflow assembler、chat session、coordinator pending/card/blackboard)已改 `ApplyContextUpdate`。coordinator 内部仍有 `Project.CurrentStage` 等字段赋值(该包为上下文 owner)。
### 5.5 U12 SSE 与 arch-check
- **测试输入**: `go test -short ./internal/stream/transport`;`./scripts/arch-check.sh --mode warn`;`./scripts/arch-check.sh --mode block`
- **实际输出**: `TestWriteNeutralFrame` / `TestHeartbeat` PASS。warn 与 block 均为 `production gate passed`。CI 增加 `arch-check --mode block`。`block_kinds: [import, event]`。未到期 sql_write(5)/path(16) 例外保留
- **评价判定**: **PASS**(已清零规则 block;路径/SQL writer 基线例外未假装清零)
- **性能与耗时**: arch-check block 约 0.2s。日志:`arch-check-warn.txt`、`arch-check-block.txt`
### 5.6 真实 PI / 浏览器 / rebuild
- **测试输入**: 占 CURRENT 集成槽后 `git merge --no-ff feature/app-composition-u11-u12`;`go vet ./...`;`unset TEST_DATABASE_URL; go test -short -count=1 ./...`;`./scripts/arch-check.sh --mode block`;主仓 `./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/health` 与 `/ready`
- **实际输出**: merge `bf59cce`。vet / short / arch-check block 均 PASS。rebuild 后容器 Recreate。health 与 ready 均为 `status=ok`、`env=dev`、`agent_backend=pi-agent`、`schema_version=38`、`schema_ready=true`、`task_store_ready=true`。镜像 `sha256:a8e3e940f01111c4298c67947ae9f4cd6105f13cf58134672f4a87daa19e27ab`(`agent-dev-app:latest`,created=2026-09-15T05:52:24Z)
- **评价判定**: **PASS**
- **性能与耗时**: rebuild 约 22s(Go 层未命中 cache;web 层 cache)。证据:`assets/2026-09-15-app-composition-u11-u12/rebuild-health-ready.txt`
- 真实 PI 编制任务:本切片不改生成链路,未重跑。浏览器:未改 web 交互。
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `unset TEST_DATABASE_URL; go test -short -count=1 ./internal/app ./internal/app/docnotify ./internal/app/stageflow ./internal/coordinator ./internal/stream/transport ./internal/archtest` | PASS |
| `go test -race -short -count=1` 同上目标包(不含 archtest) | PASS |
| `./scripts/arch-check.sh --mode warn` | PASS |
| `./scripts/arch-check.sh --mode block` | PASS(import/event 已清零) |
| `unset TEST_DATABASE_URL; go test -short -count=1 ./...` | PASS(EXIT:0,`internal/server` 9.992s) |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
U11a–U11d 与 U12 已合入 `dev@bf59cce` 并完成主仓 rebuild。未清零的 server `workspaces/` / `output.md` 路径例外与 sql_write 基线仍按到期日保留,不把 `--mode block` 写成全规则清零。
**停止扩面**(整改计划 U1–U12 已落地;未到期 path/sql_write 例外不属于本单元删除范围)。
@@ -0,0 +1,68 @@
# D4 bizdev locator 移除测试报告
## 一、 测试背景 (Background)
`bizdev.Service` 对外暴露 8 个 locator getter(`Pool` / `DocGov` / `DocRevision` / `ContextManager` / `CAS` / `ProjectWorkflow` / `FreeformDoc` / `KB`),HTTP handler 与 CLI 在每次请求上穿过编排根取协作对象。D4 要求组合根一次性 `Snapshot`,由 Runtime/Server 持有端口,并原子删除 getter。
## 二、 测试目标 (Test Objectives)
- 生产代码不再调用上述 8 个 getter。
- `*bizdev.Service` 上不再存在这 8 个方法;`BizdevService` 接口同步去掉 locator。
- archtest 禁止把 getter 加回去。
- `go test -short ./...` 与 `arch-check --mode block` 全绿。
- 不切事件 live;不删 hook API。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | go1.27.1 linux/amd64 |
| 分支 | `fix/bizdev-locator-removal` |
| 层级 | 表征/短测 + arch-check |
| 项目 143 | 只读 |
## 四、 预期结果 (Expected Results)
| 用例 | 期望 |
|------|------|
| Snapshot + Assemble | Runtime 字段来自 `bizdev.Snapshot(svc)`,不再走 getter |
| Server 端口 | handlers 使用 `s.gov` / `s.ctxMgr` / `s.rev` 等 |
| 删除 getter | `func (s *Service) DocGov()` 等 8 个方法不存在 |
| archtest | `TestBizdevNoLocatorGetters` PASS |
| 短测 | `go test -short ./...` PASS |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 getter 门禁
- **测试输入 (Input)**:`go test -count=1 ./internal/archtest -run TestBizdevNoLocatorGetters`
- **实际输出 (Actual Output)**:`ok chat-agent-system/internal/archtest 0.120s`(含于 arch-check)
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:~0.12s
### 5.2 arch-check
- **测试输入 (Input)**:`./scripts/arch-check.sh --mode block`
- **实际输出 (Actual Output)**:`arch-check block: production gate passed`
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:~0.79s
### 5.3 短测全量
- **测试输入 (Input)**:`unset TEST_DATABASE_URL DATABASE_URL CONTEXT_DB_HOST CONTEXT_DSN ALLOW_IN_MEMORY; go vet ./... && go test -short -count=1 ./...`
- **实际输出 (Actual Output)**:`go vet` 无输出;各包 `ok`(server 9.926s,cli 2.007s,其余 <2s)
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:约 12.2s
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `go test -short -count=1 ./...` | PASS |
| `./scripts/arch-check.sh --mode block` | PASS |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
D4 **PASS**。8 个 locator getter 已删除;组合根持有端口。`internal/chat` 生产包仍 import bizdev 跑 `CreateAndStart`(D7b 剩余批次)。Track P 仍只立项。不切 shared consumer live。
@@ -0,0 +1,67 @@
# D7b chat 编排剩余批次测试报告
## 一、 测试背景 (Background)
D7b 首批只把 `app/chatflow` assembler 的阶段常量迁到 `maturity`。`internal/chat` 生产包仍通过 `ActionServices.Bizdev` 和 `bizdev.TaskRunRequest` 绑在编排根上。D4 已提供 Server 端口后,本批去掉 chat 生产对 bizdev 的 import。
## 二、 测试目标 (Test Objectives)
- `internal/chat` 生产代码不再 import `bizdev`。
- 任务续跑/重启走 `stageflow.TaskRunRequest` 别名;`CreateAndStart` 类型身份不变。
- 去掉 `ActionServices.Bizdev`;仅要求 `TaskRuns`。
- arch-check 收紧 chat allowlist(去掉 bizdev,加入 app/stageflow)。
- 既有 `TestExecuteAction_DocGovReviewApprove` 与 chat 表征仍过。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | go1.27.1 linux/amd64 |
| 分支 | `fix/chatflow-orchestration-boundary` |
| 层级 | 表征/短测 + arch-check |
| 项目 143 | 只读 |
## 四、 预期结果 (Expected Results)
| 用例 | 期望 |
|------|------|
| 生产 import | chat 无 bizdev |
| 审核动作 | `TestExecuteAction_DocGovReviewApprove` PASS |
| 短测 | `go test -short ./...` PASS |
| arch-check | block 通过 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 表征
- **测试输入 (Input)**:`go test -short -count=1 ./internal/chat ./internal/server ./internal/archtest ./internal/app/stageflow`
- **实际输出 (Actual Output)**:上述包全部 `ok`(server 9.950s)
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:约 11.6s
### 5.2 arch-check
- **测试输入 (Input)**:`./scripts/arch-check.sh --mode block`
- **实际输出 (Actual Output)**:`arch-check block: production gate passed`
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:~0.22s
### 5.3 短测全量
- **测试输入 (Input)**:`go test -short -count=1 ./...`
- **实际输出 (Actual Output)**:各包 `ok`(server 10.007s,cli 2.327s)
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:约 12.6s
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| chat/server/archtest/stageflow | PASS |
| `./scripts/arch-check.sh --mode block` | PASS |
| `go test -short -count=1 ./...` | PASS |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
D7b 剩余批次 **PASS**。chat 生产不再 import bizdev。测试仍可用 bizdev 构造夹具。taskrun 签名仍是 bizdev 类型别名,未机械复制字段。Track P 仍只立项;不切 shared consumer live。

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