Repository navigation
[WEB.40] Blazor WebAssembly migration of Web: C# Site, Account and Chat profiles, TypeScript thin Worker, React retired - #35
Conversation
Step 1 of the Blazor migration. Adds the central .NET 10 solution layout
with one exact SDK pin (10.0.401), central package management and the
AGPL licence metadata on every project:
- src/ArcForges.Web.Site (C# static Site generator skeleton)
- src/ArcForges.Web.Ui (Razor class library skeleton)
- src/ArcForges.Web.App (Blazor WebAssembly standalone Account/Chat profile
skeleton, RunAOTCompilation false, transitive framework references off)
- src/ArcForges.Web.Operations (separate-origin Blazor WebAssembly profile
skeleton; no operator features)
- tools/ArcForges.Web.Tooling (refuses every command until the port lands)
- tests/ArcForges.Web.{Site,App,Ui,Operations,Policy}.Tests (xUnit v3 on
Microsoft.Testing.Platform, bUnit for Ui; the Policy suite checks the
restored NuGet closure against the admitted records, with negative cases)
NuGet admission: eng/policy/dependency-policy.json gains nugetClosure (55
exact packages from the project lock files, with content hash, licence,
nuspec SHA-256 and source) and the successor receipt
eng/policy/dependency-reviews/web-40-admission-r1.json. Every new csproj,
props, targets, global.json, NuGet.config and packages.lock.json input is
hashed in the npm input map. The npm closure is unchanged.
Architecture policy: the GOV.11 refusal of every Blazor target is reversed
to the P2-021 rule: Blazor WebAssembly standalone is allowed, and Blazor
Server render modes and circuits are refused. The fixture follows.
win.slnx keeps the ArcForges.Web.esproj entry until the React parity step.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…and browser-wasm admission Step 2 of the Blazor migration. Section 10 items first: - CON.07 identity: verified from Plan ledger con-07.md (Contracts PR 74, merge ca45f36, candidate 1.0.0-ci.287.1, publication run 36966686225) and from the nuget.org flat-container index and nuspec of all twelve packable Contracts projects (each lists 1.0.0-ci.287.1, carries repository commit ca45f36 and is Apache-2.0). ArcForges.Contracts.PublicApi 1.0.0-ci.287.1 is pinned centrally and referenced by ArcForges.Web.Ui; its transitive Foundation, Google.Protobuf 3.36.1 and Grpc.Core.Api 2.84.0 are admitted. - browser-wasm admission: Microsoft.NETCore.App.Runtime.Mono.browser-wasm 10.0.12 (implicit for the BlazorWebAssembly profile) and Microsoft.NET.Runtime.WebAssembly.Sdk 10.0.12 (PackageDownload in ArcForges.Web.App.csproj), recorded in nugetPackDownloads because NuGet does not record PackageDownload items in packages.lock.json. Microsoft.AspNetCore.App.Runtime.browser-wasm is not admitted: no such package exists on nuget.org. - Receipt web-40-admission-r2.json supersedes r1 (r1 is unchanged), with the con07Identity table, browserWasmPacks and the input digests of every changed csproj, props and packages.lock.json. Static Site (src/ArcForges.Web.Site, src/ArcForges.Web.Ui): - Public pages (/, /hello, /cloud-hello) are Razor components rendered with Microsoft.AspNetCore.Components.Web.HtmlRenderer. The markup reproduces the React prerender content: titles, descriptions, shell, copy, disabled initial controls, the default greeting and the noscript notices. No script element, no event-handler attribute and no framework reference is emitted (TB-01). Blazor internal event markers are removed from the static markup. - The stylesheet is one content-hashed asset (Tailwind preflight equivalent plus the packages/ui styles). The 404 page, robots.txt, favicon and 404.css are the React public files, byte for byte. - The Content-Security-Policy is derived from the emitted pages with the React rule (script-src 'self' plus the SHA-256 of every inline script body; no unsafe-inline, unsafe-eval or wasm-unsafe-eval; an external script is refused). _headers carries the exact React securityHeaders text. - Greeting and connection logic are ports of apps/site/app/hello.ts and cloud-hello.ts: the protobuf SayHello round trip, the JavaScript trim set, the 80-code-point limit, the control-character refusal, the exact failure text, the same-origin gRPC-Web unary call with no credentials, no redirect, a ten-second deadline and a reply size limit. - The build is deterministic: two builds of the same inputs produce the same bytes (tested). Tests: xUnit ports of the site unit cases (GreetingTests, ServerConnectionTests, bUnit HelloExampleTests and CloudHelloExampleTests), plus determinism, no-script, header, CSP, inventory and framing failure tests. The Policy suite gains the pack-download admission check. Results: Site 65 passed, Ui 7 passed, Policy 9 passed (local dotnet 10.0.401 build and run). Not in this step (recorded as remaining): apps/site and the React tests are kept until byte and content parity is shown; the interactive hello and connection checks need the Blazor App profile (no runtime JavaScript on public pages); Node/vitest and the Playwright suites were not run locally (no node_modules, hosted CI authoritative). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…on-r3) Step 3, unit U1, first commit: the dependency admission for the Account and Chat profiles and the Operations skeleton, and the project files that carry it. - eng/policy/dependency-reviews/web-40-admission-r3.json supersedes r2 (r2 is unchanged). Its review reviewer field is the pre-assigned independent reviewer w-deku-20261008-rev-web-40, not PENDING. - eng/policy/dependency-policy.json binds 39 input digests (every csproj, props, targets and packages.lock.json, plus the earlier named inputs; CRLF is normalised to LF as the policy digests them) and 65 nugetClosure rows, each read from the restored lock files and checked against its nuspec. - Directory.Packages.props, win.slnx, the App and Operations project files, and the App, Operations and test packages.lock.json files are the write-scope project files for these packages. - Restored offline-checked with dotnet 10.0.401 (global.json, no adapter needed). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ons skeleton
Step 3, unit U1, second commit: the standalone Blazor WebAssembly source of the
Account and Chat deployment profiles (ArcForges.Web.App, replacing apps/app) and
the Operations profile skeleton (ArcForges.Web.Operations), plus the shared
profile CSP helper in ArcForges.Web.Ui.
- Probe/HelloProbe.cs: the anonymous binary gRPC-Web greeting through the
generated Contracts client. Fixed in this unit: the frame watcher read the
frame length from the flag byte plus three length bytes, so a trailers frame
never reported its grpc-status (trailers-only answers became malformed); the
watcher now reads the four length bytes after the flag. The watched content
also copies bytes through the serialize path the library uses to buffer an
answer, so the status is seen on every path. Bytes are never changed.
- Pages/Chat.razor and Pages/Account.razor, Probe/*.cs, App.razor, layouts and
wwwroot: the same semantics as apps/app (routes/chat.tsx, probe/*.ts): one
message at a time, the Sending state, Cancel, cancellation on leaving the page,
the last twenty transcript entries, fixed failure text, and cookie-session,
CSRF and Origin rules unchanged.
- Operations: the project, shell route and separate-origin configuration only;
no operator feature code (OPS.05 and OPS.11 build those).
- Ui/WasmContentSecurityPolicy.cs: the exact script-src token set for the App and
Operations profiles ('self' 'wasm-unsafe-eval' plus required hashes; never
unsafe-eval or unsafe-inline).
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…cal browser opt-in
Step 3, unit U1, third commit: the xUnit and bUnit successors of the Account and
Chat probe cases (tests/unit/app-*.test.tsx and app-hello.test.ts), the profile
CSP token-set assertions, and the Operations skeleton tests.
- ArcForges.Web.App.Tests: Account, Chat, hello, session, exact unsigned and
profile policy cases with a test-only same-origin double (TestDoubles). Fixes in
this unit, without weakening any assertion:
- LeavingTheChatPageCancelsTheMessageThatIsStillPending waits for the request
to start through a completion source and disposes the rendered components
with DisposeComponentsAsync, the bUnit API that disposes components (the
context dispose only releases services).
- The cancellation token of the wait uses the xUnit test context token.
- ArcForges.Web.Operations.Tests: skeleton only (the profile, its origin and the
exact CSP token set).
- ArcForges.Web.Ui.Tests: WasmContentSecurityPolicyTests with a passing and a
failing example for each token rule.
- tests/browser/ArcForges.Web.Browser.Tests: Microsoft.Playwright for .NET, local
opt-in test-only tooling (LocalOptIn gate; not run in CI). The local browser
test is skipped unless the opt-in is set, as recorded by the test.
Results on this worktree (dotnet 10.0.401, through the build slot, after the
admission r3 restore): Ui 14 passed; App 49 passed; Operations 5 passed; Browser
6 passed and 1 local opt-in skipped; Policy 9 passed; Site 65 passed.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…e provenance and licence-boundary gaps worker/index.js becomes worker/index.ts with identical behaviour: www-to-apex 308 keeping path and query, everything else served by env.ASSETS.fetch. The candidate ships the JavaScript form emitted by Node type stripping (LF normalized) into the private worker/index.js; no bundling, no import. - tooling/project.ts: workerScript() emits the candidate Worker and verifyWorkerScript() compares the candidate bytes with that emission. - tests/unit/canonical-host.test.ts: the emitted module is importless, carries no type syntax, and answers like the TypeScript source on the redirect, asset-passthrough and loopback cases. - tests/unit/licence-boundary.test.ts: an unknown first-party package in a packages.lock.json fails the audit. - tooling/licence-boundary.ts: arcforges.contracts.foundation is an allowed first-party owner (CON.07 candidate 1.0.0-ci.287.1, admitted by web-40-admission-r2 from Contracts ca45f36, an ancestor of Contracts main). - eng/policy/licence-boundary.json: the browser-test csproj is a licence- boundary MSBuild input. - eng/provenance/files.json, biome.json, tsconfig.json: worker/index.ts replaces worker/index.js in the inventory, the lint and typecheck includes. - docs/deploying.md, docs/provenance.md: factual update for the TypeScript source. The browser-resources profile still binds worker/index.js and the previous tooling digests. The successor chain (browser-resources-r11 and admission receipt r4) is committed separately, so this commit is not the final gate. Validation: unit suite (vitest run tests/unit) 15 files, 139 tests passed; tsc -p tsconfig.json passed; biome lint passed. Candidate build not yet passing at this commit (browser-input gate, resolved by the successor). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…he TypeScript Worker browser-resources-r11 supersedes browser-resources-r10. It binds the canonical-host Worker source worker/index.ts (replacing worker/index.js), the emitter in tooling/project.ts and the active-profile selector in tooling/browser-provenance.ts. The browser graph, the normalized templates, package identities, legal inputs, Contracts metadata and both SBOM expectations are unchanged. Its sourceCommit is dc46b23, the commit that carries the reviewed Worker and emitter bytes. The reviewer field names w-deku-20261008-rev-web-40. web-40-admission-r4 chains from web-40-admission-r3 and rebinds the policy inputs to r11. It changes no package, lock, manifest or class: the NuGet and npm closures and package-lock are the r3 values. The active review pointer and the artifactRecords move to r4 and r11. The r3 receipt and the r10 profile and record stay immutable history. files.json lists the new members and its artifacts point at r11. NOTICE.txt is regenerated from the active records. Validation run locally through the workstation build slot: - node tooling/project.ts build passed and verified candidate 0.1.0-local at dc46b23 (local changes flag cleared at this commit). - node --test tests/provenance (43) and tooling/dependency-policy.test.ts (15) passed. - vitest run tests/unit: 15 files, 139 tests passed. - tsc -p tsconfig.json and biome lint passed; prettier passes on every file this commit changes. - The policy gate passed its licence, provenance and browser-input checks. It stops at the pinned Node 24.21.0 assertion, because the local runtime is 24.20.0. Hosted CI remains authoritative (brief section 10). The remaining policy steps passed locally when run without that assertion. - Not run locally: the npm run format:check repo-wide gate. It already fails on committed files outside this change (see the unit report), and the dependency-policy.json change keeps the plain JSON style that file uses. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… web-40-admission-r5 Step 4 of the Blazor migration, unit U3, first commit: the ported 'site build' command that CI needs to publish the C# static Site. - tools/ArcForges.Web.Tooling/Program.cs: 'site build --out <new-directory> [--source-ref <40-hex>]' writes every SiteBuilder file to a directory that must not exist yet (fail closed on a stale directory, refuse paths that escape it, refuse a malformed source ref with exit 2). Every other command is refused with exit 2 and the list of ported commands. - tools/ArcForges.Web.Tooling/ArcForges.Web.Tooling.csproj: ProjectReference to src/ArcForges.Web.Site. packages.lock.json records that reference and the Contracts and gRPC packages it needs, all already admitted (CON.07 identity). - eng/policy/dependency-reviews/web-40-admission-r5.json supersedes r4 (r4 is unchanged). Its reviewer field is w-deku-20261008-rev-web-40. The active review and reviewRecord in eng/policy/dependency-policy.json move to r5; the two tooling input digests are rebound and every other input is unchanged. Validation (build slot, Windows, dotnet 10.0.401): Tooling build succeeded with 0 warnings; 'site build' twice into fresh directories gives identical trees (9 files, diff -r empty); negative cases exit 2 (existing directory, bad ref, unknown option, missing --out, unknown command). node tooling/dependency-policy.ts passed (351 dependencies, 39 inputs); node --test tooling/dependency-policy.test.ts 15/15; Policy test suite 9/9. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…pt web-40-admission-r6 Step 4 of the Blazor migration, unit U3, second commit: the workflow runs the C# product on Windows and Linux and keeps the existing security jobs. .github/workflows/ci.yml: - Workflow env CSHARP_PROJECTS and CSHARP_TEST_PROJECTS list the ten C# projects explicitly. win.slnx is not used because it carries the retiring esproj entry, and tests/browser (Microsoft.Playwright, local opt-in) is never restored or built in CI. - New job csharp (ubuntu-latest, windows-latest, SDK 10.0.401 via setup-dotnet): dotnet restore --locked-mode, dotnet build --no-restore, dotnet test --no-build for the Site, Ui, App, Operations and Policy suites, dotnet publish of the Account and Chat profile and of the Operations skeleton, and a static Site build by the ported 'site build' command that is compared byte for byte with a repeat build. The Linux leg retains the Site and profile outputs for 30 days. - CodeQL matrix gains csharp with build-mode manual and an explicit locked restore and build, so CodeQL observes the real compilation. The javascript- typescript and actions analyses are unchanged (build-mode none). - Secret scan (gitleaks by digest), actionlint, npm audit, dependency review and the verify required-check gate are kept; verify now also requires csharp. - The main-push deploy job is unchanged and still ships the sealed React candidate. It carries a comment that the C# outputs are not yet promoted by it. Deploying the C# candidate needs the candidate and deploy port (a decision for the coordinator; not made here). - No browser E2E, live-service, macOS or device job is added. eng/policy/dependency-reviews/web-40-admission-r6.json supersedes r5 (r5 is unchanged). Its reviewer field is w-deku-20261008-rev-web-40. The active review and reviewRecord in eng/policy/dependency-policy.json move to r6, and the .github/workflows/ci.yml input digest is rebound (the workflow file is a gated dependency input). Every other input digest, package and class is unchanged. Validation (Windows, build slot, dotnet 10.0.401, the csharp job steps replayed from this file): restore --locked-mode for all ten projects; build of all ten; tests Site 65, Ui 14, App 49, Operations 5, Policy 9, all passed; both profile publishes succeeded; the Site built twice with identical trees (9 files). node tooling/dependency-policy.ts passed (351 dependencies, 39 inputs); the dependency test suite 15/15. prettier --check passes on ci.yml. actionlint is not installed on this workstation, so the workflow was checked with a YAML parse and the job graph read back (hosted CI remains authoritative). The Linux leg is validated separately in WSL2 Debian (see the unit report). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…de glue (U3b, part 1) - tools/ArcForges.Web.Tooling: candidate build and candidate verify (C# Site output, identity and legal files, pinned Worker digest, wrangler candidate config, build SBOM, runtime SBOM, provenance receipt, sealed manifest), and profiles bundle and profiles verify (web-profiles-<sha256>.tar, same name pattern and manifest-first layout; static web assets manifest integrity check). - tooling/candidate.ts: Node emits the Worker JavaScript and the build identity, and re-verifies the identity before deploy. - tooling/cloudflare.ts: deploy and smoke verify through the C# tool; new dry-run command (wrangler deploy --dry-run, no upload). - tests/provenance/csharp-candidate.test.ts: determinism, seal, resealed security and bundle tamper tests. Not yet run to completion locally when this commit was made (slot queued); see the unit report. - eng/provenance/files.json: inventory entries for the new files, and the receipts r5 and r6 that HEAD had omitted. - docs/deploying.md: C# candidate sequence and local dry run. Local proof (build slot): two candidate builds identical; candidate verify passes; Blazor publish; bundle builds, verifies and is byte-deterministic; wrangler dry run read 17 assets and uploaded nothing. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…-admission-r7 (U3b, part 2) - .github/workflows/ci.yml: the candidate job publishes ArcForges.Web.App, emits the Worker and identity (tooling/candidate.ts), builds the sealed C# candidate twice with a byte comparison, verifies it, and builds and verifies the profile bundle. The React candidate and profile builds leave the deploy path. The deploy job restores and builds the C# verifier and ships the same sealed candidate under the unchanged main-push guards. - eng/policy/dependency-reviews/web-40-admission-r7.json supersedes r6. Its reviewer field is w-deku-20261008-rev-web-40. Only the ci.yml input digest changed; no package, lock, class or project file changed. - eng/policy/dependency-policy.json binds r7 and the rebound ci.yml digest. Validation: tooling/dependency-policy.ts passed (351 dependencies, 39 inputs); dependency-policy tests 15/15; provenance source tests 35/35; architecture audit 0 findings; naming check pass; prettier and biome clean on changed TypeScript. Not run to completion: the C# candidate negative tests and the workflow itself (hosted CI is authoritative). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… fixtures (U4) Re-implements the GOV.11 Node/TypeScript policy as the C# successor tests/ArcForges.Web.Policy.Tests, with one xUnit refusal per rule family and sub-rule and accepted forms that must stay admitted. - Architecture: workspace (one solution, lock per project, one npm lock, manifest inventory), exact pins (SDK, Node, npm, central versions, PackageDownload), obsolete Blazor targets (Blazor Server forbidden), portable references, production and install commands, SDK-to-UI licence separation, wire-source rules, private and server imports, desktop DOM prohibition, computed and unresolved imports and the release route graph (Architecture/*.cs, ArchitecturePolicy.cs). - Licence boundary over eng/policy/licence-boundary.json (Licence/). - Forbidden-term scanner: NamingScannerTests verifies the published naming authority identity and runs the published scanner under python -I on a Git fixture for the current terms and every forbidden term. - Fixtures: Fixtures/PolicyBaseline.cs (passing repository) and Fixtures/PolicyCases.cs (refusals and accepted forms). - RepositoryPolicyTests runs the audit over the real tracked and nonignored inputs; it must report zero findings. - ci.yml csharp job: setup-node from .node-version and npm ci --ignore-scripts, so the naming authority is in node_modules for the test. - docs/development.md: factual C# policy suite paragraph. Admission: successor receipt eng/policy/dependency-reviews/web-40-admission-r8.json supersedes r7 (reviewer w-deku-20261008-rev-web-40); only the ci.yml digest changed. eng/policy/dependency-policy.json binds r8 and the rebound digest. ADP-07 supporting files (write scope, recorded per commit): .github/workflows/ci.yml docs/development.md eng/policy/dependency-policy.json eng/policy/dependency-reviews/web-40-admission-r8.json eng/provenance/files.json (12 first-party paths added) tests/ArcForges.Web.Policy.Tests/Architecture/*.cs tests/ArcForges.Web.Policy.Tests/Fixtures/*.cs tests/ArcForges.Web.Policy.Tests/Licence/LicencePolicy.cs tests/ArcForges.Web.Policy.Tests/ArchitecturePolicyTests.cs tests/ArcForges.Web.Policy.Tests/NamingScannerTests.cs tests/ArcForges.Web.Policy.Tests/RepositoryPolicyTests.cs Validation (local, Windows, .NET 10.0.401 locked): dotnet restore --locked-mode, build and test of the Policy project: 97/97 passed (includes RepositoryPolicyTests with zero findings). Validation (local, WSL2 Debian copy, SDK 10.0.400 with the pin rewritten in the copy, locked restore): restore, build and test 97/97 passed. node --test tooling/dependency-policy.test.ts: 43/43 (and dependency policy: 351 dependencies, 39 inputs). Provenance tests 43/43, vitest unit 139/139, biome lint and tsc clean. Not run locally: tooling/project.ts policy after its Node-version assertion. The local toolchain is Node 24.20.0 against the 24.21.0 pin, so that assertion fails locally and the later steps did not run; hosted CI is authoritative. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…tes (U5, step 1) Before the React sources are removed, the C# static Site is compared with the React prerender of 80900a1 (docs/web-40-site-parity.md): - index, hello and cloud-hello have equal element skeletons (99, 112 and 94 elements), equal visible text, titles, metadata, anchors, form controls, landmarks and noscript text. Only the React hydration scripts and modulepreload links differ (TB-01). - 404.html, 404.css, robots.txt and favicon.svg are byte identical. - The public stylesheet is now the React build's Tailwind v4.3.3 output, byte identical (site.d4912dbd6dc5e22b.css). The previous hand-written approximation differed in the system font stack, the placeholder colour and 15 selectors, which would have changed rendering. - The 17 security and cache header lines are identical to the React securityHeaders template; the CSP differs only by the seven React hydration script hashes, because the public pages carry no script. SiteOutputTests expects the Tailwind range-syntax breakpoint of the reviewed stylesheet. The Site suite passes 65/65. docs/web-40-site-parity.md records the open decision on the interactive /hello and /cloud-hello checks, which the static Site cannot run. eng/provenance/files.json lists the new record. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ling tests, with successor receipt web-40-admission-r9 (U5, step 2)
Replaces the React profile budgets (apps/app/budgets.json and measure.ts)
with a measured, reviewed Blazor baseline enforced by the C# tool.
- tools/ArcForges.Web.Tooling/Profiles/ProfileBudget.cs: the initial set of
the published application (every file except precompressed siblings),
measured in-process with GZip SmallestSize. ProfileBudgets.Parse refuses a
missing, extra or non-positive field and a profile set other than the
bundle's. A metric may grow by at most regressionPercent, rounded down.
- Program.cs: profiles budget --publish <dir> --budgets <file> (exit 1 on a
breach).
- eng/policy/profile-budgets.json: the baseline measured on the SDK 10.0.401
publish at this source (57 requests, 719 HTML bytes, 2245 CSS, 125944 JS,
3227235 WASM, 848189 data and 238 other gzip bytes; total 4203851). The
React interaction ceilings are re-baseline-pending (owner PRF.11, AL-06).
- .github/workflows/ci.yml: the candidate job enforces the budgets after the
App publish; the csharp job restores, builds and tests the new tooling test
project.
- ProfileBundle: every _framework file must be fingerprinted (ten lower-case
characters before the extension, .br and .gz siblings included) or be one of
the two unfingerprinted loaders; the headers add an immutable rule for
/_framework/* and no-cache overrides for blazor.webassembly.js and dotnet.js.
- tests/ArcForges.Web.Tooling.Tests: 21 xUnit cases with a passing and a
failing example per rule (budget parse, the ten percent limit, the measure,
the fingerprint rule, the headers). Policy suite 97/97; tooling 21/21; both
restored with --locked-mode.
ADP-07 supporting files (write scope):
.github/workflows/ci.yml
eng/policy/dependency-policy.json (rebound to r9; inputs recomputed)
eng/policy/dependency-reviews/web-40-admission-r9.json (supersedes r8;
reviewer w-deku-20261008-rev-web-40; npm coordinates unchanged)
eng/policy/licence-boundary.json (tooling test project row)
eng/policy/profile-budgets.json
eng/provenance/files.json
tests/ArcForges.Web.Tooling.Tests/** (project, lock, root helper, tests)
tools/ArcForges.Web.Tooling/Profiles/ProfileBudget.cs, ProfileBundle.cs,
Program.cs
Validation (Windows, dotnet 10.0.401, through the build slot): the App
publish, the budget measure, the bundle build and verify, the dependency
policy, the provenance and licence audits (run from the scratchpad) all
passed. Node 24.20 against the 24.21 pin is a local gap; the policy script's
Node assertion is not run locally.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…dored naming, add the formatting and whitespace gates, with successor receipts (U5, checkpoint) Checkpoint of unit U5. The C# validation run that gates this commit is not complete; see the remaining list below. - Identity: tooling/build-identity.ts reads the Contracts axes from the NuGet CON.07 publication record eng/contracts/ArcForges.Contracts.PublicApi/1.0.0-ci.287.1 (byte copies of build-identity.json and source.json, sourceCommit ca45f36) and pins it against the central Directory.Packages.props entry. Bound by contracts-publication-r1. - Naming: eng/naming holds byte copies of tools/naming from the NuGet package ArcForges.Contracts.Validation 1.0.0-ci.287.1; digests pinned in eng/policy/naming-candidate.json. NamingScannerTests and tooling/project.ts read it. - package.json and package-lock.json: @arcforges/api-client and @arcforges/proto removed (lock: 115 entries, removals only). Dependency policy and receipt web-40-admission-r10 derived from the lock by the repository digest functions (114 entries). - Formatting: CI csharp job runs dotnet format --verify-no-changes per project; Prettier and Biome are gone; the policy suite enforces final newline and no trailing whitespace (ArchitecturePolicy.Whitespace.cs, with refusal and accepted fixtures). - Provenance: cloud-dependency-policy-r3 supersedes r2 and cloud-build-identity-r5 is refreshed; NOTICE regenerated with writeNotice. - Wrangler root template repointed to ./artifacts/site (already staged). Local validation in this checkpoint: - typecheck, check:dependencies, test:dependencies, test (88 + 15 passing), provenance audit, licence and naming steps of policy: passed. - npm run policy stops at its Node 24.21 pin assertion (local Node 24.20 gap). Remaining before U5 can be marked complete: - C# restore --locked-mode, build, dotnet format and the Policy and Tooling test runs. - Full CI-equivalent run: npm ci, publish, Site build twice, budgets, candidate build and verify, profile bundle, wrangler dry-run. - Final doc pass and the U5 commit message. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…, the npm Contracts packages and the Prettier and Biome gates (U5 final) The C# static Site reproduces the React prerender (docs/web-40-site-parity.md): element skeletons, visible texts, metadata, the stylesheet bytes and the header lines are equal. Only the hydration scripts and the CSP script hashes differ (TB-01). The public pages carry no JavaScript; the live /hello and /cloud-hello controls are retired by the coordinator adjudication of 2026-10-09 (brief section 10), and ArcForges.Web.App remains the only interactive browser application. Removed: apps/site, apps/app, packages/ui, the Vite, Vitest, React Router, Tailwind and Playwright sources, the Node tests and TypeScript tooling that served them, the Prettier, Biome and ArcForges.Web.esproj configuration. docs/web-40-react-retirement.md maps every retired test to its C# or node:test successor. - package.json reduced to wrangler, TypeScript and @types/node (the Worker build and Node tooling). @arcforges/api-client and @arcforges/proto are retired (package-lock.json regenerated with the pinned npm 11.19.0). The sharp override is kept. - tooling/build-identity.ts reads the Contracts axes from the NuGet CON.07 publication record eng/contracts/ArcForges.Contracts.PublicApi/1.0.0-ci.287.1 (sourceCommit ca45f36, verified against the Plan ledger con-07.md) and pins it to the central Directory.Packages.props entry. - eng/naming holds byte copies of the NuGet ArcForges.Contracts.Validation 1.0.0-ci.287.1 naming tools, pinned in eng/policy/naming-candidate.json. - Formatting gate: CI runs dotnet format --verify-no-changes for every C# project. The policy suite enforces the final-newline and no-trailing-whitespace rules (ArchitecturePolicy.Whitespace.cs). The thin TypeScript Worker is type checked by npm run typecheck. - wrangler.json: the assets directory is the C# Site output (./artifacts/site); main stays ./worker/index.js. - Blazor profile size budgets: eng/policy/profile-budgets.json holds the recorded baseline, enforced in CI before the bundle. The immutable cache rule covers fingerprinted /_framework files (the two unfingerprinted loaders are no-cache), in the Site and in the profile bundle _headers. Receipts (each names reviewer w-deku-20261008-rev-web-40): web-40-admission-r10 (dependency policy rebound from the new lock), cloud-dependency-policy-r3, cloud-build-identity-r5 (the tooling digest changed by the pin move), browser-resources-r12 and contracts-publication-r1. Earlier receipts stay as immutable history. Docs: README, AGENTS.md, CONTRIBUTING, development, provenance, licence-boundary, validation, THIRD_PARTY_NOTICES and the profile bundle layout. Historical docs are marked superseded. Local validation is recorded in the WEB.40 U5 unit report. Node 24.20 is local against the 24.21 pin; the pin assertion is recorded as a local environment gap, and hosted CI is authoritative. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ace rule, tooling test visibility and the formatting gate (U5, fix 1) Found by the CI-equivalent run of U5 (dotnet format, restore, build, test and policy): - .editorconfig: the repository-wide indent_size = 2 (the React-era setting) applied to the C# sources, which use the standard 4-space indent. A [*.cs] section sets indent_size and tab_width to 4. The CRLF line endings the formatter reported are normalised (end_of_line = lf) and only indentation changed in the formatter's output (PolicyBaseline.cs, NuGetClosureAdmissionTests.cs). - ArchitecturePolicy: the root package.json may omit the workspaces field. The React workspaces are retired, so the root is the only npm project. A non-array workspaces value is still refused, and the workspace inventory stays exact (negative fixture workspace-root-workspaces-not-array). - ArcForges.Web.Tooling.csproj: InternalsVisibleTo ArcForges.Web.Tooling.Tests, so the archive tests reach the internal TarArchive writer. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ce, so the reviewed tooling project file is unchanged (U5, fix 2) The CI-equivalent run found that the InternalsVisibleTo item in ArcForges.Web.Tooling.csproj changed a reviewed dependency input (tools/ArcForges.Web.Tooling/ArcForges.Web.Tooling.csproj) of the dependency policy, and the change is not a dependency change. The project file is restored to its reviewed content, and the same visibility is declared by one assembly attribute in Profiles/TarArchive.cs, the file that defines the internal writer and reader. No receipt changes. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… carries the connection check; the retirement is recorded (U5, docs) - docs/cloud-hello.md: the current behaviour states that /hello and /cloud-hello are static C# pages since U5, that the Blazor App is the only interactive browser application and supplies the connection check through the NuGet client ArcForges.Contracts.PublicApi 1.0.0-ci.287.1, and that the 2026-09-18 browser observation predates the retirement. The npm Browser SDK row is replaced. - docs/web-40-site-parity.md: the interactive-control paragraph records the retirement (brief section 10, 2026-10-09) instead of an open decision. - docs/web-40-react-retirement.md: the coordinator adjudication of 2026-10-09 confirms the retirement. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…andidate tests, and the Account and Chat suites assert the keyboard focus order (U6, review fixes) - ci.yml: the Linux source job restores and builds tools/ArcForges.Web.Tooling (locked, Release) with the pinned SDK before npm run check, so tests/provenance/csharp-candidate.test.ts never depends on stale bin/ output. - csharp-candidate.test.ts: a missing tool build fails at load with the build command. - FocusOrder: bUnit tab-sequence, reading-order, positive-tabindex and default-button helpers. - Account: anonymous, signed-in and failed-read states have their exact tab sequence; Sign out is a native type=button. - Chat: the tab sequence is Name then Send, Cancel only while pending; Enter in the name field submits through the form's default Send button; the transcript is the polite live region. This is the successor of the retired keyboard greeting case. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…source-job change, and the classified focus-order helper (U6, review fixes) - eng/policy/dependency-reviews/web-40-admission-r11.json: the successor of web-40-admission-r10 (its bytes are unchanged). The only input change is .github/workflows/ci.yml, whose digest is computed by the repository's tooling/dependency-policy.ts digest(). The reviewer field names w-deku-20261008-rev-web-40, the pre-assigned independent reviewer. - eng/policy/dependency-policy.json: reviewRecord, the ci.yml input digest and the review object follow the successor. - eng/provenance/files.json: classifies the successor receipt and tests/ArcForges.Web.App.Tests/FocusOrder.cs. - docs/web-40-react-retirement.md: the Account and Chat row records the focus-order successor of the retired keyboard case. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…in the retirement decisions (U6, review fixes) bUnit asserts the keyboard sequence but does not move browser focus. The retirement record now states the two focus losses that remain (a focused Send button disabled while pending, and a removed Sign out button after the session ends) as a recorded decision for the coordinator. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…e document, with an AX-02 focus record and browser check (U6, review fix) Send, Sign out and Try again could lose keyboard focus: a focused control that became disabled or was removed dropped focus to the body (AX-02). Send was disabled while a message was pending, Sign out was disabled while signing out and removed once the session ended, and Try again was removed when its read began. - Chat: Send is aria-disabled while a message is pending, not disabled. The existing send guard refuses a second send, so no message is sent twice. - Account: Sign out and Try again are one action element for the visit. Its label and aria-disabled state change; the element is never removed, so focus stays on it through the sign-out, a failed sign-out and a retry. A click on an aria-disabled control is refused by the handler. - Both pages refresh their state when an operation starts, so the disabled state is rendered while the operation runs. - app.css: aria-disabled buttons look disabled, so the visual state matches the refused action. - bUnit (CI): the controls stay present and reachable at each step, and refused actions do nothing. bUnit re-parses markup on every render, so it cannot prove element identity; that is asserted by the local opt-in LocalFocusBrowserTests (Chromium, keyboard focus identity, same-origin answers fixed by routes). - ArcForges.Web.Browser.Tests: ARCFORGES_CHROMIUM_PATH selects an installed Chromium for the focus check only. Local-only; never built in CI. - docs/web-40-ax-02-focus.md records each control state, the checks and the run result. docs/web-40-react-retirement.md item 8 is updated; the Cancel focus drop in Chat stays open for the coordinator (a persistent aria-disabled Cancel or a combined Send/Cancel control). - eng/provenance/files.json classifies the new record and browser test. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…er: byte parity is not shown after removing the hydration nodes, and a coordinator waiver is needed (review fix, not complete) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ests, the normalised-DOM site parity gate, the local axe accessibility suite (Deque.AxeCore.Playwright) and successor admission web-40-admission-r12 with policy and provenance updates (U6, captured as found; full local validation and the accessibility/parity runs not yet passed) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…les for the centrally pinned AngleSharp (CentralTransitive, same version 1.7.0, no new admission; locked restore fails without it) (U6, fix) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… browser tests (U6, fix) - SiteParityTests: the anchor href check read Lines[0], which is the html element because the parser wraps the anchor in html, head and body. It now checks the anchor's own line for the verbatim href and that no stylesheet placeholder applies to a non-stylesheet href. The parity rule is unchanged. - LocalAccessibilityBrowserTests: Deque.AxeCore.Commons 4.13.0 exposes AxeResult.Violations, Passes, Incomplete, Inapplicable and AxeResultNode.Nodes as arrays, so .Count bound to the LINQ method group (CS1503, CS8978, CS0019). These now use .Length. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…and repair the r12 NuGet contentHash rows (successor admission web-40-admission-r13) - SiteParityTests: the React stylesheet named by the prerender and the candidate's content-hashed stylesheet are excused on their own side only, through CompareFileSets. Every other file-set rule stays strict: the reference-only files must be exactly the React runtime files and the candidate may have no other file. An unmatched pair fails, and the pair bytes are still compared. Four unit tests cover the pair handling. - web-40-admission-r13 (successor of r12, reviewer w-deku-20261008-rev-web-40): the contentHash of Deque.AxeCore.Commons, Deque.AxeCore.Playwright, Newtonsoft.Json and System.IO.Abstractions is the restored lock value (confirmed against .nupkg.metadata), not the .nupkg.sha512 value r12 recorded. Three stale bound lock digests (App.Tests, Operations.Tests, Ui.Tests) are re-bound. dependency-policy.json points at r13. - eng/provenance/files.json: r13 is classified; the entry for docs/web-40-accessibility.md is removed because the file was never committed (the WCAG 2.2 AA per-screen record is still to be written and must be re-listed with it). Checks run: SiteParityTests (10 passed, parity reference set, 0 skipped); NuGetClosureAdmissionTests.RestoredClosureMatchesTheAdmittedRecords (passed); node tooling/dependency-policy.ts (passed); provenance audit (passed); node --test tooling/dependency-policy.test.ts (15 passed). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… App input boundaries to 3:1, and name the axe rules per screen (U-fix) - app.css: .field input and .input-row input borders move from #b9c1b4 (1.85:1 on white, 1.66:1 on the page) and #a3b1a4 (2.20:1 on the field fill) to #6b7a72 (4.51:1 on white, 4.44:1 on #fffdf7, 4.06:1 on the page). The disabled button fill #6b7a72 (4.06:1 on the page) and the focus outline #235844 (7.41:1 on the page, 7.43:1 on the error banner) already met 3:1 and are unchanged. - index.html: the unhandled-error Dismiss is <button type="button" class="dismiss" aria-label="Dismiss">. The Blazor selector #blazor-error-ui .dismiss is unchanged (blazor.webassembly.js binds its onclick to that selector). app.css resets the button so it looks as the anchor did. No other anchor without an href exists in the App, Ui or Site sources. - LocalAccessibilityBrowserTests: each axe result writes a second line with the sorted rule IDs that passed, were incomplete, inapplicable and violated. New axe states: Chat failed send, and the error banner (shown through window.Blazor._internal.dotNetCriticalError, then Dismiss is focused and Enter hides the banner). The zero-violation assertion is kept. These local opt-in tests are built but not run in this commit. - HostPageAccessibilityTests: Dismiss markup, no href-less anchors in the host page, and 3:1 checks of the boundaries, fills and focus rings parsed from app.css. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… region so axe's region rule passes - index.html: the unhandled-error text sat directly in #blazor-error-ui, outside every landmark, region, live region or alert, and the Reload anchor (href="") was flagged by the axe 4.13.0 region rule once the banner text moved. The message and the Reload link are now inside <span role="alert">, an inline element, so the banner's markup, its #blazor-error-ui selector, the .dismiss button, its fixed position and its appearance are unchanged. - HostPageAccessibilityTests: TheErrorBannerMessageIsAnAlertAndNoTextSitsDirectlyInTheBanner asserts the alert holds the message and the Reload link, that the banner has no text node of its own, and that every link in the banner sits inside the alert. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…-state axe rule names, and list the record in provenance - docs/web-40-accessibility.md: 14 screen states (Account, Chat including the failed send, the App error banner, Site), each with the axe counts and the rule names that passed, were inapplicable, were incomplete and were violated (zero violations). pass (axe) cells are derived from the state's passed list; target-size and audio-caption were not evaluated by the run and are not claimed. - Adds pass (browser test) for the banner Dismiss keyboard assertion, the one check that is neither axe nor inspection. - Records the tool versions, the local opt-in status (P2-017), and that the Chrome version of the run is not recorded. - Open judgement items and the human AT session stay as not verified. Adds an Operations follow-up: its banner Dismiss (index.html:18) has the pre-fix markup and is outside WEB.40 scope. - eng/provenance/files.json: lists docs/web-40-accessibility.md after Directory.Packages.props (as 33c57df did) and tests/ArcForges.Web.App.Tests/HostPageAccessibilityTests.cs, which 49f72bf added without an inventory entry, so the provenance audit's inventory matches git. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…convention for all admitted rows, a restored-nuspec comparison in the policy suite, and the browser-resources-r11 gitleaks path exception (review fixes) - nuspecSha256 for all 71 admitted closure and pack-download rows is the SHA-256 of the restored .nuspec bytes with the UTF-8 BOM kept. Sixteen rows held the BOM-stripped digest in r13; they are corrected. The CON.07 rows restored locally follow the same convention; the six not restored locally are kept and marked unverified. - NuGetClosureAdmissionTests compares each admitted nuspec digest and each restored CON.07 digest with the NuGet packages folder, and requires the policy rows to equal the active receipt. Verified by a mutation run: a planted wrong digest fails two tests, and the restored file passes. - .gitleaks.toml: the reviewed public source-hash path exception covers browser-resources-r11 as well as r1 to r10, with the same eleven exact-line regexes. Needs the named independent exact-head review (w-deku-20261008-rev-web-40); gitleaks is not installed locally. - r13 stays as immutable history; dependency-policy.json and files.json point at r14. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
Reviewed 6ff8e1e for [WEB.40] epoch 1: approved Reviewer: independent session w-deku-20261008-rev-web-40, which authored none of this. Rounds: round 1 at 58f44c4 had a material finding in the admission records (nuspec digest convention). It was fixed in 6ff8e1e by successor receipt Verified at the exact head:
Non-blocking (recorded; see the PR body):
Posted by the coordinator under the 2026-10-08 publication protocol. |
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
…e candidate suite
The csharp-candidate suite calls expectedIdentity("0.1.0-local") at module load. Under GITHUB_ACTIONS=true
the producer check requires a CI-shaped version, so the whole suite failed in the hosted Source job. The
suite builds a local candidate, so it now reads the identity with the GITHUB_* variables removed and
restores them before returning. Production identity code is unchanged.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…er on Windows, with a recorded reason The hosted windows-latest job failed EveryAdmittedNuspecDigestIsTheRestoredNuspecDigest: the admitted microsoft.netcore.app.runtime.mono.browser-wasm/10.0.12 pack was not in a clean NuGet packages folder after the locked restore. The SDK adds that implicit runtime pack as a NuGet download only when its packs folder lacks the bundled version. The hosted Windows image preinstalls the wasm.tools workload into C:\Program Files\dotnet, which holds the 10.0.12 browser-wasm pack, so Windows restores no NuGet copy. Ubuntu has no workload and restores it. Reproduced with a clean NUGET_PACKAGES folder and the ci.yml C# step order: a restore with the 10.0.12 pack visible to the SDK leaves the NuGet copy absent (the hosted message), and a restore without it downloads and digests it. The test now carries an explicit PacksFolderRows table with one reason for Windows. It skips the NuGet copy only for an explicit row on the current platform whose packs copy exists at the admitted version, and reads the packs folder the way the SDK does (NetCoreTargetingPackRoot when set, else <dotnet root>/packs). Every other admitted row still needs its NuGet copy and digest. A drift test requires each table row to be an admitted pack-download row. The admitted policy rows, the receipts and ci.yml are unchanged. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…lication record for the history scan The hosted "Dependency audit and repository checks" job failed with gitleaks reporting one leak and no detail. Offline emulation of gitleaks v8 git scanning (upstream default rules, the repository .gitleaks.toml, added lines of origin/main..HEAD) found exactly one finding: rule generic-api-key at commit 2a5e17f in eng/contracts/ArcForges.Contracts.PublicApi/1.0.0-ci.287.1/source.json, line 9. The key "public/http/v1/native-auth.schema.json" contains the keyword auth, and its 64-hex value passes the entropy threshold. It is a false positive. The value is the SHA-256 of the public native-auth schema, and it equals the SHA-256 of the schema entry in the restored arcforges.contracts.publicapi 1.0.0-ci.287.1 package. All 21 recorded schema sources of that publication match their packaged bytes. The new allowlist is the narrowest form: its own [[allowlists]] block, targeting generic-api-key only, with AND over the exact source.json path and the exact line with the exact digest. The emulator calibrates against the reviewed count: without this file's allowlists, browser-resources-r11 gives 14 lines, as the r14 review recorded. This is a governed scanner-exception change. The independent exact-head review is required before merge. .gitleaks.toml is not bound by a provenance record or the dependency-policy inputs, so no successor receipt is written. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ts scanner exception and the packs-folder rows, require the pack content marker, and correct the r14 contentHash convention Reviewed base 389b9fd (reviewer w-deku-20261008-rev-web-40). r15 supersedes r14 and leaves r14 unedited. No package, version, source, licence, contentHash, nuspecSha256, closure coordinate or bound input changed. - .gitleaks.toml scanner exception (commit 389b9fd) is recorded in r15: rule generic-api-key, AND over the exact source.json path and one exact line regex; the value is the SHA-256 of the packaged native-auth schema (verified false positive). - NuGetClosureAdmissionTests: PacksFolderRows gains an explicit Linux row beside the Windows row, each with a recorded reason. A packs copy counts only with its content marker runtimes/browser-wasm/native/dotnet.native.wasm, not the folder alone. The redundant final Assert.All is removed. - r14 rationale correction: each row contentHash equals the .nupkg.metadata and lock contentHash, not the SHA-512 of the .nupkg file; nuspecSha256 is over the restored .nuspec bytes including the BOM. - dependency-policy.json points reviewRecord and review at r15; eng/provenance/files.json lists r15. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
Reviewed efe7872 for [WEB.40] epoch 1: approved (delta review over the approved 6ff8e1e, including the named exact-head exception review of the Reviewer: independent session w-deku-20261008-rev-web-40. Hosted failures at 6ff8e1e, each root-caused and reproduced under CI conditions:
Verified at efe7872, through the build slot:
Non-blocking:
Merge waits for the planning repair P2-026, because WEB.40's retained Node build tooling is recorded there (coordinator adjudication S17). Posted by the coordinator under the 2026-10-08 publication protocol. |
…gs off the profile root S20(a) of the migration brief (CLOUD.85 decisions D2 option A and D3): - Add web-site-<sha256>.tar, a deterministic ustar archive of the C# static Site output written by the same TarArchive writer as web-profiles. Entries are the Site files in ordinal path order with fixed metadata. The candidate build seals it as a root member beside the assets directory, so the seal records its digest. The verifier regenerates the Site and refuses a second archive, a name that is not the digest, or any bytes other than the regenerated archive. The Cloudflare deploy still serves only the assets directory, so nothing served changes. - Publish web-site-<sha256>.tar in the same main-push release as web-profiles, and only there (ci.yml). - Exclude the root index.html.br and index.html.gz from the web-profiles bundle. The shell is not served at the root, and its encodings are not either. Every other publish entry is kept. Verify refuses an archive that serves either encoding at the root. - Tests: Site archive determinism, name equal to digest, exact read-back; seal and verify coverage (changed, resealed, renamed, duplicated archive refused); bundle exclusion and its refusal. - Successor receipt web-40-admission-r16 (chained from r15, r15 unchanged) for the changed ci.yml input, reviewer w-deku-20261008-rev-web-40, and the provenance inventory update. Docs updated. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…d admit web-40-admission-r17 The release step located web-site-<sha256>.tar with ls, which actionlint flags as SC2012 in the hosted quality job. It now collects the archive with a nullglob bash array, requires exactly one archive, and requires the archive name to equal web-site-<sha256 of its bytes>.tar, all fail-closed. Only that script changes in ci.yml. The successor receipt web-40-admission-r17 chains from r16 and changes only the ci.yml input hash, the review metadata that names its predecessor, and the dependency-policy and provenance inventory entries that point at it. r16 is not edited. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
Reviewed 4cca32e for [WEB.40] epoch 1: approved (delta review over the approved efe7872; coordinator decision S20(a)). Reviewer: independent session w-deku-20261008-rev-web-40. The delta:
Verified:
Non-blocking:
Posted by the coordinator under the 2026-10-08 publication protocol. |
|
Reviewed c58e528 for [WEB.40] epoch 1: approved (delta review over the approved 4cca32e). Reviewer: independent session w-deku-20261008-rev-web-40. Hosted actionlint reported SC2012 ( The extracted step was run under
Also verified:
Merge waits for planning repair P2-026 (coordinator adjudication S17). Posted by the coordinator under the 2026-10-08 publication protocol. |
Claim: WEB.40 epoch 1 (w-deku-20261008-web-40)
Task record: web lane, task-web-40. Authority: P2-021 (C#-first: Web moves to Blazor WebAssembly; TypeScript only for the thin Cloudflare Worker adapter), plus the coordinator adjudications recorded for WEB.40 (sequencing, deploy switch, Site interactivity, parity waiver, focus option (a), accessibility re-proof).
What this changes
Public Site: a static C# Site, generated by the first-party Razor HtmlRenderer generator in
tools/ArcForges.Web.Tooling. Its output is deterministic, as a repeated build shows. It needs no Blazor boot for public pages.Account and Chat: Blazor WebAssembly profiles (
src/ArcForges.Web.App) on generated C# gRPC-Web clients, with session and CSRF handling, CSP, exact int64/uint64/decimal, and typed failure states. The Operations profile skeleton is in place. The owned design system isArcForges.Web.Ui.Worker: the canonical-host Worker is converted to TypeScript as a thin adapter, with no business decision and no authoritative state.
Deploy switch: the candidate seal and verifier, CI and the main-push Cloudflare deploy now operate on the C# Site and Blazor outputs. The guards are unchanged: sealed candidate, verification before upload, main-push only, no workers.dev and no previews.
React retirement: the React apps, the npm test toolchain, the npm Contracts packages and the Prettier and Biome gates are retired. The record is in
docs/web-40-react-retirement.md.Parity: normalised-DOM parity against the recorded React prerender (
docs/web-40-site-parity.md) shows 0 differences on/,/hello/,/cloud-hello/and/404.html, with byte-identical static assets and stylesheet pair.Accessibility re-proof (P2-021 item 8):
docs/web-40-accessibility.mdcovers 14 screen states with 0 axe violations (axe-core 4.13.0 in Chrome 156.0.8078.12, local opt-in), and a WCAG 2.2 A and AA checklist per state. Fixed on the way:The judgement items and the human assistive-technology session remain open and are not claimed.
Policy: the GOV.11 policy suite is ported to C#. NuGet admission successor receipts run up to
web-40-admission-r14, all naming the reviewer.Scope notes
global.json(SDK 10.0.401),Directory.Build.props,.editorconfig, the vendoredeng/namingtool (digest-pinned byeng/policy/naming-candidate.json), theeng/contractsPublicApi copy,eng/version-sources.json, and the rootREADME.md,AGENTS.md,CONTRIBUTING.mdandTHIRD_PARTY_NOTICES.md. The retired React, Prettier, VS Code and Playwright configurations are deleted.packages.lock.jsonand.nupkg.metadatacontentHash, not the.nupkgfile SHA-512, and nuspecSha256 is the SHA-256 of the restored.nuspecbytes including the BOM. The next Web successor receipt corrects the sentence; committed receipts are not rewritten.Validation actually performed
full-localpassed: locked restore,dotnet format, build, candidate publish, all test suites, profile publishes, Site build with determinism repeat and diff, browser build;a11y-paritypassed: the parity and axe suites.test:dependencies15/15, npm tests 88/88, andlicence-evaluated;🤖 Generated with Claude Code