mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
35b02b11ed8c8a36bb886e7e1c0671b261dcf8fb
906
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
fe9940dec1 |
[env-bran] Route PR/clone/release/diff consumers through the env ladder
PR target, workspace clone, read-clone pin, branch base, merge-target resolver and the default spawn git context now resolve the head rung (head_branch) instead of the raw default_branch. The release executor targets the prod rung (prod_branch) for clone/commit/tag (W-H decouple) and runs a full-chain head->...->prod promotion before the bump, fail- closed on a divergent rung (promotion_failed outcome). release_readiness switches the diff baseline to prod..head with a tag_drift cross-check (last tag != prod tip => hotfix-on-prod). release_manager_engine fetches the prod rung into the head-pinned read clone so origin/<prod> resolves. |
||
|
|
8621d01d54 |
[ENV-LADDER] Add per-project ordered environment ladder column + shim
Replace the single default_branch with an ordered environments ladder
(list[{name,branch}]; first=head=PR target, last=prod=release target,
middle=intermediates). Migration 073 adds nullable JSONB projects.environments;
a read-time shim (roboco/models/env_branches.py) synthesizes a degenerate
single-branch ladder from default_branch when environments is null, so
behavior is unchanged until the operator declares a real split in the panel.
Wired through Project/ProjectCreate/ProjectUpdate models (normalize_environments
validator: rejects empty name/branch + dup branches), ProjectTable column,
API request/response schemas, create+update routes + service. EnvSyncEngine
+ consumer rewires follow.
|
||
|
|
3338f88e1b | chore(release): 0.24.0 v0.24.0 | ||
|
|
cf668bd977 | Updated docker compose yaml to match yml | ||
|
|
e07ebf2b93 |
chore(lifecycle): regenerate artifacts for waive_finding verb
Generated by 'make lifecycle' + scripts/regenerate_verb_tables.py — the foundation-check drift gate requires these in sync with the spec. |
||
|
|
d6cdedcd22 |
fix(tracing): register waive_finding in VERBS_WITHOUT_TRACING (parity gate)
The note + task.finding_waived audit event is the durable rationale — no journal:decision needed, mirroring declare_coverage. |
||
|
|
5a34db2528 | fix(test): annotate _choreographer helper return type (CI mypy checks tests/) | ||
|
|
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. |
||
|
|
62e19ea729 |
test(e2e): vault V2 — private engine, no shared _DbHolder (kill cross-loop flake)
The push-event e2e smoke flaked ~1/50 with ``RuntimeError: Future ... attached to a different loop`` in test_create_seam_materializes_note_flag_on_and_off (and the janitor test shares the same helper). Root cause: _fresh_factory returned the app's SHARED get_session_factory() (_DbHolder engine), so the test's session shared a connection pool with the uvicorn server thread (loop B). A lingering app handler from a prior test could check out a connection on loop B; asyncpg's pool is not loop-affinity-aware, so it then handed the vault test a connection created on loop B, awaited on the test's function-scoped loop A → cross-loop. _reset_lazy_db_holder only resets at teardown, so it can't stop a lingering handler contaminating the fresh pool mid-test. Fix: _fresh_factory builds a PRIVATE engine from e2e_stack.db_url and returns (factory, engine); the caller disposes it in finally. The create/janitor seams use only the passed session (assemble_task_note_data, get_project_service, VaultJanitor never call get_session_factory), so a private engine against the same e2e DB exercises the real wiring while keeping its pool loop-pure — the app can't reach it. This is the e2e-suite cross-loop flake that was blocking PR #516's push-event e2e check (the pull_request run passed, the push run hit this unrelated vault test). Pre-existing; not introduced by the auditor fix. |
||
|
|
1c63c88cbf |
test(audit): guard await_args against None for mypy union-attr
CI mypy (which checks tests/, unlike the targeted source-only run that missed it) flagged ack_mock.await_args.args[1] — await_args is _Call | None. Assert it is not None first, matching the spawn_call pattern above. |
||
|
|
6fe0067f73 |
fix(orchestrator): stop auditor alert-spawn rotation — ack as auditor on dispatch
The auditor respawned every ~3 min on the same stale rework alerts. Root cause: _dispatch_audit_work's alert path fetched the SYSTEM-wide "not fully acked" view (list_system_notifications), but the auditor is read-only (no ack verb) and auditor_triage never acks — so once an alert existed the CEO was the only party who could clear it, and the CEO hadn't acked. The per-alert cooldown (PR #499) only paced a rotation through the N un-acked alerts; it was a damper, not a fix. Fix: fetch the auditor's OWN pending-ack view (GET /notifications authed as the auditor -> list_for_agent, which filters acked_by for the auditor) and ack the alert as the auditor on dispatch. Each alert is now a one-shot, DB-persistent: the next tick cannot respawn on an alert the auditor already observed — even one the CEO hasn't acked. Authed as the auditor (not the system identity) so the route selects the per-recipient view; HTTP rather than DB-direct so it shares the orchestrator's loop in prod and stays loop-safe in the e2e harness (which runs _dispatch_audit_work in its own asyncio.run loop, away from the app's DB engine). e2e now asserts the alert is in acked_by for the auditor after dispatch — the rotation-stopper itself, not just the spawn. |
||
|
|
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> |
||
|
|
09b797fe9c | [sandbox-ext] regenerate verb tables for request_sandbox(extensions=...) signature | ||
|
|
1f769f6315 |
[sandbox-ext] fix: drop dynamic verify SQL (bandit B608) — static query + Python membership
CI bandit -ll flagged B608 at sandbox.py:264 (f-string ANY(ARRAY[...]) with interpolated feature names). Root-cause fix: verify_step now runs a static 'SELECT extname FROM pg_extension' and verify_ok checks set membership against the installed extnames — no interpolation, no string- built-SQL surface, and a more correct check (membership vs count). The enable_step CREATE EXTENSION stays (identifiers can't be parameterized; allowlist-validated upstream, the containment). Tests updated from the count-based exec_out to the extname-list exec_out. |
||
|
|
3ae0dad3d2 | [sandbox-ext] fix: ruff format the refactor (format --check was the CI miss) | ||
|
|
2096af54e8 |
[sandbox-ext] fix: split 3 blocks under xenon rank B (gate was C)
CI xenon --max-absolute B failed on _normalize_sandbox_extensions (project.py), _sandbox_features_scope + request_sandbox (content_actions). Extracted _validate_one_sandbox_extension, _validate_per_call_extensions, _sandbox_provision_or_reject — same behavior, rank B. ruff/mypy/xenon/51 tests green. |
||
|
|
674125cf1e |
[sandbox-ext] fix: use postgresql.JSONB in migration 072 (sa.JSONB does not exist)
CI caught: AttributeError: module 'sqlalchemy' has no attribute 'JSONB'. Repo convention (mig 043/010): from sqlalchemy.dialects import postgresql; postgresql.JSONB(). Integration test now applies cleanly. |
||
|
|
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.
|
||
|
|
e7d7311636 |
[sandbox-ext] Phase 3: parameter surface — schema + project field + verb override + cache-by-features
Migration 072 adds projects.sandbox_extensions (jsonb null): a per-service
extension/module map a venture declares up front (e.g. {"postgres":
["vector","postgis"],"redis":["search"]}). Additive + nullable so
existing opted-in projects stay byte-for-byte bare — no default set, opters
set the extensions they need explicitly (TimescaleDB out unless asked).
Project model validates the map against SANDBOX_ENGINE_FEATURES: unknown
service keys and unallowed features are rejected at the model boundary with
the allowlist named (plpython3u — superuser-RCE — excluded by construction),
empty feature lists drop to bare, order normalized + deduped. The allowlist
is the security containment, not privilege. Mirrors sandbox_services: not on
ProjectCreate, only Project + ProjectUpdate.
request_sandbox gains an extensions arg; _sandbox_features_scope unions a
per-call override with the project's standing set (trusted), bounds it to the
opted set + allowlist, rejects a non-opted service or unallowed feature with
the allowlist named in remediate — scope-first priority preserved by
rej_scope or rej_features. ensure_sandbox threads features through to
provision(); cache-by-features: a cached entry satisfies a new call iff
services are a subset AND every requested feature per service is already
cached — a feature superset re-provisions (rotates creds), mirroring the
services-superset case. available_extensions rides the evidence payload so an
agent doesn't guess what was activated.
Gate: ruff clean, mypy clean (9 modules), 51 tests pass (incl. migration
round-trip).
|
||
|
|
3838d64eaa |
sandbox: kitchen-sink images, feature-aware selection (Phase 2)
Phase 1 made the provisioner able to activate allowlisted extensions post-ready but kept the bare upstream images. Phase 2 ships the images that actually carry the extension/module files, and selects them only when a venture requests features — bare sandboxes stay on the light upstream image (no heavier pull, honoring the 'existing opters stay bare' decision). - _PostgresEngine / _RedisEngine gain kitchen_sink_image + image_for(features): bare (no features) -> the light image; features requested -> the kitchen-sink image. The provisioner runs engine.image_for(features), not engine.image, so the bare path is byte-for-byte unchanged. Mongo inherits the base image_for (returns its image regardless — no activatable features). - docker/sandbox-pg.Dockerfile: pgvector/pgvector:pg16 (ships vector) + postgis apt install; contrib (pg_trgm/citext/uuid-ossp) inherited from the official postgres base. Built at deploy via the sandbox-pg-image compose one-shot (mirrors the agent-image builders); the provisioner's _ensure_image finds the local tag and never pulls. Published by release.yml; pulled in registry compose. The verify step fails loudly if an extension's files are missing. - _RedisEngine kitchen-sink image: redis/redis-stack-server:latest (headless; ships search/json/bloom as loadable-but-unloaded modules — no custom build). - Extended the sandbox image-tag ghost-tag guard (the mongo:8-alpine regression test) to also cover kitchen_sink_image: skips locally-built roboco-* images, uses the namespaced Docker Hub endpoint for redis/redis-stack-server. Image-specific package names / module .so paths are verified at the CEO's NAS deploy (the spec's NAS smoke); the unit tests with the fake runner remain the CI bar, and the verify step is the fail-loud safety net for a wrong build. |
||
|
|
b015cde9ad |
sandbox: post-ready extension/module activation + allowlist (Phase 1)
Parameterized sandbox dev DBs — groundwork for 'extensions on the fly'
(docs/internal/specs/2026-07-13-sandbox-extensions-on-the-fly.md). A
venture declares the extensions/modules it needs; the provisioner activates
them post-ready via docker exec, never via bind-mounts or initdb scripts.
Phase 1 (behavior-preserving scaffolding — no image, no schema, no caller
passes features yet):
- Allowlists SANDBOX_PG_EXTENSIONS / SANDBOX_REDIS_MODULES are the ONLY
extensions/modules the system will ever activate — the security
containment, not privilege. plpython3u & co. (superuser-RCE vectors)
are excluded by construction.
- SandboxEngine ABC gains enable_step / verify_step / verify_ok. pg:
CREATE EXTENSION IF NOT EXISTS via psql, verified by a pg_extension
count. redis: MODULE LOAD per module, verified by MODULE LIST. mongo:
no-op (server is batteries-included).
- SandboxProvisioner.provision takes features={service: [names]},
allowlist-validates before any container runs, runs enable then verify
after the base readiness probe; a failed enable or a short verify (image
missing the extension files) is fatal — an agent never receives creds
for a db missing what it asked for. Empty features = bare = the
existing path, byte-for-byte unchanged.
- SandboxConnection gains features; as_payload surfaces
available_extensions / available_modules so the agent doesn't guess.
13 new unit tests (fake docker runner): enable/verify argv per engine,
allowlist rejection of plpython3u before any run, failed-enable + failed-
verify fatality, bare-provision unchanged, payload surfacing.
|
||
|
|
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> |
||
|
|
69271f9e98 |
fix(task): push a pre-set branch_name when the ref is missing on origin
A branch_name set on a task was treated as proof the ref existed on origin, so _finalize_claim skipped _ensure_branch_for_task and create_branch/push never ran. A manual field write (or a prior failed create_branch whose rollback didn't restore branch_name) left the field set while the branch was never pushed; descendants then ls-remote'd the name, found it empty, and cut from master via create_branch's silent fallback — breaking the cell->root branch hierarchy (MegaTask f7d0a61a root-branch 404). Defect A: - _ensure_branch_for_task trust-but-verifies a pre-set branch_name: probe origin, and when the ref is confirmed missing run the full create to push it. An inconclusive probe (network error) fails soft so a transient glitch can't fail a normal resume claim. Gated on project_id so branchless coordination/umbrella tasks are untouched. - _finalize_claim always runs _ensure_branch_for_task (the single chokepoint that ensures the branch exists) and snapshots+restores branch_name on rollback, so a failed first attempt can't leave the field half-set and short-circuit a retry. - GitService.branch_exists_on_remote: ls-remote probe returning True (present) / False (absent) / None (probe errored, fail soft). |
||
|
|
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> |
||
|
|
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 |
||
|
|
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> |
||
|
|
179467943c | chore(release): 0.23.0 v0.23.0 | ||
|
|
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> |