M005 Deferred Items¶
Campaign checkpoint diagnostic polish after #3214¶
- #3261 tracks bounded stale-control and incompatible-dry-run diagnostic categories. Existing paths already refuse safely; this is operator clarity, not an acceptance/security blocker.
- Merge #3214 first, then add category/privacy regression tests in a diagnostic-only PR. Preserve fresh run/ledger reads and completion compare-and-swap fences.
Closed by the 2026-09-15 sweep (recorded 2026-09-21)¶
Twelve auth PRs merged on 2026-09-15 (#3219, #3220, #3215, #3229, #3216, #3233,
3214, #3222, #3237, #2928, #2932, #3221). No entry is deleted; this records¶
which are now resolved and which stay open. Code evidence only — nothing was deployed.
- Resolved: the
Guid.TryParse(externalSubjectId)entry inResolveInvestigatorIdAsync—SyRF.ProjectManagement.Core/Services/ApplicationService.cs:126-129now throwsInvestigatorMappingRequiredExceptionfor a GUID subject without auser_idclaim, and:115-120rejects an invalid claim. The entry's fallback no longer exists. - Already resolved, unchanged: "Resolved in PR #3214" (2026-09-05).
- Stays open: "Campaign checkpoint diagnostic polish after #3214" — tracked as #3261.
- Stays open: "The OTLP exporter endpoint is still unset in GitOps" — no exporter endpoint has been configured in cluster-gitops.
- Not re-assessed by this sweep: the build/documentation warning entries, the
seeder localhost URIs entry and the GitOps-prune/
identity-job-status.shentry.
Pre-existing build warnings observed during S01¶
SyRF.SharedKernelemits existing nullable, obsolete API, documentation, and analyzer warnings during the identity solution build.SyRF.Identity.Migrationemits existing CA1052, CA1862, and CA1851 warnings outside the S01 changes.- NuGet intermittently reports
NU1900while loading vulnerability data for the unchanged SharedKernel project from configured package sources. The S01 identity audit nevertheless completed and reported no vulnerable packages for all five projects.
These warnings did not reduce the 314-test baseline and were not changed because they are outside the authentication migration runtime/dependency slice.
Pre-existing build warnings observed during S02¶
SyRF.Identity.Endpoint.Testsretains existing CA1866 warnings in login/change-password/external-login page tests and CA1001 inAuthorizationControllerTests.- NuGet intermittently reports
NU1900while loading configured vulnerability feeds for the unchanged SharedKernel project.
These warnings did not reduce the 218-test endpoint baseline and were not changed because they are outside the Identity configuration, ingress, and readiness slice.
Pre-existing documentation validation warnings observed during S02¶
- The validation environment does not provide
yq, so the script reports that YAML validation is limited while its built-in frontmatter checks still pass. docs/how-to/local-mongodb-development.mdhas the pre-existingzenhub-ticket: '2380'value instead of an accepted#2380form.
Documentation validation completed successfully with these two warnings; neither file or tool is part of S02.
OpenIddict seeder localhost redirect and logout URIs deferred to the cleanup slices (2026-08-04)¶
SyRF.Identity.Endpoint/Services/OpenIddictClientSeeder.csregisters localhost redirect and post-logout redirect URIs alongside the transitional SPA URIs. These predate this branch (commit9978a8247, already on main) and were deliberately left untouched by the Phase 5 readiness work, which changes no client-registration behaviour.- Exposure is bounded rather than open: the client is Confidential with PKCE required, so an authorization code delivered to a localhost listener cannot be redeemed without the client secret.
- Removing them here would widen the readiness slice's blast radius past "no runtime auth path changes" for no gate. They are removed together with the other SPA transition redirect URIs in the S27/S28 decommission cleanup, which is what the inline comment in the seeder already anticipates.
GitOps prune of a rendered operation Job destroys identity-job-status.sh evidence (2026-08-04)¶
scripts/auth-migration/identity-job-status.shtreats a completed Job as the evidence for its operation: it discovers Jobs by the fixedapp.kubernetes.io/name/auth.syrf.org/environment/auth.syrf.org/operationselector and fails with "Job discovery is missing" once the object is gone.- Raising
campaign.ttlSecondsAfterFinishedto 604800 (7 days) stops Kubernetes TTL garbage collection from removing earlier operations mid-sequence, but it does not protect against ArgoCD. Each GitOps commit renders exactly one operation Job, so syncing the next operation prunes the previous one regardless of its TTL. - S12 must therefore collect the per-operation evidence JSON after each sync rather than relying on a single multi-operation query at the end of the sequence. The raised TTL and this per-sync collection are complementary: the TTL covers the manual canary confirmation and stop/resume gaps within one rendered operation, the per-sync collection covers the prune between operations.
The OTLP exporter endpoint is still unset in GitOps, so no BFF telemetry window can run yet (2026-08-04)¶
AddOpenTelemetryConfig(SyRF.WebHostConfig.Common/SyrfConfigureServices.cs:81-82) builds the resource and the API registers theSyRF.API.BffAuthmeter (SyRF.API.Endpoint/Program.cs:81-83), but no OTLP exporter endpoint is configured anywhere in cluster-gitops — a repository-wide search forOTEL/otlp/OpenTelemetryacross the GitOps repo returns nothing.- S05-SUMMARY.md:253 records this deliberately: "Later rollout slices must configure the existing BFF flag/provider/authority/session generation and OpenTelemetry exporter."
- Consequence:
scripts/auth-migration/query-auth-telemetry.shcannot return data for any non-baseline mode until the exporter is wired, so S11's first BFF window is blocked on that rollout slice rather than on the harness. - The environment dimension itself is no longer part of that gap:
BffAuthTelemetrynow emits a boundeddeployment.environmentinstrument tag (normalised by the OTLP-to-Prometheus mapping to thedeployment_environmentlabel the query script selects on), so the selector holds however the exporter is eventually configured. A resource attribute would not have been sufficient — resource attributes land ontarget_info, not on each series, unless the collector is configured to promote them.
Resolved in PR #3214 — campaign-final and import-rerun command/catalogue paths (2026-09-05)¶
campaign-finalnow reconciles the mounted export and current PM mappings against immutable import security provenance, invokes the import verifier, checks settled delivery evidence and callsCampaignRunStore.CompleteRunAsync. The disabled chart operation renders that actual CLI action with private inputs and an aggregate report sink.- The earlier claim that
import-rerunneeded only a catalogue entry was incorrect: the importer also needed actual mutation accounting. The chart now rendersimport --require-no-writes; a readable zero-write declaration is required before import. A valid declared rerun executes the importer and fails if it creates or repairs documents, without rolling those changes back. - See the checkpoint contract for the bounded evidence, non-sending behavior and reviewed operation sequence. This resolves the repository implementation deferral, not the still-required S12 live execution, inspection or retained operational evidence. No production campaign or cutover is implied by these tests.
Guid.TryParse(externalSubjectId) in ResolveInvestigatorIdAsync needs a deliberate design decision (2026-08-04)¶
ApplicationService.ResolveInvestigatorIdAsync(SyRF.ProjectManagement.Core/Services/ApplicationService.cs:115-119) falls back, when the trusteduser_idclaim is absent or non-GUID, toGuid.TryParse(externalSubjectId)and treats the parsed value as an Investigator id — callingRecordSignInAsyncwith it and creating the Investigator if none exists.- Under Auth0 that fallback was unreachable in practice: an Auth0 subject is
auth0|…/google-oauth2|…and never parses as a GUID. Under OpenIddict it is reachable for the first time, becauseAuthorizationController.UserinfosetssubtoApplicationUser.Id— a GUID the importer mints withGuid.NewGuid()(UserImporter.cs:92) — and emitsuser_idonly whenSyrfUserIdis populated. A migrated user with no matched Investigator therefore reaches the fallback with a GUID that is an ApplicationUser id, not an Investigator id. - The two outcomes are opposite in kind: either an orphan Investigator is created under the ApplicationUser's GUID, or the create collides on the user's email. Neither is obviously wrong — this may well be the intended new-user path, where a self-registered OpenIddict user legitimately becomes a new Investigator keyed on its own subject.
- Flagged during round-5 review of PR #2691 and deliberately not fixed there: the round-5 change on this path narrows to
RecordExternalSubjectIdleaving a migrated Investigator'sauth0|…provenance intact, and changing the fallback's identity semantics as well would decide a product question inside a review correction. - Needs an explicit decision before the production BFF switch: confirm whether the GUID-subject fallback is the sanctioned new-user path (and if so, cover it with a test that says so), or replace it with an explicit
sub-keyed lookup so an ApplicationUser id can never be read as an Investigator id.