# ADR 0030: Project Grants Are Always Live; The Independent-Permission Toggle Is Removed ## Status Accepted. Supersedes the file-library contract rule **D11 / P5** (《文件库-接口契约.md》, since deleted; recoverable from git history) which introduced the per-project "独立权限" (independent permission) switch. ## Context D11 gave each PROJECT a toggle (`FileLibProjectSettings.independentPermissionsEnabled`, default off). While off, project-level non-creator grants were **frozen** — present in `FileLibGrant` but excluded from `effectiveRole`; ancestor-chain grants and the creator's auto-grant were unaffected. The intent was to support two workflows: "project follows the folder's ACL" (off) vs "project has its own ACL" (on). In practice the toggle surprised operators twice: grants appeared to "not work" until someone found and flipped a per-project switch buried in the 概览 tab, and the frozen state was indistinguishable from missing grants in the UI. The product decision is that project-level grants should simply always be live. ## Decision - **Project-level grants always participate in `effectiveRole`.** The freeze branch in `hub/src/database/filelib/permission.ts` is deleted; `EffectiveRoleInput` no longer carries `independentPermissionsEnabled`. - **The toggle surface is removed end-to-end**: `PUT /database/api/projects/:id/independent-permission`, `grantService.setIndependentPermission`, the `independentPermission` field in the node detail DTO, and the 概览 tab switch in `filelib-web`. - **`FileLibProjectSettings` becomes vestigial.** The table stays (existing rows are ignored, no data migration); new projects no longer get a default row. It may be dropped in a future migration once nothing references it. - Audit action vocabulary `independent_enable` / `independent_disable` is retained for reading historical audit entries; no new entries are produced. Behavior change for existing deployments: projects whose toggle was off now have their project-level grants effective immediately — this is the intended effect of the decision. ## Consequences - Permission semantics shrink to the single P6 rule: `effective = max(grants on self ∪ ancestors for user ∪ resolved groups)`, no exceptions by node kind. - One less state dimension in tests and in the admin UI.