mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
388bab24881c8ef3877668df5fbb5f47e86a7e4f
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
388bab2488 |
feat(forge): Phase 0 — git_provider column + registration-time forge validation (#569)
* feat(forge): Phase 0 — git_provider column + registration-time forge validation Pointing a project at a GitLab/Gitea git_url used to fail silently, several steps deep, at first PR. New pure policy module (foundation/policy/forge.py) detects the provider from the git_url host and validates at the ProjectService create/update chokepoint: github auto-detects and auto-stamps, explicit git_provider=github is the GitHub Enterprise escape hatch, gitlab/gitea are recognized-but-not-yet-supported, unknown hosts get a loud rejection with guidance. An update changing git_url does NOT inherit a stored auto-stamped provider (restating the override is required), so a host swap can't smuggle the escape hatch past validation. Migration 075 adds the nullable projects.git_provider column; the panel project dialogs show the detected forge. Phase 0 of the forge-providers spec. * fix(panel): mock-mode forge detection extracts the real host CodeQL js/incomplete-url-substring-sanitization: the substring check matched github.com anywhere in the URL. Extract the hostname (URL parse or scp-form regex, mirroring forge.py) and require an exact match. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
ec6558e168 |
[2a86d1f5] CI-watch: fix the CI regression on roboco-api (#563)
* [e530aa5e] Diagnose and fix roboco-api CI failure (run 29629255153) (#561) (#562) * [e530aa5e] fix(tests): narrow None before indexing validate_init_data() result in telegram_initdata self-check CI run 29629255153 failed on mypy, not the historical pydantic-settings issue (uv.lock already pins 2.14.2). The __main__ self-check block in test_telegram_initdata.py indexed the dict[str, object] | None return of validate_init_data() without narrowing away None first. * [e530aa5e] docs(qa): document CI fix for mypy type narrowing in telegram_initdata test Explains the root cause (mypy type error in __main__ block), the solution (None narrowing before indexing), and the safe pattern for future test self-checks that call functions returning optional types. --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [0884b737] Diagnose and fix Python quality gate + e2e lifecycle smoke CI failures on PR #563 (#564) (#565) * [0884b737] fix(tests): isolate ROBOCO_SDK_URL for scripted e2e-smoke agents tests/e2e_smoke/harness.py already isolates ROBOCO_AGENT_TOKEN from the host environment (the #503/#504 fix) but left ROBOCO_SDK_URL leaking through. flow_server/do_server both default it to http://localhost:9000 and forward every rejection there for the per-verb circuit breaker; inside a real spawned agent container that port is a live SDK loopback, so the breaker records genuine attempts for the ephemeral test-agent IDs and trips circuit_open mid-test (test_sandbox_on_demand.py::test_request_sandbox_guard_chain_over_real_api, which deliberately causes 3 rejections in a row). Point it at a guaranteed-refused loopback address so every environment gets the same fail-open bypass a bare CI runner already gets by having nothing listening on 9000 at all. * [0884b737] docs(changelog): document e2e-smoke harness ROBOCO_SDK_URL isolation fix Document the fix that isolates ROBOCO_SDK_URL in the ScriptedAgent harness to prevent the per-verb circuit breaker from leaking state into ephemeral test-agent identities when the e2e-smoke suite runs inside a live agent container. This ensures the suite passes consistently regardless of whether it runs on bare CI or inside a spawned agent. --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [3b9a1771] Diagnose and fix ALL make quality + e2e-smoke stage failures on PR #563; confirm real CI green (round 3) (#566) (#567) * [3b9a1771] fix(e2e-smoke): match real embedding dimension when seeding fake journal chunk test_c3_deleted_journal_unindexed inserted a 4-dim placeholder vector into chunks_journals, but the e2e stack's app lifespan eagerly creates that table with the real settings.embedding_dimensions (1024) before the test runs, so the insert failed with "expected 1024 dimensions, not 4". Derive _SMOKE_DIM from settings.embedding_dimensions instead of a hardcoded constant so the seeded vector always matches the table's actual column width. * [3b9a1771] docs(qa): document e2e-smoke embedding dimension fix in round 3 CI diagnosis Recorded the root cause, solution, and pattern for the final e2e-smoke test failure found in comprehensive sandbox testing: the test seeded a 4-dim placeholder vector but the app's eager lifespan init created chunks_journals with the real 1024-dim embedding column. Updated _SMOKE_DIM to derive from settings.embedding_dimensions instead of a hardcoded constant. --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> |
||
|
|
ff78618b76 |
feat: Telegram messages get real formatting + push DMs at draft origination (#568)
* feat(telegram): HTML-styled bot messages + push DMs at held-draft origination * fix(telegram): attr-context escaping, balance-aware truncation, send observability; docs --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f0782cb858 |
chore(panel): selective dependency updates — Next family held at the 16.1.x pin (#560)
Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
713f91320a |
feat: Journals joins the Agents hub — third tab (#559)
* feat(panel): Journals joins the Agents hub as its third tab * docs(map): Journals tab on the Agents hub; registry retargets --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
4480dfe8d1 |
feat: Agents hub — Fleet + Conversations tabs, /a2a merged in, DM quick-action (#558)
* feat(panel): Agents hub — Fleet and Conversations tabs, /a2a redirect, DM quick-action * fix(panel): validate deep-linked DM targets against roster and exclusions; re-arm the dm latch * docs(map): panel entries for this wave --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
1a726d4c34 |
feat: customizable Quick Actions on the Overview dashboard (#557)
* feat(panel): customizable Quick Actions on Overview — registry, defaults, persisted picker * fix(panel): legacy bar actions join the quick-action defaults; empty state; persist-contract test * docs(map): panel entries for this wave --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
02601fef22 |
feat: Workstation card grids — view toggle, sorting, agent-card visual language (#556)
* feat(panel): Workstation card grids with persisted view toggle and sorting * fix(panel): stable multiplier sort with cell-label fallback after adversarial review * docs(map): panel entries for this wave --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
59594d794a |
fix(deploy): resync compose twins with a quality-gate guard; wire cloud-auth env through; regenerate .env.example; reconcile registry drift (#555)
Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
c40a7a39c3 |
feat: Telegram V3 — Mini App cockpit (initData auth + /tg surface) (#554)
* feat(telegram): Mini App auth — initData validation mints the cloud-auth session cookie * feat(panel): /tg Mini App cockpit — approvals, inbox, read-only board, A2A chat * fix(telegram,panel): unconditional webapp-auth rate limit, future-dated initData rejection, anchored /tg matcher * docs(map,rag): Telegram Mini App auth route, initData validator, (tg) surface --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
3b88c706dd |
docs(map): full _complete_map rebuild from current slices; motion-commit debt cleared (#553)
Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
2a5820cb07 |
fix(motion): release-recap beats off clip windows onto base-hidden delayed animations (#552)
Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
9fbec78126 |
feat: Telegram V2 — inbound commands + actionable approve/reject from chat (#551)
* feat(telegram): V2 inbound — command router, actionable approve/reject keyboards, chat-gated poll loop * fix(release,x,video,telegram): terminal-state guards on approve/reject; sender-identity check * docs(map,rag): Telegram V2 inbound surfaces and terminal-state approve/reject guards --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
c9c1f62981 |
feat: HyperFrames-grade video design bar — vendored craft references + catalog vocabulary (#550)
* feat(motion): demo-register visual design bar, vendored craft references, catalog vocabulary index * fix(motion): correct design-bar composition claims after adversarial fact-check * docs(map,rag): design-bar, vendored references, and catalog index on the video-engine surfaces --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
c5dfbf6063 |
feat: Workstation page — Products + Projects unified behind one sidebar entry (#549)
* feat(panel): Workstation page — Products and Projects as tabs behind one sidebar entry * docs(map): workstation page, extracted views, and the local-filter scroll trade-off --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
496c24d186 |
feat: git hygiene (branch/preview reaping + cleanup sweep) and panel charts; work sessions under Git (#548)
* feat(panel): session-start, 7d overview spend, and 30d business spend charts * feat(panel): surface work sessions as a Git page tab (route was orphaned) * feat(git): reap spent task branches and render previews at lifecycle chokepoints; guarded stale-branch sweep * feat(panel): stale-branch cleanup button on the Git page * fix(git,panel): cursor-resumable sweep, force-delete spent refs, local filter state * docs(map,rag): branch/preview reaping, cleanup sweep, git-tab work sessions, wave-2 charts --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
885d6bbe83 |
feat: CEO-grade A2A — New DM composer, CEO-DM wake, docs scrub (#547)
* feat(panel): CEO New-DM composer and direct-thread replies on the A2A page * docs(agents): remove dm-the-CEO teaching; fix Board/HoM dead-end escalation recipes * feat(a2a): CEO-authored DMs wake offline recipients via the a2a_request dispatch path * fix(a2a,panel): wake only read_a2a-capable roles; case-insensitive header defaults; wider DM picker exclusions * docs(map): CEO-DM wake mechanics, requires_ack override, A2A composer components; comms-model update --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
9b4ce6b9c8 |
fix: wave 1 quick wins — agent names, scroll bounce-back, chart empty states, model-pin preservation, UUID spawn normalization (#546)
* fix(panel): notifications show agent names, metrics charts get empty states * fix(panel): stop expand/collapse scroll bounce-back; add floating scroll-jump buttons * fix(llm): provider mode switches preserve per-agent model pins * fix(api): normalize agent UUID to slug at the orchestrator route boundary * fix(panel,docs): align routing-card copy and map docs with preserved-pin mode switches * fix(panel): drop dead unfiltered scroll hook, re-observe on Suspense swap, name system sender * docs(map): reflect preserved-pin mode switches, UUID-slug normalization, panel wave-1 deltas --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
4c8a9fc008 |
fix(video): unconfigured platforms are skipped, not pending-forever failures (#545)
A draft targeting a platform with no credentials could never complete: the X leg posted and committed its id, the TikTok leg failed as 'transient', and the card sat pending in the CEO queue with retry semantics that structurally cannot succeed. Unconfigured platforms are now an explicit skip: the draft COMPLETES when every configured platform has posted (detail names what was skipped), an approve whose targets are all unconfigured refuses loudly instead of silently completing, and genuine post failures keep their partial/retry semantics. Re-approving a parked card clears it without re-posting (the already-posted guard is covered by a dedicated test). Verified: 32/32 test_video_post_service (3 new: skip-and-complete, all-unconfigured refusal, re-approve recovery), ruff/mypy/xenon clean. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
fd621f0dba |
feat(motion,runtime): wire the three craft capabilities to the video-authoring dev (#544)
Playwright, the taste-skill design bar, and hyperframes were all implemented — and each stopped one hop short of the hands doing video work: playwright reached only fe-qa/ux-qa, the design bar's web-UI dials actively pointed a video task at 'dense product UI -> motion 2-3', and hyperframes' agent-facing doctrine never reached any agent. Three wires: - vendor the official HyperFrames agent skills (hyperframes-core, -keyframes, -creative) under motion/skills/ at a pinned upstream commit (Apache-2.0, attribution headers; prose reflowed to house style, re-vendor note in each header); README and the dev video prompt block point at them - register the playwright MCP for a ux-dev spawned onto a source=video task (_is_video_authoring_spawn: fail-closed role/team/task-source probe) so the composition author can watch their HTML live in a real browser between renders — gating-only, agent-ux already bakes the browser; QA gating unchanged, be-qa/ordinary ux-dev still excluded - design bar video-mode override in the ux_ui team prompt: video tasks are films, the web dials do not apply — use the cinematography bar and the vendored doctrine instead Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
3e801697f7 |
feat(motion): choreography engines + two renderer root causes fixed (#543)
The release cuts read as static screen recordings: one 6s cursor glide that then vanished, a locked-off camera, metronomic flat card fades. And two renderer defects were silently wrecking every cut: - @hyperframes/producer floated (^0.7.36, no lockfile — image builds get whatever is latest): 0.7.60 fails EVERY render with "Cannot access 'rt' before initialization". Pinned 0.7.36 exact and committed package-lock.json so sidecar builds are reproducible. - the producer's per-clip visibility scheduler runs on a clock that lags ~50% behind the encoded timeline on a 40s cut — the final frame showed the authored ~18s state, so the tail scenes (bell card, toast, outro) were silently missing from the MP4. This, not authoring, is why rendered cuts kept losing their late scenes. Fix: clip windows are for structural layers only (hero, panel frame, status); every beat rides base-hidden styles + delayed CSS animations, which run on the true clock. Verified frame-by-frame: all four cards, stats, toast, and outro now land exactly on schedule in both cuts. Craft, made reusable in the kit instead of per-composition heroics: - kit.js choreographCursor: data-waypoints="t x y [click]; ..." generates a multi-leg eased path with fade in/out, an idle-hand sway, and click rings + glyph press dips — the cursor behaves like a hand, never pops in, freezes, or blinks out - kit.js choreographCamera: data-shots="t x y scale; ..." — push-ins toward each beat's focal point, pull-backs for reveals, settle to end - release-0.25.0 both cuts re-choreographed: the cursor is the CEO's hand (settle on the intake while it types, ONE submit click, witness each card completing, acknowledge the toast, exit off-frame); the camera lives on every beat; springy card entrances replace flat fades - motion/README.md gains 'Cinematography & rhythm' (shot-list-first, no locked-off camera, verify motion with frame PAIRS) + the clip-window rule; kit/README.md documents both engines; the dev video prompt block carries the craft bar Verified end to end through the real sidecar: both cuts render green, 32-frame strips read visually — cursor travels and clicks on schedule, camera moves, every scene present. motion pnpm test 15/15. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
e9ca7d4036 |
Delegation detail-fidelity + PM-loop hardening (#541)
* feat(gateway): delegation detail-fidelity — details survive hand-off, both directions
Details thinned out at every delegation hop: a PM child task mapped to no
parent criterion was legal (coverage only surfaced at submit_up, after the
whole wave ran — a 12-subtask docs tree grew through 8 review rounds that
way, one child titled 'docs page and route wrapper' shipping only the
page), and QA could pass work on a gestalt read (a 4-scene video brief
shipped 3 scenes past every gate because the features existed only in
prose). Three chokepoint gates:
- delegate (down): every child must declare covers_parent_criteria
resolving against the parent's real acceptance criteria — no mapping or
an unresolvable ref rejects naming every offending child and the valid
criteria; the success envelope carries parent_ac_coverage
{covered, uncovered} so a wave-planning PM sees remaining gaps in the
same turn. Full coverage stays enforced at submit_up (waves stay legal).
- pass_review (up): mandatory criteria_verified — one {criterion,
evidence} entry per task AC, matched by the findings ledger's
id-or-exact-text matcher, evidence soup-checked and capped; rejects
naming the unverified criteria; entries render deterministically into
qa_notes as '[AC] <criterion> — verified: <evidence>' lines. The old
count-only ac_verdicts gate is superseded (arg kept for back-compat).
- video briefs (structured detail at origination): an enumerable feature
list (release highlights, or input_props.highlights carried onto a
reject re-author) becomes its own scene acceptance criterion, bounded to
the AC caps; a re-author without highlights carries the
feedback-addressed criterion instead.
Extracted findings.py's criterion matcher into shared unmatched_criteria /
uncovered_acceptance_criteria instead of duplicating it; criteria_verified
joins the WAF free-text exclusion set like findings/issues.
* fix(gateway): break the block/unblock wedge — four hardening fixes from the live PM loop
A cell task looped fe-pm/main-pm block/unblock for hours (10 cycles, 43
spawns): a transient GitHub API error resolving CI became an unwaivable
blocker finding whose own fix text said no code change was required, the
submit freshness guard then demanded a commit no finding called for,
escalate_up auto-blocked, and main-pm's correct recovery plan 422'd on
the approach length cap, degrading it to a bare unblock. Four fixes:
- pr_pass CI-unresolvable refusal is now explicitly transient-worded:
retry pr_pass shortly, do NOT pr_fail over a CI-status lookup error —
a platform blip is not a code finding
- submit freshness guard grants ONE unchanged-head resubmission per
head sha when the findings ledger has zero open rows (all addressed
without code changes) — stamped via the resubmit_unchanged_head
marker so the same head can never loop a second time
- unblock carries a flip breaker: block_flip_count marker, and at the
third flip a one-shot CEO notification flags the task as structurally
wedged (unblock itself still succeeds — the breaker signals, it does
not wedge recovery)
- i_will_plan's approach cap truncates at 800 chars instead of
rejecting — an over-detailed plan must never cost the PM its turn
---------
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
747feb2923 | sync: master → slave | ||
|
|
aa15dc40cc |
Feature/video artifact verification (#537)
* fix(release): CI wait polls the prod rung; escape the header tooltip apostrophe get_latest_ci_conclusion defaults to the ladder's head rung, so wait_for_ci searched slave for a release commit that lives on master and timed out after 40 minutes with the run already green. The wait now passes the prod branch explicitly. Also fixes the react/no-unescaped-entities error that turned master's Panel CI red. * fix(panel,video): dead dialog triggers behind tooltips; dotted composition ids render HelpTip nested inside a Dialog/AlertDialog trigger puts the trigger's click handler on the Tooltip root, which renders no DOM — the agents Spawn item and the KB Reindex-All / Delete-index confirms were dead. Tooltips now wrap the triggers. The video renderer accepts interior single dots in composition ids (release-0.25.0) with '..' still unrepresentable, and propose_video refuses an unrenderable id at authoring time. * fix(dispatch): restart-safe PM review turns A leaf task in awaiting_pm_review had no periodic pickup: the closure dispatcher bailed on childless tasks and skipped PR-bearing review tasks as already-promoted, assuming the submit-time PM session was still alive — an assumption every restart breaks. Proven live on the docs-sync leaf after the 0.25.0 redeploy, which also dependency-blocked its sibling dev task. Childless awaiting_pm_review tasks now flow to the PM's review turn, and the merge turn respawns its PM when none is active. * feat(video): verify the rendered artifact, not the source The 14s release-0.25.0 cut shipped with only one of four scenes visibly registering: the dev authored DOM, the smoke asserted DOM, QA read code — nobody consumed the rendered MP4 before the CEO did. Close that loop, and the reject loop behind it: - sidecar frames mode: POST /render with frames=1..32 renders the cut, ffprobes the REAL duration, extracts midpoint-sampled keyframe PNGs (timestamps in filenames), streams a tar.gz back with X-Video-Duration - request_render do-verb (developer/QA, request_sandbox's shape): renders the caller's ACTUAL composition — dev's own worktree (head_sha/dirty provenance), QA a read-only git-archive export of the assembled branch — extracts frames to the container-shared .previews/ path, stamps the render_preview marker, returns the paths as envelope evidence - gate: i_am_done on a source=video task refuses without a stamped render_preview (Requirement.RENDER_VERIFIED; canonical source string moved to foundation as markers.VIDEO_TASK_SOURCE; mirrored in the possibilities-matrix fast path so it cannot bypass the check) - QA claim_review evidence carries video_context (composition id, the dev's preview, a re-render instruction) so review checks output - dev spawn prompt block + a 4th authoring AC order Read-every-frame verification before submitting - reject -> re-author: a CEO reject with a reason opens a fresh authoring task carrying the verbatim feedback + a revise-in-place pointer at the existing composition (best-effort, never fails the reject) — rejection feedback no longer dies on the cancelled draft E2E: rendered the committed release-0.25.0 composition through the new frames mode locally — the returned keyframes show exactly the reported failure (blank frame at 5.8s, only 'Env ladder' by 12.8s), the check the fleet was missing. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
9081499823 | sync: master → slave | ||
|
|
797847e379 |
[1dae04a7] Video: release 0.25.0 (revision) (#536)
* fix(release): CI wait polls the prod rung; escape the header tooltip apostrophe get_latest_ci_conclusion defaults to the ladder's head rung, so wait_for_ci searched slave for a release commit that lives on master and timed out after 40 minutes with the run already green. The wait now passes the prod branch explicitly. Also fixes the react/no-unescaped-entities error that turned master's Panel CI red. * fix(panel,video): dead dialog triggers behind tooltips; dotted composition ids render HelpTip nested inside a Dialog/AlertDialog trigger puts the trigger's click handler on the Tooltip root, which renders no DOM — the agents Spawn item and the KB Reindex-All / Delete-index confirms were dead. Tooltips now wrap the triggers. The video renderer accepts interior single dots in composition ids (release-0.25.0) with '..' still unrepresentable, and propose_video refuses an unrenderable id at authoring time. * fix(dispatch): restart-safe PM review turns A leaf task in awaiting_pm_review had no periodic pickup: the closure dispatcher bailed on childless tasks and skipped PR-bearing review tasks as already-promoted, assuming the submit-time PM session was still alive — an assumption every restart breaks. Proven live on the docs-sync leaf after the 0.25.0 redeploy, which also dependency-blocked its sibling dev task. Childless awaiting_pm_review tasks now flow to the PM's review turn, and the merge turn respawns its PM when none is active. * [1dae04a7] Revise release-0.25.0 composition to 40s scene-based pacing with four feature cards * [1dae04a7] docs(motion): update release-0.25.0 README section for 40s four-card revision --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech> |
||
|
|
225abcf511 | sync: master → slave | ||
|
|
63212899ca |
[2f806123] Video: release 0.25.0 (#535)
* fix(release): CI wait polls the prod rung; escape the header tooltip apostrophe get_latest_ci_conclusion defaults to the ladder's head rung, so wait_for_ci searched slave for a release commit that lives on master and timed out after 40 minutes with the run already green. The wait now passes the prod branch explicitly. Also fixes the react/no-unescaped-entities error that turned master's Panel CI red. * [2f806123] feat(motion): add release-0.25.0 composition extending panel-demo register * [2f806123] fix(scope): revert out-of-scope backend and panel changes from video branch * [2f806123] fix(scope): revert out-of-scope backend and panel changes from video branch * [2f806123] fix(scope): restore out-of-scope files from current origin/master after stale-master revert * [2f806123] fix(scope): restore motion/pnpm-workspace.yaml from origin/master * [2f806123] docs(motion): add release-0.25.0 composition example to README --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> Co-authored-by: UX/UI Documenter <ux-doc@roboco.tech> |
||
|
|
e590e64b86 | sync: master → slave | ||
|
|
f34305f224 |
[w4] Label every fleet PR with its org-structure role (#526)
Pure derive_pr_labels (foundation/policy/pr_labels.py) maps a PR's shape
to a stable org-structure label set: to master/to slave (is_root_pr
discriminator), root, MegaTask, and the owning layer (main-pm /
cell/{team} / subtask/{team}). Mirrors batch.py: object|None inputs,
enum-or-string normalization, no DB/I/O. Full slave-targeting semantics
(base_branch vs default_branch) land with the slave/master wiring (W-H);
YAGNI now.
GitService._apply_pr_labels posts the result to the GitHub labels API
best-effort (create-before-add, swallow 422/409, never raises) so a label
failure can never block PR creation. Wired at all three PR-opening sites:
create_pr (gateway path), create_pull_request (REST/task path), and
_push_and_open_conventions_pr (static chore label). Existing PR tests
mock _apply_pr_labels so they never hit the real labels API.
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
be553ee9dd |
[w8b] Fix release-proposal flow: reject frees dedup, surface execute outcome (#525)
Reject cancelled the proposal's status but never moved it out of the held-proposal set, so the one-open-proposal dedup blocked the release manager from ever re-assessing — a rejected proposal deadlocked the cycle. reject() now sets CANCELLED (mirroring video_post_service), which list_open_release_proposals already excludes, so a fresh proposal can originate next cycle. A failed ~40min background execute (gate red, CI red, or an unexpected crash) left the proposal silently PENDING with no signal to the CEO. _run_approve_background now writes a release_execute_outcome marker (status + detail) on every terminal outcome, and an 'error' marker on an unhandled exception. GET /proposal surfaces execute_status / execute_detail / execute_in_flight (derived from the in-memory _INFLIGHT_APPROVES registry) so the panel can show a running badge, a failure block with the reason, and a Retry-approve label instead of a silent wait. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
bb3b4b0c6d |
W6: Telegram notifications bridge (V1) (#524)
* feat(gateway): reviewer/PM collision map (W5)
The collision surface (intends_to_touch / adds_migration / touches_shared)
is authored at delegate time, consumed once by SequencingService to wire
dependency edges, then never shown to a reviewer again. This surfaces it:
- Pure builder (services/gateway/choreographer/collision.py): for a task
under review, the surfaced siblings (same parent) that would collide —
file-overlap globs or a shared migration chain (both adds_migration) —
with the overlapping globs and a declared-vs-actual drift check. No
DB/IO; callers fetch siblings (one indexed get_subtasks query, mig 069)
+ actual files (git). Caps: 10 siblings, 5 globs.
- Evidence envelopes: collision_context block injected into QA
claim_review, PR-gate claim_gate_review (both carry real touched files
so drift is populated), and the PM i_will_plan briefing (no actual
files at plan time, drift omitted). Best-effort — a failure omits the
block, never breaks the verb/briefing. Empty block omitted (zero token
cost via _EVIDENCE_OMIT_WHEN_EMPTY).
- Panel: GET /api/tasks/{id}/collision-map (declared surface + sibling
overlap; no drift — the panel route resolves no workspace) + a Collision
tab on the task detail (8th tab). Mock-mode returns an empty map.
- docs/map added to the RAG auto-index dirs so the collision-map concept
is fleet-retrievable; skipped gracefully if the dir is absent.
19 new tests (15 unit on the pure builder + 4 integration on the route).
Gate green: ruff/mypy/xenon (module rank A)/pytest 13000/coverage 94.81%,
panel typecheck/lint/516 tests.
* [w6-telegram] Add Telegram notifications bridge (V1)
CEO-facing Telegram DM bridge, flag-gated off by default
(ROBOCO_TELEGRAM_ENABLED). Mirrors the X-credentials / X-client pattern:
- TelegramCredentialsTable (migration 073) — singleton Fernet-encrypted
bot_token + chat_id, all-or-nothing set/clear; API never returns plaintext.
- TelegramClient ABC / NullTelegramClient (no-op, configured->False, never
raises) / LiveTelegramClient (httpx POST sendMessage) / build_telegram_client
factory (Null when creds unset).
- /telegram/credentials CEO-only routes (write-only, guard-decorated).
- Best-effort _notify_telegram fan-out from the two CEO-notify producers
(notify_ceo_of_escalation, notify_ceo_of_completion) — guarded by the flag,
never raises into the producer, carries a panel deep-link when
panel_base_url is set.
- panel credentials card (2 fields) nested in the Telegram feature-flag row.
- panel_base_url + telegram_timeout_seconds config fields.
V1 scope only: credentials + flag + panel card + client + one-line fan-out.
Out of scope (V2): inbound commands, a TelegramEngine background loop, a
dedup ledger, a bus subscription.
* [w6-telegram] fix: slave mypy/xenon regression (product tests + helper extract)
Pre-existing on slave from prior session's merges — no PR's CI caught them
(squash merges don't re-CI the result; each branch was based on older slave).
- test_product: _product helper returned MagicMock -> list invariant error;
cast to ProductTable, move import under TYPE_CHECKING.
- test_usage: svc.session.execute (AsyncSession) has no call_args_list;
cast to MagicMock at the two call sites.
- product.progress_for_products: xenon rank C -> extract module-level
_project_to_products_map helper (repo pattern: helper-extract).
---------
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
d80dfb8bbe |
feat(env-branches): per-project ordered environment ladder (replaces default_branch) (#534)
* [env-bran] EnvSyncEngine: orchestrator-side prod→dev cascade (default-off) - EnvSyncEngine mirrors CiWatchEngine: cascade ladder_pairs top-down via GitHub merges API; clean→auto-push lower rung, conflict→one sync PR + tracked MAIN_PM task + stop. Never pushes prod (lower rung is never prod by construction). - GitService.sync_env_branch (merges API) + open_sync_pr (idempotent) + _env_merge_status/_post_sync_pr helpers (constants for 201/204/409). - TaskService.ENV_SYNC_SOURCE + list_open_env_sync_tasks (per-repo dedup). - config env_sync_enabled/_interval_seconds(1800)/_max_open_tasks(3)/_max_per_cycle(1). - Orchestrator 4-touch registration + _load_env_sync_set (ladder+token opt-in). - Feature-flags card + settings FEATURE_FLAGS entry for ROBOCO_ENV_SYNC_ENABLED. * [env-bran] Panel: environment ladder editor + types + validation - EnvironmentRung type + environments on Project/ProjectCreate/ProjectUpdate. - EnvironmentLadderEditor (plain useState, add/remove/up-down reorder, head/ prod labels) reused by create + edit project dialogs. - validateLadder (non-empty name+branch, no duplicate branches) shared, toast.error on submit; empty editor => null => inherits default_branch shim. - default_branch input kept with override-hint; API client passthrough. - 6 unit tests for validateLadder. * [env-bran] Tests + gate green: env ladder, EnvSyncEngine, promotion chain - tests/unit/models/test_env_branches.py: shim, head/prod, ladder_pairs, promotion_chain, normalize (20 tests) - tests/integration/services/test_env_sync_engine.py: cascade clean/conflict/ missing_ref/tokenless/degenerate/caps/dedup/disabled (9 tests, DB) - tests/integration/test_migration_env_branches.py: 073 defaults null + round-trip - tests/unit/services/test_release_executor*.py: add env_chain=[] to _ReleaseContext constructions (promotion_chain field is now required) - tests/unit/runtime/test_orchestrator_shutdown_drain.py: register _env_sync_task in the stop()-drain fixture (new named background loop) - roboco/services/git.py: revert _project_head_branch rename back to _project_default_branch (modify-in-place per plan); the rename in the consumers commit broke ~15 unit-test mocks that bind the original name - roboco/services/env_sync_engine.py + models/env_branches.py: ruff format - roboco/api/schemas/project.py: trailing-newline format Backend gate green (13013 passed / 439 skipped), mypy clean, ruff clean. Panel gate green (typecheck/lint/522 tests). * [env-bran] fix: add env_chain to _ReleaseContext in e2e smoke (CI red) The release-executor promotion_chain change made _ReleaseContext.env_chain required. I fixed the three unit/release test files but missed the construction in tests/e2e_smoke/test_background_engines.py:98 — my local gate ran 'mypy roboco/' (excludes tests/) and I skipped 'make e2e-smoke', so CI's mypy-on-tests + the e2e runtime job caught it instead of me. Verified locally with the CI-equivalent gates: uv run mypy roboco/ tests/ -> 1170 files, clean ROBOCO_E2E_SMOKE=1 uv run pytest tests/e2e_smoke -> 50 passed, 1 skipped * [env-bran] fix: extract _ensure_prod_fetched to clear xenon rank C (CI red) _production_assess grew past xenon --max-absolute B (rank C) when the env-branches prod-tip fetch added an if/try/except branch. Extracted the fetch-with-fallback into _ensure_prod_fetched (degan+fetch paths), moved _run_git to the module-level import. Local make quality green (all gates incl xenon/vulture/deptry/import-linter/foundation-check). --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
b7f2d84c77 |
W9-5: Tooltip sweep — HelpTip helper + per-view decode (#533)
* [W9-5a] Tooltip sweep foundation: HelpTip helper + shared cryptic badges HelpTip: DRY wrapper over the verbose 3-element Radix Tooltip pattern so a broad sweep stays a one-line wrap per site (falsy label short-circuits to the bare child). Unit-tested (3 cases). TaskStatusBadge + AgentStateBadge: the panel's most cryptic, most-frequent elements (15 task lifecycle states, 11 agent states) had no explanation anywhere. Add a per-state tooltip via HelpTip, with the canonical text in one description map and exported as taskStatusDescription / agentStateDescription so the per-view inline renderers (kanban, task header) reuse it instead of re-declaring. This is part 1 of the W9-5 tooltip sweep; the per-view inline surfaces follow in subsequent PRs. * [W9-5b] Per-view tooltip sweep: decode cryptic badges, icon-only buttons, status dots 35 HelpTip additions across 22 panel components, reusing the W9-5a helper plus taskStatusDescription/agentStateDescription. Tipped: task-id/commit-hash/branch/PR badges, severity/origin/status badges, priority (P0-P3), migration/shared flags, MegaTask umbrella badge, Review Gate / For Resumption / Confidential note badges, icon-only view/delete/edit/clear/show-hide buttons, semver bump + gate-state badges, ahead-not-pushed badge. Skipped self-explanatory labeled buttons and elements already carrying title=. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f07e2420a8 |
[W9-4] Add code-snippet viewer for revision findings (#532)
Backend: GET /git/file reads a file at a branch tip (read_file_at_branch) and slices it to a line window — explicit start/end, a line+context center, or the whole file capped at 2000 lines. _compute_file_range is the pure helper (unit-tested). Frontend: useGitFile hook + CodeSnippet (styled <pre>, line numbers, active- line highlight — matches git-diff-viewer, no shiki). Wired into FindingCard so each file:line finding shows the surrounding source. Fail-open: a missing file renders a muted hint, never breaks the card. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
1054538d2f |
[W9-3c] Enrich project table with task counts + CI-watch badge (#531)
Backend: ProjectSummaryResponse gains task_counts (done/active/blocked) + ci_watch_enabled. ProjectService.task_counts_for_projects does one GROUP BY project_id over TaskTable for every distinct project_id in the list (a project with no tasks is absent — route falls back to None). ci_watch_enabled is read straight off the Project row (already a column) — a 0-cost schema extension, honest signal that CI-watch is armed, no live-conclusion fan-out. project_to_summary takes an optional task_counts. No migration. Frontend: ProjectTable gains a Tasks column (done/active/blocked + health dot, amber at-risk when blocked>0) and a CI-Watch badge under the project name when ci_watch_enabled. Both desktop Table and mobile ResponsiveTableCard variants. Mock projects carry the new shape (two sample repos). Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
86d31bf3d3 |
[W9-3b] Enrich product table with cell mappings + task progress (#530)
Backend: ProductSummaryResponse gains cells: [{team, project_id, project_name}] and progress: {done, active, blocked}. ProductService.progress_for_products does one grouped query over tasks for every distinct project_id any product references, summed per product (monorepo case dedups a project once per product via a seen set). list_all eager-loads cells + each cell's project (selectinload + joinedload) so product_to_summary reads project.name without an N+1. No migration — reads existing tasks.status + product_projects.
Frontend: ProductTable renders a Cells column (team badges + project names, Unmapped when empty) and a Progress column (done/active/blocked counts + a health dot: amber at-risk when blocked>0). Both desktop Table and mobile ResponsiveTableCard variants. Mock products carry the new shape.
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
9a364abb74 |
[W9-3a] Enrich agent detail page with sparkline + activity timeline (#529)
Backend: optional agent_slug filter on GET /usage/time-series + UsageService.get_time_series (AgentSpawnSessionTable.agent_slug column already exists — no migration). Frontend: AgentActivityPanel on the agent detail page — a 7d per-agent token sparkline (recharts AreaChart) + a merged work-session/journal activity timeline. Work-sessions filter by the agent UUID (WorkSessionTable.agent_id is a UUID FK to agents.id), journals by slug. List grid left as-is (avoids 25-agent fan-out). Card last_active deferred (no live hook populates AgentMetrics). Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
d9084eeb07 |
[w9-2] Add 90d window, time-window selector, and chart/table toggle (#528)
Backend: widen usage _PeriodType to 24h/7d/30d/90d and add a 90d branch to _parse_period (daily buckets already cover it). TestParsePeriod pins the contract per window. Frontend: UsagePeriod += 90d with a scaleFor helper (replacing 6 inline ternaries) and 90 daily mock points. One generic SegmentedControl primitive (reuses Radix Tabs) drives both the metrics time-window selector (24h/7d/30d/90d) and the per-chart Chart/Table view toggle — one file, two roles. The Token Usage & Costs tab drops 8 hardcoded '24h' hooks for a single period state + selector; the stale '(24h)' cost-card parenthetical goes too. The Performance landing tab gains a TaskStatusChart donut fed by the status counts already on the page (no new hook). Agent/team bar charts gain an inline table view. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
533ea97d01 |
[w9-1] Wire read/ack into the notification bell (#527)
The bell showed a transient WebSocket-stream buffer count with no read/ack actions; the persisted unread/ack state and the mark-read / acknowledge / mark-all-read mutation hooks already existed (use-notifications.ts) and powered the notifications page, but the bell ignored them. The bell now derives its badge from useNotifications().unread_count (the real DB count, not the stream buffer), renders the recent items with per-item Mark Read + Acknowledge + a header Mark all read, shows the pending-ack count, and keeps the WS stream only for the connection indicator (the NotificationAlerts sibling still owns the toast/chime). The stream buffer is cleared on popover close so it can't grow unbounded now that it's no longer displayed. The mutations self-invalidate notificationKeys.all on success, so the badge + popover refresh immediately after each action; useNotifications also refetches every 30s. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f2e5676198 |
W7: Possibilities matrix (work-already-done fast path) (#522)
* [W7] Add possibilities_matrix_enabled feature flag (default off) * [W7] Add _work_appears_done predicate (status+commits+PR+ACs+no-open-findings) * [W7] Add CI-green quality proxy for the fast path (local fallback on no-CI) * [W7] Add work-already-done fast path in i_am_done (slimmed gates, no rich plan) * [W7] Add WORK_ALREADY_DONE prompt state * [W7] Make fast path mypy-clean (cast to helpers for _resolve_ci_status; typed mock locals) * [W7] Extract _all_criteria_addressed to bring _work_appears_done under xenon B --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
0089e95489 |
feat(rag): auto-index docs/map into the KB (#521)
docs/map is the agent-facing exhaustive codebase map (CLAUDE.md) but was never RAG-indexed — only docs/rag was. Add it to OptimalService._auto_index_dirs so every docs/map/*.md rides index_documentation (the generic _index_docs_directory rglobs *.md and routes only the 'standards' subdir to the standards indexer) and becomes roboco_kb_search-able. No map-specific branch needed. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
0d42232d9d |
fix(panel): active tab/route highlight (pickTab + sidebar footer exact match) (#520)
* feat(panel): add pickTab helper for validated URL tab params * fix(panel): validate kanban view + KB tab params via pickTab The bare `as T || default` cast only guarded null — a typo/invalid value (?view=deev, ?tab=foo) passed through as an out-of-set TabValue, blanking the active tab highlight and the content pane. pickTab validates against the known set and falls back to the default on null/empty/invalid. * fix(panel): highlight active sidebar footer link (exact match) SidebarFooter had no isActive branch (SidebarNav does), so footer links never highlighted. Added with EXACT match (pathname === href) — not startsWith — so /settings does not also highlight on /settings/ai-providers. Main nav keeps startsWith (longer hrefs need prefix matching); the two intentionally differ. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
ba9c9d69d8 |
fix(dispatch): prefilter sequence-held dev tasks before spawn (#519)
* fix(dispatch): prefilter sequence-held dev tasks before spawn _spawn_pending_dev booted a full dev container for a pre-assigned pending task that the assignee-blind sequence guard would refuse at the claim chokepoint (a non-terminal lower-sequence same-parent sibling — not a declared dependency). _blocked_by_earlier_lane_sibling is narrower (same dev's lane) and _validate_task_for_spawn checks declared deps, not sequence siblings, so the container spawned, the first claim hit _claim_blocked_by_sequence and was refused, and the agent exited only to be re-spawned next tick — pure churn until the predecessor went terminal. Mirror the PM path's _pending_claim_blocked prefilter (the exact claim-gate predicate, fails open) at the top of _spawn_pending_dev, before the narrower per-dev lane probe. Reuses the helper so it can't drift from the chokepoint. * fix(dispatch): prefilter sequence-held dev tasks before spawn _spawn_pending_dev booted a full dev container for a pre-assigned pending task that the assignee-blind sequence guard would refuse at the claim chokepoint (a non-terminal lower-sequence same-parent sibling — not a declared dependency). _blocked_by_earlier_lane_sibling is narrower (same dev's lane) and _validate_task_for_spawn checks declared deps, not sequence siblings, so the container spawned, the first claim hit _claim_blocked_by_sequence and was refused, and the agent exited only to be re-spawned next tick — pure churn until the predecessor went terminal. Mirror the PM path's _pending_claim_blocked prefilter (the exact claim-gate predicate, fails open) at the top of _spawn_pending_dev, before the narrower per-dev lane probe. Reuses the helper so it can't drift from the chokepoint. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
a9dee3b34e |
feat(agents): force agents to the Makefile — deny raw uv/pip/conda/poetry (CEO #15) (#518)
* fix(prompts): point agents at Makefile, drop raw uv run instructions backend.md:23-26 literally instructed raw uv run ruff/mypy/pytest (copied from the human-facing CLAUDE.md), so agents bypassed the Makefile's UV_NO_SYNC=1 + private UV_CACHE_DIR venv-corruption guard. Replace with make targets across backend/developer/qa/cell_pm + a universal rule in base.md. Regenerate verbs.md from the updated regen script (baked instruction now make foundation-check) and align the Makefile drift message. Ships with the bash-guard deny in the next commit so agents don't loop fighting the guard. * feat(bash-guard): deny raw uv/pip/conda/poetry, point at Makefile When a Makefile is present, deny raw uv run/uv pip/uv lock/add/remove, pip/pip3 install/uninstall, conda install/create/run, poetry run/install/add and remediate to make quality/gate/lint/test. Skipped when no Makefile (Makefile-less projects not blocked). ROBOCO_GUARD_SKIP_PM=1 (grok path) nudges exit 0 instead of the run-canceling exit 2. Overrides the prior bare-uv-run-allowed stance by CEO direction; the /app-targeted blocks above keep priority. * feat(grok): deny raw uv/pip/conda/poetry via native --deny + PM-skip nudge Add _RAW_PM_DENY (uv run/pip install/lock/add/remove, pip/pip3 install, conda install/create/run, poetry run/install/add) to _deny_rules so grok's graceful native --deny blocks raw package-manager commands (model adapts to make, run continues — unlike a hook deny which cancels the run). The bash-guard hook keeps the compound-command fallback (cd x && uv run) and nudges exit 0 there via ROBOCO_GUARD_SKIP_PM=1 in the grok hook env, never canceling. * test(bash-guard): align existing tests with W1 Makefile-gate policy Raw uv run / pip install are now Makefile-gated (W1, CEO item #15), so two existing bash-guard invariants reverse: - test_allows_pytest_even_if_suite_uses_requests keeps its HTTP-injection allow-path intent but uses bare `python -m pytest` (raw `uv run` is now denied); the deny case is covered by test_bash_guard_makefile_guardrail. - test_allows_pip_install_in_workspace -> test_denies_pip_install_when_makefile_ present: a workspace clone carries a Makefile, so bare pip install is now denied -> agents use `make` / `uv sync --extra dev`. Makefile-less skips stay covered. Gate: 12994 passed, 439 skipped, 94.81% cov (DB env :55432 user renzof); the lone flaky integration error passes in isolation (DB-state race, not W1). --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f03859c64c |
[4cfd99c2] Backend: docs-divergence engine, feature flag, release seam, and compose wiring (#507) (#513)
* [fe5c049b] Register docs-sync feature flag and compose wiring (#505) * [fe5c049b] Register docs-sync feature flag and compose wiring * [fe5c049b] feat(config): wire ROBOCO_DOCS_SYNC_ENABLED flag and compose defaults * [fe5c049b] docs(config): document ROBOCO_DOCS_SYNC_ENABLED flag and compose defaults --------- * [687574d2] Implement docs-sync engine and release-proposal seam (#506) * [687574d2] Add docs-sync engine and release-proposal publish seam * [687574d2] Restore task.py safeguards deleted by docs-sync engine commit and filter docs_sync version in SQL * [687574d2] docs(map): add engine-docs-sync architecture map and cross-references * [687574d2] docs(config): update docs-sync flag, cap settings, and changelog entry --------- * [3e7cd5a8] Fix task.py regressions from docs-sync PR (#509) * [3e7cd5a8] fix(task): restore deleted auditor alerts and revert descendant cast form in task.py * [3e7cd5a8] docs(task-service): restore auditor alerts and cast notes in map and changelog --------- * [e6e23c1f] Enforce docs_sync_max_per_cycle cap in docs_sync_engine.py (#510) * [e6e23c1f] Enforce docs_sync_max_per_cycle cap in DocsSyncEngine * [e6e23c1f] docs(docs-sync): document docs_sync_max_per_cycle enforcement in engine map, README, and docstring --------- * [e4b7dd0f] Revert task.py cast regressions from docs-sync PR (#511) * [e4b7dd0f] fix(task): revert cast regressions in supersede and descendants * [e4b7dd0f] docs(map): correct PR #511 cast regression entry in task-service slice map * [e4b7dd0f] docs(backend): add SQLAlchemy UUID cast pattern note and inline comments in task.py --------- * [1fdfe711] Fix Python quality gate on docs-sync PR (#512) * [1fdfe711] Fix ruff formatting in task.py and add coverage tests for docs-sync surface * [1fdfe711] fix(task): use generic JSON .as_string() accessor in list_open_docs_sync_tasks and correct test patch targets * [1fdfe711] docs(task-service): record docs-sync JSON accessor fix and list_open_docs_sync_tasks map entry --------- --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> |
||
|
|
a3524da5f8 |
[90c9474c] Auditor revival: scheduled audit trigger and reactive alert producers (#499)
* [927e64d5] Backend slice: auditor scheduled trigger and reactive alert producers (#496) * [1f2cdb4b] Reactive alert producers at QA-fail and rework (#492) * [1f2cdb4b] feat(services): add auditor-targeted rework alert producers at QA-fail and rework chokepoints * [1f2cdb4b] test(services): fix mypy typing in auditor alert producer unit tests * [1f2cdb4b] docs(backend): document reactive auditor rework alert producers in map and role docs --------- Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [5173415f] Scheduled audit trigger, config, and sweep prompt (#493) * [5173415f] Add scheduled audit trigger, interval config, sweep prompt, and focused tests * [5173415f] Allow ROBOCO_AUDIT_INTERVAL_SECONDS=0 to disable scheduled sweeps * [5173415f] docs(audit): document scheduled auditor sweeps and ROBOCO_AUDIT_INTERVAL_SECONDS --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [a26c18b9] E2E smoke test for auditor triggers (#495) * [a26c18b9] Add e2e smoke test for auditor scheduled and reactive triggers * [a26c18b9] docs(tests): add e2e smoke test catalog and changelog entry for auditor triggers --------- Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [3bc47cdc] Fix _fresh_orchestrator state for auditor trigger e2e tests (#497) * [3bc47cdc] fix(tests): initialize orchestrator state in _fresh_orchestrator helper * [3bc47cdc] docs(changelog): add _fresh_orchestrator test harness fix entry --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [8323cd50] Fix e2e smoke regression on assembled cell PR #496 (#498) * [8323cd50] fix(e2e_smoke): repair auditor-trigger smoke tests and harden harness * [8323cd50] docs(tests): document e2e smoke harness hardening for PR #498 --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> --------- Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> * [37e6d999] Backend: repair failing CI checks on auditor revival PR #499 (#503) * [6e79bada] Triage and fix Python quality gate and Analyze (python) failures (#501) * [6e79bada] fix(task): replace type ignore with forward-reference cast for SQLAlchemy Mapped UUID in get_all_descendants * [6e79bada] fix(notification_delivery): add generic type arguments to dict return types in get_ack_status and get_delivery_summary * [6e79bada] docs(changelog): add Python quality gate type-hygiene fixes to Unreleased --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [50e7e104] Triage Analyze (javascript-typescript) failure on backend-only diff (#500) * [50e7e104] Split CodeQL workflow so JS/TS analyzer only runs on panel changes * [50e7e104] docs(backend): document split CodeQL workflow triggers and branch protection notes --------- Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [203c426b] Triage and fix e2e lifecycle smoke (scripted agents) failure (#502) * [203c426b] fix(orchestrator): pre-initialize _instances in __new__ so __init__-bypass tests survive _dispatch_audit_work; allow audit_interval_seconds=0; mount /api/notifications in e2e harness * [203c426b] fix(e2e_smoke): restore ROBOCO_AGENT_TOKEN isolation and clarify /api/notifications mount comment * [203c426b] docs(map): document orchestrator __new__ pre-init and e2e harness token isolation for auditor-revival smoke fix --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [48cb05c2] Fix remaining e2e lifecycle smoke (scripted agents) failure on auditor-revival PR #503 (#504) * [48cb05c2] Harden AgentOrchestrator __new__ pre-init for auditor dispatch state * [48cb05c2] Document auditor-dispatch pre-init rationale in AgentOrchestrator __new__ * [48cb05c2] docs(orchestrator): extend __new__ pre-init docs for auditor-dispatch state --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> * [90c9474c] intake: ambient workspace note + dedupe scope clones by git_url Two intake follow-ups folded into 90c9474c's spec Notes: (a) _resolve_intake_ambient now prepends a workspace note so the intake agent knows its cwd holds clones of every project in the scope (the primary at cwd, siblings alongside under /data/workspaces) and drafts against the real trees via Grep/Glob/Read, not from memory. (b) _clone_intake_scope dedupes slugs by git_url before cloning. A multi-project scope can list several projects pointing at one repo (a monorepo's cell-projects share a git_url); cloning each produced redundant identical workspaces. Mirrors CI-watch's per-git_url dedupe: keep the first slug per non-empty git_url; a project with no/empty git_url is never collapsed onto another so distinct local repos still clone. The dedupe is a pure static helper (_dedupe_slugs_by_git_url) with unit coverage. --------- Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
ba7135ba50 |
feat(gateway): carry intake technical depth down the chain + widen review coherence scope (#491)
Two structural issues flagged by the CEO:
1. Task technical-depth dilution — intake's rich analysis (file:line
targets, code examples, rationale) was getting lost as it traveled
umbrella -> root-subtask -> cell -> dev. The detail IS preserved in
Task.description; the dilution was in delegation (PMs re-authoring)
and the intake prompt not demanding depth.
Fixes:
- evidence_repo: ancestor_context_for_task walks the parent chain
(cycle-guarded, depth-capped 16, desc-clipped 1500) and surfaces it
as parent_context in the evidence payload, so a leaf dev finally
sees the upstream intake analysis instead of a bare title.
- evidence_builder: Task.description now rides in the payload;
EvidencePayload gains description + parent_context (omit-when-empty
so no null noise).
- orchestrator: _description_body (capped 4000) injects the
description into the dev spawn prompt + SessionStart briefing.
- role prompts (main_pm/cell_pm/developer/prompter): teach pass-the-
torch, don't-dim-it; prompter now demands file:line/code-examples
in the_work/notes (reconciled with the no-code-level-ACs-on-roots
rule). main_pm's brief-not-a-spec scoped: not-a-spec applies to the
solution only, facts forward verbatim.
2. PR-review/QA scope too narrow — they only checked the AC checklist,
not whether the change is coherent with project structure/intent.
Fixes:
- qa.md + pr_reviewer.md: Coherence & intent rule (intent via
description+parent_context, coherence with project patterns,
standards). Criterion-less major findings allowed for intent drift
(Finding.criterion is optional).
- parent_context + description wired into the gate/QA/inbound-PR
evidence builders (fail-open, logged).
Skipped per YAGNI: a technical_spec JSONB column (detail is already in
description) and a criterion_kind enum (criterion is already optional).
All gates green: ruff, mypy (1152), pytest (12883 passed, 94.82% cov),
xenon, vulture, bandit, pip-audit, deptry, alembic, import-linter,
foundation-check.
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
192524265c |
[f309463f] Systematic tooltip and aria-label pass across the entire panel (#484)
* [001c9a7a] Author tooltip/aria-label spec for the panel (#469) (#473) * [001c9a7a] docs(ux_ui): add tooltip/aria-label classification spec for panel controls * [001c9a7a] docs(ux_ui): commit missing tooltip/aria-label spec content Prior commit's message claimed to add the spec but only touched unrelated generated lifecycle prompt files — the actual spec file was never git-added. This commits the real content. --------- Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> * [dbe222aa] Implement tooltip and aria-label sweep across all panel surfaces (#478) * [6f991331] Add aria-label + matching tooltip per tooltip-aria-label-spec.md (#476) * [6f991331] feat(panel): add aria-label + matching tooltip to 8 icon-only controls per tooltip-aria-label-spec.md §1a/§1b, wrap assignee-avatar initials in a full-name tooltip * [6f991331] docs(accessibility): add icon-only controls pattern guide for aria-label + matching tooltip Documented the implemented pattern for accessible icon-only controls across 8 components (bell, back-arrow, menu, toggle, drag-handle, move-forward, settings, review-link) plus the assignee-avatar tooltip. Covers when to apply the pattern, naming conventions, state-dependent labels, testing approach, and rationale for local TooltipProvider scope. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [e34da833] Fix notification-bell.tsx and assignee-avatar.tsx, re-verify all 9 claimed tooltip/aria-label retrofits (#480) * [e34da833] test(notifications): add regression coverage confirming the bell button's aria-label/title/Tooltip and re-verify the other 8 tooltip-aria-label-spec controls by direct file read * [e34da833] docs(ux_ui): update tooltip-aria-label-spec.md status to "implemented" with test coverage summary --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [09414273] fix(header): wrap refresh button in Tooltip; correct spec.md and accessible-icon-buttons.md doc-accuracy issues (#483) 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> * [f309463f] fix: missing tooltip/Link/ArrowLeft imports + dedupe command-center tooltip import, drop redundant native title on refresh button, reflow doc prose - kanban-card.tsx, header.tsx: import TooltipProvider (used but undefined -> eslint react/jsx-no-undef, blocked Panel lint + QA image panel build) - task-header.tsx: import Link (next/link) and ArrowLeft (lucide-react) for the back button tooltip - command-center.tsx: remove the duplicate tooltip primitive import block (kept the one with TooltipProvider; tsc duplicate-identifier) - header.tsx: drop native title= on the refresh button now that a Radix Tooltip carries the hint (header test expects no native title) - docs/frontend/components/accessible-icon-buttons.md: reflow hard-wrapped prose (python gate make reflow-docs) * [f309463f] chore: regenerate lifecycle artifacts + verb tables (reconcile after master merge) The branch's generated intro prose in agents/prompts/_generated/lifecycle-*.md and verbs.md had drifted to unwrapped lines (master is wrapped). The foundation- check gate (make lifecycle + regenerate_verb_tables + git diff --exit-code) caught the drift. Re-rendered via the canonical generators; no hand-edits. * [f309463f] Close remaining a11y gaps: aria-labels on task-table row-expand + pagination, titles on work-session truncated task-id/branch, secretary Start loading label --------- 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: Renn F <rennf93@users.noreply.github.com> |
||
|
|
1114ee5ea0 |
[77719d3f] A2A team telemetry: coordination event notifications for 5 event types (#477)
* [13d03d5c] Add 5 coordination-event notification producers + wire at chokepoints (#472) (#474) * [13d03d5c] Add 5 coordination-event notification producer methods * [13d03d5c] Wire reassignment/collision/unblock/dependency-revival notifications * [13d03d5c] Wire stale-claim-reaped notification into orchestrator reaper * [13d03d5c] fix(runtime): guard reaper's UUID annotation + defensive attr access The stale-claim-reaped notification hook added a runtime-unquoted `UUID` type annotation (only imported under TYPE_CHECKING, so the module raised NameError on import) and a direct `t.assigned_to` attribute access that crashes against the minimal test doubles the existing reaper test suite uses. Quote the annotation and switch to getattr-defensive access, matching `_assignee_is_provider_parked`'s existing convention in the same file. * [13d03d5c] test(notification): unit coverage for 5 coordination-event producers One test per new send_* method (reassignment, collision-sequencing, unblock, dependency-revival, stale-claim-reaped) following the existing _FakeDb/_patch_db_context pattern, asserting subject/body/ related_task_id/priority/recipient-count, plus a no-recipients no-op case for reassignment. * [13d03d5c] test(task): prove reassign + unblock don't double-fire notifications Two chokepoint-level tests mocking NotificationService at its defining module: a repeated reassign() to the same already-current target skips the notification (guarded by comparing against the pre-mutation assignee), and a repeated unblock() on the same task only notifies once since the second call short-circuits on the status!=BLOCKED guard. * [13d03d5c] style(task): ruff format the collision-sequencing wiring block No behavior change — reflows the newly-added _notify_collision_sequencing call site to satisfy ruff format's line-length rules. * [13d03d5c] docs(backend): add coordination-event notification producers guide Documented the 5 new NotificationService producers (reassignment, collision-sequencing, unblock, dependency-revival, stale-claim-reaped) with fire conditions, double-fire prevention mechanisms, and implementation patterns. Updated backend README to link the new services guide for developers integrating new coordination events. --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [3ee8150b] Frontend: render coordination-event notifications + e2e smoke coverage (#475) * [69777c3a] test(e2e-smoke): add coverage for soft-block + unblock coordination notifications (#471) Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech> * [8eb82639] Render 5 coordination-event notification types with task deep-links (#470) * [8eb82639] feat(notifications): add APPROVAL type icon and deep-link component test Add missing APPROVAL member to the frontend NotificationType enum to match backend roboco/models/base.py, wire its icon into the existing typeIcons Record in the notifications page, and add a component test covering type rendering and the task deep-link. * [8eb82639] docs(notifications): document 5 coordination-event types and APPROVAL enum addition Added comprehensive reference guide explaining the 5 notification types (TASK_ASSIGNMENT, BLOCKER_ESCALATION, REVIEW_REQUEST, DOCUMENTATION_REQUEST, APPROVAL), their visual identities (icon + color), use cases, and deep-linking behavior to related tasks. Updated panel README with quick reference table. TypeScript Record pattern ensures exhaustive type coverage at build time. --------- 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 Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [a27de2a8] fix(docs): reflow hard-wrapped notification-types.md to pass markdown gate (#479) (#481) The Python quality gate on assembled PR #477 was red because the newly added docs/frontend/components/notification-types.md (introduced by the frontend coordination-event rendering commit) had manually wrapped prose paragraphs, which scripts/reflow_md.py --check rejects as part of make quality. Reflowed the file with scripts/reflow_md.py --apply (whitespace only, no content change) so the check passes. ruff format/check, mypy, xenon, vulture, bandit, and the full pytest suite (10284 passed) all confirmed green on this commit; notification.py, task.py, and orchestrator.py are untouched. Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> * [705419d5] Remove duplicate unblock notification and fix its dependent tests (#485) (#488) * [705419d5] fix(notifications): remove duplicate unblock notification, fix its tests The /unblock route was still calling delivery.notify_assignee_of_unblock() (TASK_ASSIGNMENT) after TaskService.unblock() already sent the send_unblock_notification() ALERT wired in by an earlier task — a real duplicate notification on every unblock. Delete the route-layer call and the now-dead NotificationDeliveryService.notify_assignee_of_unblock method, fix the integration test that mocked it, and fix/extend the e2e notification-coordination-events test to assert the persisted ALERT rows (exact subjects) for both the direct-unblock and dependency-revival producers instead of the old TASK_ASSIGNMENT assertion. * [705419d5] docs(backend): update coordination-events doc for unblock duplicate removal --------- Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech> Co-authored-by: Backend Documenter <be-doc@roboco.tech> * [6c142a73] docs(changelog): document restored coordination-event notification producers and add collision-sequencing double-fire test (#489) (#490) Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech> * [77719d3f] Seed system agent in e2e harness to fix unblock/dependency-revival notifications The e2e harness's seed_company omitted the system sentinel agent that production seeds via initial_data.py. The unblock and dependency-revival notification producers default to from_agent="system", which _resolve_agent_uuid looks up by slug in the DB. With no system row the resolver returns None and _create_notification silently skips the notification, so the two ALERT assertions got 0 rows instead of 1. The soft-block test passed because it uses NotificationDeliveryService which creates the notification directly with a real agent UUID as from_agent, bypassing the slug resolution path entirely. * [77719d3f] Use foundation UUID for system agent to avoid slug collision The first attempt seeded the system agent with a random UUID. Other tests (_seed_system_and_secretary, _seed_video_agents) check by the fixed foundation UUID via session.get(AgentTable, uuid); not finding it they INSERT their own system row, hitting ix_agents_slug. Using the foundation UUID makes their check find the seed_company row and skip. * [77719d3f] Fix dependency-revival notification event loop mismatch The dependency-revival test calls _unblock_dependents directly via stack.run_db, which creates a new asyncio event loop. Inside, _notify_dependency_revival -> NotificationService._create_notification opened its own session via get_db_context(), which reuses the singleton _DbHolder engine — bound to the FastAPI server's event loop. The asyncpg connection raised 'Future attached to a different loop' and the exception was silently caught + logged as a warning, so the notification never persisted and the test saw 0 rows. Fix: add an optional db_session parameter to _create_notification and the two send methods. When provided, use the caller's session directly and skip the internal commit (the caller owns the transaction). The TaskService's _notify_unblock and _notify_dependency_revival now pass self.session, keeping the notification in the same event loop + session as the task transition. * [77719d3f] Scope system-agent seeding to notification tests only Seeding the system sentinel in seed_company (commits 3bba7b32/617b7890) fixed the 0-notification bug but caused 3 i_documented gateway_timeout failures: every e2e test now paid notification-creation latency for system-origin notifications that were previously silently skipped, pushing the already-slow i_documented verb past its 120s timeout. Move system-agent seeding out of seed_company and into a scoped _seed_system_agent helper called only by the two coordination-event tests that exercise send_unblock_notification / send_dependency_revival_notification (both resolve from_agent='system' via DB lookup). dev_lifecycle and state_machine tests revert to the pre-fix behavior (system-origin notifications silently skipped, no extra latency). The event-loop fix (commit |
||
|
|
acb4d567d2 |
fix(panel): settings preferences become real client prefs — no more 422 save, no more theater toggles (#487)
The Settings page PUT four keys (notifications_enabled, sound_enabled, auto_refresh, refresh_interval) the backend's settings allowlist never accepted — Save died on the first 422 and had never persisted these cards. Worse, nothing consumed the prefs anywhere: no auto-refresh timer, no notification toast, no sound system existed. Pure theater. - the four prefs move into the persisted UI store (client-only, same idiom as theme/sidebar) and the cards apply instantly; the dead server plumbing and the global Save button are gone — the backend allowlist stays strict and untouched - AutoRefreshDriver (new): when Auto Refresh is on, ticks the page-refresh registry every N seconds — skips while nothing is registered or a refresh is in flight; default-off so no background poller starts unasked - NotificationAlerts (new): toasts each newly-arrived WS notification (subject + priority) when notifications are enabled, with an optional ~120ms Web-Audio chime — initial backlog on connect never toasts, one chime per batch, autoplay blocks never throw - tests: settings page rewritten store-driven; fake-timer coverage for the driver; stream/store/sonner/AudioContext-mocked coverage for alerts Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
cea3e56628 |
feat(lifecycle): revision findings ledger — structured failure feedback, persisted and delivered down the chain (#486)
* feat(lifecycle): revision findings ledger — structured QA/PR/PM/CEO failure feedback, persisted and delivered down the chain Every bounce used to survive only as flattened prose: rounds overwrote each other in notes_structured, request_changes persisted nothing, two raw dev_notes appends were silently destroyed by the next handoff note, and the dev prompt pointed at fields (qa_notes via evidence(), pm_notes) the API never delivered. Agents re-interpreted and re-discovered every failure before they could start fixing it. - task_review_findings (migration 071, append-only): file/line/severity/ criterion(AC-id-validated)/expected/actual/fix/evidence per finding, with origin (qa|pr_gate|pm|ceo), round, and an open->addressed->verified lifecycle (waived reserved); new tasks.pm_notes + PmReviewContent give request_changes a structured home - producers: fail_review/pr_fail/request_changes take findings=[...] (prose issues shimmed+merged for one release, deprecation-logged); ceo_reject validates its reason (no 500), lands an origin=ceo finding, and bumps round+audit on branchless coordination roots; guardrails at the verb chokepoint (nudge >5, hard reject >10, field caps, traversal-safe file); the dev_notes data-loss appends are removed; new task.request_changes + task.ceo_reject audit events close rework attribution - delivery: qa_notes/pr_reviewer_notes/pm_notes carry the deterministic [F-id8] rendering; claim briefings, evidence(), the REVISION_REQUIRED spawn prompt, PM triage bounced-blocks, and A2A bodies deliver open findings; round-N+1 QA and gate reviewers get the full prior ledger; panel Findings tab + bounced-xN chip; metrics pm_rejects/ceo_rejects + findings counts; vault task notes render a Findings section (fail-open) - resolution closes for every origin: i_am_done and submit_up/submit_root take resolved_findings gated by FINDINGS_ADDRESSED (owner-gated so a stale non-owner PM can never mutate the ledger); pass_review/pr_pass/ complete verify-stamp same-transaction; ceo_approve stamps best-effort - 24 real-DB integration tests drive the full loop through the real choreographer; full suite 12856 green * docs: revision findings ledger sweep — CLAUDE.md, map, RAG corpus - CLAUDE.md: new ledger section + corrected request_changes row - docs/map/review-findings.md (new subsystem map) + surgical updates to task-service/pr-gate-review/metrics-observability/vault/panel maps - docs/rag: producers' findings contract across qa/pr-reviewer/developer/ cell-pm/main-pm/ceo role docs (the PM docs were missing request_changes entirely), verb references, and a new architecture/review-findings.md disambiguating ledger findings from convention findings * test(e2e): resubmit resolves the pr_fail finding per the ledger contract The scripted pr_fail revision loop resubmitted submit_up without resolved_findings — correctly rejected now that FINDINGS_ADDRESSED gates the PM resubmit verbs (green locally, red only in CI since the e2e suite skips without ROBOCO_E2E_SMOKE=1). The scripted PM now reads the open ledger row pr_fail persisted (new open_finding_ids arc helper) and resolves it on resubmit, asserting the open set drains — exercising the coordinator half of the new contract end to end. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
d03181ab48 |
feat(vault): Obsidian vault V2 — janitor, archival, weekly report, KB ingest, Bases + sync runbook (#482)
* feat(vault): V2 — create-seam + drift janitor, archival, weekly org-report, KB ingest, Bases views + sync runbook Implements the vault V2 canonical spec end to end (the splice guard shipped separately and is reused at KB-ingest time): - materialize-on-create: TaskService.create writes each task's note best-effort from the moment it exists; the transition-touch stops no-oping on live work - drift janitor (services/vault_janitor.py + hourly _vault_janitor_loop): daily changed-task re-projection, random drift sample, archival pass — restart-proof via RoboCo/_meta/.janitor_state.json, 200/cycle caps, per-item isolation, processed-only resume markers, self-repairing state file - archival: vault_archive_days (30, 0=off) moves old terminal tasks' notes to RoboCo/Archive/<year>/Tasks/<project>/ — one write_task code path for janitor and rebuild, id8 lookup across Tasks/+Archive/, alias links keep moves safe - weekly org-report: VaultWriter.write_org_report renders Reports/<ISO-week>.md from MetricsService/UsageService (numbers duplicated into frontmatter for trend queries), once per ISO week, with a best-effort CEO notification - KB ingest: IndexType.VAULT_NOTES + VaultNotesIndexPlugin + _vault_kb_loop embed the CEO's RoboCo/Notes into the RAG corpus — injection guard as a hard gate (flagged notes quarantined with an idempotent callout), traversal- and symlink-contained at both config and engine layers, content-hash dedup, 50-ingest/cycle cap, frontmatter stripped; reaches roboco_kb_search, the mentor default domain, claim-time briefings (kind vault_note), and the panel KB browser; no migration (chunks table auto-creates; migration 030's CHUNK_TABLES tuple appended per the chunks_playbooks precedent) - Bases views (Task Board.base, Reports.base — schema verified against the Obsidian docs) + the Mac sync runbook vault asset - config/flags/compose: vault_archive_days, vault_report_enabled (flags card), vault_kb_enabled (flags card; NAS compose arms it, registry ships it off), vault_kb_dirs (+ overlap/traversal validator), vault_kb_interval_seconds - e2e smoke (tests/e2e_smoke/test_vault_v2.py): real create-seam, real janitor cycle incl. archival + state, real KB engine + real guard * docs: vault V2 sweep — map, RAG corpus, CLAUDE.md - docs/map/vault.md: V1+V2 — janitor/archival/report/KB data flows, new files, config, health posture - docs/map/orchestrator.md + task-service.md: the two new loops, the create seam, the three janitor queries - docs/rag/architecture/obsidian-vault.md: agent-facing what-changed (notes from creation, archive link-safety, CEO notes retrievable, weekly report) - docs/rag/architecture/config-reference.md: the five new settings - CLAUDE.md: vault paragraph covers V1+V2; flags-card list mentions the vault report/KB flags --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
5a0fce7da4 |
docs: v0.23.0 agent-facing sweep — map, RAG corpus, CLAUDE.md (#468)
New map + RAG entries for the vault subsystem; sequence gate, lineage merge, gate diff-base, CI guard, playwright MCP, dispatcher prefilter, backup sidecar, and the 300/100 budget reflected across docs/map, docs/rag, and CLAUDE.md; stale claims fixed (agent-ux 'no extra tools', old budget defaults). No redirects needed — nothing publicly published moved. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
950b0abf5f |
feat(vault): arm the Obsidian vault in both compose files (#467)
ROBOCO_OBSIDIAN_VAULT_ENABLED + ROBOCO_VAULT_PATH (/app/vault, mounted from the data dir) + ROBOCO_VAULT_INTAKE_ENABLED on the orchestrator, default-on for the NAS deploy per the arm-new-flags convention. Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f2834cf521 |
fix(tasks): merge cross-lineage dependency content at branch cut (#466)
* fix(tasks): merge cross-lineage dependency content at branch cut The dependency gate enforced timing but never content: a dependent's fresh branch could miss a same-repo dependency's merged work when that merge landed outside the branch's own ancestor chain (cross-cell edges under one root, same-repo batch cross-root edges). After a successful branch cut, each dependency's real merge target (resolve_parent_branch) is fetched and, unless already an ancestor, merged into the new branch; conflicts abort cleanly (branch stays at its cut point, warning + an accumulating task marker note) and never fail the claim. Cross-repo dependencies are skipped — no shared history. Zero git work for the no-deps common case; resumes never re-enter (branch creation only). * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose * [lineage] mypy-clean mock idioms in the lineage orchestration tests --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
50ec283533 |
fix(api): settings PUT accepts booleans/numbers from the panel (#465)
* fix(api): settings PUT accepts the JSON scalars the panel sends The feature-flags card sends booleans and numeric settings send numbers; SettingUpdate.value was typed str, so pydantic 422'd on type before the per-key validators ever ran (live: PUT /settings/notifications_enabled). Scalars now coerce to the stored text form — bools to the 'true'/'false' the validators parse. * chore(docs): reflow hard-wrapped prose from the #401 merge * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
53a028ec04 |
fix(agents): raise tool-call budget to 300 (halt) / 100 (warn) (#464)
* fix(agents): raise the tool-call budget — 150 halted legitimate work mid-task Repeated budget-sweep bounces: a dev at the 150 ceiling gets its container killed seconds after a real commit, burning a spawn and the resumed agent's re-verification turns. 300 keeps the runaway guard while clearing a real task's footprint; warn scales to 100. * chore(docs): reflow hard-wrapped prose from the #401 merge * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
20110debab |
fix(ci): fleet-branch push triggers + dispatcher claim prefilter (#463)
* fix(ci): fleet-branch push triggers close the absent-check gap; dispatcher claim prefilter PROVEN with API receipts: when the PM squash-merges a subtask PR into a branch that is itself another PR's head (GitService.merge_pull_request → GitHub's Merge API), the pull_request synchronize webhook fires unreliably (1 of 3 in the live sample) while plain push events fired 100% — so PR heads sat with ABSENT required checks that three review rounds mistook for green. CI, CodeQL, e2e-smoke, and panel-ci now also trigger on push to the fleet's branch types, deduped by a concurrency group keyed on head_ref||ref_name so a branch that is also a PR head never double-runs. Dispatcher churn: _route_unassigned_pm_task consults the claim guards' own predicate (TaskService.is_pending_claim_blocked, a public wrapper — no duplicated SQL) before routing, so dependency- or sequence-held tasks skip the tick with zero HTTP claim round-trips; fails open so a DB hiccup degrades to the old behavior. * chore(docs): reflow hard-wrapped prose inherited from the six-PR merge train * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
786e6ffc3c |
fix(security): prompt-injection screening for engine-ingested external text (#462)
* fix(security): screen engine-ingested external text for prompt injection The X mentions poll and the vault inbox both fed attacker-writable text (tweets, tagged notes incl. meeting-bridge output) raw into local-model prompts and CEO-facing draft payloads. The agent-sdk prompt guard's detection moves to a pure roboco/foundation/policy/injection_guard.py (prompt_guard re-exports it — grok path byte-identical) and gains screen_external_text: per-line detection where a matched line is flagged in place, never dropped, and the whole text rides an explicit untrusted-content envelope. Both engines screen once at ingestion and use the screened rendering for the model prompt AND the persisted marker/description — including the vault engine's deterministic LLM-failure fallback, which previously used the raw body verbatim. * chore(docs): reflow hard-wrapped prose inherited from the six-PR merge train * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
f7f411e112 |
fix(infra): release builds all 17 registry images; pg_dump backup sidecar (#461)
* fix(infra): release builds all 17 registry images; pg_dump backup sidecar release.yml was missing roboco-agent-grok-prompter and roboco-agent-grok-secretary (both FROM the bare local roboco-agent-grok tag, so agent-grok now builds explicitly ahead of the loop, mirroring the agent-base special case) — a fresh registry pull could never succeed. Both compose files gain a backup sidecar on the data network: pg_dump -Fc on start and every 24h, crash-safe tmp+rename, newest-14 rotation, restore walkthrough in docs/backend/ops/database-backups.md. * chore(docs): reflow hard-wrapped prose inherited from the six-PR merge train * chore(foundation): regenerate lifecycle artifacts; reflow inherited prose --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
6e57066bd6 |
[a360b6e3] Redesign A2A page with conversation-first layout and agent identity (#401)
* [54b94e44] A2A page: filter controls + agent identity consistency (#387) (#392) * [54b94e44] feat(a2a): add filter bar and unify agent avatars + pulse across views Adds a status (active/all) + free-text search filter bar above the A2A switchboard/list content, backed by a shared a2a-filter-utils module so both A2ASwitchboard's pairs and A2AConversationList's conversations narrow identically. Extracts A2APairCard's pulse-flash state into a reusable usePulseFlash hook and exports its PairAvatar so the classic conversation list now renders the same two-participant avatar and emerald pulse-flash affordance the switchboard already had. * [54b94e44] docs(a2a): add comprehensive filtering and avatar documentation Documented the new A2A filter bar, filter utilities, pulse-flash hook, and conversation list API changes. Includes examples, testing guidance, and migration notes for the pulses prop requirement. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [54417f0c] UX/UI: design A2A conversation-first layout and agent identity (#399) * [f612a5ab] Add conversation-first layout, agent identity, and live-stream affordance spec (#384) Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> * [7ed2ef71] docs(ux_ui): add filter-control design spec for A2A conversations (#383) 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> * [f563bbc9] Implement conversation-first A2A layout, identity colors, connection states, transcript motion, and empty/error states (#423) (#427) * [f563bbc9] feat(a2a): conversation-first layout, team-color identity, connection states, transcript motion, empty/error states Implements docs/ux_ui/design/02-conversation-first-layout-agent-identity-live-stream.md: - xl:+ collapsible Context pane (identity cards, linked-task summary, no-task hint), persisted via the existing zustand ui-store - getAgentTeamColor + TEAM_COLOR_CLASSES in agent-utils.ts, applied to PairAvatar, the transcript row avatar, and the context pane - A2AConnectionBadge/A2AConnectionBanner rendering all four ConnectionState values distinctly with a motion-reduce-guarded pulsing dot and a dismissable reconnecting/disconnected strip - A2ATranscript: transform/opacity-only new-row entrance transition, scrolled-up "New messages" pill, split hasSelection/empty/error states with a scoped Retry - Unit tests for every new pure helper and component * [f563bbc9] docs(a2a): conversation-first layout, team-color identity, connection states, transcript motion, empty/error states Document the new conversation-first A2A layout features: - Agent team-color system (getAgentTeamColor, TEAM_COLOR_CLASSES) for six cell buckets - A2AContextPane component with identity cards, linked task summary, no-task hint - Connection state rendering (A2AConnectionBadge, A2AConnectionBanner) for all four ConnectionState values - Transcript entrance motion with transform/opacity-only transitions and prefers-reduced-motion guards - Split empty/error states (no selection, no messages, fetch error with scoped retry) - Page-level integration with xl:+ responsive grid layout Includes component API, usage examples, testing guidance, accessibility notes, and design rationale. --------- Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [478f027c] Implement A2A conversations filter control per conversations-filter-control.md (#445) (#448) * [478f027c] feat(a2a): add multi-dimension Popover filter panel for A2A conversations Replace the free-text search + active/all toggle with the Popover-triggered filter control from conversations-filter-control.md: Agent multi-select checkboxes, a Task id-fragment input with a "No linked task" toggle, Status toggle buttons, and a date range, plus an active-filter chip row and Clear all. Filtering applies to both the switchboard (Agent only) and conversation list (all four dimensions) per the design doc's per-view rules. * [478f027c] docs(a2a): add comprehensive filter-control guide covering component API, filter dimensions, and per-view rules Documents A2AFilterBar component and filter utilities with: - Component API and props - All 4 filter dimensions (Agent, Task, Status, Date range) - Per-view rules (Switchboard vs List) - Usage examples and parent setup - Filter logic and match predicates - Testing guide and accessibility notes - Design notes on client-side filtering limitation - Links to related components and the design spec Helps developers understand, use, and maintain the A2A conversations filter control without needing to read the design doc or component source. --------- 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 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@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> Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech> Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
340fcebce2 | fix(scripts): dedupe SKIP_DIRS entries left by the twin gate-fix merges (#456) | ||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
e1d1fdc707 | Merge pull request #370 from rennf93/fix/gateway/sync-branch-standalone-base | ||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
4fb0059556 |
fix: journals/learnings never reached the RAG corpus + git-readonly slug 404s (#339)
* fix(rag): per-index chunk floors — journals and learnings were never indexed The global 200-char garbage floor (sized for code/doc chunks) discarded every templated journal note and most distilled org-memory lessons, silently: ingest returned success with zero chunks, so agent journals and learnings were never retrievable via RAG. IndexConfig now carries a per-type min_chunk_length (journals 40, learnings 80, others unchanged). * fix(mcp): git-readonly tools default project_slug from the container env Agents 404ed /api/git/status with 'Project not found: roboco' — the tools made the LLM supply the slug and six doc examples taught a slug that matches no registered project. The tools now fall back to the ROBOCO_PROJECT_SLUG the orchestrator already injects, and the stale examples are corrected. * feat(rag): startup backfill re-ingests zero-chunk journals and learnings Before the per-index chunk-floor fix, ingest() returned success with chunk_count=0 for undersized content: every historical journal entry and distilled learning below the (then-global) 200-char floor was durably recorded in journal_entries but silently never got a chunks_journals / chunks_learnings row, and no exception meant the existing dead-letter (rag_index_failures) never saw it either. Extends the startup reconcile (roboco/api/app.py _reconcile_rag_indexes) with a new pass: backfill_unindexed_journals (roboco/services/ rag_index_failures.py) queries journal_entries for rows missing from each vector table and re-ingests them through the same live code paths (_reindex_journal_entry / record_learning). Journals and learnings are backfilled independently since a LEARNING entry can clear the (lower) JOURNALS floor while still failing the (higher) LEARNINGS floor — a learning's doc_source is a content hash, not the entry id, so presence there is checked by hashing each candidate the same way LearningsIndexPlugin.record_learning does and batch-querying chunks_learnings for those exact sources. Bounded to 200 rows per pass per boot (converges over restarts on a larger backlog) and best-effort per row (one failure never aborts the pass). Rows still under the current floor are excluded by a length filter in the SELECT so they are never retried forever, and private entries are excluded from the JOURNALS pass exactly like the live indexing path. * test(rag): scope backfill assertions to their own rows --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com> |