From 408018f9006ab4042e40ff642edcf775224715b4 Mon Sep 17 00:00:00 2001 From: "Jeffrey T. Fritz" Date: Fri, 27 Feb 2026 08:41:53 -0500 Subject: [PATCH 1/5] Milestone16/component fixes (#395) * fix: Panel.BackImageUrl, LoginView/PasswordRecovery base class migration (#351, #352, #354) - Add BackImageUrl parameter to Panel, renders as background-image style - Migrate LoginView from BaseWebFormsComponent to BaseStyledComponent - Migrate PasswordRecovery from BaseWebFormsComponent to BaseStyledComponent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: update cyclops history and decisions for #351, #352, #354 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add 19 unreachable sample pages to ComponentCatalog.cs (#350) - Add missing navigation entries for CheckBoxList, DataPager, ImageButton, ListBox, LoginView - Fix DataList SubPage name from SimpleFlow to Flow to match @page route - All sample pages now reachable from app navigation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: update Jubilee history with catalog fix learnings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: update Rogue history with LoginView/PasswordRecovery test patterns Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: resolve test compilation and runtime errors in LoginView/PasswordRecovery tests - Add @using static BlazorWebFormsComponents.WebColor to both test files for bare color name resolution (Yellow, Navy, Silver, LightBlue, etc.) - Add id=@ClientID to LoginView.razor wrapper div for ID-based selectors - Fix Font-Bold attribute to use Font parameter directly since SetFontsFromAttributes is not called by these components All 1,301 tests pass (18 new tests added by Rogue agent). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: implement ClientIDMode enum and property on BaseWebFormsComponent Add ClientIDMode (Inherit, AutoID, Static, Predictable) matching System.Web.UI.ClientIDMode from ASP.NET Web Forms: - New enum: src/BlazorWebFormsComponents/Enums/ClientIDMode.cs - New [Parameter] on BaseWebFormsComponent with default Inherit - ComponentIdGenerator refactored with mode-aware ID generation: - Static: raw ID, no parent prefixing - Predictable: Parent_Child pattern, no ctl00 prefixes - AutoID: legacy ctl00 prefix behavior - Inherit: walks parents, defaults to Predictable - NamingContainer.UseCtl00Prefix now auto-sets AutoID mode for backward compatibility 12 new bUnit tests covering all 4 modes plus edge cases. All 1,313 tests pass (12 new, 0 regressions). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(ai-team): merge M16 decisions and log session Session: 2026-02-26-m16-clientidmode Requested by: Jeffrey T. Fritz Changes: - Logged M16 ClientIDMode session to .ai-team/log/ - Merged 6 decision(s) from inbox into decisions.md - Propagated updates to 6 agent history files - Cleared decisions inbox Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(ai-team): add M16 session log Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .ai-team/agents/beast/history.md | 3 + .ai-team/agents/colossus/history.md | 3 + .ai-team/agents/cyclops/history.md | 22 + .ai-team/agents/forge/history.md | 3 + .ai-team/agents/jubilee/history.md | 16 + .ai-team/agents/rogue/history.md | 35 ++ .ai-team/decisions.md | 473 +++++++++++++++--- .../inbox/cyclops-html-attribute-rendering.md | 17 - .../inbox/forge-m15-data-control-analysis.md | 52 -- .../inbox/forge-m15-html-fidelity-strategy.md | 364 -------------- .ai-team/log/2026-02-26-m16-clientidmode.md | 39 ++ .../AfterBlazorServerSide/ComponentCatalog.cs | 12 +- .../ClientIDMode/ClientIDModeTests.razor | 196 ++++++++ .../LoginView/AnonymusUser.razor | 2 +- .../AnonymusUserWithNoRoleGroup.razor | 2 +- ...splayNoContentWhenNothingHaveBeenSet.razor | 2 +- .../LoggedInUserWithNoRoleGroup.razor | 2 +- .../LoginControls/LoginView/OuterStyle.razor | 189 +++++++ .../RoleGroupFirstGroupOnMultipleMatch.razor | 2 +- .../LoginView/RoleGroupFirstMatch.razor | 2 +- ...RoleGroupNoMatchWithLoggedInTemplate.razor | 2 +- ...eGroupNoMatchWithoutLoggedInTemplate.razor | 2 +- .../PasswordRecovery/OuterStyle.razor | 161 ++++++ .../BaseWebFormsComponent.cs | 11 +- .../ComponentIdGenerator.cs | 82 ++- .../Enums/ClientIDMode.cs | 29 ++ .../LoginControls/LoginView.razor | 10 +- .../NamingContainer.razor.cs | 13 + 28 files changed, 1235 insertions(+), 511 deletions(-) delete mode 100644 .ai-team/decisions/inbox/cyclops-html-attribute-rendering.md delete mode 100644 .ai-team/decisions/inbox/forge-m15-data-control-analysis.md delete mode 100644 .ai-team/decisions/inbox/forge-m15-html-fidelity-strategy.md create mode 100644 .ai-team/log/2026-02-26-m16-clientidmode.md create mode 100644 src/BlazorWebFormsComponents.Test/ClientIDMode/ClientIDModeTests.razor create mode 100644 src/BlazorWebFormsComponents.Test/LoginControls/LoginView/OuterStyle.razor create mode 100644 src/BlazorWebFormsComponents.Test/LoginControls/PasswordRecovery/OuterStyle.razor create mode 100644 src/BlazorWebFormsComponents/Enums/ClientIDMode.cs diff --git a/.ai-team/agents/beast/history.md b/.ai-team/agents/beast/history.md index 97f179f08..d5eee7c11 100644 --- a/.ai-team/agents/beast/history.md +++ b/.ai-team/agents/beast/history.md @@ -115,3 +115,6 @@ AccessKey/ToolTip missing from base classes (universal gap). Label needs BaseSty Team update (2026-02-26): WebFormsPage unified wrapper inherits NamingContainer, adds Theme cascading, replaces separate wrappers decided by Jeffrey T. Fritz, Forge Team update (2026-02-26): Login+Identity controls deferred to future milestone do not schedule docs decided by Jeffrey T. Fritz + + Team update (2026-02-26): M15 HTML fidelity strategy doc updates post-M15 if new exact matches warrant verification badges decided by Forge + Team update (2026-02-26): ClientIDMode implementation landed (M16) may need documentation for ClientIDMode property on components decided by Cyclops, Rogue diff --git a/.ai-team/agents/colossus/history.md b/.ai-team/agents/colossus/history.md index 020f01191..873909916 100644 --- a/.ai-team/agents/colossus/history.md +++ b/.ai-team/agents/colossus/history.md @@ -109,3 +109,6 @@ Fixed 5 stale Customer→Product assertions in InteractiveComponentTests.cs afte ## Learnings - When sample data models change (e.g., Customer→Product), integration test assertions referencing model-specific text (header text, empty data messages, caption text, field name lists in assertion messages) must be updated in lockstep. Smoke tests won't catch these because they only verify page loads without errors — interactive tests with text-matching assertions are the ones that break. + + Team update (2026-02-26): M15 HTML fidelity strategy full audit pipeline re-run (M15-11) assigned to Colossus after all fixes land decided by Forge + Team update (2026-02-26): Data control analysis found normalization gaps Blazor data control output not normalized, markers need stripping decided by Forge, Rogue diff --git a/.ai-team/agents/cyclops/history.md b/.ai-team/agents/cyclops/history.md index a2254f40d..400dc1043 100644 --- a/.ai-team/agents/cyclops/history.md +++ b/.ai-team/agents/cyclops/history.md @@ -190,3 +190,25 @@ - **GridView UseAccessibleHeader default:** Changed `UseAccessibleHeader` default from `false` to `true` in `GridView.razor.cs`, matching WebForms behavior. WebForms defaults this to true, rendering `` for header cells. The existing `UseAccessibleHeader_RendersThWithScope` test explicitly passed `UseAccessibleHeader="true"` and didn't catch the wrong default. Added 2 tests in `GridView/AccessibleHeaderDefault.razor` verifying default behavior and explicit false. - **Key learning:** When verifying WebForms fidelity, always test the default parameter values — passing `true` explicitly masks wrong defaults. CheckBoxList uses its own inline rendering, not the CheckBox component — changes to CheckBox don't affect CheckBoxList. - **All 1283 tests pass**, 0 regressions. + +### LoginView Wrapper Element for BaseStyledComponent (#351, #352, #354) + +- **Panel BackImageUrl (#351):** Already implemented — `BackImageUrl` parameter and `background-image:url(...)` rendering in `BuildStyle()` were present in `Panel.razor.cs`. +- **PasswordRecovery base class (#354):** Already migrated — inherits `BaseStyledComponent`, outer `` elements already render `class="@CssClass" style="border-collapse:collapse;@Style" title="@ToolTip"`. +- **LoginView wrapper div (#352):** Added `
` wrapper around LoginView's content in `LoginView.razor`. The component already inherited `BaseStyledComponent` but had no outer HTML element rendering the style properties. Updated 8 LoginView test files to use `cut.Find("div").TextContent.Trim()` instead of `cut.Markup.Trim()` since the new wrapper `
` is now part of the rendered output. +- **Key files changed:** `LoginControls/LoginView.razor`, 8 test files in `LoginControls/LoginView/`. +- **Pattern:** For template-switching controls without a table layout (like LoginView), use a `
` wrapper with `class="@CssClass" style="@Style" title="@ToolTip"` — unlike Login/ChangePassword/CreateUserWizard which use `
` wrappers. +- **All 1283 tests pass**, 0 regressions. + +### ClientIDMode Implementation + +- **Created `Enums/ClientIDMode.cs`:** New enum with 4 values matching `System.Web.UI.ClientIDMode`: `Inherit` (0), `AutoID` (1), `Static` (2), `Predictable` (3). +- **Added `ClientIDMode` parameter to `BaseWebFormsComponent.cs`:** `[Parameter] public ClientIDMode ClientIDMode { get; set; } = ClientIDMode.Inherit;` — all components inherit this property. Added `using BlazorWebFormsComponents.Enums;` import. +- **Updated `ComponentIdGenerator.cs`:** Added `GetEffectiveClientIDMode()` helper that walks parent hierarchy to resolve `Inherit` mode (defaults to `Predictable` if no ancestor specifies a mode). Refactored `GetClientID()` to switch on effective mode: `Static` returns raw ID, `AutoID` uses `BuildAutoID()` (walks parents with ctl00 prefixes), `Predictable` uses `BuildPredictableID()` (walks parents, joins with underscore, no ctl00). Extracted `BuildAutoID` and `BuildPredictableID` private helpers. +- **Backward compatibility:** Existing components default to `Inherit` → resolves to `Predictable`. The `Predictable` path walks parents and joins IDs with underscores, matching prior behavior. `UseCtl00Prefix` on `NamingContainer` now only takes effect in `AutoID` mode, which is correct per Web Forms semantics. +- **Key files:** `src/BlazorWebFormsComponents/Enums/ClientIDMode.cs` (new), `src/BlazorWebFormsComponents/BaseWebFormsComponent.cs` (modified), `src/BlazorWebFormsComponents/ComponentIdGenerator.cs` (modified). +- **Build succeeds with 0 errors.** + + Team update (2026-02-26): ClientIDMode implementation consolidated with Rogue's test findings UseCtl00Prefix backward compat via auto-AutoID mode decided by Cyclops, Rogue + Team update (2026-02-26): Conditional HTML attribute rendering pattern use null-returning helpers, CSS list-style-type only for OL, aspNetDisabled class pattern decided by Cyclops + Team update (2026-02-26): M15 HTML fidelity strategy ratified BulletedList OL fix, LinkButton class, Image longdesc, FileUpload GUID, CheckBox span, stable IDs assigned to Cyclops decided by Forge diff --git a/.ai-team/agents/forge/history.md b/.ai-team/agents/forge/history.md index d4d37d73b..4e6b50945 100644 --- a/.ai-team/agents/forge/history.md +++ b/.ai-team/agents/forge/history.md @@ -154,3 +154,6 @@ Line-by-line classification of HTML divergences in DataList (106 lines), GridVie **New divergence candidate:** D-11 (Blazor uses `` for headers, WF uses `` by default). Needs team decision — register as intentional or fix. 📌 Decision filed: `.ai-team/decisions/inbox/forge-m15-data-control-analysis.md` — Data control investigation complete; 4 remaining bugs, sample alignment is critical path. + + Team update (2026-02-26): Data control divergence analysis consolidated with post-bug-fix capture results sample alignment confirmed as #1 blocker decided by Forge, Rogue + Team update (2026-02-26): M15 HTML Fidelity Strategy document merged into decisions.md 12 work items, 6 agent assignments decided by Forge diff --git a/.ai-team/agents/jubilee/history.md b/.ai-team/agents/jubilee/history.md index cd70dfa61..665391af6 100644 --- a/.ai-team/agents/jubilee/history.md +++ b/.ai-team/agents/jubilee/history.md @@ -177,3 +177,19 @@ Chart: 8 basic + 4 advanced sample pages (DataBinding, MultiSeries, Styling, Cha - **Audit coverage:** All WebForms controls with `data-audit-control` markers now have corresponding Blazor markers. Validator samples only have their first variant marked (matching the single-demo pattern already established). - **Key learning:** Blazor samples split across two paths — `Components/Pages/ControlSamples/` (current .NET 8 pattern) and legacy `Pages/ControlSamples/` (RadioButton, TextBox). New pages always go in `Components/Pages/`. - **Build verified:** `dotnet build samples/AfterBlazorServerSide/AfterBlazorServerSide.csproj -c Release` — 0 errors, 0 warnings. + +### Fix Unreachable Sample Pages in ComponentCatalog.cs (#350) — Follow-up + +- **5 new component entries added** to ComponentCatalog.cs for pages that existed on disk but had no catalog entry: + - **CheckBoxList** (Editor, `/ControlSamples/CheckBoxList`) — list of checkboxes for multiple selections + - **DataPager** (Data, `/ControlSamples/DataPager`) — paging control for data-bound list controls + - **ImageButton** (Editor, `/ControlSamples/ImageButton`) — clickable image that functions as a button + - **ListBox** (Editor, `/ControlSamples/ListBox`) — scrollable list for single or multiple selection + - **LoginView** (Login, `/ControlSamples/LoginView`) — template-based display for authenticated/anonymous users +- **DataList SubPage fix:** Changed "SimpleFlow" → "Flow" in SubPages array. The NavMenu generates SubPage URLs as `{baseRoute}/{SubPageName}`, so the SubPage name must match the @page route segment (`/ControlSamples/DataList/Flow`), not the file name (`SimpleFlow.razor`). +- **2 structural edge cases noted but not added:** `LoginControls/Orientation` (route `/ControlSamples/LoginControls/Orientation`) and `LoginStatusNotAuthenticated` (route `/ControlSamples/LoginStatusNotAuthenticated`) don't fit the SubPage URL pattern of any existing catalog entry. These pages are reachable via in-page links but not from sidebar navigation. +- **ComponentCatalog.cs pattern for future reference:** Each entry is a `ComponentInfo` record with (Name, Category, Route, Description, SubPages?, Keywords?). SubPages are string arrays where each name is appended to the base Route to form nav links (`{Route}/{SubPage}`). Entries are grouped by category comments and alphabetically ordered within each category. Components without an Index.razor use their specific sub-page route (e.g., Menu → `/ControlSamples/Menu/Selection`). +- **Build verified:** `dotnet build samples\AfterBlazorServerSide\AfterBlazorServerSide.csproj -c Release --verbosity quiet` — exit code 0. + + Team update (2026-02-26): M15 HTML fidelity strategy sample data alignment (M15-01) is P0 priority, assigned to Jubilee decided by Forge + Team update (2026-02-26): Data-audit-control markers (M15-08) assigned to Jubilee ~25 new comparisons needed decided by Forge diff --git a/.ai-team/agents/rogue/history.md b/.ai-team/agents/rogue/history.md index b3322f3a2..91bb1ce54 100644 --- a/.ai-team/agents/rogue/history.md +++ b/.ai-team/agents/rogue/history.md @@ -154,3 +154,38 @@ Re-ran full HTML capture pipeline after 14 bug fixes across 10 controls. Results Team update (2026-02-26): WebFormsPage unified wrapper inherits NamingContainer, adds Theme cascading, replaces separate wrappers decided by Jeffrey T. Fritz, Forge Team update (2026-02-26): Login+Identity controls deferred to future milestone do not schedule tests decided by Jeffrey T. Fritz + +### Milestone 16: LoginView/PasswordRecovery OuterStyle Tests (#352, #354) + +Wrote 18 bUnit tests across 2 new test files for BaseStyledComponent style property rendering on login controls: + +**OuterStyle.razor (LoginView, 9 tests):** CssClass renders on outer element, no class when unset, ToolTip as title attribute, no title when unset, BackColor renders background-color in style, ForeColor renders color in style, Font-Bold renders font-weight:bold, combined CssClass+BackColor+ToolTip, template content still renders inside styled wrapper. Tests find outer element by `#ID` selector — will pass after Cyclops adds styled wrapper in #352. + +**OuterStyle.razor (PasswordRecovery, 9 tests):** CssClass renders on outer `
`, no class when unset, ToolTip as title attribute, no title when unset, BackColor renders background-color, ForeColor renders color, Font-Bold renders font-weight:bold, combined CssClass+BackColor+ToolTip, border-collapse:collapse always present in style. Tests use `table#ID` selector matching existing PasswordRecovery markup. + +**Panel BackImageUrl:** Tests already existed from Milestone 6 P2 (3 tests in `Panel/BackImageUrl.razor`). No new tests needed. + +📌 Test pattern: LoginView tests require AuthenticationStateProvider mock (anonymous user). PasswordRecovery tests require NavigationManager mock. Both use fully-qualified `BlazorWebFormsComponents.LoginControls.LoginView` in Razor markup to avoid ambiguity. Find outer element by `#ID` for LoginView (wrapper element unknown until Cyclops implements), `table#ID` for PasswordRecovery (outer table already renders ID/CssClass/Style/ToolTip). — Rogue + +📌 Test pattern: PasswordRecovery outer table always includes `border-collapse:collapse` in style — assertions for BackColor/ForeColor should check `ShouldContain` not exact match. LoginView currently has no styled wrapper; #352 will add one. — Rogue + +### ClientIDMode Feature Tests + +Wrote 12 bUnit tests in `ClientIDMode/ClientIDModeTests.razor` covering all 4 ClientIDMode values (Static, Predictable, AutoID, Inherit) plus edge cases. + +**Static Mode (3 tests):** Raw ID without parent prefix, inside NamingContainer ignores parent, nested NamingContainers still only raw ID. + +**Predictable Mode (3 tests):** Parent_Child pattern inside NamingContainer, Outer_Inner_Component with nesting, does NOT include ctl00 even with UseCtl00Prefix=true. + +**AutoID Mode (2 tests):** Includes ctl00 prefix from NamingContainer with UseCtl00Prefix=true, nested containers with selective ctl00 prefix. + +**Inherit Mode (2 tests):** Default resolves to Predictable behavior, walks up to parent's mode (parent with Static → child inherits Static). + +**Edge Cases (2 tests):** No ID set returns null ClientID regardless of mode, Static mode without NamingContainer returns raw ID. + +📌 Test pattern: ClientIDMode tests use Button as the test component (renders ``). `@using BlazorWebFormsComponents.Enums` is required for the enum. ClientIDMode is set directly on the component via `ClientIDMode="ClientIDMode.Static"` etc. — Rogue + +📌 Finding: The existing `NamingContainerTests.UseCtl00Prefix_PrependsCtl00ToClientID` test FAILS after the ClientIDMode feature because UseCtl00Prefix only takes effect in `BuildAutoID()` mode but the default Inherit→Predictable skips ctl00. The test needs `ClientIDMode="ClientIDMode.AutoID"` on the Button, OR the NamingContainer should auto-set AutoID mode when UseCtl00Prefix=true. — Rogue + + Team update (2026-02-26): ClientIDMode tests consolidated with Cyclops implementation backward compat regression fixed via NamingContainer auto-AutoID decided by Cyclops, Rogue + Team update (2026-02-26): Data control divergence analysis consolidated sample parity is #1 blocker, 5 genuine bugs identified decided by Forge, Rogue diff --git a/.ai-team/decisions.md b/.ai-team/decisions.md index c2e767253..bba62bede 100644 --- a/.ai-team/decisions.md +++ b/.ai-team/decisions.md @@ -4,181 +4,157 @@ + ### 2026-02-10: Sample pages use Components/Pages path **By:** Jubilee **What:** All new sample pages should be created in `Components/Pages/ControlSamples/{ComponentName}/Index.razor`. The older `Pages/ControlSamples/` path should not be used for new components. **Why:** The sample app has two page directories — the newer .NET 8+ `Components/Pages/` layout is the standard for new work. - ### 2026-02-10: PR merge readiness ratings **By:** Forge **What:** PR review ratings established: #333 Calendar (Needs Work — SelectionMode enum), #335 FileUpload (Needs Work — broken data flow), #337 ImageMap (Needs Work — wrong base class), #327 PageService (Ready with minor fixes), #328 ASCX CLI (Risky — conflicts, no tests), #309 VS Snippets (Risky — conflicts). **Why:** Systematic review of all open PRs to establish sprint priorities and identify blockers. - ### 2026-02-10: CalendarSelectionMode must be an enum, not a string (consolidated) **By:** Forge, Cyclops **What:** Created `CalendarSelectionMode` enum in `Enums/CalendarSelectionMode.cs` with values None (0), Day (1), DayWeek (2), DayWeekMonth (3). Refactored `Calendar.SelectionMode` from string to enum. Also added `Caption`, `CaptionAlign`, `UseAccessibleHeader` properties. Fixed blocking `.GetAwaiter().GetResult()` call. **Why:** Web Forms uses `CalendarSelectionMode` as an enum. Project convention requires every Web Forms enum to have a corresponding C# enum in `Enums/`. String-based modes are fragile. Blocking async calls risk deadlocks in Blazor's sync context. - ### 2026-02-10: FileUpload must use Blazor InputFile internally (consolidated) **By:** Forge, Cyclops **What:** The `@onchange` binding on `` uses `ChangeEventArgs` which does not provide file data in Blazor. FileUpload MUST use Blazor's `` component internally instead of a raw ``. `InputFile` provides proper `InputFileChangeEventArgs` with `IBrowserFile` objects that enable all file operations. Without this, `HasFile` always returns false and `FileBytes`, `FileContent`, `PostedFile`, `SaveAs()` are all broken. **Why:** Ship-blocking bug — the component cannot function without actual file data access. `InputFile` renders as `` in the DOM so existing tests still pass. Requires `@using Microsoft.AspNetCore.Components.Forms` in the `.razor` file. Any future component needing browser file access must use `InputFile`. - ### 2026-02-10: ImageMap base class must be BaseStyledComponent **By:** Forge **What:** ImageMap should inherit `BaseStyledComponent`, not `BaseWebFormsComponent`. Web Forms `ImageMap` inherits from `Image` → `WebControl` which has style properties. **Why:** `BaseWebFormsComponent` is insufficient for controls that need CssClass, Style, and other style properties. - ### 2026-02-10: ImageMap categorized under Navigation Controls **By:** Beast **What:** ImageMap is categorized under Navigation Controls in the documentation nav, alongside HyperLink, Menu, SiteMapPath, and TreeView. **Why:** ImageMap's primary purpose is clickable regions for navigation — it aligns with navigation-oriented controls rather than editor/display controls. - ### 2026-02-10: Shelve ASCX CLI and VS Snippets indefinitely **By:** Jeffrey T. Fritz (via Copilot) **What:** PR #328 (ASCX CLI, issue #18) and PR #309 (VS Snippets, issue #11) removed from sprint plan and shelved indefinitely. **Why:** Both PRs have merge conflicts and are considered risky. Not worth the effort right now. - ### 2026-02-10: Docs and samples must ship with components **By:** Jeffrey T. Fritz (via Copilot) **What:** Documentation (Beast) and sample pages (Jubilee) must be delivered in the same sprint as the component they cover — never deferred to a later sprint. **Why:** Components aren't complete without docs and samples. - ### 2026-02-10: Sprint plan — 3-sprint roadmap **By:** Forge **What:** Sprint 1: Land & Stabilize current PRs (Calendar enum fix, FileUpload data flow, ImageMap base class, PageService merge). Sprint 2: Editor & Login Controls (MultiView, Localize, ChangePassword, CreateUserWizard). Sprint 3: Data Controls + Tooling + Polish (DetailsView, PasswordRecovery, migration guide, sample updates). **Why:** Prioritizes getting current PRs mergeable first, then fills biggest control gaps, then invests in tooling and documentation. - ### 2026-02-10: Sprint 1 gate review results **By:** Forge **What:** Gate review of Sprint 1 PRs: Calendar (#333) REJECTED — branch regressed, dev already has fixes, assigned to Rogue for triage. FileUpload (#335) REJECTED — `PostedFileWrapper.SaveAs()` missing path sanitization, assigned to Jubilee. ImageMap (#337) APPROVED — ready to merge. PageService (#327) APPROVED — ready to merge. **Why:** Formal gate review to determine merge readiness. Lockout protocol enforced: Cyclops locked out of Calendar and FileUpload revisions. - ### 2026-02-10: FileUpload SaveAs path sanitization required **By:** Forge **What:** `PostedFileWrapper.SaveAs()` must sanitize file paths to prevent path traversal attacks. `Path.Combine` silently drops earlier arguments if a later argument is rooted. Must use `Path.GetFileName()` and validate resolved paths. **Why:** Security defect blocking merge of FileUpload (#335). - ### 2026-02-10: Lockout protocol — Cyclops locked out of Calendar and FileUpload **By:** Jeffrey T. Fritz **What:** Cyclops is locked out of revising Calendar (#333) and FileUpload (#335). Calendar triage assigned to Rogue. FileUpload fix assigned to Jubilee. **Why:** Lockout protocol enforcement after gate review rejection. - ### 2026-02-10: Close PR #333 — Calendar work already on dev **By:** Rogue **What:** PR #333 (`copilot/create-calendar-component`) should be closed without merging. All Calendar work including enum fix, Caption/CaptionAlign/UseAccessibleHeader, and non-blocking OnDayRender is already on `dev` (commit `d33e156`). The PR branch has 0 unique commits — merging would be a no-op or actively harmful. Issue #332 is resolved on `dev`. **Why:** Cyclops committed Calendar fixes directly to `dev` instead of the feature branch, leaving the PR branch behind with old broken code. Rebasing would produce an empty diff. Process note: future PR review fixes should go to the feature branch, not the target branch. - ### 2026-02-10: Sprint 2 Design Review **By:** Forge **What:** Design specs for Sprint 2 components — MultiView + View, Localize, ChangePassword, CreateUserWizard — covering base classes, properties, events, templates, enums, HTML output, risks, and dependencies. **Why:** Sprint 2 scope involves 4 new components touching shared systems (LoginControls, Enums, base classes). A design review before implementation prevents rework, ensures Web Forms fidelity, and establishes contracts between Cyclops (implementation), Rogue (tests), Beast (docs), and Jubilee (samples). - ### 2026-02-10: Sprint 2 complete — 4 components shipped **By:** Squad (Forge, Cyclops, Beast, Jubilee, Rogue) **What:** Localize, MultiView+View, ChangePassword, and CreateUserWizard all shipped with full docs, sample pages, and tests. Build passes with 0 errors, 709 tests. status.md updated to 41/53 components (77%). **Why:** Sprint 2 milestone — all planned components delivered with docs and samples per team policy. - ### Integration test audit — full coverage achieved **By:** Colossus **What:** Audited all 74 sample page routes against existing smoke tests. Found 32 pages without smoke tests and added them all as `[InlineData]` entries in `ControlSampleTests.cs`. Added 4 new interaction tests in `InteractiveComponentTests.cs` for Sprint 2 components: MultiView (view switching), ChangePassword (form fields), CreateUserWizard (form fields), Localize (text rendering). Fixed pre-existing Calendar sample page CS1503 errors (bare enum values → fully qualified `CalendarSelectionMode.X`). **Why:** Every sample page is a promise to developers. The integration test matrix must cover every route to catch rendering regressions. The Calendar fix was required to unblock the build — all 4 errors were in the sample page, not the component. - ### 2026-02-10: Sprint 3 Scope and Plan **By:** Forge **What:** Sprint 3 scope finalized — DetailsView and PasswordRecovery are the two buildable components. Chart, Substitution, and Xml deferred indefinitely. **Why:** With 48/53 components complete (91%), we have exactly 5 remaining. Three of them (Chart, Substitution, Xml) are poor candidates: Chart requires an entire charting library, Substitution is a cache-control mechanism that has no Blazor equivalent, and Xml/XSLT transforms are a dead-end technology with near-zero migration demand. DetailsView and PasswordRecovery are the only two that provide real migration value and are feasible to build. - ### 2026-02-10: Colossus added — dedicated integration test engineer **By:** Jeffrey T. Fritz (via Squad) **What:** Added Colossus as a new team member responsible for Playwright integration tests. Colossus owns `samples/AfterBlazorServerSide.Tests/` and ensures every sample page has a corresponding integration test (smoke, render, and interaction). Rogue retains ownership of bUnit unit tests. Integration testing split from Rogue's QA role. **Why:** Sprint 2 audit revealed no integration tests existed for any newly shipped components. Having a dedicated agent ensures integration test coverage keeps pace with component development. Every sample page is a promise to developers — Colossus verifies that promise in a real browser. - ### 2026-02-11: Deferred controls documentation pattern established **By:** Beast **What:** Created `docs/Migration/DeferredControls.md` to document the three permanently deferred controls (Chart, Substitution, Xml). Each control gets its own section with: what it did in Web Forms, why it's not implemented, and the recommended Blazor alternative with before/after migration examples. Added to mkdocs.yml nav under Migration. **Why:** Components without documentation don't exist for the developer trying to migrate. Even controls we *don't* implement need a clear "here's what to do instead" — otherwise developers hit a dead end with no guidance. This pattern can be reused if additional controls are deferred in the future. - ### 2026-02-11: DetailsView and PasswordRecovery documentation shipped **By:** Beast **What:** Created `docs/DataControls/DetailsView.md` and `docs/LoginControls/PasswordRecovery.md`. Both added to `mkdocs.yml` nav in alphabetical order. README.md updated with documentation links for both components. **Why:** Sprint 3 requires docs to ship with components per team policy. Both docs follow the established convention: title → MS docs link → Features Supported → NOT Supported → Web Forms syntax → Blazor syntax → HTML output → Migration Notes (Before/After) → Examples → See Also. PasswordRecovery follows the ChangePassword.md pattern for login controls; DetailsView follows the data control patterns from FormView/GridView. - ### 2026-02-11: DetailsView inherits DataBoundComponent, not BaseStyledComponent **By:** Cyclops **What:** DetailsView inherits `DataBoundComponent` (same as GridView and FormView) rather than `BaseStyledComponent`. The `CssClass` property is declared directly on the component. Event args use separate DetailsView-specific types (`DetailsViewCommandEventArgs`, `DetailsViewModeEventArgs`, etc.) rather than reusing FormView's event args. **Why:** Web Forms DetailsView inherits from `CompositeDataBoundControl`, which is a data-bound control. GridView and FormView already follow this pattern in the codebase via `DataBoundComponent`. Using separate event args (not FormView's) matches Web Forms where `DetailsViewInsertEventArgs` and `FormViewInsertEventArgs` are distinct types. The `DetailsViewMode` enum is also separate from `FormViewMode` even though they have identical values — Web Forms treats them as distinct types. - ### 2026-02-11: PasswordRecovery component — inherits BaseWebFormsComponent, 3-step flow **By:** Cyclops **What:** Built PasswordRecovery component in `LoginControls/` with 3-step password reset flow (UserName → Question → Success). Inherits `BaseWebFormsComponent` following existing login control patterns. Created `SuccessTextStyle` sub-component, `MailMessageEventArgs`, and `SendMailErrorEventArgs` event args. Each step has its own `EditForm`. Styles cascade via existing sub-components (`TitleTextStyle`, `LabelStyle`, `TextBoxStyle`, etc.) plus new `SuccessTextStyle`. The `SubmitButtonStyle` property maps to `LoginButtonStyle` cascading name to reuse existing sub-component. Templates (`UserNameTemplate`, `QuestionTemplate`, `SuccessTemplate`) allow full customization of each step. **Why:** Sprint 3 deliverable. Followed ChangePassword/CreateUserWizard patterns for consistency. Used `BaseWebFormsComponent` instead of spec-suggested `BaseStyledComponent` because all existing login controls use this base class and manage styles through CascadingParameters. Per-step `EditForm` prevents validation interference between steps. - ### 2026-02-11: Sprint 3 gate review — DetailsView and PasswordRecovery APPROVED **By:** Forge **What:** Both Sprint 3 components passed gate review. DetailsView: correct `DataBoundComponent` inheritance, all 10 events with proper EventArgs, table-based HTML matching Web Forms, `DetailsViewMode` enum. 3 minor non-blocking issues (CellPadding/CellSpacing logic, docs DataSource→Items). PasswordRecovery: correct `BaseWebFormsComponent` inheritance, 3-step wizard flow, all 6 events, table-based nested HTML. 3 minor non-blocking issues (RenderOuterTable unused, SubmitButtonType unused, sample uses Sender casting vs @ref). Build: 0 errors, 797 tests. Status: 50/53 (94%). **Why:** Formal gate review — both components meet Web Forms fidelity standards. No blocking issues. Minor issues tracked but do not prevent shipping. - ### 2026-02-11: DetailsView sample uses Items parameter with inline data **By:** Jubilee **What:** DetailsView sample page uses the `Items` parameter with an inline `List` rather than `SelectMethod` for data binding. This matches the GridView RowSelection sample pattern and is the clearest way to demonstrate paging and mode-switching without requiring a static query method. **Why:** The `SelectMethod` approach (used in GridView Default) requires a specific method signature with `out totalRowCount` that adds complexity. For a single-record-at-a-time control like DetailsView, the `Items` parameter is more natural and easier for migrating developers to understand. Both patterns work; `Items` is preferred for sample clarity. - ### 2026-02-12: Sprint 3 bUnit tests shipped — DetailsView + PasswordRecovery **By:** Rogue **What:** 71 new bUnit tests added for Sprint 3 components: 42 for DetailsView (5 test files: Rendering, HeaderFooter, CommandRow, Events, Paging) and 29 for PasswordRecovery (2 test files: Step1UserName, BasicFlow). Total test count now 797, all passing. **Why:** QA gate for Sprint 3 — both components needed comprehensive unit test coverage before merge. Tests verify rendering fidelity (table structure, property names/values, empty data, header/footer), interactive behavior (mode switching, paging, event firing), and edge cases (null items, single item paging, cancel flows, failure text display). - ### 2026-02-12: Chart component JS library evaluation **By:** Forge @@ -464,19 +440,16 @@ Suggested timeline: - **Sprint 4 execution:** Implement Chart with Phase 1 types, docs, samples, integration tests - **Post-Sprint 4:** Evaluate demand for Phase 2 chart types - ### 2026-02-12: Milestone 4 — Chart component with Chart.js **By:** Forge (architecture), Squad (planning) **What:** Milestone 4 will implement the Chart component using Chart.js (~60KB, MIT) via Blazor JS interop. Phase 1: 8 chart types (Column, Bar, Line, Pie, Area, Doughnut, Scatter, StackedColumn). HTML output exception: `` instead of `` (justified — API fidelity is the migration value, not HTML fidelity). 8 work items across 5 waves. Target: 51/53 components (96%). **Why:** Chart is the highest-value remaining deferred component. Chart.js provides the best balance of bundle size, chart type coverage, and Blazor ecosystem support. D3 rejected (wrong abstraction), Plotly rejected (3-4MB bundle). Design review required before implementation (auto-triggered ceremony). - ### 2026-02-12: User directive — use "milestones" not "sprints" (consolidated) **By:** Jeffrey T. Fritz (via Copilot) **What:** Going forward, use "milestones" instead of "sprints" for naming work batches. All future planning uses "milestone" terminology. **Why:** User preference — captured for team memory. Applies retroactively to planning references where practical. - ### 2026-02-23: AccessKey must be added to BaseStyledComponent **By:** Beast, Cyclops @@ -485,28 +458,24 @@ Suggested timeline: **Why:** Universal gap confirmed by two independent audits across 28 controls. Base-class fix is the highest-leverage single change available. **Status:** AccessKey added in Milestone 6. ToolTip consolidated into 2026-02-25 entry below. - ### 2026-02-23: Label should inherit BaseStyledComponent **By:** Beast **What:** `Label` currently inherits `BaseWebFormsComponent` but Web Forms `Label` inherits from `WebControl`. This means Label is missing all 9 style properties (CssClass, BackColor, ForeColor, Font, etc.). Also consider `AssociatedControlID` to render `
` elements now render CssClass and computed IStyle inline styles alongside `border-collapse:collapse;`. `[Parameter]` style properties do NOT conflict with `[CascadingParameter]` sub-styles (TitleTextStyle, LabelStyle, etc.) — completely independent mechanisms. LoginView still inherits `BaseWebFormsComponent`. LoginName and LoginStatus already had full style support. PasswordRecovery should follow the same pattern when ready. **Why:** Migrating pages that set CssClass on Login controls would break. `BaseStyledComponent` extends `BaseWebFormsComponent` — no functionality lost. - ### 2026-02-12: ChangePassword and CreateUserWizard sample pages require LoginControls using directive **By:** Colossus **What:** Added `@using BlazorWebFormsComponents.LoginControls` to `ChangePassword/Index.razor` and `CreateUserWizard/Index.razor`. Without this, the components render as raw HTML custom elements instead of Blazor components — silently failing with no error. **Why:** The root `@using BlazorWebFormsComponents` in `_Imports.razor` does not cover sub-namespaces like `LoginControls`. Any future sample page using Login Controls must include this directive. PasswordRecovery already had it; these two were missed during Sprint 2. - ### 2026-02-12: External placeholder URLs replaced with local SVG images **By:** Colossus **What:** Replaced all `https://via.placeholder.com/...` URLs in Image and ImageMap sample pages with local SVG placeholder images in `wwwroot/img/`. Created 8 SVG files matching the sizes used in the samples. **Why:** External URLs are unreachable in CI/test environments, causing integration test failures. Local SVGs are always available and test-safe. Future sample pages must never use external image URLs. - ### 2026-02-12: ASP.NET Core structured log messages filtered in integration tests **By:** Colossus **What:** Added a regex filter in `VerifyPageLoadsWithoutErrors` to exclude browser console messages matching `^\[\d{4}-\d{2}-\d{2}T` (ISO 8601 timestamp prefix). These are ASP.NET Core ILogger messages forwarded to the browser console by Blazor Server, not actual page errors. **Why:** Without this filter, any page that triggers framework-level logging (e.g., Calendar with many interactive elements) produces false positive test failures. - ### 2026-02-12: Milestone exit criteria — samples and integration tests mandatory **By:** Jeffrey T. Fritz @@ -620,7 +577,6 @@ Suggested timeline: 3. **All integration tests pass** — 100% of integration tests (both new and pre-existing) must pass before the sprint is submitted **Why:** Sprint 3 exposed gaps where components shipped without full sample coverage and integration tests. This gate ensures no sprint is declared complete until the full chain — component → sample → integration test → green — is verified. This is a permanent policy for all future sprints. - ### DetailsView auto-generated fields render inputs in Edit/Insert mode **By:** Cyclops @@ -1983,7 +1939,6 @@ Removed the `@rendermode InteractiveServer` directive. No other sample page in t **What:** Milestone 12 introduces a Migration Analysis Tool as a CLI (`bwfc-migrate`) in the same repo at `src/BlazorWebFormsComponents.MigrationAnalysis/`. The PoC uses regex-based ASPX parsing (not Roslyn) to extract `` controls, maps them against a registry of all 53 planned BWFC components + ~15 known unsupported controls, analyzes code-behind patterns via regex, scores page complexity (Green/Yellow/Red), and produces Markdown + JSON reports. Packaged as a `dotnet tool`. Three-phase roadmap: M12 = analysis + CLI, Phase 2 = Roslyn + scaffolding, Phase 3 = Copilot agent. 13 work items total. **Why:** At 51/53 components complete, the component library is mature. The highest-leverage remaining work is helping developers evaluate and execute migrations using the components we already built. Same-repo placement keeps the control mapping table in sync with the actual component library. Regex over Roslyn prevents scope creep in the PoC — Roslyn is explicitly Phase 2. The tool transforms BlazorWebFormsComponents from a component library into a migration platform. - # Decision: Dev Branch Cleanup (Fork Alignment) **Date:** 2026-02-25 @@ -2099,7 +2054,6 @@ Used --force-with-lease for the force-push to origin (not --force), which ensure **What:** All new work MUST be done on feature branches, pushed to origin, with a PR to upstream/dev. Never commit directly to the dev branch. **Why:** User directive captured for team memory - # Decision: SkinID and EnableTheming Property Defaults **Date:** 2026-02-26 @@ -2124,7 +2078,6 @@ Per Jeff's confirmed decisions: - No breaking changes — existing code that doesn't use theming is unaffected since there's no theme provider yet (#364/#366 will add that). - #366 (Forge's base class integration) can now wire these properties into the theme resolution pipeline. - # Decision: Theme Integration in BaseStyledComponent **Date:** 2026-02-26 @@ -2153,7 +2106,6 @@ With core theme types (#364) and SkinID/EnableTheming activation (#365) complete - Existing tests are unaffected — without a `ThemeProvider` ancestor, `Theme` is null and the early-return fires. - Future work: add Overline/Strikeout font properties, ILogger for missing skin warnings, Theme property override semantics. - # Decision: Theme Core Types Design **Author:** Cyclops @@ -2179,8 +2131,6 @@ WI-1 required core data types for the Skins & Themes PoC. - Integration step (#366) will need to consume `CascadingParameter` in `BaseStyledComponent` and apply skin values during initialization. - The nullable property design means the apply logic will check each property for null before overwriting the component's parameter value. - - # Decision: ThemesAndSkins.md updated to reflect PoC implementation **Author:** Beast (Technical Writer) @@ -2574,12 +2524,6 @@ Login and LoginStatus should get `LoginActionUrl` and `LogoutActionUrl` paramete - **Full analysis:** `planning-docs/LOGIN-IDENTITY-ANALYSIS.md` -### 2026-02-26: Decision: Data Control Divergence Analysis Results - -**Date:** 2026-02-27 -**By:** Forge (Lead / Web Forms Reviewer) -**Status:** Pending Review -**Relates to:** M13 HTML Fidelity Audit — Data Controls (DataList, GridView, ListView, Repeater) ## Context @@ -2663,3 +2607,418 @@ Without sample alignment, the pipeline cannot distinguish between "component ren Full analysis: `planning-docs/POST-FIX-CAPTURE-RESULTS.md` Diff report: `audit-output/diff-report-post-fix.md` + + +### LoginView uses `
` wrapper for BaseStyledComponent styles + +**By:** Cyclops +**What:** LoginView renders a `
` wrapper around its content. Unlike Login/ChangePassword/CreateUserWizard which use `
` wrappers, LoginView uses `
` because it's a template-switching control with no table layout. +**Why:** LoginView already inherited BaseStyledComponent but had no outer HTML element rendering CssClass, Style, or ToolTip. The `
` wrapper provides a DOM attachment point for these properties without introducing unnecessary table markup. + + + +# Decision: Conditional HTML attribute rendering pattern + +**Author:** Cyclops +**Date:** M15 +**Context:** Bug fixes #380, #379, #378 + +## Decision + +For conditional HTML attribute rendering in Blazor components: + +1. **Use helper methods returning null** to suppress attributes (e.g., `GetLongDesc()`, `GetCssClassOrNull()`). Blazor does not render attributes with null values. +2. **For ordered lists**, use CSS `list-style-type` only — do NOT use the HTML `type` attribute on `
    `. WebForms doesn't render `type`. +3. **Disabled state class handling** on button-like components should follow the Button pattern: append `aspNetDisabled` to CssClass when `Enabled=false`. This applies to LinkButton and any future button-like components. + +## Rationale + +WebForms audit HTML shows these are the exact patterns used by .NET Framework. Matching these patterns ensures CSS/JS compatibility after migration. + + +# M15 HTML Fidelity Strategy — Post-PR #377 Assessment + +**Date:** 2026-02-28 +**Author:** Forge (Lead / Web Forms Reviewer) +**Requested by:** Jeffrey T. Fritz +**Context:** PR #377 merged to upstream/dev — contains M11–M14 deliverables including full HTML fidelity audit (132 comparisons), 14 bug fixes, post-fix re-run (131 divergences, 1 exact match), WebFormsPage component, data alignment, and NamingContainer. + +--- + +## 1. Current State Assessment + +### Where We Stand + +After PR #377, we have the most complete picture of HTML fidelity this project has ever produced. The numbers tell a clear story: + +| Metric | Value | Assessment | +|--------|-------|------------| +| Total comparisons | 132 (128 unique + 4 HyperLink case dupes) | Good coverage of captured controls | +| Exact matches | **1** (Literal-3) | Sobering — but misleading (see below) | +| Verified structural improvements | 11 controls | The 14 bug fixes landed and verified | +| Missing Blazor captures | 64 variants | **The #1 coverage gap** | +| Sample parity false positives | ~22 entries | Noise masking real signal | +| Genuine remaining structural bugs | ~5 controls | Fixable in M15 | +| Data control investigations needed | 4 controls | Unknown severity | + +**The "1 exact match" number is misleading.** The vast majority of divergences are caused by **different sample data** between WebForms and Blazor, not by component bugs. If we align the sample data, I estimate **15–20 controls** would achieve exact or near-exact match immediately. The actual HTML structure is correct for most Tier 1 controls — DropDownList, HyperLink, HiddenField, Image (minus `longdesc`), ImageMap, Label, Literal, Panel, PlaceHolder, and AdRotator all render correct tag structure with only content differences. + +### Controls by Distance from Pixel-Perfect + +**Near-perfect (correct structure, needs sample data alignment only):** ~12 controls +- AdRotator, DropDownList (6 variants), HiddenField, HyperLink (4 variants), Image (1 of 2), ImageMap, Label (3 variants), Literal (2 of 3), Panel (3 variants), PlaceHolder + +**Close (1–2 fixable attribute/structural issues):** ~6 controls +- Button (fixed `` — now needs sample parity only), BulletedList (still needs `
      ` + `list-style-type`), CheckBox (remove `` wrapper), Image (remove empty `longdesc`), LinkButton (add `href` + `class`), FileUpload (GUID attribute leak) + +**Moderate (structural work needed):** ~4 controls +- Calendar (73% similarity — missing styles, `title`, navigation header differences), RadioButtonList (GUID IDs), GridView (33 line diff — mixed structural + sample), DataList (110 line diff — needs investigation) + +**Far (significant structural divergence):** ~3 controls +- TreeView (deep structural differences in node rendering), ListView (182 line diff — template-based output), Repeater (64 line diff) + +**Unknown (missing Blazor captures):** ~20+ controls +- All Login family (7 controls), all Validators (6 controls), Menu (9 variants), TextBox (7 variants), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), SiteMapPath (2), MultiView, Table (3), DataPager, DetailsView, FormView + +--- + +## 2. Remaining Divergence Analysis + +### Category A — Fixable Structural Bugs (5 controls, ~8–14 hours) + +These are genuine HTML structure differences where the Blazor component renders wrong elements or missing attributes. All fixable. + +| Control | Bug | Effort | Variants Fixed | +|---------|-----|--------|----------------| +| **BulletedList** | Still renders `
        ` for numbered lists (should be `
          `); wrong `list-style-type` values (`disc`/`circle` vs `decimal`/`square`) | 1–2 hrs | 3 | +| **LinkButton** | Missing `href` attribute; missing `CssClass` → `class` pass-through | 1–2 hrs | 3 | +| **CheckBox** | Extra wrapping `` around checkbox+label pair for TextAlign=Right | 1–2 hrs | 3 | +| **Image** | Emits empty `longdesc=""` when `DescriptionUrl` is unset | 30 min | 2 | +| **FileUpload** | Stray GUID fragment leaks as HTML attribute (CSS isolation scope artifact) | 1 hr | 1 | + +**Status of PR #377 fixes:** Button (``), BulletedList `` removal, LinkButton `href`, Calendar border/`
`, CheckBox wrapper removal, Image `longdesc`, DataList border-collapse, GridView `rules`/`border`, and TreeView compression were all **fixed and verified** in the post-fix capture. However, BulletedList `
    ` rendering and `list-style-type` mapping were NOT addressed. LinkButton `class` was NOT addressed. CheckBox may still have issues depending on capture state vs. code state. + +### Category B — Sample Parity Issues (NOT component bugs, ~22 entries) + +The single highest-value action for improving match rates. These controls render correct HTML structure but use completely different data/text/URLs between WebForms and Blazor samples: + +| Control | Nature of Difference | +|---------|---------------------| +| AdRotator | Bing vs Microsoft ad content, different images | +| BulletedList | Apple/Banana/Cherry vs Item One/Two/Three | +| Button | "Blue Button" w/ styling vs "Click me!" no styling | +| CheckBox | "Accept Terms" vs "I agree to terms" | +| DropDownList (×6) | Different option text/values throughout | +| HiddenField | Different `value` attribute | +| HyperLink (×4) | Bing vs GitHub, different text/URLs | +| Image (×2) | Different src/alt | +| ImageMap | Different coordinates/URLs | +| Label (×3) | Different text/classes | +| Literal (×2) | Different text content | +| Panel (×3) | Different inner content | +| PlaceHolder | Different placeholder text | + +**Fix approach:** Update Blazor sample pages to mirror exact WebForms content. This is a Jubilee task — mechanical but tedious. Estimated effort: 4–6 hours. Impact: potentially **20+ controls move to exact match** in one sprint. + +### Category C — Intentional/Unfixable Divergences (D-01 through D-10) + +These are permanent architectural differences. The normalizer already handles them. No action needed. + +| D-Code | What It Is | Status | +|--------|-----------|--------| +| D-01 | ID mangling (`ctl00_` prefixes) | ✅ Normalized — stripped before comparison | +| D-02 | `__doPostBack` → `@onclick` | ✅ Normalized — replaced with placeholder | +| D-03 | ViewState hidden fields | ✅ Normalized — stripped | +| D-04 | WebResource.axd URLs | ✅ Normalized — stripped | +| D-05 | Chart `` vs `` | ⛔ Excluded from audit entirely | +| D-06 | Menu Table mode (Blazor = List only) | ✅ Documented — 4 variants permanently divergent | +| D-07 | TreeView JS injection | ✅ Normalized — JS stripped | +| D-08 | Calendar `__doPostBack` | ✅ Normalized — postback replaced | +| D-09 | Login control auth infrastructure | ✅ Documented — compare visual shell only | +| D-10 | Validator client-side scripts | ✅ Documented — compare `` only | + +**New divergence candidates identified (need decision):** + +| Proposed | What It Is | Recommendation | +|----------|-----------|----------------| +| **D-11** | GUID-based IDs for CheckBox/RadioButton/RadioButtonList/FileUpload | **Fix, don't register as intentional.** GUIDs make HTML non-deterministic and untargetable by CSS/JS. Controls should use developer-provided `ID` parameter and append `_0`, `_1` per Web Forms convention. | +| **D-12** | Boolean attribute format: `selected=""` (HTML5) vs `selected="selected"` (XHTML) | **Register as intentional.** Both are valid HTML. Blazor uses HTML5-style; Web Forms uses XHTML-style. Add normalizer rule to treat as equivalent. | +| **D-13** | Calendar previous-month day padding (WF shows Jan 25–31; Blazor starts at Feb 1) | **Fix.** Web Forms Calendar pads the first week with previous month's days. Our Blazor Calendar should do the same — it's visible structural content. | +| **D-14** | Calendar style property pass-through (WF applies inline styles for ForeColor, Font, etc.; Blazor doesn't) | **Fix progressively.** Calendar style application is incomplete — the `
` and cell-level styles from `TitleStyle`, `DayStyle`, `OtherMonthDayStyle`, `WeekendDayStyle`, `TodayDayStyle` etc. are not being applied. This is a significant fidelity gap for Calendar specifically. | + +### Category D — Normalizer Artifacts (3 items) + +| Issue | Impact | Fix | +|-------|--------|-----| +| HyperLink/Hyperlink case-sensitivity duplication | 4 phantom entries in diff report | Case-insensitive folder matching in diff script | +| `selected=""` vs `selected="selected"` | False divergence in DropDownList | Add normalizer rule for boolean HTML attributes | +| Empty `style=""` on some controls | Noise in diffs | Strip empty `style=""` attributes in normalizer | + +--- + +## 3. Prioritized Next Steps — What M15 Should Focus On + +Ranked by **impact per unit of effort**: + +### 🔴 Tier 1 Priority: Sample Data Alignment (Impact: MASSIVE, Effort: MEDIUM) + +**This is the single highest-leverage action.** One sprint of sample alignment work could move us from 1 exact match to 15–20+ exact matches. Every other effort is wasted if the samples don't match — we can't tell what's a bug vs. what's different data. + +- Update all Blazor sample pages to use identical text, values, URLs, styles as WebForms samples +- Covers: AdRotator, BulletedList, Button, CheckBox, DropDownList, HiddenField, HyperLink, Image, ImageMap, Label, Literal, Panel, PlaceHolder, LinkButton +- Owner: Jubilee +- Effort: 4–6 hours +- Impact: ~22 false-positive divergences eliminated; true structural bugs surface cleanly + +### 🔴 Tier 2 Priority: Fix Remaining Structural Bugs (Impact: HIGH, Effort: LOW-MEDIUM) + +Ship the remaining P1–P3 bug fixes that were identified but not addressed in PR #377: + +| # | Fix | Effort | Impact | +|---|-----|--------|--------| +| 1 | BulletedList: `
    ` for numbered + correct `list-style-type` mapping | 1–2 hrs | 3 variants → exact match | +| 2 | LinkButton: Pass `CssClass` → `class` attribute | 1 hr | 3 variants improved | +| 3 | Image: Only emit `longdesc` when non-empty | 30 min | 2 variants → exact match | +| 4 | FileUpload: Remove stray GUID attribute leak | 1 hr | 1 variant → exact match | +| 5 | CheckBox: Remove wrapping `` (verify post-PR #377 state) | 1 hr | 3 variants improved | +| 6 | RadioButtonList: Stable IDs (not GUIDs) | 1–2 hrs | 2 variants improved | + +Owner: Cyclops +Total effort: 6–9 hours +Impact: 14+ variants improved, 6+ potentially exact match + +### 🟡 Tier 3 Priority: Close Blazor Capture Gaps (Impact: HIGH, Effort: MEDIUM) + +64 variants have no Blazor capture. Prioritize by ROI: + +**Phase A — Add `data-audit-control` markers to EXISTING Blazor pages (2–3 hrs):** +- TextBox (7 variants), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), Button (variants 2–5), Literal (variant 3), SiteMapPath (2), Table (3), MultiView (1) +- These controls already have Blazor sample pages — they just lack `data-audit-control` markers +- Impact: ~25 more comparisons enabled + +**Phase B — Write new Blazor sample pages for missing controls (6–10 hrs):** +- Menu (5 List-mode variants — 4 Table-mode are permanently divergent per D-06) +- Login family (7 controls × 2 variants = 14 captures) — visual shell comparison +- Validators (6 controls × 3–4 variants = ~23 captures) — `` comparison only +- DataPager, DetailsView, FormView +- Impact: ~42 more comparisons + +Owner: Jubilee (samples), Colossus (captures) + +### 🟢 Tier 4 Priority: Normalizer Enhancements (Impact: MEDIUM, Effort: LOW) + +| Enhancement | Effort | Impact | +|------------|--------|--------| +| Case-insensitive folder matching (kills 4 HyperLink dupes) | 30 min | Cleaner reports | +| Boolean attribute normalization (`selected=""` ↔ `selected="selected"`) | 30 min | DropDownList false positives eliminated | +| Empty `style=""` stripping | 15 min | Noise reduction | +| GUID ID normalization (strip or placeholder) | 1 hr | CheckBox/RadioButtonList/FileUpload noise reduced | + +Owner: Cyclops +Total effort: 2–3 hours + +### 🟢 Tier 5 Priority: Data Control Deep Investigation (Impact: UNKNOWN, Effort: MEDIUM) + +DataList (110 lines), GridView (33 lines), ListView (182 lines), Repeater (64 lines) — all have both captures but show significant divergences. Need line-by-line classification. + +**My assessment before investigation:** +- **GridView** (33 lines) — Likely mostly sample parity. The post-fix capture shows correct `
`/`` structure, `rules`/`border` attributes. Remaining diff is mostly different column names and content. Probably fixable with sample alignment. +- **DataList** (110 lines) — The `
` structure is the right approach, but template rendering likely produces different cell content. Mix of sample parity and template handling differences. +- **Repeater** (64 lines) — Repeater is unusual because it has no default chrome — it renders pure template output. Divergence is almost certainly 100% sample parity. +- **ListView** (182 lines) — Largest divergence. ListView's template model is the most flexible in Web Forms and the hardest to match structurally. This control is likely to have genuine structural differences in how templates are composed. + +Owner: Forge (classification), Cyclops (fixes) +Effort: 4–8 hours investigation, unknown fix effort + +### 🔵 Tier 6 Priority: Calendar Deep Fix (Impact: HIGH for one control, Effort: HIGH) + +Calendar is the most complex control and the closest to pixel-perfect among complex controls (73% similarity on best variant). Remaining gaps: + +1. **Previous-month day padding** — WF shows Jan 25–31 in the first row; Blazor starts at Feb 1 +2. **Style property pass-through** — `TitleStyle`, `DayStyle`, `OtherMonthDayStyle`, `WeekendDayStyle`, `TodayDayStyle`, `NextPrevStyle`, `SelectorStyle` inline styles not applied +3. **`title` attribute on `
`** — WF emits `title="Calendar"`; Blazor doesn't +4. **`id` attribute on `
`** — WF emits developer ID; Blazor doesn't (may be NamingContainer related) +5. **`color` attribute on day links** — WF emits `style="color:#000000;"`; Blazor uses `cursor:pointer` +6. **`background-color` on title row** — WF emits `background-color:#c0c0c0`; Blazor doesn't + +Owner: Cyclops +Effort: 5–8 hours (touching multiple Razor files and style resolution logic) +Impact: Could push Calendar from 73% to 90%+ similarity + +--- + +## 4. Pixel-Perfect Realism + +Let me be blunt about what "pixel-perfect" means for this project. + +### Controls That CAN Achieve Exact Normalized Match + +With sample alignment + remaining bug fixes, these controls should achieve **100% normalized HTML match**: + +| Control | What's Needed | Confidence | +|---------|--------------|------------| +| Literal | ✅ Already exact (1 of 3 variants) | 100% | +| HiddenField | Sample alignment only | 99% | +| PlaceHolder | Sample alignment only | 99% | +| Label | Sample alignment only | 98% | +| Panel | Sample alignment only | 98% | +| AdRotator | Sample alignment only | 95% | +| Image | Remove `longdesc` + sample alignment | 95% | +| HyperLink | Sample alignment only | 95% | +| ImageMap | Sample alignment only | 95% | +| DropDownList | Sample alignment + boolean attr normalizer | 90% | +| BulletedList | `
    ` fix + `list-style-type` + sample alignment | 90% | +| LinkButton | `href` + `class` fix + sample alignment | 85% | +| Button | Sample alignment only (already fixed to ``) | 85% | + +**Realistic target: 13–15 exact matches after M15 (up from 1 today).** + +### Controls That Can Achieve Near-Match (>90% normalized similarity) + +| Control | Gap | Realistic Ceiling | +|---------|-----|-------------------| +| Calendar | Style pass-through, day padding, title | 90–95% with fixes | +| CheckBox | `` removal, stable IDs | 90–95% with fixes | +| RadioButtonList | Stable IDs | 90% with ID fix | +| FileUpload | GUID attribute removal | 95% | +| GridView | Sample alignment + investigation | 85–95% TBD | + +### Controls That Will ALWAYS Have Structural Differences + +Be honest. These controls have fundamental architectural gaps that make exact HTML match impossible or impractical: + +| Control | Why | Permanent Gap | +|---------|-----|---------------| +| **Chart** | `` vs `` — completely different rendering technology | 100% different (D-05) | +| **Menu (Table mode)** | Blazor only implements List mode; 4 Table-mode variants are permanently divergent | Partial (D-06) — List mode is comparable | +| **TreeView** | Web Forms uses `
` vs ``), BUG-DL-2. +3. **Proposed D-11:** `` header section recommended as intentional divergence (semantically correct HTML5). +4. **Post-bug-fix re-run** confirmed 14 structural improvements. Exact matches: 01 (Literal-3). Sample alignment is the #1 blocker could convert 20+ divergences to exact matches. +5. **Normalization gaps:** Blazor output not normalized for data controls; `` markers need stripping. + +**Why:** Cannot distinguish component bugs from sample differences without aligned samples. Sample alignment is prerequisite for accurate audit. Bug fixes are secondary until samples match. Full analyses: `planning-docs/DATA-CONTROL-ANALYSIS.md`, `planning-docs/M15-DATA-CONTROL-ANALYSIS.md`, `planning-docs/POST-FIX-CAPTURE-RESULTS.md`. diff --git a/.ai-team/decisions/inbox/cyclops-html-attribute-rendering.md b/.ai-team/decisions/inbox/cyclops-html-attribute-rendering.md deleted file mode 100644 index e6bc6f7f1..000000000 --- a/.ai-team/decisions/inbox/cyclops-html-attribute-rendering.md +++ /dev/null @@ -1,17 +0,0 @@ -# Decision: Conditional HTML attribute rendering pattern - -**Author:** Cyclops -**Date:** M15 -**Context:** Bug fixes #380, #379, #378 - -## Decision - -For conditional HTML attribute rendering in Blazor components: - -1. **Use helper methods returning null** to suppress attributes (e.g., `GetLongDesc()`, `GetCssClassOrNull()`). Blazor does not render attributes with null values. -2. **For ordered lists**, use CSS `list-style-type` only — do NOT use the HTML `type` attribute on `
    `. WebForms doesn't render `type`. -3. **Disabled state class handling** on button-like components should follow the Button pattern: append `aspNetDisabled` to CssClass when `Enabled=false`. This applies to LinkButton and any future button-like components. - -## Rationale - -WebForms audit HTML shows these are the exact patterns used by .NET Framework. Matching these patterns ensures CSS/JS compatibility after migration. diff --git a/.ai-team/decisions/inbox/forge-m15-data-control-analysis.md b/.ai-team/decisions/inbox/forge-m15-data-control-analysis.md deleted file mode 100644 index 7594040cc..000000000 --- a/.ai-team/decisions/inbox/forge-m15-data-control-analysis.md +++ /dev/null @@ -1,52 +0,0 @@ -# Decision: M15-10 Data Control Investigation Complete - -**Date:** 2026-02-28 -**Author:** Forge (Lead / Web Forms Reviewer) -**Task:** M15-10 (GitHub #392) -**Status:** For team review - ---- - -## Context - -Performed line-by-line classification of all HTML divergences in DataList, GridView, ListView, and Repeater using post-fix normalized captures. This updates the M13 analysis in `planning-docs/DATA-CONTROL-ANALYSIS.md`. - -## Decisions - -### 1. Bug Reclassification - -3 of 5 M13 bugs are now FIXED (PR #377). 4 bugs remain: -- **BUG-GV-4b (P1):** `UseAccessibleHeader` defaults to `false` in Blazor; WF defaults to `true`. One-line fix. -- **BUG-GV-3 (P1):** `&nbsp;` encoding in empty headers due to ternary expression type resolution. Fix with `@if`/`@else`. -- **BUG-GV-4a (P2):** `
` vs `` for header rows — see D-11 proposal below. -- **BUG-DL-2 (P3):** `itemtype` not rendered from generic type parameter. - -### 2. Proposed D-11: `` Header Section - -Blazor GridView always renders header rows in ``. WF GridView defaults to `` for header rows (unless `HeaderRow.TableSection = TableRowSection.TableHeader` is explicitly set). - -**Options:** -- (A) Register as D-11 intentional divergence — `` is semantically correct and preferred -- (B) Fix to match WF by putting headers in `` when `UseAccessibleHeader=false` - -**Forge's recommendation:** Option A. `` is the correct HTML5 semantic and no real-world migration will break because of this. - -### 3. Sample Alignment is Critical Path - -22 of 26 findings are sample parity. ListView and Repeater have ZERO component bugs — their entire diff is sample authoring differences. DataList and GridView have minor bugs but the vast majority of their diffs are also sample issues. - -**Impact:** Sample alignment would immediately reduce total diff lines from 294 to ~13, revealing only genuine structural issues. - -## Artifacts - -- Full analysis: `planning-docs/M15-DATA-CONTROL-ANALYSIS.md` -- Prior analysis: `planning-docs/DATA-CONTROL-ANALYSIS.md` - -## Who Needs to Know - -- **Cyclops:** 3 bug fixes to implement (BUG-GV-4b, BUG-GV-3, BUG-DL-2) -- **Jubilee:** Sample alignment for all 4 data controls is P1 -- **Colossus:** 2 normalizer fixes (empty `style=""` stripping, consistent `
` wrapper handling) -- **Jeff:** D-11 (`
` vs ``) needs decision - -— Forge diff --git a/.ai-team/decisions/inbox/forge-m15-html-fidelity-strategy.md b/.ai-team/decisions/inbox/forge-m15-html-fidelity-strategy.md deleted file mode 100644 index c7773897a..000000000 --- a/.ai-team/decisions/inbox/forge-m15-html-fidelity-strategy.md +++ /dev/null @@ -1,364 +0,0 @@ -# M15 HTML Fidelity Strategy — Post-PR #377 Assessment - -**Date:** 2026-02-28 -**Author:** Forge (Lead / Web Forms Reviewer) -**Requested by:** Jeffrey T. Fritz -**Context:** PR #377 merged to upstream/dev — contains M11–M14 deliverables including full HTML fidelity audit (132 comparisons), 14 bug fixes, post-fix re-run (131 divergences, 1 exact match), WebFormsPage component, data alignment, and NamingContainer. - ---- - -## 1. Current State Assessment - -### Where We Stand - -After PR #377, we have the most complete picture of HTML fidelity this project has ever produced. The numbers tell a clear story: - -| Metric | Value | Assessment | -|--------|-------|------------| -| Total comparisons | 132 (128 unique + 4 HyperLink case dupes) | Good coverage of captured controls | -| Exact matches | **1** (Literal-3) | Sobering — but misleading (see below) | -| Verified structural improvements | 11 controls | The 14 bug fixes landed and verified | -| Missing Blazor captures | 64 variants | **The #1 coverage gap** | -| Sample parity false positives | ~22 entries | Noise masking real signal | -| Genuine remaining structural bugs | ~5 controls | Fixable in M15 | -| Data control investigations needed | 4 controls | Unknown severity | - -**The "1 exact match" number is misleading.** The vast majority of divergences are caused by **different sample data** between WebForms and Blazor, not by component bugs. If we align the sample data, I estimate **15–20 controls** would achieve exact or near-exact match immediately. The actual HTML structure is correct for most Tier 1 controls — DropDownList, HyperLink, HiddenField, Image (minus `longdesc`), ImageMap, Label, Literal, Panel, PlaceHolder, and AdRotator all render correct tag structure with only content differences. - -### Controls by Distance from Pixel-Perfect - -**Near-perfect (correct structure, needs sample data alignment only):** ~12 controls -- AdRotator, DropDownList (6 variants), HiddenField, HyperLink (4 variants), Image (1 of 2), ImageMap, Label (3 variants), Literal (2 of 3), Panel (3 variants), PlaceHolder - -**Close (1–2 fixable attribute/structural issues):** ~6 controls -- Button (fixed `` — now needs sample parity only), BulletedList (still needs `
    ` + `list-style-type`), CheckBox (remove `` wrapper), Image (remove empty `longdesc`), LinkButton (add `href` + `class`), FileUpload (GUID attribute leak) - -**Moderate (structural work needed):** ~4 controls -- Calendar (73% similarity — missing styles, `title`, navigation header differences), RadioButtonList (GUID IDs), GridView (33 line diff — mixed structural + sample), DataList (110 line diff — needs investigation) - -**Far (significant structural divergence):** ~3 controls -- TreeView (deep structural differences in node rendering), ListView (182 line diff — template-based output), Repeater (64 line diff) - -**Unknown (missing Blazor captures):** ~20+ controls -- All Login family (7 controls), all Validators (6 controls), Menu (9 variants), TextBox (7 variants), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), SiteMapPath (2), MultiView, Table (3), DataPager, DetailsView, FormView - ---- - -## 2. Remaining Divergence Analysis - -### Category A — Fixable Structural Bugs (5 controls, ~8–14 hours) - -These are genuine HTML structure differences where the Blazor component renders wrong elements or missing attributes. All fixable. - -| Control | Bug | Effort | Variants Fixed | -|---------|-----|--------|----------------| -| **BulletedList** | Still renders `
      ` for numbered lists (should be `
        `); wrong `list-style-type` values (`disc`/`circle` vs `decimal`/`square`) | 1–2 hrs | 3 | -| **LinkButton** | Missing `href` attribute; missing `CssClass` → `class` pass-through | 1–2 hrs | 3 | -| **CheckBox** | Extra wrapping `` around checkbox+label pair for TextAlign=Right | 1–2 hrs | 3 | -| **Image** | Emits empty `longdesc=""` when `DescriptionUrl` is unset | 30 min | 2 | -| **FileUpload** | Stray GUID fragment leaks as HTML attribute (CSS isolation scope artifact) | 1 hr | 1 | - -**Status of PR #377 fixes:** Button (``), BulletedList `` removal, LinkButton `href`, Calendar border/`
`, CheckBox wrapper removal, Image `longdesc`, DataList border-collapse, GridView `rules`/`border`, and TreeView compression were all **fixed and verified** in the post-fix capture. However, BulletedList `
    ` rendering and `list-style-type` mapping were NOT addressed. LinkButton `class` was NOT addressed. CheckBox may still have issues depending on capture state vs. code state. - -### Category B — Sample Parity Issues (NOT component bugs, ~22 entries) - -The single highest-value action for improving match rates. These controls render correct HTML structure but use completely different data/text/URLs between WebForms and Blazor samples: - -| Control | Nature of Difference | -|---------|---------------------| -| AdRotator | Bing vs Microsoft ad content, different images | -| BulletedList | Apple/Banana/Cherry vs Item One/Two/Three | -| Button | "Blue Button" w/ styling vs "Click me!" no styling | -| CheckBox | "Accept Terms" vs "I agree to terms" | -| DropDownList (×6) | Different option text/values throughout | -| HiddenField | Different `value` attribute | -| HyperLink (×4) | Bing vs GitHub, different text/URLs | -| Image (×2) | Different src/alt | -| ImageMap | Different coordinates/URLs | -| Label (×3) | Different text/classes | -| Literal (×2) | Different text content | -| Panel (×3) | Different inner content | -| PlaceHolder | Different placeholder text | - -**Fix approach:** Update Blazor sample pages to mirror exact WebForms content. This is a Jubilee task — mechanical but tedious. Estimated effort: 4–6 hours. Impact: potentially **20+ controls move to exact match** in one sprint. - -### Category C — Intentional/Unfixable Divergences (D-01 through D-10) - -These are permanent architectural differences. The normalizer already handles them. No action needed. - -| D-Code | What It Is | Status | -|--------|-----------|--------| -| D-01 | ID mangling (`ctl00_` prefixes) | ✅ Normalized — stripped before comparison | -| D-02 | `__doPostBack` → `@onclick` | ✅ Normalized — replaced with placeholder | -| D-03 | ViewState hidden fields | ✅ Normalized — stripped | -| D-04 | WebResource.axd URLs | ✅ Normalized — stripped | -| D-05 | Chart `` vs `` | ⛔ Excluded from audit entirely | -| D-06 | Menu Table mode (Blazor = List only) | ✅ Documented — 4 variants permanently divergent | -| D-07 | TreeView JS injection | ✅ Normalized — JS stripped | -| D-08 | Calendar `__doPostBack` | ✅ Normalized — postback replaced | -| D-09 | Login control auth infrastructure | ✅ Documented — compare visual shell only | -| D-10 | Validator client-side scripts | ✅ Documented — compare `` only | - -**New divergence candidates identified (need decision):** - -| Proposed | What It Is | Recommendation | -|----------|-----------|----------------| -| **D-11** | GUID-based IDs for CheckBox/RadioButton/RadioButtonList/FileUpload | **Fix, don't register as intentional.** GUIDs make HTML non-deterministic and untargetable by CSS/JS. Controls should use developer-provided `ID` parameter and append `_0`, `_1` per Web Forms convention. | -| **D-12** | Boolean attribute format: `selected=""` (HTML5) vs `selected="selected"` (XHTML) | **Register as intentional.** Both are valid HTML. Blazor uses HTML5-style; Web Forms uses XHTML-style. Add normalizer rule to treat as equivalent. | -| **D-13** | Calendar previous-month day padding (WF shows Jan 25–31; Blazor starts at Feb 1) | **Fix.** Web Forms Calendar pads the first week with previous month's days. Our Blazor Calendar should do the same — it's visible structural content. | -| **D-14** | Calendar style property pass-through (WF applies inline styles for ForeColor, Font, etc.; Blazor doesn't) | **Fix progressively.** Calendar style application is incomplete — the `
` nested hierarchy per node; Blazor simplified. This is a deep structural choice unlikely to be changed without major refactor. | 30–50% — structural redesign needed for parity | +| **Calendar** | Will never hit 100% due to `cursor:pointer` vs `color:#000000`, WF `title="Calendar"`, and style granularity differences | Ceiling ~95% with effort | +| **Login controls** | Auth infrastructure divergence (D-09) — visual HTML can match but functional attributes won't | Visual shell match possible; functional attributes diverge | +| **Validators** | Client-side script infrastructure (D-10) — `` output matchable but evaluation attributes won't | `` match possible; JS attributes diverge | + +### What "Pixel-Perfect" Realistically Means + +For this project, "pixel-perfect" should be defined as: + +> **After normalization (stripping intentional divergences D-01 through D-10+), the Blazor component's rendered HTML structure — tag names, nesting, CSS classes, and meaningful attributes — matches the Web Forms gold standard.** + +That definition excludes: +- ID values (D-01 — always different) +- Event mechanism attributes (D-02 — `__doPostBack` vs `@onclick`) +- Infrastructure elements (D-03, D-04 — ViewState, WebResource.axd) +- Content data (sample parity — responsibility of the migration developer, not the library) + +Under this definition, **I believe 20–25 controls can achieve "pixel-perfect" status** with the work outlined in M15. Another 10–15 can achieve "near-perfect" (>90% structural match). The remaining ~10–15 controls (Chart, TreeView, Menu Table-mode, Login family, Validators) will have documented intentional divergences that are architecturally unavoidable. + +--- + +## 5. Recommended M15 Scope + +### Milestone 15: HTML Fidelity Closure + +**Branch:** `milestone15/html-fidelity-closure` +**Duration estimate:** 2–3 weeks +**Theme:** Close the gap between audit findings and actual HTML fidelity. Move from 1 exact match to 15+ exact matches. + +### Work Items + +| # | Work Item | Description | Owner | Size | Priority | +|---|-----------|-------------|-------|------|----------| +| M15-01 | **Sample data alignment** | Update ALL Blazor sample pages to mirror exact WebForms sample content (text, URLs, values, attributes, data items). Use WebForms captures in `audit-output/webforms/` as source of truth. Cover: AdRotator, BulletedList, Button, CheckBox, DropDownList, HiddenField, HyperLink, Image, ImageMap, Label, LinkButton, Literal, Panel, PlaceHolder. | Jubilee | L | 🔴 P0 | +| M15-02 | **BulletedList `
    ` fix** | Render `
      ` when `BulletStyle` is Numbered/LowerAlpha/UpperAlpha/LowerRoman/UpperRoman. Fix `list-style-type` CSS mapping: Numbered→decimal, Circle→circle, Disc→disc, Square→square, LowerAlpha→lower-alpha, UpperAlpha→upper-alpha, LowerRoman→lower-roman, UpperRoman→upper-roman. | Cyclops | S | 🔴 P1 | +| M15-03 | **LinkButton `class` pass-through** | Ensure `CssClass` parameter maps to `class` attribute on the rendered `` element. | Cyclops | XS | 🔴 P1 | +| M15-04 | **Image `longdesc` conditional** | Only render `longdesc` attribute when `DescriptionUrl` has a non-empty value. | Cyclops | XS | 🟡 P2 | +| M15-05 | **FileUpload GUID attribute removal** | Investigate and remove stray CSS-isolation-scope GUID that leaks as an HTML attribute. | Cyclops | XS | 🟡 P2 | +| M15-06 | **CheckBox `` removal verification** | Verify the PR #377 fix is complete for all TextAlign variants. If `` wrapper persists for any variant, fix it. | Cyclops | S | 🟡 P2 | +| M15-07 | **Stable IDs for CheckBox/RadioButtonList** | Replace GUID-based IDs with developer-provided `ID` parameter. For RadioButtonList, append `_0`, `_1`, etc. per Web Forms convention. Fix `name` attribute to use control ID. | Cyclops | M | 🟡 P2 | +| M15-08 | **Add `data-audit-control` markers** | Add markers to existing Blazor sample pages for: TextBox (7), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), Button (variants 2–5), SiteMapPath (2), Table (3), MultiView (1). ~25 new comparisons. | Jubilee | M | 🟡 P2 | +| M15-09 | **Normalizer enhancements** | (a) Case-insensitive folder matching, (b) Boolean attribute normalization, (c) Empty `style=""` stripping, (d) GUID ID normalization. | Cyclops | S | 🟢 P3 | +| M15-10 | **Data control deep investigation** | Line-by-line classification of DataList (110 lines), GridView (33 lines), ListView (182 lines), Repeater (64 lines) divergences. Separate genuine bugs from sample parity and D-01/D-02. File issues for genuine bugs. | Forge | M | 🟢 P3 | +| M15-11 | **Re-run full audit pipeline** | After all fixes and sample alignment, re-run the complete capture + normalize + diff pipeline. Target: ≥15 exact matches. Produce updated diff report. | Colossus | M | 🟢 P3 | +| M15-12 | **Update divergence registry** | Add D-11 through D-14 as appropriate. Document any new divergences discovered during M15 investigation. Update `DIVERGENCE-REGISTRY.md`. | Forge | S | 🟢 P3 | + +### Agent Assignments + +| Agent | Work Items | Role | +|-------|-----------|------| +| **Forge** | M15-10, M15-12 | Data control investigation, divergence registry, overall review | +| **Cyclops** | M15-02 through M15-07, M15-09 | Bug fixes, normalizer enhancements | +| **Jubilee** | M15-01, M15-08 | Sample alignment, marker insertion | +| **Colossus** | M15-11 | Full pipeline re-run | +| **Rogue** | — | Test updates for any HTML fixes Cyclops makes | +| **Beast** | — | Doc updates post-M15 if new exact matches warrant verification badges | + +### Dependencies + +``` +M15-01 ──→ M15-11 (sample alignment before re-run) +M15-02 through M15-07 ──→ M15-11 (bug fixes before re-run) +M15-09 ──→ M15-11 (normalizer fixes before re-run) +M15-08 ──→ M15-11 (new markers before re-run) +M15-10 ──→ M15-12 (investigation informs registry) +M15-11 ──→ M15-12 (re-run results inform final registry) +``` + +### Exit Criteria + +1. ≥15 controls achieve exact normalized HTML match (up from 1) +2. All Category A structural bugs (BulletedList, LinkButton, Image, FileUpload, CheckBox) are fixed +3. Blazor sample data aligned to WebForms for all Tier 1 controls with existing captures +4. ≥25 new Blazor comparisons enabled via `data-audit-control` markers +5. Data control divergences (DataList, GridView, ListView, Repeater) classified with issues filed for genuine bugs +6. Normalizer enhanced with boolean attribute, case-insensitive matching, and GUID ID handling +7. Updated diff report showing improved match rates +8. Divergence registry updated to D-14 + +### Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|-----------| +| Sample alignment takes longer than estimated due to complex data binding differences | Medium | Low | Prioritize simple controls first; complex data controls can follow in M16 | +| BulletedList `
        ` fix breaks existing tests | Low | Medium | Run full test suite before PR; bUnit tests likely cover this | +| GUID ID replacement breaks Blazor event binding | Medium | Medium | Test interactivity after ID stabilization; Blazor may use `@ref` not ID for event wiring | +| Post-fix re-run reveals new regressions | Low | Low | Git bisect to isolate; targeted fix | +| Calendar style pass-through is larger than estimated | High | Medium | Defer Calendar deep fix to M16 if scope grows; capture current similarity as baseline | + +--- + +## 6. Beyond M15 — The Road to Maximum Fidelity + +If M15 hits its targets (15+ exact matches, all Tier 1 structural bugs fixed, sample parity for simple controls), the roadmap for M16+ looks like this: + +| Milestone | Focus | Expected Outcome | +|-----------|-------|-----------------| +| **M16** | Calendar deep fix (styles, day padding, title), TreeView structural alignment investigation, Menu List-mode Blazor captures | Calendar → 90%+; TreeView assessment; Menu assessed | +| **M17** | Login family visual shell captures + comparison, Validator `` comparison | Coverage expanded to 40+ controls compared | +| **M18** | Data control sample alignment + structural fixes (GridView, DataList, ListView, Repeater) | Data controls assessed and fixed | +| **M19** | CI integration — automated HTML regression in build pipeline | Prevents regression going forward | + +The honest bottom line: **This library will never achieve 100% exact HTML match for all controls.** Chart, TreeView, Menu Table-mode, and the event mechanism infrastructure are permanently divergent by design. But for the ~35 controls that represent the everyday migration path (Button, TextBox, Label, DropDownList, GridView, etc.), we should be able to reach 90%+ structural match — and that's what developers migrating from Web Forms actually need. + +--- + +**Decision:** M15 scope as defined above is recommended. Forge endorses this plan. + +— Forge, Lead / Web Forms Reviewer + +### 2026-02-26: ClientIDMode implementation and testing (consolidated) + +**By:** Cyclops, Rogue + +**What:** Implemented `ClientIDMode` enum (Static, Predictable, AutoID, Inherit) and property on `BaseWebFormsComponent`. Updated `ComponentIdGenerator` to respect all four modes: Inherit resolves by walking parents (defaults to Predictable), AutoID preserves ctl00 prefix behavior, Static returns raw ID with no parent walking, Predictable walks parents but skips ctl00 prefixes. `UseCtl00Prefix` on NamingContainer now only applies in AutoID mode. Rogue wrote 12 bUnit tests: Static (3), Predictable (3), AutoID (2), Inherit (2), Edge Cases (2) all pass. Discovered P1 regression: existing `UseCtl00Prefix_PrependsCtl00ToClientID` test failed because Inherit->Predictable doesn't include ctl00 prefixes. Fix applied: NamingContainer auto-sets ClientIDMode to AutoID when `UseCtl00Prefix="true"`, preserving backward compatibility. + +**Why:** Web Forms `System.Web.UI.Control.ClientIDMode` is a core property controlling client-side element ID generation. Migration fidelity requires all four modes so existing JavaScript, CSS selectors, and jQuery targeting Web Forms ClientIDs continue working after migration. Default Inherit->Predictable preserves backward compatibility with all existing components. + +### 2026-02-26: Data control divergence analysis and investigation (consolidated) + +**By:** Forge, Rogue + +**What:** Line-by-line classification of all HTML divergences in DataList (110 lines), GridView (33 lines), ListView (182 lines), and Repeater (64 lines). Key findings evolved across two analysis passes: + +1. **Sample parity is the dominant cause** (90%+) Blazor samples use different templates, styles, columns, and data formats. ListView and Repeater have zero component bugs; all diffs are sample authoring. +2. **Five genuine bugs identified:** BUG-DL-2 (missing `itemtype`), BUG-DL-3 (unconditional `border-collapse`), BUG-GV-1 (GridLines default mismatch), BUG-GV-2 (missing `border-collapse`), BUG-GV-3 (empty `
` vs ` `). Of these, 3 were fixed in PR #377; remaining: BUG-GV-4b (`UseAccessibleHeader` default), BUG-GV-3, BUG-GV-4a (`
` and cell-level styles from `TitleStyle`, `DayStyle`, `OtherMonthDayStyle`, `WeekendDayStyle`, `TodayDayStyle` etc. are not being applied. This is a significant fidelity gap for Calendar specifically. | - -### Category D — Normalizer Artifacts (3 items) - -| Issue | Impact | Fix | -|-------|--------|-----| -| HyperLink/Hyperlink case-sensitivity duplication | 4 phantom entries in diff report | Case-insensitive folder matching in diff script | -| `selected=""` vs `selected="selected"` | False divergence in DropDownList | Add normalizer rule for boolean HTML attributes | -| Empty `style=""` on some controls | Noise in diffs | Strip empty `style=""` attributes in normalizer | - ---- - -## 3. Prioritized Next Steps — What M15 Should Focus On - -Ranked by **impact per unit of effort**: - -### 🔴 Tier 1 Priority: Sample Data Alignment (Impact: MASSIVE, Effort: MEDIUM) - -**This is the single highest-leverage action.** One sprint of sample alignment work could move us from 1 exact match to 15–20+ exact matches. Every other effort is wasted if the samples don't match — we can't tell what's a bug vs. what's different data. - -- Update all Blazor sample pages to use identical text, values, URLs, styles as WebForms samples -- Covers: AdRotator, BulletedList, Button, CheckBox, DropDownList, HiddenField, HyperLink, Image, ImageMap, Label, Literal, Panel, PlaceHolder, LinkButton -- Owner: Jubilee -- Effort: 4–6 hours -- Impact: ~22 false-positive divergences eliminated; true structural bugs surface cleanly - -### 🔴 Tier 2 Priority: Fix Remaining Structural Bugs (Impact: HIGH, Effort: LOW-MEDIUM) - -Ship the remaining P1–P3 bug fixes that were identified but not addressed in PR #377: - -| # | Fix | Effort | Impact | -|---|-----|--------|--------| -| 1 | BulletedList: `
    ` for numbered + correct `list-style-type` mapping | 1–2 hrs | 3 variants → exact match | -| 2 | LinkButton: Pass `CssClass` → `class` attribute | 1 hr | 3 variants improved | -| 3 | Image: Only emit `longdesc` when non-empty | 30 min | 2 variants → exact match | -| 4 | FileUpload: Remove stray GUID attribute leak | 1 hr | 1 variant → exact match | -| 5 | CheckBox: Remove wrapping `` (verify post-PR #377 state) | 1 hr | 3 variants improved | -| 6 | RadioButtonList: Stable IDs (not GUIDs) | 1–2 hrs | 2 variants improved | - -Owner: Cyclops -Total effort: 6–9 hours -Impact: 14+ variants improved, 6+ potentially exact match - -### 🟡 Tier 3 Priority: Close Blazor Capture Gaps (Impact: HIGH, Effort: MEDIUM) - -64 variants have no Blazor capture. Prioritize by ROI: - -**Phase A — Add `data-audit-control` markers to EXISTING Blazor pages (2–3 hrs):** -- TextBox (7 variants), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), Button (variants 2–5), Literal (variant 3), SiteMapPath (2), Table (3), MultiView (1) -- These controls already have Blazor sample pages — they just lack `data-audit-control` markers -- Impact: ~25 more comparisons enabled - -**Phase B — Write new Blazor sample pages for missing controls (6–10 hrs):** -- Menu (5 List-mode variants — 4 Table-mode are permanently divergent per D-06) -- Login family (7 controls × 2 variants = 14 captures) — visual shell comparison -- Validators (6 controls × 3–4 variants = ~23 captures) — `` comparison only -- DataPager, DetailsView, FormView -- Impact: ~42 more comparisons - -Owner: Jubilee (samples), Colossus (captures) - -### 🟢 Tier 4 Priority: Normalizer Enhancements (Impact: MEDIUM, Effort: LOW) - -| Enhancement | Effort | Impact | -|------------|--------|--------| -| Case-insensitive folder matching (kills 4 HyperLink dupes) | 30 min | Cleaner reports | -| Boolean attribute normalization (`selected=""` ↔ `selected="selected"`) | 30 min | DropDownList false positives eliminated | -| Empty `style=""` stripping | 15 min | Noise reduction | -| GUID ID normalization (strip or placeholder) | 1 hr | CheckBox/RadioButtonList/FileUpload noise reduced | - -Owner: Cyclops -Total effort: 2–3 hours - -### 🟢 Tier 5 Priority: Data Control Deep Investigation (Impact: UNKNOWN, Effort: MEDIUM) - -DataList (110 lines), GridView (33 lines), ListView (182 lines), Repeater (64 lines) — all have both captures but show significant divergences. Need line-by-line classification. - -**My assessment before investigation:** -- **GridView** (33 lines) — Likely mostly sample parity. The post-fix capture shows correct `
`/`` structure, `rules`/`border` attributes. Remaining diff is mostly different column names and content. Probably fixable with sample alignment. -- **DataList** (110 lines) — The `
` structure is the right approach, but template rendering likely produces different cell content. Mix of sample parity and template handling differences. -- **Repeater** (64 lines) — Repeater is unusual because it has no default chrome — it renders pure template output. Divergence is almost certainly 100% sample parity. -- **ListView** (182 lines) — Largest divergence. ListView's template model is the most flexible in Web Forms and the hardest to match structurally. This control is likely to have genuine structural differences in how templates are composed. - -Owner: Forge (classification), Cyclops (fixes) -Effort: 4–8 hours investigation, unknown fix effort - -### 🔵 Tier 6 Priority: Calendar Deep Fix (Impact: HIGH for one control, Effort: HIGH) - -Calendar is the most complex control and the closest to pixel-perfect among complex controls (73% similarity on best variant). Remaining gaps: - -1. **Previous-month day padding** — WF shows Jan 25–31 in the first row; Blazor starts at Feb 1 -2. **Style property pass-through** — `TitleStyle`, `DayStyle`, `OtherMonthDayStyle`, `WeekendDayStyle`, `TodayDayStyle`, `NextPrevStyle`, `SelectorStyle` inline styles not applied -3. **`title` attribute on `
`** — WF emits `title="Calendar"`; Blazor doesn't -4. **`id` attribute on `
`** — WF emits developer ID; Blazor doesn't (may be NamingContainer related) -5. **`color` attribute on day links** — WF emits `style="color:#000000;"`; Blazor uses `cursor:pointer` -6. **`background-color` on title row** — WF emits `background-color:#c0c0c0`; Blazor doesn't - -Owner: Cyclops -Effort: 5–8 hours (touching multiple Razor files and style resolution logic) -Impact: Could push Calendar from 73% to 90%+ similarity - ---- - -## 4. Pixel-Perfect Realism - -Let me be blunt about what "pixel-perfect" means for this project. - -### Controls That CAN Achieve Exact Normalized Match - -With sample alignment + remaining bug fixes, these controls should achieve **100% normalized HTML match**: - -| Control | What's Needed | Confidence | -|---------|--------------|------------| -| Literal | ✅ Already exact (1 of 3 variants) | 100% | -| HiddenField | Sample alignment only | 99% | -| PlaceHolder | Sample alignment only | 99% | -| Label | Sample alignment only | 98% | -| Panel | Sample alignment only | 98% | -| AdRotator | Sample alignment only | 95% | -| Image | Remove `longdesc` + sample alignment | 95% | -| HyperLink | Sample alignment only | 95% | -| ImageMap | Sample alignment only | 95% | -| DropDownList | Sample alignment + boolean attr normalizer | 90% | -| BulletedList | `
    ` fix + `list-style-type` + sample alignment | 90% | -| LinkButton | `href` + `class` fix + sample alignment | 85% | -| Button | Sample alignment only (already fixed to ``) | 85% | - -**Realistic target: 13–15 exact matches after M15 (up from 1 today).** - -### Controls That Can Achieve Near-Match (>90% normalized similarity) - -| Control | Gap | Realistic Ceiling | -|---------|-----|-------------------| -| Calendar | Style pass-through, day padding, title | 90–95% with fixes | -| CheckBox | `` removal, stable IDs | 90–95% with fixes | -| RadioButtonList | Stable IDs | 90% with ID fix | -| FileUpload | GUID attribute removal | 95% | -| GridView | Sample alignment + investigation | 85–95% TBD | - -### Controls That Will ALWAYS Have Structural Differences - -Be honest. These controls have fundamental architectural gaps that make exact HTML match impossible or impractical: - -| Control | Why | Permanent Gap | -|---------|-----|---------------| -| **Chart** | `` vs `` — completely different rendering technology | 100% different (D-05) | -| **Menu (Table mode)** | Blazor only implements List mode; 4 Table-mode variants are permanently divergent | Partial (D-06) — List mode is comparable | -| **TreeView** | Web Forms uses `
+-
` nested hierarchy per node; Blazor simplified. This is a deep structural choice unlikely to be changed without major refactor. | 30–50% — structural redesign needed for parity | -| **Calendar** | Will never hit 100% due to `cursor:pointer` vs `color:#000000`, WF `title="Calendar"`, and style granularity differences | Ceiling ~95% with effort | -| **Login controls** | Auth infrastructure divergence (D-09) — visual HTML can match but functional attributes won't | Visual shell match possible; functional attributes diverge | -| **Validators** | Client-side script infrastructure (D-10) — `` output matchable but evaluation attributes won't | `` match possible; JS attributes diverge | - -### What "Pixel-Perfect" Realistically Means - -For this project, "pixel-perfect" should be defined as: - -> **After normalization (stripping intentional divergences D-01 through D-10+), the Blazor component's rendered HTML structure — tag names, nesting, CSS classes, and meaningful attributes — matches the Web Forms gold standard.** - -That definition excludes: -- ID values (D-01 — always different) -- Event mechanism attributes (D-02 — `__doPostBack` vs `@onclick`) -- Infrastructure elements (D-03, D-04 — ViewState, WebResource.axd) -- Content data (sample parity — responsibility of the migration developer, not the library) - -Under this definition, **I believe 20–25 controls can achieve "pixel-perfect" status** with the work outlined in M15. Another 10–15 can achieve "near-perfect" (>90% structural match). The remaining ~10–15 controls (Chart, TreeView, Menu Table-mode, Login family, Validators) will have documented intentional divergences that are architecturally unavoidable. - ---- - -## 5. Recommended M15 Scope - -### Milestone 15: HTML Fidelity Closure - -**Branch:** `milestone15/html-fidelity-closure` -**Duration estimate:** 2–3 weeks -**Theme:** Close the gap between audit findings and actual HTML fidelity. Move from 1 exact match to 15+ exact matches. - -### Work Items - -| # | Work Item | Description | Owner | Size | Priority | -|---|-----------|-------------|-------|------|----------| -| M15-01 | **Sample data alignment** | Update ALL Blazor sample pages to mirror exact WebForms sample content (text, URLs, values, attributes, data items). Use WebForms captures in `audit-output/webforms/` as source of truth. Cover: AdRotator, BulletedList, Button, CheckBox, DropDownList, HiddenField, HyperLink, Image, ImageMap, Label, LinkButton, Literal, Panel, PlaceHolder. | Jubilee | L | 🔴 P0 | -| M15-02 | **BulletedList `
    ` fix** | Render `
      ` when `BulletStyle` is Numbered/LowerAlpha/UpperAlpha/LowerRoman/UpperRoman. Fix `list-style-type` CSS mapping: Numbered→decimal, Circle→circle, Disc→disc, Square→square, LowerAlpha→lower-alpha, UpperAlpha→upper-alpha, LowerRoman→lower-roman, UpperRoman→upper-roman. | Cyclops | S | 🔴 P1 | -| M15-03 | **LinkButton `class` pass-through** | Ensure `CssClass` parameter maps to `class` attribute on the rendered `` element. | Cyclops | XS | 🔴 P1 | -| M15-04 | **Image `longdesc` conditional** | Only render `longdesc` attribute when `DescriptionUrl` has a non-empty value. | Cyclops | XS | 🟡 P2 | -| M15-05 | **FileUpload GUID attribute removal** | Investigate and remove stray CSS-isolation-scope GUID that leaks as an HTML attribute. | Cyclops | XS | 🟡 P2 | -| M15-06 | **CheckBox `` removal verification** | Verify the PR #377 fix is complete for all TextAlign variants. If `` wrapper persists for any variant, fix it. | Cyclops | S | 🟡 P2 | -| M15-07 | **Stable IDs for CheckBox/RadioButtonList** | Replace GUID-based IDs with developer-provided `ID` parameter. For RadioButtonList, append `_0`, `_1`, etc. per Web Forms convention. Fix `name` attribute to use control ID. | Cyclops | M | 🟡 P2 | -| M15-08 | **Add `data-audit-control` markers** | Add markers to existing Blazor sample pages for: TextBox (7), RadioButton (3), CheckBoxList (2), ImageButton (2), ListBox (2), Button (variants 2–5), SiteMapPath (2), Table (3), MultiView (1). ~25 new comparisons. | Jubilee | M | 🟡 P2 | -| M15-09 | **Normalizer enhancements** | (a) Case-insensitive folder matching, (b) Boolean attribute normalization, (c) Empty `style=""` stripping, (d) GUID ID normalization. | Cyclops | S | 🟢 P3 | -| M15-10 | **Data control deep investigation** | Line-by-line classification of DataList (110 lines), GridView (33 lines), ListView (182 lines), Repeater (64 lines) divergences. Separate genuine bugs from sample parity and D-01/D-02. File issues for genuine bugs. | Forge | M | 🟢 P3 | -| M15-11 | **Re-run full audit pipeline** | After all fixes and sample alignment, re-run the complete capture + normalize + diff pipeline. Target: ≥15 exact matches. Produce updated diff report. | Colossus | M | 🟢 P3 | -| M15-12 | **Update divergence registry** | Add D-11 through D-14 as appropriate. Document any new divergences discovered during M15 investigation. Update `DIVERGENCE-REGISTRY.md`. | Forge | S | 🟢 P3 | - -### Agent Assignments - -| Agent | Work Items | Role | -|-------|-----------|------| -| **Forge** | M15-10, M15-12 | Data control investigation, divergence registry, overall review | -| **Cyclops** | M15-02 through M15-07, M15-09 | Bug fixes, normalizer enhancements | -| **Jubilee** | M15-01, M15-08 | Sample alignment, marker insertion | -| **Colossus** | M15-11 | Full pipeline re-run | -| **Rogue** | — | Test updates for any HTML fixes Cyclops makes | -| **Beast** | — | Doc updates post-M15 if new exact matches warrant verification badges | - -### Dependencies - -``` -M15-01 ──→ M15-11 (sample alignment before re-run) -M15-02 through M15-07 ──→ M15-11 (bug fixes before re-run) -M15-09 ──→ M15-11 (normalizer fixes before re-run) -M15-08 ──→ M15-11 (new markers before re-run) -M15-10 ──→ M15-12 (investigation informs registry) -M15-11 ──→ M15-12 (re-run results inform final registry) -``` - -### Exit Criteria - -1. ≥15 controls achieve exact normalized HTML match (up from 1) -2. All Category A structural bugs (BulletedList, LinkButton, Image, FileUpload, CheckBox) are fixed -3. Blazor sample data aligned to WebForms for all Tier 1 controls with existing captures -4. ≥25 new Blazor comparisons enabled via `data-audit-control` markers -5. Data control divergences (DataList, GridView, ListView, Repeater) classified with issues filed for genuine bugs -6. Normalizer enhanced with boolean attribute, case-insensitive matching, and GUID ID handling -7. Updated diff report showing improved match rates -8. Divergence registry updated to D-14 - -### Risk Assessment - -| Risk | Likelihood | Impact | Mitigation | -|------|-----------|--------|-----------| -| Sample alignment takes longer than estimated due to complex data binding differences | Medium | Low | Prioritize simple controls first; complex data controls can follow in M16 | -| BulletedList `
        ` fix breaks existing tests | Low | Medium | Run full test suite before PR; bUnit tests likely cover this | -| GUID ID replacement breaks Blazor event binding | Medium | Medium | Test interactivity after ID stabilization; Blazor may use `@ref` not ID for event wiring | -| Post-fix re-run reveals new regressions | Low | Low | Git bisect to isolate; targeted fix | -| Calendar style pass-through is larger than estimated | High | Medium | Defer Calendar deep fix to M16 if scope grows; capture current similarity as baseline | - ---- - -## 6. Beyond M15 — The Road to Maximum Fidelity - -If M15 hits its targets (15+ exact matches, all Tier 1 structural bugs fixed, sample parity for simple controls), the roadmap for M16+ looks like this: - -| Milestone | Focus | Expected Outcome | -|-----------|-------|-----------------| -| **M16** | Calendar deep fix (styles, day padding, title), TreeView structural alignment investigation, Menu List-mode Blazor captures | Calendar → 90%+; TreeView assessment; Menu assessed | -| **M17** | Login family visual shell captures + comparison, Validator `` comparison | Coverage expanded to 40+ controls compared | -| **M18** | Data control sample alignment + structural fixes (GridView, DataList, ListView, Repeater) | Data controls assessed and fixed | -| **M19** | CI integration — automated HTML regression in build pipeline | Prevents regression going forward | - -The honest bottom line: **This library will never achieve 100% exact HTML match for all controls.** Chart, TreeView, Menu Table-mode, and the event mechanism infrastructure are permanently divergent by design. But for the ~35 controls that represent the everyday migration path (Button, TextBox, Label, DropDownList, GridView, etc.), we should be able to reach 90%+ structural match — and that's what developers migrating from Web Forms actually need. - ---- - -**Decision:** M15 scope as defined above is recommended. Forge endorses this plan. - -— Forge, Lead / Web Forms Reviewer diff --git a/.ai-team/log/2026-02-26-m16-clientidmode.md b/.ai-team/log/2026-02-26-m16-clientidmode.md new file mode 100644 index 000000000..1a38dd2a1 --- /dev/null +++ b/.ai-team/log/2026-02-26-m16-clientidmode.md @@ -0,0 +1,39 @@ +# Session: 2026-02-26 — M16 ClientIDMode + +**Requested by:** Jeffrey T. Fritz + +## Who Worked + +- **Cyclops:** ClientIDMode enum + property on BaseWebFormsComponent, ComponentIdGenerator refactoring +- **Rogue:** 12 bUnit tests for ClientIDMode (Static, Predictable, AutoID, Inherit modes) + +## What Was Done + +- Implemented `ClientIDMode` enum with four modes: Static, Predictable, AutoID, Inherit +- Added `ClientIDMode` property to `BaseWebFormsComponent` +- Updated `ComponentIdGenerator` to respect all four modes +- Inherit resolves by walking parents, defaulting to Predictable +- Static returns raw ID with no parent walking +- AutoID preserves ctl00 prefix behavior +- Predictable walks parents but skips ctl00 prefixes +- `UseCtl00Prefix` on NamingContainer now only applies in AutoID mode +- Fixed NamingContainer.UseCtl00Prefix backward compatibility regression +- Wrote 12 bUnit tests covering all four ClientIDMode values plus edge cases + +## M16 Milestone Work (cumulative) + +- Panel.BackImageUrl support +- LoginView/PasswordRecovery base class migration +- ComponentCatalog fixes +- ClientIDMode implementation (this session) + +## Key Outcomes + +- All 1,313 tests pass (30 new this milestone) +- Branch pushed to upstream +- PR creation requires manual action (HTTP 403 on automated PR creation) + +## Decisions + +- ClientIDMode implementation follows Web Forms `System.Web.UI.Control.ClientIDMode` semantics +- UseCtl00Prefix backward compatibility preserved via NamingContainer auto-setting ClientIDMode to AutoID diff --git a/samples/AfterBlazorServerSide/ComponentCatalog.cs b/samples/AfterBlazorServerSide/ComponentCatalog.cs index 0b37eeb80..92ad623cf 100644 --- a/samples/AfterBlazorServerSide/ComponentCatalog.cs +++ b/samples/AfterBlazorServerSide/ComponentCatalog.cs @@ -27,6 +27,8 @@ public static class ComponentCatalog new("CheckBox", "Editor", "/ControlSamples/CheckBox", "Boolean input control with checked state", new[] { "Style", "Events" }, new[] { "boolean", "checked", "toggle" }), + new("CheckBoxList", "Editor", "/ControlSamples/CheckBoxList", "List of checkboxes for multiple selections", + Keywords: new[] { "checkbox", "list", "multiple", "select" }), new("DropDownList", "Editor", "/ControlSamples/DropDownList", "Single-selection dropdown list control", Keywords: new[] { "select", "combo", "list" }), new("FileUpload", "Editor", "/ControlSamples/FileUpload", "File upload input control", @@ -36,12 +38,16 @@ public static class ComponentCatalog Keywords: new[] { "link", "anchor", "navigation" }), new("Image", "Editor", "/ControlSamples/Image", "Displays an image with alt text support", Keywords: new[] { "img", "picture" }), + new("ImageButton", "Editor", "/ControlSamples/ImageButton", "Clickable image that functions as a button", + Keywords: new[] { "image", "button", "click" }), new("ImageMap", "Editor", "/ControlSamples/ImageMap", "Image with clickable hotspot regions"), new("Label", "Editor", "/ControlSamples/Label", "Renders text as span or accessible label element", Keywords: new[] { "text", "label", "accessibility" }), new("LinkButton", "Editor", "/ControlSamples/LinkButton", "Button rendered as a hyperlink", new[] { "JavaScript" }, new[] { "link", "postback" }), + new("ListBox", "Editor", "/ControlSamples/ListBox", "Scrollable list for single or multiple selection", + Keywords: new[] { "list", "select", "multi", "scroll" }), new("Literal", "Editor", "/ControlSamples/Literal", "Renders text or HTML without additional markup"), new("Panel", "Editor", "/ControlSamples/Panel", "Container that renders as a div element", new[] { "BackImageUrl" }, @@ -61,8 +67,10 @@ public static class ComponentCatalog new[] { "AutoGeneratedColumns", "ShowHideHeader", "Styles" }, new[] { "grid", "table", "legacy" }), new("DataList", "Data", "/ControlSamples/DataList", "Data-bound list with repeating templates", - new[] { "RepeatColumns", "SimpleFlow", "ComplexStyle", "HeaderStyle", "FooterStyle" }, + new[] { "RepeatColumns", "Flow", "ComplexStyle", "HeaderStyle", "FooterStyle" }, new[] { "list", "template", "repeat" }), + new("DataPager", "Data", "/ControlSamples/DataPager", "Paging control for data-bound list controls", + Keywords: new[] { "pager", "pagination", "page" }), new("DetailsView", "Data", "/ControlSamples/DetailsView", "Single-record data display with auto-generated rows", new[] { "Caption", "Styles" }, new[] { "detail", "single", "record" }), @@ -112,6 +120,8 @@ public static class ComponentCatalog Keywords: new[] { "user", "name", "display" }), new("LoginStatus", "Login", "/ControlSamples/LoginStatusAuthenticated", "Shows login/logout link based on auth state", Keywords: new[] { "status", "logout", "link" }), + new("LoginView", "Login", "/ControlSamples/LoginView", "Template-based display for authenticated and anonymous users", + Keywords: new[] { "auth", "template", "anonymous", "authenticated" }), new("PasswordRecovery", "Login", "/ControlSamples/PasswordRecovery", "Multi-step password recovery form", Keywords: new[] { "password", "recovery", "reset", "security" }), diff --git a/src/BlazorWebFormsComponents.Test/ClientIDMode/ClientIDModeTests.razor b/src/BlazorWebFormsComponents.Test/ClientIDMode/ClientIDModeTests.razor new file mode 100644 index 000000000..c4460671e --- /dev/null +++ b/src/BlazorWebFormsComponents.Test/ClientIDMode/ClientIDModeTests.razor @@ -0,0 +1,196 @@ +@inherits BlazorWebFormsTestContext +@using BlazorWebFormsComponents.Enums + +@code { + // ===== Static Mode Tests ===== + + [Fact] + public void StaticMode_RendersRawID() + { + // Arrange & Act + var cut = Render( + @
+- +-
<February 2026>
SunMonTueWedThuFriSat
>25262728293031
>1234567
>891011121314
>15161718192021
>22232425262728
>1234567
+``` + +#### Calendar-4 Diff +```diff +- ++
<February 2026>
SunMonTueWedThuFriSat
>>1234567
>>891011121314
>>15161718192021
>>22232425262728
>>1234567
>>891011121314
+- +- +-
<February 2026>
>>SunMonTueWedThuFriSat>25262728293031>1234567>891011121314>15161718192021>22232425262728>1234567 +- +``` + +#### Calendar-5 Diff +```diff +- ++
>>
<February 2026>
SunMonTueWedThuFriSat
>>1234567
>>891011121314
>>15161718192021
>>22232425262728
>>1234567
>>891011121314
+- +- +-
<February 2026>
SuMoTuWeThFrSa25262728293031123456789101112131415161718192021222324252627281234567 +- +``` + +#### Calendar-6 Diff +```diff +- ++
<February 2026>
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
1234567
891011121314
+- +- +-
« PrevFebruary 2026Next »
SunMonTueWedThuFriSat25262728293031123456789101112131415161718192021222324252627281234567 +- +``` + +#### Calendar-7 Diff +```diff +- ++
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
1234567
891011121314
+- +- +-
<February 2026>
SunMonTueWedThuFriSat25262728293031123456789101112131415161718192021222324252627281234567 +- +``` + +### ChangePassword +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ChangePassword-1 | ❌ Missing in source B | File only exists in first directory | +| ChangePassword-2 | ❌ Missing in source B | File only exists in first directory | + +### CheckBox +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| CheckBox-1 | ⚠️ Divergent | Tag structure differs | +| CheckBox-2 | ⚠️ Divergent | Tag structure differs | +| CheckBox-3 | ⚠️ Divergent | Tag structure differs | + +#### CheckBox-1 Diff +```diff +- ++ ++ +``` + +#### CheckBox-2 Diff +```diff +- ++ ++ +``` + +#### CheckBox-3 Diff +```diff +- ++ ++ +``` + +### CheckBoxList +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| CheckBoxList-1 | ⚠️ Divergent | Tag structure differs | +| CheckBoxList-2 | ⚠️ Divergent | Tag structure differs | + +#### CheckBoxList-1 Diff +```diff +- ++
+- +- +- +- +- +- +- +- +- +- +``` + +#### CheckBoxList-2 Diff +```diff +- ++ +- +- +- +- +- +-
+``` + +### CompareValidator +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| CompareValidator-1 | ❌ Missing in source B | File only exists in first directory | +| CompareValidator-2 | ❌ Missing in source B | File only exists in first directory | +| CompareValidator-3 | ❌ Missing in source B | File only exists in first directory | +| CompareValidator-Submit | ❌ Missing in source B | File only exists in first directory | + +### CreateUserWizard +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| CreateUserWizard-1 | ❌ Missing in source B | File only exists in first directory | +| CreateUserWizard-2 | ❌ Missing in source B | File only exists in first directory | + +### CustomValidator +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| CustomValidator-1 | ❌ Missing in source B | File only exists in first directory | +| CustomValidator-2 | ❌ Missing in source B | File only exists in first directory | +| CustomValidator-Submit | ❌ Missing in source B | File only exists in first directory | + +### DataList +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| DataList | ⚠️ Divergent | 106 line differences | + +#### DataList Diff +```diff +- ++
Simple Widgets
First Widget - $7.99
Second Widget - $13.99
Third Widget - $100.99
Fourth Widget - $10.99
Fifth Widget - $5.99
Sixth Widget - $6.99
Seventh Widget - $12.99
Eighth Widget - $8.99
Ninth Widget - $2.99
Tenth Widget - $3.99
Eleventh Widget - $16.99
Fritz's Widget - $52.70
End of Line
+- +- This is my caption +- +- +- My Widget List +- +- +- +- First Widget +-
+- $7.99 +- +- +- Hi! I'm a separator! I keep things apart +- +- +- Second Widget +-
+- $13.99 +- +- +- Hi! I'm a separator! I keep things apart +- +- +- Third Widget +-
+- $100.99 +- +- +- Hi! I'm a separator! I keep things apart +- +- +- Fourth Widget +-
+- $10.99 +- +- +- Hi! I'm a separator! I keep things apart +... (truncated) +``` + +### DataPager +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| DataPager | ❌ Missing in source B | File only exists in first directory | + +### DetailsView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| DetailsView-1 | ❌ Missing in source A | File only exists in second directory | +| DetailsView-2 | ❌ Missing in source A | File only exists in second directory | +| DetailsView-3 | ❌ Missing in source A | File only exists in second directory | +| DetailsView-4 | ❌ Missing in source A | File only exists in second directory | +| DetailsView | ❌ Missing in source B | File only exists in first directory | + +### DropDownList +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| DropDownList-1 | ⚠️ Divergent | Tag structure differs | +| DropDownList-2 | ⚠️ Divergent | Tag structure differs | +| DropDownList-3 | ⚠️ Divergent | Tag structure differs | +| DropDownList-4 | ⚠️ Divergent | Tag structure differs | +| DropDownList-5 | ⚠️ Divergent | Tag structure differs | +| DropDownList-6 | ⚠️ Divergent | Tag structure differs | + +#### DropDownList-1 Diff +```diff +- +- +- +- +- +- +``` + +#### DropDownList-2 Diff +```diff +- +- +- +- +- +``` + +#### DropDownList-3 Diff +```diff +- +- +- +- +- +``` + +#### DropDownList-4 Diff +```diff +- +- +- +``` + +#### DropDownList-5 Diff +```diff +- +- +- +``` + +#### DropDownList-6 Diff +```diff +- +- +- +``` + +### FileUpload +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| FileUpload | ⚠️ Divergent | Tag structure differs | + +#### FileUpload Diff +```diff +- ++ +- +``` + +### FormView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| FormView | ❌ Missing in source B | File only exists in first directory | + +### GridView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| GridView | ⚠️ Divergent | Tag structure differs | + +#### GridView Diff +```diff +-
++
IDCompanyNameFirstNameLastName&nbsp;&nbsp;
1VirusJohnSmith
2BoringJoseRodriguez
3Fun MachinesJasonRamirez
+- +- +- +- +- +- +- +- +- +- +-
CustomerIDCompanyNameFirstNameLastName  
1VirusJohnSmith +- +- Search for Virus
2BoringJoseRodriguez +- +- Search for Boring
3Fun MachinesJasonRamirez +- +- Search for Fun Machines
+-
+``` + +### HiddenField +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| HiddenField | ⚠️ Divergent | Tag structure differs | + +#### HiddenField Diff +```diff +- ++ +``` + +### Hyperlink +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| HyperLink-1 | ⚠️ Divergent | Tag structure differs | +| HyperLink-2 | ⚠️ Divergent | Tag structure differs | +| HyperLink-3 | ⚠️ Divergent | Tag structure differs | +| HyperLink-4 | ⚠️ Divergent | Tag structure differs | + +#### HyperLink-1 Diff +```diff +- Blue Button ++ GitHub +``` + +#### HyperLink-2 Diff +```diff +- Blue Button ++ GitHub +``` + +#### HyperLink-3 Diff +```diff +- ++ GitHub +``` + +#### HyperLink-4 Diff +```diff +- Blue Button ++ GitHub +``` + +### Image +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Image-1 | ⚠️ Divergent | Tag structure differs | +| Image-2 | ⚠️ Divergent | Tag structure differs | + +#### Image-1 Diff +```diff +- Banner image ++ Sample placeholder image +``` + +#### Image-2 Diff +```diff +- Sized image ++ Image with tooltip +``` + +### ImageButton +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ImageButton-1 | ⚠️ Divergent | Tag structure differs | +| ImageButton-2 | ⚠️ Divergent | Tag structure differs | + +#### ImageButton-1 Diff +```diff +- ++ +``` + +#### ImageButton-2 Diff +```diff +- ++ +``` + +### ImageMap +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ImageMap | ⚠️ Divergent | Tag structure differs | + +#### ImageMap Diff +```diff +- Navigate ++ Navigation demo imageGo to Button samplesGo to CheckBox samplesGo to Image samples +- Go to BingGo to GitHub +- +``` + +### Label +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Label-1 | ⚠️ Divergent | Tag structure differs | +| Label-2 | ⚠️ Divergent | Tag structure differs | +| Label-3 | ⚠️ Divergent | Tag structure differs | + +#### Label-1 Diff +```diff +- Hello World ++ Hello, World! +``` + +#### Label-2 Diff +```diff +- Styled Label ++ Important notice +``` + +#### Label-3 Diff +```diff +- Emphasized ++ +``` + +### LinkButton +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| LinkButton-1 | ⚠️ Divergent | Tag structure differs | +| LinkButton-2 | ⚠️ Divergent | Tag structure differs | +| LinkButton-3 | ⚠️ Divergent | Tag structure differs | + +#### LinkButton-1 Diff +```diff +- Click Me ++ LinkButton1 with Command +``` + +#### LinkButton-2 Diff +```diff +- Submit Form ++ LinkButton2 with Command +``` + +#### LinkButton-3 Diff +```diff +- Disabled Link ++ Click me!! +``` + +### ListBox +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ListBox-1 | ⚠️ Divergent | Tag structure differs | +| ListBox-2 | ⚠️ Divergent | Tag structure differs | + +#### ListBox-1 Diff +```diff +- +- +- +- +- +- +- +- +``` + +#### ListBox-2 Diff +```diff +- +- +- +- +- +- +``` + +### ListView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ListView | ⚠️ Divergent | 158 line differences | + +#### ListView Diff +```diff +- ++
+- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +- ++ +... (truncated) +``` + +### Literal +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Literal-1 | ⚠️ Divergent | Tag structure differs | +| Literal-2 | ⚠️ Divergent | Tag structure differs | +| Literal-3 | ✅ Match | - | + +#### Literal-1 Diff +```diff +- This is literal content. ++ Literal +``` + +#### Literal-2 Diff +```diff +- This is <b>encoded</b> content. ++ <b>Literal</b> +``` + +### Login +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Login-1 | ❌ Missing in source B | File only exists in first directory | +| Login-2 | ❌ Missing in source B | File only exists in first directory | + +### LoginName +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| LoginName-1 | ❌ Missing in source B | File only exists in first directory | +| LoginName-2 | ❌ Missing in source B | File only exists in first directory | + +### LoginStatus +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| LoginStatus-1 | ❌ Missing in source B | File only exists in first directory | +| LoginStatus-2 | ❌ Missing in source B | File only exists in first directory | + +### LoginView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| LoginView-1 | ❌ Missing in source B | File only exists in first directory | + +### Menu +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Menu-1 | ❌ Missing in source B | File only exists in first directory | +| Menu-2 | ❌ Missing in source B | File only exists in first directory | +| Menu-3 | ❌ Missing in source B | File only exists in first directory | +| Menu-4 | ❌ Missing in source B | File only exists in first directory | +| Menu-5 | ❌ Missing in source B | File only exists in first directory | +| Menu-6 | ❌ Missing in source B | File only exists in first directory | +| Menu-7 | ❌ Missing in source B | File only exists in first directory | +| Menu-8 | ❌ Missing in source B | File only exists in first directory | +| Menu-9 | ❌ Missing in source B | File only exists in first directory | + +### MultiView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| MultiView-1 | ❌ Missing in source B | File only exists in first directory | + +### Panel +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Panel-1 | ⚠️ Divergent | Tag structure differs | +| Panel-2 | ⚠️ Divergent | Tag structure differs | +| Panel-3 | ⚠️ Divergent | Tag structure differs | + +#### Panel-1 Diff +```diff +-
++

This content is inside a basic Panel.

+-
++

A Panel renders as a div element by default.

+- +- User Info +- +- Name: +- +- +-
+``` + +#### Panel-2 Diff +```diff +-
++
User Information +-

First paragraph of content inside the scrollable panel.

++

Name: John Doe

+-

Second paragraph of content inside the scrollable panel.

++

Email: john@example.com

+-

Third paragraph of content inside the scrollable panel.

+-

Fourth paragraph of content inside the scrollable panel.

+-
+``` + +#### Panel-3 Diff +```diff +-
++

This panel has custom colors and border.

+- +- +-
+``` + +### PasswordRecovery +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| PasswordRecovery-1 | ❌ Missing in source B | File only exists in first directory | +| PasswordRecovery-2 | ❌ Missing in source B | File only exists in first directory | + +### PlaceHolder +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| PlaceHolder | ⚠️ Divergent | Tag structure differs | + +#### PlaceHolder Diff +```diff +-

This content was added programmatically.

PlaceHolder renders no HTML of its own.

++

This content is inside a PlaceHolder.

++

Note: No extra wrapper element is rendered around this content.

+``` + +### RadioButton +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| RadioButton-1 | ❌ Missing in source B | File only exists in first directory | +| RadioButton-2 | ❌ Missing in source B | File only exists in first directory | +| RadioButton-3 | ❌ Missing in source B | File only exists in first directory | + +### RadioButtonList +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| RadioButtonList-1 | ⚠️ Divergent | Tag structure differs | +| RadioButtonList-2 | ⚠️ Divergent | Tag structure differs | + +#### RadioButtonList-1 Diff +```diff +-
Id
Name
PriceIdLast Update
Name
1PriceFirst WidgetLast Update$7.99
2/26/2026
2Second Widget
$13.99
2/26/2026
31Third WidgetFirst Widget$100.99$7.992/26/2026
42/26/2026Fourth Widget
$10.99
2/26/2026
5 Fifth Widget
$5.99
2/26/2026
6
++
++ ++ ++
+-
+-
+-
+- +- +- +- +- +- +- +``` + +#### RadioButtonList-2 Diff +```diff +- ++
++ ++ ++ ++
+-
+- +-
+-
+- +- +``` + +### RangeValidator +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| RangeValidator-1 | ❌ Missing in source B | File only exists in first directory | +| RangeValidator-2 | ❌ Missing in source B | File only exists in first directory | +| RangeValidator-3 | ❌ Missing in source B | File only exists in first directory | +| RangeValidator-Submit | ❌ Missing in source B | File only exists in first directory | + +### RegularExpressionValidator +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| RegularExpressionValidator-1 | ❌ Missing in source B | File only exists in first directory | +| RegularExpressionValidator-2 | ❌ Missing in source B | File only exists in first directory | +| RegularExpressionValidator-3 | ❌ Missing in source B | File only exists in first directory | +| RegularExpressionValidator-Submit | ❌ Missing in source B | File only exists in first directory | + +### Repeater +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Repeater | ⚠️ Divergent | 62 line differences | + +#### Repeater Diff +```diff +- This is a list of widgets ++ +-
  • First Widget
  • ++ +-
    ++ +-
  • Second Widget
  • ++ +-
    ++ +-
  • Third Widget
  • ++ +-
    ++ +-
  • Fourth Widget
  • ++ +-
    ++ +-
  • Fifth Widget
  • ++ +-
    ++ +-
  • Sixth Widget
  • ++ +-
    ++ +-
  • Seventh Widget
  • ++ +-
    ++ +-
  • Eighth Widget
  • ++ +-
    ++ +-
  • Ninth Widget
  • ++ +-
    ++ +-
  • Tenth Widget
  • ++ +... (truncated) +``` + +### RequiredFieldValidator +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| RequiredFieldValidator-1 | ❌ Missing in source B | File only exists in first directory | +| RequiredFieldValidator-2 | ❌ Missing in source B | File only exists in first directory | +| RequiredFieldValidator-3 | ❌ Missing in source B | File only exists in first directory | +| RequiredFieldValidator-Submit | ❌ Missing in source B | File only exists in first directory | + +### SiteMapPath +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| SiteMapPath-1 | ⚠️ Divergent | Tag structure differs | +| SiteMapPath-2 | ⚠️ Divergent | Tag structure differs | + +#### SiteMapPath-1 Diff +```diff +- Skip Navigation LinksHome > SiteMapPath ++ Home > Products > Electronics > Phones +``` + +#### SiteMapPath-2 Diff +```diff +- Skip Navigation LinksHome > SiteMapPath ++ Home / Products / Electronics / Phones +``` + +### Table +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| Table-1 | ⚠️ Divergent | Tag structure differs | +| Table-2 | ⚠️ Divergent | Tag structure differs | +| Table-3 | ❌ Missing in source B | File only exists in first directory | + +#### Table-1 Diff +```diff +-
    1First Widget$7.992/26/2026

    2Second Widget$13.992/26/2026

    3Third Widget$100.992/26/2026

    4Fourth Widget$10.992/26/2026

    5Fifth Widget$5.992/26/2026

    6Sixth Widget$6.992/26/2026

    7Seventh Widget
    ++ Header 1 +- ++ Header 2 +- ++ Header 3 +- ++ Cell 1 +- ++ Cell 2 +- ++ Cell 3 +- ++ Cell 4 +- ++ Cell 5 +- ++ Cell 6 +- +-
    NameCategoryPrice
    Widget AHardware$9.99
    Widget BSoftware$19.99
    Widget CHardware$14.99
    +``` + +#### Table-2 Diff +```diff +- ++ Product +- ++ Price +- ++ Widget +- ++ $10.00 +- ++ Gadget +- ++ $25.00 +- +- +- +- +-
    IDProductIn Stock
    1AlphaYes
    2BetaNo
    3GammaYes
    +``` + +### TextBox +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| TextBox-1 | ❌ Missing in source B | File only exists in first directory | +| TextBox-2 | ❌ Missing in source B | File only exists in first directory | +| TextBox-3 | ❌ Missing in source B | File only exists in first directory | +| TextBox-4 | ❌ Missing in source B | File only exists in first directory | +| TextBox-5 | ❌ Missing in source B | File only exists in first directory | +| TextBox-6 | ❌ Missing in source B | File only exists in first directory | +| TextBox-7 | ❌ Missing in source B | File only exists in first directory | + +### TreeView +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| TreeView | ⚠️ Divergent | 27 line differences | + +#### TreeView Diff +```diff +- Skip Navigation Links.
    ++ +- +-
    +- +- +- +- +-
    Page1
    +- +- +- +-
    Page 2
    +-
    +-
    +``` + +### ValidationSummary +| Variant | Status | Diff Summary | +|---------|--------|-------------| +| ValidationSummary-1 | ❌ Missing in source B | File only exists in first directory | +| ValidationSummary-2 | ❌ Missing in source B | File only exists in first directory | +| ValidationSummary-3 | ❌ Missing in source B | File only exists in first directory | +| ValidationSummary-Submit | ❌ Missing in source B | File only exists in first directory | diff --git a/audit-output/normalized/blazor/Button/Button-1.html b/audit-output/normalized/blazor/Button/Button-1.html index 2dcc3f66c..004755347 100644 --- a/audit-output/normalized/blazor/Button/Button-1.html +++ b/audit-output/normalized/blazor/Button/Button-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/CheckBox/CheckBox-1.html b/audit-output/normalized/blazor/CheckBox/CheckBox-1.html index 1daa973d6..b88461bb5 100644 --- a/audit-output/normalized/blazor/CheckBox/CheckBox-1.html +++ b/audit-output/normalized/blazor/CheckBox/CheckBox-1.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/blazor/CheckBox/CheckBox-2.html b/audit-output/normalized/blazor/CheckBox/CheckBox-2.html index ef160c5da..e1e5a7727 100644 --- a/audit-output/normalized/blazor/CheckBox/CheckBox-2.html +++ b/audit-output/normalized/blazor/CheckBox/CheckBox-2.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/blazor/CheckBox/CheckBox-3.html b/audit-output/normalized/blazor/CheckBox/CheckBox-3.html index 184ec5d2f..9fd50c2d7 100644 --- a/audit-output/normalized/blazor/CheckBox/CheckBox-3.html +++ b/audit-output/normalized/blazor/CheckBox/CheckBox-3.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-1.html b/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-1.html index 2667a7f78..b9092fda8 100644 --- a/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-1.html +++ b/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-1.html @@ -1 +1 @@ -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-2.html b/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-2.html index ea9d548ac..44b294174 100644 --- a/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-2.html +++ b/audit-output/normalized/blazor/CheckBoxList/CheckBoxList-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/DropDownList/DropDownList-1.html b/audit-output/normalized/blazor/DropDownList/DropDownList-1.html index da06081b9..ca98463f2 100644 --- a/audit-output/normalized/blazor/DropDownList/DropDownList-1.html +++ b/audit-output/normalized/blazor/DropDownList/DropDownList-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/DropDownList/DropDownList-2.html b/audit-output/normalized/blazor/DropDownList/DropDownList-2.html index 0ac734516..e405e9a0e 100644 --- a/audit-output/normalized/blazor/DropDownList/DropDownList-2.html +++ b/audit-output/normalized/blazor/DropDownList/DropDownList-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/DropDownList/DropDownList-6.html b/audit-output/normalized/blazor/DropDownList/DropDownList-6.html index f7226c3c9..bc9fe96ec 100644 --- a/audit-output/normalized/blazor/DropDownList/DropDownList-6.html +++ b/audit-output/normalized/blazor/DropDownList/DropDownList-6.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/FileUpload/FileUpload.html b/audit-output/normalized/blazor/FileUpload/FileUpload.html index 9cfcddecf..44078354d 100644 --- a/audit-output/normalized/blazor/FileUpload/FileUpload.html +++ b/audit-output/normalized/blazor/FileUpload/FileUpload.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/GridView/GridView.html b/audit-output/normalized/blazor/GridView/GridView.html index 3f779d70b..77cc6a8a6 100644 --- a/audit-output/normalized/blazor/GridView/GridView.html +++ b/audit-output/normalized/blazor/GridView/GridView.html @@ -1 +1 @@ -
    IDCompanyNameFirstNameLastName&nbsp;&nbsp;
    1VirusJohnSmith
    2BoringJoseRodriguez
    3Fun MachinesJasonRamirez
    \ No newline at end of file +
    IDCompanyNameFirstNameLastName&nbsp;&nbsp;
    1VirusJohnSmith
    2BoringJoseRodriguez
    3Fun MachinesJasonRamirez
    \ No newline at end of file diff --git a/audit-output/normalized/blazor/HiddenField/HiddenField.html b/audit-output/normalized/blazor/HiddenField/HiddenField.html index 9fdb7a038..aab3c94e5 100644 --- a/audit-output/normalized/blazor/HiddenField/HiddenField.html +++ b/audit-output/normalized/blazor/HiddenField/HiddenField.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/ImageButton/ImageButton-1.html b/audit-output/normalized/blazor/ImageButton/ImageButton-1.html index 6fb4c1962..a44b6e807 100644 --- a/audit-output/normalized/blazor/ImageButton/ImageButton-1.html +++ b/audit-output/normalized/blazor/ImageButton/ImageButton-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/ImageButton/ImageButton-2.html b/audit-output/normalized/blazor/ImageButton/ImageButton-2.html index 97e2028da..6ca6ca6f3 100644 --- a/audit-output/normalized/blazor/ImageButton/ImageButton-2.html +++ b/audit-output/normalized/blazor/ImageButton/ImageButton-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/ListBox/ListBox-2.html b/audit-output/normalized/blazor/ListBox/ListBox-2.html index 03be277d9..a7354c8f9 100644 --- a/audit-output/normalized/blazor/ListBox/ListBox-2.html +++ b/audit-output/normalized/blazor/ListBox/ListBox-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-1.html b/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-1.html index 524851ef1..c9bd19e8b 100644 --- a/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-1.html +++ b/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-1.html @@ -1,4 +1,4 @@ - diff --git a/audit-output/normalized/webforms/ChangePassword/ChangePassword-2.html b/audit-output/normalized/webforms/ChangePassword/ChangePassword-2.html index aa0444824..35ea587a6 100644 --- a/audit-output/normalized/webforms/ChangePassword/ChangePassword-2.html +++ b/audit-output/normalized/webforms/ChangePassword/ChangePassword-2.html @@ -4,15 +4,15 @@ - + - + - + - +
    -
    -
    +
    +
    +
    \ No newline at end of file diff --git a/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-2.html b/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-2.html index d0b7e4d27..493e19f31 100644 --- a/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-2.html +++ b/audit-output/normalized/blazor/RadioButtonList/RadioButtonList-2.html @@ -1,5 +1,5 @@ - - + - + - + - +
    - - - +
    + + +
    \ No newline at end of file diff --git a/audit-output/normalized/blazor/TreeView/TreeView.html b/audit-output/normalized/blazor/TreeView/TreeView.html index fcbd9e644..a3b50c923 100644 --- a/audit-output/normalized/blazor/TreeView/TreeView.html +++ b/audit-output/normalized/blazor/TreeView/TreeView.html @@ -1,4 +1,4 @@ \ No newline at end of file diff --git a/audit-output/normalized/webforms/Button/Button-2.html b/audit-output/normalized/webforms/Button/Button-2.html index 4fb0845e5..f3dfaad77 100644 --- a/audit-output/normalized/webforms/Button/Button-2.html +++ b/audit-output/normalized/webforms/Button/Button-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Button/Button-3.html b/audit-output/normalized/webforms/Button/Button-3.html index ec4996d7c..46900449d 100644 --- a/audit-output/normalized/webforms/Button/Button-3.html +++ b/audit-output/normalized/webforms/Button/Button-3.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Button/Button-4.html b/audit-output/normalized/webforms/Button/Button-4.html index d430d12a2..3e940fdc3 100644 --- a/audit-output/normalized/webforms/Button/Button-4.html +++ b/audit-output/normalized/webforms/Button/Button-4.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Button/Button-5.html b/audit-output/normalized/webforms/Button/Button-5.html index 550dba8ce..6449b0dfb 100644 --- a/audit-output/normalized/webforms/Button/Button-5.html +++ b/audit-output/normalized/webforms/Button/Button-5.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/ChangePassword/ChangePassword-1.html b/audit-output/normalized/webforms/ChangePassword/ChangePassword-1.html index 7a563f05d..afec574e4 100644 --- a/audit-output/normalized/webforms/ChangePassword/ChangePassword-1.html +++ b/audit-output/normalized/webforms/ChangePassword/ChangePassword-1.html @@ -4,15 +4,15 @@
    Change Your Password
    Update Your Password
    diff --git a/audit-output/normalized/webforms/CheckBox/CheckBox-1.html b/audit-output/normalized/webforms/CheckBox/CheckBox-1.html index 94e42e31e..a89b2c89a 100644 --- a/audit-output/normalized/webforms/CheckBox/CheckBox-1.html +++ b/audit-output/normalized/webforms/CheckBox/CheckBox-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CheckBox/CheckBox-2.html b/audit-output/normalized/webforms/CheckBox/CheckBox-2.html index 07c409857..24f9ce9e8 100644 --- a/audit-output/normalized/webforms/CheckBox/CheckBox-2.html +++ b/audit-output/normalized/webforms/CheckBox/CheckBox-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CheckBox/CheckBox-3.html b/audit-output/normalized/webforms/CheckBox/CheckBox-3.html index ceb176976..0c0da5627 100644 --- a/audit-output/normalized/webforms/CheckBox/CheckBox-3.html +++ b/audit-output/normalized/webforms/CheckBox/CheckBox-3.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-1.html b/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-1.html index e9069e23e..b23f20ead 100644 --- a/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-1.html +++ b/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-1.html @@ -1,11 +1,11 @@ - + - + - + - +
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-2.html b/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-2.html index 0279fc77f..d00c4ddf1 100644 --- a/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-2.html +++ b/audit-output/normalized/webforms/CheckBoxList/CheckBoxList-2.html @@ -1,7 +1,7 @@ - + - +
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/CompareValidator/CompareValidator-1.html b/audit-output/normalized/webforms/CompareValidator/CompareValidator-1.html index c8864d02c..22d6da3b6 100644 --- a/audit-output/normalized/webforms/CompareValidator/CompareValidator-1.html +++ b/audit-output/normalized/webforms/CompareValidator/CompareValidator-1.html @@ -1,3 +1,3 @@ -Password:
    -Confirm: +Password:
    +Confirm: \ No newline at end of file diff --git a/audit-output/normalized/webforms/CompareValidator/CompareValidator-2.html b/audit-output/normalized/webforms/CompareValidator/CompareValidator-2.html index 4bc6f9f72..f08a2e780 100644 --- a/audit-output/normalized/webforms/CompareValidator/CompareValidator-2.html +++ b/audit-output/normalized/webforms/CompareValidator/CompareValidator-2.html @@ -1,3 +1,3 @@ Enter a number greater than 10: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CompareValidator/CompareValidator-3.html b/audit-output/normalized/webforms/CompareValidator/CompareValidator-3.html index 0616944ed..356156af1 100644 --- a/audit-output/normalized/webforms/CompareValidator/CompareValidator-3.html +++ b/audit-output/normalized/webforms/CompareValidator/CompareValidator-3.html @@ -1,3 +1,3 @@ Enter a date: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CompareValidator/CompareValidator-Submit.html b/audit-output/normalized/webforms/CompareValidator/CompareValidator-Submit.html index 67e9832c6..83c86efc9 100644 --- a/audit-output/normalized/webforms/CompareValidator/CompareValidator-Submit.html +++ b/audit-output/normalized/webforms/CompareValidator/CompareValidator-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-1.html b/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-1.html index fe03eac61..7fa7f0773 100644 --- a/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-1.html +++ b/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-1.html @@ -6,17 +6,17 @@ Sign Up for Your New Account - + - + - + - + - + - + @@ -26,7 +26,7 @@ - +
    diff --git a/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-2.html b/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-2.html index 7dbf4dec6..d5899f538 100644 --- a/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-2.html +++ b/audit-output/normalized/webforms/CreateUserWizard/CreateUserWizard-2.html @@ -6,17 +6,17 @@ Sign Up for Your New Account - + - + - + - + - + - + @@ -26,7 +26,7 @@ - +
    diff --git a/audit-output/normalized/webforms/CustomValidator/CustomValidator-1.html b/audit-output/normalized/webforms/CustomValidator/CustomValidator-1.html index c29d80249..461ebb11c 100644 --- a/audit-output/normalized/webforms/CustomValidator/CustomValidator-1.html +++ b/audit-output/normalized/webforms/CustomValidator/CustomValidator-1.html @@ -1,3 +1,3 @@ Enter an even number: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CustomValidator/CustomValidator-2.html b/audit-output/normalized/webforms/CustomValidator/CustomValidator-2.html index dd43186ca..46787efb1 100644 --- a/audit-output/normalized/webforms/CustomValidator/CustomValidator-2.html +++ b/audit-output/normalized/webforms/CustomValidator/CustomValidator-2.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/CustomValidator/CustomValidator-Submit.html b/audit-output/normalized/webforms/CustomValidator/CustomValidator-Submit.html index 67e9832c6..83c86efc9 100644 --- a/audit-output/normalized/webforms/CustomValidator/CustomValidator-Submit.html +++ b/audit-output/normalized/webforms/CustomValidator/CustomValidator-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/DropDownList/DropDownList-2.html b/audit-output/normalized/webforms/DropDownList/DropDownList-2.html index e975d5f2d..feb61c19a 100644 --- a/audit-output/normalized/webforms/DropDownList/DropDownList-2.html +++ b/audit-output/normalized/webforms/DropDownList/DropDownList-2.html @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/audit-output/normalized/webforms/DropDownList/DropDownList-4.html b/audit-output/normalized/webforms/DropDownList/DropDownList-4.html index fe22d3b35..4f6549133 100644 --- a/audit-output/normalized/webforms/DropDownList/DropDownList-4.html +++ b/audit-output/normalized/webforms/DropDownList/DropDownList-4.html @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/FileUpload/FileUpload.html b/audit-output/normalized/webforms/FileUpload/FileUpload.html index a111da251..6b7bb30a1 100644 --- a/audit-output/normalized/webforms/FileUpload/FileUpload.html +++ b/audit-output/normalized/webforms/FileUpload/FileUpload.html @@ -1,2 +1,2 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/audit-output/normalized/webforms/HiddenField/HiddenField.html b/audit-output/normalized/webforms/HiddenField/HiddenField.html index 96b2617a2..4f8043e73 100644 --- a/audit-output/normalized/webforms/HiddenField/HiddenField.html +++ b/audit-output/normalized/webforms/HiddenField/HiddenField.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/ImageButton/ImageButton-1.html b/audit-output/normalized/webforms/ImageButton/ImageButton-1.html index 57c518cc5..e89d1b6dd 100644 --- a/audit-output/normalized/webforms/ImageButton/ImageButton-1.html +++ b/audit-output/normalized/webforms/ImageButton/ImageButton-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/ImageButton/ImageButton-2.html b/audit-output/normalized/webforms/ImageButton/ImageButton-2.html index 0d528fb36..40df73c83 100644 --- a/audit-output/normalized/webforms/ImageButton/ImageButton-2.html +++ b/audit-output/normalized/webforms/ImageButton/ImageButton-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/ListBox/ListBox-2.html b/audit-output/normalized/webforms/ListBox/ListBox-2.html index cf44165b5..535a10b65 100644 --- a/audit-output/normalized/webforms/ListBox/ListBox-2.html +++ b/audit-output/normalized/webforms/ListBox/ListBox-2.html @@ -1,6 +1,6 @@ - - - + + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Login/Login-1.html b/audit-output/normalized/webforms/Login/Login-1.html index 5590f6720..1f10dd899 100644 --- a/audit-output/normalized/webforms/Login/Login-1.html +++ b/audit-output/normalized/webforms/Login/Login-1.html @@ -4,13 +4,13 @@ Log In - + - + - + - + diff --git a/audit-output/normalized/webforms/Login/Login-2.html b/audit-output/normalized/webforms/Login/Login-2.html index 047821bae..0e4d0b52c 100644 --- a/audit-output/normalized/webforms/Login/Login-2.html +++ b/audit-output/normalized/webforms/Login/Login-2.html @@ -4,11 +4,11 @@ Member Login - + - + - + diff --git a/audit-output/normalized/webforms/Menu/Menu-9.html b/audit-output/normalized/webforms/Menu/Menu-9.html index 5457c39a5..67190b2f8 100644 --- a/audit-output/normalized/webforms/Menu/Menu-9.html +++ b/audit-output/normalized/webforms/Menu/Menu-9.html @@ -1,9 +1,9 @@ Skip Navigation Links
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/MultiView/MultiView-1.html b/audit-output/normalized/webforms/MultiView/MultiView-1.html index 73814468f..a06db95c3 100644 --- a/audit-output/normalized/webforms/MultiView/MultiView-1.html +++ b/audit-output/normalized/webforms/MultiView/MultiView-1.html @@ -1,4 +1,4 @@

    Step 1: Personal Information

    -

    Name:

    -

    Email:

    - \ No newline at end of file +

    Name:

    +

    Email:

    + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Panel/Panel-1.html b/audit-output/normalized/webforms/Panel/Panel-1.html index dd706b4cb..5c751c10a 100644 --- a/audit-output/normalized/webforms/Panel/Panel-1.html +++ b/audit-output/normalized/webforms/Panel/Panel-1.html @@ -4,6 +4,6 @@ User Info Name: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/Panel/Panel-3.html b/audit-output/normalized/webforms/Panel/Panel-3.html index fbdee2a18..3a99f0319 100644 --- a/audit-output/normalized/webforms/Panel/Panel-3.html +++ b/audit-output/normalized/webforms/Panel/Panel-3.html @@ -1,4 +1,4 @@
    - - + +
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-1.html b/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-1.html index d26dc42d4..db0b909c1 100644 --- a/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-1.html +++ b/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-1.html @@ -6,9 +6,9 @@ Enter your User Name to receive your password. - + - + diff --git a/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-2.html b/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-2.html index a1aa561ae..80b05d1f7 100644 --- a/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-2.html +++ b/audit-output/normalized/webforms/PasswordRecovery/PasswordRecovery-2.html @@ -6,9 +6,9 @@ Enter your User Name to receive your password. - + - + diff --git a/audit-output/normalized/webforms/RadioButton/RadioButton-1.html b/audit-output/normalized/webforms/RadioButton/RadioButton-1.html index 6c3bf4a4c..d67b890ab 100644 --- a/audit-output/normalized/webforms/RadioButton/RadioButton-1.html +++ b/audit-output/normalized/webforms/RadioButton/RadioButton-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RadioButton/RadioButton-2.html b/audit-output/normalized/webforms/RadioButton/RadioButton-2.html index b20eab4bd..0dcf5a66e 100644 --- a/audit-output/normalized/webforms/RadioButton/RadioButton-2.html +++ b/audit-output/normalized/webforms/RadioButton/RadioButton-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RadioButton/RadioButton-3.html b/audit-output/normalized/webforms/RadioButton/RadioButton-3.html index 9bbc29202..9c72a22ad 100644 --- a/audit-output/normalized/webforms/RadioButton/RadioButton-3.html +++ b/audit-output/normalized/webforms/RadioButton/RadioButton-3.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-1.html b/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-1.html index f9c67b363..bcf88260f 100644 --- a/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-1.html +++ b/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-1.html @@ -1,11 +1,11 @@ - + - + - + - +
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-2.html b/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-2.html index ed66b291a..f282cd463 100644 --- a/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-2.html +++ b/audit-output/normalized/webforms/RadioButtonList/RadioButtonList-2.html @@ -1,7 +1,7 @@ - + - +
    \ No newline at end of file diff --git a/audit-output/normalized/webforms/RangeValidator/RangeValidator-1.html b/audit-output/normalized/webforms/RangeValidator/RangeValidator-1.html index 13f327381..809844a79 100644 --- a/audit-output/normalized/webforms/RangeValidator/RangeValidator-1.html +++ b/audit-output/normalized/webforms/RangeValidator/RangeValidator-1.html @@ -1,3 +1,3 @@ Enter a number between 1 and 100: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RangeValidator/RangeValidator-2.html b/audit-output/normalized/webforms/RangeValidator/RangeValidator-2.html index 8f821d945..aaca0a85b 100644 --- a/audit-output/normalized/webforms/RangeValidator/RangeValidator-2.html +++ b/audit-output/normalized/webforms/RangeValidator/RangeValidator-2.html @@ -1,3 +1,3 @@ Enter a date in 2024: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RangeValidator/RangeValidator-3.html b/audit-output/normalized/webforms/RangeValidator/RangeValidator-3.html index adc9d54c0..292f67415 100644 --- a/audit-output/normalized/webforms/RangeValidator/RangeValidator-3.html +++ b/audit-output/normalized/webforms/RangeValidator/RangeValidator-3.html @@ -1,3 +1,3 @@ Enter a price ($1.00 - $999.99): - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RangeValidator/RangeValidator-Submit.html b/audit-output/normalized/webforms/RangeValidator/RangeValidator-Submit.html index 67e9832c6..83c86efc9 100644 --- a/audit-output/normalized/webforms/RangeValidator/RangeValidator-Submit.html +++ b/audit-output/normalized/webforms/RangeValidator/RangeValidator-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-1.html b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-1.html index 3f816409e..91da39323 100644 --- a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-1.html +++ b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-1.html @@ -1,3 +1,3 @@ Email: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-2.html b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-2.html index ee07a3912..0580fb4c5 100644 --- a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-2.html +++ b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-2.html @@ -1,3 +1,3 @@ Phone (xxx-xxx-xxxx): - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-3.html b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-3.html index 3a43ac55a..5116606d6 100644 --- a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-3.html +++ b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-3.html @@ -1,3 +1,3 @@ Zip Code: - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-Submit.html b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-Submit.html index 67e9832c6..83c86efc9 100644 --- a/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-Submit.html +++ b/audit-output/normalized/webforms/RegularExpressionValidator/RegularExpressionValidator-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-1.html b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-1.html index a8fba7f5f..6d63177f7 100644 --- a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-1.html +++ b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-1.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-2.html b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-2.html index 2a820a67e..fb78c984c 100644 --- a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-2.html +++ b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-2.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-3.html b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-3.html index 4fb4e11f2..e8ee9251e 100644 --- a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-3.html +++ b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-3.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-Submit.html b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-Submit.html index 67e9832c6..83c86efc9 100644 --- a/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-Submit.html +++ b/audit-output/normalized/webforms/RequiredFieldValidator/RequiredFieldValidator-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-1.html b/audit-output/normalized/webforms/TextBox/TextBox-1.html index daa9a09ba..63ac75c15 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-1.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-1.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-2.html b/audit-output/normalized/webforms/TextBox/TextBox-2.html index 42853b238..3f9826b24 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-2.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-2.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-3.html b/audit-output/normalized/webforms/TextBox/TextBox-3.html index a042da3cc..14181ec77 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-3.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-3.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-4.html b/audit-output/normalized/webforms/TextBox/TextBox-4.html index 6535ae8a2..0f6a07d52 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-4.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-4.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-5.html b/audit-output/normalized/webforms/TextBox/TextBox-5.html index f4f8a01cd..00d07d8c3 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-5.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-5.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TextBox/TextBox-6.html b/audit-output/normalized/webforms/TextBox/TextBox-6.html index 07c752fde..4c8b08ea1 100644 --- a/audit-output/normalized/webforms/TextBox/TextBox-6.html +++ b/audit-output/normalized/webforms/TextBox/TextBox-6.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/audit-output/normalized/webforms/TreeView/TreeView.html b/audit-output/normalized/webforms/TreeView/TreeView.html index cc72630e4..9dfd0b813 100644 --- a/audit-output/normalized/webforms/TreeView/TreeView.html +++ b/audit-output/normalized/webforms/TreeView/TreeView.html @@ -1,22 +1,22 @@ Skip Navigation Links.
    - +
    This is the home image tooltipHomeThis is the home image tooltipHome
    diff --git a/audit-output/normalized/webforms/ValidationSummary/ValidationSummary-Submit.html b/audit-output/normalized/webforms/ValidationSummary/ValidationSummary-Submit.html index bb4f27608..529abfc67 100644 --- a/audit-output/normalized/webforms/ValidationSummary/ValidationSummary-Submit.html +++ b/audit-output/normalized/webforms/ValidationSummary/ValidationSummary-Submit.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/DataControls/DataGrid.md b/docs/DataControls/DataGrid.md index a6908c826..04a01ae06 100644 --- a/docs/DataControls/DataGrid.md +++ b/docs/DataControls/DataGrid.md @@ -165,8 +165,6 @@ The following DataGrid features from Web Forms are not currently supported: ## Blazor Syntax -Currently, not every syntax element of Web Forms DataGrid is supported. In the meantime, the following DataGrid in Blazor syntax will only include the implemented ones. **Custom paging and footer templates will be included later**. - ```html ` instead of ``, improv DataKeyField="CustomerID" SelectMethod="GetCustomers" PageIndexChanged="HandlePageChanged"> + @code { @@ -391,7 +390,19 @@ When `true`, header cells render as `` instead of ``, improv } ``` -When `AllowPaging="true"` and `PageSize` is set, the DataGrid automatically renders a numeric pager row. The pager displays page numbers and highlights the current page. Clicking a page number fires `PageIndexChanged` and navigates to that page. +When `AllowPaging="true"` and `PageSize` is set, the DataGrid automatically renders a numeric pager row in the table footer. The pager displays page numbers — the current page as plain text, others as clickable links. Clicking a page number fires `PageIndexChanged` and navigates to that page. + +!!! note "DataGrid Paging vs. GridView/FormView/DetailsView Paging" + DataGrid uses a **built-in numeric pager** and does not support the `` sub-component that GridView, FormView, and DetailsView use. If you need configurable pager modes (NextPrevious, NumericFirstLast, etc.), consider migrating to [GridView](GridView.md) which offers full [PagerSettings](PagerSettings.md) support. + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `AllowPaging` | `bool` | `false` | Enables or disables paging | +| `PageSize` | `int` | `10` | Number of items displayed per page | +| `CurrentPageIndex` | `int` | `0` | The zero-based index of the current page | +| `PageIndexChanged` | `EventCallback` | — | Fires when the page changes | + +The `PagerStyle` sub-component controls the visual appearance of the pager row. ### DataGrid with Sorting @@ -443,3 +454,4 @@ When migrating DataGrid from Web Forms to Blazor: - [GridView](GridView.md) - The recommended data grid control for new projects - [DataList](DataList.md) - For custom layout of repeating data - [Repeater](Repeater.md) - For lightweight data repetition +- [PagerSettings](PagerSettings.md) - Shared pager configuration (used by GridView, FormView, DetailsView) diff --git a/docs/DataControls/DetailsView.md b/docs/DataControls/DetailsView.md index e9d9f1ccb..2c071d25e 100644 --- a/docs/DataControls/DetailsView.md +++ b/docs/DataControls/DetailsView.md @@ -53,6 +53,8 @@ Original Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/api/sy AutoGenerateEditButton="True|False" AutoGenerateInsertButton="True|False" AutoGenerateRows="True|False" + Caption="string" + CaptionAlign="NotSet|Top|Bottom|Left|Right" CellPadding="integer" CellSpacing="integer" CssClass="string" @@ -79,6 +81,26 @@ Original Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/api/sy Visible="True|False" runat="server" > + + + + + + + + + + + diff --git a/docs/DataControls/FormView.md b/docs/DataControls/FormView.md index 4d108298a..3817a1982 100644 --- a/docs/DataControls/FormView.md +++ b/docs/DataControls/FormView.md @@ -6,7 +6,10 @@ The FormView component is meant to emulate the asp:FormView control in markup an - Numerical Pager - OnDataBinding and OnDataBound events trigger - ModeChanging and ModeChanged events - - Insert, Edit, Update, Delete actions and supporting events + - Insert, Edit, Update, Delete actions and supporting events: + - **OnItemDeleting** / **OnItemDeleted** — before and after delete operations + - **OnItemInserting** / **OnItemInserted** — before and after insert operations + - **OnItemUpdating** / **OnItemUpdated** — before and after update operations - **ItemCommand** event — fires when any command button within the FormView is clicked - **ItemCreated** event — fires when the FormView is first created and data-bound - **PageIndexChanging** / **PageIndexChanged** events — fires when paging occurs (cancellable) @@ -18,6 +21,13 @@ The FormView component is meant to emulate the asp:FormView control in markup an - **Style sub-components** (RowStyle, EditRowStyle, InsertRowStyle, HeaderStyle, FooterStyle, EmptyDataRowStyle, PagerStyle) - **[PagerSettings](PagerSettings.md)** — configurable pager button modes, text, images, and position +## Web Forms Features NOT Supported + +- **DataSourceID** — Blazor does not use server-side data source controls; bind data directly via `DataSource` +- **ViewState / EnableViewState** — Not needed; Blazor preserves component state natively +- **Theming / SkinID / EnableTheming** — Not applicable to Blazor +- **RenderTable** — Not implemented; the FormView always renders a table + ## Usage Notes - **ItemType attribute** - Required to specify the type of items in the collection @@ -390,6 +400,47 @@ Each style component accepts standard style properties: `BackColor`, `ForeColor` ``` +### CRUD Event Handling + +```razor + + +

    @Item.Name — @Item.Email

    +
    + +

    Editing: @Item.Name

    +
    +
    + +@code { + private List Customers = new(); + + private void HandleUpdating(FormViewUpdateEventArgs e) + { + // Validate and apply changes; set e.Cancel = true to abort + } + + private void HandleUpdated(FormViewUpdatedEventArgs e) + { + // Post-update logic (e.g., refresh data, show notification) + } + + private void HandleDeleting(FormViewDeleteEventArgs e) + { + // Perform delete; e.RowIndex gives the current position + } + + private void HandleCommand(FormViewCommandEventArgs e) + { + // Fires for any command button — check e.CommandName + } +} +``` + ## See Also - [GridView](GridView.md) - For tabular data display diff --git a/planning-docs/DIVERGENCE-REGISTRY.md b/planning-docs/DIVERGENCE-REGISTRY.md index 45141e36b..f73cb13d5 100644 --- a/planning-docs/DIVERGENCE-REGISTRY.md +++ b/planning-docs/DIVERGENCE-REGISTRY.md @@ -2,7 +2,7 @@ **Created:** 2026-02-26 **Author:** Forge (Lead / Web Forms Reviewer) -**Status:** Initial — will be updated incrementally through M11–M13 +**Status:** Updated through M18 — 14 entries (D-01 through D-14) **Milestone:** M11-02 --- @@ -31,6 +31,10 @@ This document catalogs every **known intentional difference** between HTML rende | D-08 | Calendar Day Selection | JS Interop | Calendar | None | High | | D-09 | Login Control Infrastructure | Infrastructure | Login, LoginName, LoginStatus, LoginView, ChangePassword, CreateUserWizard, PasswordRecovery | None | Low | | D-10 | Validator Client-Side Scripts | JS Interop | RequiredFieldValidator, CompareValidator, RangeValidator, RegularExpressionValidator, CustomValidator, ValidationSummary | None | High | +| D-11 | GUID-Based IDs | ID Generation | CheckBox, RadioButton, RadioButtonList, FileUpload | Medium | Medium | +| D-12 | Boolean Attribute Format | Attribute Format | DropDownList, ListBox, CheckBoxList, RadioButtonList | None | None | +| D-13 | Calendar Previous-Month Day Padding | Structural | Calendar | Low | None | +| D-14 | Calendar Style Property Pass-Through | Style | Calendar | Medium | None | --- @@ -186,6 +190,74 @@ This document catalogs every **known intentional difference** between HTML rende --- +### D-11: GUID-Based IDs + +| Field | Value | +|-------|-------| +| **Control** | CheckBox, RadioButton, RadioButtonList, FileUpload | +| **Divergence** | Web Forms generates predictable IDs from the control naming hierarchy (e.g., `MainContent_CheckBox1`, `MainContent_RadioButtonList1_0`, `MainContent_RadioButtonList1_1`). Blazor generates GUID-based IDs for some controls (e.g., `5f017a2765e3...`), making the HTML non-deterministic across renders. | +| **Category** | ID Generation | +| **Reason** | This is a **separate concern from D-01** (which covers `ctl00_` prefix mangling). D-01 addresses the naming-container prefix — a structural difference that is always intentional. D-11 addresses the fact that certain Blazor controls use `Guid.NewGuid()` to generate internal IDs for linking `` and `