Skip to content

Releasing 0.15.1#394

Merged
csharpfritz merged 8 commits intomainfrom
dev
Feb 26, 2026
Merged

Releasing 0.15.1#394
csharpfritz merged 8 commits intomainfrom
dev

Conversation

@csharpfritz
Copy link
Copy Markdown
Collaborator

No description provided.

csharpfritz and others added 8 commits February 24, 2026 23:21
* Initial plan

* Add Calendar component implementation with basic structure

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add unit tests for Calendar component - all 19 tests passing

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

* Fix code review issues: safe substring and synchronous event handling

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* fix: refactor Calendar to use CalendarSelectionMode enum (#333)

- Create CalendarSelectionMode enum (None, Day, DayWeek, DayWeekMonth)
- Refactor Calendar.SelectionMode from string to CalendarSelectionMode enum
- Remove .GetAwaiter().GetResult() blocking call in CreateDayRenderArgs
- Add Caption, CaptionAlign, UseAccessibleHeader properties
- Update tests and samples to use enum values

* samples: add demo pages for Calendar, FileUpload, ImageMap

- Calendar: date selection, selection modes, styling, day/title formats, events

- FileUpload: basic upload, file type filtering, multiple files, disabled, styled

- ImageMap: navigate/postback/mixed hot spot modes, rectangle/circle/polygon shapes

- Updated NavMenu and ComponentList with links to all three new components

* docs: add documentation for Calendar, FileUpload, ImageMap, PageService

* fix: restore .ai-team agent history and decisions lost in PR #338 merge

The FileUpload PR (#338) inadvertently reverted Sprint 1 gate review
entries from agent histories (beast, cyclops, forge, jubilee, rogue)
and downgraded the FileUpload InputFile decision in decisions.md.

Restored from commit f85aa42 (docs(ai-team): Sprint 1 gate review results).

* feat: add Copilot custom agent definitions in .github/agents/

Creates .agent.md files for all 6 team agents (Beast, Cyclops, Forge,
Jubilee, Rogue, Scribe) so they appear in GitHub Copilot's agent picker.
Content sourced from existing .ai-team/agents/*/charter.md files.

* fix: replace individual agent files with Squad coordinator agent

Squad is the single Copilot agent that delegates to the specialized
agents defined in .ai-team/agents/. Individual agent files were
incorrectly created  the correct pattern is one coordinator agent
(squad.agent.md) that routes work to Forge, Cyclops, Beast, Jubilee,
Rogue, and Scribe based on task type.

* docs(ai-team): log Sprint 2 completion

Session: 2026-02-10-sprint2-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 2 session (4 components shipped with docs, samples, tests)
- Merged Sprint 2 design review decision from inbox
- Removed duplicate FileUpload InputFile decision from inbox (already consolidated)
- Appended Sprint 2 completion decision to decisions.md
- Propagated cross-agent updates to all 5 agent histories

* Updated the squad

* docs(ai-team): Sprint 3 planning session

Session: 2026-02-11-sprint3-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-11-sprint3-planning.md
- Merged 3 decisions from inbox into decisions.md
- Updated status.md to reflect 48/53 components complete
- Sprint 3 scope: DetailsView + PasswordRecovery
- Propagated cross-agent updates to all agent history files

* docs(ai-team): Sprint 3 execution complete

Session: 2026-02-12-sprint3-execution
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 3 execution session
- Merged 7 decisions from inbox into decisions.md
- Sprint 3 gate review: DetailsView + PasswordRecovery APPROVED
- Propagated cross-agent updates to Beast, Colossus, Cyclops, Rogue, Jubilee
- status.md updated to 50/53 (94%)

* docs(ai-team): Milestone 4 planning - Chart component

Session: 2026-02-12-milestone4-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-12-milestone4-planning.md
- Merged decisions from inbox (Chart.js evaluation, milestone plan, milestones directive)
- Propagated milestone 4 updates to 5 agent history files

* docs(ai-team): Summarize Forge history (13.2KB -> 4.3KB)

Session: 2026-02-12-milestone4-planning
Requested by: Scribe (automatic)

Changes:
- Summarized Forge history.md (exceeded ~12KB threshold)
- Preserved all team updates and key patterns

* feat: Milestone 6 — Feature Gap Closure (54 work items, ~345 gaps closed)

Closes the highest-impact feature gaps from the 53-control audit.

P0 — Base class fixes (~180 gaps): AccessKey, ToolTip on all controls;
DataBoundComponent inherits BaseStyledComponent; ValidatorDisplay + SetFocusOnError;
Image/Label base class upgrades.

P1 — Control improvements (~120 gaps): GridView paging/sorting/row editing;
Calendar style sub-components + enums; FormView header/footer/empty data;
HyperLink NavigateUrl rename; ValidationSummary HeaderText/ShowSummary/ValidationGroup.

P2 — Nice-to-have (~45 gaps): DataTextFormatString + AppendDataBoundItems on
BaseListControl; CausesValidation on CheckBox/RadioButton/TextBox; Menu Orientation;
Label AssociatedControlID; Login controls base class upgrade.

168 files changed, +5,712 / -1,775 lines
1,065 tests passing, 0 failures

* fix: Menu JS interop crash, Calendar attribute rendering, Menu auto-ID generation

- Add null safety and try/catch in Menu.js to prevent circuit crash
- Fix Calendar.razor attribute rendering issue
- Auto-generate Menu ID when not explicitly provided

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decision inbox for M8 bug fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: formally defer Substitution/Xml, polish documentation

- Mark Substitution and Xml as Deferred in status.md
- Create DeferredControls.md with migration guidance
- Fix mkdocs.yml nav issues
- Update README component stats
- Remove Chart hedging language

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add shared PagerSettings sub-component for GridView/FormView/DetailsView

- Add PagerButtons and PagerPosition enums
- Add PagerSettings class with Web Forms-compatible properties
- Add IPagerSettingsContainer interface
- Add UiPagerSettings base component
- Wire PagerSettings into GridView, FormView, and DetailsView
- Follow existing style sub-component CascadingParameter pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M8 session log and decision merge

Session: 2026-02-24-m8-release-readiness
Requested by: Jeffrey T. Fritz

Changes:
- Logged M8 session to .ai-team/log/2026-02-24-m8-release-readiness.md
- Merged 18 decisions from inbox (Menu auto-ID, Substitution/Xml deferral, M8 scope, PagerSettings, M7 plan, integration tests, TreeView, GridView, DataGrid, ListView, FormView, DetailsView, validators, Menu improvements, Playwright patterns, rendermode fix)
- Propagated team updates to all 6 agent histories
- Deduplicated decisions.md (0 exact heading duplicates found)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump version to 0.14 for Milestone 8 release

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log v0.14 release completion

Session: 2026-02-25-v014-release
Requested by: Jeffrey T. Fritz

Changes:
- Logged v0.14 release final session (docs fix, CI green, release created)
- Decision inbox checked (empty, no merges needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: update stale version comment in Program.cs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan

* Add Calendar component implementation with basic structure

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add unit tests for Calendar component - all 19 tests passing

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

* Fix code review issues: safe substring and synchronous event handling

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* fix: refactor Calendar to use CalendarSelectionMode enum (#333)

- Create CalendarSelectionMode enum (None, Day, DayWeek, DayWeekMonth)
- Refactor Calendar.SelectionMode from string to CalendarSelectionMode enum
- Remove .GetAwaiter().GetResult() blocking call in CreateDayRenderArgs
- Add Caption, CaptionAlign, UseAccessibleHeader properties
- Update tests and samples to use enum values

* samples: add demo pages for Calendar, FileUpload, ImageMap

- Calendar: date selection, selection modes, styling, day/title formats, events

- FileUpload: basic upload, file type filtering, multiple files, disabled, styled

- ImageMap: navigate/postback/mixed hot spot modes, rectangle/circle/polygon shapes

- Updated NavMenu and ComponentList with links to all three new components

* docs: add documentation for Calendar, FileUpload, ImageMap, PageService

* fix: restore .ai-team agent history and decisions lost in PR #338 merge

The FileUpload PR (#338) inadvertently reverted Sprint 1 gate review
entries from agent histories (beast, cyclops, forge, jubilee, rogue)
and downgraded the FileUpload InputFile decision in decisions.md.

Restored from commit f85aa42 (docs(ai-team): Sprint 1 gate review results).

* feat: add Copilot custom agent definitions in .github/agents/

Creates .agent.md files for all 6 team agents (Beast, Cyclops, Forge,
Jubilee, Rogue, Scribe) so they appear in GitHub Copilot's agent picker.
Content sourced from existing .ai-team/agents/*/charter.md files.

* fix: replace individual agent files with Squad coordinator agent

Squad is the single Copilot agent that delegates to the specialized
agents defined in .ai-team/agents/. Individual agent files were
incorrectly created  the correct pattern is one coordinator agent
(squad.agent.md) that routes work to Forge, Cyclops, Beast, Jubilee,
Rogue, and Scribe based on task type.

* docs(ai-team): log Sprint 2 completion

Session: 2026-02-10-sprint2-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 2 session (4 components shipped with docs, samples, tests)
- Merged Sprint 2 design review decision from inbox
- Removed duplicate FileUpload InputFile decision from inbox (already consolidated)
- Appended Sprint 2 completion decision to decisions.md
- Propagated cross-agent updates to all 5 agent histories

* Updated the squad

* docs(ai-team): Sprint 3 planning session

Session: 2026-02-11-sprint3-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-11-sprint3-planning.md
- Merged 3 decisions from inbox into decisions.md
- Updated status.md to reflect 48/53 components complete
- Sprint 3 scope: DetailsView + PasswordRecovery
- Propagated cross-agent updates to all agent history files

* docs(ai-team): Sprint 3 execution complete

Session: 2026-02-12-sprint3-execution
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 3 execution session
- Merged 7 decisions from inbox into decisions.md
- Sprint 3 gate review: DetailsView + PasswordRecovery APPROVED
- Propagated cross-agent updates to Beast, Colossus, Cyclops, Rogue, Jubilee
- status.md updated to 50/53 (94%)

* docs(ai-team): Milestone 4 planning - Chart component

Session: 2026-02-12-milestone4-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-12-milestone4-planning.md
- Merged decisions from inbox (Chart.js evaluation, milestone plan, milestones directive)
- Propagated milestone 4 updates to 5 agent history files

* docs(ai-team): Summarize Forge history (13.2KB -> 4.3KB)

Session: 2026-02-12-milestone4-planning
Requested by: Scribe (automatic)

Changes:
- Summarized Forge history.md (exceeded ~12KB threshold)
- Preserved all team updates and key patterns

* feat: Milestone 6 — Feature Gap Closure (54 work items, ~345 gaps closed)

Closes the highest-impact feature gaps from the 53-control audit.

P0 — Base class fixes (~180 gaps): AccessKey, ToolTip on all controls;
DataBoundComponent inherits BaseStyledComponent; ValidatorDisplay + SetFocusOnError;
Image/Label base class upgrades.

P1 — Control improvements (~120 gaps): GridView paging/sorting/row editing;
Calendar style sub-components + enums; FormView header/footer/empty data;
HyperLink NavigateUrl rename; ValidationSummary HeaderText/ShowSummary/ValidationGroup.

P2 — Nice-to-have (~45 gaps): DataTextFormatString + AppendDataBoundItems on
BaseListControl; CausesValidation on CheckBox/RadioButton/TextBox; Menu Orientation;
Label AssociatedControlID; Login controls base class upgrade.

168 files changed, +5,712 / -1,775 lines
1,065 tests passing, 0 failures

* fix: Menu JS interop crash, Calendar attribute rendering, Menu auto-ID generation

- Add null safety and try/catch in Menu.js to prevent circuit crash
- Fix Calendar.razor attribute rendering issue
- Auto-generate Menu ID when not explicitly provided

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decision inbox for M8 bug fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: formally defer Substitution/Xml, polish documentation

- Mark Substitution and Xml as Deferred in status.md
- Create DeferredControls.md with migration guidance
- Fix mkdocs.yml nav issues
- Update README component stats
- Remove Chart hedging language

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add shared PagerSettings sub-component for GridView/FormView/DetailsView

- Add PagerButtons and PagerPosition enums
- Add PagerSettings class with Web Forms-compatible properties
- Add IPagerSettingsContainer interface
- Add UiPagerSettings base component
- Wire PagerSettings into GridView, FormView, and DetailsView
- Follow existing style sub-component CascadingParameter pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M8 session log and decision merge

Session: 2026-02-24-m8-release-readiness
Requested by: Jeffrey T. Fritz

Changes:
- Logged M8 session to .ai-team/log/2026-02-24-m8-release-readiness.md
- Merged 18 decisions from inbox (Menu auto-ID, Substitution/Xml deferral, M8 scope, PagerSettings, M7 plan, integration tests, TreeView, GridView, DataGrid, ListView, FormView, DetailsView, validators, Menu improvements, Playwright patterns, rendermode fix)
- Propagated team updates to all 6 agent histories
- Deduplicated decisions.md (0 exact heading duplicates found)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump version to 0.14 for Milestone 8 release

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log v0.14 release completion

Session: 2026-02-25-v014-release
Requested by: Jeffrey T. Fritz

Changes:
- Logged v0.14 release final session (docs fix, CI green, release created)
- Decision inbox checked (empty, no merges needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: resolve v0.14 deployment pipeline issues

- deploy-server-side.yml: compute version via nbgv before Docker build,
  pass as build-arg, tag image with version, add Azure App Service
  webhook trigger step (gated on AZURE_WEBAPP_WEBHOOK_URL secret)
- nuget.yml: add nuget.org push step gated on NUGET_API_KEY secret,
  preserving existing GitHub Packages push
- Dockerfile: accept VERSION build-arg, use it in dotnet build/publish
  so assembly version reflects git-derived version even though .git
  is excluded by .dockerignore

Required secrets (to be configured by repo admin):
  AZURE_WEBAPP_WEBHOOK_URL - Azure App Service Deployment Center webhook
  NUGET_API_KEY - nuget.org API key

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Forge history and decision inbox for deployment pipeline fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log deployment pipeline fix session

Session: 2026-02-25-deployment-pipeline-fix
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-deployment-pipeline-fix.md
- Merged decision(s) from inbox into decisions.md
- Consolidated duplicate Substitution/Xml deferral decisions
- Propagated deployment pipeline decision to Forge, Cyclops, Colossus histories

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan

* Add Calendar component implementation with basic structure

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add unit tests for Calendar component - all 19 tests passing

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

* Fix code review issues: safe substring and synchronous event handling

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* fix: refactor Calendar to use CalendarSelectionMode enum (#333)

- Create CalendarSelectionMode enum (None, Day, DayWeek, DayWeekMonth)
- Refactor Calendar.SelectionMode from string to CalendarSelectionMode enum
- Remove .GetAwaiter().GetResult() blocking call in CreateDayRenderArgs
- Add Caption, CaptionAlign, UseAccessibleHeader properties
- Update tests and samples to use enum values

* samples: add demo pages for Calendar, FileUpload, ImageMap

- Calendar: date selection, selection modes, styling, day/title formats, events

- FileUpload: basic upload, file type filtering, multiple files, disabled, styled

- ImageMap: navigate/postback/mixed hot spot modes, rectangle/circle/polygon shapes

- Updated NavMenu and ComponentList with links to all three new components

* docs: add documentation for Calendar, FileUpload, ImageMap, PageService

* fix: restore .ai-team agent history and decisions lost in PR #338 merge

The FileUpload PR (#338) inadvertently reverted Sprint 1 gate review
entries from agent histories (beast, cyclops, forge, jubilee, rogue)
and downgraded the FileUpload InputFile decision in decisions.md.

Restored from commit f85aa42 (docs(ai-team): Sprint 1 gate review results).

* feat: add Copilot custom agent definitions in .github/agents/

Creates .agent.md files for all 6 team agents (Beast, Cyclops, Forge,
Jubilee, Rogue, Scribe) so they appear in GitHub Copilot's agent picker.
Content sourced from existing .ai-team/agents/*/charter.md files.

* fix: replace individual agent files with Squad coordinator agent

Squad is the single Copilot agent that delegates to the specialized
agents defined in .ai-team/agents/. Individual agent files were
incorrectly created  the correct pattern is one coordinator agent
(squad.agent.md) that routes work to Forge, Cyclops, Beast, Jubilee,
Rogue, and Scribe based on task type.

* docs(ai-team): log Sprint 2 completion

Session: 2026-02-10-sprint2-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 2 session (4 components shipped with docs, samples, tests)
- Merged Sprint 2 design review decision from inbox
- Removed duplicate FileUpload InputFile decision from inbox (already consolidated)
- Appended Sprint 2 completion decision to decisions.md
- Propagated cross-agent updates to all 5 agent histories

* Updated the squad

* docs(ai-team): Sprint 3 planning session

Session: 2026-02-11-sprint3-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-11-sprint3-planning.md
- Merged 3 decisions from inbox into decisions.md
- Updated status.md to reflect 48/53 components complete
- Sprint 3 scope: DetailsView + PasswordRecovery
- Propagated cross-agent updates to all agent history files

* docs(ai-team): Sprint 3 execution complete

Session: 2026-02-12-sprint3-execution
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 3 execution session
- Merged 7 decisions from inbox into decisions.md
- Sprint 3 gate review: DetailsView + PasswordRecovery APPROVED
- Propagated cross-agent updates to Beast, Colossus, Cyclops, Rogue, Jubilee
- status.md updated to 50/53 (94%)

* docs(ai-team): Milestone 4 planning - Chart component

Session: 2026-02-12-milestone4-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-12-milestone4-planning.md
- Merged decisions from inbox (Chart.js evaluation, milestone plan, milestones directive)
- Propagated milestone 4 updates to 5 agent history files

* docs(ai-team): Summarize Forge history (13.2KB -> 4.3KB)

Session: 2026-02-12-milestone4-planning
Requested by: Scribe (automatic)

Changes:
- Summarized Forge history.md (exceeded ~12KB threshold)
- Preserved all team updates and key patterns

* feat: Milestone 6 — Feature Gap Closure (54 work items, ~345 gaps closed)

Closes the highest-impact feature gaps from the 53-control audit.

P0 — Base class fixes (~180 gaps): AccessKey, ToolTip on all controls;
DataBoundComponent inherits BaseStyledComponent; ValidatorDisplay + SetFocusOnError;
Image/Label base class upgrades.

P1 — Control improvements (~120 gaps): GridView paging/sorting/row editing;
Calendar style sub-components + enums; FormView header/footer/empty data;
HyperLink NavigateUrl rename; ValidationSummary HeaderText/ShowSummary/ValidationGroup.

P2 — Nice-to-have (~45 gaps): DataTextFormatString + AppendDataBoundItems on
BaseListControl; CausesValidation on CheckBox/RadioButton/TextBox; Menu Orientation;
Label AssociatedControlID; Login controls base class upgrade.

168 files changed, +5,712 / -1,775 lines
1,065 tests passing, 0 failures

* fix: Menu JS interop crash, Calendar attribute rendering, Menu auto-ID generation

- Add null safety and try/catch in Menu.js to prevent circuit crash
- Fix Calendar.razor attribute rendering issue
- Auto-generate Menu ID when not explicitly provided

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decision inbox for M8 bug fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: formally defer Substitution/Xml, polish documentation

- Mark Substitution and Xml as Deferred in status.md
- Create DeferredControls.md with migration guidance
- Fix mkdocs.yml nav issues
- Update README component stats
- Remove Chart hedging language

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add shared PagerSettings sub-component for GridView/FormView/DetailsView

- Add PagerButtons and PagerPosition enums
- Add PagerSettings class with Web Forms-compatible properties
- Add IPagerSettingsContainer interface
- Add UiPagerSettings base component
- Wire PagerSettings into GridView, FormView, and DetailsView
- Follow existing style sub-component CascadingParameter pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M8 session log and decision merge

Session: 2026-02-24-m8-release-readiness
Requested by: Jeffrey T. Fritz

Changes:
- Logged M8 session to .ai-team/log/2026-02-24-m8-release-readiness.md
- Merged 18 decisions from inbox (Menu auto-ID, Substitution/Xml deferral, M8 scope, PagerSettings, M7 plan, integration tests, TreeView, GridView, DataGrid, ListView, FormView, DetailsView, validators, Menu improvements, Playwright patterns, rendermode fix)
- Propagated team updates to all 6 agent histories
- Deduplicated decisions.md (0 exact heading duplicates found)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump version to 0.14 for Milestone 8 release

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log v0.14 release completion

Session: 2026-02-25-v014-release
Requested by: Jeffrey T. Fritz

Changes:
- Logged v0.14 release final session (docs fix, CI green, release created)
- Decision inbox checked (empty, no merges needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: ToolTip base class, ValidationSummary comma fix, SkinID type fix

- Move ToolTip parameter to BaseStyledComponent (fixes 28+ controls)
- Fix ValidationSummary comma-split data corruption bug
- Change SkinID from bool to string (matches Web Forms)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decisions for M9 code fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update documentation for ToolTip universality

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add ToolTip rendering to all styled component templates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test: ToolTip base class tests + ValidationSummary comma-split tests

- Add ToolTip rendering tests for 9 controls that gained ToolTip from base class
- Verify Button/Image/HyperLink ToolTip regression
- Add ValidationSummary tests for commas in error messages

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): milestone 9 session log and decisions merge

Session: 2026-02-25-milestone9-wave1
Requested by: Jeffrey T. Fritz

Changes:
- Logged M9 Wave 1+2 session
- Merged 5 decisions from inbox
- Consolidated ToolTip and ValidationSummary decisions
- Removed duplicate rendermode decision
- Updated 6 agent histories with cross-agent propagation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: TreeView caret not rotating on expand/collapse (#361)

The NodeImage property's fallback paths (when ShowLines=false) did not
check ShowExpandCollapse, relying solely on ImageSet.Collapse being
non-empty.  This made the logic fragile and returned Default_NoExpand.gif
for any ImageSet where Collapse was empty, even when ShowExpandCollapse
was true.

Restructured NodeImage to:
- Explicitly check ShowExpandCollapse in non-ShowLines code paths
- Always return distinct expand/collapse images when ShowExpandCollapse=true
- Fall back to Default_Collapse.gif / Default_Expand.gif when an ImageSet
  does not provide its own collapse/expand images
- Return Default_NoExpand.gif only when ShowExpandCollapse is false

Extracted ExpandCollapseImage() helper to DRY the ImageSet-to-filename
resolution with guaranteed defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M10 setup session log and decisions merge

Session: 2026-02-25-m10-setup-and-treeview-fix
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-m10-setup-and-treeview-fix.md
- Merged 3 decision(s) from inbox into decisions.md
- Propagated updates to agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): summarize oversized agent history files

Summarized older entries in 4 agent history files exceeding ~12KB:
- cyclops: 30.6KB -> 12KB (M6/M7 implementation details consolidated)
- beast: 14.5KB -> 11.3KB (doc conventions and audit findings summarized)
- forge: 13.9KB -> 12.4KB (M7 planning details condensed)
- rogue: 12.6KB -> 11.7KB (duplicate team updates removed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: sample site nav caret rotation and link contrast (#362)

- Add missing AfterBlazorServerSide.styles.css link to App.razor
  (NavMenu.razor.css scoped styles were completely ignored)
- Scope a.component-link blue color to .main-content only
- Remove unused data-bs-toggle attributes (Bootstrap JS not loaded)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Chart.js dataset z-order for mixed charts (#363)

Line/area series now render on top of bar/column series by default,
matching ASP.NET Web Forms Chart control behavior. Added Order parameter
to ChartSeries for explicit control.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan

* Add Calendar component implementation with basic structure

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add unit tests for Calendar component - all 19 tests passing

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* Add Calendar sample page and documentation

* Fix code review issues: safe substring and synchronous event handling

Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>

* fix: refactor Calendar to use CalendarSelectionMode enum (#333)

- Create CalendarSelectionMode enum (None, Day, DayWeek, DayWeekMonth)
- Refactor Calendar.SelectionMode from string to CalendarSelectionMode enum
- Remove .GetAwaiter().GetResult() blocking call in CreateDayRenderArgs
- Add Caption, CaptionAlign, UseAccessibleHeader properties
- Update tests and samples to use enum values

* samples: add demo pages for Calendar, FileUpload, ImageMap

- Calendar: date selection, selection modes, styling, day/title formats, events

- FileUpload: basic upload, file type filtering, multiple files, disabled, styled

- ImageMap: navigate/postback/mixed hot spot modes, rectangle/circle/polygon shapes

- Updated NavMenu and ComponentList with links to all three new components

* docs: add documentation for Calendar, FileUpload, ImageMap, PageService

* fix: restore .ai-team agent history and decisions lost in PR #338 merge

The FileUpload PR (#338) inadvertently reverted Sprint 1 gate review
entries from agent histories (beast, cyclops, forge, jubilee, rogue)
and downgraded the FileUpload InputFile decision in decisions.md.

Restored from commit f85aa42 (docs(ai-team): Sprint 1 gate review results).

* feat: add Copilot custom agent definitions in .github/agents/

Creates .agent.md files for all 6 team agents (Beast, Cyclops, Forge,
Jubilee, Rogue, Scribe) so they appear in GitHub Copilot's agent picker.
Content sourced from existing .ai-team/agents/*/charter.md files.

* fix: replace individual agent files with Squad coordinator agent

Squad is the single Copilot agent that delegates to the specialized
agents defined in .ai-team/agents/. Individual agent files were
incorrectly created  the correct pattern is one coordinator agent
(squad.agent.md) that routes work to Forge, Cyclops, Beast, Jubilee,
Rogue, and Scribe based on task type.

* docs(ai-team): log Sprint 2 completion

Session: 2026-02-10-sprint2-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 2 session (4 components shipped with docs, samples, tests)
- Merged Sprint 2 design review decision from inbox
- Removed duplicate FileUpload InputFile decision from inbox (already consolidated)
- Appended Sprint 2 completion decision to decisions.md
- Propagated cross-agent updates to all 5 agent histories

* Updated the squad

* docs(ai-team): Sprint 3 planning session

Session: 2026-02-11-sprint3-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-11-sprint3-planning.md
- Merged 3 decisions from inbox into decisions.md
- Updated status.md to reflect 48/53 components complete
- Sprint 3 scope: DetailsView + PasswordRecovery
- Propagated cross-agent updates to all agent history files

* docs(ai-team): Sprint 3 execution complete

Session: 2026-02-12-sprint3-execution
Requested by: Jeffrey T. Fritz

Changes:
- Logged Sprint 3 execution session
- Merged 7 decisions from inbox into decisions.md
- Sprint 3 gate review: DetailsView + PasswordRecovery APPROVED
- Propagated cross-agent updates to Beast, Colossus, Cyclops, Rogue, Jubilee
- status.md updated to 50/53 (94%)

* docs(ai-team): Milestone 4 planning - Chart component

Session: 2026-02-12-milestone4-planning
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-12-milestone4-planning.md
- Merged decisions from inbox (Chart.js evaluation, milestone plan, milestones directive)
- Propagated milestone 4 updates to 5 agent history files

* docs(ai-team): Summarize Forge history (13.2KB -> 4.3KB)

Session: 2026-02-12-milestone4-planning
Requested by: Scribe (automatic)

Changes:
- Summarized Forge history.md (exceeded ~12KB threshold)
- Preserved all team updates and key patterns

* feat: Milestone 6 — Feature Gap Closure (54 work items, ~345 gaps closed)

Closes the highest-impact feature gaps from the 53-control audit.

P0 — Base class fixes (~180 gaps): AccessKey, ToolTip on all controls;
DataBoundComponent inherits BaseStyledComponent; ValidatorDisplay + SetFocusOnError;
Image/Label base class upgrades.

P1 — Control improvements (~120 gaps): GridView paging/sorting/row editing;
Calendar style sub-components + enums; FormView header/footer/empty data;
HyperLink NavigateUrl rename; ValidationSummary HeaderText/ShowSummary/ValidationGroup.

P2 — Nice-to-have (~45 gaps): DataTextFormatString + AppendDataBoundItems on
BaseListControl; CausesValidation on CheckBox/RadioButton/TextBox; Menu Orientation;
Label AssociatedControlID; Login controls base class upgrade.

168 files changed, +5,712 / -1,775 lines
1,065 tests passing, 0 failures

* fix: Menu JS interop crash, Calendar attribute rendering, Menu auto-ID generation

- Add null safety and try/catch in Menu.js to prevent circuit crash
- Fix Calendar.razor attribute rendering issue
- Auto-generate Menu ID when not explicitly provided

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decision inbox for M8 bug fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: formally defer Substitution/Xml, polish documentation

- Mark Substitution and Xml as Deferred in status.md
- Create DeferredControls.md with migration guidance
- Fix mkdocs.yml nav issues
- Update README component stats
- Remove Chart hedging language

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add shared PagerSettings sub-component for GridView/FormView/DetailsView

- Add PagerButtons and PagerPosition enums
- Add PagerSettings class with Web Forms-compatible properties
- Add IPagerSettingsContainer interface
- Add UiPagerSettings base component
- Wire PagerSettings into GridView, FormView, and DetailsView
- Follow existing style sub-component CascadingParameter pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M8 session log and decision merge

Session: 2026-02-24-m8-release-readiness
Requested by: Jeffrey T. Fritz

Changes:
- Logged M8 session to .ai-team/log/2026-02-24-m8-release-readiness.md
- Merged 18 decisions from inbox (Menu auto-ID, Substitution/Xml deferral, M8 scope, PagerSettings, M7 plan, integration tests, TreeView, GridView, DataGrid, ListView, FormView, DetailsView, validators, Menu improvements, Playwright patterns, rendermode fix)
- Propagated team updates to all 6 agent histories
- Deduplicated decisions.md (0 exact heading duplicates found)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump version to 0.14 for Milestone 8 release

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log v0.14 release completion

Session: 2026-02-25-v014-release
Requested by: Jeffrey T. Fritz

Changes:
- Logged v0.14 release final session (docs fix, CI green, release created)
- Decision inbox checked (empty, no merges needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: add Skins/Themes PoC plan, compatibility report, audit report, and M12 plan

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: bump version to 0.15 for patch release

Includes M9 migration fidelity + post-M9 bug fixes:
- TreeView caret rotation (#361)
- Sample site nav contrast (#362)
- Chart.js dataset z-order (#363)
- Skins/Themes PoC planning docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…yml (#372)

* fix(ci): use env var pattern for secrets in nuget.yml if condition

The if: secrets.NUGET_API_KEY expression causes workflow file validation
failures in GitHub Actions. Use the env var pattern instead: set the
secret to an env var, then check env.NUGET_API_KEY in the if condition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(ci): use env var pattern for secrets in deploy-server-side.yml

Same fix as nuget.yml  secrets cannot be referenced in step-level
if conditions. Use env var pattern instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(ai-team): CI workflow fixes session

Session: 2026-02-25-ci-workflow-fixes
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-ci-workflow-fixes.md
- Merged 2 decision(s) from inbox into decisions.md
- Consolidated deployment pipeline secret-gating pattern
- Deduplicated chart component architecture entries
- Consolidated DataBoundComponent style gap + implementation
- Propagated CI secret-gating update to forge and cyclops history

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: add 19 unreachable sample pages to ComponentCatalog.cs (#350)

Add 5 missing component entries (DataBinder, ViewState, DetailsView, Menu,
PasswordRecovery) and 15 missing SubPage entries for GridView, TreeView,
FormView, ListView, DataGrid, and Panel. Fix DataList SubPage name from
'Flow' to 'SimpleFlow' to match actual file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Migrate LoginView and PasswordRecovery to BaseStyledComponent (#352, #354)

- LoginView: Change base class from BaseWebFormsComponent to BaseStyledComponent
- PasswordRecovery: Change base class from BaseWebFormsComponent to BaseStyledComponent
- PasswordRecovery: Add CssClass, Style, and ToolTip rendering to all three step table elements
- Panel BackImageUrl (#351): Already implemented, no changes needed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update 5 doc pages with M6-M8 feature additions (#359)

- ChangePassword: add Orientation and TextLayout documentation
- PagerSettings: create new dedicated doc page
- FormView: add ItemCommand, styles, PagerSettings, Caption docs
- DetailsView: add Caption, update styles/PagerSettings as supported
- DataGrid: update paging, sorting, selection as supported

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(docker): strip NBGV in Docker build for correct version stamping

NBGV unconditionally overrides -p:InformationalVersion when its MSBuild
task runs. Since .dockerignore excludes .git, NBGV falls back to a
stale version. Fix: sed removes the NBGV PackageReference from
Directory.Build.props inside the Docker build stage, letting the
explicit VERSION build arg take effect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add 5 missing integration smoke tests (#358)

Add InlineData entries for ListView/CrudOperations, Label,
Panel/BackImageUrl, LoginControls/Orientation, and DataGrid/Styles
to existing Theory smoke tests in ControlSampleTests.cs.

All 5 sample pages verified to exist. Build green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M10 batch 1 session log and decisions

Session: 2026-02-25-m10-batch1
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-m10-batch1.md
- Merged 4 decisions from inbox into decisions.md (forge, jubilee, beast, cyclops)
- Propagated cross-agent updates to all agent history files
- Summarized oversized history files (forge, cyclops, beast, rogue)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: Implement Menu level styles (StaticMenuStyle, IMenuStyleContainer, RenderFragment params) (#360)

- Add StaticMenuStyle sub-component class to MenuItemStyle.razor.cs
- Create IMenuStyleContainer interface in Interfaces/
- Menu implements IMenuStyleContainer with all 4 style properties
- Add RenderFragment parameters: DynamicMenuStyleContent, StaticMenuStyleContent,
  DynamicMenuItemStyleContent, StaticMenuItemStyleContent
- Apply StaticMenuStyle CSS to ul.level1 in Menu.razor
- Add IsFixed=true to CascadingValue for ParentMenu
- Add 8 bUnit tests covering StaticMenuStyle, RenderFragment params,
  interface implementation, and defaults

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: Update history and decisions for Menu level styles (#360)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: implement remaining ListView CRUD events (#356)

Add 7 missing events to complete ListView event parity:
- Sorting/Sorted with ListViewSortEventArgs and HandleCommand routing
- SelectedIndexChanging/SelectedIndexChanged with ListViewSelectEventArgs
- PagePropertiesChanging/PagePropertiesChanged with SetPageProperties method
- LayoutCreated converted from EventHandler to EventCallback and wired up

Add SortExpression, SortDirection, StartRowIndex, MaximumRows properties.
Add 12 bUnit tests across 4 test files. All 1229 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): M10 batch 2 session log and decisions

Session: 2026-02-25-m10-batch2
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-m10-batch2.md
- Merged 3 decisions from inbox into decisions.md (ListView CRUD, Menu styles, smoke tests)
- Propagated updates to rogue, beast, jubilee, colossus history files
- Summarized cyclops/history.md (14.8KB -> 6.6KB)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): capture feature branch workflow directive

All new work must use feature branches with PRs to upstream/dev.
Never commit directly to dev.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: activate SkinID and EnableTheming properties (#365)

Remove [Obsolete] attributes from SkinID and EnableTheming properties on
BaseWebFormsComponent. EnableTheming now defaults to true and SkinID
defaults to empty string, preparing them for theme/skin integration in #366.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decisions for #365

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add ThemeConfiguration core types for Skins/Themes PoC (#364)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: wire ThemeConfiguration into BaseStyledComponent (#366)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add Skins/Themes PoC demo page (#367)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test: add bUnit tests for Skins/Themes PoC (#368)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Calendar cursor, HTML entities, and DayWeek column alignment

- Add cursor:pointer to all clickable <a> elements (was text cursor)
- Render SelectMonthText as MarkupString (HTML entities were double-encoded)
- Add selector column to title row for DayWeek mode (column count 78 mismatch)
- DayWeekMonth shows month selector link, DayWeek shows empty alignment cell

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): Skins/Themes PoC session log and decisions

Session: 2026-02-25-m10-skins-themes-poc
Requested by: Jeffrey T. Fritz

Changes:
- Logged Skins/Themes PoC session (#364-#368) and Calendar fix
- Merged 4 decision(s) from inbox into decisions.md
- Propagated updates to agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add before/migration/after sections to Theming sample page (#367)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add Calendar Web Forms sample to BeforeWebForms project

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update ThemesAndSkins.md to reflect PoC implementation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Beast history and add themes doc decision record

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): docs/samples session log and decisions merge

Session: 2026-02-25-docs-and-samples
Requested by: Jeffrey T. Fritz

Changes:
- Logged Beast doc update and Jubilee samples session
- Merged 2 decision(s) from inbox into decisions.md
- Propagated updates to relevant agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): HTML audit strategy decision

Session: 2026-02-25-html-audit-strategy
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-25-html-audit-strategy.md
- Merged 3 decision files from inbox (audit strategy, milestones priority, milestone plan)
- Consolidated overlapping HTML Audit Strategy and Divergence Registry decisions
- Propagated updates to agent history files
- Summarized forge/history.md (17.7KB -> 6KB)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: HTML audit milestone plan (M11-M13)

Session: 2026-02-25-html-audit-milestones
Requested by: Jeffrey T. Fritz

Changes:
- Created planning-docs/HTML-AUDIT-MILESTONES.md (M11-M13)
- Renumbered MILESTONE12-PLAN.md to M14
- Logged session to .ai-team/log/
- Propagated updates to agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: scope DetailsView Edit link locators to main content area

The ComponentCatalog now includes FormView sub-pages (Edit, Events, Styles)
in the sidebar navigation. The sidebar 'Edit' link appears before the
DetailsView's Edit command link in DOM order, causing the test's .First
selector to click the sidebar link instead, navigating away from the page.

Fix: scope both DetailsView_EditButton_SwitchesMode and
DetailsView_EditMode_RendersInputTextboxes to use page.Locator("main")
before searching for the Edit link, ensuring the sidebar is excluded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add Ralph work monitor to squad

- Added Ralph to team roster with Monitor status
- Added squad-heartbeat.yml workflow (runs every 30 min)
- Ralph auto-triages squad-labeled issues and tracks work

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): Ralph addition and CI fix session log

Session: 2026-02-25-ralph-and-ci-fix
Requested by: Jeffrey T. Fritz

Changes:
- Logged session: Ralph added, CI failures fixed by Colossus
- Agent history updates from milestone notification

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ent & Data Alignment (#377)

* M11-03/M11-04: Add data-audit-control markers and create missing Tier 1 samples

Part 1 (M11-03): Added data-audit-control wrapper divs around all controls
in existing BeforeWebForms sample pages. Multi-control pages use numbered
suffixes (e.g., Button-1, Button-2). 26 existing .aspx files updated across
Button, Calendar, Chart, DataList, DropDownList, FormView, GridView,
Hyperlink, ListView, Menu, Repeater, TextBox, and TreeView samples.

Part 2 (M11-04): Created .aspx sample pages for 17 missing Tier 1 controls:
Label, Image, CheckBox, RadioButton, Panel, Literal, BulletedList,
FileUpload, HiddenField, LinkButton, ImageButton, ImageMap, ListBox,
CheckBoxList, RadioButtonList, PlaceHolder, AdRotator. Each has Default.aspx
and Default.aspx.cs with data-audit-control markers, MasterPageFile
directive, and minimal code-behind.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(scripts): add HTML normalization pipeline for fidelity audit (M11-06)

Create normalize-html.mjs and normalize-rules.json implementing:
- Strip ViewState/EventValidation hidden fields (D-03)
- Strip WebResource.axd references (D-04)
- Normalize ctl00_ ID mangling to developer IDs (D-01)
- Replace __doPostBack hrefs with [postback] placeholder (D-02)
- Strip Web Forms name attributes with naming containers (D-01)
- Remove TreeView page-level JS and onclick attrs (D-07)
- Strip validator evaluation attributes (D-10)
- Remove Blazor-specific attributes and comment markers
- Normalize self-closing tags, attribute order, whitespace
- Normalize CSS color values in style attributes
- Generate Markdown comparison reports with diff output

Uses only Node.js built-in modules (no external dependencies).
Rules are configurable via normalize-rules.json.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(m11): add IIS Express setup, divergence registry, capture & normalization scripts

M11-01: scripts/Setup-IISExpress.ps1  automates CodeBehindCodeFile, NuGet restore, IIS Express launch
M11-02: planning-docs/DIVERGENCE-REGISTRY.md  10 documented intentional HTML divergences
M11-05: scripts/capture-html.mjs + capture-blazor.mjs  Playwright HTML/screenshot capture
M11-06: scripts/normalize-html.mjs + normalize-rules.json  HTML normalization for diff comparison

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scripts): fix Roslyn DLL copy null array concatenation in strict mode

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(m11): run Tier 1 gold-standard capture  66 controls captured

Fix setup script: include .asax in CodeFile conversion, comment out
RouteConfig/BundleConfig (not dynamically compilable), fix Roslyn copy.
Fix capture script: use .aspx extension for non-FriendlyUrls routes.

Capture results: 24/30 pages succeeded, 66 controls captured.
6 pages (data-bound controls) returned 500  need data sources.
2 screenshot warnings (invisible elements)  HTML still captured.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add data-audit-control markers to Blazor sample pages

Add div wrappers with data-audit-control attributes to 18 Blazor sample
pages to enable HTML output comparison with WebForms audit captures.

Controls marked (matching audit-output/webforms/ capture names):
- AdRotator (1), BulletedList (3), Button (1), Calendar (7)
- CheckBox (3), DropDownList (6), FileUpload (1), HiddenField (1)
- HyperLink (4), Image (2), ImageMap (1), Label (3)
- LinkButton (3), Literal (2), Panel (3), PlaceHolder (1)
- RadioButtonList (2), TreeView (1)

Skipped controls with no Blazor sample directory:
- CheckBoxList, ImageButton, ListBox, RadioButton, TextBox

Skipped Menu (empty WebForms captures).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(m11): Blazor comparison capture  45 controls, 70 diffs generated

M11-08: Captured 45 Blazor controls, normalized both WebForms (66) and
Blazor (45) captures, generated diff-report.md with 70 comparison entries.

Key findings visible in report:
- Button: WebForms <input type=submit>, Blazor <button> (tag mismatch)
- BulletedList: Blazor wraps items in <span>, different list-style handling
- Calendar: structural differences in table rendering
- Many controls need sample parity before meaningful comparison

Added data-audit-control markers to 18 Blazor sample pages.
Fixed capture-blazor.mjs samplesDir path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(m11): Tier 1 HTML Audit findings report

M11-09: 70 comparisons, 0 exact matches.
Key findings: ~8-10 genuine bugs (Button <input> vs <button>,
BulletedList <ul> vs <ol>, LinkButton missing href), ~31% false
positives from sample content misalignment, rest intentional.
Priority fix list with 10 ranked items for M12.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log M12 kickoff session, merge decision inbox

Session: 2026-02-26-m12-kickoff
Requested by: Jeffrey T. Fritz

Changes:
- Logged M11 completion (9/9 items) and M12 kickoff
- Logged agent assignments (Jubilee M12-01, Cyclops M12-02)
- Logged divergence backlog items (d01, d06, d09)
- Merged decision: IIS Express setup script (Cyclops)
- Merged decision: Intentional divergence registry D-01 to D-10 (Forge)
- Deleted 2 inbox files after merging

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(scripts): enhance normalization pipeline for Tier 2 data controls (M12-02)

Add 5 new normalization rules for data control HTML comparison:
- strip-content-prefix-ids: strips MainContent_/ContentPlaceHolder_ prefixes
- strip-event-handlers: strips all on* event handler attributes
- strip-blazor-enhanced-nav: strips data-enhance-* attributes
- strip-form-action: strips form action attributes
- strip-table-legacy-attrs: strips cellpadding/cellspacing/rules/border

Enhanced existing rules:
- strip-dopostback: fully strips postback hrefs (was replacing with placeholder)
- strip-webforms-ids: handles prefix segments before ctl (MainContent_ctl00_X_ctl01_Y)

Reordered rules so Blazor attribute stripping runs before event handler
stripping to prevent partial matches on blazor:onclick.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(m12): Tier 2 data control capture  83 WF + 45 Blazor controls, 86 diffs

M12-01: DetailsView + DataPager BeforeWebForms samples with inline data
M12-02: Normalization pipeline enhanced (19 rules, up from 14)
M12-03: Gold-standard capture  83 controls from 31 pages (up from 66/24)
M12-04: Blazor comparison  45 controls, 86 divergence entries
Infrastructure fixes:
- web.config: removed System.Web.Optimization references
- Site.Master: commented out BundleReference/Scripts.Render
- Global.asax.cs: commented out Optimization/Routing usings
- GridView: added Customer model to App_Code
- Menu Default.aspx: removed stray ? character
- Setup-IISExpress.ps1: web.config patching + using directive handling
- SharedSampleObjects.dll copied to BeforeWebForms bin (netstandard2.0)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add M12 Tier 2 HTML audit findings report

Classify all 86 divergences from diff-report.md:
- 26 Sample Parity (22 unique, 4 HyperLink duplicates)
- 23 Genuine Bug (10 controls, 9 distinct bugs)
- 37 Missing Blazor Capture (Tier 2 data controls + Menu + missing markers)

Genuine bugs ranked by severity:
- Critical: Button, BulletedList (wrong HTML tags)
- High: LinkButton, Calendar, TreeView (missing attrs/structure)
- Medium: CheckBox, RadioButtonList, FileUpload (wrappers/GUIDs)
- Low: Image (empty longdesc)

No Tier 1 bugs fixed since M11. Tier 2 WF captures complete.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: add Tier 3 JS extraction strategy for M13 audit

Define how Menu, TreeView, and Calendar JavaScript injection is handled
during HTML audit comparison. Conclusion: the existing normalization
pipeline (D-02, D-04, D-07, M12 event handler stripping) is sufficient.
No new JS extraction tooling is needed.

Milestone: M13-01

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add data-audit-control markers to 7 Blazor sample pages

Add div wrappers with data-audit-control attributes for Playwright
HTML audit capture on DataList, DetailsView (4 instances),
GridView, ListView, Repeater, Menu (2 instances), and
FormView (2 instances) sample pages.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add BeforeWebForms sample pages for 16 remaining controls

Validators: RequiredFieldValidator, CompareValidator, RangeValidator,
RegularExpressionValidator, CustomValidator, ValidationSummary

Login Controls: Login, LoginName, LoginStatus, LoginView,
ChangePassword, CreateUserWizard, PasswordRecovery

Other Controls: SiteMapPath (with Web.sitemap), MultiView, Table

All pages use MasterPageFile, CodeFile convention, and wrap each
control instance with data-audit-control markers for HTML audit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(m13): comprehensive M13 capture  125 WF + 53 Blazor controls, 132 diffs

WebForms: 48 pages captured, 125 controls (up from 83 in M12)
  New: validators (6), login controls (7), SiteMapPath, MultiView, Table
Blazor: 40 pages, 53 controls (up from 45 in M12)
  New: DataList, DetailsView4, GridView, ListView, Repeater (markers added)
Diff report: 132 divergences (up from 86 in M12)
Fix: Setup-IISExpress.ps1 variable name (  )

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add comprehensive HTML fidelity audit report (M13-06)

Consolidates findings from M11 (Tier 1), M12 (Tier 2), and M13 (Tier 3+Remaining)
into a single master audit document covering all 132 comparisons across 46 controls.

Key findings:
- 9 genuine structural bugs across 10 controls (23 variant entries)
- 22 sample parity false positives
- 75 missing Blazor captures (59% coverage gap)
- 4 Tier 2 data controls needing detailed investigation
- All 10 intentional divergences (D-01 through D-10) documented

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log M13 HTML audit completion

Session: 2026-02-26-m13-complete
Requested by: Jeffrey T. Fritz

Changes:
- Logged M13 session (JS strategy, samples, captures, audit report)
- No decisions to merge (inbox empty)
- Committed all .ai-team/log/ files to branch

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: LinkButton renders href and CssClass, Image omits empty longdesc

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: data control divergence analysis (DataList, GridView, ListView, Repeater)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add data-audit-control markers to Tier 1 Blazor samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Button renders <input type=submit>, BulletedList uses <ol> for ordered styles

- Button: renders <input type=submit> with Text as value attribute (already fixed)
- Button: UseSubmitBehavior controls type=submit vs type=button (already fixed)
- BulletedList: removed <span> wrapping in Text mode, renders text directly in <li>
- BulletedList: disabled items render as plain text without <span>
- Updated all test selectors from Find("button") to Find("input[type=submit]")
- Updated BulletedList test assertions to check li text content instead of li span
- All 1253 tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: log P1 Button/BulletedList bug fixes in Cyclops history

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: create missing Blazor sample pages for CheckBoxList, ImageButton, ListBox + audit markers

- Created CheckBoxList/Index.razor with 2 instances (default items, RepeatDirection/RepeatLayout)
- Created ImageButton/Index.razor with 2 instances (basic, styled with AlternateText/ToolTip)
- Created ListBox/Index.razor with 2 instances (single selection, multiple selection)
- Added data-audit-control markers to Table/Index.razor (Table-1, Table-2)
- Added data-audit-control markers to SiteMapPath/Index.razor (SiteMapPath-1, SiteMapPath-2)
- Added data-audit-control markers to all 6 Validation sample pages:
  RequiredFieldValidator-1, CompareValidator-1, RangeValidator-1,
  RegularExpressionValidator-1, CustomValidator-1, ValidationSummary-1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Calendar structural improvements  tbody, cell widths, titles, abbr headers

- Add <tbody> wrapper around all table rows (structural correctness)
- Add width:14% on day <td> cells (layout fidelity)
- Add title attributes on day <a> links with 'MonthName Day' format (accessibility)
- Use full day names in <abbr> attribute on day headers (accessibility)
- Add align=center on day header <th> elements
- Add default border styles on root <table> (border-width, border-style, border-collapse)
- Restructure navigation row to sub-table matching WebForms output
- Add title attributes on nav links ('Go to the previous/next month')

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: CheckBox removes span wrapper, RadioButtonList stable IDs, FileUpload clean attrs

Bug 6: CheckBox no longer wraps input+label in a <span>. Styles/class/tooltip
are applied directly to the <input> element, matching WebForms output.

Bug 7: RadioButtonList and CheckBoxList now use ClientID-based names and IDs
(e.g. name="RadioButtonList1", id="RadioButtonList1_0") when the ID parameter
is set, falling back to generated IDs only when no ID is provided.

Bug 8: FileUpload now explicitly constructs its attribute dictionary via
GetInputAttributes() and passes it to InputFile's AdditionalAttributes,
preventing any stray scope or unmatched attributes from leaking into
the rendered <input type="file"> element.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: TreeView structural improvements  table-based node layout

Wrap child nodes in a <div> element to match the WebForms TreeView DOM
structure, where child nodes are enclosed in <div id=...Nodes> wrappers.
This ensures proper nesting structure for expand/collapse behavior and
CSS targeting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: DataList conditional border-collapse, GridView defaults (Both gridlines, border-collapse, nbsp headers)

DataList:
- Only add border-collapse:collapse when GridLines != None (WebForms behavior)
- Support itemtype attribute passthrough on table and span elements

GridView:
- Default GridLines to Both (renders rules=all and border=1)
- Add border-collapse:collapse to table style
- Render &nbsp; in empty header cells to match WebForms output

Update DataList tests to reflect conditional border-collapse behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add NamingContainer component for ID mangling (D-01)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: Login controls + Blazor Identity integration analysis (D-09)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add RenderingMode=Table to Menu component (D-06)

Add MenuRenderingMode enum (List/Table) and RenderingMode parameter to Menu.
When Table mode is active, Menu renders <table>/<tr>/<td> structure instead
of <ul>/<li>, matching ASP.NET Web Forms pre-4.0 output. Horizontal
orientation places all items in a single <tr>; vertical gives each item
its own <tr>. Default remains List mode for backward compatibility.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: post-bug-fix capture pipeline results

Re-ran full HTML capture pipeline after 14 bug fixes across 10 controls.
Results: 132 -> 131 divergences, 0 -> 1 exact match (Literal-3).
All 11 targeted controls show verified structural improvements.
11 new Blazor captures gained (75 -> 64 missing).
Primary blocker identified: sample data parity, not component bugs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log backlog completion and merge decisions

Session: 2026-02-26-backlog-and-pipeline
Requested by: Jeffrey T. Fritz

Changes:
- Logged session to .ai-team/log/2026-02-26-backlog-and-pipeline.md
- Merged 5 decisions from inbox into decisions.md
- Deleted inbox files after merging
- Propagated updates to 6 agent history files
- No deduplication needed (no overlapping decisions found)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add WebFormsPage unified legacy wrapper component

Combines NamingContainer (ID mangling) and ThemeProvider (skin/theme
cascading) into a single component that mirrors System.Web.UI.Page.

- Inherits NamingContainer for naming scope + UseCtl00Prefix
- Adds Theme parameter for ThemeConfiguration cascading
- Place in MainLayout.razor wrapping @Body for full legacy support
- 6 new tests, all 1267 pass
- Documentation at docs/UtilityFeatures/WebFormsPage.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: align sample data via SharedSampleObjects

- Add Product model to SharedSampleObjects with static GetProducts()
- DetailsView: both WF and Blazor now use same Product data (10 items)
- DataPager: WF now uses SharedSampleObjects.Models.Product
- Remove duplicate inline Product classes from WF code-behinds
- All 1267 tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: align GridView RowSelection data with SharedSampleObjects

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log M14 unified wrapper session, merge decisions

Session: 2026-02-26-m14-unified-wrapper
Requested by: Jeffrey T. Fritz

Changes:
- Logged M14 session: WebFormsPage build, sample data alignment
- Merged 2 inbox decisions (forge-unified-wrapper, copilot-directive-shared-data)
- Consolidated overlapping wrapper decisions (Forge design + Jeff directive)
- Propagated 3 decisions to 6 agent history files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: add NamingContainer documentation and cross-references

- Created docs/UtilityFeatures/NamingContainer.md with full component docs
- Added NamingContainer to mkdocs.yml nav
- Updated IDRendering.md with NamingContainer cross-references

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: align GridView + ListView samples with SharedSampleObjects

- Created Employee model in SharedSampleObjects for GridView DisplayProperties
- Added Product.GetProducts(count) overload for deterministic large datasets
- GridView InlineEditing/Paging/Sorting/Selection/DisplayProperties now use shared models
- ListView CrudOperations now uses Widget.SimpleWidgetList
- 6 files aligned, all builds pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(ai-team): log M14 session, merge decisions, update agent histories

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: update DetailsView integration tests for CustomerProduct migration

Update all Customer-specific assertions to match the new Product model data:
- 'Customer Details'  'Product Details' (Styles test)
- 'Customer Record'  'Product Record' (Caption test)
- 'No customers found.'  'No products found.' (EmptyData test)
- Customer field names in assertion messages  Product field names (EditMode test)

All 7 DetailsView integration tests now pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t markers (#393)

* fix: BulletedList renders <ol> for numbered styles (#380)

- Remove HTML type attribute from <ol>; WebForms uses CSS list-style-type only
- Make start attribute conditional (only when FirstBulletNumber != 1)
- Update tests to assert list-style-type CSS instead of type attribute
- Add tests for no-type-attribute and default-start-omission

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: LinkButton CssClass pass-through to class attribute (#379)

- Updated GetCssClassOrNull() to add aspNetDisabled class when Enabled=false,
  matching the Button component's CalculatedCssClass pattern
- Added tests for CssClass rendering, disabled state class, and PostBackUrl+class

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: Image longdesc only renders when DescriptionUrl has value (#378)

- Added tests verifying longdesc attribute is rendered only when
  DescriptionUrl is non-empty (conditional rendering via GetLongDesc)
- Confirmed existing GetLongDesc() correctly returns null for empty/unset
  DescriptionUrl, suppressing the longdesc attribute

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history and decision for M15 bug fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: align Blazor sample data with WebForms for M15 (#381)

Align 14 Blazor sample pages to use identical text, values, URLs, and
attributes as their WebForms counterparts for HTML audit matching:

- Label: Hello World, Styled Label (text-primary/Blue/Bold), HTML content
- Literal: PassThrough and Encode mode text to match WebForms content
- HiddenField: Value secret-value-123
- PlaceHolder: Programmatic content text
- Panel: GroupingText User Info, ScrollBars Auto, DefaultButton
- HyperLink: Blue Button text, bing.com URLs, styling/tooltip/visible
- Image: banner.png src, Banner image/Sized image alt, width/height
- Button: Blue Button text with Blue/White styling
- CheckBox: Accept Terms, Subscribe, Enable Feature labels
- DropDownList: Data-bound First/Second/Third Item, disabled/styled/colored
- BulletedList: Disc Apple/Banana/Cherry/Date, Numbered, Square HyperLinks
- LinkButton: Click Me (btn-primary), Submit Form, Disabled Link
- ImageMap: banner.png, two rect hotspots (Bing/GitHub)
- AdRotator: Ads.xml with Visit Bing/Visit GitHub ads, banner.png
- Added wwwroot/Content/Images/banner.png for image path parity

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Jubilee history with M15-01 sample alignment learnings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: Forge M15-10 data control analysis and M15 strategy

Classify all 294 diff lines across DataList, GridView, ListView, Repeater.
Key finding: only 4 genuine bugs remain; 22 are sample parity issues.
ListView and Repeater have zero component bugs.

Resolves #392

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add data-audit-control markers to Blazor sample pages (#384)

Add audit markers to 10 existing Blazor sample pages that were missing
data-audit-control wrapper divs, matching the WebForms counterparts:
- ChangePassword (ChangePassword-1)
- Chart (Chart)
- CreateUserWizard (CreateUserWizard-1)
- Login (Login-1)
- LoginName (LoginName-1)
- LoginStatus (LoginStatus-1, LoginStatus-2)
- MultiView (MultiView-1)
- PasswordRecovery (PasswordRecovery-1, PasswordRecovery-2)
- Table (Table-3)

Create 2 new Blazor sample pages for controls that had WebForms samples
but no Blazor equivalents:
- DataPager (DataPager)
- LoginView (LoginView-1)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update jubilee history with M15-08 audit marker learnings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: FileUpload renders developer-set ID without GUID suffix (#383)

Add regression tests verifying that FileUpload renders the exact ID
the developer sets (no GUID suffix) and omits the id attribute entirely
when no ID is specified, matching WebForms behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: CheckBox renders without unnecessary span wrapper (#382)

Add regression tests verifying that CheckBox renders <input> and
<label> directly without a <span> wrapper, matching WebForms output.
CheckBoxList uses its own inline rendering and is unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: GridView UseAccessibleHeader defaults to true matching WebForms

WebForms defaults UseAccessibleHeader to true, rendering header cells
as th scope=col. The Blazor component incorrectly defaulted to false.
Change default to true and add tests for both default and explicit
false behaviors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update Cyclops history with M15 closure fix learnings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: update Ads.xml to use correct image paths matching wwwroot

Update ImageUrl entries from non-existent /Content/Images/banner.png to
/img/CSharp.png and /img/VB.png which exist in wwwroot/img/. Update
AlternateText to match integration test expectations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@@ -1,8 +1,17 @@
@inherits BaseWebFormsComponent

@if (ParentMenu?.RenderingMode == MenuRenderingMode.Table)
{
@if (ParentMenu?.Orientation == Orientation.Vertical)

Check warning

Code scanning / CodeQL

Constant condition Warning

Condition is always not null because of
call to operator ==
.

Copilot Autofix

AI 2 months ago

To fix the problem, remove the redundant null-conditional access on ParentMenu inside the if block that is already guarded by ParentMenu?.RenderingMode == MenuRenderingMode.Table. Once we are inside that if, ParentMenu is known to be non‑null whenever the block executes, so subsequent uses can safely reference ParentMenu directly. This simplifies the condition and removes the constant-condition warning without changing functionality.

Concretely, in src/BlazorWebFormsComponents/MenuItem.razor, on line 5 change ParentMenu?.Orientation to ParentMenu.Orientation. No other changes are required, and no new imports or methods are needed. All other uses of ParentMenu?. occur outside the guarded block or form part of public API-style checks and should remain as-is.

Suggested changeset 1
src/BlazorWebFormsComponents/MenuItem.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents/MenuItem.razor b/src/BlazorWebFormsComponents/MenuItem.razor
--- a/src/BlazorWebFormsComponents/MenuItem.razor
+++ b/src/BlazorWebFormsComponents/MenuItem.razor
@@ -2,7 +2,7 @@
 
 @if (ParentMenu?.RenderingMode == MenuRenderingMode.Table)
 {
-	@if (ParentMenu?.Orientation == Orientation.Vertical)
+	@if (ParentMenu.Orientation == Orientation.Vertical)
 	{<tr><td><a title="@Title" class="@GetItemCssClass()" style="@GetItemStyle()" href="@NavigateUrl" target="@EffectiveTarget" @onclick="HandleClick" @onclick:preventDefault="@(string.IsNullOrEmpty(NavigateUrl))">@Text</a></td></tr>}
 	else
 	{<td><a title="@Title" class="@GetItemCssClass()" style="@GetItemStyle()" href="@NavigateUrl" target="@EffectiveTarget" @onclick="HandleClick" @onclick:preventDefault="@(string.IsNullOrEmpty(NavigateUrl))">@Text</a></td>}
EOF
@@ -2,7 +2,7 @@

@if (ParentMenu?.RenderingMode == MenuRenderingMode.Table)
{
@if (ParentMenu?.Orientation == Orientation.Vertical)
@if (ParentMenu.Orientation == Orientation.Vertical)
{<tr><td><a title="@Title" class="@GetItemCssClass()" style="@GetItemStyle()" href="@NavigateUrl" target="@EffectiveTarget" @onclick="HandleClick" @onclick:preventDefault="@(string.IsNullOrEmpty(NavigateUrl))">@Text</a></td></tr>}
else
{<td><a title="@Title" class="@GetItemCssClass()" style="@GetItemStyle()" href="@NavigateUrl" target="@EffectiveTarget" @onclick="HandleClick" @onclick:preventDefault="@(string.IsNullOrEmpty(NavigateUrl))">@Text</a></td>}
Copilot is powered by AI and may make mistakes. Always verify output.
);

var menu = cut.FindComponent<Menu>().Instance;
(menu is BlazorWebFormsComponents.Interfaces.IMenuStyleContainer).ShouldBeTrue();

Check warning

Code scanning / CodeQL

Useless type test Warning test

There is no need to test whether an instance of
Menu
is also an instance of
IMenuStyleContainer
- it always is.
There is no need to test whether an instance of
Menu
is also an instance of
IMenuStyleContainer
- it always is.
There is no need to test whether an instance of Menu is also an instance of
IMenuStyleContainer
- it always is.
There is no need to test whether an instance of Menu is also an instance of
IMenuStyleContainer
- it always is.

Copilot Autofix

AI 2 months ago

In general, to fix a useless type test where a variable’s static type is already known to implement an interface, you remove the is/as check and either rely on compile-time typing or use members of the interface directly. For a unit test whose only purpose is to assert the type relationship, you can instead assert the presence or behavior of members that the interface is expected to provide.

For this specific code, menu is obtained via cut.FindComponent<Menu>().Instance, so its static type is Menu. Since Menu is always an IMenuStyleContainer, the expression (menu is BlazorWebFormsComponents.Interfaces.IMenuStyleContainer) is a redundant runtime test. The test’s intent is to ensure that Menu provides menu-style container behavior. We can keep that intent without the useless type test by asserting on a member expected from IMenuStyleContainer that we already use elsewhere in this file—namely StaticMenuStyle. A simple, non-redundant check is to assert that menu.StaticMenuStyle is not null, which demonstrates that the “menu style container” capability is present.

Concretely, in src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor, within the Menu_ImplementsIMenuStyleContainer test, replace line 176 to assert that menu.StaticMenuStyle is not null instead of asserting the is relationship. No new imports are required because ShouldBeTrue is already used elsewhere and ShouldNotBeNull is already used in the Menu_StaticMenuStyle_DefaultIsNotNull test below, so the assertion library is available.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor b/src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor
--- a/src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor
+++ b/src/BlazorWebFormsComponents.Test/Menu/MenuLevelStyles.razor
@@ -173,7 +173,7 @@
 		);
 
 		var menu = cut.FindComponent<Menu>().Instance;
-		(menu is BlazorWebFormsComponents.Interfaces.IMenuStyleContainer).ShouldBeTrue();
+		menu.StaticMenuStyle.ShouldNotBeNull();
 	}
 
 	[Fact]
EOF
@@ -173,7 +173,7 @@
);

var menu = cut.FindComponent<Menu>().Instance;
(menu is BlazorWebFormsComponents.Interfaces.IMenuStyleContainer).ShouldBeTrue();
menu.StaticMenuStyle.ShouldNotBeNull();
}

[Fact]
Copilot is powered by AI and may make mistakes. Always verify output.
private ExModel model1 = new ExModel();

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'ref2' can be 'readonly'.

Copilot Autofix

AI 2 months ago

To fix the issue, make the field ref2 a readonly field so that its reference cannot be changed after initialization. This aligns with how the field is used: it's created once and then only consumed. To keep the code consistent and avoid similar warnings for the other analogous fields, we should also mark ref1, ref3, and ref4 as readonly, as they share the same initialization and usage pattern.

Concretely, in src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, at the bottom of the @code block, update the four ForwardRef<InputBase<string>> field declarations (lines 90, 94, 98, and 102) to include the readonly modifier. No new imports or methods are required; this is purely a modifier change on existing field declarations.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -87,19 +87,19 @@
 
 	// Separate model/handler instances per test to avoid shared state
 	private bool _invalid1 = false;
-	ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
 	private ExModel model1 = new ExModel();
 
 	private bool _invalid2 = false;
-	ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
 	private ExModel model2 = new ExModel();
 
 	private bool _invalid3 = false;
-	ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
 	private ExModel model3 = new ExModel();
 
 	private bool _invalid4 = false;
-	ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
 	private ExModel model4 = new ExModel();
 
 	public class ExModel
EOF
@@ -87,19 +87,19 @@

// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private ExModel model1 = new ExModel();

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private ExModel model3 = new ExModel();

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();

public class ExModel
Copilot is powered by AI and may make mistakes. Always verify output.
// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private ExModel model1 = new ExModel();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'model1' can be 'readonly'.

Copilot Autofix

AI 2 months ago

To fix the problem, add the readonly modifier to the model1 field so it cannot be reassigned after construction/initialization, while still allowing mutation of the object it references (e.g., changing Name), which is not restricted by readonly. This aligns with the rule’s recommendation and does not change existing functionality because the tests only pass model1 into components and do not reassign it.

Concretely, in src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, at the bottom of the file where the fields are declared, update the model1 declaration on line 91 from private ExModel model1 = new ExModel(); to private readonly ExModel model1 = new ExModel();. The rest of the fields (model2, model3, model4, and the ForwardRef and _invalid flags) are not mentioned by CodeQL here, and we have no instruction to change them, so they should remain as-is. No new imports or method changes are needed; readonly is a standard C# modifier and does not require extra dependencies.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -88,7 +88,7 @@
 	// Separate model/handler instances per test to avoid shared state
 	private bool _invalid1 = false;
 	ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
-	private ExModel model1 = new ExModel();
+	private readonly ExModel model1 = new ExModel();
 
 	private bool _invalid2 = false;
 	ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
EOF
@@ -88,7 +88,7 @@
// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private ExModel model1 = new ExModel();
private readonly ExModel model1 = new ExModel();

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
Copilot is powered by AI and may make mistakes. Always verify output.

// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'ref1' can be 'readonly'.

Copilot Autofix

AI 2 months ago

In general, to fix a "Missed 'readonly' opportunity" issue, you add the readonly modifier to fields that are only assigned at declaration or within constructors of the same class. This prevents later unintended reassignment of the field reference while allowing mutation of the object the field points to.

For this file, the best fix is to mark the ForwardRef<InputBase<string>> fields (ref1, ref2, ref3, and ref4) as readonly. They are initialized once at their declarations and never reassigned in the snippet; they are simply used in the markup to refer to input components and validators. Adding readonly will not affect how Blazor uses the ForwardRef instance, since Blazor mutates the Current property of the ForwardRef object rather than reassigning the field variable.

Concretely:

  • In src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, on the four lines where ref1, ref2, ref3, and ref4 are declared, change ForwardRef<InputBase<string>> refX = ...; to private readonly ForwardRef<InputBase<string>> refX = ...;.
  • No new imports, methods, or other definitions are required; this is a pure modifier change on existing fields.
Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -87,19 +87,19 @@
 
 	// Separate model/handler instances per test to avoid shared state
 	private bool _invalid1 = false;
-	ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
 	private ExModel model1 = new ExModel();
 
 	private bool _invalid2 = false;
-	ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
 	private ExModel model2 = new ExModel();
 
 	private bool _invalid3 = false;
-	ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
 	private ExModel model3 = new ExModel();
 
 	private bool _invalid4 = false;
-	ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
 	private ExModel model4 = new ExModel();
 
 	public class ExModel
EOF
@@ -87,19 +87,19 @@

// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private ExModel model1 = new ExModel();

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private ExModel model3 = new ExModel();

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();

public class ExModel
Copilot is powered by AI and may make mistakes. Always verify output.

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'model4' can be 'readonly'.

Copilot Autofix

AI 2 months ago

In general, to fix a “Missed readonly opportunity” issue, add the readonly modifier to any field that is fully assigned either at its declaration or within a constructor in the same class and never reassigned elsewhere. This prevents unintended reassignment of the field reference while still allowing mutation of the referenced object’s internal state if it is a reference type.

For this specific case, we should add readonly to the model4 field declaration on line 103: change private ExModel model4 = new ExModel(); to private readonly ExModel model4 = new ExModel();. This preserves all existing functionality: the EditForm continues to bind to model4, and the Name property can still change via user input; only reassignment of the model4 field itself becomes disallowed. No additional imports, methods, or other definitions are required, and no other lines in this file need modification.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -100,7 +100,7 @@
 
 	private bool _invalid4 = false;
 	ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
-	private ExModel model4 = new ExModel();
+	private readonly ExModel model4 = new ExModel();
 
 	public class ExModel
 	{
EOF
@@ -100,7 +100,7 @@

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();
private readonly ExModel model4 = new ExModel();

public class ExModel
{
Copilot is powered by AI and may make mistakes. Always verify output.
private ExModel model3 = new ExModel();

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'ref4' can be 'readonly'.

Copilot Autofix

AI 2 months ago

To fix the issue, the field ref4 should be declared with the readonly modifier since it is only assigned at declaration. This prevents unintended reassignment after object initialization while preserving current behavior.

Concretely, in src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, locate the field declaration near the bottom:

ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();

and add the readonly modifier:

private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();

This aligns ref4 with the CodeQL recommendation without changing any test logic. No additional methods, imports, or definitions are needed, and no other code regions need modification based on the information provided.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -99,7 +99,7 @@
 	private ExModel model3 = new ExModel();
 
 	private bool _invalid4 = false;
-	ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
 	private ExModel model4 = new ExModel();
 
 	public class ExModel
EOF
@@ -99,7 +99,7 @@
private ExModel model3 = new ExModel();

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();

public class ExModel
Copilot is powered by AI and may make mistakes. Always verify output.

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private ExModel model3 = new ExModel();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'model3' can be 'readonly'.

Copilot Autofix

AI 2 months ago

To fix the problem in general, mark any field as readonly when it is only assigned at declaration or within constructors of the same class, and never reassigned elsewhere. This constrains the field reference to be immutable after construction while still allowing mutation of the object’s internal state.

In this specific file, the best fix without changing functionality is to add the readonly modifier to model3 (and, by the same reasoning, to the other model fields model1, model2, and model4 if they are similarly flagged). Each of these fields is initialized once with new ExModel() and then used as the model for the corresponding EditForm. Changing them to private readonly ExModel modelX = new ExModel(); does not affect the tests because the code never reassigns the fields; only the Name property is mutated through binding. No new imports or helper methods are required; only the field declarations at the bottom of the @code block need their modifiers updated.

Concretely, in src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, update the declarations on lines 91, 95, 99, and 103 so each private ExModel modelN = new ExModel(); becomes private readonly ExModel modelN = new ExModel();.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -88,19 +88,19 @@
 	// Separate model/handler instances per test to avoid shared state
 	private bool _invalid1 = false;
 	ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
-	private ExModel model1 = new ExModel();
+	private readonly ExModel model1 = new ExModel();
 
 	private bool _invalid2 = false;
 	ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
-	private ExModel model2 = new ExModel();
+	private readonly ExModel model2 = new ExModel();
 
 	private bool _invalid3 = false;
 	ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
-	private ExModel model3 = new ExModel();
+	private readonly ExModel model3 = new ExModel();
 
 	private bool _invalid4 = false;
 	ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
-	private ExModel model4 = new ExModel();
+	private readonly ExModel model4 = new ExModel();
 
 	public class ExModel
 	{
EOF
@@ -88,19 +88,19 @@
// Separate model/handler instances per test to avoid shared state
private bool _invalid1 = false;
ForwardRef<InputBase<string>> ref1 = new ForwardRef<InputBase<string>>();
private ExModel model1 = new ExModel();
private readonly ExModel model1 = new ExModel();

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private ExModel model2 = new ExModel();
private readonly ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private ExModel model3 = new ExModel();
private readonly ExModel model3 = new ExModel();

private bool _invalid4 = false;
ForwardRef<InputBase<string>> ref4 = new ForwardRef<InputBase<string>>();
private ExModel model4 = new ExModel();
private readonly ExModel model4 = new ExModel();

public class ExModel
{
Copilot is powered by AI and may make mistakes. Always verify output.
private ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'ref3' can be 'readonly'.

Copilot Autofix

AI 2 months ago

In general, to fix a "Missed 'readonly' opportunity" for a field, you add the readonly modifier to the field declaration when the field is only assigned at declaration time and/or in the class’s constructors. This ensures that the field reference cannot be changed after object initialization, while leaving the object it refers to free to mutate as normal.

For this specific case in src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor, we should update the declaration of ref3 (and only ref3, as requested) to add the readonly modifier. The original line:

ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();

should become:

private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();

This preserves the existing initialization and type, simply constraining the field so that it cannot be reassigned later. No new imports, helper methods, or other structural changes are required, and no other fields need to be modified for this particular CodeQL finding.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -95,7 +95,7 @@
 	private ExModel model2 = new ExModel();
 
 	private bool _invalid3 = false;
-	ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
+	private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
 	private ExModel model3 = new ExModel();
 
 	private bool _invalid4 = false;
EOF
@@ -95,7 +95,7 @@
private ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private readonly ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
private ExModel model3 = new ExModel();

private bool _invalid4 = false;
Copilot is powered by AI and may make mistakes. Always verify output.

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private ExModel model2 = new ExModel();

Check notice

Code scanning / CodeQL

Missed 'readonly' opportunity Note test

Field 'model2' can be 'readonly'.

Copilot Autofix

AI 2 months ago

In general, to fix a “Missed 'readonly' opportunity” for a field, you add the readonly modifier to the field declaration, provided that the field is only ever assigned at its declaration or within constructors of the same class. This prevents later unintended reassignment of the field while still allowing mutation of the object it references (if it’s a reference type).

For this specific case, the best fix is to add the readonly modifier to the model2 field declaration on line 95 of CommaSplitTests.razor, changing private ExModel model2 = new ExModel(); to private readonly ExModel model2 = new ExModel();. This does not change any existing behavior: the tests and bindings will continue to work because they mutate model2’s properties, not the field reference. No new methods or imports are required, and no other lines need to be edited.

Suggested changeset 1
src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
--- a/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
+++ b/src/BlazorWebFormsComponents.Test/Validations/ValidationSummary/CommaSplitTests.razor
@@ -92,7 +92,7 @@
 
 	private bool _invalid2 = false;
 	ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
-	private ExModel model2 = new ExModel();
+	private readonly ExModel model2 = new ExModel();
 
 	private bool _invalid3 = false;
 	ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
EOF
@@ -92,7 +92,7 @@

private bool _invalid2 = false;
ForwardRef<InputBase<string>> ref2 = new ForwardRef<InputBase<string>>();
private ExModel model2 = new ExModel();
private readonly ExModel model2 = new ExModel();

private bool _invalid3 = false;
ForwardRef<InputBase<string>> ref3 = new ForwardRef<InputBase<string>>();
Copilot is powered by AI and may make mistakes. Always verify output.
@csharpfritz csharpfritz merged commit 8885e7c into main Feb 26, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants