Root cause (CURRENT_ROADMAP.md item #3): wwwroot/assets/* and
wwwroot/index.html under KArtSell.Host are 100% Vite build output (no
hand-authored files in there) but were committed to git. Every local
dotnet build re-triggers pnpm build via the BuildFrontend MSBuild
target, which produces new content-hashed filenames even when no
frontend source changed, and the old hashed files were never cleaned
up (4 of the 6 committed asset files were already orphaned/unreferenced
before this fix, confirmed by diffing wwwroot/index.html's script/link
tags against what was actually on disk).
Investigated whether the committed output was load-bearing for
deployment before picking a fix:
- .gitea/workflows/deploy.yml (the real production deploy path) already
wipes wwwroot and rebuilds it fresh from pnpm build on every deploy,
so the committed files were never actually used there.
- .gitea/workflows/ci.yml's `publish` job (Gitea Release zip) was the
only place actually depending on the committed wwwroot contents,
since it runs `dotnet publish` without ever building the frontend.
Given that, committing the hashed output was pure architectural
mistake with no deployment benefit, and the smaller/more correct fix
is to stop tracking it rather than bolt MSBuild Inputs/Outputs
incrementality onto the BuildFrontend target (which would also be
fragile: git checkouts/worktrees can normalize file mtimes in ways
that defeat timestamp-based up-to-date checks).
Fix:
- .gitignore: ignore src/KArtSell.Host/wwwroot/assets/ and
wwwroot/index.html (generated by BuildFrontend target locally and by
deploy.yml in production).
- git rm --cached the 7 previously-tracked generated files.
- ci.yml publish job: add the same pnpm install/build + wipe-and-copy
step deploy.yml already uses, so the release zip still ships a real
frontend build instead of losing it now that git no longer carries it.
- Left the BuildFrontend MSBuild target itself unchanged (still runs
pnpm build on every local `dotnet build`) since re-running it is no
longer a problem now that its output isn't tracked.
Verified (not just asserted):
- `dotnet build KArtSell.sln -c Release` run twice in a row: `git
status`/`git diff --stat` identical after both runs (only the 9
intentional lines in .gitignore/ci.yml), even though wwwroot/assets
on disk got fresh hashed filenames both times.
- Reverted to pre-fix state and ran a single `dotnet build` with zero
source changes: reproduced the bug exactly as described -
wwwroot/index.html showed a 13-line diff and 2 new untracked hash
files appeared, with the old stale ones left behind. Then restored
the fix and re-verified the two-consecutive-build check above.
- `cd frontend && pnpm install --frozen-lockfile && pnpm typecheck &&
pnpm build` all pass cleanly on their own.
- `dotnet test tests/KArtSell.ModelOperations.UnitTests` still 54/54
passing after the build changes.
Separate, out-of-scope finding recorded in CURRENT_ROADMAP.md: ~130
frontend/src/**/*.js files compiled from .ts/.vue siblings (plus
tsconfig.tsbuildinfo, vite.config.js) are also committed and also
regenerate on every `pnpm build` via `vue-tsc -b`, because
tsconfig.json has no `noEmit: true`. Same class of problem, not fixed
here to keep this PR to one goal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tests now guard against accidental drop of kartsell_migration_test by throwing
when the credential source DB is the destructive rehearsal target. Distinct
credential DB (kartselldb_test) prevents config collision.
AEG-X-004 evidence consolidated: rehearsal .trx files + preflight markdown
documented. Schema 0032 (shadow_run_queued_status_contract) verified
fresh/upgrade/recovery on isolated DB.
AGENTS.md: Necessity-driven (guard against destructive accident); no new feature.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>