Commit Graph
815 Commits
Author SHA1 Message Date
58354a364e [e56e6543] Reorder sidebar, rename A2A, remove Notifications entry, 2-col objectives (#394)
* [11e82f2e] Frontend: sidebar reorder, A2A rename, Notifications removal, 2-col objectives (#393)

* [946802b2] Objectives editor: 2-column desktop grid, 1-column mobile (#385)

* [946802b2] feat(goals-tab): objectives editor 2-col grid on desktop, 1-col mobile

* [946802b2] docs(goals-tab): document ObjectivesEditor responsive grid layout

Added comprehensive JSDoc comment explaining the 2-column desktop / 1-column mobile responsive grid layout for objective cards. Documents the grid-cols-1 / md:grid-cols-2 classes, the gap spacing, and clarifies that the '+ Add objective' button sits as a full-width sibling below the grid rather than as a grid item. Includes a visual layout structure for future reference.

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [639c0d54] Sidebar: reorder + dividers + A2A rename + remove Notifications (#389)

* [639c0d54] feat(panel): sidebar dividers, A2A rename, remove Notifications entry

Group navItems into six sections rendered with a visible Separator
between each group in SidebarNav (shared by desktop + mobile Sheet),
rename the /a2a entry from "A2A Live" to "A2A", and drop the
Notifications entry from the sidebar (/notifications stays reachable
via the header's NotificationBell). Adds sidebar.test.tsx covering
group dividers, the rename, the removed entry, item order, and the
collapsed icon-only state.

* [639c0d54] docs(sidebar): add navigation structure and grouping documentation

Document the six-group sidebar organization with dividers, the A2A rename
from "A2A Live", and the removal of Notifications from the sidebar. Covers
visual behavior across desktop expanded/collapsed and mobile states,
data structure rationale, and testing. Explains that Notifications remains
accessible via the header NotificationBell.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [92a46054] Fix sidebar: exact flat order + move Business to footer (#415)

* [11a612e2] Flatten sidebar nav order + move Business to footer (#413)

* [11a612e2] fix(panel): flatten sidebar navItems + move Business to footer

* [11a612e2] docs(sidebar): update navigation structure documentation for flat navItems + Business in footer

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [dc518639] revert(business): drop out-of-scope 2-col objectives grid from PR #415 (#418)

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [e2b50b06] Re-implement 2-column objectives grid in goals-tab.tsx (#435)

Branch rebuilt from the root fork point so the assembled delta against
master contains ONLY this task's work: the responsive objectives grid
(grid-cols-1 md:grid-cols-2) and its test. The prior branch inherited the
root's sidebar work into the against-master view, which the PR gate
correctly flagged as an AC4 violation.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 07:42:37 +02:00
eefaca1d3b [3dfc43a1] Task detail overhaul: markdown, navigation, collapsible sections, timestamps (#410)
* [35a27c3d] UX/UI: design task-detail overhaul (#404)

* [39ea1900] docs(ux_ui): add content-readability spec for markdown, collapsible sections, timestamps (#388)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [71f9aec6] docs(ux_ui): add task navigation/structure design spec (#400)

Adds docs/ux_ui/design/task-navigation-structure.md covering the
breadcrumb trail, prev/next sibling navigation, and a distinct visual
treatment for the read-only constraints section, grounded in the real
task-detail components and existing amber/Lock read-only tokens.

Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>

* [9baa1c34] Frontend: implement task-detail overhaul (#408)

* [13b6c723] Task detail: inline timestamps + breadcrumb + prev/next navigation (#390)

* [13b6c723] feat(panel): add inline absolute timestamps, task breadcrumb, and prev/next list nav to task detail

Adds a shared formatAbsoluteTimestamp helper used inline (with tooltip)
next to relative time on progress updates and checkpoints in
tab-progress.tsx, progress-timeline.tsx, and checkpoint-card.tsx.
Adds TaskBreadcrumb (renders only when task.parent_task_id is set) and
TaskListNav, which reads a new taskListNav context in the
scroll-restoration zustand store — populated by the Tasks list page from
TaskTable's live filtered/sorted order — to move to the adjacent task.
When no list context exists for the session or the current task isn't
part of the captured order, both nav buttons render disabled with an
explanatory tooltip (the documented fallback).

* [13b6c723] docs(guide): task detail navigation, timestamps, breadcrumb, and prev/next behavior

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [40acdd31] Task detail: collapsible markdown sections + distinct Constraints styling (#407)

* [40acdd31] feat(panel): collapsible task-detail sections + distinct Constraints styling

Wrap the Description, per-field Notes, and Plan cards in a new
CollapsibleSection (Radix Collapsible + tw-animate-css fade/slide, so
collapse/expand only animates opacity/transform) so a long task no longer
forces continuous scrolling. Restyle the read-only Constraints card with an
amber accent border, background tint, and ShieldAlert icon so it reads as
distinct from authored content. Existing edit/preview toggles are
force-open while active and otherwise unchanged. Adds a global
prefers-reduced-motion override in globals.css.

* [40acdd31] docs(panel): CollapsibleSection component API and usage guide

Documents the new CollapsibleSection wrapper component used for independent collapse/expand of task-detail sections (Description, Constraints, Notes, Plan). Covers component API, controlled vs. uncontrolled state patterns, animation behavior (fade+slide, transform/opacity only), prefers-reduced-motion handling, and usage examples across task-description.tsx / tab-notes.tsx / tab-plan.tsx.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [73f8311f] fix(task-table): remove exhaustive-deps suppression on visible-order effect (#409)

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [eb417ef1] Fix: apply auto-collapse thresholds to Progress and Acceptance Criteria surfaces (#429)

* [4e855d24] Apply content-readability-spec collapse thresholds to Progress and Acceptance Criteria surfaces (#416)

* [4e855d24] feat(task-detail): auto-collapse long progress/checkpoint/AC content per readability spec

* [4e855d24] refactor(task-detail): remove inline JSX section-marker comments per no-inline-comments convention

* [4e855d24] docs(task-detail): document content-readability-spec collapse thresholds for CollapsibleSection

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [3c90ef34] Wire content-readability thresholds into CollapsibleSection, tab-progress, acceptance-criteria (#430)

* [3c90ef34] test(task-detail): add AC4 combined readability test — 30+ progress entries + long acceptance-criteria list

* [3c90ef34] docs: enhance content-readability thresholds documentation and code comments

- Enhance panel/src/lib/content-readability.ts with usage examples and clarified intent
- Enhance CollapsibleSection with auto-collapse logic explanation and precedence rules
- Enhance TabProgress's RECENT_OPEN_COUNT logic with dual-threshold explanation
- Add comprehensive architecture guide: panel/docs/CONTENT_READABILITY_THRESHOLDS.md covering thresholds, components, testing, and implementation notes

The readability feature prevents long-history tasks (30+ updates, 20+ criteria) from rendering fully expanded, keeping pages navigable. Tests confirm 32 progress updates default to 2 open, and long criteria lists collapse while short ones stay expanded.

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [fc04d84a] Round-3 revision: fix 4 named gaps on task-detail overhaul, one dev leaf per fix (#455)

* [cac9b603] fix(panel): fall back to task.created_at for missing written_at stamp in tab-notes.tsx (#446)

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

* [31dd4f99] Remove ArrowLeft back button from task-header.tsx (#441)

* [31dd4f99] Remove ArrowLeft back button and Link wrapper from task-header.tsx, drop now-unused imports

* [31dd4f99] docs(task-navigation): mark spec as implemented, clarify ArrowLeft button removal

Update task-navigation-structure.md to reflect v0.21.0+ implementation:
- Status changed from "proposed" to "implemented"
- Clarified that ArrowLeft back button was removed from task-header.tsx
- Noted that breadcrumb and prev/next navigation now provide all navigation
- Constraints section styling with amber tint and ShieldAlert icon is complete
- Referenced related guide documentation for task-detail-navigation features

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [75fd7444] Wire content prop into EditableNoteCard's CollapsibleSection (#449)

* [75fd7444] feat(panel): wire content prop into EditableNoteCard's CollapsibleSection

Pass the note field's current value into CollapsibleSection's content
prop and derive EditableNoteCard's initial sectionOpen state from
exceedsReadabilityThreshold, so long notes default collapsed with an
expand affordance while short notes render fully expanded.

* [75fd7444] docs(panel): document EditableNoteCard's content-driven collapse pattern in collapsible-section.md

Updated docs/frontend/components/collapsible-section.md to reflect how EditableNoteCard in tab-notes.tsx uses both controlled mode (force-open while editing) and content-driven initialization (seed sectionOpen from content length). Added a new "Combined: controlled + content-driven initialization" example showing this pattern for future developers extending editable-content sections.

Pattern: long notes default collapsed with expand affordance, short notes default expanded, edit forms always visible during editing.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [18ada610] docs(ux-ui): reconcile prev/next nav design spec with shipped list-order behavior (#453)

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [3dfc43a1] round-3 fixes: reconcile nav spec, Alt+Arrow shortcuts, CHANGELOG

The breadcrumb section of task-navigation-structure.md now describes the
shipped single-ancestor design (and drops the stale DropdownMenu claims);
Alt+ArrowLeft/Right on TaskListNav mirror the visible prev/next buttons,
suppressed while an editable element has focus, with tests; the
user-facing CHANGELOG entry lands under Unreleased. Also reflows the
round-1 content-readability-spec so the prose gate is green branch-wide.

* [3dfc43a1] blank line between Unreleased and 0.22.0 sections

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 07:41:15 +02:00
f0f09b2204 [1197c975] Re-add Playwright chromium to FE/UX QA images and add browser-verification prompt guidance (#406)
* [3e552255] Re-add Playwright chromium to QA images + prompt guidance (#395) (#405)

* [3e552255] feat(docker): re-add Playwright chromium-headless-shell to QA images

* [3e552255] ci(docker): add Playwright QA image build + headless smoke check workflow

* [3e552255] fix(ci): scope agent-image-smoke.yml trigger to paths only, add PR comment

The workflow was gated by `branches: [master]` on both push and
pull_request, but this repo's task-hierarchy PRs open against nested
parent feature branches, not master, until root->master assembly - so
the workflow never fired on a dev-level PR and produced zero evidence.
Drop the branch filter (path scoping is sufficient) and post the
size-delta table + smoke-check output as a PR comment via
actions/github-script, since no agent role has gh CLI or GitHub API
read access to pull check-run output directly.

* [3e552255] fix(ci): post agent-image-smoke PR comment even on step failure

The 'Post results as a PR comment' step only had
`if: github.event_name == 'pull_request'`, which GitHub implicitly ANDs
with success() — so if the docker build or headless-launch smoke check
failed, the PR comment (the only evidence-delivery path QA/PM has, since
no agent role can read the Checks tab) silently never posted. Added
always() so a partial report always lands on the PR.

This commit also re-lands the branches-filter removal + PR-comment step
from 747e4d74 to make sure this fix actually reaches the remote PR
branch — QA's needs_revision at 05:48 came after that commit's local
timestamp (05:43) but still saw the pre-fix workflow, indicating the
prior push never reached GitHub.

* [3e552255] docs(qa): add browser verification guide and CHANGELOG entry for Playwright chromium

- Added comprehensive QA browser verification guide at docs/backend/qa/browser-verification.md covering setup, examples for fe-qa/ux-qa, limitations, and troubleshooting
- Updated CHANGELOG.md with Unreleased entry documenting Playwright chromium-headless-shell re-add to agent-qa-fe and agent-ux images, CI smoke workflow, and links to QA guidance
- Guide explains when to use browser verification (rendered output, computed styles, a11y, visual design), how to launch headless chromium, and provides practical examples for both FE and UX QA use cases
- References built-in guidance in fe-qa.md/ux-qa.md identity prompts and CI smoke workflow verification

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [9aafe8f5] Revision: fix reflow-check CI failure and resolve orchestrator Playwright-allowance gap (#421)

* [9973237c] fix(docs): separate reflow-joined metadata lines in browser-verification.md (#419)

scripts/reflow_md.py --check treats two adjacent non-blank lines as one
paragraph and flags it as hard-wrapped prose needing a join. Insert a
blank line between the `**For:**` and `**Purpose:**` metadata lines so
each stays its own single-line paragraph; verified the reflow is now a
no-op and the non-whitespace token sequence is unchanged.

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [cc355a2b] docs(qa): add no-op analysis for orchestrator.py Playwright allowance (#422)

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [a506cc10] docs(qa): quote real Dockerfile Playwright snippets in no-op analysis (#424)

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [2b35dd4e] Resolve merge conflict, confirm green CI, add Playwright MCP registration, re-verify 5 ACs (#447) (#450)

* [2b35dd4e] docs(changelog): resolve Unreleased/0.22.0 ordering conflict, keep Playwright entry

* [2b35dd4e] feat(runtime): register Playwright MCP server for fe-qa/ux-qa, per CEO round-3 note

Adds @playwright/mcp to agent-qa-fe and agent-ux images, wired via a wrapper
entrypoint that points the server at each image's already-baked
chromium-headless-shell instead of downloading a second browser. The
orchestrator registers the `playwright` MCP server only for the qa role on
the frontend/ux_ui teams, so be-qa and ux-dev never see it. Updates the QA
identity prompts and docs/backend/qa/browser-verification.md to document the
structured mcp__playwright__* tools in place of hand-scripted Bash+Python,
adds CI smoke coverage (binary + baked-chromium resolution + a real
panel-page screenshot from inside the ux-qa image), and records the change
in CHANGELOG.md.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [1197c975] type the mcpServers extraction so mypy's no-any-return passes

* [1197c975] extract role-scoped MCP registration — orchestrator back under the complexity budget

The playwright branch pushed _generate_mcp_config to rank C in the merge
ref; docs/research/playwright registrations move to one helper, behavior
identical.

* [1197c975] basename-sanitize the MCP config filename

CodeQL's path-injection query re-fired on the (moved, unchanged) config
write; agent ids are orchestrator-issued, but the filename now rides the
same os.path.basename sanitizer _grok_usage_json established.

* [1197c975] basename the agent id variable itself — the sanitizer shape CodeQL models

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 07:39:53 +02:00
7f138d3bf5 [e4ed92d6] Video pipeline per-project requests, re-render action, composition preview (#403)
* [7f2c881a] Project-scope video pipeline + re-render + preview proxy (#386) (#396)

* [7f2c881a] feat(video): scope on-demand video requests + render loop to project_id

Require project_id on VideoRequestBody (404 when unresolvable or not
opted into the video engine), thread it through VideoEngine.open_video_task
via a shared resolve_authoring_project helper, and resolve the render
loop's motion/ workspace from the authoring task's own project_id instead
of the hardcoded self_heal_project_slug.

* [7f2c881a] fix(video): cast task.id to UUID before VideoEngine.rerender calls

mypy flagged task.id as sqlalchemy.sql.sqltypes.UUID[Any] rather than
uuid.UUID in the three rerender tests; cast to UUID per the codebase's
established idiom (cast("UUID", obj.id)) used elsewhere for the same
SQLAlchemy Mapped-attribute inference gap.

* [7f2c881a] docs(video): API endpoints for project-scoped requests, re-render, and preview proxy

Add comprehensive API documentation for the new project-scoped video engine endpoints:
- POST /api/video/request: on-demand video authoring scoped to project_id (breaking change)
- POST /api/video/pipeline/{task_id}/rerender: CEO-triggered re-render with idempotency key clearing
- GET /api/video/preview/{task_id}/{file_path}: CEO preview proxy with path-traversal confinement

Document project-scoping architecture: authoring tasks and render loop now resolve from task's own project_id instead of hardcoded self_heal_project_slug.

Add migration guide covering breaking change to VideoRequestBody schema (project_id now required), error handling changes (404 on unresolvable/non-opted-in projects), and client migration steps.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [8f959c3b] docs(ux_ui): add project picker, re-render control, and composition preview panel spec (#381) (#398)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [1fb5b5cb] Project picker, re-render button, and composition preview panel (#397) (#402)

* [1fb5b5cb] feat(video): project picker, re-render button, and composition preview panel

* [1fb5b5cb] docs(video): add comprehensive guide for project picker, re-render button, and composition preview panel

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [a512f364] Add video_engine_enabled to ProjectSummaryResponse (#412) (#414)

* [a512f364] feat(api): surface video_engine_enabled on ProjectSummaryResponse

* [a512f364] docs(api): document video_engine_enabled on ProjectSummaryResponse

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [03607ab9] Fix re-render control gating/placement and project picker filter (#434)

* [f2f3e89f] Fix RerenderControl gating/placement across queue and strip views (#431)

* [f2f3e89f] feat(video): widen RerenderControl gating and share it across queue/strip views

Extracts RerenderControl into a shared panel/src/components/dashboard/
video-rerender-control.tsx component, widens its gate from
render_status === 'failed' to source_task_id + composition_id present
(matching what the backend rerender endpoint actually requires), adds a
confirm dialog before firing the mutation, and wires the same component
into video-pipeline-strip.tsx for still-in-flight rendering/render_failed
rows.

* [f2f3e89f] docs(video): enhance RerenderControl JSDoc with gating logic and usage examples

Add comprehensive JSDoc to the RerenderControl component covering its
purpose, gating logic (render for any source_task_id + composition_id,
regardless of render_status), three visual button states (idle/loading/
error), confirm-dialog guard behavior, and usage examples for both
video-post-queue.tsx and video-pipeline-strip.tsx contexts. Explains
why the backend's rerender endpoint doesn't require a failed render and
how the component prevents accidental re-renders.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [404d8ed3] Filter project picker to video-engine-enabled projects (#432)

* [404d8ed3] feat(panel): filter video-request project picker to opted-in projects

Add video_engine_enabled to the client ProjectSummary type, give
ProjectSelector a videoEngineOnly filter prop, default RequestVideoDialog's
picker to the current video-enabled project with a friendly empty-state
when none exist, and cover the filter with a new project-selector test.

* [404d8ed3] docs(panel): add ProjectSelector component API reference with videoEngineOnly filter

Document the reusable ProjectSelector component with its props, filtering behavior,
and new videoEngineOnly filter for video-engine-enabled projects. Follows the
existing component documentation pattern from page-refresh-provider.

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [519a4088] fix(panel): import missing RerenderControl in video-post-queue and correct stale doc (#436)

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

* [8e912c3e] Reflow hard-wrapped video UX design doc to pass quality gate (#439)

* [ccfe2015] docs(ux_ui): reflow video request composition-controls spec to one line per paragraph (#438)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [99c3ed9c] docs(backend): reflow hard-wrapped prose in video-engine-endpoints.md and video-project-scoping.md (#442)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [c2e98fc0] docs(backend): strip stray trailing whitespace in video-engine-endpoints.md fence (#451)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [9c7bc11a] Reflow all 3 hard-wrapped docs on this branch and verify quality gate (#457)

* [9c7bc11a] test(scripts): guard reflow_md.py --check wiring into make quality

* [9c7bc11a] docs(standards): document markdown reflow quality gate workflow and verification

Added comprehensive guide explaining the one-logical-unit-per-line markdown prose standard, how the reflow check integrates into make quality, the three reflowed files (video-engine-endpoints.md, video-project-scoping.md, composition-controls spec), and the regression test added to ensure wiring stability. This task verifies all three ACs are satisfied: reflow_md.py --check exits 0, make quality passes (non-DB portions), and the three files are whitespace-only reflowed.

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>

* [002f0cdd] docs(rag): document reflow-check zero-diff troubleshooting path (#459) (#460)

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [e4ed92d6] fix rerender missing-task test — assert the empty queue it creates

The test never seeds; the trailing assertion expected a phantom video
post. Broken since the branch's first commit but never executed — every
earlier CI run short-circuited at a pre-pytest gate step.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 07:39:17 +02:00
4d52f6ff59 [1f6a06a2] PR-review gate: verify ACs literally and require green CI before pr_pass (#428)
* [a1bde3b9] Add CI-status guard to pr_pass + update pr_reviewer prompt (#417) (#420)

* [a1bde3b9] feat(gateway): CI-status guard on pr_pass + reviewer prompt update

* [a1bde3b9] docs(pr-gate-review, worksession-git): document CI-status guard on pr_pass

Updated two architecture documentation files to reflect the new CI-status guard:

**pr-gate-review.md:**
- Documented _ci_status_guard method: blocks pr_pass on failing/pending/unscheduled/error CI with reviewer-aware pr_fail remediation
- Documented _resolve_ci_status: best-effort GitHub check-runs lookup with fail-open behavior
- Updated _pr_pass_blocked description: now returns (rejection_envelope, ci_note) tuple
- Updated _record_gate_verdict_for/verdict to note ci_status field stamping on pr_pass
- Added ci_note parameter documentation for evidence tracking when no CI is configured
- Updated Logical Tree to show new methods
- Added Config Flags note: CI guard is always armed, fails open on config gaps
- Added two regression risks: check-runs-only limitation, fail-open design

**worksession-git.md:**
- Documented GitService.get_pr_ci_status(project_slug, pr_number): CI status lookup with state classification
- Documented supporting methods: _ci_status_prereqs, _fetch_check_runs, _classify_check_runs, _classify_zero_check_runs
- Each method notes its fail-open behavior and configuration gap handling

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [e8f275d7] test(gateway): lock the 7-AC-to-test map + assert pr_reviewer prompt content (#425) (#426)

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* [24b4237e] Fix reflow-check, CI-status classification, and noqa suppression (#440) (#443)

* [24b4237e] fix(gateway): classify unreachable/nonexistent CI-status repo as no_ci_configured, remove test noqa, reflow pr_reviewer.md

Split GitService.get_pr_ci_status's PR-head-sha lookup into a dedicated
helper so a config gap (missing project/git_url/token) or an unreachable/
nonexistent repo/PR (network error or 404) classifies as no_ci_configured
(pr_pass passes through and stamps the evidence note) while a genuine
GitHub API failure on a real, reachable repo (any other non-2xx, or an
unparseable body) stays the fail-closed error state. Replaced the
`# noqa: PLR2004` in test_git_pr_ci_status.py with a named HTTP-status
range constant, updated the config-gap tests to assert the new
classification, and added tests for the unreachable-repo and real-repo-
API-error branches. Reflowed agents/prompts/roles/pr_reviewer.md's one
hard-wrapped continuation line so it passes make reflow-check.

* [24b4237e] docs(gateway): update pr-gate-review.md for CI-status classification refactor

Updated the internal architectural map to reflect the new CI-status classification
scheme introduced in PR #440. Configuration gaps (missing project/git_url/token) and
unreachable/nonexistent repos (404 or network error) now explicitly classify as
no_ci_configured and pass through with evidence stamps. Genuine GitHub API failures
on reachable repos classify as error and stay fail-closed (retryable).

- Clarified _ci_status_guard behavior: config gaps/unreachable repos pass through
  with distinct classification; only real API failures stay fail-closed
- Updated Config Flags section to describe the new three-way classification
- Updated Regression Risks section to document the new explicit classification scheme
- Noted that _resolve_ci_status now wraps git.get_pr_ci_status and interprets its result dict

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>

* [1f6a06a2] round-3 fixes: pr_gate back to xenon rank A; 404 means no CI, not error

Eight extracted helpers bring the module average from B(5.05) to A(4.04)
with every external contract untouched (170 gate tests byte-identical).
The CI-status guard now classifies a 404 on the check-runs or workflows
endpoints as no_ci_configured (pass-through with evidence note) —
a repo without Actions is not a transport failure — reserving the
fail-closed error state for network/5xx/auth failures, with pinning
tests for all four shapes. The e2e fake-GitHub router gains check-runs
and workflows routes so the scripted lifecycle exercises the guard's
green-CI success branch end to end.

* [1f6a06a2] merge master; align gate-diff-base tests with the tuple contract

The merged tree is the first integration of the CI-status guard with the
preferred-parent diff-base guard: _pr_pass_blocked now returns
(rejection, ci_note), so the diff-base tests unpack it instead of
asserting on a bare result. Both guards verified live in the merged
pr_gate (preferred_parent threading and _ci_status_guard present).

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 07:38:06 +02:00
15a3e87a2f feat(vault): Obsidian vault V1 — projection core, Auditor narrative, input loop (#458)
* fix(gateway): gate review diffs against the task's real parent branch (#444)

The in-path PR-review gate's evidence diff (claim_gate_review) and the
pr_pass conventions guard derived their diff base via parent_branch_for
string surgery, which reuses the child branch's own team segment — wrong
for every cross-team hop (a frontend child of a main_pm root derives a
ref that never existed) and silently falls back to the repo default
branch, so the reviewer judged the entire inherited base-branch content
as the task's own work and failed acceptance criteria the task never
touched. Bounced a live goals-tab fix three times, unfixable by branch
surgery.

The gate now resolves the base via resolve_parent_branch (the parent
task's recorded branch_name, cross-team correct) and threads it as a new
preferred_parent override through git.diff / list_changed_files /
conventions_check_for_task — consulted only when no explicit base is
given, so the pinned literal-base contract (base="HEAD~1") and every
other diff caller (QA, doc, content) are byte-identical. Parent lookup
fails open (derived-base fallback) like the other resolve_parent_branch
call sites, and is skipped entirely while the conventions flag is off.

Also excludes .uv-cache/ and .claude/ (agent worktrees, private uv
cache) from the markdown prose scanner — both are repo-local tool dirs
whose vendored/generated files tripped make reflow-check.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>

* feat(vault): Obsidian vault V1 — projection core + input loop

The vault is a rebuildable projection of the DB (never a source of
truth), default-off behind ROBOCO_OBSIDIAN_VAULT_ENABLED + ROBOCO_VAULT_PATH.

Projection core: VaultWriter materializes tasks/journals/A2A/agents as
wikilinked markdown (id-suffixed stable filenames, alias-based links so
renames never break, is_private journals excluded like the RAG corpus);
event seams materialize on journal write and A2A send and touch task-note
frontmatter at the status-transition chokepoint — all best-effort, a
vault failure never blocks a verb. Shipped .obsidian config (Dataview,
Kanban, team/status graph groups) + _meta dashboards; python -m
roboco.vault rebuild/relocate (rebuild preserves the narrative section).

Auditor narrative duty: curate_vault content verb (auditor-only,
playbook-curation pattern) spawned by a dedicated root-completion hook
with its own cooldown — fully separate from _dispatch_audit_work, whose
scheduled-sweep/alert-producer revival belongs to the queued fleet task.

Input loop: VaultIntakeEngine (ROBOCO_VAULT_INTAKE_*) watches the
intake folder for #roboco-tagged notes and materializes each as ONE held
draft (confirmed_by_human=False, Secretary-owned, source=vault_note,
excluded by the dispatchers via _is_held_ceo_source) with local-model
extraction and a deterministic fallback; vault_seen_notes ledger
(migration 070) keyed on path+content-hash (the CEO-feedback callout is
stripped before hashing so the engine's own append never self-triggers);
per-cycle and open-draft caps. Nothing auto-starts.

* fix(vault): integrate with master — re-chain migration 070 onto 069, mypy-clean tests

The vault branch was cut from slave before the sequence-gate promotion,
so migration 070 chained from 068 while master already carried 069 —
two heads on merge. Master is now merged in and 070 revises 069.
Vault test files also get mypy-clean mock idioms (monkeypatch.setattr
over method assignment; await_args narrowed before access).

* fix(scripts): dedupe SKIP_DIRS again after the master merge

Master still carries the twin-merge duplicate (its dedupe hotfix is an
unmerged PR); the merge re-imported it here.

* fix(vault): reflow hard-wrapped prose in the vault asset templates

* chore(config): exclude .uv-cache and .claude from deptry's scan scope

Same repo-local tool dirs the prose scanner skips; the standalone deptry
target walks the repo root and drowned in the cache's unpacked wheels.

* fix(vault): board-review activation path for vault drafts + relocate graft

The input loop's held-artifact posture was a dead end: vault_note drafts
were unconditionally held by _is_held_ceo_source, owned by the verbless
Secretary, hidden from the panel's approval surfaces by team, and the
open-drafts cap counted them forever — the engine self-bricked after ten
notes. Vault drafts now ride the intake board-review path instead: a
tagged note becomes a PENDING Product-Owner-assigned Board draft (the
exact confirm_live_draft board shape), the board reviews it, and only
the CEO's approve_and_start makes it deliverable — never-auto-starts now
rests on the board gate, proven by tests against the real dispatchers.
The cap counts only drafts still awaiting the CEO (team==BOARD,
non-terminal), so approval and cancellation both free it.

relocate into an existing personal vault now grafts old_root/RoboCo as a
direct child (refusing loudly if RoboCo/ already exists there) and adds
only absent .obsidian/_meta files — a personal vault's config is never
clobbered. An absent destination keeps the whole-tree move.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-11 03:17:59 +02:00
Renzo FandGitHub 340fcebce2 fix(scripts): dedupe SKIP_DIRS entries left by the twin gate-fix merges (#456) 2026-07-11 02:22:03 +02:00
8f3f4236c0 feat(tasks): sequence is the bar — strict sibling ordering at the claim chokepoint (#452)
* feat(tasks): enforce sibling sequence order at the claim chokepoint

A task with a parent and effective sequence N (COALESCE(sequence, 0))
can no longer be claimed while any sibling with a strictly lower
effective sequence is non-terminal — assignee-blind, independent of and
stricter than dependency_ids, enforced in _validate_claim_preconditions
so both claim paths (gateway verbs and the dispatcher's raw REST claim)
cross it. Ties run parallel; cancelled siblings never block; sequence 0
and parentless tasks are unaffected. Live failure this guards: a PM
delegated revision subtasks sequenced 0..3 with no dependency edges and
seq 2 started alongside seq 0 — sequence was advisory-only.

set_sequence's contract updated accordingly. New e2e smoke case drives
the refusal and the post-completion claim through the real gateway.

* chore(scripts): skip .uv-cache and .claude in the prose scanner

Repo-local tool dirs (private uv cache, agent worktrees) carry vendored
and generated markdown that tripped make reflow-check.

* fix(tasks): wave-derived delegation sequences + claim-gate hardening

Three fixes from the adversarial review of the sequence claim gate:

Delegation no longer stamps a raw per-sibling ordinal (deterministic
merge-order bookkeeping) as sequence — under the strict gate that
serialized ALL delegated work, including fully independent cross-dev and
cross-cell siblings. Sequences are now wave-derived post-wiring
(stamp_wave_sequence: 1 + max same-parent dependency sequence, 0 when
independent), so independent siblings tie and run parallel while
colliding/ordered work ascends. The cross-cell UX wiring restamps
instead of writing relative ux+1 values (a relative write could invert
a collision-derived stamp), and the dispatch merge/lane barriers gain a
created_at tiebreak for wave-tied siblings so shared-branch merge order
stays deterministic. PM-authored sequences are never rewritten.

The guard now also fires on reclaims from needs_revision (a lower-
sequence sibling delegated after the first claim was invisible), and
tasks.parent_task_id gains an index (migration 069) — the guard's
sibling probe ran as a Seq Scan on the hottest verb.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 22:55:00 +02:00
7ff70ab5e2 fix(gateway): gate review diffs against the task's real parent branch (#444) (#454)
The in-path PR-review gate's evidence diff (claim_gate_review) and the
pr_pass conventions guard derived their diff base via parent_branch_for
string surgery, which reuses the child branch's own team segment — wrong
for every cross-team hop (a frontend child of a main_pm root derives a
ref that never existed) and silently falls back to the repo default
branch, so the reviewer judged the entire inherited base-branch content
as the task's own work and failed acceptance criteria the task never
touched. Bounced a live goals-tab fix three times, unfixable by branch
surgery.

The gate now resolves the base via resolve_parent_branch (the parent
task's recorded branch_name, cross-team correct) and threads it as a new
preferred_parent override through git.diff / list_changed_files /
conventions_check_for_task — consulted only when no explicit base is
given, so the pinned literal-base contract (base="HEAD~1") and every
other diff caller (QA, doc, content) are byte-identical. Parent lookup
fails open (derived-base fallback) like the other resolve_parent_branch
call sites, and is skipped entirely while the conventions flag is off.

Also excludes .uv-cache/ and .claude/ (agent worktrees, private uv
cache) from the markdown prose scanner — both are repo-local tool dirs
whose vendored/generated files tripped make reflow-check.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 19:55:38 +02:00
Renn F 76a396b152 chore(release): 0.22.0 v0.22.0 2026-07-10 10:25:21 +02:00
bba20a3917 feat(prompter): board-review → redraft loop for MegaTask batches (#411)
Batch parity with the single-draft keep-alive redraft loop. A first
board-route confirm-batch parks the intake session against the umbrella
(instead of the unconditional reap), so the existing board-completion
injection reaches the still-live chat — now with a batch-aware brief
(compose_batch_redraft_message: live root-subtask snapshots + board
notes + a one-propose_batch re-proposal instruction). The re-confirm
carries BatchConfirmRequest.task_id and routes to the new
PrompterService.update_live_batch: in-place umbrella + root-subtask
update (positional patch of live children, cancel+recreate on scope
change, create/cancel on count change, dependency edges rewired to the
fresh wave plan) gated by the same _validate_batch_scope as create.
Readers use the CANCELLED-excluding get_live_subtasks view so
multi-round redrafts survive earlier cancels.

Cold path: re-interview now handles a branchless umbrella by recovering
its multi-repo scope from live children (distinct_projects_for_batch)
and returning project_ids — fixes the live 400 behind the task-detail
redraft button on umbrellas. Panel: confirmBatch board branch keeps the
chat open, threads batchRedraftTaskIdRef (persisted) into the
re-confirm, treats a redraft re-confirm as terminal on both routes, and
surfaces the server's real validation message on confirm failure.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 09:38:10 +02:00
3674a1e002 fix(megatask): wire cross-cell sequencing for batch root-subtasks (#391)
Within a MegaTask root-subtask, the per-cell tasks got sequence numbers but zero
dependency edges, so they ran fully in parallel (UX finished after backend
started, frontend self-blocked) — divergent branches, duplicated/wasted work.

The cross-cell wiring (_wire_ux_frontend_dependency: FE/BE cells depend on the UX
cell, bidirectional, propagated to dev subtasks via inherit_unmet_dependencies)
already exists, but it bails unless the parent has a product_id. A MegaTask
root-subtask has no product_id — it targets its cells via cell_projects — so the
wiring silently no-op'd for every MegaTask root (confirmed on the live video
root: product_id=None, three cells, all with empty dependency_ids).

Broaden the guard to fire on product_id OR is_batch_root_subtask(batch_id,
parent_task_id) (scalar fields; cell_projects is a lazy relationship). The same
tested wiring now holds MegaTask cells in order like a product fan-out.

Adds test_megatask_root_wires_cross_cell_ux_dependency.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 07:46:17 +02:00
91f9642f27 fix(megatask): guardrail the wave sequence at the claim chokepoint (#382)
The Main PM claimed every MegaTask wave at once, ignoring the collision-ordered
dependencies. The sequencing data was correct (analyzer wired proper waves), but
enforcement was only half-wired: the unmet-dependency guard lives on the gateway
claim verbs (i_will_plan -> _run_claim_guards), while the orchestrator dispatches
coordination roots itself — _dispatch_pm_work fetches pending with no dependency
filter and _claim_task_for_agent system-claims via the raw POST /tasks/{id}/claim
route -> TaskService.claim, which had no dependency check. So the orchestrator
claimed every pending root-subtask for the Main PM regardless of wave.

Enforce the sequence at the claim chokepoint: _validate_claim_preconditions now
refuses to claim a PENDING task while any depends_on task is non-terminal
(extracted into _claim_blocked_by_dependencies for the complexity budget). This
guardrails every claim path — the gateway verbs (redundant) and the orchestrator
raw dispatch claim (the hole). Scoped to a PENDING start-of-work claim so a
mid-lifecycle QA/doc claim is unaffected; dependencies are monotonic so each wave
claims normally once the prior one completes.

Adds test_claim_pending_with_unmet_dependency_returns_none (blocked with an
unfinished dependency; claimable once it completes).

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 06:51:49 +02:00
f601e32788 fix(prompter): batch confirm ignores a vestigial top-level project slug (#380)
* fix(prompter): batch confirm ignores a vestigial top-level project slug

The MegaTask confirm-batch 400'd with "Invalid project_id UUID: roboco-api".
The intake agent authors each draft's project as the repo slug it read, and the
panel only nulls the top-level project_id when the CEO toggles that draft's
picker — so an untouched draft carried the slug through to create_task_from_draft,
whose eager _resolve_uuid_field(project_id) raised on the non-UUID and rejected
the whole batch (guard-release from the prior fix surfaced it as a clean 400
instead of a wedged 500).

A batch root-subtask targets its repos via the the_work per-cell map (the panel
fills those with real project UUIDs); the top-level project_id/product_id is
vestigial for it. Strip it from a sub-draft when its cell map carries the real
target — a legacy no-the_work draft keeps its panel-filled top-level UUID, and
scope validation (which already runs off the cell map) is unchanged.

Adds a repro test with two cell-map drafts that also carry leftover top-level
slugs (roboco-api / roboco-panel); they now confirm instead of 400-ing.

* fix(tests): conventions PR integration test honors the #375 workspace-scope guard

#375 added a containment guard to open_conventions_pr (workspace_path must sit
under {workspaces_root}/{slug}); the unit test was updated but this integration
test still seeded a bare tmp_path/repo, so open_conventions_pr returned None and
test_open_conventions_pr_commits_locally_without_remote failed on master. Anchor
workspaces_root at the test dir and place the repo under the project's slug.

* refactor(prompter): extract batch sub-draft sanitize (xenon rank B)

The inline vestigial-target strip pushed _build_confirm_batch to cyclomatic
rank C (over the --max-absolute B gate). Move the assigned_to + top-level
project/product stripping into a pure _batch_subtask_draft helper; behavior is
unchanged, _build_confirm_batch drops back under the limit.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 03:59:13 +02:00
2297d448f3 fix(prompter): keep a watched intake chat alive (idle-reap counted reading as idle) (#379)
* fix(prompter): keep a watched intake chat alive (idle-reap counted reading as idle)

Intake chats "dropped after a while" — the panel showed "Live connection lost".
The idle reaper retires an interactive session whose last_activity is older than
interactive_idle_reap_seconds (30m default), but last_activity was bumped only by
an agent event or a human turn. An open SSE stream — the human reading a proposed
draft / MegaTask spec without typing — bumped nothing, so a chat under active
review was reaped mid-read, closing the stream (the SSE transport error the panel
reports as "Live connection lost").

stream() now runs a keepalive task that refreshes last_activity every 60s while
the stream is connected, so an open, actively-watched chat counts as alive; when
the tab closes the generator ends, the keepalive is cancelled, and a genuinely
abandoned chat still reaps after the threshold. The keepalive runs beside an
un-cancelled queue.get() so no live token or the close sentinel can be dropped.

* fix(tests): conventions PR integration test honors the #375 workspace-scope guard

#375 added a containment guard to open_conventions_pr (workspace_path must sit
under {workspaces_root}/{slug}); the unit test was updated but this integration
test still seeded a bare tmp_path/repo, so open_conventions_pr returned None and
test_open_conventions_pr_commits_locally_without_remote failed on master. Anchor
workspaces_root at the test dir and place the repo under the project's slug.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 03:58:37 +02:00
3787d15524 fix(agents): block subagent spawning at the Claude Code level (disallow Task) (#377)
The fleet-wide subagent ban was implemented as an allowlist omission, but Task
is a default-permitted Claude Code built-in — an allowlist auto-approves, it
does not restrict. Under permission_mode="dontAsk" (intake/secretary SDK) and
defaultMode="bypassPermissions" (fleet), Task ran regardless and can_use_tool
was never invoked for it, so every Claude-path agent could still spawn
subagents despite allows_subagent=False. Only the grok path blocked it.

Explicitly disallow the subagent tool at every Claude-path spawn point:
disallowed_tools=["Task"] on the intake and secretary SDK drivers, and "Task"
in the fleet settings.json base_deny (an explicit deny applies even under
bypassPermissions). This mirrors the grok path's --disallowed-tools Agent.

Pins the ban in test_cc_lockdown.py (fleet settings deny Task) and a new
test_sdk_driver_subagent_ban.py (intake + secretary options disallow Task).

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 02:37:12 +02:00
92410d47cf fix(prompter): MegaTask review card scrolls + confirm-batch guard releases on failure (#376)
The MegaTask review card was a static sibling of the scrollable chat list with
no height bound, so a tall batch overflowed the clipped container and stranded
the launch buttons off-screen with no scrollbar. It now owns the scroll area
(min-h-0 flex-1 overflow-y-auto), matching the pattern ChatMessages already uses.

confirm_live_batch's Redis idempotency guard (1h TTL) was acquired before the
build but only released via a success sidecar, so a build failure wedged the
session: every retry hit ServiceError("already in progress") -> HTTP 500 for an
hour. The build now releases the guard on any failure before the sidecar write,
so a retry re-attempts (and surfaces the real error) instead of being locked out.
Extracted _build_confirm_batch to keep the try/except thin.

Adds DB-backed tests for the panel the_work[].project_id shape, multi-cell
root-subtasks, dense same-repo collisions (both routes), and guard release.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 00:15:28 +02:00
7be725cc13 fix(security): disposition all 104 code-scanning + dependabot alerts (#375)
Fix the 4 real CodeQL path-injection alerts (open_conventions_pr trusted the
API-settable project.workspace_path with no containment) plus defense-in-depth
segment validation at the get_workspace_path chokepoint. Bump next 16.1.1->16.1.7
and transitive lockfile deps to clear 24 Dependabot alerts. Close the intake
subagent-ban gap: the Claude intake driver still carried the Task tool and the
prompter prompt told it to fan out research subagents, contradicting the
fleet-wide ban. The remaining 47 CodeQL + 29 Dependabot alerts are dismissed on
GitHub with per-alert justifications (guard patterns CodeQL can't model across
call hops; next 16.2.x blocked by the verified tab-hostage router regression).

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-10 00:15:04 +02:00
0450ec9e89 feat(x-engine): smart spotlight cadence — daily when there's news, quiet when there isn't (#374)
CEO verdict on the blind 3-day timer: 'It should default to 1 day and
be more like... smart.' Now: interval defaults to 1 day; the cycle
skips (with logged reasons) while a spotlight draft is still awaiting
the CEO, and stretches to 3x the interval when nothing has shipped
(CHANGELOG sections via the read clone) since the last spotlight
activity — where activity is a materialized draft's seen_at or a
completed exploration's updated_at, deliberately excluding the stale-
cycle janitor's cancels. The HoM gains an explicit skip exit
(propose_feature_spotlight skip=true + reason: completes the
exploration, no draft, no seen-slug, still counts as activity), and
its spawn prompt now carries the seen ledger WITH dates, what shipped
since the last spotlight, and recently rejected drafts with the CEO's
reasons — fresh-but-unspotlighted first. Fail-open on changelog read
errors so a signal outage never starves the engine.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 20:59:53 +02:00
3cb32e3c5f fix(release-recap): darkmode logo hero — the commit that missed the #333 merge (#373)
* [e0bc418f] add v019-release HyperFrames composition with vertical/square cuts, theme, props, and smoke tests

* [e0bc418f] fix(v019-release): remove local artifacts, replace em dashes, add captions.json and regression tests

* [e0bc418f] chore: delete .venv symlink and tighten .gitignore for symlink leakage

* [e0bc418f] chore(.gitignore): remove duplicate .pnpm-store line

* [e0bc418f] fix(v019-release): clean internal em dashes and add package-lock regression test

* [e0bc418f] chore(v019-release): remove committed vitest cache artifact from node_modules

* [e0bc418f] fix(.gitignore): restore .pnpm-store/ next to its GH001 comment and remove stray duplicate

* [e0bc418f] docs(motion): document v019-release composition and captions convention

* [e0bc418f] feat(release-recap): rebuild v0.19.0 video as panel-demo three-release recap

CEO rejected the text-card v019-release composition and rescoped this
to a recap of three releases (0.18.0-0.20.0) shipped in six days,
built in the panel-demo register per the CEO's brief. Brings
motion/kit/ and motion/compositions/panel-demo/ into this branch
(byte-identical to master, which merged them after this branch
diverged and cannot be rebased onto directly), deletes the obsolete
motion/compositions/v019-release/ text-card composition, and adds
motion/compositions/release-recap/: the panel frame, one intake typing
reveal, three release cards (v0.18.0/v0.19.0/v0.20.0) cycling through
a single shared kanban slot with their own progress-to-completed pill
flip, a cursor that glides in once and click-pulses at each flip, a
closing toast, and the roboco.tech outro, both at 1080x1920 and
1080x1080. Includes props.js, captions.json (X 136/280 chars, TikTok
365/2200 chars, no em dash), and a vitest smoke test (11/11 passing
across all three compositions in the package). Also refreshes
motion/README.md with the current design-bar/panel-demo-kit sections
and a release-recap example replacing the deleted v019-release one.

* [e0bc418f] fix(release-recap): polish pass — accumulate the three releases, fix facts, robust typewriter

Cards now stack and accumulate instead of cycling one absolute slot (the
three-release story never landed visually); duration tightened 20s to
15s; per-release copy corrected (0.18.0 fleet doctrine + design bar,
0.19.0 video engine + sandboxes, 0.20.0 root-owned coverage + the kit)
along with the same fixes in captions.json; one cursor with one glide
and one click landing at the pill edge instead of parking on pill text
for 17s; the per-char typing reveal (which partially froze) replaced by
a single width-steps mono typewriter sized to the supplied text.

* [e0bc418f] feat(release-recap): identity redesign — real logo, real-UI sidebar, explainers, stat beat

CEO review round 2: no logo, no similarity with the actual UI, explains
nothing. Rebuilt: branded cold open (the real logo on an app-icon tile
with a ring sweep, wordmark, tagline), a labeled sidebar mirroring the
real panel (nav labels + active state + search + Live dot + CEO chip),
a one-line explainer under each release title, a kinetic stat beat
(3 releases / 6 days / 1 human — full-frame interstitial on the square
cut where no side zone exists), and a logo lockup outro; 18s. The logo
PNG is vendored into motion/public (offline constraint, same pattern
as the fonts).

* [e0bc418f] fix(release-recap): darkmode logo hero — crisp 1024px mark replaces the pixelated 64px tile

The cold open now uses logos/roboco-logo-darkmode.png (vendored into
motion/public), built for dark backgrounds with the wordmark included:
full-size mark with a soft glow and the ring sweep, no white tile, no
separate typed wordmark. The small app-icon tiles in the sidebar and
outro keep the 64px icon where tiny sizes favor it.

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 19:21:47 +02:00
Renn F 1c799ea139 fix(tests): grok session test pins the fleet-wide subagent ban
The last test asserting the prompter kept the Agent tool — it pinned
the allowance through the disallowed-tools string, which the #372 test
sweep (grepping the flag names) missed.
v0.21.0
2026-07-09 18:53:28 +02:00
6188cce58c [e0bc418f] Video: v0.19.0 - our newest release (#333)
* [e0bc418f] add v019-release HyperFrames composition with vertical/square cuts, theme, props, and smoke tests

* [e0bc418f] fix(v019-release): remove local artifacts, replace em dashes, add captions.json and regression tests

* [e0bc418f] chore: delete .venv symlink and tighten .gitignore for symlink leakage

* [e0bc418f] chore(.gitignore): remove duplicate .pnpm-store line

* [e0bc418f] fix(v019-release): clean internal em dashes and add package-lock regression test

* [e0bc418f] chore(v019-release): remove committed vitest cache artifact from node_modules

* [e0bc418f] fix(.gitignore): restore .pnpm-store/ next to its GH001 comment and remove stray duplicate

* [e0bc418f] docs(motion): document v019-release composition and captions convention

* [e0bc418f] feat(release-recap): rebuild v0.19.0 video as panel-demo three-release recap

CEO rejected the text-card v019-release composition and rescoped this
to a recap of three releases (0.18.0-0.20.0) shipped in six days,
built in the panel-demo register per the CEO's brief. Brings
motion/kit/ and motion/compositions/panel-demo/ into this branch
(byte-identical to master, which merged them after this branch
diverged and cannot be rebased onto directly), deletes the obsolete
motion/compositions/v019-release/ text-card composition, and adds
motion/compositions/release-recap/: the panel frame, one intake typing
reveal, three release cards (v0.18.0/v0.19.0/v0.20.0) cycling through
a single shared kanban slot with their own progress-to-completed pill
flip, a cursor that glides in once and click-pulses at each flip, a
closing toast, and the roboco.tech outro, both at 1080x1920 and
1080x1080. Includes props.js, captions.json (X 136/280 chars, TikTok
365/2200 chars, no em dash), and a vitest smoke test (11/11 passing
across all three compositions in the package). Also refreshes
motion/README.md with the current design-bar/panel-demo-kit sections
and a release-recap example replacing the deleted v019-release one.

* [e0bc418f] fix(release-recap): polish pass — accumulate the three releases, fix facts, robust typewriter

Cards now stack and accumulate instead of cycling one absolute slot (the
three-release story never landed visually); duration tightened 20s to
15s; per-release copy corrected (0.18.0 fleet doctrine + design bar,
0.19.0 video engine + sandboxes, 0.20.0 root-owned coverage + the kit)
along with the same fixes in captions.json; one cursor with one glide
and one click landing at the pill edge instead of parking on pill text
for 17s; the per-char typing reveal (which partially froze) replaced by
a single width-steps mono typewriter sized to the supplied text.

* [e0bc418f] feat(release-recap): identity redesign — real logo, real-UI sidebar, explainers, stat beat

CEO review round 2: no logo, no similarity with the actual UI, explains
nothing. Rebuilt: branded cold open (the real logo on an app-icon tile
with a ring sweep, wordmark, tagline), a labeled sidebar mirroring the
real panel (nav labels + active state + search + Live dot + CEO chip),
a one-line explainer under each release title, a kinetic stat beat
(3 releases / 6 days / 1 human — full-frame interstitial on the square
cut where no side zone exists), and a logo lockup outro; 18s. The logo
PNG is vendored into motion/public (offline constraint, same pattern
as the fonts).

* [e0bc418f] fix(release-recap): darkmode logo hero — crisp 1024px mark replaces the pixelated 64px tile

The cold open now uses logos/roboco-logo-darkmode.png (vendored into
motion/public), built for dark backgrounds with the wordmark included:
full-size mark with a soft glow and the ring sweep, no white tile, no
separate typed wordmark. The small app-icon tiles in the sidebar and
outro keep the 64px icon where tiny sizes favor it.

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 18:48:46 +02:00
Renn F a322dc8f9f chore(release): 0.21.0 2026-07-09 18:41:58 +02:00
Renn F e1a8734daa fix(tests): hoist ROLE_CONFIGS import in the subagent invariant test
PLC0415 red on master's quality gate — the module already imports
ROLE_CONFIGS at top level; the function-level re-import from #372's
invariant test is deleted.
2026-07-09 18:40:12 +02:00
7bc42ec114 fix(runtime): fleet-wide subagent ban — no role fans out, not one (#372)
CEO directive 2026-07-09: every allows_subagent in role_config flips to
False (was True for cell_pm, main_pm, product_owner, head_marketing,
prompter, secretary); the grok path's drifted _SUBAGENT_ALLOWED_ROLES
allowlist empties to match. The spawn manifest already consumes the
flag, so Claude-path agents lose the Agent tool and grok-path agents
get it in disallowed-tools by construction. New invariant test iterates
every role config so a single role can't quietly regain it.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 17:14:13 +02:00
d585260087 fix(panel): pin next to 16.1.1 — 16.2.x breaks searchParams soft navigation in Chrome (#371)
Every URL-driven tabbed page (kanban/business/metrics/notifications/KB)
was stuck on the first tab in real Chrome 149 against a production
build: clicking a tab fetched the target RSC payload, then Next's
router MPA-reloaded the CURRENT url, snapping the tab back. Bisected
empirically with a scripted real-Chrome sweep: 16.1.1 green, 16.2.6
red, 16.2.10 (latest stable) red — the regression spans the 16.2 line
and reproduces with zero app data, no proxy, and a fresh profile. Dev
builds and Playwright's bundled Chromium mask it, which is how the
#354 bump (shipped in v0.20.0) passed review. Reverts the next half of
that bump; the axios half stays.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 16:26:42 +02:00
Renzo FandGitHub e1d1fdc707 Merge pull request #370 from rennf93/fix/gateway/sync-branch-standalone-base 2026-07-09 13:21:03 +02:00
Renn F a87b55f748 ci(cla): allowlist the org's own agent identities
Agent workspace clones commit as '<Display Name> <slug@roboco.tech>';
the emails map to no GitHub account, so CLA Assistant identifies those
committers by display name and reds any PR carrying agent-authored
commits with a signature no agent can post (live on PR #333). The
fleet is the org's own machinery, not an external contributor — the
roster names are allowlisted, wildcarded per team family.
2026-07-09 12:19:11 +02:00
Renn F 213b6ba830 refactor(gateway): fold sync_branch base refusal into one helper for the xenon budget
The inline compound condition pushed _sync_branch_preflight_rejection
to cyclomatic rank C on the PR gate; the whole refusal predicate now
lives in _sync_base_refused.
2026-07-09 12:14:10 +02:00
Renn F 93f63d5fe9 fix(gateway): allow sync_branch onto a legitimately-master base
A standalone task (video/CI-watch/dep-update — no parent) and a child
of a branchless coordination parent merge into the project default
branch by design, but the protected-base guard refused every
master/main base, hard-wedging their rebases into block/PM/respawn
churn (hit live on the v0.19.0 video task). The rebase force-pushes
only the task branch (with lease) and cannot write to the base, so the
guard now refuses master/main only when it is mis-resolved: a
branch-bearing parent exists or the parent row is missing/corrupt.
The '-'-prefixed injection guard stays unconditional.
2026-07-09 08:44:11 +02:00
18998c4a42 Video pipeline fixes: visibility strip, rich briefs, spotlight timing + fps (#369)
* feat(video): pipeline visibility — strip, state-aware queue, render-error capture

Task 1 of the 2026-07-09 video-pipeline review. New CEO-gated GET
/video/pipeline lists every in-flight video item (authoring statuses,
rendering attempt n/max, terminal failures with the error — now stamped
onto the video_draft marker instead of dying as a log line).
source_task_id exposed on both video schemas. Panel: pipeline strip on
the Social page, state-aware queue empty copy, title/script on queue
rows, missing cuts disabled instead of a blank player, notifications
deep-link related_task_id. MAX_VIDEO_RENDER_ATTEMPTS moved to the
markers policy layer (single source of truth).

* feat(video): rich authoring briefs — changelog section, brand voice, kit pointer

Task 2 of the 2026-07-09 video-pipeline review. The release brief is
now a structured block (full CHANGELOG section capped at 4000 chars +
highlights) instead of one LLM-compressed sentence; brand_voice and a
motion/kit design-bar pointer are appended centrally in open_video_task
so release, spotlight, and on-demand paths all inherit them.
suggested_input_props seeded on the video_draft marker; third
acceptance criterion pins the design bar; propose_video docstring
points at the kit.

* fix(video): spotlight video drafts on CEO approval, renderer honors data-fps

Task 4 of the 2026-07-09 video-pipeline review. The companion-video
hook moves from propose_feature_spotlight (HoM authoring time) to
XPostService approve's posted-success branch for x_feature drafts,
mirroring the release-publish seam — a rejected spotlight no longer
burns a ux-dev cycle; wants_video/video_script ride the x_feature_ref
marker. Best-effort: a video-engine failure never breaks the post.
render.js reads data-fps from the composition HTML (clamped 24-60,
fallback 30) instead of hardcoding 30; parseFps covered by node --test.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 08:31:08 +02:00
Renn F 12b91d17a2 chore(lifecycle): regenerate stale verb-table artifacts
Verb-description changes from the recent gateway PRs (declare_coverage,
sync_branch stash, reviewer unclaim) never regenerated the artifacts;
the master gate died at reflow-check before foundation-check could
flag it.
v0.20.0
2026-07-09 07:22:34 +02:00
Renn F 9e6f3a5c6c docs(motion): reflow hard-wrapped prose + lock 0.20.0
The kit READMEs from #365 were hard-wrapped and failed the master
quality gate's reflow-check (the gate runs on master pushes, not PRs).
uv.lock picks up the 0.20.0 project version from the release bump.
2026-07-09 07:03:51 +02:00
Renn F 80e54390dc + uv.lock 2026-07-09 07:03:32 +02:00
Renn F 7b6eaa47c8 chore(release): 0.20.0 2026-07-09 06:59:59 +02:00
dd71eb381e feat(motion): panel-demo kit + reference composition (#365)
Reusable pk-* building blocks (motion/kit/) that recreate the control
panel's look for HyperFrames compositions: frame chrome, task card,
status pills with swap crossfade, chips, toast, typing reveal, cursor
sprite. Tokens lifted from the panel's dark theme and badge components.

Reference composition motion/compositions/panel-demo/ (12s, both cuts):
a task title types into intake, the card materializes, the cursor
clicks, the status pill flips to completed, a toast slides in.

Verified: motion vitest gate green (7/7); both cuts visually checked
in-browser at native resolution.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 06:44:55 +02:00
08c02e2251 [79d686f0] Add page-scoped refresh button to the navbar (#351)
* [870467e6] Frontend: page-scoped refresh provider, hook, and navbar button (#347)

* [55376b8a] Create page-scoped refresh provider and context (#327)

* [55376b8a] feat(panel): add page-scoped refresh context and provider

* [55376b8a] docs(frontend): add page-refresh-provider component documentation

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [a0c02d0f] Add public usePageRefresh hook (#332)

* [a0c02d0f] test(hooks): assert usePageRefresh is exported from hooks barrel

* [a0c02d0f] feat(hooks): add public usePageRefresh hook with provider and tests

* [a0c02d0f] fix(panel): move hook test wrappers to components and rename providers.tsx to unshadow barrel

* [a0c02d0f] docs(panel): document usePageRefresh hook and PageRefreshProvider API

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>

* [5f28dd9b] Add navbar refresh button and remove inline dashboard refresh buttons (#336)

* [5f28dd9b] Align PageRefreshProvider with active hook API and remove inline dashboard refresh buttons

* [5f28dd9b] Remove unused scope-keyed PageRefreshProvider, context, and associated tests

* [5f28dd9b] Address QA revision: add header refresh tests, page-scoped label, remove dead provider code and .venv symlink, revert formatting-only changes

* [5f28dd9b] Remove remaining inline dashboard refresh buttons and committed .venv symlink

* [5f28dd9b] docs(frontend): update page-refresh provider docs and panel README for navbar refresh button

* [5f28dd9b] fix(panel): remove .venv symlink, ignore root .venv entries, and thin task-detail page data fetch into useTaskDetail hook

* [5f28dd9b] Extract GitBrowser data fetching into useGitBrowser hook and add tests; verify .venv cleanup and task-detail thin hook usage

* [5f28dd9b] fix(panel): remove root .venv symlink, restore .gitignore anchored rule, and revert lifecycle.json formatting noise

* Delete .venv

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>

* [b8e1de1b] Fix navbar refresh button disabled state when registry is empty (#356) (#358)

* [b8e1de1b] fix(panel): derive navbar refresh disabled state from registry, not unused prop

PageRefreshProvider now computes `disabled` from whether any refresh
callback is currently registered (registry size > 0) instead of a
static, never-passed `disabled` prop that left the button permanently
enabled. header.tsx now destructures `disabled` from usePageRefresh()
and disables the button on `disabled || loading`. Updated the tests
that asserted the old always-enabled-by-default behavior and added a
new header test asserting the button is disabled with zero registered
callbacks.

* [b8e1de1b] docs(panel): document PageRefreshProvider disabled state derived from registry

Updated documentation to reflect the refactored PageRefreshProvider behavior: the `disabled` state is now derived from whether any refresh callbacks are currently registered (empty registry = disabled), rather than a static `disabled` prop. Clarified in both panel/README.md and the full component guide that the navbar refresh button disables when no callbacks are registered and when a refresh cycle is in progress. Updated API documentation to remove the now-removed `disabled` prop from PageRefreshProviderProps and updated code examples and test coverage descriptions to reflect the new callback-driven semantics.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* test(panel): mock usePageRefresh in tests predating the provider

Merge-skew: the page-refresh feature makes CommandCenter and the agent
detail page call usePageRefresh; three tests merged from master render
them without the new provider. Mock the hook module, matching the
files' stub-everything style.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 05:27:14 +02:00
ec5323917e [d8a2999b] CI-watch: fix the CI regression on roboco-api (#364)
* [ffcc7317] fix(tests): tolerate tagless checkouts in release-readiness smoke test (#362) (#363)

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>

* docs: reflow panel/UPGRADE.md — no hard-wrapped prose

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 05:26:30 +02:00
Renzo FGitHubFrontend Developer 1Frontend Documenterdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0888fefdac [3f57bfb0] Supersede external PR #344: finish + harden it ourselves (#360)
* chore(deps): bump axios from 1.13.2 to 1.16.0 in /panel

Bumps [axios](https://github.com/axios/axios) from 1.13.2 to 1.16.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.16.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.16.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* [47c230b6] Finish + harden axios dependency bump (supersedes PR #344) (#355)

* [9a0e97fb] Bump axios to ^1.16.0 and verify build/lint/typecheck/test (#349)

* [9a0e97fb] chore(panel): regenerate lockfile for axios ^1.16.0 (1.18.1)

* [9a0e97fb] docs(changelog): document axios ^1.16.0 bump with new transitive deps

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [2b0d5fe8] docs(api-client): record axios 1.16 compatibility audit finding (#352)

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [36ae2ab0] Remove stray .venv symlink and harden .gitignore (#359)

* [36ae2ab0] chore(repo): remove stray .venv symlink and harden .gitignore

Removes the tracked .venv symlink at the repository root and drops
the trailing slash on the .gitignore .venv entry so the pattern
matches a symlink or plain file named .venv, not only a real
directory.

* [36ae2ab0] chore(repo): untrack the .venv symlink from the branch

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
2026-07-09 03:47:43 +02:00
47c927c598 feat(gateway): root-owned acceptance criteria via declare_coverage (#357)
The coverage gates had no vocabulary for criteria only the root itself
can satisfy (the supersede PR from feature/main_pm/*, closing the
contributor's PR): once a Main PM declared coverage for the legitimate
cell criteria, the idle gate demanded a cell for the impossible ones
too, so they got pushed into a cell task and the cell PM (correctly)
escalated. declare_coverage now accepts the PM's own task: self-declared
criteria count as claimed for the idle gate and satisfied for the
roll-up (the roll-up actor is their owner by construction), surface as
claimed_by=root in the briefing, and both PM prompts say to never hand
a cell a criterion it cannot satisfy inside its own cell.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 03:17:20 +02:00
Renzo FGitHubFrontend Developer 1Frontend Documenterdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8327df4fd2 [f9ab9c9d] Supersede external PR #343: finish + harden it ourselves (#354)
* chore(deps): bump next from 16.1.1 to 16.2.6 in /panel

Bumps [next](https://github.com/vercel/next.js) from 16.1.1 to 16.2.6.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.1.1...v16.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* [bd79402c] Verify and harden panel/ on Next.js 16.2.6 (#350) (#353)

* [bd79402c] chore(panel): align eslint-config-next to 16.2.6 with next

* [bd79402c] docs(panel): add UPGRADE guide and dependency alignment note

Documented the Next.js 16.2.6 dependency bump and version-alignment requirement for eslint-config-next. Added UPGRADE.md with procedures for future Next.js bumps and troubleshooting, and updated README.md with a dependency management section pointing to the guide.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
2026-07-09 03:05:10 +02:00
94dd6b6d53 chore(prompts): decomposition minimalism — fewest subtasks the work needs (#348)
CEO doctrine after an axios bump became a planning parent plus two
sequenced same-branch code children: single-concern work is ONE subtask
covering change, verification, and PR; same-branch sequenced siblings
are one task wearing two ids (the gateway serializes sibling code
subtasks anyway, so the split buys zero parallelism); the i_will_plan
sub_tasks list is a checklist, not a delegation quota.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 02:25:32 +02:00
199cc5d2bc fix(api): run the RAG reconcile in the background, never on the bind path (#346)
The lifespan awaited the reconcile, and the journal/learning backfill
made it expensive: up to 200 entries each needing an Ollama embedding
behind a busy Ollama held the API bind down for 30+ minutes on the NAS
(observed: ~6 embeds/min). uvicorn only binds after the lifespan
completes, so the whole stack 502'd while a best-effort maintenance
pass ran. The reconcile is now a background task scheduled at the end
of startup (crash-logged via done-callback, cancelled at shutdown); the
backfill still converges across boots under its per-boot cap.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 01:59:23 +02:00
f0b6390189 feat: Social page — aggregated post queues + X/video history (#345)
* feat(api): x/video post history endpoints

Approved or rejected drafts vanished from both queues permanently --
the listers exclude terminal statuses and no history surface existed,
so a posted tweet or video was only findable in the raw task list.
GET /x/posts/history and GET /video/posts/history (CEO-gated, bounded)
return acted-on drafts newest-first with the posted platform ids and
reject reasons from the draft markers. Route tests assert by identity,
not emptiness: approve/reject commits the whole session, so prior
tests' rows legitimately persist in the shared test DB.

* feat(panel): Social page aggregating post queues and history

New dashboard page composing the X and video post queues with one
unified history section beneath them -- both platforms interleaved
newest-first, kind and outcome badges, posted X ids linking to the
live tweet, reject reasons shown. The command center's two full queue
cards become a compact pending-counts card linking to the page, so the
queues have one home instead of duplicated surfaces.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 00:44:51 +02:00
5886336259 fix(db): latch init_db per database and time-bound the alembic runner (#342)
Bootstrap and the API lifespan both ran init_db in one process seconds
apart; the second call re-entered the alembic-in-thread machinery
(nested asyncio.run + NullPool engine + greenlet bridge in a reused
worker thread) for zero benefit and hung two consecutive NAS boots
there, blocking the API bind forever with zero SQL activity. init_db
now latches per database URL (drop_db resets it; a different DB always
runs fully), and the alembic worker is bounded at 300s -- a wedged
thread fails startup loudly with a pinpointed error so the container
restarts into a clean retry instead of hanging silently.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-08 23:39:39 +02:00
Renn F 5e7c498d00 fix(runtime): auto-submit is unconditional; refusals brief the fallback PM
The PR-gate turn cut (#295) already auto-submitted assembled tasks, but
its refusals fell back to a PM spawn silently -- in production the PM
turns the cut was meant to remove kept happening with no visible cause
(live case: an AC-coverage refusal). The flag is gone (the fallback is
the safety net), the umbrella/branchless exclusion uses the canonical
batch predicates, and every refusal reason now rides into the spawned
PM's prompt so the fallback starts informed.
2026-07-08 22:16:50 +02:00
f48d088c08 fix(gateway): working exits for wedged agents + declare_coverage roll-up unblock (#341)
A live task burned 5+ hours because every exit was locked. unclaim now
works from verifying and needs_revision (service guard + lifecycle edge);
the circuit breaker and the i_am_done push-failure remediate name the
working chain ending in unclaim(); sync_branch(stash=true) clears the
DIRTY_WORKSPACE dead-end (pop-conflict preserves the stash); blocking a
task QA already owns now says to idle instead of listing states; the
orchestrator auto-block logs real errors and skips states where blocking
is meaningless instead of force-blocking them.

declare_coverage (cell/main PM) retroactively stamps parent-AC refs on a
child that implements them -- closing the roll-up deadlock where the
declaring child was cancelled and its re-delegated replacement completed
the work uncredited. Cancelling a ref-declaring child now warns and
surfaces the orphaned criteria.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-08 21:40:22 +02:00
Renn F 889d48b99b Merge branch 'master' of https://github.com/rennf93/roboco into fix/backend/video-renderer-producer-api 2026-07-08 16:40:42 +02:00
47d78f50ee feat(sandbox): on-demand provisioning via request_sandbox verb (#338)
* feat(sandbox): on-demand request_sandbox verb replaces eager provisioning

Sandboxes were provisioned at every agent spawn for opted-in projects,
so every role paid the sidecar spin-up and a provisioning failure
refused the spawn. Provisioning now happens when an agent asks: the
request_sandbox do-verb (dev + QA) reaches the orchestrator through
ContentActionsDeps, ensure_sandbox provisions idempotently with an
in-memory per-agent cache (evicted at teardown and janitor sweep), and
creds return in the envelope payload including ready-to-export
ROBOCO_TEST_* values. Spawn now only injects a marker env naming the
available services plus a briefing line; sandbox failures can no longer
refuse a spawn. Teardown lifecycle unchanged.

* feat(sandbox): harden request_sandbox + Phase 3 wiring proof and docs

Hardening from adversarial review: ensure_sandbox now provisions the
project's full opted-in set on first request (a later superset can
never tear down a live sandbox mid-use), serializes per-agent behind an
asyncio lock (a client timeout-retry no longer races its own in-flight
provision), and verifies container liveness on every cache hit (a dead
sandbox evicts and re-provisions instead of serving dead creds). MCP
client budget 720->1080s for the full-set cold case. Phase 3: e2e smoke
wiring test (manifest grants + guard-chain envelopes over the real
API), sandbox-db/tools/map docs and CLAUDE.md rewritten for on-demand.

* feat(sandbox): release sandboxes when the agent's work ends

CEO directive: sidecars must not dangle once the agent is done. The six
work-ending verbs (i_am_done, unclaim, i_am_idle, pass_review,
fail_review, i_documented) now release the caller's sandbox best-effort
on their success path via release_sandbox (lock + teardown + cache
evict; a no-sandbox agent costs a dict lookup). Container removal and
the janitor remain the backstop; a re-request provisions fresh.

* test(sandbox): monkeypatch the release hook instead of method assignment

mypy method-assign rejected the direct AsyncMock assignments; the prior
static gate ran before this test file landed.

* test(sandbox): guard envelope evidence for mypy in verb tests

* chore(prompts): regenerate verb tables for request_sandbox

* chore: resolve merge with master (breadcrumbs + statement budget)

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-08 16:40:02 +02:00
9e4025b822 fix(git): scope post-op ownership repair to what the op could change (#337)
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-08 16:38:32 +02:00