Skip to Content
Updates

Updates

What changed in the application recently, what each change was for, and what has explicitly not been done yet.

Rebranded to IndicaView, and repositioned as a hosted service

The product was renamed to IndicaView and repositioned. It is a hosted SaaS web application: nothing to install, nothing to self-host.

What changed in the product and in these docs:

BeforeNow
Namethe previous working nameIndicaView
Delivery“runs on your machine”, “local-first”hosted — the browser application is served as static files
Cost“free to use”usage metered in credits — no plan, price or credit cost decided yet
Accountsoptional, manages a profileoptional; adds a profile and a security tab, and is where a credit balance and billing details will live once metering is switched on
Source repositoryadvertised in the landing page’s SoftwareSourceCode schemaremoved — a commercial hosted product does not advertise a source repo

Nothing about billing, checkout, plans or credit consumption is implemented. What exists is the seam: a canonical product/commercial configuration (app/js/brand/product-config.js), a credit-balance accessor (app/js/commercial/credits.js) that reports “unavailable” rather than inventing a number, and reserved (nullable, unpopulated) credit columns on the account profile. See Commercial model — or, in the repository, docs/commercial-model.md.

The retired name and the retired positioning have been removed from every user-facing surface, and scripts/check-product-config.cjs fails the build if either comes back.

Four substantial features

The largest changes since this documentation was last written. Each has its own page.

FeaturePageOne line
Supabase sign-in and My AccountAuthenticationOptional; guests keep the entire workspace
NSGA-IIAlgorithmsA seventh, multi-objective optimizer
Shareable result cardSharing & exportA 2160 × 3840 PNG rendered client-side
Responsive / mobile layoutMobileA phone layout below 768 px

Authentication

Optional Supabase sign-in integrated directly into the static workspace, plus a My Account area with Profile and Security tabs. Email and password only; no OAuth, no MFA, no account deletion.

The important design point is that a single constant decides whether sign-in is required, and the default is 'optional' — guests reach the chart, the optimizer and the analysis without an account, and a missing or unreachable auth backend degrades to that state rather than breaking.

Profile data is protected by row-level security rather than by the routing flag. Details, the RLS model and the unverified email-delivery path are in Authentication.

NSGA-II

A seventh optimizer, for when two objectives genuinely conflict — profit against drawdown, say. Trials become vectors rather than scalars, and the population is sorted into Pareto fronts.

It ships alongside GA rather than replacing it, and shares GA’s operators and non-dominated sort. A follow-up commit closed four correctness and honesty defects, and forced the legacy contract back on the new code so the two algorithms stay comparable.

Result-card export

A client-rendered PNG summarising an optimizer run — drawn with canvas, at 2160 × 3840, with no network request. Your Pine source and the winning parameter values are excluded by a whitelist rather than a blacklist.

It is reachable from the optimizer results, the Analysis toolbar and the detached window — though on desktop the results control now lives in a kebab rather than on the toolbar. See Sharing & export.

Responsive layout

A phone layout below 768 px, built as a phone-first enhancement rather than a desktop reduction: a two-tab pane switcher, bottom sheets replacing selects and dropdowns, kebab menus replacing button groups, measured column pins, and 44 px touch targets achieved by growing hit areas rather than painted boxes.

Most of the recorded before/after numbers exist because the first attempt looked plausible in code and was visibly wrong on a device. See Mobile.

Supporting changes

  • Visual language — drawdown redrawn throughout, the Run control reduced to a play glyph and one word, and an Apple-style sign-in treatment.
  • New in-repo docs — docs/authentication.md, docs/SHARE_CARD.md and docs/mobile-ux-audit.md. All three are more detailed than this site; two of them are themselves slightly stale, and this site records where.
  • A smoke aggregate runner — scripts/run-smokes.cjs, which times out per file and records TIMEOUT rather than skipping quietly.
  • Auth test suites — a unit tier and a Playwright tier, both against mocked Supabase HTTP.
  • RLS migrations under supabase/migrations/, with rollback-only SQL checks under tests/auth/.

Where the documentation itself disagrees

Worth knowing before you trust any internal design note:

  • Three files under docs/ are ported upstream reports from a different host toolchain. They describe an astra.cmd harness and a chart backend this repository no longer uses. Treat them as provenance, not as current state.
  • The repository’s own README.md and docs/architecture.md describe an earlier phase of the application. Where they conflict with this site or with the code, the code is right.
  • One consequence you can verify yourself: the charting library was swapped from ApexCharts to Apache ECharts 6.1.0 in 790cfbb, because ApexCharts requires an OEM licence once embedded in a third-party product. Any note still describing ApexCharts is stale.
  • docs/SHARE_CARD.md is close but has drifted in three places: it says the result card hands the file to the OS share sheet on a phone (that path is unreachable), it shows the desktop control as a visible button (it is now in a kebab), and it describes the footer as configuration-driven (that one string is hardcoded).

Recent changes

Grouped by theme rather than by date.

Optimizer ownership and data contracts

The optimizer was progressively moved from a detached results window onto an in-workspace surface, while the canonical data layer was kept intact.

ChangeWhat it didCommit
Ownership handoverMoved 45 canonical-only controls into the new workspace shell. Deliberately kept two canonical capabilities the upstream shell lacked: the algorithm selector (upstream ships 5 methods, canonical ships 7) and the absolute maxDrawdown sort option3e179d4
Ownership regression guardAdded a browser-free static check that parses the page and asserts no duplicate ids and exactly one owner per opt-* id. It also corrected an inventory error in the process — an id that had been counted as canonical-only is in fact shared0130ad0
Load Params + snapshot producerAdded applyValues() and a snapshot event, writing through the editor’s own controls so the change listener rebuilds the override map. Refuses while a run is active757bf95
Results table presentationSwapped in the upstream table while keeping canonical’s data layer. Trial identity is preserved: sorting and filtering return the same trial objects wrapped with their original index, never cloned or renumbered559af7e
Analysis workspace activatedBrought the analysis surface up on canonical snapshots, merging back five canonical contracts including honest total/truncated trial reporting and detail-on-demandce260f2
Live results and run controlsConnected real runs to the UI. Verified with a real TPE run reaching finished with the correct row count, plus real SA and GA runs through the same boundary41a6651
The pattern behind these commits

The recurring discipline is that the two halves are merged, not that one side is rebuilt around the other. The upstream presentation was adopted; canonical behaviours were merged into it. Every externally consumed API survived the swap.

That is why a change like “bring in the upstream table” is a large-looking commit that is actually low-risk: the data contract is unchanged, and there is a static guard asserting that the DOM has exactly one owner per id.

Correctness fixes

ChangeWhat it didCommit
Trial identity preservedFlipped trial identity from array position to canonical run index, so selection survives sorting and filtering270f718
Chart load order + chart dependenciesMoved the chart library <script> into <head> ahead of the editor’s loader, and restored a status-marker structure that the ownership handover had flattened399745a
Series styling mergeA series override was replacing the whole series array and silently dropping 40 drawdown points. Styling now merges by indexab6bb01
Stepped progressionA step set on the wrong object was a no-op, so the best-so-far curve rendered as a plain line. Found by pixel-diffing a rendered canvas, not by inspecting the optionfafdd60
Canvas-safe labelsHeatmap cell labels were emitted as HTML, which a canvas renderer does not parse. A formatter left bound to a categorical axis rendered every year as a dash0df5d39
Navigation and responsive shellMarket controls pushed the run button off-screen at narrow widths; controls are now wrapped in a scroller, and a snapshot fast path left a view blank when toggled repeatedly2da0bd5
The transferable lesson from the chart fixes

Three of these chart bugs produced no error. The chart rendered, it just rendered wrongly — a missing step, missing points, wrong labels.

They were caught by asserting on rendered output (pixel counts from a real canvas), not by asserting that the option object was well-formed. The option object was well-formed in every one of these cases; it was being applied to the wrong place.

Tooling and documentation

ChangeWhat it didCommit
Support files ported unwiredPresentation stylesheets, browser smoke suites and UI baselines landed ahead of the wiring that would use them589de7d, 73528d8, 686e603, 65b3a88
Documentation siteThis site892a179

Phase F

Phase F is the most recent delivery sequence, and it is unusually well documented because each commit carries a detailed body.

StepWhat it delivered
F1Mounted and drove the backtest presentation. It was inert by construction, not merely unwired: the five chart host elements did not exist, and the height function threw before its own null guard, aborting the rest of the animation frame
F2Connected the in-page analysis detail request path. The analysis surface could already ask for a trial’s detail; the coordinator that computes it existed; nothing in between did, so every in-page request failed
F3Made the chart follow the application theme. It had been pinned to dark at construction, so light mode left a dark chart in a light workspace
F4Added a light editor theme and made the editor follow the application theme, carrying the same token rules with light-appropriate values rather than inventing a second palette
F5Removed superseded wiring — mostly a list of what it refused to remove, and why
F6Added the browser smoke for the whole sequence
F1's ownership rule, and why it was the whole point

The five chart hosts are created as siblings of the tab panels that the application rewrites via innerHTML on every run.

A host placed inside a panel would be destroyed the next time a backtest ran. That single decision is why the application code never has to write presentation markup, and it is the reason F1 was safe to land as a staged change.

F5's refusals are the interesting part

F5 removed one unreachable click binding. The commit body is mostly a list of what was deliberately retained, each with a reason:

  • The detached window’s open function and its call sites — the detached surface is not yet owned by the replacement; retiring it is a decision for review, not for this phase.
  • The detached page and its window manager, for the same reason.
  • The export bindings — live, and part of a frozen contract.
  • Sidebar persistence and the divider-resize handler.

It also records a test bug worth noting: the smoke assertion matched the function definition as well as the call, so it would have failed even after the correct removal. It now matches the binding specifically.


The optimizer redesign

The redesign was a presentation and control-surface change, explicitly not an engine change. Engine algorithms, scoring, metric calculation, search-space rules, Pine sources, market-data behaviour, database names and database version were all left alone — and the engine-versus-synthetic distinction between real and reconstructed results was preserved throughout.

The shipped architecture is a deliberate four-way split:

LayerOwner
Data and lifecyclethe canonical controller
Presentationthe workspace, results table and analysis modules
DOM ownership~90 ids, one owner each, statically guarded
Application bridgesa handful of calls; no presentation markup
The parallel evaluation decision, which reversed itself

Parallel evaluation was first rejected on measurement — a benchmark showed the pool running at 2–11 % of sequential speed — and then implemented, because the benchmark was broken rather than the system.

The cause: the benchmark passed the wrong field names, so the Pine engine received no source at all and every trial failed in ~0.2 ms without doing work. The benchmark now refuses to report timings when nothing reached the engine.

Corrected numbers, at the application’s default depth: 518 ms per trial, break-even at roughly 13 trials, best observed speedup 3.33×. Details and the invariants that keep batched runs identical to serial ones are in Execution.

The redesign document closes by superseding itself and pointing at the analysis implementation notes, so treat it as a historical record of a decision rather than current behaviour.


What is in flight

Everything here is a real, sourced “not done”.

Explicitly deferred

  • Live email delivery is unverified. Signup acceptance, confirmation, reset and a real authenticated browser save/reload have not been confirmed end to end. Dashboard redirects, email templates and SMTP are manual steps no tooling can check.
  • The NSGA-II Pareto archive is never consumed. The search maintains it; only the current generation’s front is displayed.
  • The result card’s OS share path is unreachable. The code exists and the UI never passes the option it needs, so every path ends at Download PNG. There is also no copy-to-clipboard.
  • No mobile smoke test. Every responsive claim rests on manual measurement in Chrome device emulation; safe-area insets, non-Chromium engines and real devices are untested.
  • Live market integration and Python hyperopt are deferred. The Python optimiser work was neither run nor repaired as part of this sequence.
  • Walk-forward / out-of-sample validation is a later phase. Until it exists, every sweep result is a candidate, not a validated edge. Extending to prop-firm simulation does not fix this — in-sample variance is still in-sample.
  • Zero-copy worker transport is designed and disabled; it needs headers a plain static deployment cannot set.
  • Multi-asset support is blocked: adding a field to the market descriptor activates a module-level, order-populated cache inside the vendor bundle.

Superseded conclusions

  • “Parallel evaluation is not worth it” — retracted. The correct statement is 3.33× at the default depth, gated by depth.
  • The detached optimiser-results window — superseded by the in-workspace analysis surface. Legacy links redirect.
  • ApexCharts — superseded by ECharts in this repository.

Retained but unowned

The detached window surface and its page are still present and still openable, but are explicitly not yet owned by the replacement. Retiring them is an open decision, not a pending task.

Verification gaps

  • The browser smoke skips rather than fails when its automation dependency is missing.
  • The end-to-end run-to-charts assertion was explicitly deferred out of the step that would naturally have covered it.
  • Five seeded browser trials cover startup sampling — not mature convergence, and not every algorithm or strategy. No large stress run has been performed in the browser.
  • Storage-quota exhaustion and delayed-write ordering were tested with controlled adapters, not by exhausting real storage.
  • No screen-reader session, no physical touch-device test, no blocked-popup test, and no exhaustive malformed-record test. Narrow-layout checks used desktop viewport emulation.
Two things that are broken, not merely stale

Both are in the test tree and are worth a small fix pass before they get quoted anywhere:

  • One smoke file’s header comment still carries the pre-correction id counts, while its own assertions carry the corrected ones. A reader who trusts the comment will state the wrong numbers.
  • Another smoke file’s header says a module “is deliberately not migrated yet” — which stopped being true when that migration landed. The block is written to self-disable, so it is inert rather than broken, but the comment is now misleading.

Next

Last updated on