Skip to content

Create LICENSE.md#9

Merged
frstrtr merged 1 commit intoorigin/sharechain/async_threadfrom
add-license-1
Aug 20, 2021
Merged

Create LICENSE.md#9
frstrtr merged 1 commit intoorigin/sharechain/async_threadfrom
add-license-1

Conversation

@frstrtr
Copy link
Copy Markdown
Owner

@frstrtr frstrtr commented Aug 20, 2021

No description provided.

@frstrtr frstrtr merged commit d3dd31c into origin/sharechain/async_thread Aug 20, 2021
frstrtr added a commit that referenced this pull request Apr 20, 2026
Introduces a parallel test surface — dashboard-bundled.html — that
wires the extracted Realtime orchestrator against a live c2pool
server via HttpTransport. Operators run it alongside the untouched
production dashboard.html in a second tab to visually A/B the
bundled pipeline against the inline renderer. Production
dashboard.html stays unchanged until parity is verified —
spec §11 / plugin-arch §16 migration discipline.

Deliberately *not* modifying dashboard.html this commit. Swapping
the inline renderer with a <script type="module"> bundle import
is a later commit gated by a query-string feature flag for
safe rollout.

dashboard-bundled.html (~75 LOC)

- Minimal CSP-compliant shell (same policy as the demo page).
- Header inputs: base URL (defaults http://127.0.0.1:8080) and
  "my address" (optional, for mine-variant colouring).
- Connect / disconnect / refresh buttons.
- Live status pill + stats line (share count, tip-short, animation
  state, queue state, fetch state).
- Rolling 8 KB log pane for structured ExplorerError / info events.
- Canvas filling the grid wrap; RAF-driven paint via createRealtime.

dashboard-bundled.mjs (~100 LOC)

- Imports createHttpTransport + createRealtime from dist/.
- URL params: ?base= / ?addr= / ?autoconnect=0 / ?fast=1.
- Persists {base, myAddress} in localStorage under
  'c2p-bundled-prefs' so reconnect-on-reload is typing-free.
- onError handler maps ExplorerError.{type,status,message} into
  the log pane without leaking internal context.
- 250 ms stats-loop updates the header stats from
  RealtimeController.getState() — gives operators live visibility
  into the state machine.
- Exposes window.__explorer = RealtimeController for devtools
  poking (getState, refresh, etc.).
- beforeunload hooks stop() so SSE subscriptions + RAF are
  cleanly torn down when the tab closes.

README.md (~95 LOC)

First top-level README for the module. Documents:
- Directory layout + npm scripts
- Three surfaces: demo.html (synthetic) / dashboard-bundled.html
  (live A/B) / dashboard.html (untouched production).
- Pointer to the eight-doc design baseline in frstrtr/the.
- Bundle-size numbers + current Phase A/B status.
- Instructions for live A/B testing (serve with python -m
  http.server or c2pool's HTTP server, open both pages in
  parallel tabs).

Status

- No source/test changes — verify remains 166/166 green.
- Bundles unchanged: shared-core 25.1 KB / 40, sharechain-explorer
  42.0 KB / 120.
- dashboard-bundled.html now loads the bundle via
  <script type="module" src="./dashboard-bundled.mjs"> and Just
  Works against any c2pool instance exposing the spec §5 endpoints.

Next: either Phase B #9 — wire the bundle into dashboard.html
behind a ?new-explorer=1 feature flag (final M2 step; removes
the inline defrag once pixel-diff confirms parity), or Phase B
#10 particles + card overlays, or Qt refactor step 1 (CMake deps).
frstrtr added a commit that referenced this pull request Apr 20, 2026
… flag

Wires the extracted @c2pool/sharechain-explorer bundle into the
production dashboard, OFF by default. Operators opt in per-tab with
?new-explorer=1 (or persistently via localStorage.c2p_new_explorer=1).
Zero byte / behaviour change for default users — the bundle script
is dynamically imported only inside the flag-on branch, so the CSP
and network footprint of the inline path are unchanged.

Closes M2 mechanical extraction per the Explorer spec §11 / plugin-
arch doc §16.2 migration flag. Pixel-diff CI against an
`explorer-baseline-v0` tag becomes meaningful after this commit
lands: operators can toggle the flag inside the same browser
(identical DPR / fonts / CSS) and compare the two paths rigorously.

Two surgical edits to dashboard.html (75 insertions, no deletions):

1) Flag check + defrag disarm (just after the inline `defrag`
   object definition, before defrag.init()):

   - Resolves the flag from URLSearchParams then localStorage with
     a narrow try/catch per source so older browsers without
     URLSearchParams gracefully fall through.
   - When ON: walks defrag's own keys, replaces every function-
     valued entry with a no-op. This disarms init(), render(),
     load(), _animate3D(), toggleRealTime(), showZoom(), and any
     other method the RealTime toggle / auto-refresh timer /
     inline handlers might call — so the bundled renderer owns
     the canvas unambiguously.
   - Logs a clear `console.info` so devtools shows which path
     is active.

2) Bundled bootstrap script (just before </body>):

   - `<script type="module">` with `import('./sharechain-explorer/
     dist/sharechain-explorer.js')`. Dynamic import so the bundle
     is fetched only when the flag is set.
   - createHttpTransport({ baseUrl: '..' }) matches dashboard.html's
     existing relative-path convention (d3.json('../current_merged_
     payouts', ...) at :2517 / :4064).
   - createRealtime wires canvas + containerWidth against the
     existing #defrag-canvas + its wrap. userContext pulls my-
     address from window.currency_info where available.
   - onError callback routes structured ExplorerError to console.
   - Hides #defrag-loading when mount succeeds.
   - Exposes window.__explorerBundled = RealtimeController for
     devtools poking (.getState(), .refresh(), etc.).

Known limitations in flag-on mode (documented in the inline comment
near the flag block and in README.md):

- Right-hand stats panel (#defrag-total, #defrag-chain-len, etc.)
  stays at "-". Bundled Realtime does not yet update these
  elements — Phase B #10 wires stat emission.
- RealTime toggle button does nothing (bundled is always live).
  The inline toggle calls a disarmed no-op.
- Hover-zoom + per-share PPLNS treemap not yet ported.

None of these affect the default path — operators without the flag
see the existing dashboard verbatim.

Safety posture:

- dashboard.html on branch explorer-module, not master. No
  production pool is affected until the branch is merged.
- Flag is default OFF; even after merge, zero behaviour change
  unless an operator deliberately opts in.
- Can be reverted to the pre-flag state with one `git revert` if
  the bundled path exhibits regressions in the wild.

Status

- 166/166 tests pass in 2.2s — no test-surface changes.
- Bundles unchanged: shared-core 25.1 KB / 40 KB, sharechain-
  explorer 42.0 KB / 120 KB.
- curl smoke test confirms dashboard.html still serves (200 OK,
  411 KB) and the bundle is reachable from the relative path.

Next: Phase B #10 particles + card overlays to close cosmetic
parity, or wire stat-panel emission into Realtime so flag-on mode
matches the inline stats output, or Qt refactor step 1 (CMake
deps + option flags).
frstrtr added a commit that referenced this pull request Apr 20, 2026
Closes the most visible limitation of ?new-explorer=1 (Phase B #9):
operators enabling the flag no longer see dashes across the stats
panel. Parity with the inline renderer's stat counters achieved
except for minor #defrag-blocks formatting (coin-name still
hardcoded "LTC / DOGE"; generic merged-chain labelling arrives with
CoinDescriptor consumption per M1 D5).

src/explorer/delta.ts

- WindowSnapshot<S> gains three optional metadata fields:
    chainLength, primaryBlocks, dogeBlocks
  All typed explicitly as `T | undefined` so
  exactOptionalPropertyTypes stays satisfied.

src/explorer/realtime.ts

- New type RealtimeStats: shares, chainLength, verified, mine,
  stale, dead, fee, v36native, v36signaling, primaryBlocks,
  dogeBlocks.
- RealtimeState.stats surfaced through getState(), lazy-computed
  by currentStats() and cached per lastAppliedTip so repeated
  polls on the same tip are O(1). Cache invalidated on rebuild +
  on applyDelta.
- extractMeta() helper pulls chain_length + blocks + doge_blocks
  from raw /sharechain/window and /sharechain/delta payloads (spec
  §5.1 + §5.3). Only-defined-fields return keeps
  exactOptionalPropertyTypes happy across the spread patterns.
- rebuildWindow + applyDelta populate the new meta fields from the
  raw response; applyDelta preserves previous meta fields across
  deltas that don't carry them.
- Classification thresholds use ctx.shareVersion so a Dash V16 host
  reports v36native / v36signaling counts against 16 — the field
  names are legacy from dashboard.html; semantics are coin-agnostic.

src/explorer/index.ts

- Re-exports RealtimeStats.

tests/unit/realtime-stats.test.ts (10 tests)

- Empty window → all-zero stats.
- Priority order: dead(2) / stale(1) / unverified / fee / verified.
- Mine counting against myAddress; empty myAddress always 0.
- v36native vs v36signaling branches including boundary V===36 +
  V===37 native counting.
- Dash V16 threshold demonstrates coin-agnostic behaviour.
- chain_length + blocks + doge_blocks passthrough from payload.
- Cache identity: same tip → same object reference (===).
- Cache invalidation: delta merge produces distinct stats object.

web-static/dashboard.html (flag-on bootstrap)

- Builds an element lookup once (#defrag-total, -chain-len,
  -verified, -mine, -stale, -dead, -fee, -v36native, -v36sig,
  -blocks).
- 250 ms setInterval calls writeStats() which short-circuits when
  lastAppliedTip hasn't changed — matches the orchestrator's
  per-tip caching so DOM writes are minimal.
- #defrag-blocks formatted as "N LTC / M DOGE" — identical to the
  inline path at :5909. Coin-aware label comes with CoinBridge.
- beforeunload clears the interval.

web-static/sharechain-explorer/dashboard-bundled.mjs

- Header stats line now surfaces chain length, v36/v36sig, mine,
  stale/dead, primary/doge blocks counts alongside the existing
  tip + connection state. Dropped fields that are zero to keep
  the line compact.

Status

- 176/176 tests pass (166 prior + 10 new).
- Typecheck clean.
- Bundles: shared-core 25.1 KB / 40, sharechain-explorer 43.5 KB
  / 120 — both under budget. (+1.5 KB from ~2 KB of new stats
  code.)
- dashboard.html default path (flag off) touches zero new code at
  runtime — the stat polling is gated inside the flag-on bootstrap.

Next: Phase B #11 particles + card overlays (largest remaining
visual piece), or Phase B #12 hover-zoom + per-share PPLNS treemap
(dashboard.html:5686-5800 port), or Qt refactor step 1.
frstrtr added a commit that referenced this pull request Apr 20, 2026
Closes the second-most-visible flag-on gap identified in Phase B #9:
hovering a share cell now pops the 240x240 squarified PPLNS panel
that the inline renderer showed via dashboard.html:5686-5782. Both
dashboard.html (?new-explorer=1) and dashboard-bundled.html get the
feature in this commit.

Three new primitives, all verbatim-ported from dashboard.html so
M2 pixel-diff holds.

src/explorer/pplns.ts (~45 LOC)

- interface PPLNSEntry = { addr, amt, pct }
- parsePPLNS(raw): handles both flat {addr: amt} and merged
  {addr: {amount, merged:[]}} payload shapes, filters zero/
  negative/NaN amounts, sorts desc by amt, normalises pct to the
  remaining total. Byte-identical behaviour to dashboard.html's
  _parsePPLNS() at :5631-5643.
- PPLNSPlugin: id 'explorer.pplns.parser', provides 'pplns.parser'.

src/explorer/hover-zoom.ts (~210 LOC)

- buildHoverZoomProgram(opts): PaintCommand[] — pure builder. Uses
  SharedCore's squarify + addrHue. Cell colours preserved verbatim
  (dashboard.html:5719-5725):
    hovered miner  → hsl(hue, 85%, 55%)   brightest
    my address     → hsl(hue, 60%, 42%)   mid
    everyone else  → hsl(hue, 35%, 30%)   muted
  White highlight ring on hovered miner (line 2.5). Label emission
  thresholds preserved: % when cell > 30x16, address when > 44x28
  with font-size scaling exactly matching dashboard.html:5746-5761.

- createHoverZoomPanel(opts): HoverZoomPanel — thin DOM adapter.
  position: fixed 240x240 canvas + label row + border/padding.
  show() clamps to viewport edges (flip left past a configurable
  tooltip-width offset, matches dashboard.html:5775-5781).
  destroy() removes from parent. Does not capture pointer events
  (pointer-events: none) so hover-through still works.

- HoverZoomPlugin: id 'explorer.hover-zoom.canvas', provides
  'renderer.hover-zoom', fills slot 'explorer.main.overlay'.

src/explorer/delta.ts + realtime.ts

- WindowSnapshot<S> gains:
    pplnsCurrent?: readonly PPLNSEntry[]
    pplnsByShare?: ReadonlyMap<string, readonly PPLNSEntry[]>
- RealtimeOrchestrator.extractMeta() parses pplns_current + pplns
  from /sharechain/window and /sharechain/delta payloads (spec
  §5.1, §5.3). Every parse uses parsePPLNS() so the same shape
  handling applies everywhere.
- applyDelta merges pplnsByShare additively across deltas; delta
  entries win over prior (mirrors dashboard.html:8079-8080).
  Growth bounded at 2 x windowSize per architecture doc §2 ("up
  to 10000 entries") / delta v1 §C.2 LRU.
- New method: orchestrator.getPPLNSForShare(shortHash). Implements
  the three-step fallback from dashboard.html:5647-5663:
    exact cache hit → walk backward (toward newer) to nearest
    cached → pplns_current.
- RealtimeController surfaces getPPLNSForShare passthrough for
  DOM consumers.

web-static/dashboard.html (flag-on path)

- After rt.start(), startHoverZoom() creates a HoverZoomPanel and
  attaches mousemove + mouseleave to #defrag-canvas.
- mousemove: computes layout from current containerWidth, hit-tests
  via cellAtPoint, looks up share via getState().window.shares[idx],
  fetches PPLNS via controller.getPPLNSForShare(share.h), calls
  panel.show() with cursor coords. Cell-index memoised to avoid
  re-rendering when hover stays inside the same cell.
- mouseleave: hides panel.

web-static/sharechain-explorer/dashboard-bundled.mjs

- Parallel wiring so the A/B surface also shows hover-zoom.
- disconnect() / connect() manage hoverPanel lifecycle.
- onMouseMove reuses controller.getPPLNSForShare. myAddress is
  read from the header input so A/B-testers can exercise the
  is-me colour.

tests/unit/pplns-hoverzoom.test.ts (15 tests)

- parsePPLNS: empty / flat / merged / zero-filter / missing-amount
- getPPLNSForShare: exact / walk-backward / fallback to
  pplns_current / additive-across-deltas
- buildHoverZoomProgram: empty → bg only; correct fill count;
  hovered miner gets 2 strokes including white highlight;
  large cell gets % + address labels; tiny cells skip labels.

Status

- 191/191 tests pass (176 prior + 15 new).
- Typecheck clean.
- Bundles: shared-core 25.1 KB / 40, sharechain-explorer 48.3 KB
  / 120 — both under budget. (+4.8 KB from the new modules.)
- dashboard.html default path (flag off) unchanged: bundle isn't
  loaded, no new DOM, no new event listeners.

Flag-on parity with inline now covers: canvas rendering + all
stat panel counters + hover-zoom PPLNS treemap. Remaining cosmetic
gaps from Phase B #9: RealTime toggle button (inert; bundled is
always live) and particles + dissolve/birth card overlays.

Next: Phase B #11 particles + cards (final cosmetic parity), or
Phase B #13 RealTime-toggle plumbing (small, wires the button to
rt.start/rt.stop), or Qt refactor step 1 (CMake deps).
frstrtr added a commit that referenced this pull request Apr 20, 2026
Closes the "RealTime toggle button inert" limitation documented in
Phase B #9's commit message. Clicking the existing #realtime-btn
in ?new-explorer=1 mode now stops + restarts the bundled
orchestrator instead of a no-op.

src/explorer/realtime.ts

- RealtimeOrchestrator.stop() now clears _started so a subsequent
  start() works. Previously stop was one-way: _stopped=true blocked
  restart with an error. The toggle workflow (OFF → ON → OFF → ON
  over one session) needs restartability.
- start() picks up the pattern: it now resets _stopped=false so the
  full init sequence (rebuildWindow + subscribeStream) runs again.
- No caller-visible semantic change when .stop() is terminal (which
  it was in every pre-B#13 call site). Existing 12 realtime.test.ts
  tests still pass verbatim.
- New test: 'restart: start/stop/start cycle works' exercises the
  second start() — window re-fetched, subscription re-registered,
  subsequent tips processed.

web-static/dashboard.html (flag-on path)

- Overrides window.toggleRealTime() — the handler the existing
  `<a href="javascript:toggleRealTime()" id="realtime-btn">` at
  line 2139 invokes. In bundled mode the inline implementation
  (lines 7939-7997: manages its own EventSource + polling +
  #realtime-btn styling) never runs because defrag methods are
  disarmed; our override takes its place.
- Two helpers (setRtButtonOn / setRtButtonOff) replicate the
  inline path's button styling exactly:
    ON  → "RealTime: SSE", bg #28a745, white text
    OFF → "RealTime: OFF", bg var(--card-bg), text-muted
- Initial mount: bundled Realtime auto-starts, so the button is
  painted green before any user interaction (consistent with how
  the inline path looks after its first click).
- Click flow: reads rt.getState().started and calls rt.stop() or
  rt.start() accordingly. Thenable chain updates the button only
  after the orchestrator transitions, so a fast double-click
  doesn't desync button text from underlying state.

Status

- 192/192 tests pass (191 prior + 1 new restart test)
- Typecheck clean
- Bundles unchanged at 48.3 KB (behaviour-only change)
- Flag-off (default) path untouched — inline toggleRealTime()
  still owns the button as before.

Gap list at end of Phase B #13:

- Particles + cards (dying-share ash dissolution, birth coalescence,
  hold-frame miner/PPLNS-% cards during phases 1 and 3). Purely
  cosmetic; not on the critical path to functional parity.

After this commit flag-on mode is functionally complete modulo
those animations: canvas render + all stat panel counters + hover-
zoom PPLNS treemap + RealTime toggle control. Pixel-diff against
the inline path can now be run in A/B tabs with a reasonable
expectation of exact-matching frame content (animations aside).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant