Skip to content

Stage 2.3: the Project board view and who may act on it (owner vs member) #1710

Closed

Description

@Birfy

Written-by: Chief
Part of #1550, Stage 2 third slice. Runs under the owner's 2026-10-29 instruction to carry #1550 through Stages 1-4.

Why

Stage 2.1 gave a Project an identity (d5347032) and Stage 2.2 gave it one board read model (#1703, merged as 554d939e): a Project id now resolves to rows from Bot boards, group boards and workflow runs, each with a stable id. Nothing shows them yet, and nothing decides who may act on what.

What to build

  1. One Project board view that renders the rows of the read model: grouped by source (bot | group | workflow), showing column, assignee and the run/node when there is one. A row opens the task it comes from; the view never edits.
  2. Role-gated actions. The Project's owner sees the management affordances Stage 2 names (Project settings, bindings, members). A session that is not the owner sees the same board read-only — no create, no reassign, no settings. The refusal is decided on the host, never by hiding a button alone.
  3. No second board. The view reads the aggregate; it does not keep its own task rows, and a change made on a Bot or group board shows up on the Project board without a copy.

Acceptance

  • Tests in core/test/: the board renders rows from all three sources; a non-owner session gets a refusal from the host action, not just a hidden control; the row id equals the underlying task id.
  • A Project with nothing under it renders an empty state, not an error.
  • No second store and no new configuration key.
  • npm run verify green at the tip (TZ=UTC); core/client.js regenerated if core/src/client/ changed; the subsystem page updated or a valid Docs-not-needed: in both the branch commit and the PR body.
  • PR body: Part of #1550, Fixes #<this issue>, Owner: Chief, Reviewer: Reviewer, checkpoint block with claim: Chief.

Out of scope

The Maintainer console and the Member role as separate shipped roles (they stay planned, as docs/governance.md §7 says); the Project Assistant (Stage 2.5).

Activity

  1. Birfy commented on Oct 29, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Triage

    Label set: agent-ready (no previous state label to remove).

    Design conflict resolved. The owner approved the five-stage direction on 2026-10-29 (decisions/2026-10-29-stage-1-approved.md, #1550 comment 11:32Z), and Stage 2's own acceptance already states the rule: "Owner can reach members, Bots, resources and governance controls; non-owners cannot perform those operations." Whose look the Project is, and that non-owners may not act, is therefore settled. Stage 2.1 (#1691) landed ownerUserId on state.projects; Stage 2.2 (#1696, merged 554d939e) landed the read-only project-board aggregate. Actor identity and host refusal already exist: core/src/host/channel.js resolves actor from x-flybot-member-session, and core/src/host/tasks.js:199-215 is the precedent (requesterOf, mayAct, forbidden, fallback to the first member when no session exists). No new owner ruling is needed.

    Scope for the implementer:

    • View: new core/src/client/project-board.js, one pure projectBoardView({ project, rows, canManage }) — group rows by source (bot | group | workflow), each row shows column, assignee and runId/nodeId when present; the row id is the underlying task id and opening it opens that task; no rows → an empty state, never an error. It holds no task rows of its own (no second store, no new configuration key) and never edits, so a change on a Bot/group board shows up on the next read. Wire it into the existing settings/panes surface in core/src/client/index.js; regenerate core/client.js (npm run build in core/).
    • Host gate: take actor into projectEndpoint in core/src/host/store.js (same shape taskEndpoint already uses), resolve the owner as project.ownerUserId with the tasks.js fallback (a single-human install with no sessions is the owner), return the host-computed canManage from project-read, and refuse project-bind from a non-owner with bot/forbidden; a project-create by a signed-in actor stamps that actor as ownerUserId. Hiding the button is allowed; the refusal must be the host's. Reads (project-read, project-board) stay available to any signed-in actor.
    • Live defect this slice must fix: project-board is missing from TASK_ENDPOINTS in core/src/host/authz.js, so once member sessions exist the board is refused as Unknown endpoint project-board; add it beside the other project endpoints.
    • Out of this slice: settings/members screens that have no endpoint yet. The only Project write surfaces that exist are project-create and project-bind, and the gate covers them; the view offers no move/reassign to anyone, which is what items 1 and 3 ("the view never edits", "no second board") require.
    • Tests, red first: new core/test/project-board-view.test.js, bundled the way core/test/board-card.test.js bundles a client component — rows from all three sources, grouping, runId/nodeId, empty state, row id equals the underlying task id; extend core/test/projects.test.js — non-owner project-bind refused (bot/forbidden), owner accepted, project-read reports canManage true/false, and a signed-in actor may read project-board.

    Docs: docs/subsystems/core-host.md (gate, canManage, endpoint list) and docs/subsystems/core-client.md (the view), or a valid Docs-not-needed: in both the branch commit and the PR body.

    Risk: T3. core/src/host/channel.js and core/src/host/authz.js are T3 paths in .github/agent/risk-rules.json; store.js is T2 and the client is T1, highest wins. So the PR needs a PASS at the tip, green tests-ok at that tip, npm run verify with TZ=UTC, and the merge queue.

  2. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 29, 2026
  3. self-assigned this
    on Oct 29, 2026
  4. Birfy commented on Oct 29, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Claim 12f7

    Claimed #1710 — branch dev/1710-project-board. First step: the pure projectBoardView grouped over the read model #1703 shipped.

  5. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 29, 2026
  6. removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:uiWeb/desktop UI and copyenhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions