Commit graph

533 commits

Author SHA1 Message Date
e6bc101194 fix(nws): normalize severities to schema; drop CAP pre-filter
Remove the nws_handler broadcast_severities/warning_suffix_promotes
pre-filter (GATE A) that dropped sub-Severe NWS products before the
pipeline. All NWS alerts now normalize to routine/priority/immediate
(map_severity) and breadth is governed solely by the per-toggle
dispatcher threshold. Warning-class categories are promoted to
immediate so a wrong/missing CAP severity int cant under-rank a real
warning. broadcast_severities/warning_suffix_promotes are now inert
(marked deprecated). Fixes sub-Severe alerts (Special Weather
Statements / advisories) for Magic Valley / East Idaho never reaching
the mesh despite a routine toggle threshold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 00:12:27 +00:00
Ubuntu
e982cbbdf6 refactor(danger-zones): drop min_severity + position_max_age; table snow (grayed/inert)
- alert on any hazard touching a node (severity gate removed)
- alert regardless of position staleness; only skip nodes with no position
- snow tabled: grayed-out in GUI + skipped in correlator pending snowfall+elevation pipeline

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 06:56:22 +00:00
Ubuntu
95b1a23ef1 feat(danger-zones): configurable infra-node hazard correlation + fire age-gate
- danger_zones config section (isolated dataclass + danger_zones.yaml + GUI panel on Notifications page); defaults disabled + dry_run
- DangerZoneCorrelator: distance-based correlation of hazard events vs infra nodes (CLIENT_BASE/ROUTER/ROUTER_LATE), DM delivery, cooldown
- fire age-gate (wfigs max_declare_age_seconds) suppresses stale/closed fires announced as "New"
- tests: correlator + fire-gate boundary; wfigs fixture fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 06:33:54 +00:00
Matt Johnson
b6e15f656f chore: capture in-flight fire-spam/drain-pacer + reconnect ground truth from CT108
Preserve the live CT108 working-tree state (the running container is already
built and is unaffected by this commit).

Canonical build tree (work/ — what ships):
  - work/meshai/config.py      : ConnectionConfig watchdog reconnect knobs
  - work/meshai/connector.py   : watchdog link-state, socket-based liveness,
                                 active_probe, in-place reconnect
  - work/meshai/main.py        : connection supervisor (watchdog) task
  - work/Dockerfile            : healthcheck also asserts /tmp/meshai.link=up
  - work/docker-compose.yml    : matching healthcheck change

Root tree (stale duplicate, earlier reconnect iteration — preserved for fidelity):
  - meshai/config.py, meshai/connector.py, meshai/main.py
  - Dockerfile, docker-compose.yml

New (root only, NOT under work/, currently unimported / not in build):
  - meshai/notifications/pipeline/severity_router.py

Excluded: all *.bak / *.bak2 backup artifacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 05:58:23 +00:00
Ubuntu
6ed8ad4945 fix(satpass): add date label and single-observer region to wire format
Passes not happening today now show "tomorrow" or "Mon Jun 17" so they
aren't mistaken for past events. Single-observer consolidations now show
the observer name as region context, e.g. "(Treasure Valley)".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 15:01:20 +00:00
Ubuntu
6e3eae39fb fix(ci): add package-lock.json for npm ci in Docker build
npm ci requires a lockfile. Generated from existing package.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 03:48:44 +00:00
Ubuntu
107f5435b2 fix(ci): add README.md to work/ for Docker build context
pyproject.toml references readme = "README.md" and the Dockerfile
COPYs it for pip install -e. With build context set to work/, the
file must exist there.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 03:46:39 +00:00
Ubuntu
2e1fb325f7 refactor: move source tree into work/, multi-stage Docker build, fix satpass
- Move all application source (meshai/, dashboard-frontend/, tests/,
  config/, docs/, Dockerfile, etc.) into work/ directory
- Add Node.js multi-stage build to Dockerfile for frontend compilation;
  remove compiled static assets from git tracking
- Fix satpass missing time windows: consolidation was splitting wire on
  newline and only putting line 1 in event.title, dropping the time
  window line that the composer uses for precomposed broadcasts
- Fix satpass burst flooding: stagger consolidation timers (+60s per
  pending pass) so Central batch publishes don't blast the mesh
- Update CI workflow build context to work/
- Anchor lib/ and data/ gitignore patterns to repo root to prevent
  false matches on nested directories
- Add dashboard-frontend/node_modules/ to .dockerignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-16 03:40:31 +00:00
Ubuntu
7128b432ee fix(satpass): add AOS horizon guard to reject stale far-future passes
Passes whose AOS is more than max_aos_horizon_hours (default 24) in the
future are now rejected in the handler. Prevents stale predictions
republished via NATS LAST_PER_SUBJECT from broadcasting passes that are
too far out to be actionable. Complements the existing los < now guard
which catches passes that already ended.

New adapter_config key: satpass.max_aos_horizon_hours (int, default 24,
0 = disabled).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 23:11:50 +00:00
Ubuntu
85d48ce3c9 fix(fire): remove immediate-severity exemption from grouper + cooldown
Fire events carried _severity_override="immediate" which zeroed the
dispatcher cooldown and skipped the Grouper coalescer. This meant fire
had no rate control in normal live operation. Drain-mode pacer handles
reconnect bursts; this change closes the live-operation gap so fire
obeys the toggle cooldown_seconds like every other family.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 23:01:15 +00:00
Ubuntu
de69a9fd57 feat(satpass): consolidate per-observer broadcasts into single regional pass
Satellite passes were broadcasting 3x (once per observer: Filer, Boise,
Idaho Falls). Now accumulates all observers for the same satellite+hour
into satpass_pending, waits 5s for stragglers, then emits one consolidated
broadcast showing entry→exit sweep (e.g. "Filer→Idaho Falls").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 22:52:25 +00:00
Ubuntu
20cae52408 merge: fire spam drain pacer (de50414) into main
Fixes post-reconnect fire broadcast spam: severity downgrade
(immediate→priority), FIFO output pacer (≤1/min), drain mode
with per-IrwinID decision pass on NATS backlog catch-up.
2026-06-15 21:37:56 +00:00
Ubuntu
de50414471 fix(drain): add missing asyncio import for call_later
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 21:26:32 +00:00
Ubuntu
9ecd8652e1 fix(drain): add 30s timeout for empty-backlog drain exit
If LAST_PER_SUBJECT has no pending messages (container was only down
briefly), no _on_message callback fires and drain mode never exits.
Add a call_later timeout that auto-completes drain after 30s of no
num_pending==0 trigger.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 21:25:09 +00:00
Ubuntu
af4d2a3697 fix(drain): msg.metadata is a property, not a method
nats-py's Msg.metadata is a property returning a Metadata object
directly — not an async callable. Removes the erroneous () call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 21:22:06 +00:00
Ubuntu
2f677e85a1 fix(fire): drain-mode pacer to prevent post-reconnect broadcast spam
After a NATS consumer outage, LAST_PER_SUBJECT delivery floods thousands
of events in seconds. Fire events with _severity_override="immediate"
bypassed the Grouper and zeroed dispatcher cooldowns, causing duplicate
"New" broadcasts for the same fire.

Three-part fix:
- Downgrade fire severity from "immediate" to "priority" so pipeline
  guards (Grouper, cooldown) apply normally
- Add FirePacer (FIFO queue, <=1 fire broadcast/min) for rate-limiting
- Add drain mode to CentralConsumer: suppress bus.emit() during backlog
  catch-up, then run a decision pass per fire IrwinID against final DB
  state (New/Update/Closure/Silence) and route through pacer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 21:19:00 +00:00
Claude
1557f3f5b7 merge: satpass compass fallback (cb8a2af) into main 2026-06-13 16:36:30 +00:00
Claude
cb8a2af075 fix(satpass): fall back to raw azimuth degrees for compass directions
satpass_predict envelopes carry only raw azimuth_at_aos/los/peak as
float degrees — they lack the precomputed _compass string fields that
n2yo envelopes provide. The handler read only the _compass fields,
producing empty compass directions ("→") in broadcast wire text.

Apply _azimuth_to_compass() as fallback when _compass strings are
absent, preserving the existing string-field preference for n2yo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-13 15:20:47 +00:00
Claude
e2e065dda0 merge: satpass Tier1+2, fire recency, tombstone path, guard fix into main 2026-06-13 08:00:37 +00:00
Claude
2318f76015 fix(satpass): staleness guard — reject passes whose window already ended
Late-delivered or redelivered events for passes with los_epoch < now
were broadcasting as if upcoming.  Guard added after los_epoch parse,
before dedup/DB work.

Ongoing passes (aos past, los future) still broadcast.  los_epoch=None
falls through unchanged.

Existing tests pinned to fixed now= values to avoid false staleness
rejections on hardcoded envelope timestamps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-13 01:10:58 +00:00
Claude
f94cf20953 fix(satpass): coerce norad_ids to int set at comparison site
GUI saves norad_ids as JSON strings (["25544"]), wire delivers norad_id
as int.  Membership test `25544 in ["25544"]` was False — opt-in list
silently matched nothing.

Build allow_set as {int(x) for x in norad_ids_raw if str(x).isdigit()},
accept both string and int shapes forever.  Garbage entries silently
skipped.  satpass_cmd already coerces via [int(x) for x in cfg_ids].

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 23:36:18 +00:00
Claude
17808c3d65 feat(satpass): GUI safety controls panel — armed-state banner, dry-run toggle, rate cap
Tracking panel gains both new adapter-config keys:
- dry_run toggle (sky-blue accent, visually distinct from enabled)
- max_broadcasts_per_hour number input (1–60 range)

Armed-state banner at top of panel:
- OFF (grey) when disabled
- DRY RUN (sky-blue) when enabled + dry_run
- ⚠ LIVE (amber, pulsing) when enabled + !dry_run

Load/save through adapter-config API per 199929f pattern.
NORAD IDs helper updated to reflect opt-in semantics.

Bundle hash: index-DPN58SF4.js → index-Di1mw816.js
             index-CB06j1ej.css → index-WwNJt5S-.css

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 23:26:08 +00:00
Claude
e903444356 fix(satpass): broadcast safety controls — opt-in filter, rate cap, dry-run, wire format
Incident response for 343 broadcasts in 126s (2026-06-12 22:10 UTC).

Five safety controls:

1. OPT-IN BIRD FILTER: norad_ids=[] now means "broadcast nothing"
   (was "all birds"). Empty list logs once at INFO and suppresses all
   broadcasts. The !satpass DM command remains ungated — it queries
   any bird in the TLE cache using command_norad_ids as bare-command
   default. Two paths, two rules.

2. RATE CAP: new satpass.max_broadcasts_per_hour (int, default 4).
   Excess qualifying passes logged and suppressed. Broadcast path only.

3. DRY-RUN MODE: new satpass.dry_run (bool, default TRUE). Logs exact
   wire text at INFO prefixed "DRY-RUN would air:" without dispatching.
   Go-live: enabled=true + dry_run=true → observe → dry_run=false.

4. ELEVATION DEFAULT: min_elevation REGISTRY default already at 30
   (confirmed, no change needed).

5. BROADCAST WIRE FORMAT: two-line LoRa-tight format with buckets:
     🛰️ {name} {bucket}, {aos_compass}→{los_compass}
     {duration} minute window, {rise}–{set} {AM/PM} MDT
   Buckets: overhead (≥60°), high pass (30-59°), low pass (<30°).
   DM format keeps exact degrees. One format_pass() function with
   broadcast= mode switch — two callers, one function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 23:00:03 +00:00
0cb175d65b fix: correct satpass_handler wire field names + add pass. category prefix
satpass_handler.py: fix 6 field reads to match actual Central NATS
wire names (max_elevation_deg, satellite_name, observer_name/slug,
aos_time, los_time, azimuth_at_peak_compass).

consumer.py: add pass. prefix to _CATEGORY_MAP so
pass.n2yo_visualpasses routes to sat_pass instead of default-deny.
Add sat domain fallback to _SUBJECT_DOMAIN_CATEGORY.

Tests: 9 new tests using verbatim live NOAA-18 envelope from
central.sat.pass.us.id.filer (2026-06-10). Updates existing
test_satpass_handler.py fixtures to match corrected wire names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 20:55:01 +00:00
199929ff1c fix: GUI satpass enabled toggle now persists through adapter-config API
The Tracking panel toggle for satpass.enabled was silently dropped on
save because SatpassConfig lacked the enabled field. The toggle wrote
to a phantom env.satpass.enabled (not in EnvConfig) which the
environmental config endpoint ignored. Handlers read enabled from the
adapter_config SQLite table, which was never updated.

Changes:
- Add enabled:boolean to SatpassConfig interface + initial state
- Convert GET /api/adapter-config/satpass array response to keyed dict
  so load actually reads saved values (fixes pre-existing load bug)
- Wire enabled into the save path via saveAdapterConfig PUT
- Override AdapterPanel enabled/onEnabled for satpass to use
  satpassConfig instead of the phantom env field
- Add test_bool_roundtrip.py: 6 tests proving PUT true/false round-
  trips through DB (value_json) and accessor (Python bool), plus
  second+third adapter boolean round-trips (wfigs, fires)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 20:16:07 +00:00
116e66369e test: satpass event path — wire adapter routing + enabled gate
13 tests covering the full sat event routing chain:

- CENTRAL_ADAPTER_TO_SOURCE maps celestrak_tle, n2yo_visualpasses,
  and satpass_predict to 'satpass' (3 tests)
- No stale adapter names (sat_passes, sat_tles, sat_tle) in map
- TLE handler inserts sat_tles row when enabled (integration)
- TLE handler drops when satpass.enabled=false
- Pass handler accepts n2yo_visualpasses and satpass_predict envelopes
- Pass handler rejects celestrak_tle envelope
- REGISTRY key is min_elevation (not min_elevation_deg)
- Handler source reads min_elevation (not min_elevation_deg)
- Consumer dispatch source has correct wire names

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 17:19:52 +00:00
be4443feb9 fix: wire adapter name mismatch in satpass event path
Central publishes sat events with wire adapter names celestrak_tle,
n2yo_visualpasses, and satpass_predict.  Task C's routing matched on
sat_tles/sat_tle/sat_passes — names that exist nowhere on the wire —
so every sat event was silently dropped at three kill points:

1. CENTRAL_ADAPTER_TO_SOURCE map (consumer.py line ~216)
2. _normalize dispatch conditionals (consumer.py line ~549)
3. satpass_handler adapter guard (satpass_handler.py line ~118)

All three now use the correct wire names.  Both handlers also gain an
enabled gate that returns None when satpass.enabled=false, logging at
INFO once per process lifetime via a _disabled_logged function flag.

Existing test fixtures updated for the new adapter names and the
enabled gate (cfg.enabled=True in mock, _disabled_logged cleanup).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 17:19:44 +00:00
4a17c7b702 fix: add satpass to region rewrite table in _subjects_for()
_subjects_for() consults a per-adapter region table when region is set
(e.g. us.id). The table had no satpass entry, so it returned [] and
Central silently subscribed to nothing for sat subjects.

Changes:
- Add satpass entry to the region table: pass alerts use Convention A
  (central.sat.pass.{region}.>), TLEs are global (central.sat.tle.>)
- Update test_central_region_default_propagates_to_consumer_subjects
  to expect satpass subjects (satpass defaults to feed_source=central)
- Add 3 tests in test_satpass_registration.py: _subjects_for with
  region, without region, and empty region fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 15:33:25 +00:00
aa2838fee3 fix: register satpass adapter on EnvironmentalConfig
_subject_owned() iterates _SUBJECTS_BARE keys and calls
getattr(self._env, attr) — but EnvironmentalConfig had no satpass
attribute, so Central never subscribed to central.sat.> subjects.

Changes:
- Add SatpassConfig(_SourcedFeed) with feed_source=central default
- Add satpass field to EnvironmentalConfig
- Add satpass YAML parsing handler in _dict_to_dataclass
- Add (satpass, enabled) to adapter_config REGISTRY
- Fix 3 satpass REGISTRY entries: type list -> json (vocabulary bug)
- Update stale count assertions (SCHEMA 16->17, REGISTRY 84->90,
  ADAPTER_META 21->23)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 07:39:44 +00:00
5418ed1f65 feat(satpass): Tier 2 on-demand satellite pass predictions (!satpass command)
Four-part implementation:
- Part 1: TLE cache handler subscribes central.sat.tle.>, upserts latest-wins
  on epoch, 14-day staleness exclusion at read time (tle_handler.py)
- Part 2: SGP4 pass predictor with 30s step propagation, ECI→topocentric
  look angles, grouped into PassInfo objects (pass_predictor.py)
- Part 3: ZCTA centroid CSV vendored (33,144 ZIPs), lazy-loaded for
  ZIP→lat/lon lookup with no runtime network dependency
- Part 4: !satpass command with three forms: bare (adapter_config defaults),
  name/NORAD ID, ZIP code observer. Location chain: GPS→ZIP→ask.
  Reply formatted as 'ISS 09:36-09:43 MDT max 64deg SW->NE'

Schema v16→v17 (sat_tles table). sgp4>=2.22 added to requirements.
24 new tests covering TLE upsert/staleness, pass prediction reference,
ZCTA lookup, command routing, location chain, and reply format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 06:36:32 +00:00
886bb6510b fix: tombstone broadcast path — immediate severity + commit handles
Tombstone closure broadcasts were silently dropped because the handler
set severity to routine (below the dispatcher floor) and never called
_attach_commit_handles(), leaving event_log.handled=0 permanently.

Changes:
- wfigs_handler.py: tombstone severity routine → immediate
- wfigs_handler.py: attach commit handles with dedup suffix closed
- wfigs_handler.py: use _log_event_returning_id so commit callback
  can flip handled=1 on successful broadcast
- env_reporter.py: build_env_summary fire count excludes tombstoned
  and 100%-contained fires (matches build_fires_detail WHERE)
- tests/test_tombstone_broadcast.py: 11 tests covering severity,
  commit handles, dedup suffix, callback, closure wire, and
  env_summary exclusion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 05:48:25 +00:00
b5a8f5cf97 fix(fire_digest): trim lines to name + location, correct tail count after budget trim
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 04:39:57 +00:00
bf88bdc9e6 fix(fires): recency-only ordering, exclude contained/tombstoned in LLM context and digest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 04:17:50 +00:00
fa79fa1c9e fix(env_reporter): fire context hybrid recent+largest, exclude tombstoned
Chat LLM context selected top-10 fires by acreage only; small fresh
incidents (IA/assist fires) ranked below the cutoff and were invisible
to chat. Also excluded: tombstoned fires were listed as active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 03:14:14 +00:00
1f34f74e5a feat(satpass): add satellite pass GUI to Environment + Notifications pages
- Environment: add satpass adapter to Tracking tab with observers,
  min_elevation, and norad_ids controls via adapter_config API
- Notifications: add satpass family to master toggles
- Rebuild dashboard bundle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 00:10:51 +00:00
782899d4b1 feat(satpass): add satellite pass alert family (tier 1)
- Add satpass_handler.py with observer/elevation/NORAD filters
- Subscribe to central.sat.pass.> in consumer.py
- Add satpass toggle family to config.py
- Add sat_pass category mapping in categories.py
- Add satpass config section in adapter_config/defaults.py
- Add 9 unit tests for handler logic

Wire format: 3-line LoRa-tight (sat name, AOS/LOS times, observer)
Dedup: hourly bucket per sat/observer
Severity: 60deg+=immediate, 45deg+=priority, else routine
2026-06-11 23:23:24 +00:00
meshai-fix
40ad40f277 fix(dispatcher): commit guards only after successful delivery (B13) + dedup suffix for WFIGS lifecycle updates 2026-06-11 17:44:02 +00:00
98e3fcf675 Merge branch 'feature/mesh-intelligence' 2026-06-10 21:03:08 +00:00
b36223146f fix: harden EnvironmentalStore adapter init — isolate failures
- Wrap each adapter registration in try/except via _register_adapter()
- Track failed adapters in _failed_adapters dict with error message
- Add get_status() method for /api/env/status to report failed adapters
- No single adapter failure can abort loading of remaining adapters

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-06-10 20:25:50 +00:00
3dd48b6337 fix: Carbon sweep — TownAnchors + GaugeSites cyan/slate → Carbon tokens
- Replace bg-slate-800/60 and bg-slate-800 with bg-bg-card/bg-bg
- Replace border-slate-700 with border-border
- Replace divide-slate-700/60 with divide-border
- Replace hover:bg-slate-800/50 and hover:bg-slate-700 with hover:bg-bg-hover
- Remove all rounded classes for sharp Carbon edges

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-06-10 19:55:02 +00:00
72611cc148 feat: move Photon geocoder config to config.yaml — public komoot default, local override in deployment config 2026-06-10 19:49:26 +00:00
f65d1d2f59 fix: Carbon sweep — GaugeSites, TownAnchors, Notifications, Alerts — teal/cyan/blue → amber 2026-06-10 19:42:39 +00:00
bce11b2196 fix: Layout.tsx — logo container bg, Carbon nav colors, remove stale blue active states 2026-06-10 19:37:13 +00:00
e181d0c126 feat: MeshAI logo PNG in sidebar, favicon wired 2026-06-10 19:33:58 +00:00
768f6e72ac Merge branch 'feature/mesh-intelligence' 2026-06-10 15:44:54 +00:00
06a5cc23ef fix: Carbon theme — bump muted text tiers for legibility (#333/#444 → #666/#777)
text-[#333] → text-[#666] (63 hits), text-[#444] → text-[#777] (38 hits)
across all tsx/css. Scrollbar thumb #1e1e1e → #2a2a2a.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-10 15:44:48 +00:00
7de460804f Merge branch 'feature/mesh-intelligence' 2026-06-10 15:37:33 +00:00
d0bf298f89 feat: Carbon theme — amber accent, Inter/JetBrains Mono, sharp corners, traffic-light semantic colors across all components
Global: removed all rounded-lg/md/sm classes, replaced blue-500 with
sky-400 informational, cyan accents with amber across all tsx files.
Environment.tsx + AdapterConfig.tsx: full Carbon color sweep — slate
hierarchy replaced with #333/#444/white tokens, border-border tokens,
font-sans labels, font-mono values. Layout.tsx logo text-[15px].

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-10 15:37:27 +00:00
f054d80efc Merge branch 'feature/mesh-intelligence' 2026-06-10 14:37:49 +00:00
6b08cdc004 feat: apply Carbon theme — amber accent, Inter/JetBrains Mono, sharp corners, Lucide icons preserved
Carbon palette: #111111/#0d0d0d backgrounds, #1e1e1e borders, traffic-light
data colors (green/red/sky/amber), 10px uppercase card headers, StatCard
colored border-tops, Layout sidebar amber bar + right nav indicator.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-10 14:37:33 +00:00