Compose system project membership implementation candidates
Why: Host-only project creation and domain membership must form one verified identity. Evidence: Tool-imported SELF receipts and independent Backend and Frontend replay attestations; composed acceptance and final CI remain in progress. Impact: Advance fixed component pins and record the authorized implementation and privacy boundaries without deployment or runtime changes. Refs: .task/feature-project-member-access.md; system-project-membership proposal r1
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# Project Membership Implementation Plan r1
|
||||
|
||||
> For agentic workers: use subagent-driven-development for independent module work and test-driven-development for each behavior. The root agent owns the domain identity service, integration, evidence, review and shipping.
|
||||
|
||||
**Goal:** Every member works in the same globally named project using private conversations and the project's authorized two trees and trace graph.
|
||||
|
||||
**Architecture:** RDM owns project identity, members and domain data. Backend exposes an optional lifecycle provider and actor-scoped host projection capabilities. A persistent one-to-one mapping connects the domain root to the existing host project; every public project mutation uses the provider when present.
|
||||
|
||||
**Tech Stack:** Go, existing SQLite/PostgreSQL stores, React/TypeScript/Vitest, existing Gitea CI.
|
||||
|
||||
**Spec:** ../feature-project-member-access.md r0.1; user approval on 2026-10-13 covers stages 1–9 continuously.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Do not deploy or modify the 8788 runtime database; do not remove worktrees.
|
||||
- Do not import Backend internal packages from RDM or edit the code inside RDM pins.
|
||||
- Stage 1–9 is authorized-continuous; source review, independent replay and exact HEAD CI remain required.
|
||||
- Existing conversations, uploads and ownership survive adoption and archive.
|
||||
- The name rule in this increment is trimmed exact names. No automatic Unicode/case merge or historical name reuse.
|
||||
- Use project-specific WorldFor; reject missing/unregistered domain roots.
|
||||
- Frontend consumes existing UI tokens and motion primitives; DESIGN.md applies.
|
||||
|
||||
## Frozen Interfaces
|
||||
|
||||
Backend adds the following optional extension interfaces and lifecycle callbacks:
|
||||
|
||||
```go
|
||||
type ProjectHost interface {
|
||||
Owner() string
|
||||
OwnedProjects() ([]core.Project, error)
|
||||
ProjectMetadata(projectID string) (core.Project, error)
|
||||
OwnedProject(projectID string) (core.Project, error)
|
||||
EnsureProject(projectID, name string) (core.Project, error)
|
||||
RenameOwnedProject(projectID, name string) (core.Project, error)
|
||||
ProjectNameAvailable(name, exceptID string) (bool, error)
|
||||
}
|
||||
type ProjectLifecycle struct {
|
||||
List func(context.Context, Host) ([]core.Project, error)
|
||||
Create func(context.Context, Host, string) (core.Project, error)
|
||||
Rename func(context.Context, Host, string, string) (core.Project, error)
|
||||
Archive func(context.Context, Host, string) error
|
||||
Work func(context.Context, string, core.ID) (bool, error)
|
||||
}
|
||||
type ProjectLifecycleRegistry interface {
|
||||
RegisterProjectLifecycle(ProjectLifecycle) error
|
||||
}
|
||||
```
|
||||
|
||||
Each callback's Host is actor-scoped. ProjectMetadata is owned-or-authorized metadata only; OwnedProject and host mutations remain owner-only. EnsureProject takes a deterministic host ID, creates or verifies the same owner/name, and protects global host-name admission transactionally; rename checks the same name namespace. A trusted callback error implementing `StatusCode() int` maps to its 400/403/404/409/503 status. Unregistered providers preserve existing base behavior.
|
||||
|
||||
RDM responses decorate project Settings with `rdm.projectId` and `rdm.state` (`ready`, `provisioning`, `failed`, `unbound`, `archived`, `closed`). These are service-provided metadata; they are not authorization credentials. Shared user metadata cannot grant project administration.
|
||||
|
||||
RDM command registration resolves any supplied host project ID through a ready map to a registered domain ID, checking trusted HostProjectID for consistency when available. Member commands never write an unregistered project ID. Legacy adoption is an explicit owner-authorized command with preview/apply, preserving the host ID.
|
||||
|
||||
## Review Focus
|
||||
|
||||
- A project can fail between domain reservation and host creation: retries reuse its identity and persisted state.
|
||||
- Two accounts can race for an invisible name: exactly one domain name reservation succeeds and no duplicate host projection is produced.
|
||||
- A member can be removed after a list was fetched: new work rechecks live membership; private history stays owned.
|
||||
- A user can supply another project's ID to a member/duty/upload command: binding and project ownership cannot be forged.
|
||||
- A published slice can point back to a private source: shared retrieval contains the slice, not unrestricted original content or private chat.
|
||||
|
||||
### Task 1: Backend project lifecycle and member private conversations
|
||||
|
||||
**Files:** new pkg/extension/projects.go; internal/app project slot/host capability file; internal/store host projection file/tests; internal/server project lifecycle file/tests; extension surface.txt/version; existing app wiring and project/conversation handlers.
|
||||
|
||||
**Produces:** Frozen interfaces; Server provider delegation; shared member creation/listing and /new via one helper; work guard on chat/execution entry points; owned-only conversation detail remains private.
|
||||
|
||||
- [x] Write real store/HTTP/registration tests first. Required assertions include member POST conversation=200, member GET project conversations contains only that member's IDs, nonmember=404, read-only provider doesn't authorize writes, provider create/rename/delete called, archive preserves conversations, and two-owner name admission yields one success.
|
||||
- [x] Run `go test ./internal/store ./internal/server ./internal/app ./pkg/extension` and observe missing capability/behavior failures before implementation.
|
||||
- [x] Implement the optional registration, actor-scoped projection host, slot wiring, public API delegation, conflict/error mapping and private conversation helper.
|
||||
- [x] Test with real SQLite and the existing PostgreSQL harness, then run the Backend suite. Preserve red/green receipts.
|
||||
- [x] Commit only Backend-owned files with Why/Evidence/Impact/Refs.
|
||||
|
||||
### Task 2: RDM system project provisioning, canonical IDs and adoption
|
||||
|
||||
**Files:** internal/projects provisioning methods/tests; new internal/rdmapp/system_projects.go/tests; existing project/member guards and plugin command registration; new plugins/rdm system-project handlers/tests; docs/design project sharing contract.
|
||||
|
||||
**Consumes:** Task 1 Frozen Interfaces; current project/member stores and WorldFor.
|
||||
**Produces:** Registered provider, transactional domain project+creator+mapping state, ready work authorization, canonical command project IDs and explicit preview/apply adoption.
|
||||
|
||||
- [x] Test an authenticated project create → creator membership → bound host ID; same-name conflict across actors; partial host failure and same identity retry; member add using host ID; wrong host binding refusal; orphan member refusal even for administrator; adoption preview changes nothing, apply preserves ID/ownership and existing rows, second apply idempotent.
|
||||
- [x] Run `go test ./internal/projects ./internal/rdmapp ./plugins/rdm` and observe the expected failures.
|
||||
- [x] Reserve project/member/binding in one domain transaction. Use persistent provisioning/failed state around host projection; do not hold a domain DB transaction across host calls. Never infer identity from names or the first project.
|
||||
- [x] Resolve IDs once at the command boundary. Verify domain existence and trusted host context; require ready and live member/role/state for project work.
|
||||
- [x] Route domain and generic lifecycle commands through the same service; archive rather than delete; preserve historical name reservations.
|
||||
- [x] Add explicit adoption preview/apply and documentation. Run all RDM tests and commit the domain change after the new Backend surface is available for isolated composition testing.
|
||||
|
||||
### Task 3: RDM private resources and shared published knowledge
|
||||
|
||||
**Files:** new internal/rdmapp/project_resource_authz.go/tests; ingestion/publication metadata where required; plugins/rdm resource registration delegates to the new authorizer (root owns the registration edit).
|
||||
|
||||
**Consumes:** ResourceAuthzQuery existing public contract, RDM project bindings/members, WorldFor and publication metadata.
|
||||
**Produces:** `func (rt *Runtime) AuthorizeProjectResourceQuery(q extension.ResourceAuthzQuery) (bool, error)` and correct project identity stamping on published knowledge.
|
||||
|
||||
- [x] Test private artifact/attachment denied to another project member while owned reads remain possible; project structural streams allowed to members; only published RDM slices available cross-owner; other-project/nonmember/private-source queries denied; errors and missing metadata fail closed.
|
||||
- [x] Run the focused RDM tests and observe failures before implementation.
|
||||
- [x] Implement actor/resource/action checks using existing source publication/duty data; do not equate member membership with arbitrary content permission. Preserve document duty/state rules.
|
||||
- [x] Ensure ingest publication stamps the same domain project ID that its World uses; do not emit private originals or draft content into shared knowledge indexes.
|
||||
- [x] Test real stores, supported commands and two-project isolation; commit only owned files.
|
||||
|
||||
### Task 4: Frontend project metadata and failure behavior
|
||||
|
||||
**Files:** src/store.ts, src/api.ts, src/rdmManagement.ts, relevant project/sidebar components and tests.
|
||||
|
||||
**Consumes:** Existing project API with the service-produced `rdm.projectId`/`rdm.state` settings keys.
|
||||
**Produces:** Member setting/duty commands use the canonical domain ID; work creation respects non-ready/archived states; failed mutations give an actionable message; account changes clear prior identity's project/session state.
|
||||
|
||||
- [x] Test member/duty payload uses canonical domain ID from metadata; unbound project does not produce a fabricated domain ID; no default-name fallback bypasses a non-ready selected project; rejected delete/rename does not report success; stale responses after login change cannot populate another user's list.
|
||||
- [x] Run `npm test` to observe relevant failures.
|
||||
- [x] Reuse the existing sidebar/settings UI and token styles; add no additional management screen. Use plain user-facing errors and existing toast/empty states.
|
||||
- [x] Run Frontend tests/build and commit only Frontend-owned files.
|
||||
|
||||
### Task 5: Composition, browser acceptance and delivery
|
||||
|
||||
**Files:** Dev task card and component gitlinks, Documents extension request/current plan status, RDM consumer pins by approved compatibility path, isolated combination scenario/browser script.
|
||||
|
||||
- [ ] Build a fixed Backend/Frontend/RDM composition in isolated temporary data. Use real authentication and command dispatch; create projects through the user endpoint rather than seeding ready bindings.
|
||||
- [ ] Replay three users/two projects: globally duplicate name rejected, member visible project, member private conversation creation/list, private originals/drafts denied, published slice shared, other project isolated, refresh/restart/revocation behavior.
|
||||
- [ ] Synchronize relevant origin/main, resolve conflicts within the approved design, then run Dev `make test`/`make build` and the complete RDM suite with evidence against exact objects.
|
||||
- [ ] Independent reviewer replays minimum checks before consuming author evidence. Fix findings and repeat affected checks.
|
||||
- [ ] Push task branches, create/attach PRs, verify current HEAD CI and platform admission, merge components in dependency order, verify resulting contents/pins, and close this task's cards within the authorized delivery scope. Preserve worktrees; do not deploy.
|
||||
|
||||
## Progress Ledger
|
||||
|
||||
Tasks 1–4 implementation and author verification are saved; Task 5 combination, final independent review and CI/merge are in progress. Root owns authoritative receipts and integration commits; each worker's scope is a different repository or exclusive file set. No worker may deploy, touch live data, create releases, merge, clean worktrees or independently widen the shared API.
|
||||
|
||||
Ruling: use trimmed exact names for this increment; case/Unicode policy changes are excluded to avoid ambiguous existing-data merges.
|
||||
Ruling: parallel module implementation uses frozen interfaces, with one independent task review and an independent whole-composition review before shipping.
|
||||
Ruling: existing legacy post-merge auto-close behavior in RDM produced feature/card-close-20261013-080221Z while syncing main; preserve this unrelated branch, do not merge or delete it as part of this task.
|
||||
|
||||
Final refinements: ResourceAuthzQuery.Source carries the actual stored provenance; retrieval maps trusted host metadata to the domain ID and applies TopK after resource authorization. Private history/body/export/upload/count adapters enforce live duties and actor ownership. Ready legacy bindings additionally prove the physical host owner. Generic project PATCH checks managed settings before any mutation, and shared metadata uses detached credential masks. These correct concrete regression and review findings within the approved boundaries.
|
||||
File diff suppressed because one or more lines are too long
@@ -63,3 +63,5 @@ U2 起实施与部署分别评审。
|
||||
发布消费方须从固定 Dev 提交递归物化后运行 `make build`,再核验制品与实际运行状态。
|
||||
|
||||
- [渐进工作台界面重设计 r0.2](modules/documents/docs/proposals/2026-10-12-work-companion-ui-design.md):用户已授权连续实施;[计划 r1](modules/documents/docs/proposals/2026-10-12-work-companion-ui-plan.md)覆盖任务摘要、对话/输入、窄屏和真实状态投影;进展见对应任务卡。
|
||||
|
||||
- [系统项目、成员工作入口与私域协作闭环 r1](modules/documents/docs/proposals/2026-10-13-system-project-membership.md):2026-10-13 用户批准阶段 1–9 连续推进;统一全局项目身份与名称、成员个人会话、每项目两树一网和私域权限;当前组合验证/CI/tag 消费推进中,部署与线上修复未授权。
|
||||
|
||||
+1
-1
Submodule modules/backend updated: cfb8308895...c4435d1415
+1
-1
Submodule modules/core updated: 0f94e4b062...5773e74086
+1
-1
Submodule modules/documents updated: a73c84b5be...61e0aef39c
+1
-1
Submodule modules/frontend updated: 44b964682c...07a03ac4f6
Reference in New Issue
Block a user