Requirement 001 phase 6, S5:
- Tasks tab: every pending ask, rule request, operator row and choice
card shows under "waits on Operator"; a choice request goes out on a
fixed channel button, post and call with an agent multi-select, and a
click on an option sends a passkey-signed answer the agent checks with
operator_message. The unsigned /api/decisions/<id>/choose route is
gone, and a decision, choice answer or choice recipient whose name
holds "*" is refused, so a signed answer never reaches every agent.
- Gantt view: one bar per task from start to end (running to now), one
arrow per explicit, branch-base and queue-order edge, hatched forecast
bars (always, points only, real only) from the median duration or
points times median hours per point.
- rasci.py set --after/--drop-after stores task dependencies and refuses
unknown tasks and cycles.
- Estimation toggle (No estimate default, Story points) is stored in the
hub settings; burndown and burnup per whole register, list filter or
one agent or line, counting tasks or summing complexity with the
unestimated tasks as their own line.
- New skill kvb-org-queue-estimate: "Request estimates" (story points
mode, passkey-signed board action) or the skill sends exactly one
newsletter listing every unestimated task with its RASCI parties; a
party name that is no plain name shows as "unnamed party".
- Business value per task or in bulk is stored only with a verified
passkey assertion over the exact ids and values; WSJF uses it instead
of the median. The task list sorts by every decision-50 mode both ways.
- e2e: the walk's pending ask lives an hour instead of 60 s, and the
CDP and BiDi drivers retry removing the browser profile while the
browser exits (ENOTEMPTY).
Evidence: make test 709 OK, ruff and markdownlint clean
(/tmp/s5-make-test-fix-2.log); e2e 26 OK in Chromium and Firefox
(/tmp/s5-e2e-fix-2.log); MEDUSA 50 files, an independent skeptic
rejected four holes (unsigned choose route, unsigned estimates request,
free-text party names, "*" recipients incl. normalizer bypasses), all
fixed and re-verified, the 8 remaining pattern hits accepted, rescan 0
open.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 88
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Requirement 001 phase 6, S1:
- Fit: Agents and Artifacts in a graph view fill the window from 861 px
up (body.fit flex column); the e2e walk probes #agents/orbit at every
width for a page no taller than the window.
- Rename once: a session seen under two names by one source (two claims)
flipped its name on every state build, so the Stream logged a rename
each poll. Names.observe keeps only the newest sighting per session
and source, and the timeline emits each (session, before, after) pair
once.
- Deutschlandfunk: root cause was the signed media-src, which never
listed the redirect target f111.rndfnk.com that st01.sslstream.dlf.de
answers with (fixed in ba97f7c). The e2e now replays that chain, a
302 from one https origin to a second, in Chromium and Firefox, with
self-signed throwaway certificates the drivers accept.
- Squelch: a settings slider 0..1 scales every tone; at 0 no beep plays,
music on or off (Voice.beep skips a silent tone). Stored settings
without the key load with 1.0.
- Tree: the missing tree file error names `pkgmgr branch tree` and the
release and install step that makes the timer write it.
Evidence: make test 655 OK, ruff and markdownlint clean
(/tmp/s1-make-test-1.log); e2e 17 OK, none skipped (/tmp/s1-e2e-3.log);
MEDUSA 14 files, 0 findings.
🎯 Fix: 94 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 90
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deutschlandfunk stayed silent: its signed URL answers 302 to
f111.rndfnk.com, an origin the signed media-src never listed, so the
browser blocked the redirected load and reported only the station's own
URL in securitypolicyviolation.
The hub now resolves each https stream's redirect chain server side when
a settings save adds or changes it and stores the extra origins as the
stream's via list. media-src lists them next to the signed origins. A CDN
host of three or more labels widens to its siblings (*.rndfnk.com); an
IP, a two-label host and a name under a country code's generic second
level stay exact.
Hardening:
- Only the signed URL itself may lie at a non-global address; every
redirect hop dials a global address only, checked on the address
actually dialed (NAT64 and IPv4-compatible IPv6 count by the embedded
IPv4 address).
- A resolve answers within three socket timeouts even for a server that
drips its headers; a late probe goes on in a daemon thread and a url
still in flight is not probed twice.
- A failed resolution stores via null and retries on a save ten minutes
later; the radio page says so instead of blaming the CSP.
- A save whose settings changed while it was resolved fails instead of
overwriting them (compare and set under the settings lock).
- A new stream URL at an already signed origin takes the passkey too.
- Settings written before via existed load as via [] and never dial.
Residuals:
- The passkey proof is spent before the resolve, so a save racing
another one fails and the operator signs again.
- A save that hits a due retry blocks up to twelve seconds and may
reload the page.
- A page loaded before the upgrade throws on the missing via until it
reloads.
- A private multi-tenant suffix such as github.io still widens.
- getaddrinfo has no timeout; it runs inside the daemon thread.
Operator step after install: remove Deutschlandfunk in Radio, Sender
bearbeiten, save, add it again and save with the passkey.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 88
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Surface (requirement 001 phase 2): navigation Stream (Inbox, Regeln) / Agents / Artifacts with keys 1-3 and hash routes (#graph and #tree redirect), header with title, command palette and settings only, server-side badges (unsnoozed inbox, beats within 900 s, open jobs), a Mayday banner with "aufheben", four stream chips with agent:/art:/seit: search, Filter and time menus, the inbox in main, an agents toolbar (Funk an alle with Newsletter, Broadcast, Pan-Pan, Security, Mayday; Priorität; Tag/Nacht), Post or Call in the agent panel, Ambiente in the settings and read-aloud over the seven classes with Mayday locked.
Rename (decision 9): hub/ is orchestrator/, the package kvb_orchestrator, the unit kvb-orchestrator-runner.service, scripts/orchestrator.sh, environment KVB_ORCHESTRATOR_*, make targets orchestrator-*, the MCP server, image and compose project kvb-orchestrator, the guard header X-Kvb-Orchestrator and the message marker [kvb-orchestrator msg <id>]. install runs migrate first: it stops the old container, removes its image and code, moves state, approvals and pinned keys, swaps the MCP registration, the PermissionRequest hook and the runner unit, and changes nothing on a second run (scratch-HOME test with stub docker, claude and systemctl). Saved views fall back to the old localStorage key once.
MEDUSA acceptances carried to the renamed paths: 82 rows whose lines are unchanged (reason prefixed "renamed from <old path>, line unchanged"), and 7 rows whose text changed only in the product name, the package name, a temp prefix or a new class argument, each upheld by one kvb-think-criticize skeptic (approval.py:60, messaging.py:53, server.py:56, tests/hub_support.py:64, passkey.py:205, page-agent.js:75, language.py:46).
Cost 101 %: the longer name adds 15 tokens of skill text; the operator approved it with the commit.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 101 %
⏱️ Time: –
🛡️ Security: 100 %
💰 Value: ?
🏆 Score: 87
🚦 Gate: ⚠️ cost 101 % > 100: ask the operator before the commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>