Commit Graph
159 Commits
Author SHA1 Message Date
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>
2026-07-18 07:06:32 +02:00
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>
2026-07-18 07:05:20 +02:00
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>
2026-07-18 07:04:38 +02:00
Renn F 29b375f1b5 fix(panel): session links target the owning task — /work-sessions/<id> never existed 2026-07-18 05:41:07 +02:00
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>
2026-07-18 02:47:59 +02:00
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>
2026-07-18 00:47:09 +02:00
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>
2026-07-18 00:45:21 +02:00
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>
2026-07-18 00:44:48 +02:00
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>
2026-07-18 00:44:00 +02:00
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>
2026-07-18 00:42:13 +02:00
Renn F 0843bbaaaa 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.
2026-07-16 15:47:08 +02:00
Renn F 33cb4d7104 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.
2026-07-16 06:59:22 +02:00
Renn F e939d73844 fix(panel): hide the Report-CEO button when no handler is wired
The prop was never passed by any consumer, leaving a silent no-op
button on urgent flags; it now renders only when a real handler
exists.
2026-07-15 18:05:58 +02:00
Renn F dcd2f84e69 feat(panel): dense tooltip pass — work surfaces (270 tips)
Task lifecycle actions get a 25-action tip map, every dialog field and
git panel control annotated; fixes two round-1 disabled-button tips
that could never fire and a double data-state stamp on tab-progress.
2026-07-15 18:04:00 +02:00
Renn F f9dbb30a4e feat(panel): dense tooltip pass — org surfaces + layout chrome (253 tips)
Every sidebar destination, metric derivation, sortable column, queue
action, and dialog control explains itself; mobile tab bar shares the
sidebar's descriptions so the two nav surfaces can't drift.
2026-07-15 18:04:00 +02:00
Renn F e7d8e7ecb5 fix(panel): AI routing breathing room — wider column gutters, roomier override rows
Key band gets a 14-unit gutter between the key column and self-hosted;
mix-mode rows gain horizontal separation, vertical rhythm, and taller
row padding.
2026-07-15 17:57:42 +02:00
Renn F 57254b3ce2 feat(panel): dense tooltip pass — projects, products, social, KB, business, settings, notifications (178 tips)
Density bar: every dialog field, column header, filter, badge, and
status pill explains itself — grounded in the backend (ladder
normalization, rate-limit park/probe, self-hosted fallback, reindex
scope). Disabled buttons span-wrap so tips fire; tabs re-assert
data-state.
2026-07-15 17:56:12 +02:00
Renn F 84563e84b6 feat(panel): worked-example tooltip on the environment ladder
The section label now explains the typical dev/slave -> prod/master
two-rung setup inline, when to add middle rungs, and what no ladder
means.
2026-07-15 17:31:45 +02:00
Renn F 5fefb0f2c0 fix(panel): environment ladder speaks promotion flow, not git jargon
First rung badges 'PRs land', last badges 'release', middles drop the
fake rung-N names, and a 'promotes to' connector shows the direction
between rows; helper copy and the dialogs' default-branch hint follow
the same vocabulary.
2026-07-15 17:30:35 +02:00
Renn F 77229b10b1 fix(panel): agent cards — intrinsic auto-fill grid, roomier cards
repeat(auto-fill, minmax(17rem, 1fr)) replaces the breakpoint ladder:
one column on a phone through eight on a 27", consistent card width
across every team section at any viewport. Cards gain padding and a
base-size title.
2026-07-15 17:17:19 +02:00
Renn F 3d1c20e95a feat(panel): tooltip sweep — overview, agents, A2A, journals, auditor, metrics
Derivation tips on every key-metric, scorecard, and quality-metrics
figure; the cryptic member-scorecard headers get full decodes; avatar
initials, truncated ids, and toggle buttons gain accessible names;
title-only hints upgrade to the HelpTip idiom throughout.
2026-07-15 16:40:13 +02:00
Renn F c37516f640 feat(panel): tooltip sweep — projects, products, social, KB, business, settings, notifications
All 34 feature flags get verified one-line tips; secret inputs state
the write-only contract; KB index types get canonical descriptions;
switch tips ride Labels so Radix data-state stays intact. Also fixes
the scorecard SectionLabel swallowing props, which made tooltips on it
silently inert.
2026-07-15 16:33:22 +02:00
Renn F d1b02e3747 feat(panel): tooltip sweep — tasks, kanban, task assistant, git, work sessions (58 tips, 22 files)
Full import-graph walk per page: filter-chip and plan-section icon
buttons gain their first accessible names, per-state description maps
for git/docs/finding/priority badges, truncation-gated full-value tips,
disabled buttons explain their gate. Stateful Radix triggers use the
task-tabs data-state re-assertion pattern.
2026-07-15 16:30:26 +02:00
Renn F 14ee9b3b49 fix(panel): phantom agent states in dashboard + metrics counters
by_state.running / a.state 'running'/'stopped' never exist in the
orchestrator enum (offline/starting/active/waiting/idle/stopping), so
these counters were structurally zero — same class as the agents-page
Active bug, remaining two sites.
2026-07-15 16:07:55 +02:00
Renn F 9b0a8b0fae fix(panel): agents page — truthful counts, merged stat row, dense org grid
Total Agents now counts the roster (backend total_agents is live
containers only) and Active reads by_state.active — running/ready never
existed in the backend enum, so the counter was structurally zero.
Board + Main PM fold into one leadership band, cards compress to a
status dot + single detail line, and the grid densifies with per-team
count badges.
2026-07-15 16:06:38 +02:00
Renn F 2efc2f9542 fix(panel): compact task-status tiles beside the donut; journal ids copyable + task-linked
Five near-empty stat cards become a 2x3 tile band sharing the row with
the status donut. Journal entry cards and the entry page render full
ids with the shared CopyButton and a /tasks quick-link badge, with the
entry-card anchor restructured so links no longer nest.
2026-07-15 16:03:11 +02:00
Renn F 614c22ed70 fix(panel): AI providers layout — org-grouped two-column override list; key cards beside self-hosted
Per-agent mix rows group under Board / Main PM / cell / intake headers
in a two-column grid with compact selects; Grok + Ollama key cards
stack in the left column with the self-hosted section to their right.
Save-mix and inherit semantics untouched.
2026-07-15 16:01:06 +02:00
Renn F 6dee7e66a0 fix(panel): task-detail active tab highlight — tooltip wrapper clobbered Radix Tabs data-state
TooltipTrigger asChild spreads its own data-state (closed) through the
Slot merge onto the TabsTrigger, overriding Tabs' active/inactive
attribute, so no tab ever matched the data-[state=active] styles.
Re-asserting data-state in the trigger's own props survives the merge;
derived from the same activeTab that drives the controlled Tabs.
2026-07-15 16:00:18 +02:00
Renn F fb02ae726f fix(panel): agent detail survives a stopped agent — fatal card only on a real roster miss
GET /orchestrator/agents/{id} 404s for any non-running container, and
the page's error early-return unmounted the DB-backed header/activity
content #529 had placed behind it. The fatal card now gates on the
roster identity lookup; a live-status error degrades in place to a
not-running banner + spawn dialog, with retry disabled on the
deterministic 404.
2026-07-15 15:58:29 +02:00
Renn F 59ff610805 fix(panel): overview reorder — quick actions + key cards first, team health second, queues last; PR Reviews + Social share a row
Removes the mobile order hack that hoisted decision queues above the
fold; the empty PR-Reviews state drops to the compact house convention.
2026-07-15 15:58:11 +02:00
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>
2026-07-15 06:10:31 +02:00
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>
2026-07-15 05:45:57 +02:00
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>
2026-07-15 04:43:37 +02:00
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>
2026-07-15 04:34:17 +02:00
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>
2026-07-15 04:34:12 +02:00
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>
2026-07-15 04:34:06 +02:00
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>
2026-07-15 04:34:01 +02:00
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>
2026-07-15 04:33:55 +02:00
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>
2026-07-15 04:33:50 +02:00
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>
2026-07-15 04:33:44 +02:00
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>
2026-07-15 04:33:24 +02:00
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>
2026-07-15 04:33:13 +02:00
Renn FandRenzo F 05a83f45cb feat(auditor): waive_finding verb + findings queue panel
Wire the long-unwired mark_waived repo method to a new auditor-only
flow verb waive_finding, severity-scoped to minor/nit (blocker/major
must be fixed, never waived), requiring a note, with a task.finding_waived
audit event and no task status change. Add the verb to the IntentSpec
table (auto-derived into the auditor manifest), the flow_auditor route,
and the flow_server MCP tool.

Surface open review findings (cross-task, blocking-first) on the
auditor dashboard via ReviewFindingsRepository.list_open_findings and a
new findings field on AuditorDashboard. Restore the panel's 4-card
auditor layout with a new read-only FindingsQueuePanel as the 4th card.
2026-07-14 08:56:55 +02:00
Renn FandRenzo F 6336e82082 [sandbox-ext] Phase 4: panel extension picker + allowlist docs
Project edit dialog (Sandbox section) exposes a per-service extension
picker — Switches from the allowlist grouped under each enabled service
(postgres: pgvector/PostGIS/pg_trgm/citext/uuid-ossp; redis: RediSearch/
RedisJSON/RedisBloom; mongo has none), mirroring the backend
SANDBOX_ENGINE_FEATURES allowlist. State holds a per-service Set; payload
builds sandbox_extensions only for enabled services with non-empty picks
(empty {} clears the column, mirroring sandbox_services' always-send —
exclude_unset + no exclude_none means an explicit {} writes NULL). The
picker renders only for opted-in services with activatable features.

Types: Project.sandbox_extensions (Record<string,string[]> | null),
ProjectUpdate.sandbox_extensions? (not on ProjectCreate, mirroring
sandbox_services). Mock create seeds null.

Docs name the allowlist (the security containment — no plpython3u), the
no-default-set rule (opters set explicitly, existing opters stay bare), the
standing-vs-per-call union, cache-by-features, kitchen-sink image selection,
and the recommendation to set the full set in project settings so agents
request subsets. sandbox-db.md gains an Extensions section; task-tools.md
and config-reference.md updated; CLAUDE.md sandbox paragraph extended.

Gate: panel typecheck + lint + prettier clean, 516 tests pass.
2026-07-13 20:05:45 +02:00
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>
2026-07-13 06:38:48 +02:00
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 7b95d77d: pass db_session=self.session to
_create_notification) is unchanged — dependency_revival still needs it
because stack.run_db creates a new event loop while _DbHolder.engine is
bound to the FastAPI server loop.

* [77719d3f] Fix reassignment notification deadlock + suppressed-notification commit regression

Two fixes in notification.py / task.py:

1. Cross-session self-deadlock in send_reassignment_notification:
   TaskService.reassign() flushes an uncommitted row lock on the task,
   then calls _notify_reassignment -> send_reassignment_notification ->
   _create_notification(db_session=None) which opens a SEPARATE session
   via get_db_context() and INSERTs a notification with related_task_id
   FK -> tasks.id. The FK key-share lock blocks on the request session's
   uncommitted exclusive lock, but the request can't commit until the
   notify returns -> 120s verb hard-cut. Fix: pass db_session=self.session
   so the notification joins the verb's own transaction, same pattern as
   the unblock/dependency-revival fix in 7b95d77d.

2. Suppressed-notification commit regression: the 7b95d77d refactor moved
   await db.commit() out of _create_notification_with_session into
   _create_notification's db_session=None branch, where it ran
   unconditionally — even when _create_notification_with_session returned
   early (suppressed: unresolvable from_agent / no recipients /
   refire-guard / dedup-hit). Fix: _create_notification_with_session now
   returns bool (False at each early return, True after delivery);
   _create_notification commits only when created is True.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-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>
Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-13 06:38:15 +02:00
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>
2026-07-12 00:43:43 +02:00
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>
2026-07-11 22:54:42 +02:00
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>
2026-07-11 15:51:19 +02:00
Renn F e211a3c15e fix(panel): task-detail tab state in URL, nav placement, kanban overflow, sidebar divider, tooltip sweep
- Task detail: active tab lives in ?tab= (survives reload, back/forward, and
  prev/next task jumps); prev/next arrows move into the header row next to
  Actions instead of their own row above the title
- Constraints section always starts collapsed (project boilerplate)
- Kanban: native overflow scroll replaces Radix ScrollArea (display:table
  viewport let cards grow past the column and clip); columns share width
  (flex-1, 18rem floor, 24rem cap); dark column colors normalized to /40 tints
- Sidebar footer: drop the Separator doubled with the wrapper's border-t
- Tooltips: self-providing Tooltip root (300ms) + hover hints across sidebar,
  header, task detail, kanban, and every icon-only button that had none
2026-07-11 10:59:26 +02:00