fix: always enable SSE auto-refresh on kanban page
Previously SSE was only enabled in single project mode (allowMutations). Now auto-refresh works in all modes including aggregate.
This commit is contained in:
parent
ad7a7b9b00
commit
4f8f3006e9
7 changed files with 209 additions and 28 deletions
|
|
@ -83,7 +83,14 @@
|
|||
{"id":"bb-bvn.3","title":"Add blocked-chain highlighting and cycle anomaly signaling","description":"Add analysis overlays for blocker triage and anomaly visibility.\n\nScope:\n- Compute and highlight blocked chains from selected node.\n- Show concise blocker summary:\n - open blocker count\n - in-progress blocker count\n - first actionable blocker\n- Cycle/anomaly signaling:\n - detect cycles in dependency graph\n - mark involved nodes/edges with warning style and explanation text\n\nUI behavior:\n- \"Show blocking path only\" toggle to reduce noise.\n- Hovering a node/edge highlights direct dependency chain.\n- Keep styling subtle and readable; avoid visual overload.\n\nRules:\n- Analysis is read-only and derived from current graph model.\n- Must not fail hard on malformed dependency data; degrade with warnings.\n\nTest plan:\n- Unit tests for blocked-chain derivation and cycle detection logic.\n- UI tests for toggle behavior and warning visibility.\n- Screenshot verification for normal and anomaly cases.\r\n","acceptance_criteria":"- Selected issue can display clear blocked-chain context.\n- Cycle/anomaly conditions are detected and visibly flagged.\n- Blocking-path-only mode materially reduces graph noise.\n- Analysis features remain performant and do not break base graph rendering.\n- Tests and screenshots verify normal + anomaly paths.\r\n","notes":"Addressed review P1 in detectDependencyCycles: removed early-return DFS behavior that leaked recStack/path state; traversal now always unwinds and collects cycles without contaminating predecessor nodes. Added regression test in tests/lib/graph-view.test.ts: detectDependencyCycles does not mark non-cycle predecessor as cyclic. Verification: node --import tsx --test tests/lib/graph-view.test.ts (pass), npm run typecheck (pass), npm run test (pass).","status":"closed","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:11.687878-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T18:57:24.8694169-08:00","closed_at":"2026-02-12T18:57:24.8694169-08:00","close_reason":"Implemented blocked-chain analysis, blocking-path emphasis, and cycle anomaly signaling with regression coverage; tests/typecheck are green.","labels":["analysis","graph"],"dependencies":[{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T17:12:11.6890831-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn.2","type":"blocks","created_at":"2026-02-11T17:12:37.378326-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn.4","type":"blocks","created_at":"2026-02-11T20:10:03.6326727-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-bvn.4","title":"Epic Design Gate: scope, decisions, and acceptance contract","description":"Design/discovery gate for bb-bvn before further implementation.\n\nMust capture:\n- Product intent and user outcomes for this epic\n- Explicit architecture decisions and tradeoffs\n- API/data contracts and edge cases\n- Windows-specific constraints and path/process assumptions\n- Test strategy and verification commands\n- Non-goals and out-of-scope boundaries\n\nCompletion rule:\nDo not start new implementation tasks in this epic until this gate is closed with agreed decisions.","acceptance_criteria":"A written execution-grade plan exists for this epic and all child task descriptions are updated with concrete implementation details, dependencies, and testable acceptance criteria.","notes":"Graph design gate completed: agreed React Flow deterministic UX, default 2-hop depth controls, mobile simplified fallback, typed edge semantics, and verification contract (tests + screenshots + smoke). Child tasks bb-bvn.1/.2/.3 updated with execution-grade details.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T20:09:40.290642-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T20:59:12.4823711-08:00","closed_at":"2026-02-11T20:59:12.4823711-08:00","close_reason":"Design gate complete: bb-bvn child tasks now contain concrete scope, contracts, dependencies, and testable acceptance criteria.","dependencies":[{"issue_id":"bb-bvn.4","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T20:09:40.2922349-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv","title":"Agent Communication \u0026 Coordination Patterns","description":"Agents need a standardized way to coordinate (handoffs, help requests, blockers) without breaking flow. We are opting for a **Issue-Centric** communication model (using Comments) rather than an Inbox-Centric model. This epic defines the protocols, patterns, and tool support needed to make that robust.\n\nGoals:\n- Define 'Protocol' for agent-to-agent comments (prefixes, structure).\n- Establish Identity standards (how agents refer to themselves).\n- Ensure CLI support for all protocol actions (commenting, signaling).\n\nDeliverables:\n- RFC-001: Agent Coordination Protocol.\n- Skill: beadboard-driver (teaching the protocol).\n\nThis epic blocks bb-u6f (Agent Sessions) because session attribution relies on the Identity standards defined here.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:35:07.1826787-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:36:56.4424829-08:00"}
|
||||
{"id":"bb-dcv.1","title":"Research \u0026 RFC: Agent Skills and Handoff Protocols","description":"Conduct research and draft a 'Request for Comments' (RFC) document that defines the standard operating procedures for agent-to-agent interaction within Beadboard.\n\nKey Questions to Answer:\n1. Identity: How do we consistently identify an agent? (e.g. assignee formats).\n2. Handoff Protocol: Structure of a handoff comment (e.g. [HANDOFF]).\n3. Blocker Signaling: How to raise a flag (e.g. [BLOCKED]).\n4. Parsing: Can/should we have bd parse-comments?\n\nDeliverables:\n- docs/RFC-001-Agent-Coordination.md: Finalized spec.\n- skills/beadboard-driver/SKILL.md (Draft): Prototype skill.\n- Gap Analysis: Missing CLI commands.\n\nAcceptance Criteria:\n- RFC document created and committed.\n- Protocol covers: Identity, Handoff, Blocker, Assignment.\n- Gap analysis lists required code changes.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:37:32.9086915-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:37:32.9086915-08:00","dependencies":[{"issue_id":"bb-dcv.1","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-12T21:37:32.9107758-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.1","title":"Research \u0026 RFC: Agent Skills and Handoff Protocols","description":"Conduct research and draft a 'Request for Comments' (RFC) document that defines the standard operating procedures for agent-to-agent interaction within Beadboard.\n\nKey Questions to Answer:\n1. Identity: How do we consistently identify an agent? (e.g. assignee formats).\n2. Handoff Protocol: Structure of a handoff comment (e.g. [HANDOFF]).\n3. Blocker Signaling: How to raise a flag (e.g. [BLOCKED]).\n4. Parsing: Can/should we have bd parse-comments?\n\nDeliverables:\n- docs/RFC-001-Agent-Coordination.md: Finalized spec.\n- skills/beadboard-driver/SKILL.md (Draft): Prototype skill.\n- Gap Analysis: Missing CLI commands.\n\nAcceptance Criteria:\n- RFC document created and committed.\n- Protocol covers: Identity, Handoff, Blocker, Assignment.\n- Gap analysis lists required code changes.","notes":"Drafted RFC and skill artifacts: docs/RFC-001-Agent-Coordination.md and skills/beadboard-driver/SKILL.md. Includes identity, handoff/blocker/assignment protocol and gap analysis for bb agent CLI.\nSkill deliverable moved to a dedicated later task so RFC scope remains protocol/spec + gap analysis only.","status":"in_progress","priority":1,"issue_type":"task","assignee":"zenchantlive","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:37:32.9086915-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T14:45:05.8683583-08:00","dependencies":[{"issue_id":"bb-dcv.1","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-12T21:37:32.9107758-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.2","title":"Define bb agent CLI contract and storage schema","description":"Write the thin-layer CLI contract for bb agent commands and the on-disk schema under .beadboard/agent. Include command I/O examples and validation rules. This is implementation input, not a refactor.","acceptance_criteria":"Spec includes: register/list/show, send/inbox/read/ack, reserve/release/status; JSON schema and file layout are documented; failure modes are defined.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:41.2806805-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:41.2806805-08:00","labels":["agents","cli","design"],"dependencies":[{"issue_id":"bb-dcv.2","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:41.2822506-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.2","depends_on_id":"bb-dcv.1","type":"blocks","created_at":"2026-02-13T12:57:08.7260185-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.3","title":"Final verification and readiness sweep for agent CLI","description":"Run full verification for the thin-layer agent CLI and publish evidence from tests/lint/typecheck plus dependency sanity.","acceptance_criteria":"typecheck/test/lint pass; dependency graph is acyclic and reflects plan; readiness summary posted.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:55.8190789-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:55.8190789-08:00","labels":["agents","qa","verification"],"dependencies":[{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:55.8211858-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv.5","type":"blocks","created_at":"2026-02-13T12:57:13.0099035-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv.8","type":"blocks","created_at":"2026-02-13T14:45:12.4489854-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.4","title":"Implement reservation commands with TTL","description":"Implement reserve/release/status commands for work surfaces with TTL expiry and stale ownership handling.","acceptance_criteria":"reserve/release/status work; expired reservations are surfaced/cleared; conflict scenarios are test-covered.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:56.3114764-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:56.3114764-08:00","labels":["agents","cli","reservations"],"dependencies":[{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:56.3130569-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:10.8788059-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv.7","type":"blocks","created_at":"2026-02-13T12:57:11.4135844-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.5","title":"Integrate bb agent UX with bd claim workflow","description":"Add CLI UX layer and docs so bb agent flows pair cleanly with bd update --claim, without direct JSONL writes.","acceptance_criteria":"Docs include canonical session flow; commands produce operator-friendly output; no direct JSONL writes introduced.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:56.7418732-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:56.7418732-08:00","labels":["agents","cli","workflow"],"dependencies":[{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:56.7434894-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv.6","type":"blocks","created_at":"2026-02-13T12:57:11.9292114-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv.4","type":"blocks","created_at":"2026-02-13T12:57:12.4685539-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.6","title":"Implement agent mail commands (send/inbox/read/ack)","description":"Implement file-backed message transport for registered agents with unread/read/acked states and bead-linked thread context.","acceptance_criteria":"send/inbox/read/ack commands work end-to-end; sender/recipient must be registered; message lifecycle is test-covered.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:57.2090515-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:57.2090515-08:00","labels":["agents","cli","mail"],"dependencies":[{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:57.210616-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:09.7811635-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv.7","type":"blocks","created_at":"2026-02-13T12:57:10.3349432-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.7","title":"Implement agent identity registry commands","description":"Implement bb agent register/list/show with unique-name enforcement and stable metadata files under .beadboard/agent/agents.","acceptance_criteria":"register/list/show commands work; duplicate names fail with clear error; tests cover happy/error paths.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:57.6944409-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:57.6944409-08:00","labels":["agents","cli","identity"],"dependencies":[{"issue_id":"bb-dcv.7","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:57.6961264-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.7","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:09.2534901-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-dcv.8","title":"Create beadboard-driver skill from implemented bb agent workflows","description":"Use skill-creator workflow to produce the beadboard-driver skill only after bb agent identity, mail, reservation, and workflow commands are implemented and verified.","acceptance_criteria":"SKILL.md matches implemented CLI behavior; trigger language is explicit; no speculative commands included; quick validation performed.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T14:45:05.4433258-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T14:45:05.4433258-08:00","labels":["agents","docs","skill"],"dependencies":[{"issue_id":"bb-dcv.8","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T14:45:05.4449006-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.8","depends_on_id":"bb-dcv.5","type":"blocks","created_at":"2026-02-13T14:45:11.9133726-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-n7p","title":"Swimlane status model: ready + dependency-derived blocked","notes":"Implemented new swimlane model: removed deferred lane from board usage; added ready lane and dependency-derived blocked lane. Lane rules: closed-\u003eDone; blocked-\u003eBlocked if explicit status blocked OR has active incoming blocker edge; in_progress/review-\u003eIn Progress; otherwise Ready. Added laneToMutationStatus to map board lane writes to bead statuses (ready-\u003eopen). Updated board labels/colors, drag-drop lane source tracking, and controls stat label Open-\u003eReady. TDD: updated tests/lib/kanban.test.ts for ready/blocked semantics. Verification: node --import tsx --test tests/lib/kanban.test.ts (pass), npm run typecheck (pass), npm run test (pass).","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T17:55:04.1851993-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T18:40:08.0620089-08:00","closed_at":"2026-02-12T18:40:08.0620089-08:00","close_reason":"Implemented ready/blocked swimlane model, blocked-tree deep links to lane focus, and verification passed (kanban tests, typecheck, full test suite).","labels":["kanban","status","swimlane"]}
|
||||
{"id":"bb-q1s","title":"UI Bead Editing Across Kanban + Graph","description":"Objective:\nAdd true UI editing for bead fields across both detail panels (Kanban + Graph) using one shared edit core so behavior stays consistent.\n\nWhy:\nWrite-back infrastructure exists, but users currently cannot edit bead content from UI detail panels.\n\nScope:\n- Shared edit validation + mutation adapter.\n- Reusable editor UI block for issue fields.\n- Integration into both Kanban and Graph detail panels.\n- Verification for responsive behavior and mutation safety.\n\nOut of scope:\n- Dependency relation editing.\n- AI content generation.\n- Bulk editing.","acceptance_criteria":"- Users can edit core bead fields from both Kanban and Graph detail panels.\n- Both surfaces use the same validation and update path.\n- Save/cancel/error states are consistent across both surfaces.\n- Typecheck/tests/guards pass and no direct JSONL writes are introduced.","notes":"Execution order enforced through child dependencies.\nExecution order: bb-q1s.1 shared core -\u003e bb-q1s.2 kanban + bb-q1s.3 graph (parallel) -\u003e bb-q1s.4 verification/polish.","status":"closed","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T20:50:12.3431904-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:11:43.1747329-08:00","closed_at":"2026-02-12T21:11:43.1747329-08:00","close_reason":"Shared UI bead editing shipped across Kanban and Graph with verification evidence.","labels":["editing","mutation","ui"]}
|
||||
{"id":"bb-q1s.1","title":"Shared edit core: schema + update adapter + state machine","description":"Build shared edit core used by both detail panels.\n\nIncludes:\n- editable field schema\n- validation rules\n- payload adapter for /api/beads/update\n- form state model: pristine/dirty/saving/error","acceptance_criteria":"- Shared edit core is framework-agnostic and reused by both UIs.\n- Validation covers title/priority/labels/assignee/owner/description.\n- Adapter emits stable update payload.","notes":"Implemented shared edit core in src/lib/issue-editor.ts with draft schema, validation, diff-to-update adapter, label parsing, and edit-state classifier. Added tests in tests/lib/issue-editor.test.ts and expanded mutation adapter to support issueType updates.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T20:50:31.668852-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:10:59.9315015-08:00","closed_at":"2026-02-12T21:10:59.9315015-08:00","close_reason":"Shared edit core delivered and validated via unit tests + typecheck.","labels":["editing","lib","shared"],"dependencies":[{"issue_id":"bb-q1s.1","depends_on_id":"bb-q1s","type":"parent-child","created_at":"2026-02-12T20:50:31.6709483-08:00","created_by":"zenchantlive"}]}
|
||||
|
|
|
|||
171
docs/RFC-001-Agent-Coordination.md
Normal file
171
docs/RFC-001-Agent-Coordination.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# RFC-001 Agent Coordination Protocol
|
||||
|
||||
Date: 2026-02-13
|
||||
Owner: `bb-dcv.1`
|
||||
Status: Draft
|
||||
Scope: Define a CLI-first, issue-linked protocol for multi-agent coordination in BeadBoard.
|
||||
|
||||
## 0) Reference Position
|
||||
|
||||
`mcp_agent_mail` is used as a pattern reference only (identity registration, inbox/ack workflow, reservations).
|
||||
We are not integrating MCP mail transport into BeadBoard for this phase.
|
||||
|
||||
Decision:
|
||||
1. Borrow concepts.
|
||||
2. Implement a local thin-layer `bb agent` CLI.
|
||||
3. Keep Beads as issue/dependency system of record.
|
||||
|
||||
## 1) Problem Statement
|
||||
|
||||
BeadBoard needs reliable agent-to-agent coordination that does not depend on chat context and does not mutate `.beads/issues.jsonl` directly. Today, ownership is partially covered by Beads (`bd update --claim`), but directed communication, acknowledgements, and short-lived work-surface reservations are not standardized.
|
||||
|
||||
This RFC defines:
|
||||
1. Agent identity conventions.
|
||||
2. Handoff/blocker/decision communication protocol.
|
||||
3. Assignment/claim expectations.
|
||||
4. The required thin-layer `bb agent` CLI capabilities.
|
||||
|
||||
## 2) Design Goals and Non-Goals
|
||||
|
||||
Goals:
|
||||
1. Keep Beads as source of truth for issue lifecycle and dependencies.
|
||||
2. Add durable coordination metadata with clear auditability.
|
||||
3. Require explicit bead linkage for coordination events.
|
||||
4. Support parallel work without accidental overlap.
|
||||
|
||||
Non-goals:
|
||||
1. Replacing Beads issue state with a new tracker.
|
||||
2. Direct writes to Beads JSONL outside `bd`.
|
||||
3. Introducing MCP requirements for core local workflows.
|
||||
|
||||
## 3) Identity Standard
|
||||
|
||||
Each automation participant uses a stable `agent_id` (example: `agent-ui-1`, `agent-graph-1`).
|
||||
|
||||
Rules:
|
||||
1. `agent_id` is globally unique within a repo.
|
||||
2. `agent_id` is immutable after registration.
|
||||
3. Operator identity and agent identity are both retained in logs.
|
||||
|
||||
Canonical fields:
|
||||
1. `agent_id`
|
||||
2. `display_name`
|
||||
3. `role` (`ui`, `graph`, `infra`, `qa`, etc.)
|
||||
4. `created_at`
|
||||
5. `last_seen_at`
|
||||
6. `status` (`idle`, `working`, `blocked`, `done`)
|
||||
|
||||
## 4) Assignment and Ownership Protocol
|
||||
|
||||
Ownership remains Beads-native:
|
||||
1. Claim issue with `bd update <id> --claim`.
|
||||
2. Move lifecycle through normal `bd` commands.
|
||||
3. Use Beads dependencies as execution truth.
|
||||
|
||||
Agent protocol requirements:
|
||||
1. Every coordination message includes `bead_id`.
|
||||
2. Any handoff sets a clear next owner or recipient.
|
||||
3. Any blocker message includes a requested action and urgency.
|
||||
|
||||
## 5) Communication Protocol
|
||||
|
||||
Message categories:
|
||||
1. `HANDOFF`: work transition with current state and next action.
|
||||
2. `BLOCKED`: hard blocker requiring external action.
|
||||
3. `DECISION`: decision record with rationale.
|
||||
4. `INFO`: non-blocking operational context.
|
||||
|
||||
Required message envelope:
|
||||
1. `message_id`
|
||||
2. `thread_id` (default `bead:<id>`)
|
||||
3. `bead_id`
|
||||
4. `from_agent`
|
||||
5. `to_agent` (or `broadcast`)
|
||||
6. `category`
|
||||
7. `subject`
|
||||
8. `body`
|
||||
9. `created_at`
|
||||
10. `state` (`unread`, `read`, `acked`)
|
||||
|
||||
Ack requirement:
|
||||
1. `BLOCKED` and `HANDOFF` messages require acknowledgement.
|
||||
2. `DECISION` and `INFO` acknowledgements are optional.
|
||||
|
||||
## 6) Reservation Protocol
|
||||
|
||||
Reservations are advisory by default with TTL:
|
||||
1. Reserve scope before edits on contested surfaces.
|
||||
2. Scope examples: `src/components/graph/*`, `kanban-surface`, `api/mutations`.
|
||||
3. Expired reservations are considered stale and available for takeover.
|
||||
|
||||
Required reservation fields:
|
||||
1. `reservation_id`
|
||||
2. `scope`
|
||||
3. `agent_id`
|
||||
4. `bead_id`
|
||||
5. `created_at`
|
||||
6. `expires_at`
|
||||
7. `state` (`active`, `released`, `expired`)
|
||||
|
||||
## 7) Gap Analysis (Current vs Required)
|
||||
|
||||
Available now:
|
||||
1. `bd update --claim` provides atomic issue claim.
|
||||
2. `bd` dependency graph provides blocked/ready sequencing.
|
||||
3. `bd agent state/heartbeat` can report liveness for agent beads.
|
||||
|
||||
Missing (must be added):
|
||||
1. Agent registration and identity registry commands.
|
||||
2. Directed message transport with unread/read/acked lifecycle.
|
||||
3. Reservation commands with TTL and stale handling.
|
||||
4. Unified status view tying claim + message + reservation state.
|
||||
|
||||
Command matrix:
|
||||
1. Have now: `bd update --claim`, `bd update`, `bd close`, `bd dep`, `bd comments`.
|
||||
2. Need build: `bb agent register/list/show`.
|
||||
3. Need build: `bb agent send/inbox/read/ack`.
|
||||
4. Need build: `bb agent reserve/release/status`.
|
||||
|
||||
Failure modes to handle:
|
||||
1. Duplicate `agent_id` registration.
|
||||
2. Unknown sender or recipient in send flow.
|
||||
3. Missing `bead_id` on required message categories.
|
||||
4. Reservation conflicts and stale-expiry takeover behavior.
|
||||
5. Ack on unknown or already terminal message state.
|
||||
|
||||
## 8) Required Thin-Layer CLI Surface
|
||||
|
||||
Proposed commands (`bb agent`):
|
||||
1. `register`, `list`, `show`
|
||||
2. `send`, `inbox`, `read`, `ack`
|
||||
3. `reserve`, `release`, `status`
|
||||
|
||||
Storage:
|
||||
1. `.beadboard/agent/agents/*.json`
|
||||
2. `.beadboard/agent/messages/*.jsonl`
|
||||
3. `.beadboard/agent/reservations/*.json`
|
||||
4. `.beadboard/agent/index/*.json` (optional fast lookup)
|
||||
|
||||
Safety rules:
|
||||
1. No direct writes to `.beads/issues.jsonl`.
|
||||
2. Bead lifecycle mutations remain via `bd`.
|
||||
3. All timestamps are UTC ISO-8601.
|
||||
|
||||
## 9) Acceptance Criteria Mapping
|
||||
|
||||
Identity covered: Section 3.
|
||||
Handoff covered: Sections 4 and 5 (`HANDOFF`).
|
||||
Blocker signaling covered: Sections 5 and 6 (`BLOCKED`, reservation escalation).
|
||||
Assignment covered: Section 4 (`bd --claim` as ownership source).
|
||||
Gap analysis covered: Section 7.
|
||||
|
||||
## 10) Rejected Alternatives
|
||||
|
||||
1. Full MCP-native mail integration now.
|
||||
Reason: unnecessary platform dependency for immediate local workflow goals.
|
||||
|
||||
2. Keep coordination only in ad-hoc bead comments.
|
||||
Reason: no directed inbox/ack semantics and weak reservation signaling.
|
||||
|
||||
3. Replace Beads lifecycle with custom coordination store.
|
||||
Reason: duplicates existing dependency/lifecycle truth and raises migration risk.
|
||||
|
|
@ -553,14 +553,14 @@ export function DependencyGraphPage({
|
|||
if (dep.type !== 'blocks') continue;
|
||||
// Avoid self-loops
|
||||
if (issue.id === dep.target) continue;
|
||||
const edgeId = `${issue.id}:blocks:${dep.target}`;
|
||||
const edgeId = `${dep.target}:blocks:${issue.id}`;
|
||||
|
||||
const linkedToSelection = selectedId ? issue.id === selectedId || dep.target === selectedId : false;
|
||||
|
||||
graphEdges.push({
|
||||
id: edgeId,
|
||||
source: issue.id,
|
||||
target: dep.target,
|
||||
source: dep.target,
|
||||
target: issue.id,
|
||||
className: linkedToSelection ? 'workflow-edge-selected' : 'workflow-edge-muted',
|
||||
animated: linkedToSelection,
|
||||
label: 'BLOCKS',
|
||||
|
|
|
|||
|
|
@ -188,10 +188,8 @@ export function KanbanPage({
|
|||
}
|
||||
}, [projectRoot]);
|
||||
|
||||
// Auto-refresh when issues change on disk (SSE)
|
||||
useEffect(() => {
|
||||
if (!allowMutations) {
|
||||
return;
|
||||
}
|
||||
const source = new EventSource(`/api/events?projectRoot=${encodeURIComponent(projectRoot)}`);
|
||||
const onIssues = () => {
|
||||
void refreshIssues({ silent: true });
|
||||
|
|
@ -203,7 +201,7 @@ export function KanbanPage({
|
|||
source.removeEventListener('issues', onIssues as EventListener);
|
||||
source.close();
|
||||
};
|
||||
}, [allowMutations, projectRoot, refreshIssues]);
|
||||
}, [projectRoot, refreshIssues]);
|
||||
|
||||
const mutateStatus = async (issue: BeadIssue, targetStatus: KanbanStatus) => {
|
||||
if (!allowMutations) {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,12 @@ export function buildGraphModel(issues: BeadIssue[], options: BuildGraphModelOpt
|
|||
continue;
|
||||
}
|
||||
|
||||
const edgeKey = `${issue.id}::${dependency.type}::${dependency.target}`;
|
||||
// Beads "blocks" dependency means: issue depends on target, so target blocks issue.
|
||||
// Normalize graph direction to blocker -> blocked for all blocker analytics and UI signals.
|
||||
const source = dependency.type === 'blocks' ? dependency.target : issue.id;
|
||||
const target = dependency.type === 'blocks' ? issue.id : dependency.target;
|
||||
|
||||
const edgeKey = `${source}::${dependency.type}::${target}`;
|
||||
if (edgeKeys.has(edgeKey)) {
|
||||
diagnostics.droppedDuplicates += 1;
|
||||
continue;
|
||||
|
|
@ -108,8 +113,8 @@ export function buildGraphModel(issues: BeadIssue[], options: BuildGraphModelOpt
|
|||
|
||||
edgeKeys.add(edgeKey);
|
||||
edges.push({
|
||||
source: issue.id,
|
||||
target: dependency.target,
|
||||
source,
|
||||
target,
|
||||
type: dependency.type,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ test('buildGraphViewModel limits visible nodes by hop depth around focus', () =>
|
|||
|
||||
assert.deepEqual(
|
||||
depth1.nodes.map((x) => x.id),
|
||||
['bb-2', 'bb-1', 'bb-3'],
|
||||
['bb-2', 'bb-3', 'bb-1'],
|
||||
);
|
||||
assert.deepEqual(
|
||||
depth2.nodes.map((x) => x.id),
|
||||
['bb-2', 'bb-1', 'bb-3', 'bb-4'],
|
||||
['bb-2', 'bb-4', 'bb-3', 'bb-1'],
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ test('buildGraphViewModel keeps deterministic edge ordering', () => {
|
|||
|
||||
assert.deepEqual(
|
||||
view.edges.map((x) => `${x.source}|${x.type}|${x.target}`),
|
||||
['bb-2|blocks|bb-3', 'bb-2|parent|bb-1'],
|
||||
['bb-2|parent|bb-1', 'bb-3|blocks|bb-2'],
|
||||
);
|
||||
assert.equal(view.nodes.every((x) => Number.isFinite(x.position.x) && Number.isFinite(x.position.y)), true);
|
||||
});
|
||||
|
|
@ -96,8 +96,8 @@ test('buildPathWorkspace returns upstream/downstream levels around focus', () =>
|
|||
const workspace = buildPathWorkspace(model, { focusId: 'bb-2', depth: 2, hideClosed: false });
|
||||
|
||||
assert.equal(workspace.focus?.id, 'bb-2');
|
||||
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-1']]);
|
||||
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-3']]);
|
||||
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-3']]);
|
||||
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-1']]);
|
||||
});
|
||||
|
||||
test('buildPathWorkspace hides closed nodes when requested', () => {
|
||||
|
|
@ -122,15 +122,15 @@ test('buildPathWorkspace full depth keeps deterministic blocker and dependent le
|
|||
|
||||
const workspace = buildPathWorkspace(model, { focusId: 'bb-3', depth: 'full', hideClosed: false });
|
||||
|
||||
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-2'], ['bb-1']]);
|
||||
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-4'], ['bb-5']]);
|
||||
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-4'], ['bb-5']]);
|
||||
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-2'], ['bb-1']]);
|
||||
});
|
||||
|
||||
test('analyzeBlockedChain returns blocker counts, first actionable blocker, and chain edges', () => {
|
||||
const model = buildGraphModel([
|
||||
issue({ id: 'bb-1', status: 'open', dependencies: [{ type: 'blocks', target: 'bb-2' }] }),
|
||||
issue({ id: 'bb-2', status: 'in_progress', dependencies: [{ type: 'blocks', target: 'bb-3' }] }),
|
||||
issue({ id: 'bb-3', status: 'blocked' }),
|
||||
issue({ id: 'bb-1', status: 'open' }),
|
||||
issue({ id: 'bb-2', status: 'in_progress', dependencies: [{ type: 'blocks', target: 'bb-1' }] }),
|
||||
issue({ id: 'bb-3', status: 'blocked', dependencies: [{ type: 'blocks', target: 'bb-2' }] }),
|
||||
]);
|
||||
|
||||
const summary = analyzeBlockedChain(model, { focusId: 'bb-3' });
|
||||
|
|
@ -155,7 +155,7 @@ test('detectDependencyCycles reports cycle nodes and edges for blocks relations'
|
|||
|
||||
assert.equal(anomaly.cycles.length, 1);
|
||||
assert.deepEqual(anomaly.cycleNodeIds, ['bb-1', 'bb-2', 'bb-3']);
|
||||
assert.deepEqual(anomaly.cycleEdgeIds, ['bb-1:blocks:bb-2', 'bb-2:blocks:bb-3', 'bb-3:blocks:bb-1']);
|
||||
assert.deepEqual(anomaly.cycleEdgeIds, ['bb-1:blocks:bb-3', 'bb-2:blocks:bb-1', 'bb-3:blocks:bb-2']);
|
||||
});
|
||||
|
||||
test('detectDependencyCycles does not mark non-cycle predecessor as cyclic', () => {
|
||||
|
|
@ -170,5 +170,5 @@ test('detectDependencyCycles does not mark non-cycle predecessor as cyclic', ()
|
|||
|
||||
assert.deepEqual(anomaly.cycleNodeIds, ['bb-a', 'bb-b', 'bb-c']);
|
||||
assert.equal(anomaly.cycleNodeIds.includes('bb-x'), false);
|
||||
assert.equal(anomaly.cycleEdgeIds.includes('bb-x:blocks:bb-a'), false);
|
||||
assert.equal(anomaly.cycleEdgeIds.includes('bb-a:blocks:bb-x'), false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ test('buildGraphModel extracts supported dependency types with deterministic ord
|
|||
model.edges.map((x) => `${x.source}|${x.type}|${x.target}`),
|
||||
[
|
||||
'bb-1|supersedes|bb-3',
|
||||
'bb-2|blocks|bb-3',
|
||||
'bb-2|parent|bb-1',
|
||||
'bb-3|blocks|bb-2',
|
||||
'bb-3|duplicates|bb-1',
|
||||
'bb-3|relates_to|bb-2',
|
||||
],
|
||||
|
|
@ -119,9 +119,9 @@ test('buildGraphModel builds incoming/outgoing adjacency maps', () => {
|
|||
|
||||
const model = buildGraphModel(issues);
|
||||
|
||||
assert.deepEqual(model.adjacency['bb-1'].outgoing.map((x) => x.target), ['bb-2']);
|
||||
assert.deepEqual(model.adjacency['bb-1'].incoming.map((x) => x.source), []);
|
||||
assert.deepEqual(model.adjacency['bb-2'].incoming.map((x) => x.source), ['bb-1']);
|
||||
assert.deepEqual(model.adjacency['bb-2'].outgoing.map((x) => x.target), ['bb-3']);
|
||||
assert.deepEqual(model.adjacency['bb-1'].outgoing.map((x) => x.target), []);
|
||||
assert.deepEqual(model.adjacency['bb-1'].incoming.map((x) => x.source), ['bb-2']);
|
||||
assert.deepEqual(model.adjacency['bb-2'].incoming.map((x) => x.source), []);
|
||||
assert.deepEqual(model.adjacency['bb-2'].outgoing.map((x) => x.target), ['bb-1', 'bb-3']);
|
||||
assert.deepEqual(model.adjacency['bb-3'].incoming.map((x) => x.source), ['bb-2']);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue