14 KiB
Fiche STG-SF5m-VAL — Niveau N1 — Modèle prévu (agent lp-validator) | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
STG-SF5m-VAL : validation statique de S-F5m / S-F5n (relevage des personnes enfoncées contre un décor solide) (2026-10-14)
Copie D:\Game\LifePlay-master 5.8, branche ue5.8. Lecture seule, hors ce livrable. Pas de build, pas d'UE, jeu non lancé, aucune commande git qui écrit.
Verdict : PASS-STATIC (rien compilé, rien exécuté en jeu), avec réserves R1 à R4 (§ 5).
1. Fiches amont relues
STG-SF5m-IMPL.md(en entier, 73 lignes),STG-SF5m.diff(en entier, 139 lignes),STG-COMMUN8-DIAG.md§ A.3 et § A.4 (l. 34-78),STG-SF5k-VAL.md(l. 1-60 : références des API et gardes déjà relues).STG-SF5j-VAL.md: présent, non relu en entier (les gardes S-F5j sont relues ici directement dans le code, § 3 cmd 5).- Écart de forme (E1) : l'IMPL ne suit pas le gabarit IMPL (
lp-doc/gabarits.md) : pas de section « Écarts à la SPEC », « Ce qui n'a pas été fait » est en § 3 et non en § 4, les points à confirmer sont en § 4 (le gabarit les met en § 5), « Fichiers à commiter » est en § 7 (avec M/A, sans le dépôt précisé). Les trois points à confirmer existent et sont repris au § 2.
2. Points à confirmer des IMPL
| Id | Point (IMPL § 4) | Résultat |
|---|---|---|
| P1 | Rue, arrivée au bord contre une façade : relevage en moins de 2 s ; journal releve de … puis ecarte de … (… S-F5m), ou une seule ligne « aucun point libre » |
reporté (COMMUN-9, essai en jeu). Statique : chemin de code et journal conformes (§ 3 cmd 3 et 4) |
| P2 | Rue, arrivée ordinaire : relevage en place comme COMMUN-6, sans ligne S-F5m | reporté (COMMUN-9). Statique : PASS-STATIC, TryPlace reproduit l'ancienne boucle et bMoved reste faux (§ 3 cmd 3) |
| P3 | Plage ou forêt : rien de changé | reporté (COMMUN-9). Statique : PASS-STATIC, LiftSunkPersons n'est appelée que sous if (bOutdoor) (LPOutdoorRoomSubsystem.cpp:175-182), aucun autre appelant |
| — | Compilation | BLOCKED-NONCOMPILE : à la charge du BUILD COMMUN-9 |
3. Critères rejoués (commande → résultat brut)
Cmd 1. MD5, instantané, fins de ligne, ASCII (md5sum, FileCheck.ps1 -Lot STG-SF5m -OnlyChanged, LC_ALL=C grep -c -P, git ls-files --eol).
9dcf0a35a1418bcb52e1a6a5b7d0f58f *LPOutdoorRoomSubsystem.cpp
60fce1de305f4133738193d82cd05f05 *LPOutdoorRoomSubsystem.h
90f9324be06a4eab10e105aa9d78f137 *…/STG-SF5m/Source/LifePlay/LPOutdoorRoomSubsystem.cpp
f9ed4d2df44af11163c0e3fbb3b4a4ca *…/STG-SF5m/Source/LifePlay/LPOutdoorRoomSubsystem.h
Fins CRLF LF CR BOM MD5 ... Alerte Fichier
LF 0 510 0 - 9DCF0A35A1418BCB52E1A6A5B7D0F58F modifie Source\LifePlay\LPOutdoorRoomSubsystem.cpp
LF 0 82 0 - 60FCE1DE305F4133738193D82CD05F05 modifie Source\LifePlay\LPOutdoorRoomSubsystem.h
fichiers=2 LF=2 alertes=0 introuvables=0 ; exit 0
non-ASCII cpp:0 h:0 ; CR cpp:0 h:0 IMPL:0 ; 'C:.Users' dans l'IMPL : 0
i/lf w/lf attr/-text Source/LifePlay/LPOutdoorRoomSubsystem.cpp
Les MD5 actuels égalent l'IMPL § 5 (9DCF0A35… / 60FCE1DE…) ; l'instantané égale 90F9324B… / F9ED4D2D… (IMPL § 1). Fichiers en LF, 0 CR, ASCII pur, aucune alerte FileCheck. IMPL en LF (0 CR), en-tête complet (modèle, agent, skills), sans C:\Users. (La commande FileCheck sur l'IMPL et le .diff comme arguments positionnels a échoué : paramètre inconnu ; l'IMPL a été contrôlé par grep à la place, le .diff n'est pas un fichier source.)
Cmd 2. Diff régénéré = STG-SF5m.diff (git diff --no-index --numstat ; puis lignes +/- hors en-têtes, empreinte).
80 5 …/STG-SF5m/Source/LifePlay/LPOutdoorRoomSubsystem.cpp => LPOutdoorRoomSubsystem.cpp
2 0 …/STG-SF5m/Source/LifePlay/LPOutdoorRoomSubsystem.h => LPOutdoorRoomSubsystem.h
lignes +/- régénérées : 416c8126b17fe63f310d0ab5591af8eb
lignes +/- de STG-SF5m.diff : 416c8126b17fe63f310d0ab5591af8eb
Numstat conforme (80/5 et 2/0), lignes ajoutées/retirées identiques au .diff livré. Diff lu en entier : seuls hunks, .cpp (LiftSunkPersons uniquement : nettoyage de UnplacedLogged, retrait en fin d'épisode, lambda TryPlace, bloc S-F5m, journal, retrait au relevé) et .h (commentaire + membre UnplacedLogged) ; correspond exactement à l'IMPL § 2. Aucun ajout non demandé. Les 5 retraits sont : for (const FVector& Candidate…) d'origine, continue;, bPlaced = true; break; de l'ancienne boucle, et if (Near) (devenu else if (Near)).
Cmd 3. Équivalence de l'ancienne boucle (lecture …/STG-SF5m/…cpp:405-432 contre …cpp:414-444 actuel).
| Élément | Avant | Après (TryPlace) |
Verdict |
|---|---|---|---|
| Start / End | FloorTop + HalfHeight + LiftProbe / - 2.0 en (Candidate.X, Y) (lignes inchangées, hors hunk) |
idem, l. 418-419 | identique |
Remise de Hit, TargetZ par défaut |
Hit = FHitResult(); TargetZ = FloorTop + HalfHeight + 2.0 |
idem, l. 420-421 | identique |
| Balayage | SweepSingleByChannel(… Query, Responses) |
idem, l. 422 | identique |
bStartPenetrating |
continue (point suivant) |
return false (point suivant dans la boucle appelante) |
équivalent |
| Sol trouvé | TargetZ = Hit.Location.Z + 1.0 |
idem, l. 432 | identique |
| Sortie | Target = FVector(X, Y, TargetZ); bPlaced = true; break; |
Target = …; return true; puis bPlaced = true; break; (l. 439-443) |
équivalent |
Hit et Target après la boucle |
lus par la ligne « releve de » (Hit.GetComponent(), Target.Z) |
Hit, Target capturés par référence ; Hit est remis à zéro à chaque appel, donc après un succès il décrit le dernier balayage, comme avant |
identique |
Ordre des points d'origine inchangé : S-F5k (Candidates : ±50 cm si Near) puis Location en dernier (l. 396-407). InPlace n'est écrit que si Candidate.Equals(Location) ; Location est toujours ajouté à Candidates (l. 407), donc InPlace est toujours renseigné quand le point sur place échoue (il n'échoue que par bStartPenetrating). Quand un point d'origine aboutit : même Target, même relevage, mêmes lignes de journal, bMoved faux ; seul changement : UnplacedLogged.Remove(Person) (l. 493, sans effet si absent). Aucun changement de comportement hors cas « tous les points d'origine en recouvrement » (avant : personne sautée sans ligne ; maintenant : S-F5m). |
Cmd 4. S-F5m / S-F5n (lecture LPOutdoorRoomSubsystem.cpp:449-508).
| Exigence | Constat | Verdict |
|---|---|---|
| S-F5n en premier, seulement après échec des origines | if (!bPlaced) l. 450 ; premier ajout Escapes l. 455-458 |
PASS-STATIC |
| Normale horizontale, profondeur + 2 | Push = InPlace.Normal; Push.Z = 0.0, condition InPlace.bStartPenetrating && Push.SizeSquared() > 0.01, point Location + Push.GetSafeNormal() * (PenetrationDepth + 2.0) ; la garde écarte une normale verticale ou nulle (donc InPlace vide, bStartPenetrating faux) |
PASS-STATIC |
| Petit axe vers le centre, grand axe ±, petit axe opposé | Long/Short choisis comme S-F5k (échelle Y ≥ X → grand axe = droite) ; Inward = signe de (Room - Location)·Short ; ordre Short*Inward, +Long, -Long, -Short*Inward (l. 468-471) = DIAG A.4 |
PASS-STATIC |
| Cinq points au plus, ordre respecté, une seule action | boucle l. 472-480, break au premier succès ; un seul SetActorLocation (l. 494) ; TInlineAllocator<5> couvre 1 + 4 |
PASS-STATIC |
| Ligne « ecarte … S-F5m » contre « S-F5k » | if (bMoved) S-F5m sinon else if (Near) S-F5k (l. 498-507) : une seule des deux ; la ligne « releve de » reste écrite avant |
PASS-STATIC |
| Ligne « aucun point libre » une fois par épisode | Contains puis Add puis log (l. 484-490) ; retrait si relevé (l. 493), si Bottom >= FloorTop - SunkDepth (l. 361-365), si l'acteur est détruit (nettoyage l. 338-344, avant la boucle). Pas de spam : une personne non relevée n'entre pas dans Seen (l. 371-375), son compte repart à 1 : réessai toutes les 3 examens (≈ 1,5 s), mais la ligne est écrite une fois |
PASS-STATIC |
Cmd 5. Gardes inchangées, rien hors extérieur (lecture …cpp:325-380, diff).
Cachée / classe Person_C / sans collision / OccupyingFnt / UsedInScene (l. 350-353), SexOn (l. 329), seuil SunkDepth 15 cm et mouvement (l. 359), examens immobiles 3 ou 4 (l. 369-375), PlayerBusy (l. 377) : aucune ligne modifiée par le diff (seul l'ajout du Remove dans la branche l. 361-365, qui reste suivie de continue). Le seul déplacement ajouté est dans LiftSunkPersons, appelée uniquement en extérieur (l. 175-182). PASS-STATIC.
Cmd 6. Compilabilité (statique, moteur D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime).
| Élément | Source | Verdict |
|---|---|---|
FHitResult::Normal est FVector_NetQuantizeNormal, dérivé de FVector ; copie dans FVector Push |
Engine/Classes/Engine/HitResult.h:61 ; Engine/Classes/Engine/NetSerialization.h:540 |
PASS-STATIC |
PenetrationDepth est float ; static_cast<double> |
HitResult.h:91 |
PASS-STATIC |
TSet::Contains(KeyInitType), Remove(KeyInitType) (int32), Add(const&) / Add(&&), CreateIterator, RemoveCurrent, operator-> |
Core/Public/Containers/SparseSet.h.inl:960, 905, 415-419, 1710, 1666, 1522 (Set.h n'inclut que CompactSet/SparseSet) |
PASS-STATIC |
Contains/Add/Remove(ACharacter*) : conversion implicite vers TWeakObjectPtr<AActor> |
même conversion déjà compilée par SunkPersons.Find(Person) (SF5j/SF5k, builds antérieurs) |
PASS-STATIC (estimé : même conversion, sauf Add qui prend un temporaire) |
Logged->IsValid() |
TWeakObjectPtr::IsValid() : CoreUObject/Public/UObject/WeakObjectPtr.h:300 ; usage voisin .cpp:274-275 |
PASS-STATIC |
FVector::Equals, SizeSquared, GetSafeNormal, Dist2D, OneVector |
API usuelle, utilisée déjà dans le fichier (Dist2D l. 390 ; GetSafeNormal l. 402) |
PASS-STATIC |
Lambda [&] : Hit, Target, InPlace, World, Capsule, Query, Responses, FloorTop, HalfHeight, Location déclarés avant le lambda (l. 356-415) ; LiftProbe (namespace constexpr) sans capture |
.cpp:356-422 |
PASS-STATIC |
TArray<FVector, TInlineAllocator<5>> |
même forme que TInlineAllocator<3> l. 396 |
PASS-STATIC |
Masquage (C4458/C4456/C4457) : Scale déclaré dans if (Near) (l. 399, bloc fermé l. 406) puis dans if (!bPlaced) (l. 459) : portées sœurs, pas de masquage ; Long, Short, Push, Escapes, Inward, bLongIsY, bMoved, InPlace, TryPlace absents des membres de la classe (.h:56-81) et du namespace anonyme (.cpp:25-51) |
lecture | PASS-STATIC |
| Collision unity : tout est local à la fonction ; aucun nouveau symbole de namespace | diff | PASS-STATIC |
C4244 : opérations en double partout (Inward, LiftSpacing double) ; UE_LOG %.1f avec double |
lecture | PASS-STATIC |
Format des UE_LOG : %s%s %.1f %s, arguments const TCHAR*/*FString, même motif que la ligne « releve de » existante |
.cpp:487-489, 500-501 |
PASS-STATIC |
| Aucune compilation lancée : le résultat de l'unité LifePlay reste à prouver par le BUILD COMMUN-9. |
4. Diff lu en entier
STG-SF5m.diff (139 lignes) lu en entier, plus le code final LPOutdoorRoomSubsystem.cpp:325-510 et .h (en entier). Deux fichiers : .cpp +80 / -5, .h +2 / -0. Recompte indépendant : git diff --no-index --numstat (méthode distincte du diff de l'IMPL) = 80/5 et 2/0 ; empreinte des lignes +/- identique à celle du .diff livré.
5. Verdict
PASS-STATIC. MD5 conformes, diff conforme à l'IMPL, équivalence de l'ancienne boucle établie par lecture, S-F5m/S-F5n conformes à STG-COMMUN8-DIAG.md § A.4, gardes intactes, API relues dans le moteur 5.8. Non rejoué : compilation, exécution, essais en jeu (reportés à COMMUN-9).
Réserves et risques (aucun n'est un FAIL) :
- R1 (estimé) : cloison ou rue. Chaque point de repli n'est validé que par la descente de la capsule (pas de test de ligne de vue ni de limite de rue). Un point à 50 cm peut être de l'autre côté d'une cloison mince ou hors du trottoir (grand axe ±) ; S-F5n (profondeur + 2 cm) est moins exposé. Atténuation : l'ordre place le petit axe vers le centre en premier, et la façade n'est essayée qu'en dernier.
- R2 (estimé) : « centre » = origine de Room.
InwardutiliseRoom->GetActorLocation(); si l'origine n'est pas le centre géométrique de la rue, le sens « vers le centre » peut être faux ; les trois autres points restent essayés. - R3 (estimé) : normale de dépénétration. Sur un décor en collision complexe, la normale d'un recouvrement initial peut être verticale ou la profondeur nulle ; dans le premier cas S-F5n est sauté (garde
SizeSquared() > 0.01), dans le second le point n'est décalé que de 2 cm et peut encore chevaucher (le balayage échoue alors et on passe au point suivant). Le coût est un balayage inutile. - R4 (établi, mineur) : épisode non remis à zéro hors extérieur.
UnplacedLoggedn'est pas vidé auReset()deSunkPersons(l. 331) ni quand la pièce redevient intérieure ; une entrée ne part que si la personne remonte au-dessus du seuil ou est détruite. Conséquence : une personne restée enfoncée d'un lieu à l'autre ne reloguerait pas ; sans effet sur le déplacement. Coût : au plus 5 balayages supplémentaires par personne enfoncée et par réessai (≈ 1,5 s), négligeable. Les points ±Long déjà essayés par S-F5k (quandNear) sont réessayés une fois pour rien.
6. Points à confirmer par l'utilisateur
- COMMUN-9 : essai en jeu « rue, arrivée au bord contre une façade » (IMPL P1) : relevage en moins de 2 s, ligne
ecarte … (depart dans …, S-F5m)ou une seule ligne « aucun point libre ». - COMMUN-9 : essai « rue, arrivée ordinaire » (P2) et « plage ou forêt » (P3) : aucune ligne S-F5m.
- Le point écarté ne se retrouve ni de l'autre côté d'une cloison ni hors de la rue (R1, R2).
- BUILD COMMUN-9 : 0 erreur, aucun avertissement nouveau sur
LPOutdoorRoomSubsystem.cpp(C4458, C4244). - Forme de l'IMPL (E1) : accepter l'écart au gabarit ou faire compléter.
Fichiers à commiter
Aucun (seul livrable écrit : Docs/Migration/etat/ST/STG/STG-SF5m-VAL.md, A).
Tours : 11 / 25