Commit Graph
1012 Commits
Author SHA1 Message Date
ec74298faa [467e263d] Diagnose CI run 29653535468 and fix the root cause (#572) (#573) (#574)
* [467e263d] fix(ci): restore green Python quality gate on slave (mypy + xenon)

Two independent bugs broke run 29653535468's 'Python quality gate' job,
not the pydantic-settings pin (already correctly 2.14.2 on this branch).

- git.py: _delete_remote_branch_best_effort's success path fell off the
  function with no return, failing mypy's missing-return-statement check
  and silently returning None instead of the documented True.
- company_goals.py: CompanyGoalsService.upsert's six repetitive
  `if key in data` branches pushed the module's average cyclomatic
  complexity past xenon's --max-modules A gate; refactored into a loop
  over the mutable-field tuple (behaviourally identical).

* [467e263d] docs(changelog): restore green Python quality gate on slave (CI run 29653535468)

Documented two independent code-level bugs fixed in commit 5ed93ca7:
1. git.py: missing return True statement in _delete_remote_branch_best_effort success path (mypy failure)
2. company_goals.py: cyclomatic complexity refactoring for xenon gate pass

Both bugs identified and fixed by dev team; verified via full CI reproduction locally.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
2026-07-18 23:14:35 +02:00
Renn F 9618e345e8 fix(alembic): renumber git_provider migration to 076 — single head restored
The two parallel spec-item branches each took 075 off head 074 (flagged in
both PRs); merging both left two alembic heads. git_provider now revises
075_company_goals_company_name; verified with a real upgrade chain run.
2026-07-18 19:14:36 +02:00
461a6e1ae7 feat(forge): Phase 1 — GitProvider seam, GitHub transport extracted (#571)
* feat(forge): Phase 0 — git_provider column + registration-time forge validation

Pointing a project at a GitLab/Gitea git_url used to fail silently, several
steps deep, at first PR. New pure policy module (foundation/policy/forge.py)
detects the provider from the git_url host and validates at the
ProjectService create/update chokepoint: github auto-detects and
auto-stamps, explicit git_provider=github is the GitHub Enterprise escape
hatch, gitlab/gitea are recognized-but-not-yet-supported, unknown hosts get
a loud rejection with guidance. An update changing git_url does NOT inherit
a stored auto-stamped provider (restating the override is required), so a
host swap can't smuggle the escape hatch past validation. Migration 075
adds the nullable projects.git_provider column; the panel project dialogs
show the detected forge. Phase 0 of the forge-providers spec.

* feat(forge): Phase 1 — GitProvider seam, GitHub transport extracted

roboco/services/forge/: base.py holds the pure contracts (RepoRef +
GitProvider ABC, stdlib-only — a later GitLabProvider is implemented by
reading this file alone), github.py the httpx transport (20 endpoint
methods behind one shared request-plumbing helper set), registry.py the
wiring (git_provider column -> provider, failing loud on gitlab/gitea).
GitService keeps its exact public surface and all response
classification; its 26 inline REST call sites route through a lazy
_forge property (several suites build GitService via __new__, so an
__init__-set attribute breaks them). github_provisioning and
release_executor ride the same provider. Zero behavior change — the
pre-existing suites pass unmodified; per-project provider resolution
lands with the second provider.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 19:11:56 +02:00
7e01c0cecf feat(marketing): project-branded drafts + project badges on the X/video queues (#570)
Item B+C of the video/X per-project targeting spec, plus the
company_goals.company_name field they depend on (migration 075).

- CompanyGoalsService.resolve_product_name is the single fallback chain
  (project name -> charter company_name -> RoboCo); XEngine and
  VideoEngine both call it and their prompt builders are pure functions
  taking product_name — release posts/videos stop hardcoding RoboCo.
- The X and video queue responses carry project_slug/project_name via one
  shared unloaded-guard helper (api/schemas/project_fields.py); both
  panel queues render a shared ProjectBadge so multi-project drafts are
  tellable apart.
- Business -> Goals editor gains the company-name input.
- Fixes a pre-existing test-isolation leak: the company-goals routes test
  commits the charter singleton into the session-scoped test DB and
  polluted later suites; it now deletes the row on teardown.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 19:11:03 +02:00
388bab2488 feat(forge): Phase 0 — git_provider column + registration-time forge validation (#569)
* feat(forge): Phase 0 — git_provider column + registration-time forge validation

Pointing a project at a GitLab/Gitea git_url used to fail silently, several
steps deep, at first PR. New pure policy module (foundation/policy/forge.py)
detects the provider from the git_url host and validates at the
ProjectService create/update chokepoint: github auto-detects and
auto-stamps, explicit git_provider=github is the GitHub Enterprise escape
hatch, gitlab/gitea are recognized-but-not-yet-supported, unknown hosts get
a loud rejection with guidance. An update changing git_url does NOT inherit
a stored auto-stamped provider (restating the override is required), so a
host swap can't smuggle the escape hatch past validation. Migration 075
adds the nullable projects.git_provider column; the panel project dialogs
show the detected forge. Phase 0 of the forge-providers spec.

* fix(panel): mock-mode forge detection extracts the real host

CodeQL js/incomplete-url-substring-sanitization: the substring check
matched github.com anywhere in the URL. Extract the hostname (URL parse
or scp-form regex, mirroring forge.py) and require an exact match.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 19:10:43 +02:00
Renn F 5ed90429a8 fix(security): fail closed in production; arm registry auth by default
GHSA-4f7g-w95g-5q2c (CVSS 9.8) — the default registry deploy ran in
header-trust mode: with ROBOCO_AGENT_AUTH_REQUIRED unset and cloud auth
off, require_panel_token / _check_agent_auth_token returned without
verifying a credential, so any client reaching the API could write
settings and claim X-Agent-Role: ceo with no token. Binding :8000 to
loopback (c4053d5f) closed the direct path but not nginx :3000, which
proxies /api/ to the orchestrator and passes client X-Agent-* through.

Root cause: header-trust is the default even in production. _auth_required
now fails closed when settings.environment == production (the registry
compose already declares it) — an explicit false still opts out for a
trusted private network. The registry compose arms auth by default and
requires ROBOCO_PANEL_AGENT_TOKEN so nginx injects a valid CEO token and
the panel keeps working. The CEO's NAS deploy is unaffected: it runs
cloud auth, which already enforced tokens on every role.
2026-07-18 17:40:49 +02:00
Renn F f89d01ad08 fix(tests): gate diff-base parentless test stubs the head-rung resolver
The env-ladder change makes a parentless root consult the project head
rung before string derivation; on a bare AsyncMock the resolver probe
auto-materializes and returns a truthy mock. Stub it to None so the test
exercises the no-project string-derivation fallback its name promises,
matching test_merge_chain's pattern.
2026-07-18 17:03:10 +02:00
Renn F b0dcb03356 fix(marketing): release and spotlight drafts carry their source project
draft_release_post / draft_release_video accept a project_id and the
release-proposal approve hooks pass the proposal task's own project;
the spotlight companion video forwards the spotlight draft's project
into open_video_task — previously it always authored against the
deployment-anchor project's motion/ tree regardless of which project
the spotlight was about. Omitted project_id keeps the anchor-project
fallback, so single-project deployments are unchanged.
2026-07-18 16:48:45 +02:00
Renn F fecb021eef fix(release): version detection accepts manifest variants, never crashes the sweep
_pyproject_version read pyproject.toml with no error handling, so a
non-Python project failed the release-manager cycle every interval
forever. _project_version now probes pyproject.toml, package.json,
Cargo.toml, then a bare VERSION file; missing or unparseable manifests
are skipped and no manifest degrades to an empty version.
2026-07-18 16:41:18 +02:00
Renn F 6a30cca4af fix(gateway): root PR base resolves the project's env ladder, not literal master
A parentless root's PR base / merge target now resolves through
resolve_parent_branch to the project's panel-configured head rung —
submit_root passed a hardcoded 'master', which on a main-default repo made
_ensure_base_on_remote silently create a spurious master branch and land
the assembled root PR there. Literal master survives only as the
no-project string-derivation fallback.
2026-07-18 16:41:17 +02:00
Renn F 99224e65cd fix(tests): satisfy mypy on the queue-item push tests
The #568 tests unpacked AsyncMock.await_args without narrowing its
Optional type and passed a SimpleNamespace where _format_task_detail
is annotated TaskTable. Narrow with the repo-standard 'assert
await_args is not None' and cast the fake task at the call sites.
2026-07-18 16:35:28 +02:00
ec6558e168 [2a86d1f5] CI-watch: fix the CI regression on roboco-api (#563)
* [e530aa5e] Diagnose and fix roboco-api CI failure (run 29629255153) (#561) (#562)

* [e530aa5e] fix(tests): narrow None before indexing validate_init_data() result in telegram_initdata self-check

CI run 29629255153 failed on mypy, not the historical pydantic-settings
issue (uv.lock already pins 2.14.2). The __main__ self-check block in
test_telegram_initdata.py indexed the dict[str, object] | None return
of validate_init_data() without narrowing away None first.

* [e530aa5e] docs(qa): document CI fix for mypy type narrowing in telegram_initdata test

Explains the root cause (mypy type error in __main__ block), the solution (None narrowing before indexing), and the safe pattern for future test self-checks that call functions returning optional types.

---------

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

* [0884b737] Diagnose and fix Python quality gate + e2e lifecycle smoke CI failures on PR #563 (#564) (#565)

* [0884b737] fix(tests): isolate ROBOCO_SDK_URL for scripted e2e-smoke agents

tests/e2e_smoke/harness.py already isolates ROBOCO_AGENT_TOKEN from the
host environment (the #503/#504 fix) but left ROBOCO_SDK_URL leaking
through. flow_server/do_server both default it to
http://localhost:9000 and forward every rejection there for the
per-verb circuit breaker; inside a real spawned agent container that
port is a live SDK loopback, so the breaker records genuine attempts
for the ephemeral test-agent IDs and trips circuit_open mid-test
(test_sandbox_on_demand.py::test_request_sandbox_guard_chain_over_real_api,
which deliberately causes 3 rejections in a row). Point it at a
guaranteed-refused loopback address so every environment gets the same
fail-open bypass a bare CI runner already gets by having nothing
listening on 9000 at all.

* [0884b737] docs(changelog): document e2e-smoke harness ROBOCO_SDK_URL isolation fix

Document the fix that isolates ROBOCO_SDK_URL in the ScriptedAgent harness to prevent the per-verb circuit breaker from leaking state into ephemeral test-agent identities when the e2e-smoke suite runs inside a live agent container. This ensures the suite passes consistently regardless of whether it runs on bare CI or inside a spawned agent.

---------

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

* [3b9a1771] Diagnose and fix ALL make quality + e2e-smoke stage failures on PR #563; confirm real CI green (round 3) (#566) (#567)

* [3b9a1771] fix(e2e-smoke): match real embedding dimension when seeding fake journal chunk

test_c3_deleted_journal_unindexed inserted a 4-dim placeholder vector
into chunks_journals, but the e2e stack's app lifespan eagerly creates
that table with the real settings.embedding_dimensions (1024) before
the test runs, so the insert failed with "expected 1024 dimensions,
not 4". Derive _SMOKE_DIM from settings.embedding_dimensions instead
of a hardcoded constant so the seeded vector always matches the
table's actual column width.

* [3b9a1771] docs(qa): document e2e-smoke embedding dimension fix in round 3 CI diagnosis

Recorded the root cause, solution, and pattern for the final e2e-smoke test failure found in comprehensive sandbox testing: the test seeded a 4-dim placeholder vector but the app's eager lifespan init created chunks_journals with the real 1024-dim embedding column. Updated _SMOKE_DIM to derive from settings.embedding_dimensions instead of a hardcoded constant.

---------

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

---------

Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
2026-07-18 16:13:47 +02:00
Renn F 06cc986f06 Merge branch 'slave' of https://github.com/rennf93/roboco into slave 2026-07-18 16:01:59 +02:00
Renn F d441fb2591 fix(git): dedupe check-runs per name so cancelled duplicates can't mask green
_classify_check_runs counted any completed cancelled check-run as failing.
The push + pull_request double-trigger leaves cancelled same-name
check-runs on the same head SHA next to the surviving run's green, so the
pr_pass gate saw permanent red on a genuinely green PR. Keep only the
newest (highest-id) run per check name before classifying.
2026-07-18 15:55:55 +02:00
Renn F 0f1e60fb95 fix(gateway): no model self-attribution in agent commits
Two layers: generated agent settings now set includeCoAuthoredBy: false
(never set anywhere before, so the CLI nudged models into appending
'Co-Authored-By: Claude ...' to commit messages), and the commit verb
strips AI-attribution lines deterministically at the chokepoint every
provider routes through.
2026-07-18 15:55:48 +02:00
Renn F fc6d6f6458 fix(a2a): CEO pairs join the switchboard matrix; sections collapsible
_SWITCHBOARD_SLUGS reused is_human_only_role (spawn semantics) and dropped
the CEO before can_a2a_direct — which allows CEO -> anyone — ever ran, so
the static pair matrix had no CEO pairs and a Renzo filter emptied the
switchboard. Only prompter/secretary/system are excluded now; CEO pairs
get their own 'CEO Direct' section (matrix 70 -> 93). Every switchboard
section header is now a collapse toggle (Radix Collapsible, default open).
2026-07-18 15:55:40 +02:00
ff78618b76 feat: Telegram messages get real formatting + push DMs at draft origination (#568)
* feat(telegram): HTML-styled bot messages + push DMs at held-draft origination

* fix(telegram): attr-context escaping, balance-aware truncation, send observability; docs

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 15:54:49 +02:00
f0782cb858 chore(panel): selective dependency updates — Next family held at the 16.1.x pin (#560)
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 08:12:43 +02:00
Renn F 5cf667aaaf Merge branch 'slave' of https://github.com/rennf93/roboco into security/api-8000-loopback 2026-07-18 07:53:04 +02:00
713f91320a feat: Journals joins the Agents hub — third tab (#559)
* feat(panel): Journals joins the Agents hub as its third tab

* docs(map): Journals tab on the Agents hub; registry retargets

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 07:52:28 +02:00
Renn F c4053d5ffd fix(security): bind orchestrator :8000 to loopback (GHSA-4f7g-w95g-5q2c)
Both deploy composes published the orchestrator API on 0.0.0.0:8000, so any
host that could reach the machine hit the control plane directly — past nginx
and, in the default header-trust posture, with no credential: read/write
runtime settings and X-Agent-Role: ceo spawn/stop. nginx reaches the API over
the internal Docker network, so a routable host publish is never needed; bind
it to 127.0.0.1. On-host debugging and normal panel operation are unchanged;
off-host access must go through nginx + cloud auth.
2026-07-18 07:28:14 +02:00
4480dfe8d1 feat: Agents hub — Fleet + Conversations tabs, /a2a merged in, DM quick-action (#558)
* feat(panel): Agents hub — Fleet and Conversations tabs, /a2a redirect, DM quick-action

* fix(panel): validate deep-linked DM targets against roster and exclusions; re-arm the dm latch

* docs(map): panel entries for this wave

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 07:06:32 +02:00
1a726d4c34 feat: customizable Quick Actions on the Overview dashboard (#557)
* feat(panel): customizable Quick Actions on Overview — registry, defaults, persisted picker

* fix(panel): legacy bar actions join the quick-action defaults; empty state; persist-contract test

* docs(map): panel entries for this wave

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 07:05:20 +02:00
02601fef22 feat: Workstation card grids — view toggle, sorting, agent-card visual language (#556)
* feat(panel): Workstation card grids with persisted view toggle and sorting

* fix(panel): stable multiplier sort with cell-label fallback after adversarial review

* docs(map): panel entries for this wave

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 07:04:38 +02:00
Renn F 4e12e65869 fix(motion): override adm-zip >=0.6.0 — dependabot alert 88 (crafted-ZIP 4GB allocation) 2026-07-18 06:05:31 +02:00
Renn F 29b375f1b5 fix(panel): session links target the owning task — /work-sessions/<id> never existed 2026-07-18 05:41:07 +02:00
Renn F e3ec24f58f fix(deploy): arm the Telegram trio by default in the NAS compose per the arm-new-flags convention 2026-07-18 05:21:22 +02:00
59594d794a fix(deploy): resync compose twins with a quality-gate guard; wire cloud-auth env through; regenerate .env.example; reconcile registry drift (#555)
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 05:13:49 +02:00
c40a7a39c3 feat: Telegram V3 — Mini App cockpit (initData auth + /tg surface) (#554)
* feat(telegram): Mini App auth — initData validation mints the cloud-auth session cookie

* feat(panel): /tg Mini App cockpit — approvals, inbox, read-only board, A2A chat

* fix(telegram,panel): unconditional webapp-auth rate limit, future-dated initData rejection, anchored /tg matcher

* docs(map,rag): Telegram Mini App auth route, initData validator, (tg) surface

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 02:47:59 +02:00
3b88c706dd docs(map): full _complete_map rebuild from current slices; motion-commit debt cleared (#553)
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 02:09:08 +02:00
2a5820cb07 fix(motion): release-recap beats off clip windows onto base-hidden delayed animations (#552)
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 02:06:44 +02:00
Renn F 796ab05d3d test(runtime): drain fixture uses the real engine-slot initializer, not a stale copy 2026-07-18 00:56:04 +02:00
9fbec78126 feat: Telegram V2 — inbound commands + actionable approve/reject from chat (#551)
* feat(telegram): V2 inbound — command router, actionable approve/reject keyboards, chat-gated poll loop

* fix(release,x,video,telegram): terminal-state guards on approve/reject; sender-identity check

* docs(map,rag): Telegram V2 inbound surfaces and terminal-state approve/reject guards

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:47:09 +02:00
c9c1f62981 feat: HyperFrames-grade video design bar — vendored craft references + catalog vocabulary (#550)
* feat(motion): demo-register visual design bar, vendored craft references, catalog vocabulary index

* fix(motion): correct design-bar composition claims after adversarial fact-check

* docs(map,rag): design-bar, vendored references, and catalog index on the video-engine surfaces

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:46:01 +02:00
c5dfbf6063 feat: Workstation page — Products + Projects unified behind one sidebar entry (#549)
* feat(panel): Workstation page — Products and Projects as tabs behind one sidebar entry

* docs(map): workstation page, extracted views, and the local-filter scroll trade-off

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:45:21 +02:00
496c24d186 feat: git hygiene (branch/preview reaping + cleanup sweep) and panel charts; work sessions under Git (#548)
* feat(panel): session-start, 7d overview spend, and 30d business spend charts

* feat(panel): surface work sessions as a Git page tab (route was orphaned)

* feat(git): reap spent task branches and render previews at lifecycle chokepoints; guarded stale-branch sweep

* feat(panel): stale-branch cleanup button on the Git page

* fix(git,panel): cursor-resumable sweep, force-delete spent refs, local filter state

* docs(map,rag): branch/preview reaping, cleanup sweep, git-tab work sessions, wave-2 charts

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:44:48 +02:00
885d6bbe83 feat: CEO-grade A2A — New DM composer, CEO-DM wake, docs scrub (#547)
* feat(panel): CEO New-DM composer and direct-thread replies on the A2A page

* docs(agents): remove dm-the-CEO teaching; fix Board/HoM dead-end escalation recipes

* feat(a2a): CEO-authored DMs wake offline recipients via the a2a_request dispatch path

* fix(a2a,panel): wake only read_a2a-capable roles; case-insensitive header defaults; wider DM picker exclusions

* docs(map): CEO-DM wake mechanics, requires_ack override, A2A composer components; comms-model update

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:44:00 +02:00
9b4ce6b9c8 fix: wave 1 quick wins — agent names, scroll bounce-back, chart empty states, model-pin preservation, UUID spawn normalization (#546)
* fix(panel): notifications show agent names, metrics charts get empty states

* fix(panel): stop expand/collapse scroll bounce-back; add floating scroll-jump buttons

* fix(llm): provider mode switches preserve per-agent model pins

* fix(api): normalize agent UUID to slug at the orchestrator route boundary

* fix(panel,docs): align routing-card copy and map docs with preserved-pin mode switches

* fix(panel): drop dead unfiltered scroll hook, re-observe on Suspense swap, name system sender

* docs(map): reflect preserved-pin mode switches, UUID-slug normalization, panel wave-1 deltas

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-18 00:42:13 +02:00
4c8a9fc008 fix(video): unconfigured platforms are skipped, not pending-forever failures (#545)
A draft targeting a platform with no credentials could never complete:
the X leg posted and committed its id, the TikTok leg failed as
'transient', and the card sat pending in the CEO queue with retry
semantics that structurally cannot succeed. Unconfigured platforms are
now an explicit skip: the draft COMPLETES when every configured
platform has posted (detail names what was skipped), an approve whose
targets are all unconfigured refuses loudly instead of silently
completing, and genuine post failures keep their partial/retry
semantics. Re-approving a parked card clears it without re-posting
(the already-posted guard is covered by a dedicated test).

Verified: 32/32 test_video_post_service (3 new: skip-and-complete,
all-unconfigured refusal, re-approve recovery), ruff/mypy/xenon clean.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-17 07:12:11 +02:00
Renn F a12fefcba9 fix(video-renderer): regenerate pnpm-lock.yaml for the producer pin
The 0.7.36 exact-pin landed via an npm install, which wrote a stray
package-lock.json and left pnpm-lock.yaml stale — the image build's
pnpm install --frozen-lockfile then correctly refused the spec
mismatch, blocking deploys. Lockfile regenerated with the Dockerfile's
own pinned pnpm@11.10.0 (resolves @hyperframes/producer@0.7.36 exactly,
frozen-lockfile install and the sidecar's node --test 15/15 verified
locally); the npm lockfile is removed — this package is pnpm-managed.
2026-07-17 05:43:34 +02:00
Renn F c33a03f2aa Updated uv.lock 2026-07-17 05:41:35 +02:00
fd621f0dba feat(motion,runtime): wire the three craft capabilities to the video-authoring dev (#544)
Playwright, the taste-skill design bar, and hyperframes were all
implemented — and each stopped one hop short of the hands doing video
work: playwright reached only fe-qa/ux-qa, the design bar's web-UI dials
actively pointed a video task at 'dense product UI -> motion 2-3', and
hyperframes' agent-facing doctrine never reached any agent. Three wires:

- vendor the official HyperFrames agent skills (hyperframes-core,
  -keyframes, -creative) under motion/skills/ at a pinned upstream
  commit (Apache-2.0, attribution headers; prose reflowed to house
  style, re-vendor note in each header); README and the dev video
  prompt block point at them
- register the playwright MCP for a ux-dev spawned onto a source=video
  task (_is_video_authoring_spawn: fail-closed role/team/task-source
  probe) so the composition author can watch their HTML live in a real
  browser between renders — gating-only, agent-ux already bakes the
  browser; QA gating unchanged, be-qa/ordinary ux-dev still excluded
- design bar video-mode override in the ux_ui team prompt: video tasks
  are films, the web dials do not apply — use the cinematography bar
  and the vendored doctrine instead

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-17 05:26:42 +02:00
Renn F 1416bd1de9 docs(motion): point authors at the official HyperFrames agent skills
The vendor publishes seek-safe authoring doctrine as installable agent
skills (hyperframes-keyframes / hyperframes-creative / hyperframes-core);
its primary seek-safe primitive is GSAP tweens on window.__timelines —
the kit's CSS register is a house pattern and the clip-window rule is
its empirically-derived companion.
2026-07-17 04:01:52 +02:00
3e801697f7 feat(motion): choreography engines + two renderer root causes fixed (#543)
The release cuts read as static screen recordings: one 6s cursor glide
that then vanished, a locked-off camera, metronomic flat card fades. And
two renderer defects were silently wrecking every cut:

- @hyperframes/producer floated (^0.7.36, no lockfile — image builds get
  whatever is latest): 0.7.60 fails EVERY render with "Cannot access 'rt'
  before initialization". Pinned 0.7.36 exact and committed
  package-lock.json so sidecar builds are reproducible.
- the producer's per-clip visibility scheduler runs on a clock that lags
  ~50% behind the encoded timeline on a 40s cut — the final frame showed
  the authored ~18s state, so the tail scenes (bell card, toast, outro)
  were silently missing from the MP4. This, not authoring, is why
  rendered cuts kept losing their late scenes. Fix: clip windows are for
  structural layers only (hero, panel frame, status); every beat rides
  base-hidden styles + delayed CSS animations, which run on the true
  clock. Verified frame-by-frame: all four cards, stats, toast, and
  outro now land exactly on schedule in both cuts.

Craft, made reusable in the kit instead of per-composition heroics:

- kit.js choreographCursor: data-waypoints="t x y [click]; ..." generates
  a multi-leg eased path with fade in/out, an idle-hand sway, and click
  rings + glyph press dips — the cursor behaves like a hand, never pops
  in, freezes, or blinks out
- kit.js choreographCamera: data-shots="t x y scale; ..." — push-ins
  toward each beat's focal point, pull-backs for reveals, settle to end
- release-0.25.0 both cuts re-choreographed: the cursor is the CEO's
  hand (settle on the intake while it types, ONE submit click, witness
  each card completing, acknowledge the toast, exit off-frame); the
  camera lives on every beat; springy card entrances replace flat fades
- motion/README.md gains 'Cinematography & rhythm' (shot-list-first, no
  locked-off camera, verify motion with frame PAIRS) + the clip-window
  rule; kit/README.md documents both engines; the dev video prompt block
  carries the craft bar

Verified end to end through the real sidecar: both cuts render green,
32-frame strips read visually — cursor travels and clicks on schedule,
camera moves, every scene present. motion pnpm test 15/15.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-17 03:58:08 +02:00
e9ca7d4036 Delegation detail-fidelity + PM-loop hardening (#541)
* feat(gateway): delegation detail-fidelity — details survive hand-off, both directions

Details thinned out at every delegation hop: a PM child task mapped to no
parent criterion was legal (coverage only surfaced at submit_up, after the
whole wave ran — a 12-subtask docs tree grew through 8 review rounds that
way, one child titled 'docs page and route wrapper' shipping only the
page), and QA could pass work on a gestalt read (a 4-scene video brief
shipped 3 scenes past every gate because the features existed only in
prose). Three chokepoint gates:

- delegate (down): every child must declare covers_parent_criteria
  resolving against the parent's real acceptance criteria — no mapping or
  an unresolvable ref rejects naming every offending child and the valid
  criteria; the success envelope carries parent_ac_coverage
  {covered, uncovered} so a wave-planning PM sees remaining gaps in the
  same turn. Full coverage stays enforced at submit_up (waves stay legal).
- pass_review (up): mandatory criteria_verified — one {criterion,
  evidence} entry per task AC, matched by the findings ledger's
  id-or-exact-text matcher, evidence soup-checked and capped; rejects
  naming the unverified criteria; entries render deterministically into
  qa_notes as '[AC] <criterion> — verified: <evidence>' lines. The old
  count-only ac_verdicts gate is superseded (arg kept for back-compat).
- video briefs (structured detail at origination): an enumerable feature
  list (release highlights, or input_props.highlights carried onto a
  reject re-author) becomes its own scene acceptance criterion, bounded to
  the AC caps; a re-author without highlights carries the
  feedback-addressed criterion instead.

Extracted findings.py's criterion matcher into shared unmatched_criteria /
uncovered_acceptance_criteria instead of duplicating it; criteria_verified
joins the WAF free-text exclusion set like findings/issues.

* fix(gateway): break the block/unblock wedge — four hardening fixes from the live PM loop

A cell task looped fe-pm/main-pm block/unblock for hours (10 cycles, 43
spawns): a transient GitHub API error resolving CI became an unwaivable
blocker finding whose own fix text said no code change was required, the
submit freshness guard then demanded a commit no finding called for,
escalate_up auto-blocked, and main-pm's correct recovery plan 422'd on
the approach length cap, degrading it to a bare unblock. Four fixes:

- pr_pass CI-unresolvable refusal is now explicitly transient-worded:
  retry pr_pass shortly, do NOT pr_fail over a CI-status lookup error —
  a platform blip is not a code finding
- submit freshness guard grants ONE unchanged-head resubmission per
  head sha when the findings ledger has zero open rows (all addressed
  without code changes) — stamped via the resubmit_unchanged_head
  marker so the same head can never loop a second time
- unblock carries a flip breaker: block_flip_count marker, and at the
  third flip a one-shot CEO notification flags the task as structurally
  wedged (unblock itself still succeeds — the breaker signals, it does
  not wedge recovery)
- i_will_plan's approach cap truncates at 800 chars instead of
  rejecting — an over-detailed plan must never cost the PM its turn

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-17 01:52:33 +02:00
Renn F 028b11871b Merge branch 'master' into slave 2026-07-17 01:48:49 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6b98d489f8 bump actions/upload-artifact from 4 to 7 (#540)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-17 01:45:53 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
35b02b11ed bump actions/setup-node from 6 to 7 (#539)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-17 01:45:37 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3f5d433796 bump actions/github-script from 7 to 9 (#538)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-17 01:45:21 +02:00
Renn F 54cb4ae99c Merge branch 'slave' of https://github.com/rennf93/roboco into slave 2026-07-16 19:50:43 +02:00