mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(board): materialize program items as Main-PM roots, make reports actionable (#711)
Two coupled gaps in the Board Program output path. Approved items were created unowned and in BACKLOG. Nothing dispatches BACKLOG, and once activated a cell PM claimed the parentless task as a root, where _cell_pm_complete resolves its merge target through resolve_parent_branch — which for a parentless task falls through to the project head rung. The result was a cell branch merging straight into the trunk, bypassing the Main-PM root, the root->master PR and the CEO gate (live: PRs #703 and #704 both targeted slave directly). All eight materializers now create a PENDING, main-pm-assigned root with team=Team.MAIN_PM, matching what approve_and_start does for an intake draft. The team is load-bearing, not cosmetic: _next_hint_pr_fail, _deliver_pr_fail_to_owner, delegate's wave-chain dispatch and the PR layer label all key on it, and a cell-teamed root drops the 'do NOT re-submit the root' steer that exists because of PR #138's infinite pr_fail loop. The item's own cell survives as a delegation hint in the description, which is what the Main PM's briefing renders. Periscope, Sentinel and Coroner produced artifacts with no way to act on them — three panel surfaces carried explicit 'no approve/reject UI' comments while each item already held a machine-readable suggested action. They now have per-item approve and dismiss, modelled on the roadmap queue: idempotent per item, CEO-gated, deep-copy-before-mutate so SQLAlchemy's dirty check still fires, and every decision recorded through record_decision so it reaches the next cycle's prompt. Approving materializes through the same corrected Main-PM-owned path. Target project resolves to each engine's own existing anchor — RoboCo's project for Periscope and Sentinel, the incident's project for Coroner — and fails with a clean invalid_state naming what is unresolvable rather than guessing at a repo. Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
+15
-3
@@ -40,14 +40,17 @@ def seed_company(stack: E2EStack) -> Company:
|
||||
return _COMPANY_CACHE["company"]
|
||||
|
||||
from roboco.db.tables import AgentTable
|
||||
from roboco.foundation import identity as _foundation
|
||||
from roboco.models import AgentRole, AgentStatus, Team
|
||||
|
||||
out = Company()
|
||||
|
||||
async def _run(session: AsyncSession) -> None:
|
||||
def agent(slug: str, role: AgentRole, team: Team | None) -> AgentTable:
|
||||
def agent(
|
||||
slug: str, role: AgentRole, team: Team | None, *, agent_id: Any = None
|
||||
) -> AgentTable:
|
||||
row = AgentTable(
|
||||
id=uuid4(),
|
||||
id=agent_id or uuid4(),
|
||||
name=slug,
|
||||
slug=slug,
|
||||
role=role,
|
||||
@@ -66,7 +69,16 @@ def seed_company(stack: E2EStack) -> Company:
|
||||
qa = agent("be-qa", AgentRole.QA, Team.BACKEND)
|
||||
doc = agent("be-doc", AgentRole.DOCUMENTER, Team.BACKEND)
|
||||
cell_pm = agent("be-pm", AgentRole.CELL_PM, Team.BACKEND)
|
||||
main_pm = agent("main-pm", AgentRole.MAIN_PM, None)
|
||||
# The canonical fixed UUID, not a random one: RoadmapService et al.'s
|
||||
# per-item materialize (and the MegaTask main_pm-route batch confirm)
|
||||
# hardcode AGENT_UUIDS["main-pm"] as the owning assignee, an FK to a
|
||||
# real agents row — the same identity production seeding uses.
|
||||
main_pm = agent(
|
||||
"main-pm",
|
||||
AgentRole.MAIN_PM,
|
||||
None,
|
||||
agent_id=_foundation.AGENTS["main-pm"].uuid,
|
||||
)
|
||||
reviewer = agent("pr-reviewer-1", AgentRole.PR_REVIEWER, None)
|
||||
ceo = agent("ceo", AgentRole.CEO, None)
|
||||
hom = agent("head-marketing", AgentRole.HEAD_MARKETING, Team.BOARD)
|
||||
|
||||
@@ -57,6 +57,12 @@ def _seed_system_hom_ceo_and_project(stack: E2EStack) -> str:
|
||||
Team.BOARD,
|
||||
),
|
||||
(_foundation.AGENTS["ceo"].uuid, "ceo", AgentRole.CEO, None),
|
||||
(
|
||||
_foundation.AGENTS["main-pm"].uuid,
|
||||
"main-pm",
|
||||
AgentRole.MAIN_PM,
|
||||
Team.MAIN_PM,
|
||||
),
|
||||
):
|
||||
if await session.get(AgentTable, agent_uuid) is not None:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user