Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e4ba87d
feat(cli): compile page code-behind safely
csharpfritz Apr 29, 2026
a27306b
feat(cli): port NuGet asset extraction and EDMX conversion to native C#
csharpfritz May 6, 2026
6c4fc72
chore: WingtipToys Run 32 benchmark output and sample improvements
csharpfritz May 6, 2026
750dab3
feat(cli): add ServerCodeBlockTransform and TemplateFieldChildCompone…
csharpfritz May 6, 2026
a148070
chore: Run 33 benchmark report and gap analysis
csharpfritz May 6, 2026
0f674ab
chore: WingtipToys migration Run 34 — 25/25 tests passing
csharpfritz May 6, 2026
a6fa245
Fix Run 34 shim and transform gaps
csharpfritz May 6, 2026
aa8f70c
Add Run 35 gap transforms
csharpfritz May 6, 2026
d35ff5c
Fix DisplayExpressionTransform to emit idiomatic @expr for simple exp…
csharpfritz May 7, 2026
a00373f
Fix Run 37 gaps: G1 display-expr, G2 ScriptManager strip, G4 compile-…
csharpfritz May 7, 2026
24c144a
Protect BWFC data control migrations
csharpfritz May 7, 2026
851c709
Fix FormView SSR first-render and SessionShim string round-trip
csharpfritz May 7, 2026
f4a9e9c
Add WingtipToys migration benchmark Run 39
csharpfritz May 7, 2026
79a324d
Add WingtipToys migration benchmark reports Run 35-38
csharpfritz May 7, 2026
0606280
Add regression tests for FormView SSR and SessionShim round-trip
csharpfritz May 7, 2026
b9689d1
Add runtime scaffold detection for benchmark migrations
csharpfritz May 7, 2026
a8ba153
Run Wingtip benchmark 40
csharpfritz May 7, 2026
19b0fe7
chore: log Run 40 benchmark results and merge decisions
csharpfritz May 7, 2026
1bdbb1f
Fix BWFC data control template emission for ListView, FormView, GridView
csharpfritz May 7, 2026
4e211ea
chore: log template emission fix session
csharpfritz May 7, 2026
76e4916
Add CartSessionKeyTransform for stable cart persistence
csharpfritz May 7, 2026
83eed88
Add compile-surface quarantine for non-migratable pages
csharpfritz May 7, 2026
f3a3946
WingtipToys migration benchmark Run 41
csharpfritz May 7, 2026
1db2b3f
Fix quarantine allowlist, static files, and antiforgery gaps from Run 41
csharpfritz May 7, 2026
9fac3fa
docs(ai-team): Scribe memory consolidation
csharpfritz May 7, 2026
3bfe62c
WingtipToys migration benchmark Run 42 — 25/25, 22:00, 96% first-pass
csharpfritz May 8, 2026
0558fa2
Update copilot-instructions.md with CLI, migration toolkit, and migra…
csharpfritz May 8, 2026
de2ab85
Add migration benchmark progression and sample complexity ordering
csharpfritz May 8, 2026
fb08940
docs(ai-team): Merge Bishop spawn decisions and logs
csharpfritz May 8, 2026
290cea4
Fix G3 auth redirect scaffold and G4 validator type inference
csharpfritz May 8, 2026
f64e1c3
Run 43: 25/25 acceptance tests — G3+G4 validated, runtime fixes
csharpfritz May 8, 2026
7e6823e
Fix G6 route aliasing and G7 quarantine bypass
csharpfritz May 8, 2026
78678c7
feat: add FormView DataItem parameter + Content SSR fallback + Run 44…
csharpfritz May 8, 2026
bdce418
docs(ai-team): Merge bishop TemplateField fix decisions; orchestratio…
csharpfritz May 8, 2026
22a17a9
feat: WingtipToys Run 45 — 25/25 acceptance tests, TemplateField pres…
csharpfritz May 8, 2026
66498f1
fix(ci): remove WingtipToys tests from CI integration tests
csharpfritz May 8, 2026
e827d26
ci: disable CodeQL on PRs/push, keep manual dispatch only
csharpfritz May 8, 2026
caef3c2
ci: disable Squad workflows, keep manual dispatch only
csharpfritz May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/skills/wingtip-migration-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ Focus on:

- Keeping the generated project shape in `samples\AfterWingtipToys\`
- Preserving Web Forms semantics through BWFC shims where available
- **NEVER replace generated BWFC data controls (`ListView`, `FormView`, `GridView`, `DataList`, `Repeater`) with manual HTML. Fix the generated markup to work with the BWFC component instead.**
- Fixing build errors iteratively until the app runs cleanly enough for acceptance validation
- Treating the migration toolkit as the thing under test; manual fixes should be documented as toolkit gaps

Expand Down
97 changes: 96 additions & 1 deletion .squad/agents/bishop/history.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions .squad/decisions/inbox/bishop-display-expr-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Decision: DisplayExpressionTransform emits idiomatic Razor for simple expressions

**Date:** 2026-05-06
**Author:** Bishop (Migration Tooling Dev)
**Status:** Implemented

## Decision

Update `DisplayExpressionTransform` so simple dotted identifier display expressions emit bare Razor `@expr`, while complex expressions continue to emit `@(expr)`.

## Scope

- Simple expressions match identifier chains such as `Item.ProductName`, `Item.UnitPrice`, `Model.Title`, and `user.Email`.
- Complex expressions keep parentheses, including method calls, operators, ternaries, indexers, and casts.
- Broken generated `@(: expr)` output is normalized through the same formatter so simple cases become idiomatic Razor too.

## Rationale

The old transform emitted `@(expr)` for every display expression. That output compiled, but it produced noisy, non-idiomatic Razor for the most common migrated shape: property access on the current item or model.

Using bare `@expr` for simple member chains keeps generated Razor closer to what a Blazor developer would naturally write, without sacrificing correctness for complex expressions that still require grouping.

## Files Updated

- `src\BlazorWebFormsComponents.Cli\Transforms\Markup\DisplayExpressionTransform.cs`
- `tests\BlazorWebFormsComponents.Cli.Tests\TransformUnit\DisplayExpressionTransformTests.cs`
- `tests\BlazorWebFormsComponents.Cli.Tests\TestData\expected\TC06-Expressions.razor`
- `tests\BlazorWebFormsComponents.Cli.Tests\TestData\expected\TC30-DataDrivenPage.razor`

## Validation

- `dotnet test tests\BlazorWebFormsComponents.Cli.Tests --nologo --filter "DisplayExpression"`
- `dotnet test tests\BlazorWebFormsComponents.Cli.Tests --nologo`
33 changes: 33 additions & 0 deletions .squad/decisions/inbox/bishop-g1-g3-g8-g10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Bishop decisions — G1 / G3 / G8 / G10

## Context
Run 35 exposed four recurring Layer 1 gaps in migrated Wingtip output: invalid display-expression Razor, EF6 DbContext constructor emission, unsupported `Server.*` compatibility calls, and `HttpUtility` ambiguity when migrated apps still carry the legacy package.

## Decisions

1. **Normalize Web Forms display expressions before the main expression pass.**
- Added `DisplayExpressionTransform` at Order 490.
- It converts `<%#: expr %>`, `<%=: expr %>`, and broken `@(: expr)` into `@(...)` early so later markup transforms operate on valid Razor.

2. **Modernize EF6 DbContext constructors in Layer 1 instead of leaving them for manual repair.**
- Added `EfContextConstructorTransform` at Order 106.
- It rewrites `: base("name")` constructors on `DbContext` / `IdentityDbContext` types to EF Core `DbContextOptions<TContext>` constructors and ensures `using Microsoft.EntityFrameworkCore;` exists.

3. **Treat `Server.Transfer`, `Server.GetLastError`, and `Server.ClearError` as supported shim surface.**
- Extended `ServerShim` with compatibility implementations/stubs.
- Updated CLI guidance so these calls are no longer flagged as “NO SHIM” manual rewrites.

4. **Rewrite `HttpUtility` inline instead of depending on the compatibility shim.**
- Added `HttpUtilityRewriteTransform` at Order 104.
- The CLI now rewrites supported `HttpUtility` calls directly to `WebUtility`, adds `using System.Net`, and avoids relying on `System.Web.HttpUtility` in the generated app.

5. **Apply G3/G10 fixes to copied source files, not only page code-behind.**
- Updated `SourceFileCopier` to include the new transforms so `Models`, `Logic`, and similar copied files receive the same modernization pass.

6. **Guard generated projects against the legacy HttpUtility package.**
- Added an explicit `System.Web.HttpUtility` package-strip guard in `ProjectScaffolder` and a regression assertion in scaffolding tests.

## Validation
- `dotnet build src\BlazorWebFormsComponents\BlazorWebFormsComponents.csproj --nologo`
- `dotnet test src\BlazorWebFormsComponents.Test --nologo`
- `dotnet test tests\BlazorWebFormsComponents.Cli.Tests --nologo`
100 changes: 100 additions & 0 deletions .squad/decisions/inbox/bishop-g1g2g4-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Decision: Run 37 gap fixes G1 / G2 / G4 for the CLI pipeline

**Date:** 2026-05-06
**Author:** Bishop (Migration Tooling Dev)
**Status:** Implemented & Tested

---

## Context

WingtipToys Run 37 still exposed three deterministic CLI gaps:

- **G1** — `DisplayExpressionTransform` intentionally skipped `String.Format(...)`, leaving raw `<%#:` blocks in generated Razor.
- **G2** — master-page output still carried Web Forms-only script infrastructure (`ScriptManager`, `webopt:bundlereference`, `Scripts.Render(...)`) that has no Blazor equivalent.
- **G4** — large Account/Admin/infrastructure-heavy routable pages still blocked generated-app builds because their code-behind referenced ASP.NET Identity, OWIN, OpenAuth, or external payment APIs.

---

## Decision 1 — G1 display-expression coverage

`DisplayExpressionTransform` now excludes only `Bind(...)` and `Eval(...)` in its negative lookahead.

### Why
`Bind` and `Eval` still need specialized downstream handling, but `String.Format(...)` is just a normal complex expression. Letting it flow through the display-expression transform yields valid Razor `@(String.Format(...))` and prevents raw Web Forms syntax from leaking into `.razor` output.

### Coverage
Focused tests now verify both simple and nested `String.Format(...)` cases, while ensuring `Bind(...)` and `Eval(...)` remain untouched.

---

## Decision 2 — G2 ScriptManager strip pass (Order 255)

Added `ScriptManagerStripTransform` immediately after `MasterPageTransform`.

### What it removes
- `<asp:ScriptManager ...>...</asp:ScriptManager>` blocks
- `<webopt:bundlereference ... />`
- `<asp:PlaceHolder runat="server">` blocks whose only content is `Scripts.Render(...)`

### What it leaves behind
The first stripped ScriptManager block is replaced with:

```razor
@* Framework scripts are managed by Blazor — no ScriptManager needed. *@
```

Blank-line cleanup then collapses any `\n\n\n+` sequences back to a single empty line.

### Why
This infrastructure belongs to the old Web Forms request/update pipeline. Leaving it in generated master pages creates invalid output and distracts Layer 2 work with shell-level noise that should have been removed deterministically.

---

## Decision 3 — G4 compile-surface page stubs (Order 850)

Added `CompileSurfaceStubTransform` plus planner/pipeline support for dual output.

### Detection heuristic
A page is stubbed when it is **not** `Login.aspx` or `Register.aspx` and either:
- lives under `Account\` or `Admin\`, or
- still references ASP.NET Identity, OWIN, `OpenAuthProviders`, or payment-service namespaces such as PayPal/Stripe.

### Output contract
For detected pages:
- markup becomes a visible stub page with the original route and an "under migration" message
- compile-surface code-behind becomes a minimal `ComponentBase` partial class
- the transformed pre-stub code-behind is preserved under `migration-artifacts\codebehind\...`
- the pipeline records a `bwfc-compile-surface` manual item so downstream tooling knows this page was intentionally parked behind a safe stub

### Why dual output matters
A pure quarantine keeps the build clean but removes the route entirely. A pure stub keeps the route but loses the migration context. Emitting both gives us a build-safe app **and** a preserved artifact that Layer 2 can revisit later.

---

## Registration / docs impact

Updated both production and test registrations:
- `src\BlazorWebFormsComponents.Cli\Program.cs`
- `tests\BlazorWebFormsComponents.Cli.Tests\TestHelpers.cs`

Updated CLI docs:
- `docs\cli\index.md`
- `docs\cli\transforms.md`

---

## Validation

Ran the full CLI suite after each fix:

1. Baseline — `573` passing
2. After G1 — `577` passing
3. After G2 — `582` passing
4. After G4/final docs/tests — `588` passing

Command used each time:

```powershell
dotnet test tests\BlazorWebFormsComponents.Cli.Tests --no-restore --nologo
```
71 changes: 71 additions & 0 deletions .squad/decisions/inbox/bishop-run39-gaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Bishop Run 39 Gap Analysis

## Priority summary

### P0 — Must fix to keep the benchmark green

1. **Acceptance-path runtime wiring**
- **Category:** Runtime wiring
- **Gap:** Fresh output still needed manual catalog, cart, and auth runtime setup before the benchmark path worked end-to-end.
- **Concrete fix:** Add a Wingtip benchmark scaffold mode in the CLI that emits the lightweight runtime used in successful runs: benchmark-safe catalog data service, cart persistence wiring, session-enabled request pipeline, and simple auth pages/services.
- **Estimated impact:** Saves 5-8 minutes per run and removes the biggest remaining manual repair bucket.

2. **Compile-surface debt outside the benchmark path**
- **Category:** Compile surface
- **Gap:** Fresh output still depended on prior compile-surface reduction strategy so non-benchmark pages would not block build/test validation.
- **Concrete fix:** Expand CLI quarantine/stub coverage for heavy Account/Admin/Checkout/payment pages and automatically exclude or park unsupported artifacts behind safe routable stubs plus migration-artifact preservation.
- **Estimated impact:** Saves 3-5 minutes per run and prevents build-blocking regressions.

### P1 — Significant time savings

3. **FormView SSR first-render behavior**
- **Category:** Library fix
- **Gap:** `FormView` did not establish `CurrentItem` until after first render, so SSR details pages arrived blank on first request.
- **Concrete fix:** Keep the current library fix and add focused regression coverage proving `CurrentItem` is available during parameter processing/first SSR render.
- **Estimated impact:** Saves 3-4 minutes of debugging and prevents benchmark-path false negatives.

4. **Session raw-string round-trip**
- **Category:** Library fix
- **Gap:** Page-side cart/session lookups could miss persisted raw string values because `SessionShim` assumed JSON payloads on readback.
- **Concrete fix:** Keep the current shim fallback for raw strings and add regression tests for mixed JSON/object and raw-string session storage across requests.
- **Estimated impact:** Saves 2-3 minutes and prevents cart/auth state mismatches.

### P2 — Quality improvements with smaller time wins

5. **Generate request-safe session access patterns**
- **Category:** CLI transform
- **Gap:** Benchmark pages still needed manual repair to read/write cart IDs directly against `Context.Session` on request-bound paths.
- **Concrete fix:** Add a transform or scaffold helper that rewrites obvious session-cookie/cart-ID patterns to request-safe APIs when migrating action/cart pages.
- **Estimated impact:** Saves 1-2 minutes and reduces fragile manual edits.

6. **Port/process safety during iterative validation**
- **Category:** Runtime wiring
- **Gap:** Rebuilds while the app was still live caused transient `MSB3027/MSB3021` output-lock failures.
- **Concrete fix:** Have the migration test workflow or helper script detect/stop the prior app PID before rebuild/run phases.
- **Estimated impact:** Saves about 1 minute and reduces noisy false failures.

### P3 — Nice to have

7. **Benchmark-path diagnostics in reports/tooling**
- **Category:** Runtime wiring
- **Gap:** Blank SSR details pages and session mismatches were diagnosable, but only after manual inspection.
- **Concrete fix:** Add a lightweight smoke check after migration/build for key pages (`/ProductList`, `/ProductDetails?id=...`, `/ShoppingCart`) to flag blank-body SSR or missing cart persistence before full Playwright runs.
- **Estimated impact:** Saves less than 1 minute on average, but improves operator feedback.

## Run 38 → Run 39 progress

### Fixed since Run 38

- **Acceptance-path data controls are no longer being replaced by manual HTML.** Run 39 preserved `ListView`, `FormView`, and `GridView` on the benchmark path.
- **Run 38 `FormView/query-details` gap is materially improved.** The details page no longer needs manual control replacement; the remaining issue was a library SSR timing bug, now fixed in `FormView`.
- **The cart path is closer to framework-correct behavior.** Run 39 isolated the remaining failure to session-string round-trip and repaired it in `SessionShim`.

### Still persisting from Run 38

- **Runtime scaffold gap persists.** Fresh output still needs manual catalog/cart/auth setup to satisfy the benchmark suite.
- **Compile-surface exclusion/quarantine gap persists.** Non-benchmark pages still need automated pruning/stubbing so they do not block build validation.
- **Checkout/payment and heavy account/admin surfaces remain outside automatic coverage.** They are still part of the compile-surface debt even if the benchmark path can be made green.

## Net assessment

Run 39 shows clear progress: the benchmark path now keeps BWFC data controls intact and the two regressions were true library bugs, not proof that the controls must be flattened. The next highest-value work is no longer control preservation; it is automating the benchmark runtime scaffold and hardening compile-surface quarantine so fresh runs reach green with minimal manual repair.
61 changes: 61 additions & 0 deletions .squad/decisions/inbox/bishop-shims-and-transform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Decision: Run 34 shim compatibility and attribute data-binding transform

**Date:** 2026-05-06
**Author:** Bishop (Migration Tooling Dev)
**Status:** Proposed

## Context

Run 34 exposed four deterministic migration gaps that should be fixed in tooling rather than left for Layer 2 manual cleanup:

1. BWFC components accepted `Width="500"` but not CSS-style string literals such as `Width="500px"` or `Width="50%"` in migrated Razor.
2. Migrated code frequently used `Request.QueryString.Get("key")`, but `RequestShim.QueryString` surfaced `IQueryCollection`, which only supported indexer access.
3. Migrated code also referenced `System.Web.HttpUtility`, which modern .NET apps do not expose by default.
4. The CLI handled `<%# ... %>` expressions in content, but not when those expressions appeared inside attribute values.

## Decision

### 1. Width and Height parameters on `BaseStyledComponent`

Use **string-backed component parameters** for `Width` and `Height`, while preserving the internal `IStyle`/`IHasLayoutStyle` contract as `Unit` via explicit interface implementation.

- Public component parameters accept plain strings such as `"500"`, `"500px"`, and `"50%"`.
- Existing quoted legacy syntax such as `Width="Unit.Pixel(200)"` is preserved by parsing `Unit.Pixel(...)`, `Unit.Point(...)`, and `Unit.Percentage(...)` string forms.
- Internal style generation, theme skin application, and style-copy logic still operate on `Unit` values.

### 2. Query string `.Get()` compatibility

Add `BlazorWebFormsComponents.QueryStringExtensions.Get(string)` as a global BWFC extension for `IQueryCollection`.

- This keeps migrated `Request.QueryString.Get("key")` code compiling unchanged.
- Returning `queryString[key]?.ToString()` matches Web Forms expectations closely enough for migration compatibility.

### 3. `System.Web.HttpUtility` compatibility shim

Add a static `System.Web.HttpUtility` type to the BWFC library backed by `System.Net.WebUtility`.

- `UrlEncode` / `UrlDecode` delegate to `WebUtility.UrlEncode` / `WebUtility.UrlDecode`.
- `HtmlEncode` / `HtmlDecode` delegate to `WebUtility.HtmlEncode` / `WebUtility.HtmlDecode`.
- This provides the Web Forms API surface without requiring migrated apps to rewrite these calls immediately.

### 4. Attribute data-binding transform

Add `DataBindingAttributeTransform` with **Order 615**, registered immediately after `AspPrefixTransform` in both the CLI runtime and test pipeline.

- It rewrites attribute values containing `<%# ... %>` or `<%= ... %>` into Razor `@(...)` expressions.
- It preserves surrounding attributes and switches quote styles when needed so embedded C# string literals remain valid Razor.
- This closes the gap for controls like `<HyperLink NavigateUrl='<%# Item.GetUrl() %>' />`.

## Rationale

These four fixes are all deterministic compile-surface issues. Leaving them to Layer 2 wastes manual time and creates noisy false negatives in benchmark runs, while the tooling can resolve them mechanically and safely.

Using string-backed `Width`/`Height` parameters is the least disruptive way to unlock plain migrated Razor markup while preserving the typed `Unit` behavior internally where BWFC styling already depends on it. The shim additions follow the existing project direction of zero-rewrite compile-compatibility for common Web Forms APIs.

## Validation

- `dotnet build src\BlazorWebFormsComponents\BlazorWebFormsComponents.csproj --nologo`
- `dotnet test src\BlazorWebFormsComponents.Test --nologo`
- `dotnet test tests\BlazorWebFormsComponents.Cli.Tests --nologo`

All commands succeeded after the changes.
33 changes: 33 additions & 0 deletions .squad/skills/cli-compile-surface-hardening/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: "cli-compile-surface-hardening"
description: "Keep migrated Blazor output compiling when more Web Forms artifacts stay on the generated compile surface"
domain: "migration-tooling"
confidence: "high"
source: "earned"
---

## Context
Use this when the migration CLI starts emitting more generated `.razor.cs` files or copying more legacy source into the output project. The goal is to preserve deterministic L1 behavior while preventing compile failures from style analyzers, generic Razor component inference, or unresolved markup references.

## Patterns
- In generated migration projects, prefer `<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>` over broad warning suppression when copied legacy files would otherwise fail repo-level IDE analyzers.
- Add validator generic arguments with the BWFC component's actual generic parameter name, not an assumed `TValue` alias:
- `RequiredFieldValidator` → `Type="string"`
- `CompareValidator` / `RangeValidator` → `InputType="string"`
- Run markup-driven member stub generation after the main code-behind transforms, using transformed Razor markup (`metadata.MarkupContent`) as the source of truth.
- Stub only the deterministic missing-member shapes that are safe to infer mechanically:
- `@MethodName()` → render-method stub returning `object?`
- `@_fieldName` → private `object?` field
- `OnClick="@HandlerName"` and similar → `void HandlerName(object? sender, EventArgs e)`
- Register new transforms in both production DI (`src\BlazorWebFormsComponents.Cli\Program.cs`) and `tests\BlazorWebFormsComponents.Cli.Tests\TestHelpers.cs` so the lightweight and full pipelines stay aligned.

## Examples
- `src\BlazorWebFormsComponents.Cli\Transforms\Markup\ValidatorGenericTypeTransform.cs`
- `src\BlazorWebFormsComponents.Cli\Transforms\CodeBehind\MarkupReferencedMemberStubTransform.cs`
- `tests\BlazorWebFormsComponents.Cli.Tests\TransformUnit\CompiledCodeBehindStubPipelineTests.cs`

## Anti-Patterns
- Suppressing all warnings/errors in the generated project when only code-style analyzers are the problem.
- Injecting `TValue="string"` into BWFC validators that actually expose `Type` or `InputType` generic parameters.
- Generating markup-reference stubs before markup transforms run, or reading original Web Forms markup instead of the transformed Razor output.
- Emitting placeholder stubs for every `@Identifier` token; restrict deterministic generation to the specific reference shapes you can classify safely.
Loading
Loading