Operator edits on another org's row: say
## Defect
Since #5694 (PR #4967), an operator's GET binds the whole fleet, so under "All orgs" they see every org's tasks, projects and credentials (epic #5680, "Operator can see everything"). Mutations still bind the operator's own org: `apps/api/app/authz.py:2230-2231`, "A mutation stays on the operator's own org". Editing another org's row therefore fails only after submit, and a create-form picker that offers another org's row fails the same way. #5694's report records this as an unfiled follow-up ("Editing such a row, or choosing one in a create-form picker, fails on submit"). The epic introduced it, because before #5694 those rows were not visible at all.
## Decision taken (finish #5700, Full Auto)
The operator does NOT gain cross-org write power. PRD R5.7 says "the filter … never grants or removes any power", and the interview chose a view filter over act-as-org. The fix makes the read-only state honest instead.
## Fix
1. Server: when an operator mutates a by-id row that exists in another org, return 403 with `{"reason": "other_org", "org": "<name>"}` instead of a 404. Do this once, in the authz mutation path, not per route. The message reads: "This belongs to <org>. Operators can view other orgs' rows but not edit them; use Change org… to move it."
2. Web: show that message in the shared mutation error handling.
3. Web: on Task detail and Project detail, when the row's org is not the operator's own org, disable the edit, state-change, comment and delete controls, with a one-line reason naming the org. Create-form pickers (project, credential) list only the operator's own org's rows.
## Done means
- An API test: an operator PATCH/DELETE on another org's task, project and credential returns 403 `other_org` naming the org, and no row changes. An operator mutation on an own-org row is unchanged. Non-operators still get 404 for another org's row (no existence leak).
- Component tests: Task detail and Project detail for another org's row show the controls disabled with the reason. Pickers list own-org rows only.
- Dev browser check as operator under All orgs: open a Gmind task while the operator's own org is Operator. The controls are disabled with the reason, and a forced submit shows the 403 message.
- `./dc check full` is green, the PR is merged, and its Jaah Deploy succeeded.
Out of scope: do NOT add operator cross-org writes, impersonation or act-as-org. Do NOT change read narrowing or the org filter. Do NOT touch the transfer routes (they are Tenancy.OPERATOR and already work).
Outcome
Operator writes on another org's task/project/credential now get 403 other_org naming the org; detail pages lock with a reason; pickers own-org only. PR #5018 merged, Jaah Deploy OK. Full gate red only on unrelated jaahd tests (#5017). Follow-ups in report.
Artifacts
Activity
- Ready
- Runner started
- Runner ended (done)