docs(redesign): record native saved-search P1 finding

This commit is contained in:
cesnimda
2026-10-09 13:31:25 +02:00
parent 83d3e909f5
commit 4c52b57123
@@ -0,0 +1,267 @@
{
"recordedUtc": "2026-10-09T11:28:44.921507+00:00",
"checkpoint": "P5-15-01",
"sourceCheckpoint": "932b962b9038ddb5ad59b982c0199475bfb50454",
"result": "FAIL",
"scope": "Saved-search listing on the current local SQLite runtime",
"issue": {
"id": "P5-15-01-DISCOVERY-01",
"priority": "P1",
"severity": "High functional availability/preservation defect in the saved-search workflow",
"affectedRoute": "/discover",
"affectedEndpoint": "GET /api/job-discovery/saved-searches",
"symptom": "Normal and administrator fixture accounts receive HTTP 500 loading saved searches.",
"impact": "Saved searches cannot be listed after route entry or refresh. The client silently suppresses the load error and leaves an empty list, hiding existing saved searches and their pause/run/delete/results controls. Newly created rows may display in the current session, but listing on refresh still fails.",
"securityDisposition": "No demonstrated authorization bypass, exploit, tenant disclosure or security leak; this finding is functional availability.",
"preservationDisposition": "Affected saved-search/list workflow is NO-GO pending an approved owner-specific repair; automated route render and the passing backend total do not prove this workflow."
},
"nativeHttpEvidence": [
{
"role": "admin",
"trace": ".artifacts/p5-15-01/browser/route-correction-results/functional-acceptance--P5--beb39-fresh-and-admin-permissions-chromium/trace.zip",
"traceSha256": "8db571b87c648bbcccc158312ad781b4eedb5da14fa29cdc4b2bbd3a97aff8af",
"method": "GET",
"path": "/api/job-discovery/saved-searches",
"status": 500,
"contentMimeType": "application/problem+json; charset=utf-8",
"resource": "5104a20f495751f99b79d6958c275a139a8abd22.dat",
"bodySha256": "4a46c8b6176bc529f24749d427598aac71746abf038501cfe6a85643180d9cf1",
"exception": null,
"relevantStack": []
},
{
"role": "normal",
"trace": ".artifacts/p5-15-01/browser/route-correction-results/functional-acceptance--P5--ece7d-resh-and-normal-permissions-chromium/trace.zip",
"traceSha256": "623f8f4cefee18aa100487fc9128790ba7e9b9858002006dc27c12ec3f9ae99b",
"method": "GET",
"path": "/api/job-discovery/saved-searches",
"status": 500,
"contentMimeType": "application/problem+json; charset=utf-8",
"resource": "9f95f31b96cc142ca9d3878decb32e3d723cd5fe.dat",
"bodySha256": "80cc7abd680ba0b36569f8afe8f7b959a24fa7e5b93d7f477cf25a37cd5ce037",
"exception": null,
"relevantStack": []
}
],
"rootCause": {
"status": "PROVEN for the exact current SQLite query/provider; native HTTP bodies are redacted and do not themselves contain the exception stack.",
"query": "SavedJobSearches.AsNoTracking().Include(x => x.Results).Where(x => x.OwnerUserId == owner).OrderByDescending(x => x.UpdatedAtUtc)",
"explanation": "UpdatedAtUtc is an unconverted DateTimeOffset mapped to SQLite TEXT. EF Core Sqlite rejects ORDER BY on this expression during query translation. ListSavedSearches awaits the query without handling this exception, producing the observed HTTP 500. The failure is before executing SQL, so it also affects empty accounts and is independent of NAV/provider configuration.",
"installedProviderReproduction": {
"result": "REPRODUCED",
"provider": "Microsoft.EntityFrameworkCore.Sqlite",
"propertyType": "System.DateTimeOffset",
"columnType": "TEXT",
"hasValueConverter": false,
"exceptionType": "System.NotSupportedException",
"message": "SQLite does not support expressions of type 'DateTimeOffset' in ORDER BY clauses. Convert the values to a supported type, or use LINQ to Objects to order the results on the client side.",
"relevantStack": [
"at Microsoft.EntityFrameworkCore.Sqlite.Query.Internal.SqliteQueryableMethodTranslatingExpressionVisitor.TranslateOrderBy(ShapedQueryExpression source, LambdaExpression keySelector, Boolean ascending)"
],
"databaseConnectionState": "Closed",
"externalCalls": 0,
"applicationDatabaseWrites": 0
},
"commandRecord": {
"command": [
"rtk",
"proxy",
"C:/Users/Connor/.dotnet/dotnet.exe",
".artifacts\\p5-15-01\\discovery-investigation\\harness\\bin\\Release\\net9.0\\DiscoveryInvestigation.dll"
],
"startedUtc": "2026-10-09T11:26:57.481170+00:00",
"finishedUtc": "2026-10-09T11:26:58.436946+00:00",
"exitCode": 0,
"log": ".artifacts/p5-15-01/discovery-investigation/translate-native.log",
"nativeDependencySource": "JobTrackerApi/bin/Release/net9.0/runtimes/win-x64/native/e_sqlite3.dll",
"nativeDependencySha256": "b7385d722c83fb52142a00477a726723745916d22a555711ee89834c1111fb2e",
"logSha256": "5f2f59ec217324fd78713dd06b15790c4ff6dc019232d54801038bb4c29075df"
},
"assemblyHashes": [
{
"path": "JobTrackerApi/bin/Release/net9.0/JobTrackerApi.dll",
"sha256": "c1170121a37dcf3ba4aca2882c21fa5541f0fe3159346ffe84df59b4dd69fc80"
},
{
"path": "JobTrackerApi/bin/Release/net9.0/Microsoft.EntityFrameworkCore.Sqlite.dll",
"sha256": "0bcde51bb9a7215d6e2a178605879df01efa0ade6edb217f3e423fd29809e7e3"
}
],
"harnessHashes": [
{
"path": ".artifacts/p5-15-01/discovery-investigation/harness/Program.cs",
"sha256": "b342e194fdf454033847832d95a077c272aa23904ff2bff33c0d1aeadc4cfb6f"
},
{
"path": ".artifacts/p5-15-01/discovery-investigation/harness/DiscoveryInvestigation.csproj",
"sha256": "f3b846389dcf6ede9514b0df18a3e8c364ff9c30900fd40c61daa53c954d78ce"
}
],
"initialHarnessAttempt": {
"result": "HARNESS_DEPENDENCY_FAILURE",
"explanation": "Initial ignored harness output did not contain the installed e_sqlite3 native DLL. It failed before query translation. The existing API win-x64 native DLL was copied unchanged into ignored output; the subsequent translation assertion passed.",
"preservedCommands": [
{
"name": "restore",
"command": [
"rtk",
"proxy",
"C:/Users/Connor/.dotnet/dotnet.exe",
"restore",
".artifacts\\p5-15-01\\discovery-investigation\\harness\\DiscoveryInvestigation.csproj",
"--source",
"E:\\Storage\\Projects\\Active\\Job tracker\\.artifacts\\p5-15-01\\discovery-investigation\\empty-local-package-source"
],
"startedUtc": "2026-10-09T11:26:16.425858+00:00",
"finishedUtc": "2026-10-09T11:26:17.392474+00:00",
"exitCode": 0,
"log": ".artifacts/p5-15-01/discovery-investigation/restore.log",
"logSha256": "d194008e6be316f553abeab92c6fc97d8bb0e22d7591668a1fef2ba16a77a02f"
},
{
"name": "build",
"command": [
"rtk",
"proxy",
"C:/Users/Connor/.dotnet/dotnet.exe",
"build",
".artifacts\\p5-15-01\\discovery-investigation\\harness\\DiscoveryInvestigation.csproj",
"--configuration",
"Release",
"--no-restore"
],
"startedUtc": "2026-10-09T11:26:17.392976+00:00",
"finishedUtc": "2026-10-09T11:26:20.751663+00:00",
"exitCode": 0,
"log": ".artifacts/p5-15-01/discovery-investigation/build.log",
"logSha256": "5b581dd8a79c2451ca438dc6b69aa6274528c30feeda3c168c56443f287478b4"
},
{
"name": "translate",
"command": [
"rtk",
"proxy",
"C:/Users/Connor/.dotnet/dotnet.exe",
".artifacts\\p5-15-01\\discovery-investigation\\harness\\bin\\Release\\net9.0\\DiscoveryInvestigation.dll"
],
"startedUtc": "2026-10-09T11:26:20.752164+00:00",
"finishedUtc": "2026-10-09T11:26:22.849042+00:00",
"exitCode": 3762504530,
"log": ".artifacts/p5-15-01/discovery-investigation/translate.log",
"logSha256": "8e27ec578bf3b5a36747cd0b1267b317040ad43463e03b173424949224663df3"
}
]
},
"offlinePreparation": "Standalone framework-only harness restored against an empty local directory as the sole source before the no-restore clarification. No PackageReferences, downloads or network; existing Release DLL references only. No further restore."
},
"runtimeScope": {
"localProvider": "Microsoft.EntityFrameworkCore.Sqlite",
"efCoreSqlite": "9.0.14",
"dotnetSdk": "9.0.317",
"localEvidence": "Current Playwright server recipe uses Development and a fresh disposable DataRoot, with no explicit Database:Provider/connection string; API fallback selects SQLite.",
"productionProvider": "NOT VERIFIED. Program also supports mysql/mariadb with MariaDbServerVersion11.0.0. This SQLite translator exception does not prove a MariaDB production failure or pass.",
"databaseOpened": false,
"applicationDatabaseWrites": 0,
"httpServerStarted": false,
"externalProviderCalls": 0
},
"testCoverageGap": {
"freshBackendCases": [
{
"name": "JobTrackerApi.Tests.JobDiscoveryControllerTests.Search_keeps_latest_active_event_and_removes_inactive_duplicates",
"outcome": "Passed"
},
{
"name": "JobTrackerApi.Tests.JobDiscoveryControllerTests.Search_filters_recent_active_nav_jobs",
"outcome": "Passed"
},
{
"name": "JobTrackerApi.Tests.SavedJobSearchAlertTests.Worker_establishes_baseline_then_notifies_only_for_later_results",
"outcome": "Passed"
},
{
"name": "JobTrackerApi.Tests.JobDiscoveryControllerTests.Saved_search_tracks_new_seen_and_dismissed_results_per_owner",
"outcome": "Passed"
}
],
"backendTotal": "1023 passed, zero failed/skipped",
"reason": "Saved_search_tracks_new_seen_and_dismissed_results_per_owner executes ListSavedSearches against EF InMemory. Worker alert coverage also uses EF InMemory and orders by integer Id rather than UpdatedAtUtc. Existing SQLite DateTimeOffset compatibility coverage exercises CV/workspace/usage/extraction/package queries, but omits discovery saved-search listing.",
"recommendedProof": "A disposable SQLite controller regression with two dated owned searches and a foreign search; assert successful empty listing, exact descending owned order, results/counts and foreign-row exclusion, then the native no-provider route GET for both roles."
},
"remediationRecommendation": {
"checkpoint": "P5-15-04 owner-specific bounded repair; not implemented in this audit",
"owner": "Backend discovery owner",
"approach": "Reuse CvVariantService.ListAsync existing provider pattern: enforce owner/query filters before materialization; SQLite sorts the owned results in memory, while SQL-capable providers retain server ordering. Keep cancellation, Results include, DTO counts and newest-first semantics. Avoid global type conversions/schema migrations or returning an empty list on exception.",
"validation": "Add focused SQLite regression, run its owner suite and required full baseline, then native /discover refresh for normal/admin fixtures; maintain explicit production-provider limits."
},
"sourceEvidence": [
{
"path": "JobTrackerApi/Controllers/JobDiscoveryController.cs",
"startLine": 51,
"endLine": 55,
"sha256": "1d3c64a5d5d88027b2add267bef5a2489933ff1f68aa3aca84cc5e2e5826b9c7"
},
{
"path": "JobTrackerApi/Models/SavedJobSearch.cs",
"startLine": 13,
"endLine": 13,
"sha256": "7385b52232fc2434123b3e89045b5380f0a7185881c4a19fbbda8b4c410f2f9b"
},
{
"path": "JobTrackerApi/Data/JobTrackerContext.cs",
"startLine": 431,
"endLine": 439,
"sha256": "d755c97ad025d09e06e92e4d338be8cfbb332ea13e2fd4c32046fe2763a006be"
},
{
"path": "JobTrackerApi/Program.cs",
"startLine": 98,
"endLine": 124,
"sha256": "74de01e586055e4b125a1929500bbdae54cad30a5d46e8c657217f22c2706d9b"
},
{
"path": "JobTrackerApi.Tests/JobDiscoveryControllerTests.cs",
"startLine": 53,
"endLine": 74,
"sha256": "a37087613dc75584d986bd5d300e625c800f092b3aedf1754cf12530b7e9f6b7"
},
{
"path": "JobTrackerApi.Tests/SavedJobSearchAlertTests.cs",
"startLine": 35,
"endLine": 35,
"sha256": "a1ea58ac16cfb504bb73d48bd214603587282d8b830a19ab9de7d89a8c728a70"
},
{
"path": "JobTrackerApi.Tests/SqliteDateTimeOffsetCompatibilityTests.cs",
"startLine": 151,
"endLine": 192,
"sha256": "be2a965d71ffdb2b17cc220e682d50fc65af97d6da3ad571f082a0c9aac5a758"
},
{
"path": "JobTrackerApi/Services/CvVariantService.cs",
"startLine": 62,
"endLine": 73,
"sha256": "97f450fc3613c03de064816e6388a8cfab60d46db5d2739ed3e9ba5da7a71bc2"
},
{
"path": "job-tracker-ui/src/views/JobDiscoveryPage.tsx",
"startLine": 52,
"endLine": 58,
"sha256": "5df7ab8a2af437d587535e8d91c68e801fb86c1fcf2638d69206cfb1c30b0f9b"
},
{
"path": "job-tracker-ui/playwright.config.ts",
"startLine": 38,
"endLine": 64,
"sha256": "80da205d1b692b0d1c317772fdeda618a0e848d8c25625f8097a0e33ff2456e1"
},
{
"path": "JobTrackerApi/Services/SavedJobSearchAlertHostedService.cs",
"startLine": 51,
"endLine": 56,
"sha256": "20b33c143c946ea36fa2009f31789d6b420a5fb13445999eb7910fb5b58fe4ba"
}
],
"sourceComparedFilesUnchangedFromCheckpoint": true,
"qualification": "Read-only investigation of retained local synthetic trace and installed provider translation. No application/test source edit, live server/port5302 call, application database open/write, Docker operation, commit/push, external data/provider/model call or deployment."
}