Commit Graph
215 Commits
Author SHA1 Message Date
NuklearRabbit f715085f65 M20: stabilize production acceptance
MobilityOps acceptance / backend (push) Canceled after 0s
MobilityOps acceptance / frontend (push) Canceled after 0s
2026-08-10 13:02:03 +02:00
NuklearRabbit 5d7a5e7359 M19: harden performance and recovery
MobilityOps acceptance / backend (push) Canceled after 0s
MobilityOps acceptance / frontend (push) Canceled after 0s
2026-08-10 12:51:41 +02:00
NuklearRabbit fe06ff75a1 M18: implement operational workspaces 2026-08-10 12:41:28 +02:00
NuklearRabbit 8030753dbc M17: ground knowledge and integration evidence 2026-08-10 12:27:17 +02:00
NuklearRabbit 686795a452 M16: isolate acceptance and harden readiness 2026-08-10 12:08:42 +02:00
NuklearRabbit 2ee8b2d82b M15: synchronize contracts and acceptance 2026-08-10 05:39:19 +02:00
NuklearRabbit 58fb515337 M14: add n8n execution health telemetry 2026-08-10 03:41:06 +02:00
NuklearRabbit 218599af7d M13: harden MCP trust boundary 2026-08-10 03:24:17 +02:00
NuklearRabbit 15bdbe40ac M12: complete daily operations cycle 2026-08-10 03:15:46 +02:00
NuklearRabbit 4a3c3bd0a9 M11: implement operational booking lifecycle 2026-08-10 03:06:30 +02:00
NuklearRabbit 3f13912739 test: select an available vehicle for booking creation 2026-08-10 02:54:50 +02:00
NuklearRabbit b2e1ae7f17 test: make booking overlap assertion deterministic 2026-08-10 02:53:40 +02:00
NuklearRabbit de151914b6 M10: harden knowledge trust and telemetry 2026-08-10 02:51:07 +02:00
NuklearRabbit e577c16db5 M9: create validated internal bookings 2026-08-10 02:20:28 +02:00
NuklearRabbit c194c18ca9 docs: record operational mode validation 2026-08-10 02:11:26 +02:00
NuklearRabbit 948d5eb6a6 fix: normalize return risk timestamps 2026-08-10 02:10:02 +02:00
NuklearRabbit 3cd9ddfa66 fix: retain demo sessions across seed resets 2026-08-10 02:08:40 +02:00
NuklearRabbit 0bfcf71ff7 M8: add operational authentication mode 2026-08-10 02:06:50 +02:00
NuklearRabbit 4cdf667dc1 docs: record booking scale-up verification 2026-08-10 01:49:49 +02:00
NuklearRabbit 0ef4a6fa98 UX: paginate booking operations 2026-08-10 01:47:35 +02:00
NuklearRabbit 2648cef8e3 docs: record final roadmap verification 2026-08-10 01:15:16 +02:00
NuklearRabbit aacf0e04bc fix: preserve mobile record status 2026-08-10 01:14:20 +02:00
NuklearRabbit ad1182582d docs: record visual roadmap evidence 2026-08-10 01:05:30 +02:00
NuklearRabbit f2cdad194c UX: implement visual product roadmap 2026-08-10 01:05:07 +02:00
NuklearRabbitandClaude Sonnet 5 13ad2ba6a3 docs: record the MCP Hub URL fix and RAGcore Procedure Sync go-live
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 22:07:41 +02:00
NuklearRabbitandClaude Sonnet 5 086dfed992 fix: publish RAGcore Procedure Sync and derive its evidence for real
MCP_HUB_BASE_URL had the same wrong-hostname bug as RAGCORE_BASE_URL earlier
this session (itworx-mcp-hub:8000 doesn't resolve; the real container is
reachable at the host's own 192.168.10.150:1100) -- fixed live, resolving the
Automation page showing "Operationeel" and "Hub Onbereikbaar" simultaneously.

Went on to actually publish the "Fleet Ops -- RAGcore Procedure Sync" n8n
workflow now that RAGcore is reachable: its own RAGcore Sync Token credential
had gone stale from the same rotation as the earlier one, so minted a fresh,
dedicated, minimally-scoped (sources:sync only) credential, verified a real
manual run (33 synced, 0 failed, result registered) before publishing.

That exposed a real, now-stale bug: derive_n8n_status() hardcoded this
workflow's evidence to None with a comment explaining it was unpublished --
true when written, false now. The workflow's own result-report callback
already writes a real n8n_procedures_synced audit event; wired that in as its
evidence source, the same pattern the scheduled scan and error handler already
use, instead of a value that could never update itself once the workflow went
live.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 22:05:13 +02:00
NuklearRabbitandClaude Sonnet 5 64cc96fa4b docs: record the RAGcore go-live fix and evidence
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 21:22:57 +02:00
NuklearRabbitandClaude Sonnet 5 319f43312e fix: drop RAGcore's opaque version UUID from the fallback answer sentence
document_version_id is an internal UUID, not a human-meaningful version like
the demo corpus's markdown frontmatter -- confirmed live it made the fallback
answer read as "Per \"vehicle-checkout-procedure.md\" (v2e139422-b10b-...)".
Still shown on the source card itself, just not in the composed sentence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 21:18:58 +02:00
NuklearRabbitandClaude Sonnet 5 a2433d7fa3 fix: fall back to real RAGcore search when /v1/answers is unavailable
RAGcore's /v1/answers (generation + citation validation) is currently returning
a consistent 503 VALIDATION_RETRIES_EXHAUSTED live -- a RAGcore-side bug in its
own generation/validation step, out of scope to fix here (CLAUDE.md forbids
modifying the RAGcore repo). Its retrieval pipeline (/v1/search) is a materially
different, simpler stage with no generation step, and returns real, correctly
cited results right now.

RAGcoreKnowledgeProvider.ask() tries /v1/answers first (unchanged behavior once
RAGcore's generation is fixed), and only when that endpoint itself is
unavailable -- non-2xx or unreachable, never a real 200 classifying the
question as insufficiently answerable -- falls back to /v1/search and builds
the shown "answer" as an extractive citation-wrapped excerpt, mirroring
DemoKnowledgeProvider's own existing template exactly. Never invents an answer
to the question; only ever shows a real, cited excerpt RAGcore's own search
actually found.

Also fixed two real config bugs found while wiring this up live: RAGCORE_BASE_URL
pointed at a non-existent internal hostname (ragcore-api:8000 -- the real
container is reachable at the host's own address on port 1237), and the
previous test credential had been invalidated with nothing to replace it. Minted
a fresh, correctly-scoped service-account credential via RAGcore's own admin
control plane (the documented, legitimate way to obtain one).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 21:11:28 +02:00
NuklearRabbitandClaude Sonnet 5 453c7241fe docs: record the MCP Hub go-live fix and evidence
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 20:19:07 +02:00
NuklearRabbitandClaude Sonnet 5 529e7364a9 fix: pass MCP_HUB_REGISTRATION_ENABLED/MCP_HUB_BASE_URL through to the api container
compose.yaml's api service environment block forwarded MCP_HUB_SERVICE_TOKEN but
never these two -- so .env's value was silently ignored and Settings always fell
back to its Python default (false / empty), no matter what .env said. Found while
flipping the flag live: the container's actual reported registration_enabled
stayed false after a full recreate, even though .env had been updated and two
real mcp_tool_request audit events already existed (itworx-mcp-hub:readiness ->
fleet_ops_get_operations_summary), proving the Hub's connector already reaches
Fleet Ops successfully independent of this flag -- only the status display was
gated, and silently stuck off.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 20:15:17 +02:00
NuklearRabbitandClaude Sonnet 5 7d686ae2aa docs: record polish fixes, merge, and second deploy evidence
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 19:04:42 +02:00
NuklearRabbitandClaude Sonnet 5 c2b8268927 fix: form field alignment, raw maintenance text, and static movements list
- .form-grid labels (missing-field form, odometer-regression correction fields)
  and the odometer/overlap note textareas had no stacked label-above-input
  styling at all -- the shared rule only covered .filters/.return-form, so these
  fell back to default inline browser layout with mismatched input widths.
  Extended the existing rule to cover .form-grid and label:has(> textarea).

- Vehicle maintenance list showed the raw, untranslated seed text
  ("Synthetic scheduled service record") regardless of locale -- purely
  decorative and 1:1 redundant with the (already-translated) category. Replaced
  it with the record's real odometer reading, mirroring the sibling
  Inspections tab's pattern.

- "Today's movements" was always the same fixed 4 bookings (2 returns, 2
  departures) on every reset, reading as a static mockup rather than live
  fleet activity. Added 8 more bookings anchored to land on "today" across 8
  additional vehicles, spread through the day.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 18:29:56 +02:00
NuklearRabbitandClaude Sonnet 5 9e9dd8e0e3 docs: record the three-defect fix, gates, and live verification evidence
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 17:52:13 +02:00
NuklearRabbitandClaude Sonnet 5 4faac24b5a fix: localize dashboard evidence, explain blocked vehicles, clarify pending odometers
Three content defects found by a live reviewer:

- Dashboard attention subtext was raw, untranslated evidence.summary text, and for
  11 of 15 seeded issues that text was literally "Synthetic deterministic seed
  issue". AttentionItem now exposes evidence_signals (stable code + params, same
  shape as the issue detail page) instead of a detail string; the frontend renders
  them through a shared describeEvidenceSignal() used by both the dashboard and the
  issue detail page. Every previously-placeholder seed row now cites a real,
  per-rule-type fact (a genuinely crossed service threshold, a genuinely blank
  field, or a real pair of booking odometer readings) instead of invented prose.

- 5 of 7 blocked vehicles had no quality issue at all and one had only a resolved
  one, so "needs attention" led nowhere. Each now has a real open
  missing_required_field issue backed by a genuinely blank field (no schema change,
  no migration -- reuses the existing data-quality pipeline).

- Booking odometer fields showing a bare "-" for 25 reserved + 1 active booking now
  show a localized explanation ("trip hasn't started yet" / "not yet closed").
  MO-024's rented-but-service-overdue contradiction was already caught by the
  vehicle-status evaluator (DQ-SCAN, vehicle.manual_review_required) -- added a
  regression test rather than new logic.

Also fixed a related bug the above exposed: the vehicle entity_snapshot omitted
registration_number entirely, so the "provide missing fields" form always showed
it blank regardless of the real value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 17:44:32 +02:00
NuklearRabbitandClaude Sonnet 5 3808bbe132 docs: record push, Unraid deploy, and live verification evidence
Closes out the demo-scenario fix: pushed the two pending commits, deployed
6f77a30 to Unraid, and verified all four live checks (integration status,
failed-workflow listing, retry via API and UI, audit trail, Automation page).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 16:39:41 +02:00
NuklearRabbit 6f77a30dce fix: stop the prepared demo failure from degrading n8n integration health
The demo seed plants exactly one failed delivery (BK-H-0020) to demonstrate
retry and audit. Because derive_n8n_status() counted any failure, every fresh
reset pinned the n8n integration to "degraded" -- the demo showed a warning
about a prop, which tells a viewer something untrue about the automation.

The seeded failure now carries its own error code, demoScenarioTimeout, rather
than the generic connectionError a real timeout produces. No column and no
migration: last_error_code already existed, is already surfaced to the UI and is
already localizable.

- integration status splits failed into unexpected_failed and
  demo_scenario_failed; only unexpected failures may move the state. A staged
  failure alone leaves n8n operational.
- latest_failure_at is a health signal and now ignores the staged failure;
  latest_demo_scenario_at reports it separately.
- /api/v1/workflows exposes is_demo_scenario. The Automation page labels the run
  as a prepared demo scenario, explains that it is a simulated temporary failure
  that does not affect automation health, and offers a distinct "retry demo
  scenario" action. Translated in nl-BE, en-GB and fr-BE.
- the carve-out stays narrow: a real failure still degrades n8n, and a genuine
  later failure of the same event overwrites the demo code with the real one.
- the retry itself is unchanged and real: the event goes back on the outbox and
  the dispatcher delivers it to n8n like any other, so 19+1 becomes 20+0 only on
  an actual round trip. The audit records which kind of failure was retried.

Tests that assert on the seeded scenario now reseed first, since earlier test
files legitimately mutate the outbox and the suite shares one database.

Verified locally against a real PostgreSQL 16: 181 passed, ruff clean, mypy
clean (50 files), tsc clean, frontend build clean. Not deployed and not
browser-verified.
2026-08-05 14:07:05 +00:00
NuklearRabbit e5307a7c0f fix: derive demo-manifest MCP Hub status from real tool-call evidence
The demo manifest still reported the MCP Hub integration as operational purely
because MCP_HUB_REGISTRATION_ENABLED was set, while the integration status page
had already moved to evidence-based status in Batch 4. Registration is
catalog-driven on the Hub's side, so the flag alone proves nothing; reuse
derive_mcp_hub_status() so "operational" requires real recorded mcp_tool_request
calls.

No change to the MCP integration contract: the four read-only routes, service
token and client id handling, inbound X-Correlation-Id preservation, the locale
field on search-knowledge and the provider/correlation_id response fields were
verified as already correct at deployed revision 727c19a and left untouched.
2026-08-05 13:28:43 +00:00
NuklearRabbitandClaude Sonnet 5 dee8f2f7e9 docs: record Batch 5 evidence and final session state
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 13:51:11 +02:00
NuklearRabbitandClaude Sonnet 5 57992bf153 M10: AI Operations Brief runbook, full live e2e regression, final evidence
Ran a real AI Operations Brief via the live ITWorx MCP Hub connector's own
MobilityOpsClient against production Fleet Ops: real operations summary, real
most-pressing vehicle, real grounded knowledge answer with citations, real
correlation IDs verified end-to-end in Fleet Ops's own audit log. No write
actions performed. Runbook and full output in
docs/final-integrations/ai-operations-brief-runbook.md.

Ran the full Playwright e2e suite against the live deployed instance and fixed
two pre-existing fragile locators unrelated to this session's feature work
(both broke because Automation now legitimately has two tables sharing the
same generic selectors, exposed by running the full suite rather than
individual files) plus one pre-existing untranslated-loanword false positive.
All specs pass.

artifacts/final-integrations/final-summary.md has the complete evidence
write-up: repository/deployment state, what was fixed vs. handed off, test
results, and known limitations stated plainly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 13:49:23 +02:00
NuklearRabbitandClaude Sonnet 5 727c19a779 M9: MCP Hub locale/correlation propagation, real Hub health check, fix stale test image
Fixed two concrete gaps in the MCP knowledge-search endpoint: no locale field
existed at all (now nl-BE/en-GB/fr-BE, wired to the knowledge provider's
existing language param), and the correlation ID was always freshly minted,
ignoring any inbound X-Correlation-Id header. Added a shared dependency and
applied it to all four MCP endpoints so Fleet Ops's own audit log preserves
the Hub's real correlation ID end to end.

MCP_HUB_BASE_URL/MCP_PROVIDER_ID were declared in .env.example but never read
anywhere. Since the Hub's own registration is catalog-driven (it never needs
Fleet Ops to push a registration call), wired mcp_hub_base_url for a real Hub
reachability health check instead of an unneeded self-registration call.

Renamed Fleet Ops's own internal audit tool labels mobilityops_* -> fleet_ops_*
(mirrored in contracts/mcp-tools.json with mobilityops_* kept as deprecated
aliases); documented that the live Hub connector's own dotted tool namespace
is a separate, Hub-owned naming layer, deliberately not touched.

Automation page's MCP card now shows real evidence (last tool/client/count/
timestamp, honest no-evidence state) instead of just the registration flag.

Also fixed a real methodology gap found mid-session: compose.yaml's api
service has no bind mount, so `docker compose run --rm api` silently tests a
stale image until rebuilt. Re-ran every local gate after rebuilding; fixed one
genuinely stale test assertion and two lint line-length errors surfaced by
that rebuild. 176 tests passing, ruff clean, mypy clean (50 files).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 13:30:24 +02:00
NuklearRabbitandClaude Sonnet 5 2ae2044e3a docs: record Batches 1-3 evidence and exact next action
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 13:05:53 +02:00
NuklearRabbitandClaude Sonnet 5 34df66d28c M8: GUI polish, n8n workflow-3 fixes, RAGcore retrieval root-cause and fix
GUI: dashboard Attention Queue presents a curated severity mix instead of pure
severity-sort (grouped Now/Today/Later headers); Today's Movements seed data
curated so a fresh reset shows a credible day (2+ departures, 2+ returns), with
a new seed-integrity test; About Demo restructured into a compact grid with
progressive disclosure for technical sections; Duplicate Merge shows match/conflict
counts, hides matching fields by default, and previews the final merged record
before confirmation.

Repo hygiene: removed a stray empty `backend;C` directory and an untracked 31MB
zip export; `.gitignore` now excludes future archive exports.

n8n: fixed invalid JSON (a missing `},` between two node objects) in the committed
`fleet-ops-vehicle-return.json` -- the file could not be parsed. Live-validated
workflow 3 (RAGcore Procedure Sync): found and fixed a real defect (three body
parameters had a stray trailing `}}`) and a missing Error Workflow wiring, both
via the safe `n8n import:workflow` CLI path; exported the corrected, still-
inactive workflow as the new source of truth and updated MANIFEST.md/check_drift.py.
Publishing it (starts real daily unattended runs) remains a separate decision.

RAGcore: root-caused and fixed (live, approved) the "zero retrieval candidates"
bug -- a filesystem permission bug (`embedding_profiles.json` unreadable by the
app's own runtime user) that broke every retrieval call before it reached Qdrant.
Every other suspect (grants, scope resolution, Qdrant filters, embeddings) was
verified healthy first. Found a second, deeper gap: the reranker adapter calls
an Ollama HTTP route that does not exist on the deployed Ollama version, so
`/v1/answers` still returns `not_answerable`. `KNOWLEDGE_PROVIDER` stays `demo`
until that is resolved on the RAGcore side. Evidence-based MCP Hub integration
status (real tool-call audit history, not just a boolean flag) replaces the old
`configured`/`not_configured` guess. Full findings in
`docs/final-integrations/current-state-audit.md`.

Backend: 172 tests passing, ruff clean, mypy clean (50 files). Frontend: tsc
clean, production build clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 13:05:02 +02:00
NuklearRabbitandClaude Sonnet 5 3ebca9e9b7 feat: replace brand mark with waypoint (pin-on-route) logo
Swaps the peaks-over-a-road glyph for a location pin on a route line
in both the favicon and the BrandMark component, so the mark stays
legible at 16px favicon size and reads more literally as fleet/route
tracking. Palette unchanged (navy #0f172a, teal #2dd4bf).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 11:47:11 +02:00
NuklearRabbitandClaude Sonnet 5 b66521da82 docs: record branch push and Unraid redeploy to 0571a40
Pushed feat/live-n8n-ragcore-integration to origin, then redeployed
the live Fleet Ops instance from 0da5251 to 0571a40 following the
deployment directory's own established source-archive convention.
Verified live: /health OK, the new n8n procedures endpoint (added
this branch) is reachable and correctly auth-gated, KNOWLEDGE_PROVIDER
still demo as intended.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 11:25:30 +02:00
NuklearRabbitandClaude Sonnet 5 0571a40649 docs: record n8n proxy-hops fix and completed workflow-3 build
Root cause found via the live n8n container's own logs: N8N_PROXY_HOPS=0
in the Unraid template didn't match the real reverse-proxy in front of
it, breaking the browserId/CSRF check on every workflow save while
leaving the UI looking fully signed in -- the user's pushback that it
"shows logged in" was correct and prompted digging into server logs
instead of continuing to guess client-side.

Fixed by editing the Unraid template (N8N_PROXY_HOPS 0->1, backed up
first) and recreating the container with every other setting preserved
exactly. Verified by reproducing the exact save action that used to
fail; it now works, and node persistence survives a full reload.

Built and saved both remaining workflow-3 nodes (Summarize sync
result, Report sync result to Fleet Ops) after recovering from an
errant Ctrl+A that deleted a node mid-verification (caught via node
count, restored via n8n's own Version History, redone carefully). Not
published -- that starts real daily production runs and is left for a
separate decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 07:12:57 +02:00
NuklearRabbitandClaude Sonnet 5 4227fe4f58 docs: record live /v1/answers verification and a retrieval finding
Issued a fresh scoped credential via the RAGcore admin UI (separate,
working OIDC session, unaffected by the n8n auth problem) and made a
real authenticated /v1/answers call. Got a clean 200 with a real
answer_id/retrieval_run_id, not degraded -- but not_answerable, 0
citations.

Confirmed this isn't a regression: the same query through RAGcore's
own pre-existing Query Lab tool (untouched this session) returns the
identical result down to zero dense/sparse candidates at the raw
retrieval stage. Ruled out the obvious causes via direct Qdrant/
Postgres checks -- workspace_id, space_id, status, and embedding
digest all correctly match real indexed content. Root cause not yet
found; flagged as a follow-up rather than pursued further to avoid
scope creep on what was a deployment-verification task.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 04:01:16 +02:00
NuklearRabbitandClaude Sonnet 5 c790ec99cb docs: record RAGcore search/answer wiring deployment to production
Deployed a2905cc to the live RAGcore instance (approved). Verified
the fix directly: POST /v1/search now returns 401
AUTHENTICATION_REQUIRED instead of the old permanent 503
SEARCH_UNAVAILABLE, proving the endpoint reaches real request
handling. A full authenticated /v1/answers call with a real grounded
answer is still outstanding -- the previously-issued production
credential's raw token was never persisted anywhere retrievable, and
issuing a fresh one needs the RAGcore admin UI, not attempted this
round.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 03:44:39 +02:00
NuklearRabbitandClaude Sonnet 5 fd390df423 docs: record n8n workflow-3 wipe/recovery and the live auth blocker
The live "Fleet Ops -- RAGcore Procedure Sync" workflow's canvas was
found at zero nodes -- the earlier session's abandoned direct n8n
REST API attempt had gone far enough to wipe it before hitting its
401. Recovered via n8n's own Version History "Restore version"
action back to the last good 4-node save; verified via DOM node
count before and after.

Adding the two remaining nodes then hit the same failure mode: n8n's
own first-party autosave reported "Unauthorized" moments after a
fresh, successful interactive sign-in. Stopped deliberately rather
than retrying against a live instance that already caused one data
loss incident this session -- this looks like an n8n-side session/auth
problem, not something fixable from browser automation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 03:38:16 +02:00
NuklearRabbitandClaude Sonnet 5 e5d8466266 knowledge: rewrite RAGcoreKnowledgeProvider to the real search/answers contract
The previous adapter targeted an endpoint shape RAGcore never actually
exposed. health() now checks /health/ready and ask() posts to the real
POST /v1/answers with Bearer auth and requested_space_ids, matching
RAGcore's actual contract after this session's Bearer-auth and
search/answer wiring work.

Adds RAGCORE_SPACE_ID config/env plumbing (a question is meaningless
without a knowledge space to scope it to) and 12 new adapter tests
covering degradation paths: missing space id, connection errors,
non-200 responses, malformed responses, not-answerable, and
answerable-without-citations all fail closed to "insufficient
evidence" rather than fabricating an answer.

KNOWLEDGE_PROVIDER stays "demo" in production for now -- switching
requires RAGcore's own search/answer application to actually be
deployed and live-verified, tracked separately in PROJECT_STATE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 03:20:55 +02:00