The daily-triage workflow completed end-to-end with all three evidence
surfaces (working-memory note, State Hub daily_triage event, ActivityRun
row) referencing the same run_id f9b97749. Backend: llm-connect against
OpenRouter anthropic/claude-sonnet-4, 12.85s end-to-end.
Add Implementation Notes - 2026-06-02 capturing the bug chain found and
fixed today (five llm-connect commits, two activity-core commits), the
backend choice and its consequences for the next scheduled run, and an
explicit carve-out: the operational cutover step (pause Codex, flip
enabled: true, sync schedules) is intentionally deferred to operator
action and remains a prerequisite for T08.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
llm-connect's CLI default port (:8080) collides with the dev stack's
temporal-ui container. Hit during the 2026-06-01 cutover attempt with
OSError: Address already in use. Update Steps 3, 5, and 6 to use :8088
and note the conflict reason inline so the next operator does not
rediscover this the slow way.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
T06 remains in_progress — no canary was rerun. Capture the runbook deliverable
(workplans/CUST-WP-0045-cutover-runbook.md @ 8ef5399), the still-unchanged
upstream fixes that should let the patched canary succeed, and the two
operational gotchas the runbook now documents (host-mode env overrides vs.
Docker-network .env; Claude CLI quota collision when triggering from inside
an active Claude Code session). Bump updated: to 2026-06-01.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Exact command sequence to rerun the patched real-LLM canary and, on success,
perform the Codex → activity-core cutover. Captures the heads-up about CLI
session collision, the host-mode env-var overrides for the worker/API, and the
verification queries for all three evidence surfaces. Frontmatter uses
type: runbook so the consistency checker does not treat it as a workstream.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Makes the state hub an event publisher so activity-core can drive
maintenance automation declaratively via ActivityDefinitions, rather
than the hub creating tasks itself.
- api/events/: lazy JetStream publisher + EventEnvelope mirroring
activity-core's contract; no-op when NATS_URL unset, fire-and-forget
with logged failures so publishing never breaks an API request.
- Wired publishers on the five v1.0 lifecycle events:
org.statehub.repo.registered (POST /repos/)
org.statehub.workstream.completed (PATCH /workstreams/* on transition)
org.statehub.decision.resolved (POST /decisions/*/resolve)
org.statehub.domain.goal.activated (POST /domain-goals/*/activate)
org.statehub.task.stale (scripts/cleanup_stale_tasks.py)
- docs/nats-event-subjects.md: subject naming convention + catalog.
- docs/cron-migration.md: design stub for replacing custodian-sync
systemd timer and cleanup-stale cron with ActivityDefinitions
(depends on activity-core WP-0003).
- docs/activity-core-delegation.md: protocol, invariants, cutover plan.
- SCOPE.md: declares activity-core as downstream event consumer and
restates that the state hub stays a read model, not a task factory.
Workplan: workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md
242 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Migration t7o8p9q0r1s2: indexes on tasks.status, tasks(workstream_id,status),
workstreams.status, sbom_snapshots(repo_id,snapshot_at)
- workplan-index: 30 s TTL cache + ?refresh param (4171 ms → 16 ms on hit)
- /state/summary: 15 s TTL cache, bypassed on Cache-Control: no-cache
- /topics/: noload(workstreams, decisions, progress_events) (2382 ms → 115 ms)
- /domains/: noload(topics, repos, goals) (2252 ms → 39 ms)
- /repos/: noload(goals) (2222 ms → 599 ms first / fast on repeat)
- conftest: reset TTL caches between tests to prevent bleed-through
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Workplan for delegating maintenance automation from the state hub to
activity-core via NATS JetStream. Covers NATS publisher wiring, subject
schema, lifecycle event emission, cron migration stubs, and delegation
protocol docs.
Hub workstream: d8ac100b-a844-46a5-9684-415df0d32539
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
T4: workstreams.md and dependencies.md now call /state/deps instead of the
full /state/summary — removes 2 heavy 10-table queries per 60 s cycle.
T5: index.md's 4 independent polling loops (summaryState, sbomSnapState,
regsState, wsChartState) consolidated into a single pageState generator
with one Promise.all batch and a shared backoff counter.
T6: config.js gains waitForVisible(ms) — pauses polling entirely while the
tab is hidden and fires immediately on visibilitychange. pollDelay()
simplified (hidden-tab POLL_HIDDEN logic removed). All 16 polling pages
migrated from await sleep(pollDelay(...)) to await waitForVisible(pollDelay(...)).
CUST-WP-0039 complete — all 6 tasks done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
T1: Cache-Control max-age=60 on /topics/, /repos/, /domains/ list endpoints
so repeated dashboard polls within a minute are served from browser cache.
T2: ETag middleware (md5 hash) on all JSON GET responses with conditional-GET
(304 Not Modified) support; If-None-Match and ETag added to CORS headers.
ETag registered inside CORS so 304s automatically carry CORS headers.
T3: GET /state/deps — lightweight dep-graph endpoint returning open workstreams
with depends_on/blocks edges only, skipping the 10-table full-summary query.
Prerequisite for T4 (switching workstreams.md and dependencies.md off /state/summary).
Workplan: CUST-WP-0039-dashboard-poll-optimization.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>