Skip to content

v10.5.3 - WebUI fixes and linting + refactor to C#15. Prepare of dotnet11 - #28

Merged
techbuzzz merged 13 commits into
mainfrom
feat/v10.5.3
Oct 11, 2026
Merged

techbuzzz merged 13 commits into
mainfrom
feat/v10.5.3

Conversation

@techbuzzz

Copy link
Copy Markdown
Owner

Pull Request

Description

Related Issues

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that changes existing behaviour)
  • 📚 Documentation update
  • 🧹 Refactor / chore

Checklist

  • My code follows the project's coding standards (see CONTRIBUTING.md)
  • The solution builds with 0 errors and 0 warnings (dotnet build --configuration Release)
  • I have added/updated XML documentation for public APIs
  • I have updated relevant documentation (README.md, QuickStart.md)
  • I have tested my changes (examples run as expected)

Additional Notes

techbuzzz and others added 8 commits October 10, 2026 18:09
The first version of the site only walked `docs/*.md`, which silently dropped
`docs/TASKS/` and `docs/scope/` - 9 committed, public documents. The previous landing
page linked `docs/TASKS/README.md` ("Work log - open items by severity, including what
is deliberately not fixed"), so losing them was a coverage regression, not a curation
decision.

The docs route is now a catch-all and the slug mirrors the directory layout:

| File                          | Page                                |
| ----------------------------- | ----------------------------------- |
| docs/QuickStart.md            | /docs/quickstart/                   |
| docs/TASKS/README.md          | /docs/tasks/                        |
| docs/TASKS/W1-correctness.md  | /docs/tasks/w1-correctness/         |
| docs/scope/I-00-project-vision.md | /docs/scope/i-00-project-vision/ |

A directory's README.md collapses to the directory itself, which is why the work log stays
reachable at /docs/tasks/. The index groups by source directory - keying on the slug filed
the work-log index under "Guides", because its slug has no path separator.

Two description bugs fixed while re-reading the cards:

- a description took only the first *line* of a paragraph, so a wrapped sentence was cut
  mid-clause ("...referenced Microsoft.Extensions.AI 10.8.0 and"). It now joins the whole
  paragraph and trims on a word boundary;
- stripping `#` everywhere turned "C# 15" into "C 15". Only leading/trailing markers are
  heading syntax now; a `#` inside a word is part of it.

docs/habr/ stays excluded: it is a draft for another platform carrying editorial notes about
which headline to use, the same category as the gitignored .articles/.

36 pages, up from 27. typecheck, build and verify all green.
…reams

The typecheck has been reporting green while checking less than it should.
`npm run typecheck` printed "[Vue] Load plugin failed:
vue-router/volar/sfc-route-blocks" on every run and still exited 0, so CI
saw a pass. The plugin comes from vue-router, and package.json pinned
vue-router@^4 - a different major from the one nuxt depends on, for a
package no source file imports. Two defects sat behind that one message:
vue-tsc@2 cannot load a vue-router@5 plugin at all, and the plugin also
has to resolve from the project root, which it does not while it only
exists nested under node_modules/nuxt.

vue-router is now pinned to the major nuxt actually wants, and the
toolchain moved with it: nuxt 4.6.1, vue-tsc 3.3, vitest 5,
@nuxt/test-utils 4, happy-dom 20. The check is clean for the first time.

Node is pinned to 22.23.3 - .nvmrc, plus one ARG across the Dockerfile's
three stages - because nuxt@4.6.1 declares an exact engines range,
^22.22.3 || ^24.15.0 || >=26.0.0, that the floating node:22-alpine tag
only satisfied by luck.

The proxy runs every upstream call with timeout: 0, so nothing else ever
ended those requests: closing the tab or navigating away left the
server-side SSE connection running for the rest of the debate, one leaked
stream per piece of user navigation. It now aborts its fetch when the
response closes before it was written, and swallows the resulting read
error, because a client hanging up is not an upstream fault worth
reporting to nobody.

Measured on the fixture, the upstream socket closes 6ms after the client
goes away with the fix and 2699ms without it - the second being the moment
the fake upstream ends its own response, which is exactly the point: a
connection the proxy never cancelled closes anyway. The regression test
therefore asserts the timing, not the count, since the count passes
either way.

Three quieter fixes. Cancel reported neither of its two outcomes, because
both branches were the same line. Changing a filter did not re-query,
leaving the previous results under controls claiming the new selection.
And npm test failed on a clean checkout, because the SSE suite needs the
built server that only CI happened to build first.

Live rounds now reach a screen reader through a polite live region, each
route titles itself, and buttons, inputs and rows gained hover states and
a visible focus ring - the browser default being near-invisible against
these dark surfaces.

The server route stays on h3 rather than the new nuxt/server surface:
that one omits the response-writing helpers this proxy is built on, and
Nuxt's RequestEvent is not assignable to h3's H3Event. The reasoning is
recorded at the import so it is not re-attempted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The header showed the horizontal lockup. Switching it to
img/delibera-square-1024x1024.png means cropping to the scales mark - x 244..778,
y 170..581 - because the full lockup is 662px tall inside a 1024px canvas and the wordmark
caps would render at about 3px at header size. The hero keeps the wide lockup.

The crop is a wrapper with negative offsets rather than a rewritten PNG: the Pages build runs
on ubuntu, where System.Drawing does not exist, so cropping at sync-assets time would work on
a Windows dev machine and fail in CI.

Two things the measurements turned up:

- the first crop clipped the base of the scales and the left pan, because their antialiased
  edge pixels sit just above a strict threshold; the source background is a flat 253-254, so
  the threshold is 251 and the bounds carry a pixel of slack;
- keeping the scale as its own custom property does not work. `calc(30px / 405)` is a *length*,
  not a unitless number, so multiplying it by another length is invalid at computed-value time
  and the box silently collapses to 0px. Dividing numbers first and multiplying by the height
  last stays valid.

All three brand PNGs are Format24bppRgb with an opaque near-white background, so there is no
alpha to blend. The mark is dark navy, which means the chip carries an explicit white plate in
both themes - on a dark header the mark would otherwise be invisible.

typecheck, build and verify green.
The two publish workflows looked equally protected and were not. Both gate on
`refs/tags/v`, so neither publishes on a merge to main - but only the NuGet publish job ran
inside a GitHub environment (`nuget-prod`). The Docker job had none.

That difference matters more than the tag gate it sits next to. The gate stops an accidental
merge from shipping; it does nothing about a mistyped tag, or about anyone able to push a
`v*` tag. Pushing `latest` to a registry consumers pull from is not undone by re-tagging, and
the multi-arch smoke checks only prove the manifest is well-formed - not that the tag was
meant.

`dockerhub-prod` puts the job behind Required reviewers, so a tag push queues the run and a
human approves the push. Enabling reviewers is a repository setting
(Settings -> Environments -> dockerhub-prod -> Required reviewers); the environment itself is
created on first use, so the release path is unchanged until that is switched on.

The same environment can hold `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` as environment-scoped
secrets instead of repository-scoped ones - the job already runs inside it.

build and webui-tests stay outside the environment on purpose: they push nothing and should
not wait on an approval nobody can give.

ReleaseProcess.md documents the approval step, since tagging now pauses the workflow.
…very merge

Two changes, both about the cost of a routine merge.

**Merge commits instead of squash.** Squash is what made branch handling expensive: the
squashed PR's commits are not ancestors of main, so `git merge-base --is-ancestor <branch>
main` cannot answer whether the work shipped, and merging main back into an open feature
branch produces a disconnected merge instead of a fast-forward - which is why the branch got
recreated rather than reconciled. A merge commit keeps that ancestry. `git log
--first-parent main` is unaffected and still reads as the release list.

This is a repository setting, not a workflow change: Settings -> General -> Pull Requests ->
Merge options -> Allow merge commits. Squash can stay enabled; the team just uses merge.

**`release` is tag-only now.** It also ran on every push to main, where it resolved the newest
reachable v* tag and rewrote that release's body: a full fetch-depth-0 clone, a PR-notes
generation and a release API call per merge, to rewrite a body that usually had not changed. The
"usually" is the defect - a merge that happened to touch the release-notes header or the
WhatsNew doc silently edited an already published release. The repair path is unchanged and
still one click: Actions -> release -> Run workflow, with or without a tag.

`dockerhub-metadata` keeps its main trigger. It is already filtered by
`paths: [dockerhub/**]`, so it costs nothing on an ordinary merge and is exactly what
re-syncs the Hub cards when a description is edited - the case it exists for.

Documented in CONTRIBUTING.md (branch + PR conventions, including the repo-setting step) and
ReleaseProcess.md (merge rule, branch deletion, the backfill table).
@techbuzzz techbuzzz self-assigned this Oct 11, 2026
Bumps every packaged project from 10.5.2 to 10.5.3. Without this the v10.5.3
tag packs 10.5.2 nupkgs, and 'dotnet nuget push --skip-duplicate' skips them
silently against the already-published 10.5.2.

Converts CHANGELOG [Unreleased] to [10.5.3] - 2026-10-11 and records:

Added:
- Project website on GitHub Pages (Next.js static export in site/)
- Opt-in CORS for static browser clients (Delibera:Server:Cors:AllowedOrigins)
- BuiltIn constants extracted across Delibera.Core
- Accessibility: polite live region, route titles, focus rings
- CI improvements: dockerhub-prod environment, release pages from WhatsNew

Fixed:
- Three per-request server costs (ValidationFilter caching, Redis multiplexer, SSE writer)
- Web UI proxy leaked upstream SSE connections after client disconnect
- Web UI typecheck was passing while silently checking less (dependency upgrades)
- Three Web UI behaviours: cancel message, filter re-query, npm test pretest
- Web UI lockfile out of sync under npm 10 (unplugin@3.4.0 missing)

Changed:
- Node pinned to 22.23.3 (exact patch)
- npm pinned to 10.9.4 in Dockerfile

Adds docs/WhatsNew-v10.5.3.md, v10.5.3 sections to both READMEs, and the
DELIBERA_VERSION pin.

Verified on this tree: build -warnaserror 0 errors / 0 warnings; 635/635 tests
(493 Core + 132 Server + 10 gRPC); pack emits Delibera.{Core,Server,Redis}
.10.5.3; 44 Web UI tests passing; Web UI typecheck clean; Server nuspec
resolves Delibera.Redis 10.5.3.
@techbuzzz
techbuzzz merged commit 7d5f566 into main Oct 11, 2026
5 checks passed
@techbuzzz
techbuzzz deleted the feat/v10.5.3 branch October 11, 2026 15:41
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