Skip to content

Commit f64e1c3

Browse files
csharpfritzCopilot
andcommitted
Run 43: 25/25 acceptance tests — G3+G4 validated, runtime fixes
- G3: Auth redirect scaffold with POST-based LoginHandler/RegisterHandler - G4: RequiredFieldValidator type inference (TextBox→string) - Build repair: 86→0 errors in 2 rounds - Runtime fixes: SQL Server→SQLite, seed data, route aliasing, cart page - New gaps identified: G5 (db provider), G6 (route aliasing), G7 (redirect page quarantine) - 6 screenshots captured, full report at dev-docs/migration-tests/wingtiptoys/run43/ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 290cea4 commit f64e1c3

48 files changed

Lines changed: 2213 additions & 732 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
70.8 KB
Loading
75.3 KB
Loading
71.5 KB
Loading
55.3 KB
Loading
58.1 KB
Loading
55.8 KB
Loading
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# WingtipToys Migration Benchmark — Run 43
2+
3+
## Run Metadata
4+
5+
| Field | Value |
6+
|-------|-------|
7+
| **Date** | 2026-05-08 |
8+
| **Branch** | `feature/wingtip-next-features-review` |
9+
| **Operator** | Coordinator (with repair-43 agent) |
10+
| **Total Wall-Clock Time** | **~35:00** |
11+
| **Prior Run** | Run 42 — 22:00 (25/25) |
12+
| **Improvement** | Regression — runtime repair dominated (see analysis) |
13+
14+
## Paths
15+
16+
| Item | Path |
17+
|------|------|
18+
| Web Forms source | `samples/WingtipToys/` |
19+
| Blazor output | `samples/AfterWingtipToys/` |
20+
| Toolkit entry point | `migration-toolkit/scripts/bwfc-migrate.ps1` |
21+
| Acceptance tests | `src/WingtipToys.AcceptanceTests/` |
22+
23+
## Summary
24+
25+
Run 43 validates G3 (auth post-login redirect) and G4 (RequiredFieldValidator generic type inference) fixes from Bishop. The migration toolkit produced 203 files (188 written) with 0 L1 errors. Build repair brought 86 errors to 0 in 2 rounds. However, **runtime issues dominated repair time** — SQL Server LocalDB connection strings required manual SQLite conversion, seed data setup, route mismatches, and shopping cart page code-behind reconstruction.
26+
27+
### Key Fixes Validated
28+
29+
1. **G3 — Auth redirect scaffold**: POST-based `/Account/LoginHandler` and `/Account/RegisterHandler` endpoints emitted by ProgramCsEmitter
30+
2. **G4 — Validator type inference**: `RequiredFieldValidator<string>` correctly inferred from TextBox controls (though `@ref` variable types still needed repair-agent fixup)
31+
32+
## Results
33+
34+
| Metric | Value |
35+
|--------|-------|
36+
| **Acceptance Tests** | **25/25 ✅** |
37+
| **First-Pass Rate** | 17/25 (68%) |
38+
| **Build: Initial Errors** | 86 |
39+
| **Build: After Repair** | 0 (2 rounds) |
40+
| **Runtime Repair Rounds** | 4 (SQL→SQLite, seed data, routes, cart) |
41+
| **CLI Tests** | 618/618 ✅ |
42+
43+
### First-Pass Failures (8 tests)
44+
45+
| Test | Root Cause | Fix Applied |
46+
|------|-----------|-------------|
47+
| `RegisterPage_HasExpectedFormFields` | Route at `/Register`, test navigates to `/Account/Register` | Added `@page "/Account/Register"` |
48+
| `LoginPage_HasExpectedFormFields` | Route at `/Login`, test navigates to `/Account/Login` | Added `@page "/Account/Login"` |
49+
| `RegisterAndLogin_EndToEnd` | Same route issue | Same fix |
50+
| `ProductList_DisplaysProducts` | Links used `GetRouteUrl()` which doesn't work in Blazor | Replaced with `/ProductDetails/@Item.ProductID` |
51+
| `AddItemToCart_AppearsInCart` | ProductDetails missing route param + AddToCart link | Added `{ProductId:int}` param, "Add To Cart" link |
52+
| `UpdateCartQuantity_ChangesItemCount` | AddToCart code-behind quarantined | Rebuilt AddToCart.razor with inline code |
53+
| `RemoveItemFromCart_EmptiesCart` | Same cart dependency chain | Same fix |
54+
| (1 more cart-related) | ShoppingCart page depended on working AddToCart | Fixed by cart page chain |
55+
56+
## Phase Timing
57+
58+
| Phase | Duration | Notes |
59+
|-------|----------|-------|
60+
| Phase 0: Preparation | ~1:00 | Clear output, kill lingering dotnet process, create report folder |
61+
| Phase 1: L1 Toolkit Run | ~2:00 | `bwfc-migrate.ps1` — 203 files, 32 processed, 80 static, 0 errors |
62+
| Phase 2: Build Repair | ~8:00 | 86 → 0 errors in 2 repair rounds (repair-43 agent) |
63+
| Phase 3: Runtime Fix — SQL→SQLite | ~5:00 | csproj package swap, connection strings, DbContext fallbacks |
64+
| Phase 4: Runtime Fix — Seed Data | ~3:00 | EnsureCreated + 5 categories + 16 products |
65+
| Phase 5: Runtime Fix — Routes & Cart | ~8:00 | Auth routes, ProductList links, ProductDetails param, AddToCart code-behind |
66+
| Phase 6: Screenshots | ~2:00 | 6 screenshots captured |
67+
| Phase 7: Report | ~3:00 | This document |
68+
69+
## What Worked Well
70+
71+
### CLI Migration Quality
72+
- **0 L1 errors** — the toolkit produced clean output
73+
- **203 files emitted** including 80 static assets (images, CSS)
74+
- G3 auth scaffold emitted proper login/register forms with POST endpoints
75+
- G4 validator inference worked for TextBox→string mapping
76+
77+
### Build Repair Efficiency
78+
- Only 2 rounds to go from 86 → 0 errors
79+
- Repair agent handled nullable warnings, namespace fixes, type mismatches systematically
80+
81+
## What Needs Improvement
82+
83+
### G5 — Database Provider Selection (NEW)
84+
**Severity: High** — The CLI always emits SQL Server connection strings from the original `Web.config`. For portable benchmark runs (and many real migrations), SQLite is needed. The scaffold should:
85+
1. Detect connection strings in `Web.config`
86+
2. Offer a `--database-provider` flag (default: `sqlite`)
87+
3. Emit appropriate NuGet package, connection string, and `Use*()` call
88+
89+
### G6 — Route Aliasing (NEW)
90+
**Severity: Medium** — Account pages scaffold at `/Login` but Web Forms convention is `/Account/Login`. The CLI should emit both `@page` directives for account/admin pages to preserve compatibility.
91+
92+
### G7 — AddToCart Code-Behind Quarantine (NEW)
93+
**Severity: Medium** — The AddToCart page is a "redirect-only" page (no UI, just processes query string and redirects). These should NOT be quarantined — they're simple action pages that compile cleanly. Need a heuristic: if code-behind only reads Request, calls a service method, and redirects, keep it.
94+
95+
### G8 — Seed Data Generation (NEW)
96+
**Severity: Low** — For benchmark portability, the CLI could detect `Configuration.cs` (EF Migrations seed) and emit `EnsureCreated()` + seed data in `Program.cs`. Not critical for production migrations.
97+
98+
## Screenshots
99+
100+
| Page | Screenshot |
101+
|------|-----------|
102+
| Home | ![Home](images/01-home.png) |
103+
| Product List | ![Products](images/02-productlist.png) |
104+
| Product Details | ![Details](images/03-productdetails.png) |
105+
| Login | ![Login](images/04-login.png) |
106+
| Register | ![Register](images/05-register.png) |
107+
| About | ![About](images/06-about.png) |
108+
109+
## Trend
110+
111+
| Run | Date | Tests | Time | Notes |
112+
|-----|------|-------|------|-------|
113+
| 37 | 2026-05-04 | 25/25 | 18:39 | Baseline with G1/G2/G4 dispatch |
114+
| 38 | 2026-05-05 | 25/25 | 24:08 | BWFC component preservation |
115+
| 39 | 2026-05-05 | 25/25 | 22:45 | BWFC component directive fix |
116+
| 40 | 2026-05-06 | 25/25 | 19:47 | Template emission fix |
117+
| 41 | 2026-05-06 | 25/25 | 47:54 | Quarantine regression |
118+
| 42 | 2026-05-07 | 25/25 | 22:00 | Quarantine allowlist fix |
119+
| **43** | **2026-05-08** | **25/25** | **~35:00** | **G3+G4 validated, runtime repair heavy** |
120+
121+
## Next Steps
122+
123+
1. **Fix G5 (database provider)** — Add `--database-provider sqlite` flag to CLI, emit SQLite package/config
124+
2. **Fix G6 (route aliasing)** — Emit dual `@page` directives for Account/* pages
125+
3. **Fix G7 (redirect page quarantine)** — Don't quarantine simple redirect-only pages
126+
4. **Run 44** — Target: sub-20 minutes with G5+G6+G7 fixes
Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,62 @@
11
@page "/Account/Login"
2+
@page "/Login"
23
<PageTitle>Log in</PageTitle>
34
<Site>
45
<ChildComponents>
56
<Content ContentPlaceHolderID="MainContent">
6-
<h1>Login</h1>
7-
@if (Registered.GetValueOrDefault() != 0)
8-
{
9-
<p class="text-success">Registration succeeded. Please log in.</p>
10-
}
11-
@if (!string.IsNullOrWhiteSpace(Error))
12-
{
13-
<p class="text-danger">@Error</p>
14-
}
15-
<form method="post" action="/Account/LoginHandler" class="form-horizontal" @formname="login-form">
16-
<AntiforgeryToken />
17-
@if (!string.IsNullOrWhiteSpace(ReturnUrl))
18-
{
19-
<input type="hidden" name="ReturnUrl" value="@ReturnUrl" />
20-
}
21-
<div class="form-group">
22-
<label class="col-md-2 control-label" for="email">Email</label>
23-
<div class="col-md-10">
24-
<input id="email" name="Email" type="email" class="form-control" />
25-
</div>
7+
<h1>Login</h1>
8+
@* TODO(bwfc-identity): Wire this account page to ASP.NET Core Identity or your app's authentication service. *@
9+
@* TODO(bwfc-identity): Recreate validation and submit handling with EditForm, minimal APIs, or an equivalent SSR-safe endpoint. *@
10+
@if (Registered.GetValueOrDefault() != 0)
11+
{
12+
<p class="text-success">Registration succeeded. Please log in.</p>
13+
}
14+
@if (!string.IsNullOrWhiteSpace(Error))
15+
{
16+
<p class="text-danger">@Error</p>
17+
}
18+
<form method="post" action="/Account/LoginHandler" class="form-horizontal" @formname="bwfc-form-1">
19+
<AntiforgeryToken />
20+
@if (!string.IsNullOrWhiteSpace(ReturnUrl))
21+
{
22+
<input type="hidden" name="ReturnUrl" value="@ReturnUrl" />
23+
}
24+
<div class="form-group">
25+
<label class="col-md-2 control-label" for="email">Email</label>
26+
<div class="col-md-10">
27+
<input id="email" name="Email" type="email" class="form-control" />
28+
</div>
29+
</div>
30+
<div class="form-group">
31+
<label class="col-md-2 control-label" for="password">Password</label>
32+
<div class="col-md-10">
33+
<input id="password" name="Password" type="password" class="form-control" />
34+
</div>
35+
</div>
36+
<div class="form-group">
37+
<div class="col-md-offset-2 col-md-10">
38+
<div class="checkbox">
39+
<input id="remember-me" name="RememberMe" type="checkbox" />
40+
<label for="remember-me">Remember me?</label>
2641
</div>
27-
<div class="form-group">
28-
<label class="col-md-2 control-label" for="password">Password</label>
29-
<div class="col-md-10">
30-
<input id="password" name="Password" type="password" class="form-control" />
31-
</div>
32-
</div>
33-
<div class="form-group">
34-
<div class="col-md-offset-2 col-md-10">
35-
<button type="submit" class="btn btn-default">Log in</button>
36-
</div>
37-
</div>
38-
</form>
39-
<p><a href="/Account/Register">Register as a new user</a></p>
40-
</Content>
42+
</div>
43+
</div>
44+
<div class="form-group">
45+
<div class="col-md-offset-2 col-md-10">
46+
<button type="submit" class="btn btn-default">Log in</button>
47+
</div>
48+
</div>
49+
</form>
50+
<p><a href="/Account/Register">Register as a new user</a></p>
51+
<p><a href="#">Forgot your password?</a></p>
52+
</Content>
4153
</ChildComponents>
4254
</Site>
4355

4456
@code {
45-
[Parameter, SupplyParameterFromQuery(Name = "error")]
46-
public string? Error { get; set; }
57+
[Parameter, SupplyParameterFromQuery(Name = "error")] public string? Error { get; set; }
4758

48-
[Parameter, SupplyParameterFromQuery(Name = "registered")]
49-
public int? Registered { get; set; }
59+
[Parameter, SupplyParameterFromQuery(Name = "registered")] public int? Registered { get; set; }
5060

51-
[Parameter, SupplyParameterFromQuery(Name = "returnUrl")]
52-
public string? ReturnUrl { get; set; }
53-
}
61+
[Parameter, SupplyParameterFromQuery(Name = "returnUrl")] public string? ReturnUrl { get; set; }
62+
}
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
<div id="socialLoginList">
2-
<p>External login providers are not configured for this benchmark run.</p>
2+
<h4>Use another service to log in.</h4>
3+
<hr />
4+
<ListView id="providerDetails" @ref="providerDetails" ItemType="String"
5+
SelectMethod="GetProviderNames">
6+
<ItemTemplate Context="Item">
7+
<p>
8+
<button type="submit" class="btn btn-default" name="provider" value="@Item"
9+
title="Log in using your @Item account.">
10+
@Item
11+
</button>
12+
</p>
13+
</ItemTemplate>
14+
<EmptyDataTemplate>
15+
<div>
16+
<p>There are no external authentication services configured. See <a href="http://go.microsoft.com/fwlink/?LinkId=252803">this article</a> for details on setting up this ASP.NET application to support logging in via external services.</p>
17+
</div>
18+
</EmptyDataTemplate>
19+
</ListView>
320
</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using BlazorWebFormsComponents;
2+
3+
namespace WingtipToys.Account;
4+
5+
public partial class OpenAuthProviders
6+
{
7+
private ListView<string> providerDetails = default!;
8+
9+
private IQueryable<string> GetProviderNames(int maxRows, int startRowIndex, string sortByExpression, out int totalRowCount)
10+
{
11+
totalRowCount = 0;
12+
return Array.Empty<string>().AsQueryable();
13+
}
14+
}

0 commit comments

Comments
 (0)