Skip to content

ci: gate jobs by changed paths and merge Go lint with test - #247

Draft
zheli wants to merge 68 commits into
mainfrom
cursor/f6a78fe9
Draft

ci: gate jobs by changed paths and merge Go lint with test#247
zheli wants to merge 68 commits into
mainfrom
cursor/f6a78fe9

Conversation

@zheli

@zheli zheli commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

CI now runs only the jobs affected by changed paths, and Go lint/build/test share one job with lint first so failures fail fast without duplicate checkout.

Changes

  • Add a changes job using pinned dorny/paths-filter@v4.0.2 to detect Go, install.sh, frontend, and mockup edits
  • Merge separate test and lint jobs into one go job (lint → build → test)
  • Gate frontend and mockup-syntax jobs on their respective path filters
  • Run install.sh syntax validation only when install.sh changes

Test plan

  • Go-only PR runs go only; frontend and mockup-syntax are skipped
  • Frontend-only PR runs frontend only
  • Mockup .jsx PR runs mockup-syntax only
  • install.sh-only PR runs syntax check without lint/build/test
  • Doc-only PR does not trigger CI

Checklist

  • Tests pass locally (workflow YAML validated; no application code changed)
  • No coverage regression on touched code
  • Docs updated (and website/ synced if any mirrored docs/*.md changed)
  • CLI ↔ Web UI parity maintained (or follow-up issue + TODO(#issue) comment)

zheli and others added 30 commits June 25, 2026 22:50
The help text no longer references cache/instance paths, but the
format call still passed those values and failed govet printf.

Co-authored-by: Cursor <cursoragent@cursor.com>
Modified the labels for wallet endpoints in the orderedEndpointKeys function to include the username for each wallet type, enhancing clarity for users. This change improves the user interface by providing more descriptive labels for the Wallet options.
The down test computed the non-devkit container count with
`grep -cv ... || echo "0"`. On empty/no-match input, `grep -c`
already prints "0" but also exits non-zero, so the `|| echo "0"`
fallback fired and produced a two-line value ("0\n0"). That broke the
subsequent `[ "$BEFORE" -eq "$AFTER" ]` integer comparison
("[: 0\n0: integer expected"), making the test fail with
"down failed or containers remain" even though localnet down
succeeded.

Drop the redundant fallback so the count is a clean integer.
The E2E job runs on a persistent self-hosted runner. `docker compose
down --volumes` only removes volumes Compose itself created; volumes
left by an earlier run are re-adopted as external on the next `up`
(Compose warns "already exists but was not created by Docker Compose")
and are NOT removed by `down --volumes`.

This stranded canton-e2e-test-default_postgres and
_domain-upgrade-dump across runs, tripping M1-CLN-001's "volumes remain
after clean" check even though `canton-devkit clean` ran correctly.
The failure was an environment/harness issue, not a product bug.

Explicitly remove the per-project volumes by name prefix in both the
pre-run "Clean stale state" and the "Force cleanup on failure" steps so
each run starts from a clean slate regardless of how prior volumes were
created.
Updated AGENTS.md to include a new section on best practices for creating temporary files and directories. Emphasized the importance of using the current working directory or repository root, suggested relative paths, and outlined cleanup procedures. Noted exceptions for using system-level directories like /tmp when necessary.
Add docs/changes-from-proposal.md, a maintained changelog of every
deliberate deviation between the original Development Fund proposal
(docs/original-devkit-proposal.md) and the shipped implementation.

Seeded with 24 entries covering all deviations audited from the current
CLI surface: instance name addressing, --format vs --json, command
aliases, new lifecycle/inspection/token subcommands, connection flag
conventions, telemetry, and up-time flag additions.

Also adds a load-bearing 'Proposal deviation tracking' rule to AGENTS.md
(plus PR checklist item #7) requiring contributors to update the
changes file in the same PR whenever command syntax, flags, aliases,
defaults, or user-facing behaviour diverges from the proposal. The rule
lives in AGENTS.md rather than a .claude/skills/ skill so it fires on
every agent session, not only when an agent judges the task matches.
Group all deviations by the subcommand they affect instead of a flat
list. Add a top-level framing paragraph stating that every deviation is
intentional (UX, performance/resource efficiency, security, correctness,
or CLI \u2194 Web UI parity) rather than a mistake.

Structural changes:
- Add 'Cross-cutting conventions' section for name addressing, --format,
  and aliases (span multiple commands so not tied to one subcommand)
- Group all three 'localnet up' flag additions under a single section
  with subsections
- Merge contracts/tx entries into one section with subsections
- Merge dar entries into one section with subsections
- Merge all five token entries into one section with subsections
- Rebuild table of contents to match new structure

No content removed; all 'Proposal said / Shipped / Why' text preserved
and lightly improved to reinforce intentionality.
Comment out the DPM component OCI publish steps (Install DPM CLI, Lay
out component dirs, Log in to GHCR, Validate manifest, Publish) and
their associated env vars (GHCR_NAMESPACE, DPM_VERSION, DPM_LINUX_SHA256).

The OCI publish now lives in homebrew-canton-devkit's publish-oci.yml
workflow, which triggers on GitHub Release creation and publishes to
the public namespace ghcr.io/bitdynamics-ab/homebrew-canton-devkit:<ver>.

The commented-out steps are preserved with a TODO for re-enabling once
we have a public OCI registry we can push to directly from this repo.

Also updates docs (getting-started.md, packaging.md, README.md) to
reference the new public GHCR namespace.
The release workflow has no docker build/push. Everything published to ghcr.io/bitdynamics-ab/canton-devkit:<tag> goes through 'dpm publish component'. This was leftover wording from before the DPM-component publish existed.
…rkflow

Describes the GitHub Actions workflow to add at .github/workflows/verify-public-oci.yml. Verifies that the public canton-devkit DPM component OCI artifact is:
- Anonymously pullable from GHCR (package is Public)
- Multi-arch in OCI index metadata (linux/amd64, darwin/arm64, windows/amd64)
- Installable + runnable on linux/amd64 via 'dpm install package oci://...'

Resolves the sdk-version open question: 'dpm install package' accepts the OCI ref as a positional argument, requiring no project file or sdk-version.
Weekly (Mon 05:00 UTC) + manually-dispatchable workflow that proves the
published ghcr.io/bitdynamics-ab/canton-devkit DPM component is:

1. Anonymously pullable from GHCR (the package is genuinely Public).
2. Multi-arch in metadata — the OCI index lists linux/amd64,
   darwin/arm64, and windows/amd64.
3. Installable + runnable on linux/amd64 via 'dpm install package
   oci://...' and 'dpm localnet --help'.

The check uses only raw curl (v2 API with a self-fetched public pull
token) and the sha256-pinned DPM CLI — no Docker credentials, no Docker
images, no marketplace actions beyond curl/jq on the runner.

Also adds a '# Keep in sync with verify-public-oci.yml' cross-reference
comment in release.yml next to DPM_VERSION / DPM_LINUX_SHA256 so both
files are bumped together.
$GITHUB_PATH additions only take effect in subsequent steps, not in the
same step where the echo is done. Bare 'dpm --version' therefore failed
with exit 127. Use "$bindir/dpm" --version (matching release.yml:401).
Problem 1: 'dpm install package' requires a daml.yaml with a components:
entry in the current directory — there is no argument form. The step was
passing the OCI ref as a positional arg, which dpm does not support.

Problem 2: 'dpm install package' requires a strict semver OCI tag;
symbolic tags like 'latest' are rejected with 'invalid semantic version'.
The resolved version is extracted from the manifest's
org.opencontainers.image.version annotation (written by dpm publish) and
stored as INSTALL_VERSION for use in the install step.

Fix: after the anonymous fetch step, extract INSTALL_VERSION from
manifest.json. The smoke test creates a minimal daml.yaml (no sdk-version
to avoid the 'opt-in components + SDK bundle' conflict) in a RUNNER_TEMP
workdir, then runs 'dpm install package' and 'dpm localnet --help' from
that directory. Verified locally against latest (resolved to 0.10.1).
Bumps [undici](https://github.com/nodejs/undici) from 7.27.0 to 7.28.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v7.27.0...v7.28.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.28.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Rename for clarity — the workflow name now describes what it tests
(canton-devkit end-to-end functions / Milestone 1 lifecycle) rather
than just 'E2E'. Updates the display name to match.
Updates display name to 'E2E: DPM Installation', job name to
e2e-test-dpm-installation, and the cross-reference comment in
release.yml. No logic changes.
The App config panel and JWT generator rendered tokens as <redacted>,
so copy-pasted env/json/yaml config and generated JWTs were unusable
against the running ledger.

LocalNet is loopback-only and signs with a shared dev secret (the
dev-secret warning already renders on the JWT panel), so surface the
raw token directly:

- api.ts: app-config fetchers request ?include_jwt=true
- DeveloperSetup: JWT panel issues with include_jwt=true on mount and
  shows the token immediately; drop the reveal/hide toggle in favor of
  a Copy-only button

Backend and CLI keep their redacted-by-default behavior; only the
LocalNet Web UI opts into raw tokens.
The unquoted 'name: E2E: ...' value was parsed as a nested mapping
(colon-space), making both e2e workflows invalid YAML so GitHub Actions
never ran them. Quote the value to fix parsing.
- Reconcile platform-support claim in faq.md with the tested
  matrix (macOS arm64, Linux amd64, Windows amd64).
- Drop the "Homebrew not yet published" hedge in getting-started;
  point to docs/homebrew.md (tap + formula automation already ship).
- Rewrite the limitations.md observability section: the host-level
  shared stack has shipped (observability.md is authoritative); the
  remaining limitation is the transitional per-instance dual stack.
- Remove brittle "proposal line 188" citations.
- Fix a broken link to a nonexistent docs/issues/*.md in the M1 e2e
  transcript.
- Align install-snippet version placeholders in packaging.md.
- Add observability.md to the README docs index.
- Move two stale internal docs out of the tree (content preserved in
  Linear BIT-234 and BIT-235): design/localnet-token-workspace.md
  (shipped; now covered by docs/tokens.md) and
  ux-improvement-followup.md (residual --name→positional TODO).
- Remove obsolete .claude/launch.json.
Remove documents that only made sense inside the development-fund
process: the original proposal, the proposal-deviation log, the reviewer
kit, the internal telemetry design proposal, and the per-milestone e2e
test scripts. Reframe the remaining docs in neutral OSS voice: no
milestone/acceptance framing, no internal reviewer process, working
links only.

Replace AGENTS.md with CONTRIBUTING.md: same engineering rules (build,
test, lint, testing requirements, the CLI/Web-UI parity convention,
commit and PR guidance) minus the internal process framing. Drop
CLAUDE.md and local tooling entries from .gitignore.
Remove comments that restate the code, historical narration, and
internal process references; compress verbose rationale to its load-
bearing core; delete provably dead unexported code; apply mechanical
simplifications (redundant else-after-return, unneeded conversions,
single-use trivial helpers) where equivalence is certain.

Deliberately unchanged: all exported identifiers and signatures, error
strings, exit codes, CLI flags and help text, JSON field names, HTTP
routes, log formats, and generated files. Genuine why/invariant/
security/concurrency comments stay. Full go test, golangci-lint,
tsc, and vitest suites pass identically.
New website/ directory with a Starlight site built from the repo docs:
landing page with quick start, guides (lifecycle, DAR, explorer,
observability, tokens), and reference (versions, packaging, telemetry,
limitations, troubleshooting). Builds with npm run build (16 pages).

Add a GitHub Pages deploy workflow (SHA-pinned actions) that publishes
the site on pushes to main touching website/ or docs/.
zheli and others added 29 commits July 6, 2026 18:13
* feat(localnet): add standalone stop/start commands and unpause alias

Split `start`/`stop` out of the up/down aliases into first-class
lifecycle commands that sit between pause/resume and down/up:

  - `localnet stop`  → docker compose stop (containers kept on disk)
  - `localnet start` → docker compose start, falling back to a full
    `up` (reusing the recorded version + profiles) when the containers
    were already removed or the instance isn't registered
  - `unpause` added as an alias of `resume`

Full CLI ↔ Web UI parity: the instance detail card gains Stop and
Start actions (and a distinct Down button), backed by new
/stop (sync 204) and /start (204 fast / 202 up-fallback) handlers.

Docker layer gains `-p`-only StopContainers/Start; shared logic lives
in internal/localnet/stopstart.go. Reconciler now preserves the
stopped status when no container is running.

Docs updated: pause-vs-stop-vs-down comparison table + guidance in the
lifecycle guide, corrected alias claims + new verbs in the agent skill
doc, and a new stop/start section in changes-from-proposal.

BEHAVIOUR CHANGE: `localnet stop` no longer removes containers (was an
alias for `down`) and `localnet start` no longer unconditionally
recreates the stack (was an alias for `up`); it converges to running,
recreating only when containers are gone. Use `down`/`up` explicitly
for the old behaviour.

* fix(ui): show down action for stopped instances

* feat(localnet): add standalone stop/start commands and unpause alias

Split `start`/`stop` out of the up/down aliases into first-class
lifecycle commands that sit between pause/resume and down/up:

  - `localnet stop`  → docker compose stop (containers kept on disk)
  - `localnet start` → docker compose start, falling back to a full
    `up` (reusing the recorded version + profiles) when the containers
    were already removed or the instance isn't registered
  - `unpause` added as an alias of `resume`

Full CLI ↔ Web UI parity: the instance detail card gains Stop and
Start actions (and a distinct Down button), backed by new
/stop (sync 204) and /start (204 fast / 202 up-fallback) handlers.

Docker layer gains `-p`-only StopContainers/Start; shared logic lives
in internal/localnet/stopstart.go. Reconciler now preserves the
stopped status when no container is running.

Docs updated: pause-vs-stop-vs-down comparison table + guidance in the
lifecycle guide, corrected alias claims + new verbs in the agent skill
doc, and a new stop/start section in changes-from-proposal.

BEHAVIOUR CHANGE: `localnet stop` no longer removes containers (was an
alias for `down`) and `localnet start` no longer unconditionally
recreates the stack (was an alias for `up`); it converges to running,
recreating only when containers are gone. Use `down`/`up` explicitly
for the old behaviour.
* fix(ui): generalize action failure banner
The release-stats workflow pushed generated charts directly to main,
which the branch ruleset rejects (changes must go through a PR).
Publish to a separate release-stats-data branch instead — it isn't
covered by the ruleset — and point the README at raw.githubusercontent.com
URLs on that branch.
Starlight's defaults render the pagination titles at 24px inside
8px-radius cards with a drop shadow — oversized against the rest of
the page. Restyle to the design system's quiet cut: hairline border
at 4px radius, no shadow, 12px muted eyebrow, 15px/500 titles, 14px
arrows, hover tint on the system's 120ms curve.
Remove decorative CLI hero output, replace marketing wording, expand the
docs index, and sync the website landing page so operators get factual
onboarding copy instead of pitch-deck tone.
Updated README to clarify functionality and prerequisites.
* docs(website): align index intro with revised README
* Improve description
Document the quick-install script and Homebrew upgrade flow while keeping
DPM primary, and point standalone downloads at the distribution repo.
* feat(cli): rename localnet clean to remove, keep clean as alias

`remove` names the destructive teardown action plainly and reads
unambiguously next to the other lifecycle verbs (down, stop, remove),
where "clean" could be mistaken for a non-destructive tidy-up. The
`clean` alias is retained so existing scripts, CI pipelines, and muscle
memory keep working without a breaking change.

- clean.go: Use "remove", Aliases ["clean"]; flag/help wording updated
- help.go + help_test.go: advertise "remove" in --help
- telemetry allowlist: add "remove" verb (canonical CommandPath), keep
  "clean" so historical counters stay valid
- cli_test.go: assert both remove and the clean alias require a target
- skills docs: ci-localnet / lifecycle use "remove" (skills-lint resolves
  canonical Name(), not aliases)
- docs, CI examples, down.go hint, Web UI copy, mockups: use "remove"
- changes-from-proposal.md: record the clean -> remove rename + alias

* refactor: rename clean.go files to remove.go to match the command

The command was renamed clean -> remove; align the source filenames
(internal/cli/localnet and internal/localnet, plus its test) so the
file names match the canonical command. Pure file rename — symbols and
behaviour are unchanged.
Fix formatting and clarify installation methods in README.
Complete the clean -> remove rename by renaming all Clean/clean symbols
and comments to Remove/remove, and make the remove command accept the
instance name positionally (localnet remove <name>) like the other
lifecycle verbs, while keeping --name for backward compatibility and
--all mutually exclusive with naming a single instance.
* Update README badges for Homebrew and downloads

Updated badge links for Homebrew and added Other Downloads badge.

* Fix badge link for Other Downloads in README.md

* Update README with download badges

Added Homebrew and Other Downloads badges to README.

* Revise download links in README.md

Updated download links for Homebrew and other installations in README.
Updated wording for Homebrew and other installation sections in README.md.
* feat(cli): detect direct vs DPM invocation

Distinguish `canton-devkit localnet …` (direct) from `dpm localnet …`
(via DPM). Both reach the binary with identical args, so DPM now prepends
a `--via-dpm` marker via the component manifest's exec-args. App.Run
strips the marker and records an InvocationMode.

The mode drives:
- Help/examples: `dpm localnet …` under DPM, `canton-devkit localnet …`
  when run directly.
- Flag visibility: `dar build-upload --project` is hidden under DPM (where
  cwd is always the Daml project root); the flag still works and defaults
  to cwd.

Adds detectMode unit tests, mode-aware help/flag tests, and extends
TestRunIsArgvOnly to cover the marker-prefixed argv.

* docs: trim runtime invocation-mode details from packaging.md

The manifest subsection already states why exec-args carries the
--via-dpm marker. The runtime behavior (help/examples wording, flag
hiding) is a CLI concern documented at the source in
internal/cli/invocation.go, so drop the duplicate section here.
* docs: add canonical installer script and wire CI check

Point install instructions at the new root install.sh that downloads canton-devkit releases, and validate the script syntax in CI so installer regressions are caught early.

* docs: fix DPM install example and ignore tmp/

Add daml-script to the README daml.yaml example and ignore tmp/ so local scratch directories stay out of commits.
Replace the Docker-compose framing with the AGENTS.md one-liner so CLI
help and the linked design mockup describe what DevKit actually does.
Standardize contributor intake with a PR checklist aligned to
CONTRIBUTING.md and a structured bug report form for LocalNet issues.
…ana sidecar (#239)

Enabling grafana via the observability toggle ran `docker compose
--profile grafana up -d grafana`, which filtered prometheus out of the
project model and broke grafana's `depends_on: prometheus`
("depends on undefined service prometheus: invalid compose project").
This failed even the enable-both path, where prometheus comes up fine
and the separate grafana invocation then rejects the project.

Activate the prometheus profile alongside grafana whenever grafana is
started, and scope the up with --no-deps so activating that profile
makes the dependency target defined without dragging a prometheus
container up in a grafana-only (external-scrape) setup. Both the CLI
verb and the Web UI Metrics toggle go through the shared
SetObservability, so parity holds.
* feat(docs): bar download charts with dual-repo aggregation

Replace README line charts with all-time bar charts and merge release
download counts from canton-devkit and homebrew-canton-devkit by tag.

* fix(docs): restore line chart for version download stats

Keep the platform breakdown as a bar chart while reverting the per-version
README chart to the original time-series line style.

* fix(docs): emit valid SVG x-axis labels in version chart

Stream release tags from jq instead of joining with a control character
that leaked into the SVG as invalid XML.
…mo fix (#241)

* ui: dual-theme design system with the new shell chrome

Restyle the Web UI to the provided design and add a light theme
alongside the existing dark one, without changing the app's flow or
information architecture.

Theming
- index.css now defines the full token ramp as CSS variables with a
  dark default (:root) and a light override (:root[data-theme]). The
  W.* tokens in tokens.ts resolve through those variables, so every
  screen that already used W.* themes for both palettes with no
  per-screen color edit — one architecture change instead of touching
  19 screens by hand.
- theme.ts owns the active theme: written to data-theme on <html>,
  persisted to localStorage, applied before first paint (no flash).
  useTheme() drives the topbar toggle.
- The 55 `${W.x}NN` hex-alpha concatenations that would become invalid
  once W.x is a variable (var(--accent)1A is not a color) are replaced
  with a tint() helper backed by color-mix. The handful of hardcoded
  hexes that actually break in light mode — dark text meant to sit on
  the cobalt fill, dark switch-track backgrounds — move to W.onAccent /
  W.borderHi so they flip; the dataviz mid-tones (teal/amber/green
  series colors) stay fixed since they read on either background.

Shell chrome
- Topbar: page title, an instance-switcher pill with a status dot and
  wide-caps label, a Commands button that opens the ⌘K palette, a
  Connected health pill, the light/dark toggle, and a Docs link.
- Sidebar: a LocalNet group label, icon + label nav (one stroke glyph
  per route), and a pinned footer showing loopback-only and the live
  schema version.
- CommandPalette gains an openPalette() event hook so the topbar
  button can open it while the component keeps ownership of its state.

Verified: tsc clean, 218/218 frontend tests, Go UI suite, make lint
0 issues, and both themes reviewed live against a running LocalNet
(Overview, Explorer, DAR, Agent Skills) — the toggle flips the entire
app.

* feat(token): make the one-click demo work on standard (V1) instances

`token demo` (and the Web UI "Launch demo token" button) required a
token-standard-v2 instance: it always created a new on-ledger V2
instrument, which needs the splice-test-token-v2 DAR that a standard
release doesn't publish — so on a normal LocalNet the demo failed with
"the test-token DAR isn't published for this instance's Splice version".

RunDemo now adapts to the instance instead of assuming V2:

- token-standard-v2 instance → unchanged: allocate an issuer, create a
  V2 instrument, mint the supply, seed a holder.
- standard instance (V1) → there is no create/mint (Amulet is the only
  instrument), so allocate a holder and fund it with Amulet moved from
  the role's network-funded party (app-user) via the faucet — a
  transferable balance in one click, no alpha DAR required.

The path is chosen by the instance's catalogue channel
(SupportedVersions[version].IsAlpha()), not the alpha_protocol_enabled
flag — that flag is true on both standard and V2 0.6.x instances and so
can't discriminate. Unknown/uncurated versions default to the V1 path,
which works on any running instance.

Both surfaces call RunDemo, so the CLI and Web UI are fixed by one
change; the CLI help text is updated to describe both paths. Adds a
V1-path regression test and threads a routing seam through the existing
V2 tests so they still exercise the V2 flow.

* ui: Carbon Slate palette + console design polish

Two related passes to make the Web UI read as crafted and considered,
both theme-aware (dark + light).

Palette (Carbon Slate)
- Replace the cobalt-on-navy palette, which shared one blue hue family
  between accent and neutrals and read flat. Carbon Slate uses a
  near-neutral graphite ramp with a single indigo-violet accent that
  sits well off the neutral hue, so action separates from chrome.
- Every text/background pair verified WCAG AA in both themes (body 15:1,
  secondary ~8:1, status ~5:1, faint ~3.5:1, white-on-indigo button
  5.7:1); the light-mode greens/reds/amber were darkened to clear 4.5,
  and the focus ring moved to the indigo family.

Design polish (theme-agnostic)
- One status renderer (StatusBadge): Title-Case label + redundant dot,
  so status is never color-only.
- One ledger-id renderer (MonoId): middle-truncation with click-to-copy
  and tabular figures, replacing tail-only truncation that hid the
  discriminating suffix.
- In-app ConfirmDialog replaces native confirm() for destructive
  actions, with the real dpm command shown inline.
- Layout-matched Skeleton loaders replace bare "Loading…" text so
  tables don't pop in and shift.
- Replace the coloured left-border selection idiom across the ACS,
  filter chips, and DAR/token/skill rows with a flat active fill and
  constant padding, so rows no longer shift on click.
- One depth technique per surface (hairline or shadow, not both);
  radii normalized to 2/4/8; decorative gradients and per-element
  hover-lifts removed from data views; transition:all scoped;
  microcopy tightened; error/empty states given cause + action +
  retry and left-aligned.

Verified: tsc clean, 218/218 frontend tests, both themes reviewed live
against a running LocalNet across Overview, Explorer, DAR, and Tokens.

* fix(ui): correct the Metrics screen queries for Splice 0.6.4

Two panels queried metrics Splice 0.6.4 does not provide, so they never
populated:

- ACS lookup buffer used
  daml_participant_api_index_db_active_contract_lookup_batch_buffer_length,
  which is no longer emitted. Point it at the live
  daml_participant_api_index_active_contracts_buffer_size gauge.
- The latency panels used histogram_quantile on the sequencing-duration
  histogram, which 0.6.4 exports with only the +Inf bucket, so quantiles
  are NaN regardless of load. Show the computable average (sum/count)
  instead, labelled as an average, and hide the p50/p95/p99 strip when
  the backend can't compute those (it returns on versions whose
  histograms carry finite buckets).

* ui: trim comment noise and correct stale palette naming

Comment-only pass over the console. The component and shell files had
grown header blocks that narrated redesign history and editorialised
about the audience ("the discipline an auditor relies on", "reads as
unfinished", "one depth technique") rather than documenting the code.
Trim those to the load-bearing "why" and drop the asides; the metric,
race-condition, and accessibility comments are left intact.

Also fix palette naming left over from before the Carbon Slate swap:
the accent is no longer cobalt, so the design-token, CSS, and Button
docs that still called it that were inaccurate. The chart ramp stays
labelled cobalt — those hexes really are cobalt-blue.

One small non-comment change: MonoId's clipboard copy collapses the
redundant Promise temporary into a single optional-chained call.

* metrics: show sequencing-latency average for CLI↔UI parity

The Web UI Metrics screen shows the mean sequencing latency because
Splice 0.6.4 exports the submission-duration histogram with only the
+Inf bucket, so histogram_quantile (p50/p95/p99) is NaN there while the
mean (sum/count) is exact. The CLI `dpm localnet metrics` and the
/metrics/summary handler still led with those NaN percentiles.

Add a MediatorAvg query to the shared metricsq map so both surfaces pick
it up automatically. The CLI text now leads with `avg` and prints
p50/p95/p99 only when the histogram carries finite buckets (rather than a
row of dashes); the JSON and the handler expose `avg_ms` alongside the
percentiles. Percentiles remain for Splice versions whose histograms are
bucketed, so no data is lost where it exists.

* refactor: compress running-commentary comments

Cut the narration-track comments across the Web UI and the token-demo
backend — redesign-history headers, step-by-step narration, section
banners, and prose that merely restated the code — down to load-bearing
why. Kept and tightened the genuine rationale: concurrency/ordering
constraints, accessibility reasons, the iframe-sandbox security note, and
the Splice-0.6.x substitute-metric notes the accuracy bar depends on.

Comments only (plus one empty catch collapsed to a single line). The
frontend type-checks and the full Go suite passes.

* Match frontend wordmark to docs site (CANTON DEVKIT)

* ui: default to the light theme

New sessions (no stored preference) now open in light. The JS default and
the useSyncExternalStore server snapshot return "light", and the root
<html> carries data-theme="light" so the first paint is light too, with a
matching theme-color. A stored preference and the toggle still win.

* fix(charts): give the area-fill gradient an id-safe handle

The AreaChart built its gradient id from series.label, so a label with
spaces ("ACS lookup buffer") produced url(#area-ACS lookup buffer) — an
invalid reference, which falls back to the initial fill value, black. It
was invisible on the dark background and became a solid black block once
light became the default. Derive the id from useId() instead, so it is
always url-safe and unique.

* ui: make the catch-all route read as a 404, not an unshipped stub

Placeholder renders only for the path="*" wildcard, but its comment and
copy ("Route stub for screens whose backend hasn't landed yet", "Not
implemented yet in this build") implied unfinished features exist. Reword
to a plain not-found message.

* grafana: switch the bundled dashboard to figures that work on 0.6.4

Third surface of the same fix already applied to the CLI and Web UI. The
bundled canton-localnet dashboard led with histogram_quantile p95/p50
latency panels, which are NaN on stock Splice 0.6.4 (its sequencing
histogram exports only the +Inf bucket), and an ACS panel querying
daml_participant_api_index_db_active_contract_lookup_batch_buffer_length,
a metric 0.6.4 no longer emits.

- Both latency panels now show the mean (sum/count) in seconds, labelled
  as an average, with a note that percentiles return on versions whose
  histograms carry finite buckets.
- The ACS panel points at the live daml_participant_api_index_active_
  contracts_buffer_size gauge.
- docs/dashboard-customization.md updated to match, and its claim that the
  p95 panel was "audited on stock Splice 0.6.4" (the NaN case) is removed.

* fix(ui): restore dist/index.html placeholder + guard test

The committed index.html referenced hashed Vite assets
(assets/index-*.js/.css) that are git-ignored and thus never committed,
so a fresh checkout pointed at nonexistent files. Restore the tracked
DEVKIT_FRONTEND_PLACEHOLDER version and document, in the file and
.gitignore, that a real build must not be committed over it.

Add TestFrontend_TrackedDistIsPlaceholder, which asserts the
git-tracked (HEAD) dist/index.html still carries the placeholder
sentinel. Existing tests only checked the working-tree file (which
make frontend legitimately overwrites) and accepted either a
placeholder or a real build, so neither caught this regression class.

* test(assets): sync ACS panel title pin with dashboard rename

Commit 8180a80 renamed Grafana panel id=14 from "ACS Lookup Buffer
Length" to "ACS Lookup Buffer" (and switched its metric query to the
live 0.6.4 signal) but did not update the pinning test, so
TestDashboardHasACSAndThroughputPanels failed in CI. Align the expected
title with the shipped dashboard JSON.

---------

Co-authored-by: Zhe Li <linuxcity.jn@gmail.com>
Skip frontend, mockup, and Go work when unrelated paths change, and run
golangci-lint before build/test in a single Go job to fail fast.
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.

2 participants