diff --git a/.squad/agents/boromir/history.md b/.squad/agents/boromir/history.md index dc6eb056..88051d78 100644 --- a/.squad/agents/boromir/history.md +++ b/.squad/agents/boromir/history.md @@ -48,6 +48,61 @@ ## Learnings +### 2026-05-19 — Issue #348: Resolve Remaining Database Runtime Issues (post-PR #346 investigation) + +**Context:** Issue #348 was opened because MongoDB container crashes were still visible after PR #346 (which pinned `mongo:7` + `mongo-data-v7`). Assigned to Boromir + Sam + Gimli. + +**Root cause identified via `ps aux` + `docker ps -a`:** The running Aspire AppHost process was +`/home/mpaulosky/github/MyBlog/src/AppHost/bin/Debug/net10.0/AppHost.dll` — built from the +**MAIN REPO**, not the worktree. The main repo's local `dev` branch was 2 commits behind +`origin/dev`, missing both PR #346 (image/volume fix) and PR #347 (docs). As a result, Aspire +was still launching `mongo:8.2` against the old `mongo-data` volume → exit 139 (SIGSEGV, AVX). + +**How to identify which AppHost DLL is active:** + +```bash +ps aux | grep AppHost.dll +# DLL path reveals the repo root; compare to git log in that repo to confirm branch/commit +``` + +**Volume state at investigation time:** + +- `mongo-data` — FCV-contaminated (written by mongo:8.2; UUID-format collection files). MongoDB 7 refuses it with exit 62. +- `mongo-data-v7` — clean, numeric-ident format (WiredTiger 11.x, mongo:7-compatible), lock file 0 bytes. Safe to use. + +**Remediation steps performed:** + +1. `git pull origin dev` on main repo — fast-forwarded to `883137f`, pulling both PR #346 + #347. +2. `dotnet restore` + `dotnet build src/AppHost/AppHost.csproj -c Debug` — rebuilt with correct `mongo:7` + `mongo-data-v7` config. **0 errors.** +3. Next Aspire session will start MongoDB with the correct image and volume. + +**Worktree code review:** `src/AppHost/AppHost.cs` in the worktree was already correct. +`Web/Program.cs`, `BlogDbContext.cs`, and all repository code confirmed correct. No +application-layer changes needed. + +**All tests confirmed passing:** + +- `MongoDbContainerConfigurationTests` — 4/4 (image tag + volume regression coverage) +- `Web.Tests.Integration` (Testcontainers) — 29/29 + +**Key lesson — developer environment sync:** When a squad member opens a new Aspire session, +verify the running process DLL matches the current worktree. Use `ps aux | grep AppHost` to +identify which build is active. If the main repo's `dev` branch is behind `origin/dev`, pull +before starting. Stale local branches silently run old infra code. + +**Standing rule added to MongoDB DBA skill:** Added "Running environment sync check" rule — +document the `ps aux` diagnostic and the importance of syncing the main repo dev branch after +merged PRs. + +**Changed files:** + +- `.squad/agents/boromir/history.md` — this entry +- `.squad/skills/mongodb-dba-patterns/SKILL.md` — running environment sync rule added + +**Note:** Architectural decision captured separately for Scribe merge into `.squad/decisions.md`. + +--- + ### 2026-05-19 — Issue #345: Fix AppHost MongoDB Container Crash (exit code 139 + exit code 62) **Finding (pass 1):** MongoDB 8.x (the `Aspire.Hosting.MongoDB` 13.3.3 default image `mongo:8.2`) requires AVX CPU instructions on x86-64 hosts. Virtualized environments that do not expose AVX cause MongoDB 8.x to SIGSEGV immediately → container exit code 139, OOMKilled=false, ~30 s after start. Fix: pin to `mongo:7` via `.WithImageTag("7")`. diff --git a/.squad/agents/gimli/history.md b/.squad/agents/gimli/history.md index 7b21e40d..04338212 100644 --- a/.squad/agents/gimli/history.md +++ b/.squad/agents/gimli/history.md @@ -1286,3 +1286,21 @@ code. Prefer configuration-focused tests that guard the intended MongoDB image/t 3. When downgrading a local MongoDB container image, volume names matter too: reusing a volume created by MongoDB 8.2 can preserve FCV metadata that makes MongoDB 7 fail at startup. Guard the named volume in AppHost tests, not just the container image tag. + +## Session: Issue #348 — MongoDB Runtime Connectivity Regression Coverage (2026-05-17) + +### Task + +Inspect current AppHost/Web database startup and runtime connectivity coverage for issue #348, then add the smallest behavior-first regression test that proves the running web app can still read MongoDB through the AppHost-wired path. + +### Work Done + +- Reviewed `tests/AppHost.Tests/`, `tests/Web.Tests.Integration/`, `src/AppHost/AppHost.cs`, `src/Web/Program.cs`, and MongoDB data-layer files. +- Confirmed the existing coverage split: AppHost tests verify Mongo container wiring and operator commands, while Web integration tests verify repositories directly against Testcontainers. +- Added `SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page` to `tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs`. +- Validated targeted database suites with `CI=true dotnet test` to skip the Tailwind build gate during test execution. + +### Learnings + +1. The pre-existing gap was runtime read coverage: no test exercised `/blog` against the real Aspire/AppHost MongoDB connection, so wiring regressions could slip past command-level and repository-level tests. +2. A seed-command-plus-page-read test is the smallest useful tracer bullet here because it proves the full public path: AppHost Mongo wiring -> Web DI -> repository/handler -> rendered page. diff --git a/.squad/agents/sam/history.md b/.squad/agents/sam/history.md index 43d55268..09e12c9f 100644 --- a/.squad/agents/sam/history.md +++ b/.squad/agents/sam/history.md @@ -1,5 +1,58 @@ # Sam's Work History +## 2026-05-19 — Issue #348: Resolve Remaining Database Runtime Issues (branch squad/348-resolve-database-runtime-issues) + +### Task + +Re-investigate remaining database runtime issues after PR #346 (MongoDB 7 pin + fresh volume) and PR #347 (docs). Determine whether any Sam-owned backend defect remains. + +### Finding + +**No remaining backend defect found.** All Sam-owned code is correct. + +Thorough audit performed: + +| Check | Result | +| --- | --- | +| `AddMongoDBClient("myblog")` → `AddDbContextFactory` wiring | ✅ Correct | +| `MongoDbBlogPostRepository` — all CRUD methods use short-lived IDbContextFactory contexts | ✅ Correct | +| `MongoDbCategoryRepository` — all CRUD methods use short-lived IDbContextFactory contexts | ✅ Correct | +| `BlogDbContext.OnModelCreating` — blogposts, categories, owned Author, CategoryId element name | ✅ Correct | +| AppHost.cs — MongoDB 7 tag, mongo-data-v7 volume, `.WaitFor(mongo)` before web | ✅ Correct | +| Unit tests (Web.Tests) — 210/210 passed | ✅ | +| Architecture tests — 16/16 passed | ✅ | +| Integration tests (Web.Tests.Integration) — 29/29 passed | ✅ | +| AppHost.Tests non-Docker tests — 20/20 passed | ✅ | +| Build (Release) — 0 errors | ✅ | + +**Unstaged file in worktree:** `tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs` contains an uncommitted test `SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page` (added during investigation). This is a **Gimli-owned** test file; Sam does NOT commit or modify it. + +**Seed data GUID format:** The AppHost seed command uses `GuidRepresentation.Standard` (BinData subtype 4) for all GUID fields. `MongoDB.EntityFrameworkCore 10.0.1` also uses Standard UUID by default. No format mismatch. + +**Cache layer (BlogPostCacheService):** L1 (IMemoryCache, 1 min) + L2 (Redis, 5 min). After a seed, the first blog page request hits MongoDB correctly since no prior cache entry exists for the session. Cache staleness is not a production bug — it is expected TTL behaviour. + +### Changed Files + +None. No production code change required. + +### Validation Performed + +- ✅ `dotnet build MyBlog.slnx -c Release` — 0 errors +- ✅ `dotnet test tests/Web.Tests/Web.Tests.csproj -c Release` — 210/210 passed +- ✅ `dotnet test tests/Architecture.Tests/Architecture.Tests.csproj -c Release` — 16/16 passed +- ✅ `dotnet test tests/Web.Tests.Integration/Web.Tests.Integration.csproj -c Release` — 29/29 passed +- ✅ AppHost non-Docker unit tests (MongoDb container config + seed/clear/stats command model tests) — 20/20 passed + +### Recommendation + +The runtime "remaining issues" after PR #346 are an **AppHost/Docker/runtime verification concern**, not a backend code defect: + +1. The new test `SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page` (Gimli's file) is the canary that verifies the end-to-end path. Gimli should commit and run it in a Docker-enabled environment. +2. Boromir should verify that the `mongo-data-v7` Docker volume is fresh (no MongoDB 8.x compatibility metadata) on any machine that previously ran the old `mongo-data` volume config. +3. If the Aspire health checks time out in CI, Boromir should check DCP health-check configuration for the MongoDB 7 container. + +--- + ## 2026-05-19 — Issue #345: AppHost MongoDB Container Crash Investigation (branch squad/345-fix-apphost-mongodb-crash) ### Task @@ -125,6 +178,19 @@ make MongoDB 7 exit with code 62 during startup. Web timeout logs remain as downstream symptoms of the container crash and should not be mistaken for wiring bugs. +### "Remaining database runtime issues" after container fix are runtime-verification concerns, not backend bugs + +When a database container crash is fixed (PR #346), downstream "remaining issues" often turn out to be end-to-end runtime verification gaps, not new backend code defects. The correct response is: + +1. Re-run the full non-Docker test suite to confirm baseline (unit + integration + architecture all pass). +2. Audit each repository and DbContext mapping against the seed data format — check GUID representation, field name alignment, and owned-entity mapping. +3. If all tests pass and code is correct, defer the runtime-only scenario to an AppHost/Docker integration test (Gimli) and Boromir for environment verification. +4. Never block a PR waiting for a Docker-requiring test when all code-level tests are green. + +### Seed command GUID representation must match MongoDB.EntityFrameworkCore serialisation + +The AppHost seed command writes documents via the raw MongoDB driver. Always use `GuidRepresentation.Standard` (BinData subtype 4) for all GUID fields, which matches `MongoDB.EntityFrameworkCore 10.0.1`'s default serialisation. Using a legacy representation (subtype 3) would cause EF Core `GetAllAsync` to deserialise zeros or throw. + --- ## 2026-05-15 — PR #338: Skill Template Compliance Fix diff --git a/.squad/decisions.md b/.squad/decisions.md index d0013a63..48ce6366 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -2960,3 +2960,129 @@ When MongoDB major version changes on an Aspire dev environment with a pre-exist #### Future Consideration When the team's standard dev/CI runner is confirmed to expose AVX (or when MongoDB 8.x AVX requirement is lifted), the image pin can be removed to resume tracking the hosting default. At that point rename the volume to `mongo-data-v8` (or remove the suffix if the pin is gone and volumes will be freshly created). + +--- + +## Issue #348: Resolve Remaining Database Runtime Issues + +### Decision 1: AppHost Binary Must Match Current Branch Before Starting Aspire + +**Status:** ✅ Decided +**Date:** 2026-05-19 +**Author:** Boromir (DevOps/Infrastructure) +**Issue:** #348 +**Scope:** Development workflow, AppHost infrastructure changes + +#### Problem + +After PR #346 merged MongoDB 7 + `mongo-data-v7` fixes to `origin/dev`, +Aspire continued to fail with MongoDB containers crashing (exit code 139 / +SIGSEGV). Investigation revealed the running AppHost DLL was built from a +local `dev` branch 2 commits behind `origin/dev` and still contained the old +`mongo:8.2` configuration. Aspire resolves MongoDB image tags and volume names +**at build time**, compiled into the binary — a stale build runs outdated +infrastructure silently with no warning. + +#### Decision + +Before starting or restarting Aspire, developers **must** verify the active AppHost binary reflects the current intended code: + +1. Run `git pull origin dev` on the main repo after AppHost-related PR merges +2. Rebuild: `dotnet build src/AppHost/AppHost.csproj -c Debug` +3. When MongoDB crashes unexpectedly, verify the active build: `ps aux | grep AppHost.dll` and confirm it is from the expected branch + +#### Rationale + +AppHost infrastructure configuration (image tags, volume names, environment variables, wait-for ordering) is embedded at compile time. Stale builds silently run obsolete infrastructure. This is especially dangerous after a configuration fix is merged — the fix exists in the codebase but the running binary predates it. + +#### Scope + +- Applies whenever AppHost infrastructure changes (image tags, volume names, env vars, wait-for configuration) are merged to `dev` +- Boromir owns documenting and enforcing this as part of DevOps workflow +- Documented in `.squad/skills/mongodb-dba-patterns/SKILL.md` as rule 6 + +#### No Code Change Required + +`src/AppHost/AppHost.cs` already contains the correct configuration from PR #346. This decision governs developer workflow, not production code. + +--- + +### Decision 2: Add AppHost End-to-End Regression Test for MongoDB Connectivity + +**Status:** ✅ Decided +**Date:** 2026-05-19 +**Author:** Gimli (Testing / QA) +**Issue:** #348 +**Implementation PR:** #349 + +#### Problem + +AppHost coverage verified MongoDB container configuration and operator commands. Web integration coverage verified repositories against Testcontainers. However, neither suite proved that the running web app could read seeded MongoDB data through the AppHost-provided connection string — a critical runtime wiring gap. + +#### Decision + +Add and maintain at least one AppHost-level regression test that: + +1. Seeds MongoDB via AppHost operator +2. Asserts the public `/blog` page renders seeded data +3. Stays behavior-first by checking the public endpoint, not internal DI details + +#### Rationale + +This catches runtime wiring failures that unit repository tests and operator-command tests can miss. It verifies end-to-end data flow from seeded MongoDB through AppHost connection string to public web page. + +#### Implementation + +- New test class: `MongoSeedDataIntegrationTests` in `tests/AppHost.Tests/` +- Test method: `SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page` +- Run in Docker-enabled environment to confirm full AppHost lifecycle + +#### Impact + +- Issue #348 now has tracer-bullet test for MongoDB runtime connectivity +- Future MongoDB/AppHost regressions should extend this pattern before changing production wiring +- Regression test provides safety net for image version, volume naming, and connection string changes + +--- + +### Decision 3: No Further Backend Code Changes Required for Issue #348 + +**Status:** ✅ Verified +**Date:** 2026-05-19 +**Author:** Sam (Backend / Web) +**Issue:** #348 + +#### Finding + +Issue #348 ("Resolve remaining database runtime issues") was raised after PR #346 fixed the MongoDB 8.x container crash. Sam was tasked to determine whether any Web/backend code defect remains. + +Verification confirmed: **No further Sam-owned backend changes required.** + +All Web/backend code is correct as-of HEAD of `squad/348-resolve-database-runtime-issues`. + +#### Validation Results + +| Check | Result | +| --- | --- | +| `AddMongoDBClient("myblog")` + `AddDbContextFactory` wiring | ✅ Correct | +| `MongoDbBlogPostRepository` — all methods use short-lived factory contexts | ✅ Correct | +| `MongoDbCategoryRepository` — all methods use short-lived factory contexts | ✅ Correct | +| `BlogDbContext` mappings (blogposts, categories, owned Author, CategoryId) | ✅ Correct | +| AppHost.cs — MongoDB 7, `mongo-data-v7`, `.WaitFor(mongo)` before web | ✅ Correct | +| Seed command GUID format (`GuidRepresentation.Standard`) matches EF Core 10.0.1 | ✅ Correct | +| Unit tests 210/210, architecture 16/16, integration 29/29, AppHost non-Docker 20/20 | ✅ All pass | + +#### Rationale + +The "remaining issues" after PR #346 are: + +1. **Runtime verification gap** — addressed by Gimli's new end-to-end test (Decision 2 above) +2. **Stale Docker volume concern** — addressed by Boromir's volume naming convention and DevOps workflow (Decision 1 above) + +Neither is a Web/backend code defect. All code paths are correct. + +#### Routing + +- **Gimli:** commit and run `SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page` in Docker-enabled environment to confirm end-to-end coverage +- **Boromir:** verify `mongo-data-v7` volume is fresh on all developer machines that previously ran `mongo-data` (MongoDB 8.x) configuration +- **Sam:** no further action required for Issue #348 backend scope diff --git a/.squad/skills/mongodb-dba-patterns/SKILL.md b/.squad/skills/mongodb-dba-patterns/SKILL.md index 32e21959..ec5975b0 100644 --- a/.squad/skills/mongodb-dba-patterns/SKILL.md +++ b/.squad/skills/mongodb-dba-patterns/SKILL.md @@ -65,6 +65,19 @@ live conventions versus future-only operator notes. updates in `Integration.Tests`. - Gimli owns the test side; Sam owns runtime implementation. +6. **Sync the main repo before starting Aspire (running environment check).** + - The Aspire AppHost DLL that is currently running determines which MongoDB + image and volume are in use. A stale local `dev` branch will silently run + old infra code even after a fix has been merged. + - Before starting (or restarting) Aspire, confirm the main repo is current + by running `git pull origin dev` then + `dotnet build src/AppHost/AppHost.csproj -c Debug`. + - If Aspire is already running and MongoDB is crashing, identify the active + build with `ps aux | grep AppHost.dll` — the DLL path shows which repo + root is in use. + - If the path points to a repo other than your current worktree, rebuild that + repo's AppHost or restart Aspire from the correct directory. + ### Local development and inspection Preferred tooling: diff --git a/tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs b/tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs index 748502ce..6211580d 100644 --- a/tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs +++ b/tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs @@ -7,6 +7,8 @@ // Project Name : AppHost.Tests // ============================================= +using System.Net; + using AppHost.Tests.Infrastructure; using Aspire.Hosting; @@ -148,6 +150,66 @@ public async Task SeedMyBlogData_Empty_Database_Results_In_BlogPosts_After_Seed( count.Should().BeGreaterThanOrEqualTo(1, "blogposts collection must have documents after seed"); } + /// + /// After seeding succeeds, the running web app must be able to read the seeded posts + /// through its real AppHost-wired MongoDB path. + /// + [Fact] + public async Task SeedMyBlogData_Makes_Seeded_Posts_Visible_On_The_Blog_Page() + { + // Arrange — start from a clean database so any BlogPostCacheService L1/L2 cached + // state cannot satisfy the assertions without a real MongoDB read. + using var mongoClient = new MongoClient(fixture.MongoConnectionString); + await mongoClient.DropDatabaseAsync("myblog", TestContext.Current.CancellationToken); + + var annotation = GetAnnotation(); + var endpoint = fixture.App.GetEndpoint("web", "https"); + using var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, + }; + using var webClient = new HttpClient(handler) { BaseAddress = endpoint }; + await WaitForWebReadyAsync(webClient); + + // Act + var seedResult = await annotation.ExecuteCommand(MakeContext()); + + // Assert — seeding succeeded. + seedResult.Success.Should().BeTrue("seeding must succeed before the page can read MongoDB data"); + + // Canonical proof #1 (cache-independent): documents are physically present in MongoDB, + // confirming the real AppHost-wired seed path wrote to the live container. + var db = mongoClient.GetDatabase("myblog"); + var seededCount = await db.GetCollection("blogposts") + .CountDocumentsAsync(FilterDefinition.Empty, + cancellationToken: TestContext.Current.CancellationToken); + seededCount.Should().BeGreaterThanOrEqualTo(2, + "at least 2 published posts must be present in MongoDB after seeding"); + + // Canonical proof #2: the Web app reads the freshly seeded posts through the real + // AppHost-wired MongoDB path. With [StreamRendering] the server runs + // OnInitializedAsync during SSR pre-render and streams the final rendered DOM + // (including @post.Title rows) as a