Commit Graph
100 Commits
Author SHA1 Message Date
Sameh Khamis 82bbf16a8f feat(ui): render the Cockpit briefing card from a store
The Cockpit controller no longer writes the briefing card's pages, cycle
toggle, regional news and local conditions: it keeps them as plain state,
starting from cockpitBriefPages.js, and publishes a copy to a new
gev-cockpit store. A new CockpitBriefing component, lifted verbatim from
the Cockpit view, renders it. News rows are keyed by story, so a focused
link never turns into another story on refresh. The controls keep the
controller's listeners; the route card and the signal list keep their
owners' bindings for now. The boot-time kicker translation is gone, as
the card translates its own text.
2026-10-31 13:56:31 -07:00
Sameh Khamis d134aefd77 feat(ui): render the phone tab bar and sheet backdrop from a store
The phone shell no longer builds its tab bar and backdrop or writes their
aria-expanded, aria-hidden and hidden state: it publishes its tabs,
whether it is on and the open sheet to the gev-display store, and a new
PhoneTabBar component in the dock teleports them to the end of the page
from the first publish until the shell is destroyed, so they still follow
the scene's credits. The shell takes tab and backdrop clicks from the
document and returns focus to a tab once the tab bar shows it closed; a
reopen or destroy cancels a pending return.
2026-10-31 13:31:23 -07:00
Sameh Khamis 5f8f9bb921 feat(ui): render the location tray's pills, mini status and search error from a store
LocationControls (./ui/location) no longer builds the city and landmark
pills or writes the mini status and the search error: it presents the tray
and hands it to its publish option, so the entry stays Vue-free. The shell
publishes it to a new gev-location store and connects the controls, and
the dock renders it and calls chooseCity() and choosePoi(). The landmark
row still expands a frame after its pills render. The search field, its
toggle and the reset buttons keep their listeners. The location QA harness
reads the rendered elements.
2026-10-31 12:19:44 -07:00
Sameh Khamis 4966877859 feat(ui): render the map source chips and status badge from the store
createMapSourceControls() (./ui/maps) no longer builds the chip row or
writes the status badge: it presents both and hands them to its publish
option, so the entry stays Vue-free. The shell publishes them to the
gev-display store and connects the controls, and the dock renders the
chips and calls select() for an available one. renderMapStackChips and
syncMapStackChips are deprecated. The map source QA harnesses wait for
the dock to render and no longer read the removed element refs.
2026-10-31 12:11:35 -07:00
Sameh Khamis decac29fbd feat(ui): render the active style in the dock and the ACTIVE STYLE corner from the store
VisualSettings no longer toggles the style buttons' active class or writes
the dock's style mini status and the ACTIVE STYLE corner. It publishes the
active style and its label to the gev-display store; CommandDockView and
SceneChromeView render them. The buttons keep their owner's listeners, and
the initial label renders through t().
2026-10-31 12:05:19 -07:00
Sameh Khamis 66a60ff67e feat(ui): render the Space Missions roster and selected mission from the launches layer's published view
The launches layer no longer builds the roster or the selected mission
panel as HTML strings in #space-mission-panel-host. It presents both as a
plain view and publishes it through subscribePanel(); MissionRoster and
MissionDetail render it from the gev-context store and call the layer's
panel commands. Replay controls are presented the same way.

The roster keeps keyboard focus on the same mission across refreshes, or
continues beyond the list when the mission departs, and the row under the
pointer takes the preview back on its next movement. Lines a null view
rebuilds are translated through t(). Disposing the shell clears the
Contacts and Space Missions views.
2026-10-31 10:48:20 -07:00
Sameh Khamis 1e4df63efe feat(ui): render the Contacts panel from the awareness layer's published view
The awareness layer presents its panel as a plain view and publishes it through subscribePanel() instead of writing markup into #military-awareness-panel. AwarenessPanel renders it from the gev-context store, calls the layer's navigation, and keeps focus on the same control by identity across live repaints, continuing at the note when that control leaves or is disabled.
2026-10-31 01:03:28 -07:00
Sameh Khamis 749bfd5cd4 feat(ui): render the Context mode switch from a store
ContextControls presents the selected mode, the transition busy state and the nearby sites search through a publish option, and ContextView renders them from the gev-context store. ./ui/context stays free of Vue. The Radio QA reads the search button's aria-busy, the state it actually carries.
2026-10-31 00:51:29 -07:00
Sameh Khamis b6c7c130f6 feat(ui): render the local RTL-SDR card from the store
LocalSdrControls publishes the card to the radio store and SdrCard renders it. The new v-field-value directive never overwrites a focused field, including one a render disables.
2026-10-31 00:43:27 -07:00
Sameh Khamis ccb7edd0d1 feat(ui): render the Radio panel's directory, station card and transport from a store
RadioPanel, lifted from ContextView, renders the layer state, Enable, the tag filter, station card, transport, volume and playback line from the gev-radio store that RadioControls publishes to. The tuner, the local SDR card and the Cockpit radio controls keep their element bindings. Enable's busy mark and the dragged volume go through the owner so a render never leaves them stale, and the markup's tag option stands until the categories first change. ./ui/radio now imports Vue and Pinia.
2026-10-31 00:20:07 -07:00
Sameh Khamis a068a45a89 feat(ui): render the Display panel's imported file list from the store
The file import publishes its rows and hint to the gev-display store and DisplayPanel renders them, keyed by file, so a toggled row keeps its controls. Keyboard focus is given back once the list has rendered: a removed row's next row, else the previous one, else the Import button; a second change before the render keeps the first target, and focus moved elsewhere meanwhile stays there.
2026-10-31 00:05:25 -07:00
Sameh Khamis 9eb969c682 test: format the draw tool test 2026-10-30 23:56:20 -07:00
Sameh Khamis c1dd9246eb fix(ui): keep the removed Display and layout exports as deprecated shims
Restore shouldHideCollapsedRightPanels, syncScopeControls and the fadeSliders field, skipping sliders already bound by name. Note the API changes in the changelog.
2026-10-30 23:56:20 -07:00
Sameh Khamis a767b84486 fix(ui): give the Cyber stacks the panel rail clearance
The Cyber stack offsets add --panel-rail-clearance so the rails clear the HUD edge readouts.
2026-10-30 23:56:20 -07:00
Sameh Khamis dc9d200725 fix(ui): keep the voice highlight on layer rows
Toggle the count-line modifier with a directive that leaves other classes alone, so a re-render no longer clears gev-voice-focus.
2026-10-30 23:56:20 -07:00
Sameh Khamis 231ac4b67b fix(ui): return Escape focus to the rail item and read rail direction from the panel
A desktop side panel hides once collapsed, so Escape hands focus to its visible rail item instead of the hidden disclosure. Rail selection reads the panel's collapsed class rather than the store, which follows it a microtask late.
2026-10-30 23:56:20 -07:00
Sameh Khamis 54b8060f71 fix(ui): keep the scene select on the published scene after a local pick
Re-apply the published scene to the select after every option render, as the imperative renderer did. The scene and visual-input QA scripts click a held shot label after disposal and wait a frame for the bloom row.
2026-10-30 23:56:20 -07:00
Sameh Khamis b870df4199 feat(ui): render the Display panel's Draw controls from the store 2026-10-30 23:45:03 -07:00
Sameh Khamis bca7495cbf feat(ui): render the generated style parameter rows through Vue 2026-10-30 23:23:58 -07:00
Sameh Khamis 926253e8a3 feat(ui): render the Display panel's 3D aircraft group from the store 2026-10-30 23:13:37 -07:00
Sameh Khamis 1139d364c7 feat(ui): render the Display panel's Scope and Celestial controls from the store 2026-10-30 23:07:21 -07:00
Sameh Khamis 3aa5a3e5e3 feat(ui): render the Display panel's HUD and Sonar controls from the store 2026-10-30 23:01:09 -07:00
Sameh Khamis c99c0e8000 feat(ui): render the Display panel's detection controls from the store 2026-10-30 22:51:47 -07:00
Sameh Khamis 343bdebe98 feat(ui): render the Display panel's bloom and sharpen from a store 2026-10-30 22:41:07 -07:00
Sameh Khamis 5707a8a151 fix(ui): inset the side panels so their rails clear the HUD edge readout 2026-10-30 22:23:40 -07:00
Sameh Khamis d63f4d697b feat(ui): render the data layer rows through Vue from presented row state 2026-10-30 22:23:40 -07:00
Sameh Khamis ce343c1c6d feat(ui): render the CCTV camera picker from the store
The picker's options are data: CctvControls computes the cameras in view
and the closing note for those left out, keeps a focused picker's list and
prepends a camera activated under it, and publishes the options, disabled
state and selection. CctvPicker renders them keyed by camera id and
applies the selection once the options are in place; it updates only when
the controls publish, as the old picker did on layer notifications. A
picker about to be disabled no longer counts as focused.

This completes the CCTV panel: everything it shows is rendered from the
gev-cctv store.
2026-10-30 22:05:41 -07:00
Sameh Khamis eef3dec759 feat(ui): render the CCTV frame preview, source badge and summary from the store
The frame lifecycle keeps its request state in an object instead of the
image's dataset and publishes it; the panel binds the image's src, class
and data attributes and the wrapper's loading and has-frame classes from
it, so preload tokens, kept pixels on a failed refresh and clearing on a
camera change are unchanged. The source badge is the pure
presentCctvSourceBadge(), the live switch and the typed summary are
published too. The video surface still draws into the panel's canvas.
2026-10-30 21:54:42 -07:00
Sameh Khamis 6c7035f617 feat(ui): render the CCTV calibration readout and its pose editor from the store
presentCctvCalibration() joins the panel view: ADJUST, SAVE CAL, RESET CAL
and the seven pose chips render from the gev-cctv store. The inline editor
is store state: starting an edit publishes its field, starting value and
finish(), and the CctvCalValue chip renders the number input. The draft is
set once on mount so a refresh while typing keeps it; each edit gets its
own input. Commit and cancel rules, the captured base pose and the camera
guards stay with CctvControls.

formField.js had no other user and is removed.
2026-10-30 21:45:24 -07:00
Sameh Khamis 5b8cb40fce feat(ui): render the CCTV panel's buttons, CAL chip and meta line from a store
CctvControls presents the switch, navigation and toggle buttons, the CAL
chip and the meta line with a pure presentCctvPanel() and publishes them
to the gev-cctv store; CctvPanel renders them. The controls keep their
listeners on the same elements, and still write the picker, frame, source
badge, calibration readout and summary, which carry no bindings.

A page that imports ui/cctv with its own markup no longer has these
elements painted for it, as with Street Level.
2026-10-30 20:57:03 -07:00
Sameh Khamis e6aee52ea0 feat(ui): render the Street Level panel from a store
The panel's markup moves, verbatim, into StreetLevelPanel, which renders
the presentation StreetLevelControls publishes to the gev-street-level
store, with the EXPAND state. The controls keep their listeners, full
screen and popover handling, focus moves, resizing and transitions. The
SINCE readout follows the thumb while dragging and shows the recorded
window once the thumb is there; the thumb never moves under the user's
hand. Text the panel now renders itself drops its data-i18n markers.
Panels lifted out of a view live in src/ui/views/panels/, kept out of
Prettier like the views.
2026-10-30 20:43:42 -07:00
Sameh Khamis 3a2acf9b0f test: compare DOM nodes by identity, never through assert.equal
A failed assert.equal or deepEqual prints both operands, and a happy-dom
node reaches the whole page and window: printing one exhausted memory and
took the machine down. assertSameNode() compares identity and fails with
a short description of each node; every node comparison in the happy-dom
tests uses it.
2026-10-30 20:38:29 -07:00
Sameh Khamis e949584c0a feat(ui): render the Recent imagery readout as components
createRecentImageryPanel() computes the readout from the layer snapshot
and renders RecentImageryReadout and its day cards synchronously; its
delegated listeners stay on the stable root and the mode buttons keep their
segmented control. Rail card actions take optional pressed and reserved
states, replacing the owner's patches after render. Thumbnails, focus,
scroll preservation, the DETAILS reveal and export behave as before, and
nothing paints after teardown.
2026-10-30 18:58:32 -07:00
Sameh Khamis a318376203 feat(ui): render the Weather readout as one component
createWeatherPanel() computes the readout it shows (forecast and event
cards, the observed group's scope, the history timeline state and observed
cards) and renders WeatherReadout synchronously into the panel body, so a
newly opened card is still revealed after measuring. The hand-built hosts
and the separate card and timeline builders are gone; markup, open-card
choice, first appearance and teardown are unchanged.
2026-10-30 18:48:46 -07:00
Sameh Khamis ce6040bde1 feat(ui): render the rail timeline as a component behind its builder
The observed-history transport is RailTimeline in src/ui/rail/, rendered
by createRailTimeline() with the same update and destroy API. Drag preview,
the coalesced 150 ms commit, release, cancel and blur behave as before; the
slider keeps the ticks it is dragged over, an update from inside a preview
cannot move the handle back, and readouts follow the handle within the same
task. utcClock moves to its own module and is still exported here.
2026-10-30 18:41:31 -07:00
Sameh Khamis dcecf5c34c feat(ui): render rail cards and card blocks as components behind their builders
The rail cards, card blocks, settings, chips and row lists are Vue
components in src/ui/rail/. createRailCards() and createRailCardBlocks()
keep their update and destroy API and patch the components synchronously
with render(), so Weather and Recent imagery are unchanged. Controls of a
removed block dispatch nothing, a released range keeps its value until the
owner's next update, and range values are written only when they differ.
Weather's remount state is keyed by its panel. Tests of rendered parts run
on happy-dom.
2026-10-30 18:36:01 -07:00
Sameh Khamis d9fdcfc641 feat(ui): render the Scene panel's shot list and scene options as components
SceneShotList and SceneOptions render the project from a gev-scenes
store instead of scenePresentation building rows with createElement.
SceneControls stays the owner: it publishes the director's state and
attaches the row actions, and a late destroy cannot detach a newer
owner. Rows keep their identity across selection; a rename keeps its
typed text across republishing and ends with its row. The select still
changes its choice only when its options are rendered.

Vue keeps whitespace in every component, so Prettier formats single-file
components with strict whitespace sensitivity, and the test loader parses
templates with the same options as the browser build. The i18n check
reads view text without its interpolations, whose t() calls are scanned
with the sources.
2026-10-30 18:13:11 -07:00
Sameh Khamis 6802c9c8b0 feat(ui): render every application template except the loading screen as a Vue view
The scene chrome, cockpit, Display controls, command dock, layer panels,
Context rail, welcome card and Provider Settings move verbatim into
src/ui/views and mount into their hosts before the page is translated and
wired. Each view renders the same elements, attributes and text as its
template; Vue keeps whitespace between elements as one space, and no view
markup sits under a white-space: pre rule.

Template asset URLs stay literal, view files are left out of Prettier so
the markup is not reflowed, and the Node component loader moves to build/
and is exported as build/register-vue for host test runners. Hosts that do
not initialize Core's locale pass localePicker: false instead of editing
the markup.
2026-10-30 17:47:52 -07:00
Sameh Khamis 9d24945143 feat(ui): render application templates as Vue views mounted before wiring
Templates listed in build/applicationViews.js expand to mount hosts, and
mountApplicationViews() renders them before translation and wiring. Markup
tests read the page through a server-side render helper, the i18n scanner
reads view templates, and Vue preserves whitespace so views keep the exact
DOM. No template is converted yet.
2026-10-30 17:23:45 -07:00
Sameh Khamis b7e7058a5c test: compile option-API components and report template errors in the Vue test loader 2026-10-30 16:41:29 -07:00
Sameh Khamis 3d5d3ef014 feat(ui): add a desktop panel rail to each sidebar
Each side stack hosts a Vue rail listing its panels; selecting one opens it
through PanelChrome. The shell owns one Vue runtime and Pinia instance, and a
panel store mirrors each side's panels from the DOM. The rail hides with its
stack, in Cockpit, clean view and recording, and on phones. Panels without a
catalog entry get a generic item, and Data Layers leaves the rail while the
f shortcut hides it.
2026-10-30 16:41:29 -07:00
Sameh Khamis eed7657516 fix(ui): let revealed panels own their side and keep Cockpit's left strip
A panel a feature opens (Street Level's viewer, a selected radio station)
now becomes its side's open panel instead of being collapsed again by the
next layout pass. Cockpit keeps showing its collapsed Data Layers strip,
which Cyber's Cockpit layout aligns to, and Cyber's focus layout no longer
re-shows collapsed left panels. Both sidebars share one accordion helper.
2026-10-30 16:41:29 -07:00
Sameh Khamis 2035c767ce feat(ui): keep one side panel open per desktop sidebar in every HUD layout
The Cyber accordion now applies to both sidebars and every HUD layout:
opening a side panel collapses its peers, the layout normalizes restored
state to one owner, and collapsed panels are hidden on desktop. Phones keep
showing several panels per sheet.
2026-10-30 16:28:08 -07:00
Sameh Khamis 7307c11c74 feat(ui): add the Vue component kit with UiRail, UiTooltip and UiIcon 2026-10-30 16:11:48 -07:00
Sameh Khamis c13c487dcf build: add Vue and Pinia to the browser build and unit tests 2026-10-30 16:07:44 -07:00
Sameh Khamis 6d6df9d83b docs: plan the Vue migration and the panel rail 2026-10-30 16:03:44 -07:00
Sameh Khamis 2640f6378c Add the changelog entry for the CCTV view thinning 2026-10-29 21:32:45 -07:00
Sameh Khamis 93942d0dbe Show only the CCTV cameras in view, thinned to one per ground cell when zoomed out
The CCTV layer kept every loaded camera live: each view change touched every
icon, every notification rebuilt every camera's state, and the picker listed
the whole catalog. With the default 4,000 cameras, a continental drag ran at
152-179 fps with 18-24 frames over 30 ms (worst 112 ms). It now runs at
235 fps with none. The layer now:

- shows icons only on or near the screen, and when zoomed out keeps one camera
  per world-anchored cell (healthy feeds first), so panning keeps the same
  cameras;
- grounds and draws coverage only for the cameras in view, the active camera
  and its coverage neighbours, retrying a camera at most twice per view regime;
- reruns the view pass while the camera moves, paced by its own cost, and
  projects with one matrix per pass instead of a Cesium call per camera;
- keeps the billboard buffer-usage hint fixed, so showing or hiding a few
  icons no longer rewrites the vertex data of every billboard;
- lists the cameras in view (active camera first) in the picker, closing with
  the count of cameras outside the view, and builds the full camera list in
  the UI state only when it is read.
2026-10-29 21:31:59 -07:00
Sameh Khamis 391dba74eb Add the changelog entry 2026-10-28 22:36:18 -07:00
Sameh Khamis f69e9bba8b Update Vite and Puppeteer, and remove the unused screenshot helper 2026-10-28 22:35:08 -07:00
Sameh Khamis d1e0ff4e06 Name the HUD lookups changelog entry after its pull request 2026-10-28 17:09:50 -07:00
Sameh Khamis c1f60cb7e7 Cut the Google requests the HUD summary makes on its own
The HUD builds place context for its AI summary whenever the camera
settles, and each build paid for up to four reverse geocodes plus a Nearby
Places search, even when no OpenAI key was configured to use them.

- Ask GET /api/openai/hud-summary/status once; with no summary configured,
  or after an unconfigured reply, make no place lookups for the page.
- Reverse-geocode at most two points: the view center and one viewport
  point.
- Reuse a lookup until the view center moves a quarter of the visible
  width, the camera's distance to it doubles or halves, or the camera
  crosses a lookup height. The reused points are asked again, so only a
  timeout, failure or empty answer spends.
- Repaint the last AI reply when a small pan leaves the context unchanged.

Cached-only hosts and voice context lookups are unchanged.
2026-10-28 14:59:33 -07:00
Sameh Khamis 237684ba86 chore(release): prepare v0.3.0 2026-10-27 22:08:29 -07:00
Sameh Khamis c533b1994c Merge main and preserve voice panel and GhostMaps schema coverage 2026-10-26 08:52:03 -07:00
Sameh Khamis ddbcd2053b fix(voice): preserve idle evidence through recoverable response errors 2026-10-26 08:47:54 -07:00
Sameh Khamis 074e272356 fix(voice): recover idle timers and retire panel audio observers 2026-10-26 08:42:41 -07:00
Sameh Khamis aeee3652ce Merge PR #1299 with current main for validation 2026-10-26 08:39:16 -07:00
Sameh Khamis 292a7a9d08 Merge main into PR #948 2026-10-25 18:53:39 -07:00
Sameh Khamis 1663733b58 style: format Vite deny-list test imports 2026-10-25 18:49:31 -07:00
Sameh Khamis 0dce2f8d04 fix: complete PR #948 integration and documentation 2026-10-25 18:47:57 -07:00
Sameh Khamis 80449af6bd Merge main into PR #948 2026-10-25 18:47:57 -07:00
Sameh Khamis 3a28dcab07 fix(docker): align health probe port parsing and document health status 2026-10-25 17:32:15 -07:00
Sameh Khamis e03e58135d Merge main into PR #1394 2026-10-25 17:32:15 -07:00
Sameh Khamis a07b5a65fd Merge current public main with PR #1232 2026-10-25 16:40:20 -07:00
Sameh Khamis f4b3517e9b Merge main into PR #1390 2026-10-25 16:15:38 -07:00
Sameh Khamis 9b52e83fd7 Merge main into PR #1395 2026-10-25 14:14:33 -07:00
Sameh Khamis 1ad472fecf fix(awareness): register and document bearing presentation 2026-10-25 14:08:32 -07:00
Sameh Khamis 6642176de5 docs: document Local ADS-B track rounding 2026-10-25 14:08:32 -07:00
Sameh Khamis 3de745bd33 fix(fires): reject rolled-over acquisition dates and document UTC times 2026-10-25 14:08:25 -07:00
Sameh Khamis d987149f17 Merge PR #1390 contribution for review 2026-10-25 14:07:14 -07:00
Sameh Khamis 9aeeb37ccf Merge PR #1396 contribution for review 2026-10-25 14:07:13 -07:00
Sameh Khamis 5ae18032fc Merge PR #1395 contribution for review 2026-10-25 14:07:10 -07:00
Sameh Khamis e6e8bb0e95 Merge main into PR #1389 2026-10-25 12:26:21 -07:00
Sameh Khamis 8f02541657 docs: document PR #1389 rounding behavior 2026-10-25 12:11:49 -07:00
Sameh Khamis 1244ec1332 Merge PR #1389 contribution for review 2026-10-25 12:11:49 -07:00
Sameh Khamis 6ebdee6710 docs: document PR #1388 rounding behavior 2026-10-25 12:11:19 -07:00
Sameh Khamis 1031569f47 Merge PR #1388 contribution for review 2026-10-25 12:11:19 -07:00
Sameh Khamis ba783b4eea Merge main into PR #1387 2026-10-25 09:01:32 -07:00
Sameh Khamis 3cd795527c Merge main into PR #1386 2026-10-25 08:55:23 -07:00
Sameh Khamis 48e649a95e docs(directions): scope the distance rounding threshold precisely 2026-10-25 08:50:11 -07:00
Sameh Khamis 455dbf2b5f docs: clarify unit transition examples 2026-10-25 08:49:00 -07:00
Sameh Khamis 4d64ac48bc docs: clarify unit transition examples 2026-10-25 08:48:58 -07:00
Sameh Khamis c30d2d3473 docs: document PR #1387 rounding behavior 2026-10-25 08:48:37 -07:00
Sameh Khamis d8d3ac85b6 Merge PR #1387 contribution for review 2026-10-25 08:48:36 -07:00
Sameh Khamis d6ae581652 docs: document PR #1386 rounding behavior 2026-10-25 08:48:30 -07:00
Sameh Khamis 5c8d371552 Merge PR #1386 contribution for review 2026-10-25 08:48:29 -07:00
Sameh Khamis be869f9160 docs: document PR #1385 rounding behavior 2026-10-25 08:48:22 -07:00
Sameh Khamis 9d07e67cf8 Merge PR #1385 contribution for review 2026-10-25 08:48:22 -07:00
Sameh Khamis ad79e57028 Merge main into PR #1207 2026-10-25 08:14:59 -07:00
Sameh Khamis 1a72da81b5 docs(voice): document stable entity labels and localized presentation 2026-10-25 07:54:47 -07:00
Sameh Khamis dae03f9a11 Merge PR #1207 with current main 2026-10-25 07:54:46 -07:00
Sameh Khamis 75eaa56c15 Merge remote-tracking branch 'origin/main' into perf/aircraft-label-candidates 2026-10-24 23:42:23 -07:00
Sameh Khamis d53d68b7cf docs: record aircraft candidate processing improvement 2026-10-24 23:36:58 -07:00
Sameh Khamis e7cf071a1c Merge remote-tracking branch 'origin/main' into perf/aircraft-label-candidates 2026-10-24 23:36:30 -07:00
Sameh Khamis 45a093fb42 perf(flights): reuse resolved models in detection queries 2026-10-24 23:36:30 -07:00
Sameh Khamis 7cdaa6044b perf(flights): cache unchanged detection label text 2026-10-24 23:36:30 -07:00
Sameh Khamis 5d21beed9a Merge main into PR #1326 2026-10-24 23:21:10 -07:00
Sameh Khamis 29db102f59 docs: document PR #1326 behavior 2026-10-24 23:14:56 -07:00
Sameh Khamis 134505f716 Merge PR #1326 with current main 2026-10-24 23:14:55 -07:00
Sameh Khamis 04b6a99a30 docs: document PR #1349 behavior 2026-10-24 23:14:52 -07:00