refactor(api): durcir la sonde boot-log derrière une porte test-only (#1319) - #1380
Merged
Conversation
…nitialize (#1319) The probe gate must run before any other startup step so a refused boot does not depend on any other configuration being present, and so the hard-reject added next exits before any host or database work. Also extends the test-only child harness (Lib/Testing, compiled into the test project only) with a raw RunBootProcess that returns exit code plus both streams verbatim and strips PUBLYAPP_TEST_BOOT_PROBE from the inherited environment unless a spec explicitly pins it, keeping refusal cases hermetic. Adds constants for the flag name and the 78 (EX_CONFIG) refusal exit code.
Roslyn two-view lexer spec that fails the build if the test-only --emit-canary-boot-log wiring escapes its three sanctioned call sites, leaks into deploy manifests, or drops the PUBLYAPP_TEST_BOOT_PROBE gate.
Runbook subsection for the misconfigured-container outage mode and a social-accounts guide section covering the arg+flag contract and the exit-78 refusal path.
CaptureBootLogLines drives the probe's ACCEPTANCE path, so it must hand the boot gate PUBLYAPP_TEST_BOOT_PROBE explicitly now that the arg alone is hard-rejected (exit 78). Refusal cases still go through RunBootProcess directly and stay hermetic.
Both spec classes clone the SAME fixed-name template database (witness_boot_canary_test) and xUnit runs different classes in parallel, so adding a third guard test made the latent #1309 collision real: CREATE DATABASE ... TEMPLATE hit 23505 duplicate key on pg_database_datname_index when both classes cloned concurrently. Group them in one DisableParallelization collection, matching the existing AcmeTenantMutation/TenantUserExport precedent.
…manifests Extend DeployManifests() with apps/api/Properties/launchSettings.json, apps/front/docker-compose.test.yml, and apps/front/docker-compose.fork-overlay.yml so the #1317-class regression cannot reintroduce the probe through any of the three remaining boot manifests. The scan now fails loudly when a manifest is missing or unreadable instead of silently skipping it.
Round-1 fix for #1319: PUBLYAPP_TEST_BOOT_PROBE=1 in a deployed container re-enabled the probe because the gate only checked the flag. The probe now requires BOTH an accepted flag value AND a test-shaped hosting environment (Development/Testing, resolved via ASPNETCORE_ENVIRONMENT then DOTNET_ENVIRONMENT with blank = unset; no Production fallback). Refusal exits 78 and names its cause in plain words per the transparent- failure rule: quoting the resolved non-test environment, or stating the unset bare-container case explicitly, then the flag half when it is absent or unaccepted. The emit harness pins Development alongside the flag by default so the suite's acceptance path presents the sanctioned shape end to end; guard spec covers Production+flag refusal, unset+flag refusal naming the unset cause, and the flag+Development acceptance against a real clone.
radandevist
added a commit
that referenced
this pull request
Aug 25, 2026
…ventory (#1264) (#1326) Closes #1264 ## Summary Resolves every React Compiler compatibility follow-up queued in the #1234 skip inventory, then rebases onto a develop that advanced three times mid-flight (#1305, #1310, #1314, #1323/#1325 on the front side, plus API/scripts-only lanes). Regenerated against the final tree: **13 diagnostics across 9 files** (down from 36 across 20 when this branch started); **compiled client modules rise from 90 to 97** against the pinned floor of 72. Per item (one commit each, red/green evidence under `.dump/` by name): 1. **`useWatch()` in `_create-post-drawer.tsx`** — replaces the render-time `watch('body')` read (IncompatibleLibrary). 2. **Shared `useLanguageKeyedZodResolver` hook** — replaces the `[i18n.language]`-memoised resolver + eslint-disable pattern in 7 files (Suppression family). 3. **`profiles.tsx` / `profiles-new.tsx`** — latest-callback ref indirection collapsed to plain functions; ref writes moved out of handlers into an open-transition effect (probe-verified: ref writes inside a handler passed to the column factory taint it); `lastEditedProfileRef` became state. 4. **Big forms render-time ref reads** — `invitations/new.tsx`: known-profile-names map → state with idempotent effect folds plus synchronous per-render union of fresh rows; redirect timer → state-armed deadline owned by an effect; saved-flag re-baseline via synchronous form reset before navigate. (`staff-users/$userId-edit.tsx`, originally covered here too, was later superseded by develop's #1314 — see Rebase record.) 5. **Preserve-memo drops** — `$tenantId/users.tsx` + `invitations.tsx`: manual useCallback/useMemo wrappers deleted; the compiler caches per value. Plus an inventory refresh in `docs/guides/front/react-compiler.md` (every row dispositioned) and a gate commit clearing all react-doctor findings in touched files (HARD gate: findings must be fixed or suppressed with per-line rationale). ## Rebase record Three rebases onto a moving origin/develop. Each resolution kept both intents where they coexisted and preferred develop's implementation where it already superseded ours: 1. **Rebase 1 — `_profile-form-drawer.tsx`:** resolved to develop's side entirely. Develop's rewrite moved form ownership to the host page and deleted the very effects/suppressions our commit targeted; our hunk had nothing left to preserve. 2. **Rebase 2 (+#1310 no-iife, #1314 refs-out-of-render, #1323/#1325 DataTable exemption) — `staff-users/$userId-edit.tsx`:** took develop's side everywhere. #1314 implements our item 4 better (module-level snapshots written outside render, adjust-state-during-render absorption, snapshot-based nav blocker), and it untaints the submit closure our version left flagged. Our parallel item-4 work in `invitations/new.tsx` survives unchanged. 3. **Rebase 3 (+#1315 uploads, #1328 launcher — API/scripts only, zero front overlap):** completed clean after discarding a locally regenerated `routeTree.gen.ts` Register block (local toolchain artifact; committed versions intentionally lack it). Net effect on the skip inventory, recorded honestly in the refreshed doc: - **Fixed elsewhere:** `$userId-edit.tsx` now compiles outright (#1314); `$tenantId-edit.tsx`'s Refs diagnostic stopped firing after #1305's QueryDisplay restructure; one `_assign-members-drawer` suppression went quiet; the erroneous `__root.tsx` row (its ref write was already effect-wrapped) was dropped. - **Regressions owned:** #1305 reinstated try/finally in three handlers #1234 had fixed — `staff-users/$userId.tsx` (×2), tenant `users.tsx`, tenant `users/$userId.tsx`. They are re-queued in the inventory rather than papered over. - **Omission corrected:** `_profile-edit-details-drawer.tsx`'s exhaustive-deps suppression predates this refresh but was missing from the earlier inventory; it is now listed as an acceptable skip. ## Gates - Artifact guard on the final tree: **97 ≥ 72** compiled modules, runtime chunk present (`compiler-runtime-CNG2r3iR.js`), exit 0 (`check-react-compiler.mjs`) - Full front suite under the heavy lock, post-rebase: **220 files / 2393 tests passed**, exit 0 (evidence tail `.dump/rebase2-final-suite.log`); typecheck clean - Root lint gate (oxlint + disable-comment audit + frontend barrels) exit 0 · oxfmt check exit 0 · `just ci-drift` exit 0 - `react-doctor@0.9.12 --scope files --base origin/develop --blocking warning` exit 0 - Skip-inventory parser suite (`packages/scripts-ts`): 7/7 green - Design-system guard (611 files, 0 violations) and z-index guard (16311 candidates) green inside the suite run Implementer: Ox Alpha (stealth/ox-alpha via Nous Portal, max effort, jcode). Reviewer: pending adversarial review. ## Round 1 fix Review r1 (APPROVED_WITH_FOLLOW_UPS) flagged the added `react-doctor-disable-next-line` comments as guard-loosening residue of the clearing commit. Disposition, per the repo rule that added suppression comments are themselves a finding: - **Audited against origin/develop, not assumed.** A scratch worktree of origin/develop (@301f2b835) scanned with the pinned `react-doctor@0.9.12` shows the annotated effect patterns (open-transition resets, dirty-flag uplinks, click-handler navigate) ARE flagged on develop itself — genuinely pre-existing findings, not introduced by this diff. - **Kept only under the sanctioned exemption**, each now carrying an explicit per-line rationale (deliberate pattern + pre-existing on develop); `profiles.tsx` restores develop's own rationale block verbatim. No code changes: the fix commit is a comment-only diff. - **react-doctor before/after:** with the suppressions stripped entirely, `just react-doctor` (`--scope files --base origin/develop --blocking warning`) fails on those pre-existing findings surfaced in the touched files; with the rationales in place it exits 0 with zero new findings. Whole-repo score: develop 66 → this branch 68 (this PR's real fixes raise it; no regression). - **Re-validated after the fix:** production build + artifact guard (97 ≥ 72 compiled modules, runtime chunk present), full front suite under the heavy lock (exit 0), front typecheck, root lint, oxfmt check, `just ci-drift` — all exit 0. **Mid-flight develop advances handled:** the first fix push went red because origin/develop moved (#1329 anti-slop rungs 4+5 enabling `anti-slop/no-chained-type-assertions` at error, plus #1312/#1331/#1332); the merge-ref CI therefore flagged four chained-assertion sites in files this PR touches. Rebased onto origin/develop (clean, one overlapping file) and fixed them per #1329's own recipe — no suppressions, no config change: the resolver hook's `as unknown as` chain became a single cast seam, and the three `ROUTE_COMPONENTS` entries of `trans-render.guard.test.tsx` (pre-existing on develop) were narrowed via a local helper. That state went **fully green** in CI (`48a0d8c0a`: quality, react-doctor-gate, supply-chain, all four front-e2e shards). Develop then advanced again before merge: #1335 (staff profile edit surface) touched the same guard-test file with its own equivalent `routeComponentThunk` helper, and #1336 moved jobs code, leaving the PR CONFLICTING. Rebased once more; the sole conflict (`trans-render.guard.test.tsx`) was resolved to **develop's version verbatim** rather than keeping a second competing helper, so the top commit now reduces to the resolver-hook fix alone. That state went fully green locally and was pushed (`a7161537a`): CI came back green everywhere except one shard — `front-e2e (4/4)` died at 43 s inside the **Pull stack** step on a GHCR network timeout pulling the third-party `shopify/toxiproxy` image (`context deadline exceeded`), before a single test executed; the other three shards passed, so this was an infrastructure flake, not a diff regression. Meanwhile develop advanced yet again (#1343 adds the `publy/no-never-any-casts` rule, #1338 the NuGet-audit record — no file overlap with this PR). Final rebase onto that tip and full re-validation: root lint (both anti-slop rules active), front typecheck, oxfmt, `just react-doctor`, `just ci-drift` — all exit 0; targeted trans-render suite (27/27), production build with the artifact guard (97 ≥ 72 compiled modules), and the full front suite under the heavy lock — all green. Round 1 fix implementer: Ox Alpha (via Nous Portal, max effort, jcode). ## Round 2 fix Review r2 returned APPROVED_WITH_FOLLOW_UPS for exactly one reason: the round-1 fix had kept suppression comments where it could not immediately root-cause the finding. This round removes every added suppression by fixing the underlying pattern instead — zero suppression-type lines added vs origin/develop: - **`_change-email-dialog.tsx`** — the open-transition reset effect is gone, replaced by a keyed wrapper: an outer shell increments `sessionKey` on every closed→open transition and remounts a pure `Inner` form through `key`. A fresh mount initialises from `defaultValues` by construction, so no imperative reset exists at all. - **`_invite-user-drawer.tsx` / `_profile-edit-details-drawer.tsx`** — the dirty-flag uplink no longer compares watch-stream snapshots against a component-captured pristine baseline (the root of the `no-ref-initializer-runs-on-every-render`, `no-pass-live-state-to-parent` and `exhaustive-deps` findings). Dirtiness now comes from react-hook-form's own synchronous dirty computation (`control._getDirty`), which always answers "differs from the pristine session seed". The partial-failure reseed pins its baseline with `keepDefaultValues: true`, so retried failed rows still count as unsaved user data. The profile drawer keys sessions on `${sessionKey}:${profile.id}` so switching profiles remounts while a same-id refetch does not. - **`use-language-keyed-zod-resolver.ts`** — doc comment reworded so it no longer contains the literal text `eslint-disable-next-line react-hooks/exhaustive-deps -- [i18n.language]` (grep-proof pollution only, no behaviour change). **Suppression proof:** `git diff origin/develop --unified=0 | grep '^+' | grep -E 'react-doctor-disable|eslint-disable|@ts-expect-error'` returns **no matches** across the whole diff (transcript: `.dump/round2-suppression-proof.txt`; full-suite log tail: `.dump/round2-full-suite.log`). `react-doctor@0.9.12 --scope files --base origin/develop --blocking warning` exits 0 with **zero findings**. **Gates after round 2:** front typecheck clean; production build + artifact guard **97 ≥ 72** compiled modules with runtime chunk present; full front suite under the heavy lock **224 files / 2436 tests passed**; three targeted suites **35/35**; root lint gate (oxlint + disable-comment audit + barrels) exit 0; oxfmt check exit 0; `just ci-drift` exit 0. Round 2 implementer: ox-alpha (max effort, jcode). ## Unverified / blocked-by-infra - All non-e2e checks are green on ad6116f (17 pass). CI-side front-e2e (4 specs) has not run locally by design; on CI it is currently **blocked by an owner-level GitHub Packages problem, not by this diff**: the `Push stack images to GHCR` step fails deterministically (`permission_denied: The requested installation does not exist`) before any test executes — reproduced across 5 runs (initial + 3 reruns + 1 fresh run), while image-content-neutral lanes succeeded in the same window with the same actor. The `publyapp-e2e-*` container packages resolve with `"repository": null` (unlinked from this repo), so token-authenticated uploads of new layers are refused. Full transcript: `.dump/round2-front-e2e-infra-failure.txt`; tracked in #1397 for the owner. - API suites were not re-run: this branch touches no API code (front-only diff, verified via merge-base file list). ## Rebase after #1396 Develop merged #1396 (GHCR namespace + repo path repoint after the move to the PublyApp org) plus nine more commits (#1382/#1349, #1402, #1380, #1399/#1391 EF Core 10.0.11, #1351, #1358, #1355 specs, #1353), leaving this branch CONFLICTING again. Rebased onto `origin/develop` @ `f2811483a`; reviewed round-3 tip was `ad6116f97`, new tip is **`d7139e212`** (pushed with `--force-with-lease`). Exactly one conflict across the 14 rebased commits, in `docs/guides/front/react-compiler.md`: develop's side of the decision-vocabulary paragraph still pointed “follow-up” at #1264 as an open queue, while this lane's regenerated inventory (which auto-merged everywhere else in the same file) uses the post-#1264 vocabulary. Resolution keeps this lane's updated paragraph, verified against both sides in full before editing; no `--ours`/`--theirs` anywhere. #1396's workflow/package changes applied cleanly with no overlap. Lockfile untouched by develop, so no reinstall was needed. Full local re-validation on the new tip, all green: front typecheck exit 0; root lint gate (`just check-write`) exit 0; full front suite **224 files / 2263 tests passed** (exit 0); design-system guard 0 violations across 620 files; z-index guard OK; React Compiler artifact guard **97 ≥ 72** compiled modules with runtime chunk present. Full record: `.dump/rebase-report.md`. ## Rebase after #1396 again (#1385/#1381/#1360/#1403/#1318), tip 1b3abb1 Develop advanced again while the PR sat reviewed (#1385, #1381, #1360, #1403, #1318), leaving it CONFLICTING a third time. Rebased all 14 commits onto `origin/develop` @ `933319f3f`; reviewed tip `ad6116f97` → first-rebase tip `d7139e212` → **new tip `1b3abb19e`** (pushed with `--force-with-lease`). Five replay stops conflicted, all from develop's #1318 no-giant-component extraction of the giant staff forms; every resolution keeps both intents by taking develop's extracted structure and porting this PR's compiler work into its new home — no `--ours`/`--theirs` anywhere: - **Item 2 (language-keyed resolver):** `tenants-new.tsx` keeps develop's thin wrapper; the resolver-hook change moved into `_tenants-new-form.tsx` (manual `useMemo(zodResolver(...), [t, i18n.language])` → `useLanguageKeyedZodResolver`, max-seats ref-getter preserved). `$tenantId-edit.tsx` and `$tenantId/users/$userId-edit.tsx` keep develop's extracted-section bodies; import-level conflicts resolved to exactly what the merged bodies use (the hook import in, retired-inline-layout imports out). - **Item 3 (latest-callback collapse):** `profiles.tsx` keeps develop's thin page over `_use-profiles-list-state.ts`; the item-3 mechanics were ported into that hook — `lastEditedProfileRef` became render-read-safe **state**, the bypass re-arm + PUSH bookkeeping moved into an effect on the open transition, and the `openEditDrawerRef` indirection + columns `useMemo` were dropped for a plain handler handed straight to `makeTenantProfileColumns`. - **Items 4–5:** auto-merges verified intent-preserving (`profiles-new.tsx` hasSavedRef removal; plain handlers + unwrapped columns in `invitations.tsx`/`users.tsx`). - **Gate + review-r1 comment commits:** `profiles.tsx` conflicts resolved to develop's side — the one carried suppression targeted inline `openEditDrawer` calling `navigate()` directly, a pattern that no longer exists under the hook architecture (`openEditDrawer` now calls `pushSearch`), so there was nothing to suppress; the drawer files' “Pre-existing on develop” rationales merged cleanly. Full local re-validation on `1b3abb19e`: `pnpm install --frozen-lockfile` (develop had moved the lockfile), front typecheck exit 0, **full front suite green** (design-system guard 0 violations / 718 files, z-index guard OK, React Compiler artifact guard **97 ≥ 72** compiled modules with runtime chunk present — the ported work survives develop's refactor), `just check-write` exit 0, `just react-doctor` zero findings. Full record: `.dump/rebase-report.md`. Pushed CI on `1b3abb19e`: **all checks green** — 27 pass, spec-drift skipping as designed for a front-only diff (front-e2e 4/4 under the org namespace), zero failures. ## Rebase after #1396, final take (#1384/#1411), tip 6372398 — all green Develop moved again while take 1 was green in CI: #1384 (pristine-save guard + shared `resolveProfileSaveFailure`) rewrote exactly the tenant profile-edit drawer this PR refactors, plus #1411 (DLQ backend, no overlap). Rebased once more onto that tip; **new tip `6372398b3`** (`--force-with-lease`). Three replay stops conflicted, all in `_profile-edit-details-drawer.tsx`, all resolved keeping both intents: the gate/r1 comment conflicts keep develop's already-justified suppressions with r1's "pre-existing on develop" wording merged in; the round-2 conflict keeps #1384's new save/failure handling while restoring r2's render-phase `seededFor` reseed and event-driven `methods.watch` dirty uplink (zero suppressions introduced — net removal vs pre-#1384 develop). Local gates on `6372398b3`: typecheck exit 0; full front suite green (React Compiler artifact guard 97 ≥ 72 compiled modules); `just check-write` exit 0; `just react-doctor` zero findings. Lockfile untouched this time, no reinstall needed. Full record: `.dump/rebase-report.md`. Pushed CI on `6372398b3`: **all checks green** — 27 pass, spec-drift skipping as designed for a front-only diff (front-e2e 4/4 under the org namespace), zero failures; GitHub reports the branch **MERGEABLE**. --- Implementer: Ox Alpha (Nous Portal, jcode, max effort). Reviews: r1/r2 (free chain), r3 APPROVED at ad6116f, r4 APPROVED by tencent/hy3:free at 6372398 after three rebases onto develop (deltas attributable to #1318/#1385/#1384; 14-commit intent intact; 0 suppressions added); CI 27/27 green incl. front-e2e 4/4.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé
Clôture le suivi adversarial de #1317 : l'argument de sonde boot-log
--emit-canary-boot-logfait retournerMainjuste après les portes witness avec exit 0 et AUCUN hôte démarré (worker : pas de moteur de jobs ; api web : pas de socket). Unecommand:Dokploy mal configurée produisait donc une panne totale d'apparence saine. Désormais :PUBLYAPP_TEST_BOOT_PROBE(exactement1outrue) refuse le démarrage avec exit 78 (EX_CONFIG) et une cause en mots simples nommant la variable — avant TOUTE autre étape de démarrage (Mainactive la sonde avantAppEnvironment.Initialize()), donc un refus ne dépend d'aucune autre configuration. Toute autre valeur de la variable échoue fort ; jamais de repli silencieux.CanaryBootLogProbeGuardSpecboote l'assembly livré comme processus enfant réel (même harnais queMasterKeyWitnessBootIntegrationSpec) : argument sans variable → exit 78 + cause nommant la variable + aucun marqueur de capture ; variable=1 (+ worker contre une vraie base clonée du template) → sonde acceptée, marqueurs émis ; valeur non analysable (yes) → refus fort.CanaryProbeContainmentSpec(garde d'architecture, lexing Roslyn commeJobEnqueueBoundarySpec) prouve qu'aucune activation de la sonde n'existe hors de son fichier de définition et du câblage sanctionné deProgram.cs, et que Dockerfile / dokploy.yml / docker-compose.services.yml / .env.example ne passent jamais l'argument ni n'exportent la variable — avec un corpus auto-testé (camouflage commentaires/chaînes/trous d'interpolation).production-deploy-runbook.md+ entrée du playbook de pannes dansdocs/guides/social-accounts.md.Preuves rouges/vertes appariées
TDD strict, transcripts bruts locaux au lane (.dump/, gitignoré) :
Failed: 2, Passed: 1— les deux cas de refus échouent, l'enfant ignore la variable et plante plus loin dans la validation Production (exit 134) au lieu de refuser proprement :Passed! - Failed: 0, Passed: 3, Skipped: 0, Total: 3.if (false && IsTestOnlyFlagValueAccepted(...))— la variable est ignorée, refus systématique) : ROUGE attendu sur le cas d'acceptation — la suite doit prouver qu'elle détecte une porte qui refuse toujours aussi bien qu'une qui n'existe pas. Revert → VERT 3/3.Mainpour ré-exécuterAppEnvironment.Initialize()avant la sonde) : ROUGE attendu — l'enfant plante à nouveau en validation Production (exit 134, pas de cause en mots simples) au lieu des 78 attendus ; prouve que la position précoce de la porte est elle-même sous spécification. Revert → VERT 3/3.CanaryProbeContainmentSpecvert ; scan de l'arbre vivant vert (aucun offender).Portes
Sous
heavy.sh: specs ciblées (guard + containment + witness boot integration + composition/seeder probes) puis suite API complète (1929tests) ·pnpm lint·pnpm format·just ci-drift. Pas de pile e2e locale (politique de vérification du captain ; CI couvre front-e2e sur la PR).Deux vrais défauts d'intégration trouvés par la première passe de la suite complète et corrigés dans cette PR :
CanaryBootLogCli.CaptureBootLogLines(harnais api: social-accounts canary boot-log guards — assert the artifact, and BeEmpty on the skipped path #1309) ne présentait pas la variable test-only ; le rejet dur api: canary boot-log probe argument must be inert in deployed containers (hard-reject without test-only flag) #1319 refusait donc les boots witness existants (exit 78). Corrigé : le mode emit présente explicitementPUBLYAPP_TEST_BOOT_PROBE=true; les cas de refus passent toujours parRunBootProcessdirect et restent hermétiques.MasterKeyWitnessBootIntegrationSpecetCanaryBootLogProbeGuardSpecclonent toutes deuxwitness_boot_canary_test; xUnit parallélise des classes différentes, donc l'ajout d'une troisième garde a rendu réel le flop latent api: social-accounts canary boot-log guards — assert the artifact, and BeEmpty on the skipped path #1309 (23505 duplicate keysurCREATE DATABASE … TEMPLATE). Regroupées dans une collectionDisableParallelization(précédentAcmeTenantMutation/TenantUserExport).Closes #1319
Round 1 — revue APPROVED_WITH_FOLLOW_UPS : MEDIUM bloquant corrigé
La revue adversariale (tip examiné
f231dc621aef) a approuvé avec un suivi bloquant : la porte ne refusait la sonde que lorsque le flag est UNSET. Un conteneur déployé portantPUBLYAPP_TEST_BOOT_PROBE=1(fuite de config, héritage Compose, etc.) réactivait donc la sonde et reproduisait l'outage #1317 (exit 0 sans hôte démarré). Round 1 :03b72da9f…8c7f2f2e6) : la sonde exige maintenant un flag accepté ET un environnement d'hôte de forme test —Development/Testinguniquement, résolu depuisASPNETCORE_ENVIRONMENTpuisDOTNET_ENVIRONMENT, valeur blanche = unset, aucun repli Production. Un conteneur déployé (Production résolu OU environnement unset, forme bare-container) refuse désormais même avec le flag, exit 78, cause en mots simples citant l'environnement résolu (environment 'Production' is not a test environment; the test-only flag is ignored here) ou nommant explicitement le cas unset (the hosting environment is not set: neither ASPNETCORE_ENVIRONMENT nor DOTNET_ENVIRONMENT is set …). Règle transparence-des-échecs respectée : la cause nomme les DEUX moitiés de la porte quand elles sont fautives.03b72da9f) :DeployManifests()couvre maintenantapps/api/Properties/launchSettings.json,apps/front/docker-compose.test.ymletapps/front/docker-compose.fork-overlay.yml(les trois manifestes de boot restants), et le scan échoue fort sur manifeste manquant/illisible au lieu de le sauter silencieusement.8c7f2f2e6) :CaptureBootLogLinesépingleASPNETCORE_ENVIRONMENT=Developmentpar défaut aux côtés du flag — la forme sanctionnée du chemin d'acceptation — tout en laissant un appelant épingler son propre environnement hôte (utilisé verbatim) ; les cas de refus passent toujours parRunBootProcessdirect et restent hermétiques.Preuves rouges/vertes appariées (round 1)
Failed: 2, Passed: 4— les deux NOUVEAUX tests d'environnement échouent précisément parce que les enfants acceptent la sonde au lieu de refuser :.dump/red-build.log,.dump/red-r1.txt.Passed! - Failed: 0, Passed: 12, Total: 12, puis suite API complètePassed! - Failed: 0, Passed: 1948, Skipped: 0, Total: 1948sousheavy.sh(le compteur passe de 1929 à 1948 avec les tests ajoutés par cette PR). Transcripts :.dump/green-build.log,.dump/green-r1.txt,.dump/full-suite-r1.txt..dump/pristine/avant modification.Commits round 1 :
03b72da9f(containment),8c7f2f2e6(porte environnement).Implementer: Ox Alpha (stealth/ox-alpha via Nous Portal, max effort, jcode). Reviewer: round 1 = APPROVED_WITH_FOLLOW_UPS ; ce push corrige le MEDIUM bloquant et attend la contre-revue.
Unverified
Le corps initial a subi une revue adversariale (round 1 ci-dessus) ; ses preuves rouges/vertes locales (.dump/, gitignoré) n'ont pas été ré-exécutées par un second modèle. Les nouvelles preuves round 1 sont locales au lane et attendent la contre-revue.