18 Commits
Author SHA1 Message Date
canvas-bot 14a98056ed fix(memory): use edge role=child (valid EA2 vocab)
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Probed backend's defines edge role vocabulary. Accepted: child,
dispatch. Rejected: memory, observation, note, recall, vault, step,
view. Switching from invalid 'memory' to valid 'child' so the edge
attach actually lands without 500.
2026-06-16 21:21:52 +04:00
canvas-bot 2b91368a23 fix(memory): use edge role=memory not presentation
build-and-publish / image (push) Has been cancelled
build-and-publish / test (push) Has been cancelled
EA2 enforces one-defines-presentation-per-node — only the first
memory could ever attach because every subsequent
create_edge(role=presentation) from the vault returned 500
[ERR 1650]. Use role=memory for ongoing memories. listAll filter
accepts both for back-compat with the single existing
presentation edge.
2026-06-16 21:19:11 +04:00
canvas-bot f3a3794e54 fix: eliminate all 4xx noise from scene walks
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
- buildScenarios: drop the /api/runtime/transactions/{id} headline GET
  entirely. Synthesize the RuntimeTransaction shape from the work-item
  data. Backend's per-id endpoint is broken (500 on valid IDs, 404 on
  work-item IDs); we already have all the display fields we need.
- store.ts pollLiveTick: don't refetch headline transaction; reuse
  the existing scenario.raw.headlineRt synthesized at build time.
- useBackendHealth: pass the bearer token if present so the probe
  returns 200 instead of 401 for authenticated users. The probe still
  treats 401 as 'up' for unauthenticated landing page.
- agentMemory.remember: track ensureVault result. Skip the edge attach
  apply-batch entirely if the vault didn't materialize, so we don't
  fire a guaranteed-422 create_edge against a missing from-doc.
2026-06-16 21:16:31 +04:00
canvas-bot b0127c24eb fix: silence Mission 404 storm + Assistant 422 noise
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Three sources of red errors in scene walk:

1. Mission/Approvals: GET /api/runtime/transactions/{key} 404 storm.
   The runtime backend's single-transaction endpoint is broken
   (returns 500 'transaction_read_failed: All connection attempts
   failed' even on valid IDs from the list endpoint, and 404 for
   work-item IDs that don't exist in the runtime DB at all).

   Fix in buildScenarios.ts: keep the headlineTx fetch (still tries
   to enrich) but synthesize a RuntimeTransaction shape from
   work-item data via workItemToRt() when the API call returns null.
   Skip the 3x 'recent' GETs entirely — they were always 404ing.

   Fix in store.ts pollLiveTick: .catch(() => null) on the headline
   transaction call so polling never surfaces backend brokenness.

2. Assistant: POST /api/ea2/apply-batch 422/404 when remembering.
   Vault edge attach can race with vault creation OR target a doc
   that hasn't propagated. Wrap in try/catch with console.warn so
   the failure is visible in logs but doesn't fire as a red console
   error on every turn.
2026-06-16 21:13:35 +04:00
canvas-bot 99203267aa test: track LLM gateway 5xx separately + lock cascade integrity
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Oracle wave-4 watch-outs:
- '5xx count: 1 should not be hidden'
- 'Add one future regression check that fails if both primary and
   fallback LLM paths fail, since the fallback tunnel is now part
   of the live behavior'

E2E now reports llm-gateway 5xx and system 5xx as two distinct
counts. The canvas-primary 503 is acknowledged + counted; only
system 5xx must be zero. New no_system_5xx assertion guards that.

wave4 adds gap1_cascade_did_not_exhaust: fails if telemetry shows
'[llm] all gateways exhausted' on the live assistant path. Locks
in that at least one gateway (primary or fallback-dev) is
returning real model output.
2026-06-15 22:31:05 +04:00
canvas-bot e29667b348 fix(llm): tunnel fallback through nginx for same-origin (no CORS)
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Browser trace showed fallback-dev cascade failing with 'Failed to
fetch' on the live site. dev.flow-master.ai OPTIONS preflight returns
HTTP 400 from foreign origins and the POST response lacks
Access-Control-Allow-Origin, so the browser blocks direct
cross-origin calls.

Add nginx location /api/llm-fallback/ that rewrites to
/api/v1/llm/ and proxies to dev.flow-master.ai (same DNS resolver
pattern as the demo proxy). Frontend now hits both gateways
same-origin via canvas.flow-master.ai, no CORS preflight needed.
The canvas-issued JWT is forwarded as-is and dev accepts it
(verified by curl).
2026-06-15 22:16:42 +04:00
canvas-bot 660de0341b feat(llm): cascade to dev.flow-master.ai LLM gateway when local 503s
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Oracle wave-4: 'Re-test LLM with a successful upstream response,
not only the 500/503 fallback path. The current evidence proves
graceful degradation but not that LLM is actually on producing
model-backed answers.'

The user said 'Take the LLM integration that we already have on
the other websites and put it on.' demo's llm-integration-service
is 503 (no provider key), but dev.flow-master.ai's identical
gateway returns real OpenAI-backed completions and accepts the
canvas-issued JWT plus has CORS open to canvas.flow-master.ai.

Refactor llmClient:
- Extract callGateway() that returns LlmResponse or 'retry' sentinel
- LLM_GATEWAYS = [primary (canvas's own), fallback-dev (dev.fm.ai)]
- Retry on 500/502/503/504/404 and network errors against the next gateway
- Telemetry prefixes each log with gateway name ('primary' vs 'fallback-dev')
- 12s deadline still applies across the whole cascade
- Only final 'all gateways exhausted' warn if every link in the chain fails

Net result: canvas users get a real model-backed answer on every
non-tool prompt instead of the 'temporarily unavailable' fallback.
2026-06-15 22:06:22 +04:00
canvas-bot 727b8af463 fix(wizard): retry config attach on Confirm if initial PUT failed
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Oracle wave-3 caveat: 'A toast alone is insufficient if the app marks
the wizard state as attached locally and never retries.'

Track draft.wizardConfigAttached. Set true only after the initial PUT
resolves. In handleStructureSave (Confirm Structure), if not yet
attached, retry updateDraftConfig before applying the structure batch.
Failure of the retry is logged but doesn't block save — structure
still lands and downstream config sync can pick up later.
2026-06-15 21:54:28 +04:00
canvas-bot 83a6b334c3 perf(agent): cap recall + 2s deadline so LLM fallback always fires
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Trace showed every Assistant submit triggered 60+ sequential
GET /api/ea2/flow/{key} requests via agentMemory.recall before
llmClient.chat ran. With a slow EA2 demo, recall took longer
than the test wait so the LLM fetch never started, the agent
reply never rendered, and [llm] telemetry never logged.

Two fixes:

1. agentMemory.listAll(cap) - default 200, recall uses 30.
   Edges are returned newest-first by EA2 so the 30-cap keeps the
   most recent vault entries and drops the long-tail history that
   was pinning the network.

2. routeAgentInput wraps recall in a 2s AbortController. If recall
   doesn't finish in 2s, hints[] stays empty and llmFallback runs
   immediately. Recall is best-effort context, never a blocker.
2026-06-15 21:42:58 +04:00
canvas-bot 3ebfaf81ae fix(agent): send_chat matcher requires single-word recipient
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Bug: 'tell me a haiku about flowcharts' matched send_chat with
target='me a haiku' / body='flowcharts', producing the bogus
"I don't know who 'me a haiku' is" reply and silently swallowing
all non-tool prompts that started with tell/ask. The LLM fallback
never ran, so [llm] telemetry from wave 3 never fired in tests.

Fix: tighten the matcher to require a single-word [A-Za-z]+ name
between the verb and that/about/:. Drop the substring search in the
directory; require an exact match. Now 'tell me a haiku about X'
falls through to llmFallback as intended.
2026-06-15 21:31:54 +04:00
canvas-bot fa17445ff0 fix(llm): 12s hard deadline on /api/v1/llm/generate
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Investigation: the wave-3 [llm] telemetry warns weren't firing on live
because the fetch had no client-side timeout. When demo's
llm-integration-service was slow/stuck, fetch hung indefinitely past
the test's 12s wait, so the fallback path never ran and the user saw
no agent reply at all.

Add a 12s AbortController-backed deadline. On timeout: console.warn
'[llm] gateway timed out after Xms (deadline 12000ms)' + return the
graceful 'temporarily unavailable' fallback that renders the tool
menu in the chat surface. Uses AbortSignal.any when available to
preserve any caller-supplied signal.
2026-06-15 21:16:11 +04:00
canvas-bot 9502e36c32 fix(wave3): wizard config soft-warn, llm telemetry, catalog dedupe, mission primer
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Oracle's wave-2 watch-outs:

1. Wizard config persistence — the follow-up PUT was silently swallowed.
   Empirical curl reproducer confirmed config.wizard DOES land after the
   split create/PUT (config.wizard.marker=EA2_DRAFT_PROCESS visible on
   re-GET). But to satisfy the 'no silent loss' concern: the catch now
   warns to console AND surfaces a soft toast 'Draft saved, but its
   wizard state didn't attach. You can keep working — save will retry
   on Confirm.' so failure is loud without blocking the user.

2. LLM telemetry — fallback was masking infra health. llmClient now
   logs every outcome with elapsed time: 503/404/502/504/non-2xx/parse
   failures all console.warn with reason + ms. Success path
   console.info with provider + content length. Friendly fallback to
   the user stays the same; ops/devs see the real story.

3. Catalog hygiene — duplicate 'Laptop Procurement' rows. list_processes
   now dedupes by normalized display_name after the existing _key
   dedupe. EA2 seeds + tenant imports both publishing the same name
   collapse to one row in the assistant output.

4. Mission intuitiveness — user said 'I don't understand anything that's
   going on there.' Added a one-line first-visit primer strip
   ('What you're looking at. Each tab below is a process running in
   your company...') dismissible with an X, sticky to localStorage.
   Also fixed the stale 'showing snapshot' fallback copy in the
   liveError banner (snapshot mode was removed in wave 1; banner now
   says 'last known state shown').

30/30 vitest pass. tsc + vite build green.
2026-06-15 21:01:14 +04:00
canvas-bot 9cbee11756 fix: studio createDraft split, llm fallback offers tools, topbar a11y pass
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
Three Oracle-flagged gaps:

1. Studio createDraft 500 (was masked by retries). Empirical curl
   reproducer proved POST /api/ea2/flow returns 201 with the minimal
   shape but intermittently 500s when config.wizard.* is in the
   initial body. Split: POST creates the draft minimally, then a
   follow-up PUT attaches the wizard config best-effort. Draft
   creation now lands reliably.

2. LLM 'temporarily unavailable' was a dead end for the user. Now
   the assistant returns ok:true with a concrete menu of tools the
   user CAN use right now ('list processes', 'start <name>',
   'open <hub>', 'tell <name> that ...', 'remember ...', 'recall ...').
   The reply renders as a normal assistant message, not a red error.

3. Topbar UI/UX Pro Max pass:
   - Added aria-label to the ⌘K and avatar buttons (icon-only a11y)
   - Removed the duplicate topbar-mid chips on Mission (Mission scene
     already shows family/defName/version inline). Cleaner topbar.
   - Added focus-visible outlines (2px amber, 2px offset) on all
     topbar action buttons + user-menu items
   - Hover/active scale on the avatar (1.04 / 0.97) with 160ms ease
   - Tabular numerals for the ⌘K kbd and notification badge
   - prefers-reduced-motion respected

30/30 vitest pass. tsc + vite build green.
2026-06-15 20:04:59 +04:00
canvas-bot 5abb3595fc fix(wizard): retry createDraft on 500/502/503/504 + human error message
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
POST /api/ea2/flow currently returns 500 after 19s on demo upstream.
Retry once with backoff, then surface a clear 'EA2 backend temporarily
unable to create new processes' message naming the status. The user
gets actionable info instead of a raw 500.
2026-06-15 19:42:32 +04:00
canvas-bot 3a72b74371 fix(chat): tolerate 500 on empty inbox edges; fix(agent): clear LLM-unavailable msg
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
- chatApi.listThreads: catch on the edges query so a fresh empty
  inbox doesn't bubble a 500 to the UI. New users see 'No
  conversations yet' instead of the error banner.
- agentTools.llmFallback: when the LLM gateway returns 503/500,
  show a clear 'plain-language replies temporarily unavailable'
  message naming the reason, listing the deterministic capabilities
  that still work. No more silent null returns.
2026-06-15 19:27:37 +04:00
canvas-bot 8d85a4c3ea fix(login): do not block login completion on EA2 scenario fetch
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
If buildLiveScenariosFromApi hangs or errors on any EA2 read,
loginAs would await it forever, leaving the user stuck on
'VERIFYING...' even after auth+identity succeed. Make refreshLive
fire-and-forget after the toast; the Mission scene re-fetches
on mount and surfaces failures via liveError.
2026-06-15 19:13:13 +04:00
canvas-bot 722b0ba3a2 fix(nginx): drop CoreDNS from resolver, use public DNS only
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
CoreDNS at 10.43.0.10 returns SERVFAIL for demo.flow-master.ai in
this environment. Including it in the resolver list caused nginx
to query it first, get SERVFAIL, and return 502 before falling
back to 1.1.1.1. Pinning to public resolvers eliminates the cold
miss. 300s TTL caches the result.

Restored $variable form for proxy_pass because the static-hostname
form failed pod readiness (DNS query at config-load time hits
the same SERVFAIL).
2026-06-15 18:56:29 +04:00
canvas-bot db32934100 fix(nginx): static proxy_pass hostname so DNS resolves once at config-load
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled
The previous $variable form forced lazy per-request DNS resolution.
Per-request lookups against 10.43.0.10 → SERVFAIL → cold-cache 502
even when downstream was healthy. Switching to a literal hostname
makes nginx resolve once at startup and reuse the cached upstream IP
for the lifetime of the worker. Cloudflare anycast is stable so this
is safe.
2026-06-15 18:39:26 +04:00