test(mosaic): record targeted STEP20C partial closure
Record exact-SHA scale and extended G samples, same-source blur measurements and retained negative saved/input results. Keep STEP20C NEXT and production multi-output unsupported; no production integration. Preserve immutable probe fixtures, offline regressions and compact artifact provenance. Fourteen consumed runs / 125 output captures, independent final audit accepted. Saved timeout/GPU lifetime, whole-H1 return, input after camera mutation and all-frame damage remain open.
This commit is contained in:
parent
30dc3182ab
commit
ed9375797e
39 changed files with 6061 additions and 66 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -2,3 +2,4 @@
|
|||
tooling/probes/step20c-valid-grab/*.patch -whitespace
|
||||
tooling/probes/step20c-saved-target-timeout-input/target-hit-trace.patch -whitespace
|
||||
tooling/probes/step20c-optimized-blur-cache/*.patch -whitespace
|
||||
tooling/probes/step20c-targeted-diagnostic/saved-passive.patch -whitespace
|
||||
|
|
|
|||
27
CHANGELOG.md
27
CHANGELOG.md
|
|
@ -4,6 +4,33 @@
|
|||
|
||||
### STEP20C experimental evidence
|
||||
|
||||
- Record the targeted private campaign: 14 unique runs, 125 captures and 520
|
||||
reserved events, with exact A/G/pristine/C3 identities and separate measurement,
|
||||
raw runtime, scientific cleanup and architecture statuses. Scale grabs/input
|
||||
and G dynamic/hidden/R90 extend sampled evidence; terminal IPC exit 1 remains
|
||||
INCONCLUSIVE in every run.
|
||||
- Preserve real held configure 39 with saved A/G measurement stops and client
|
||||
error 32 during compositor teardown; timeout/native saved identity/normal
|
||||
close remain unqualified. Classic blur is exercised, whole-H1 A/B/A RGB
|
||||
restoration still fails in pristine/A/G, and input camera changes during the
|
||||
click window remain an incomplete fixture measurement. New native replay
|
||||
pairs 789 of 821 final commits without claiming atomic generation or GPU
|
||||
lifetime.
|
||||
- Update the integration draft to the twenty requested evidence questions and
|
||||
retain private stage/source-verification success, full package build NOT RUN,
|
||||
ABI/notice/legal/maintenance and instrumentation limits. C3 is consumed with
|
||||
INCONCLUSIVE runtime: native creation/draw/teardown
|
||||
are partially observed, but a frozen unique-address predicate rejects actual
|
||||
node-address reuse. Its bounded wait stop is not a natural transaction timeout;
|
||||
held/live PNG, normal close and GPU completion remain unqualified. Final
|
||||
independent review is ACCEPTED / audit PASS for experimental evidence fidelity:
|
||||
43 offline tests,22 additional mutations rejected,0 BLOCKING,1 NON_BLOCKING
|
||||
editorial finding and3 FUTURE_SCOPE. Documentary publication is authorized
|
||||
and prepared, not executed at this edition; final refs belong to the private
|
||||
closeout and final handoff. Production
|
||||
source, current package, UX and historical evidence are unchanged; STEP20C
|
||||
NEXT, production multi-output NOT YET SUPPORTED.
|
||||
|
||||
- Local offline nested geometry/fixture review protocol: separate SHM, assigned/rendered, scene, XDG and PNG spaces; exhaustive assertion/source/test register and independent review required. No graphical launch authorized; final offline verdict INCONCLUSIVE.
|
||||
|
||||
- Preserved static nested-grab fixture failure: sole unchanged-binary run confirms identity/output/camera/tiled clip and exact whole-H2 pre-popup references, then fails before any click/grab on a native-SHM versus painted-height assertion. INCONCLUSIVE / UNDECIDED; additional IPC-y/titlebar assumption invalid, offline assertion audit insufficient. Raw runner exit1 and compositor exit0 retained; popup/standard gates NOT TESTED, no retry/build/production change. Historical runner and sealed artifacts preserved.
|
||||
|
|
|
|||
|
|
@ -541,3 +541,35 @@ recommendation is PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE, not integration.
|
|||
Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Documentary publication is prepared, not executed at this edition;
|
||||
final publication identities belong to the private receipt and final handoff.
|
||||
|
||||
## Targeted STEP20C evidence — 2026-10-14
|
||||
|
||||
The [targeted closure dossier](design/STEP20C_TARGETED_CLOSURE_DECISION.md)
|
||||
records 14 unique private runs/125 captures/520 reserved events, with exact
|
||||
A/G/pristine/C3 identities.
|
||||
Scale root/nested grabs and sampled G hidden/R90/dynamic paths have their own
|
||||
observations beyond the historical horizontal smoke. Owner/root association is
|
||||
bounded by source and opening-window evidence; no direct native host/owner ID
|
||||
join or atomic generation is established. G dynamic uses fresh toplevel input
|
||||
when popup_done has ended the chain, without recreating it.
|
||||
|
||||
All raw runtime outcomes remain INCONCLUSIVE on terminal IPC exit 1. Mechanical
|
||||
process cleanup, scientific cleanup, measurement and architectural verdicts are
|
||||
separate. Held XDG configure 39 is real on A/G, but native saved-node/render
|
||||
identity and natural timeout/normal close are not observed; client error 32 at
|
||||
compositor teardown prevents a scientific cleanup PASS. Whole-H1 optimized
|
||||
A/B/A restoration fails in pristine/A/G; 16 homologous A/G captures are RGB exact
|
||||
but do not establish instrumentation neutrality. Native buffer/GPU lifetime,
|
||||
atomic scene/input/present generation and complete damage remain NOT PROVEN.
|
||||
|
||||
The consumed C3 diagnostic has its own exact binary and remains INCONCLUSIVE:
|
||||
a frozen globally unique-address predicate rejects a reused saved-node address.
|
||||
It observes creation, H1 drawing and teardown only, with lock 3 to 4; no natural
|
||||
transaction timeout or held/live PNG was observed. Offline create-to-next-destroy
|
||||
intervals are descriptive and establish no native generation identity. Owner
|
||||
error 32 despite process code 0 keeps scientific cleanup INCONCLUSIVE; saved
|
||||
clipping and GPU lifetime remain unqualified. No result transfers to A/G. Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Documentary publication is authorized and prepared, not executed at
|
||||
this edition; final refs belong to the private closeout and final handoff. These observations adopt no architecture, UX or production
|
||||
dependency. Native compositor/tree authority and Row 0 borrowing are unchanged;
|
||||
STEP20C NEXT, production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -486,3 +486,35 @@ Production multi-output remains NOT YET SUPPORTED. No production, UX or current
|
|||
package contract is changed. Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Documentary publication is prepared, not executed at this edition;
|
||||
production integration remains undecided.
|
||||
|
||||
## Targeted STEP20C limits — 2026-10-14
|
||||
|
||||
The [targeted dossier](design/STEP20C_TARGETED_CLOSURE_DECISION.md) adds exact-SHA
|
||||
scale and G dynamic/hidden/R90 observations. It retains 14 raw INCONCLUSIVE
|
||||
runtime outcomes (terminal IPC exit 1), distinct from positive measurements and
|
||||
process codes 0. Saved A/G show a real held configure, but no natural timeout,
|
||||
held image/native saved identity or normal close; error 32 during compositor
|
||||
teardown keeps scientific cleanup INCONCLUSIVE. The distinct C3 run also stops:
|
||||
its frozen unique-address predicate rejects actual node-address reuse. C3
|
||||
creation/H1 draw/teardown and lock 3 to 4 are partially observed, but the bounded
|
||||
wait failure is not a natural transaction timeout. Held/live PNG, H2 held
|
||||
clipping, normal owner close and GPU completion remain unqualified; no result
|
||||
transfers to A/G.
|
||||
|
||||
Classic blur is genuinely exercised in pristine/A/G. Whole-H1 optimized return
|
||||
still fails by 37,252 pristine and 34,323 A/G pixels, maximum channel delta 6,
|
||||
without masks. A/G's 16 homologous RGB frames are exact; a deterministic source
|
||||
kernel model does not reproduce the native signed deltas, so GPU causality and
|
||||
neutrality remain INCONCLUSIVE. Permitted interior shadow is NOT EXERCISED.
|
||||
Input A/G stops at a focus/camera mutation during delivery; observed local
|
||||
coordinates agree with the latest native origin, but remaining camera/layout
|
||||
coverage and atomic generation are unqualified. Native replay pairs 789 of 821
|
||||
final commits (13 initial runs: 758/788; C3: 31/33); buffer identity, complete damage and lifetime remain NOT PROVEN.
|
||||
|
||||
Private recipe metadata/source verification and five-file stages are validated;
|
||||
full package build is NOT RUN. Exact incorporation/legal notices, named
|
||||
release/security ownership and all other SceneFX/wlroots pairs remain open.
|
||||
Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Documentary publication is authorized and prepared, not executed at
|
||||
this edition; final refs belong to the private closeout and final handoff.
|
||||
STEP20C remains NEXT; production multi-output remains NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -374,3 +374,33 @@ preserves exact identities, budget and private provenance references. Recommenda
|
|||
PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE; no production decision applied.
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED. Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Documentary publication is prepared, not executed at this edition.
|
||||
|
||||
## Targeted STEP20C evidence — 2026-10-14
|
||||
|
||||
These new experimental reports supplement immutable historical evidence; they
|
||||
do not supersede canonical contracts or qualify production. The targeted
|
||||
campaign records 14 unique runs/125 PNG/520 reserved events. Raw runtime remains
|
||||
INCONCLUSIVE for all terminal IPC exits, with measurement/scientific cleanup
|
||||
separate. C3 observes native creation/draw/teardown partially, but stops on a
|
||||
frozen predicate rejecting reused node addresses; no natural transaction timeout
|
||||
or held/live PNG. Final independent review is ACCEPTED / audit PASS for experimental evidence
|
||||
fidelity. Publication is authorized and prepared, not executed at this edition;
|
||||
final refs belong to the private closeout and final handoff. STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
||||
| Report | Scope and retained limits |
|
||||
| --- | --- |
|
||||
| [Targeted scale/popup gate](design/STEP20C_TARGETED_SCALE_AND_POPUP_GATE.md) | Own A/G scale1.25 grabs/pixels/input, sampled FEASIBLE; association bounded |
|
||||
| [Targeted saved lifecycle](design/STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md) | Real held configure; C3 creation/draw/teardown partial; timeout/held PNG/GPU lifetime unqualified, INCONCLUSIVE |
|
||||
| [Targeted effects/cache diagnosis](design/STEP20C_TARGETED_EFFECTS_CACHE_DIAGNOSIS.md) | Classic EXERCISED, whole-H1 FAIL, GPU attribution INCONCLUSIVE |
|
||||
| [Targeted input/native ordering](design/STEP20C_TARGETED_INPUT_NATIVE_ORDERING.md) | Focus/camera mutation during click; 789/821 final paired, no atomic generation |
|
||||
| [Release-shape extended matrix](design/STEP20C_RELEASE_SHAPE_EXTENDED_MATRIX.md) | Exact-G dynamic/hidden/R90, residual neutrality and ABI/package/legal limits |
|
||||
| [Targeted closure decision](design/STEP20C_TARGETED_CLOSURE_DECISION.md) | Exact identities, 14-run matrix, risks and distinct lifecycle markers |
|
||||
| [Production decision draft](design/STEP20C_PRODUCTION_INTEGRATION_DECISION_DRAFT.md) | Twenty current questions; PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE |
|
||||
|
||||
Public evidence: [results README](../tooling/probes/step20c-targeted-results/README.md),
|
||||
[compact results](../tooling/probes/step20c-targeted-results/RESULTS.json) and
|
||||
[artifact hashes](../tooling/probes/step20c-targeted-results/ARTIFACTS.json).
|
||||
The 460 retained run artifacts include 125 output captures and three marker-source
|
||||
PNGs (128 PNG files total); source PNGs are not output captures. The [review supplement](../tooling/probes/step20c-targeted-results/REVIEW.json)
|
||||
is maintained separately by the parent. See the closure report for the exact private review
|
||||
paths/hashes, 43 offline tests, 22 rejected mutations and finalization limits.
|
||||
|
|
|
|||
|
|
@ -483,3 +483,30 @@ Production multi-output remains NOT YET SUPPORTED. No STEP20D work or production
|
|||
integration follows automatically from documentary publication. Final independent
|
||||
review is ACCEPTED / audit PASS for experimental evidence fidelity. Documentary
|
||||
publication is prepared, not executed at this edition.
|
||||
|
||||
## Targeted STEP20C handoff — 2026-10-14
|
||||
|
||||
The [targeted closure](design/STEP20C_TARGETED_CLOSURE_DECISION.md) advances
|
||||
private scale/popup and release-shape output evidence, actually exercises
|
||||
classic blur and obtains a held configure on A/G. It preserves whole-H1 effects
|
||||
FAIL, incomplete saved/input measurements and INCONCLUSIVE terminal IPC outcomes.
|
||||
The recommendation remains PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE.
|
||||
|
||||
C3 is a consumed distinct diagnostic with INCONCLUSIVE runtime and partial
|
||||
native saved creation/draw/teardown observations. Its frozen unique-address
|
||||
predicate rejects actual node-address reuse; no fixture repair or retry follows.
|
||||
Natural transaction timeout, held/live PNG, normal close and GPU completion are
|
||||
unqualified. The final campaign is 14 runs/125 PNG/520 reserved events; independent
|
||||
review is ACCEPTED for experimental evidence fidelity, without closing production
|
||||
gates. Remaining smallest gates
|
||||
are saved/native lifetime, input mutation
|
||||
measurement and bounded native GPU discrimination, followed by relevant
|
||||
transaction/damage/neutrality and exact-pair/package/legal/maintenance closure.
|
||||
Any further runtime or production change requires its own accepted scope and
|
||||
budget. Popup UX remains undecided; canonical contracts precede any eventual
|
||||
implementation. Final independent dossier review is ACCEPTED / audit PASS for experimental
|
||||
evidence fidelity. Publication is authorized and prepared, not executed at this
|
||||
edition; final refs belong to the private closeout and final handoff.
|
||||
STEP20A DONE; STEP20B EXPERIMENTAL; STEP20C NEXT; STEP20D–G PLANNED. Production
|
||||
multi-output NOT YET SUPPORTED; documentary publication does not authorize
|
||||
integration or STEP20D.
|
||||
|
|
|
|||
|
|
@ -1,109 +1,85 @@
|
|||
# STEP20C — décision d’intégration production, draft
|
||||
|
||||
> EXPERIMENTAL — édition documentaire du 2026-10-14, après revue finale ACCEPTED / audit PASS du dossier expérimental ; publication préparée, non exécutée à cette édition. Les résultats concernent des laboratoires privés ; aucune intégration production, installation ou décision UX. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Les anciens rapports restent historiques et leurs résultats ne se transfèrent pas à un nouveau SHA.
|
||||
> EXPERIMENTAL — mise à jour ciblée du 2026-10-14. Revue finale indépendante du nouveau dossier : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. C3 exécuté : INCONCLUSIVE, observations natives partielles sans transfert à A/G. Les verdicts historiques restent inchangés. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB ci-dessous sont des références locales de preuve, pas des fichiers distribués. Les sources de fixture préservées se trouvent dans [tooling/probes/step20c-overnight](../../tooling/probes/step20c-overnight/qualification/README.md). La [provenance compacte](../../tooling/probes/step20c-overnight/qualification/provenance.json) lie les identités et reçus sans publier logs, images, binaires, archives ou patches candidats.
|
||||
La recommandation reste **PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE**. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) lie les quatorze runs ciblés, les identités exactes et leurs risques à LAB `/home/fy59/swayfx-mosaic-targeted-7gge6h8b`. L’ancien LAB `/home/fy59/swayfx-mosaic-overnight-mcolx0gq` reste en lecture seule, PARTIALLY_ADVANCED, 18 runs/196 captures. Les [fixtures](../../tooling/probes/step20c-targeted/README.md) sont des sources scellées, pas des résultats de production. Les vingt réponses ci-dessous enregistrent l’évidence disponible, sans auto-approbation.
|
||||
|
||||
## Recommandation soumise, non appliquée
|
||||
## 1. G est-il qualifié au-delà du smoke horizontal ?
|
||||
|
||||
**PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE**. L’état global proposé est PARTIALLY_ADVANCED, sous réserve de publication observée, jamais PRODUCTION_READY. Aucun défaut P0 clip/input confirmé dans le scope mesuré, mais les gates lifetime, damage/transactions, effets, ABI-maintenance, packaging/notices et politique humaine restent ouverts. L’issue globale scientifique est PARTIALLY_ADVANCED ; ce draft ne décide pas une intégration et n’autorise ni distribution ni STEP20D.
|
||||
Oui, pour de nouveaux échantillons sur son propre SHA `8063478b2d5948da3eb8b1a329978882dc1d045cf36932cc2145a78af20ba76a`, build ID `83896fdb36f3fd21522becec0e8c5219e15f4b8e` : scale, FX, input, saved, dynamic, hidden, R90. [Matrice G](STEP20C_RELEASE_SHAPE_EXTENDED_MATRIX.md) : dynamic PARTIALLY_FEASIBLE, hidden/R90/scale FEASIBLE échantillonné ; saved/input restent incomplets, whole-H1 FX FAIL. Aucun all-matrix PASS et aucun résultat A transféré.
|
||||
|
||||
Les réponses sont liées aux [matrices exactes](STEP20C_ANNOTATED_GRAPHICS_MATRIX.md), au [build/stage](STEP20C_ANNOTATED_REBUILD_AND_PRIVATE_STAGE.md) et aux [limites lifecycle](STEP20C_LIFECYCLE_EFFECTS_AND_NATIVE_ORDERING.md). Elles distinguent preuve locale et contrat futur.
|
||||
## 2. Le scale 1,25 est-il réel avec input et grabs ?
|
||||
|
||||
## 1. Le nouveau binaire annoté est-il réellement qualifié?
|
||||
Oui. [A/G séparément](STEP20C_TARGETED_SCALE_AND_POPUP_GATE.md) : mode physique1000×750, logique800×600, scale1,25, markers PNG, deux vrais grabs35/44, root/nested franchissant x=0, B visible livré, bouton interdit non livré/dismissal et H2 entier exact. Neuf PNG/quatre clics par run ; association bornée source, pas de join natif host/owner ID. Retour standard NOT EXERCISED dans cette allocation. Runtime brut INCONCLUSIVE sur IPC terminal1.
|
||||
|
||||
A est qualifié localement pour source/build/model/ELF/stage et possède ses propres mesures graphiques C/D/E/F. FEASIBLE pour C horizontal ; PARTIALLY_FEASIBLE globalement. Ni qualification production complète ni READY.
|
||||
## 3. Un saved buffer réel a-t-il été observé ?
|
||||
|
||||
## 2. Quelles matrices ont été exercées?
|
||||
Un nouveau configure réel tenu sans ACK est prouvé sur A/G : ACK 30 puis serial 39,636×573→636×513, HELD_WIRE_VALIDATED. Cela établit le trigger et le hold client ; [identité native saved-node/render](STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md) NOT OBSERVABLE dans ces deux runs. Les anciens saved nodes d’autres binaires restent historiques. C3 distinct observe un saved node réel créé après gaps, sa référence source et un draw H1 ; le prédicat figé unique unreused saved node rejette l’adresse réutilisée. Création/rendu/teardown partiellement observés, runtime INCONCLUSIVE, sans transfert à A/G.
|
||||
|
||||
18 runs uniques : C0/C1/C2 horizontal négatif ; D1 vertical pair ; D2 scale1,25 pair ; D3 R90/1,25 pair ; D4 resize/migration pair ; E1 hide/return ; E2 saved trigger ; E3 effets/cache pair ; F regions/ordering pair ; G smoke. Les limites et actions non exercées restent explicites dans la matrice.
|
||||
## 4. Son clipping est-il correct ?
|
||||
|
||||
## 3. Quels contrôles pristine sont disponibles?
|
||||
Il n’est pas qualifié par les nouveaux saved-A/G : chacun s’arrête après deux références H2 sur le champ workspace IPC gaps absent. Aucun PNG pendant hold/timeout, aucun saved render natif lié. Saved clipping INCONCLUSIVE, sans FAIL produit démontré et sans PASS rétroactif. C3 observe draw/intersection héritée sur H1 mais aucun PNG held/live ou contrôle H2 pendant hold : clipping INCONCLUSIVE. Les preuves saved historiques ne se transfèrent pas aux SHA A/G ou C3.
|
||||
|
||||
C0 et D1/D2/D3/D4/E3/F pristine réellement exécutés sur le SHA retenu. C0/C1 full RGB égal aux huit états homologues ; D2/D3 markers et spill/input ordinary effectifs. Pristine F non modifié ne porte aucune PI privée. Ces contrôles ne qualifient pas un autre SHA.
|
||||
## 5. Le lifetime est-il prouvé ou partiellement observé ?
|
||||
|
||||
## 4. Quels résultats restent partiels?
|
||||
L’audit natif est SOURCE_AUDIT_ONLY : création d’un nœud saved distinct, référence wlr_buffer lockée, destruction/unlock et réactivation live. Les runs FX ont normal close/error0/releases SHM avant compositeur ; saved-A/G terminent error32 pendant teardown malgré processus 0. C3 trace locks 3→4 puis destruction/release/destroy au teardown seulement ; owner error32/code0, sans timeout naturel ni normal close. Son découpage create→next destroy reste descriptif, sans génération native inventée. Lifetime complet buffers/textures/cache/GPU et commit rejeté NOT PROVEN. Cleanup mécanique, scientifique et lifetime restent distincts.
|
||||
|
||||
D2-Mosaic association root ambiguë avant input/final ; E2 saved NOT EXERCISED ; E3 full-H1 return FAIL dans les deux contrôles, classic NOT EXERCISED ; F géométrie fixture périmée et suite non exercée ; G horizontal smoke seul ; ABI future/notices/legal/package complets non qualifiés.
|
||||
## 6. Le classic blur a-t-il vraiment filtré l’image ?
|
||||
|
||||
## 5. Existe-t-il un défaut bloquant de clipping ou d’input?
|
||||
Oui dans pristine/A/G : [4096 pixels](STEP20C_TARGETED_EFFECTS_CACHE_DIAGNOSIS.md) de ROI centrale prospective changent à source SHM constante, contraste adjacent12,783069→0,090278. Fond haute fréquence XRGB, filler transparent et verre prémultiplié0x88442010 sont retenus. EXERCISED ; l’ancien filler opaque explique les anciens pixels uniformes selon source audit seulement, bytes historiques absents.
|
||||
|
||||
Aucun défaut bloquant démontré dans les fenêtres échantillonnées C/D1/D3/D4/E1/G. D2/F stops sont expliqués par le fixture, sans PASS rétroactif. Cela ne prouve pas l’absence universelle de défaut.
|
||||
## 7. La restauration A/B/A passe-t-elle sur H1 entière ?
|
||||
|
||||
## 6. Existe-t-il un risque de lifetime non résolu?
|
||||
Non. Sans masque ni ROI opportuniste : FAIL 37252 pixels pristine/34323 A/G, max 6, signes natifs non positifs ; bbox pristine[400,0,800,600], A/G[480,0,800,600]. Centre exact et source A 1/A 3 byte-exact ne changent pas ce verdict. Le modèle donne68969 pixels history/0 fresh mais signe positif max 33 différent du natif négatif max 6 ; causalité native INCONCLUSIVE.
|
||||
|
||||
Oui : identité native buffers, locks/références/releases GPU/saved, teardown exhaustif et scénarios de commit rejeté ne sont pas prouvés. Cleanup PID propre est une preuve de processus, pas de lifetime GPU. G garde FBO bind-before-failed potentiellement non passif.
|
||||
## 8. Les différences sont-elles communes au pristine ?
|
||||
|
||||
## 7. Quel est l’état réel du damage?
|
||||
Oui, le nouveau pristine reproduit le retour whole-H1 imparfait. Les géométries visibles pristine/Mosaic diffèrent, donc les comptages ne démontrent pas une régression clip. Les seize captures A/G homologues sont RGB exactes et état/source normalisés égaux. Cela réduit une hypothèse visible propre aux traces A ; la causalité GPU et la neutralité temporelle restent NOT PROVEN.
|
||||
|
||||
Échantillons et traces extents conservés, H2 exact dans les états citées ; whole-H1 A-return effets échoue dans les deux contrôles. Damage exhaustif, minimal, stale pixels intermédiaires et contenu exact présenté NOT PROVEN.
|
||||
## 9. L’input suit-il l’origine appliquée après les mutations ?
|
||||
|
||||
## 8. Quelle est la portée des preuves de transactions?
|
||||
Les observations obtenues sont cohérentes avec la dernière origine native. Au troisième clic A/G : globale(-314,30), origine pré-capturée(-318,25), dernière native(-638,25), motion(324,5), boutons45/46 livrés. La camera change via focus pendant clic ; [fixture ambigu](STEP20C_TARGETED_INPUT_NATIVE_ORDERING.md), suite camera/layout NOT EXERCISED. Pristine contrôle standard complet ; aucune panne produit ni atomicité démontrée.
|
||||
|
||||
Source applied clip et callbacks échantillonnés, regions full/empty/full observées. Sur12 couples initiaux F,10 PAIRED/2 MISSING_PRESENT ;57 commits bruts. Pas d’epoch atomique ni de fenêtre naturelle discriminante ni d’identité pixels/hit/present complète.
|
||||
## 10. Les couples commit/present sont-ils correctement corrélés ?
|
||||
|
||||
## 9. Le candidat release-shape existe-t-il?
|
||||
Le replay utilise (output, commit_seq). Total final 14 runs : 821 commits,789 paired,32 missing (treize initiaux788/758/30 ; C3 ajoute 33/31/2) ; pristine PI NOT OBSERVABLE. F historique complet : 57 commits, 55 paired, 2 missing(seq 2 H1/H2), sans réécrire son ancien sous-ensemble 10/12. Le pairage correct ne lie pas contenu/pixels/GPU ; fenêtre naturelle mutation entre matching commit/present NOT EXERCISED.
|
||||
|
||||
Oui, G privé source/build/stage exact existe, SHA8063478b2d5948da3eb8b1a329978882dc1d045cf36932cc2145a78af20ba76a, build ID83896fdb36f3fd21522becec0e8c5219e15f4b8e. Aucun candidat binaire/package public distribué.
|
||||
## 11. Quels buffers sont réellement identifiés ?
|
||||
|
||||
## 10. Son comportement est-il testé ou seulement compilé?
|
||||
Les buffers SHM client/wire, dimensions et dumps sources sont identifiés dans leur espace propre. Les callbacks output portent output/commit_seq ; A FX identifie un pointeur cache/FBO choisi, sans readback contenu. A/G n’identifient pas un saved-node/buffer GPU avec locks/releases ni l’image exacte présentée. C3 identifie un nœud/source dans l’intervalle descriptif de sa création à la prochaine destruction et un draw, sans identité de génération ou preuve GPU completion. wl_buffer release, saved node, texture/cache, output-state buffer, present et fin GPU restent distincts.
|
||||
|
||||
G est buildable et possède un smoke propre17 PNG/8 clics/4 grabs/retour splith, indépendamment revu. SMOKE_FEASIBLE horizontal seulement ; matrice G étendue et neutralité complète NOT TESTED/NOT PROVEN.
|
||||
## 12. Quelles preuves de damage restent insuffisantes ?
|
||||
|
||||
## 11. Quels patches fonctionnels doivent être conservés?
|
||||
Les captures stabilisées et traces disponibles restent échantillonnées. Le nouvel audit `parent/damage-envelopes.json` compare99 transitions d’images adjacentes entières des treize runs initiaux : 18 différences contenues dans des enveloppes physiques A, 79 NOT OBSERVABLE(trace absente/intervalle vide), deux changements de dimensions NOT COMPARABLE. Une enveloppe extents ne prouve pas région exacte/minimale, tous frames/stale pixels, ni liaison à un buffer présenté ou génération atomique.
|
||||
|
||||
Dans le candidat privé : subtree clip SceneFX, clip owner-derived popup, guard owner totalement caché et delta natif Mosaic. Les commentaires token-equivalent sont acceptés. Une extraction de production exige encore revue exacte source/ownership/lifetime et décision, sans appliquer ces patches maintenant.
|
||||
## 13. Quel risque d’instrumentation résiduelle demeure dans G ?
|
||||
|
||||
## 12. Quels patches de trace peuvent être retirés?
|
||||
PI listeners, traversées scène/owner/popup, clocks et logs restent ; logging peut bloquer/allouer.26 statements OPT/helpers retirés ne rendent pas G uninstrumented. FBO bind-before-failed reste différent de pristine ; failure semantics NOT TESTED.16 images A/G exactes limitent une différence visible dans le scope, neutralité timing/GPU INCONCLUSIVE. Audit/retrait et requalification futurs exigent budget distinct.
|
||||
|
||||
Seulement le retrait privé G déjà revu :26 logs/7 fichiers et helpers réellement orphelins. Timing/cache/PI ne se retirent pas en bloc sans audit ; PI listeners et FBO bind ordering restent. Aucun patch de production réécrit.
|
||||
## 14. Les tests graphiques G permettent-ils une revue d’intégration ?
|
||||
|
||||
## 13. Quelle ABI SceneFX est réellement qualifiée?
|
||||
Ils permettent une revue plus informée du candidat privé, pas une approbation production. Dynamic 14 PNG resize 960/back/migrationH1/H2/H1/input frais lorsque popup_done, hidden 12 PNG même chaîne/emptyclip/retourB, R90 neuf PNG 750×1000 physique/scale1,25/logique800×600/markers sont propres à G. Saved/input partiels, FX FAIL, lifetime/damage/génération ouverts. Revue finale indépendante du dossier ciblé ACCEPTED, audit PASS pour la fidélité expérimentale ; aucune approbation d’intégration production.
|
||||
|
||||
SceneFX0.5 statique exact local, ELF appels clip directs,17 structs/6 offsets/85 overlaps/34 diagnostic bindings. Pas une ABI externe stable, ni tous providers runtime, ni une ABI future ou full semantic safety.
|
||||
## 15. Quelles limites ABI persistent ?
|
||||
|
||||
## 14. Quelle paire wlroots est réellement qualifiée?
|
||||
Paire locale SceneFX 0,5 commit 37ccd723bef49e6891156ffafce8f549f01446cc / wlroots 0,20,2 commitd783533489e1f75d6886c2ab5c5960090ef268f8, libSHA7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837,121 headers vérifiés.17 structs/six offsets égaux, 85 overlaps caractérisés, 34 bindings dont31 vers executable/trois wlroots. Ni incompatibilité prouvée ni safety complète ; toutes autres paires NOT QUALIFIED. Maintenance projet approuvée privé, release/security à nommer.
|
||||
|
||||
Paire locale SceneFX37ccd723bef49e6891156ffafce8f549f01446cc + wlroots0.20.2 d783533489e1f75d6886c2ab5c5960090ef268f8, libSHA7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837 et121 headers épinglés. Tous autres builds/paires NOT QUALIFIED ; changement implique rebuild/requalification.
|
||||
## 16. Quels points packaging restent ouverts ?
|
||||
|
||||
## 15. La future recette Arch est-elle reproductible?
|
||||
Syntaxe, septchecksums, makepkg --printsrcinfo/--verifysource local, forwardchecks deux patches PASS ; stage privé exact cinq fichiers réguliers sans symlink, DT_NEEDED sans SceneFX shared. Fullmakepkgbuild NOT RUN, reproductibilité bit à bit NOT PROVEN. Inventories895/894 entrées, 894/893 chemins uniques ; doublons/testlog ne prouvent pas incorporation. Préprocesseur/extraction archive/notices exactes et revue juridique HUMAN_REVIEW_REQUIRED. PKGBUILD réel inchangé, aucune installation/distribution.
|
||||
|
||||
Inputs privés hashés, syntaxe shell/Python et sources PASS ; makepkg metadata/source verification/build NOT RUN. Pas de reproductibilité binaire bit à bit ni de paquet distribution publique validé. PKGBUILD.future ne modifie pas PKGBUILD réel.
|
||||
## 17. Quelles décisions UX popup restent nécessaires ?
|
||||
|
||||
## 16. Quels textes de licence restent à valider?
|
||||
Offscreen hide/dismiss/reposition et click-through sous grab restent UNDECIDED. Les comparaisons contrôlées et routing/dismissal échantillonnés ne définissent pas une règle universelle. Aucun changement docs/UX ni bindings/configuration personnelle ; Mosaic reste opt-in dans workspace Sway ordinaire.
|
||||
|
||||
Les quatre fichiers stage incluent LICENSE SceneFX/SwayFX/wlroots et INCORPORATED-NOTICES. Inventaires895 A/894 G conservateurs ; incorporation exacte, extraction archives et contributions conditionnelles puis suffisance juridique nécessitent validation humaine. Aucun legal PASS.
|
||||
## 18. Quels travaux exigent encore un changement de code ?
|
||||
|
||||
## 17. Qui devra assurer les releases et la sécurité?
|
||||
Le fixture input doit mesurer/autoriser la mutation pendant livraison ; la mesure saved exige un predicate IPC adéquat et observabilité native bornée. Un discriminant GPU nécessite readback FBO/cache/output natif autorisé. Un éventuel retrait résiduel G et l’intégration clip/owner guard exigent revue exacte et requalification. Aucun correctif de produit causal n’est établi par PNG seuls ; aucun code production n’est modifié ici. C3 est un travail privé distinct consommé, runtime INCONCLUSIVE : son prédicat d’adresse globalement unique est trop strict pour la réutilisation observée. Aucun fixture gelé réparé, aucune relance.
|
||||
|
||||
Responsabilité projet pour SceneFX embarqué déjà approuvée dans le périmètre privé ; release maintainer et security reviewer doivent être désignés avant distribution. Aucun nom ni SLA inventé. Veille, impact, rebuild, tests, notices et publication documentés comme procédure proposée.
|
||||
## 19. Quelle plus petite tranche production est éventuellement envisageable ?
|
||||
|
||||
## 18. Quelle politique popup UX reste à décider?
|
||||
Après décisions humaines et fermeture des gates pertinents seulement : clip natif optionnel, owner-popup/hidden guard et retour standard workspace-local, Row0 empruntant workspace->tiling. Contrats Architecture/UX/Packaging/Upstream/Development avant code, puis delta petit/revu/testé sur nouveau SHA. Tests build/model/headlessIPC/pristine et matrice pertinente, ABI/header/providers, stage/notices/package complet et patch export/apply/source-equivalence/checksum. Fallback standard SwayFX indépendant,/usr/bin/sway intact, sans provides/conflicts/replaces ni remplacement système/config ; déploiement/rollback décision distincte. Aucun STEP20D ni tranche autorisée ici.
|
||||
|
||||
Hide/dismiss/reposition de popup offscreen et comportement sous grab/click-through restent ouverts. Les observations de routing ne fixent pas une politique universelle. Aucun changement UX dans cette tranche.
|
||||
## 20. Quels risques imposent de différer toute intégration ?
|
||||
|
||||
## 19. Quelles corrections sont nécessaires avant une intégration dans main?
|
||||
|
||||
Nouveau fixture ciblé saved provoquant configure runtime attesté, diagnostic full-H1 effets avec contrôles, assertion input liée à géométrie appliquée, mesure lifetime/native refs/releases/temporal discriminante et neutralité G/FBO. Chaque gate pertinent doit avoir critères acceptés et nouvelle autorisation/budget ; aucun rerun dans le budget clos. Puis politiques humaines ABI/notices/release/security/UX, contrats canoniques avant code.
|
||||
|
||||
## 20. Quelle est la plus petite tranche de production envisageable après décision utilisateur?
|
||||
|
||||
Après décision humaine et gates pertinents clos seulement : clip natif optionnel dans workspace Sway ordinaire, Row0 empruntant workspace->tiling, owner popup clip et hidden-owner guard revus, restauration standard locale préservée. Contrats Architecture/UX/Packaging/Upstream/Development d’abord, puis petit delta revu/testé. Aucun STEP20D, ligne runtime additionnelle, animation ou taille finale ; aucune implementation ici.
|
||||
|
||||
## 21. Quels tests doivent impérativement être refaits après une intégration?
|
||||
|
||||
Nouveau exact SHA : compile/model/headless IPC et standard pristine, export cumulatif forward apply/source-equivalence/checksum, ELF/header/layout/providers/relocations, manifests stage/notices et package complet, toute matrice graphique C/D/E/F pertinente et smoke propre G, input/popups/grabs/retour standard, geometry scale/rotation/migration, saved/effects/damage/lifetime. Pas d’héritage automatique du LAB.
|
||||
|
||||
## 22. Quel plan de rollback protège SwayFX standard?
|
||||
|
||||
Proposition future : conserver package SwayFX et /usr/bin/sway indépendants, sélectionner sa session existante après quitter la candidate ; retirer seulement fichiers appartenant à Mosaic vérifiés. Aucun provides/conflicts/replaces, système lib/config/dotfiles remplacé. Déploiement et rollback nécessitent décision distincte, jamais exécutés ici.
|
||||
|
||||
## Conditions de décision
|
||||
|
||||
Ce dossier apporte un candidat et des preuves reviewables. La revue finale indépendante est ACCEPTED / audit PASS pour la fidélité de l’évidence expérimentale, sans adoption production. Publication documentaire préparée, non exécutée à cette édition. Publication des docs/fixtures et adoption en production sont des actes distincts ; le résultat réel et les SHAs finaux origin/github feront foi dans le reçu privé et le handoff final, sans faux hash futur dans ce draft.
|
||||
|
||||
## Revue finale observée et publication préparée
|
||||
|
||||
Revue indépendante finale ACCEPTED / audit PASS pour la fidélité du dossier expérimental : 0 BLOCKING, 4 NON_BLOCKING, 3 FUTURE_SCOPE ; 180 checks hors ligne et 15 mutations de preuves réelles rejetées. Rapport privé `reviews/overnight-final-review.md`, SHA256 `bb4000dffb51b07b59e86f91e8dd76bc2c4f0b9513b48a52c9f6bd6c8c3f45af` ; reçu JSON SHA256 `72ba252092ca3375d344faae1c2026c8d5626fd190e87771d5c0c1ad8212c9b0`. Index scientifique post-exécution `seals/index.json`, SHA256 `cdf034e1f8466a9ae8a0e0a33aa8d0d0195273f0d1bc782667b50c3bcf682505`, contexte de preuve courant, pas un binding pré-exécution.
|
||||
|
||||
NB-01 est complété dans l’index compact depuis les grabs wire réels de chacun des huit runs concernés, avec lignes et hashes sources dans `parent/metadata-serial-completion.json`. Les stops fixtures, échecs E3 et incident IPC restent documentés. Les gates lifetime/génération/damage, couverture G, maintenance ABI/paquet/juridique et robustesse/coût des sidecars privés restent ouverts. L’acceptation documentaire ne qualifie pas la production et n’applique aucune décision. Publication préparée, pas encore exécutée à cette édition ; les refs/SHAs finaux et le résultat de publication feront foi dans le reçu privé et le handoff final.
|
||||
P1 whole-H1GPU, lifetime saved/génération/damage, input temporel et couverture G ; P2 neutralité/ABI-maintenance, package/notices/legal, nominations, IPCterminal/attribution runtimepaths ; P3 sorties physiques plus larges. Aucun P0 prouvé. Les [risques sourcés](STEP20C_TARGETED_CLOSURE_DECISION.md) gardent critères de clôture et décisions humaines. C3 INCONCLUSIVE ; final review ACCEPTED, publication documentaire préparée/non exécutée à cette édition ; recommandation PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE, production NEXT/NOT YET SUPPORTED.
|
||||
|
|
|
|||
31
docs/design/STEP20C_RELEASE_SHAPE_EXTENDED_MATRIX.md
Normal file
31
docs/design/STEP20C_RELEASE_SHAPE_EXTENDED_MATRIX.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# STEP20C — matrice étendue release-shape
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. Le diagnostic C3 est exécuté : résultat INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST désigne `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB/HIST sont des artefacts externes locaux, pas des fichiers distribués. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) donne les identités exactes, la matrice des quatorze runs et les limites. Les sources de [fixture ciblé](../../tooling/probes/step20c-targeted/README.md) restent des entrées expérimentales ; elles n’ajoutent aucune dépendance de production. Les rapports historiques et leurs verdicts restent inchangés.
|
||||
|
||||
## Résultats graphiques propres à G
|
||||
|
||||
G possède son propre SHA et n’hérite d’aucun PASS de A. Le smoke horizontal historique reste historique ; les nouveaux runs sont scale-G, saved-G, FX-G, input-G et les trois cellules ci-dessous.
|
||||
|
||||
| Run G ciblé | PNG | Grabs wire A/B | Observations retenues | Verdict architecture |
|
||||
| --- | ---: | --- | --- | --- |
|
||||
| G-dynamic-G | 14 | 42/51 | resize 960 puis800, migration H1→H2→H1, quatre étapes et input frais | PARTIALLY_FEASIBLE |
|
||||
| G-hidden-G | 12 | 61/70 | même hiérarchie conservée, owner pleinement caché/clip vide/aucun enter, retour et clic B | FEASIBLE pour l’échantillon |
|
||||
| G-R90-G | 9 | 35/44 | transform R90 réel, mode physique750×1000, scale1,25, logique800×600, PNG1000×750/markers | FEASIBLE pour l’échantillon |
|
||||
|
||||
Le dynamique mesure de nouveaux clics toplevel lorsque `popup_done` a fermé la chaîne ; aucun popup n’est recréé. Il ne prouve pas une chaîne grabbed persistante durant chaque migration. R90 conserve B visible, exclusion du bouton interdit, dismissal et H2 final exact. Les mesures de ces trois runs sont PASS ; chaque résultat runtime reste INCONCLUSIVE (IPC terminal1), processus 0 et scientific cleanup PASS distincts. Standard return n’est pas exercé dans cette allocation. Les résultats saved/input/FX partiels figurent dans leurs rapports dédiés.
|
||||
|
||||
## Instrumentation résiduelle et ABI exacte
|
||||
|
||||
G a retiré26 statements OPT et des helpers orphelins ; il conserve listener commit, logs present, boucles scène/owner/popup et clocks. L’absence de nouveau lock/référence/allocation dans les callbacks PI est un audit source ; logging peut bloquer/allouer. `fx_framebuffer_bind(pass->buffer)` reste avant la branche failed, avec ordre différent de pristine. Cette neutralité est **INCONCLUSIVE**, pas garantie par les seize images A/G exactes.
|
||||
|
||||
La paire locale est SceneFX 0.5 commit `37ccd723bef49e6891156ffafce8f549f01446cc` et wlroots 0.20.2 commit `d783533489e1f75d6886c2ab5c5960090ef268f8`, bibliothèque SHA `7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837`. Les121 headers sont inchangés et chaque nouveau run possède ses propres maps. Aucune SceneFX shared séparée n’y est mappée. Les17 structs/six offsets égaux et85 exports chevauchants sont des checks nécessaires :34 bindings retenus, 31 vers l’exécutable/trois vers wlroots. Ils ne prouvent ni incompatibilité ni safety complète ; toutes autres paires **NOT QUALIFIED**.
|
||||
|
||||
## Package privé, notices et maintenance
|
||||
|
||||
LAB `parent/package-audit.json` rapporte `bash -n`, sept checksums, `makepkg --printsrcinfo`, `makepkg --verifysource` et `git apply --check` des deux patches PASS sur copies privées locales. Aucun réseau/install ; full `makepkg` build **NOT RUN**. Les stages A/G contiennent exactement cinq fichiers réguliers sans symlink : binaire mode755, quatre notices mode644 sous `/usr/share/licenses/swayfx-mosaic/`. DT_NEEDED ne contient pas SceneFX shared. Le PKGBUILD courant reste inchangé ; aucune distribution n’est validée.
|
||||
|
||||
LAB `parent/abi-maintenance.json` vérifie les hashes de notices et inventories conservateurs895/894 entrées A/G, 894/893 chemins uniques (un doublon chacun). `testlog.junit.xml` recensé est un résultat de test, pas du code incorporé. Sept C changent A/G et `opt_probe.h` est retiré ; cette comparaison ne prouve pas l’incorporation exacte par préprocesseur ni les membres réellement extraits des archives. Suffisance des licences : **HUMAN_REVIEW_REQUIRED**.
|
||||
|
||||
La responsabilité projet SceneFX embarqué est déjà approuvée pour le candidat privé. Release maintainer et security reviewer restent à nommer, sans noms/SLA inventés. Avant distribution : veille/impact des fixes, pins source+hash, rebuild paire exacte, tests ABI/graphique/lifetime/clip/damage, notices et stage, puis décision distincte de publication. Standard SwayFX reste indépendant et fallback ; aucun système d’update, dépendance ou politique d’installation nouveau n’est adopté. Ces gates prolongent le contrat privé existant sans modifier Packaging/Upstream/Development.
|
||||
149
docs/design/STEP20C_TARGETED_CLOSURE_DECISION.md
Normal file
149
docs/design/STEP20C_TARGETED_CLOSURE_DECISION.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# SWAYFX_MOSAIC_STEP20C_TARGETED_CLOSURE_DECISION
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. C3 exécuté : INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
## Recommandation et autorité
|
||||
|
||||
**PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE** reste la recommandation, non une décision appliquée. L’évidence ciblée avance plusieurs cellules privées, mais les gates saved/lifetime, génération/damage, restauration GPU, input temporel, neutralité, ABI maintenue et distribution restent ouverts. L’état scientifique global reste **PARTIALLY_ADVANCED** ; aucun READY/PRODUCTION_READY n’est revendiqué.
|
||||
|
||||
LAB = `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST = `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`, lecture seule. Ces répertoires privés contiennent images, logs, maps, binaires, archives et reçus non distribués. Les [sources ciblées](../../tooling/probes/step20c-targeted/README.md) sont un protocole scellé, pas un compte rendu post-exécution. Les résultats sont consignés ici, séparément des sources figées.
|
||||
|
||||
Le closeout historique SHA `dba268a6aa415bd07c26371ec1ba9e66e4b54b5b51bd24ae05bd1d281bd27a3a` et son manifeste primaire `cdf034e1f8466a9ae8a0e0a33aa8d0d0195273f0d1bc782667b50c3bcf682505` ont été revalidés :6138 entrées PASS, 18 runs uniques/196 captures. Le résultat historique reste PARTIALLY_ADVANCED ; aucun rapport ancien n’est corrigé rétroactivement. Le point de départ documentaire est main `30dc3182`, initialement identique à origin/github.
|
||||
|
||||
## Identités exactes
|
||||
|
||||
| Binaire | SHA256 exécutable | Build ID |
|
||||
| --- | --- | --- |
|
||||
| A annoté | `979dcd95ab43fa1e465d6e9d262485b73d186cedacd0f957059dd24f482ce6f4` | `fabfeb823754a0f5107f83eb077323ad17ddedd1` |
|
||||
| G release-shape | `8063478b2d5948da3eb8b1a329978882dc1d045cf36932cc2145a78af20ba76a` | `83896fdb36f3fd21522becec0e8c5219e15f4b8e` |
|
||||
| pristine | `8ac865481bc0487344210cd0e16d8e6c7655b29db887cd58ddc11b0ca22fe494` | `298a9626b331139ff2f081ade9c4efdde2d4fb19` |
|
||||
|
||||
Chemins réels : A `HIST/stage-static/usr/bin/swayfx-mosaic`, G `HIST/release-shape/stage-static/usr/bin/swayfx-mosaic`, pristine `/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n/pristine-build/sway/sway`. Aucun binaire n’a été reconstruit pour les treize runs. Chaque run retient argv et `proc-maps.txt`, hash du binaire et bibliothèque wlroots exacte. Aucun objet SceneFX partagé distinct n’est revendiqué. C3 possède un build/stage distinct, LAB `diagnostic/build-stage.json`, SHA `9c0dc0e94ccc7fcbd7a6cddf14e90f1bb7b7bf385a0740e85ec7d0e1c1c1e705`, build ID `67a4bcb6a37e8ec691a0da5099d12275429a7076`. Son runtime est INCONCLUSIVE après rejet du prédicat d’adresse unique ; création/rendu/teardown sont partiellement observés, sans transfert à A/G.
|
||||
|
||||
## Matrice unique des quatorze runs
|
||||
|
||||
Tous les outcomes runtime bruts sont **INCONCLUSIVE**, terminal IPC exit1, tous les codes des processus enregistrés0, reaped/runtime_removed vrais, aucun rescue/watchdog. Ces faits mécaniques ne remplacent pas le scientific cleanup. Les comptes PNG proviennent du registre réel, y compris les captures réservées sur les runs interrompus. `native` = commits/paired/missing ; `budget` = captures réservées/plafond local, puis nombre total de réservations d’action. Tous les détails et hashes d’artefacts proviennent de LAB `parent/run-summary.json` (treize initiaux), les plafonds et actions de `budget.json`. Le résumé final et C3 sont LAB `parent/run-summary-final.json` et `parent/c3-observations.json`.
|
||||
|
||||
| Run / binaire | PNG / budget / actions | Géométrie et grabs | Input observé | native | Mesure ; architecture | Scientific cleanup |
|
||||
| --- | --- | --- | ---: | --- | --- | --- |
|
||||
| `FX-A` / A | 16 / 16/16 / 61 | H1 -800,800×600 ; 0 grab | 0 | 81/77/4 | PARTIALLY_FEASIBLE ; PARTIALLY_FEASIBLE | PASS |
|
||||
| `FX-G` / G | 16 / 16/16 / 61 | H1 -800,800×600 ; 0 grab | 0 | 80/76/4 | PARTIALLY_FEASIBLE ; PARTIALLY_FEASIBLE | PASS |
|
||||
| `FX-pristine` / pristine | 16 / 16/16 / 57 | H1 -800,800×600 ; 0 grab | 0 | 0/0/0 | PARTIALLY_FEASIBLE ; PARTIALLY_FEASIBLE | PASS |
|
||||
| `G-R90-G` / G | 9 / 9/10 / 35 | H1 -800 ; R90 physique750×1000 scale1,25 ; 35/44 | 4 | 80/78/2 | PASS ; FEASIBLE | PASS |
|
||||
| `G-dynamic-G` / G | 14 / 14/14 / 50 | H1 -800,800×600→960→800 ; H1/H2/H1 ; 42/51 | 6 | 119/113/6 | PASS ; PARTIALLY_FEASIBLE | PASS |
|
||||
| `G-hidden-G` / G | 12 / 12/12 / 45 | H1 -800,800×600 ; 61/70 | 4 | 91/89/2 | PASS ; FEASIBLE | PASS |
|
||||
| `input-A` / A | 5 / 5/12 / 26 | H1 -800,800×600 ; 0 grab | 3 | 58/56/2 | INCONCLUSIVE ; PARTIALLY_FEASIBLE | INCONCLUSIVE |
|
||||
| `input-G` / G | 5 / 5/12 / 26 | H1 -800,800×600 ; 0 grab | 3 | 59/57/2 | INCONCLUSIVE ; PARTIALLY_FEASIBLE | INCONCLUSIVE |
|
||||
| `input-pristine` / pristine | 8 / 8/12 / 32 | H1 -800,800×600 ; 0 grab | 4 | 0/0/0 | INCONCLUSIVE ; FEASIBLE standard (PI NOT OBSERVABLE) | PASS |
|
||||
| `saved-A` / A | 2 / 2/10 / 19 | H1 -800,800×600 ; 0 grab | 0 | 31/29/2 | INCONCLUSIVE ; INCONCLUSIVE | INCONCLUSIVE (error32 après teardown) |
|
||||
| `saved-G` / G | 2 / 2/10 / 19 | H1 -800,800×600 ; 0 grab | 0 | 31/29/2 | INCONCLUSIVE ; INCONCLUSIVE | INCONCLUSIVE (error32 après teardown) |
|
||||
| `scale-A` / A | 9 / 9/12 / 35 | H1 -800 ; physique1000×750 scale1,25 ; 35/44 | 4 | 79/77/2 | PASS ; FEASIBLE | PASS |
|
||||
| `scale-G` / G | 9 / 9/12 / 35 | H1 -800 ; physique1000×750 scale1,25 ; 35/44 | 4 | 79/77/2 | PASS ; FEASIBLE | PASS |
|
||||
| `saved-diagnostic-A` / C3 | 2 / 2/10 / 19 | H1 -800,800×600 ; 0 grab ; HELD39 | 0 | 33/31/2 | INCONCLUSIVE ; lifecycle partiellement observé, clipping INCONCLUSIVE | INCONCLUSIVE (error32 après teardown) |
|
||||
|
||||
Total : **14 runs uniques, 125 captures, 520 événements réservés**. Les treize runs initiaux représentent 13/123/501, le C3 consommé ajoute 1/2/19. Campagnes scale 2/18, saved 3/6, FX 3/48, input 3/18, G 3/35. Aucun retry/remboursement ; le budget accepte au plus 14 tentatives et 174 PNG, le diagnostic a été consommé sous son binding séparé. La durée de mesure réelle va de 3,045 à 9,172 s, watchdog 143 s/cleanup 150 s ; elle ne constitue pas une couverture temporelle exhaustive. Les chemins individuels de runtime des treize runs initiaux n’ont pas été conservés ; C3 retient son runtime privé `/tmp/m20-75jrtuws` et ses sockets dans son reçu ; aucun PID probe ni socket LAB ou `/tmp/m20-*` restant n’a été trouvé, et les répertoires temporaires non attribuables restent intacts.
|
||||
|
||||
Le validateur runtime indépendant en lecture seule, LAB `reviews/runtime-validation-13.{md,json}`, rapporte **PASS 681 checks** sur les treize runs initiaux, 469 bindings d’entrée/441 hashes d’artefacts et cinq commandes readelf. SHA script `97dc45cd4b606e1208c0a7671937c9b8a21c96425f45f94f165124ccb6443647`. Freeze `ba30fb2298b4ed9b11e807741541ce99b337e00d6086840ecac9714a55f927d5`, revue fixture `5843196534ab88188f0c9b942b4c28a7bd49b35fea9da82b19215125c3442747`. Validation des observations ne signifie pas PASS runtime ni clôture de production.
|
||||
|
||||
## Résultats discriminants et limites
|
||||
|
||||
- [Scale/popups](STEP20C_TARGETED_SCALE_AND_POPUP_GATE.md) : chacun A/G possède deux vrais grabs, A et B franchissant x=0, B visible délivré, B interdit non délivré/dismissal, H2 entier exact. Association source bornée ; pas de join natif host/owner ID ni retour standard dans cette allocation.
|
||||
- [Saved lifecycle](STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md) : configure 39 tenu après ACK 30,636×573→636×513 prouvé, mais fixture champ IPC absent ; timeout/held PNG/native saved IDs/normal close non exercés. `error32` au teardown interdit scientific cleanup PASS. C3 distinct observe création/rendu/teardown partiels mais rejet d’identité par réutilisation d’adresse ; clipping INCONCLUSIVE.
|
||||
- [Effets/cache](STEP20C_TARGETED_EFFECTS_CACHE_DIAGNOSIS.md) : classique réellement filtrant ; whole-H1 retour FAIL 37252 pristine/34323 A/G, max 6. Les seize images A/G RGB exactes ; modèle history 68969/fresh 0 diverge du signe natif. Causalité GPU INCONCLUSIVE.
|
||||
- [Input/ordre](STEP20C_TARGETED_INPUT_NATIVE_ORDERING.md) : contrôle pristine terminé ; A/G caméra change durant troisième clic, coordonnées wire égales à dernière origine native. Suite input arrêtée ; aucune panne produit ou atomicité démontrée.821 commits/789 paired/32 missing au total final (treize initiaux : 788/758/30), pas d’identité buffer/pixels commune.
|
||||
- [G/ABI/package](STEP20C_RELEASE_SHAPE_EXTENDED_MATRIX.md) : nouveaux runs dynamiques/caché/R90 propres à G ; neutralité résiduelle INCONCLUSIVE. Stage privé exact cinq fichiers, metadata/source verification/patch checks PASS ; full package build NOT RUN, droit de distribution HUMAN_REVIEW_REQUIRED.
|
||||
|
||||
## C3 consommé, stop fixture conservé
|
||||
|
||||
Le C3 dure3,682s et s’arrête sur bounded wait, jamais sur timeout naturel de
|
||||
transaction. Le prédicat frozen `unique unreused saved node` rejette une adresse
|
||||
réutilisée : une tree owner 10 antérieure à gaps puis une nouvelle tree owner 10
|
||||
après gaps. Le held39 reste réel. La nouvelle création source-buffer/saved-node,
|
||||
locks 3→4, draw H1/intersection héritée puis destruction/release/destroy au
|
||||
teardown sont observés. Le découpage offline create→next destroy est descriptif,
|
||||
sans génération native inventée. Owner EXIT error32/code0 ; scientific cleanup
|
||||
INCONCLUSIVE, aucune capture held/live ou H2 held, normal close/timeout
|
||||
NOT EXERCISED. Voir le [détail saved lifecycle](STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md).
|
||||
Clipping INCONCLUSIVE, lifetime GPU NOT PROVEN, aucun transfert à A/G.
|
||||
|
||||
## Damage hors ligne, observation bornée
|
||||
|
||||
LAB `parent/damage-envelopes.json` rapporte 99 comparaisons de captures
|
||||
adjacentes par output sur les treize runs initiaux, RGB entier sans masque : 18 différences contenues dans
|
||||
l’union d’enveloppes physiques A ; 79 NOT OBSERVABLE (trace absente ou intervalle
|
||||
vide) ;deux changements de dimensions NOT COMPARABLE. Le source audit distingue
|
||||
les damage extents, `scene_output_damage`, le buffer soumis et le present natif.
|
||||
Les unions couvrent un intervalle large entre captures ; elles ne démontrent ni
|
||||
région exacte pixman/minimale, ni chaque frame, ni contenu du buffer présenté.
|
||||
Résultat PARTIALLY_FEASIBLE pour l’observation, complete damage NOT PROVEN.
|
||||
|
||||
## Risques et conditions de clôture
|
||||
|
||||
La priorité exprime le risque de qualification, pas une panne prouvée. Pour chaque ligne, la source et le reproducer sont les artefacts privés et sources hashées de la campagne ; aucun problème sans preuve n’est classé P0.
|
||||
|
||||
| ID / priorité | Observation et source reproductible | Binaire / conditions | Impact | Reste à faire et dépendance de clôture / décision humaine |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| R00 / P0 | aucun défaut P0 clip/input démontré ; runtime-validation13 | A/G, échantillons headless | absence de preuve universelle | conserver gates ouverts ; aucune adoption automatique |
|
||||
| R01 / P1 | whole-H1 RGB FAIL ; FX diagnosis/source/dumps | pristine/A/G, ABA optimisé | restauration GPU non qualifiée | readback natif borné et interprétation revue ; nouveau budget GPU autorisé |
|
||||
| R02 / P1 | error32 ; saved logs/native-lifetime audit | A/G, held39, teardown avant timeout | lifetime saved/GPU non prouvée | C3 distinct : création/rendu/teardown partiels, prédicat adresse unique rejeté ; timeout/held pixels/normal close et lifetime GPU non clos, revue sans transfert |
|
||||
| R03 / P1 | commits/paired/missing ; native audit | A/G, headless | génération atomique/damage exhaustif non prouvés | fenêtre discriminante, buffers/pixels/hit liés, tous frames ; contrat temporel à décider |
|
||||
| R04 / P1 | origine change durant click ; input logs | A/G, fullrestore/focus | fixture temporel et couverture input incomplets | mesurer mutation pendant livraison et suite camera/layout ; nouvel essai autorisé |
|
||||
| R05 / P1 | saved/input G partiels ; propres outcomes | G SHA exact | couverture release-shape incomplète | exact-SHA saved/lifetime/input, autres chemins pertinents ; pas de PASS A transféré |
|
||||
| R06 / P2 | PI loops/listeners/logs et FBO bind-before-failed ; ABI audit | G versus pristine | neutralité timing/failure indéterminée | audit/retrait privé mesuré et requalification ; budget distinct |
|
||||
| R07 / P2 |85 overlaps/34 bindings, 17 structs/six offsets/121 headers | paire SceneFX 0,5/wlroots 0,20,2 | maintenance/semantics ABI liées à paire | requalifier chaque changement ; responsable release/security à désigner |
|
||||
| R08 / P2 | notices895/894 entrées et stage5 ; package/ABI audit | A/G, copies privées | incorporation exacte/legal/package build non clos | exact preprocessing/archive extraction, full package build et revue juridique humaine |
|
||||
| R09 / P2 | aucun nom/SLA ; contrat privé existant | futur artefact distribué | suivi fixes non attribué | nominations release/security et politique publication distincte |
|
||||
| R10 / P2 | IPC terminal1 / runtime paths individuels absents ; validation13 | les 14 runs | résultat runtime et attribution cleanup bornés | transport robuste/receipt paths dans futur fixture ; préserver raw exit1 |
|
||||
| R11 / P3 | matrices physiques plus larges absentes ; dossiers historiques | autres backends/scales/transformations | généralisation non qualifiée | cellules pertinentes explicites NOT TESTED ; autorisation/budget séparés |
|
||||
|
||||
Popup offscreen hide/dismiss/reposition et click-through sous grab sont des décisions humaines encore ouvertes. La maintenance exacte de SceneFX, ses notices et la paire wlroots ont un contrat privé approuvé, mais aucun maintainer nommé ni avis juridique final. La première tranche de production éventuelle exige d’abord décisions, fermeture des gates pertinents et contrats canoniques Architecture/UX/Packaging/Upstream/Development, puis delta opt-in native clip/owner guard revu avec restauration standard workspace-local. Elle n’est pas autorisée ici et ne comprend aucun STEP20D.
|
||||
|
||||
La [provenance publique compacte](../../tooling/probes/step20c-targeted-results/RESULTS.json)
|
||||
est présente et vérifiée. Le [README des résultats](../../tooling/probes/step20c-targeted-results/README.md)
|
||||
explique sa portée ; le [manifeste d’artefacts](../../tooling/probes/step20c-targeted-results/ARTIFACTS.json)
|
||||
lie460 fichiers retenus. Ils comprennent125 captures output et trois PNG sources
|
||||
de markers, donc128 fichiers PNG ; les trois sources ne sont pas facturées comme
|
||||
captures output. Les plafonds de captures ne sont pas atteints. Les deux PNG C3
|
||||
sont des références H2, sans preuve de damage pendant hold ; les99 transitions
|
||||
de damage restent limitées aux treize runs initiaux.
|
||||
|
||||
## Revue indépendante et publication préparée
|
||||
|
||||
L’unique revue finale indépendante est **ACCEPTED**, audit PASS pour la fidélité
|
||||
et le gel de l’évidence expérimentale : zéro BLOCKING, un NON_BLOCKING (N-01,
|
||||
deux coquilles corrigées ici) et trois FUTURE_SCOPE. Elle rapporte43 tests hors
|
||||
ligne PASS (14 core, six FX,23 C3) et22 mutations additionnelles rejetées.
|
||||
Cette acceptation ne change aucun résultat runtime, scientifique ou de production.
|
||||
Rapport privé : `/home/fy59/swayfx-mosaic-targeted-7gge6h8b/reviews/targeted-final-review.md`,
|
||||
SHA256 `73f06404ccfaa985cd6e279e606debeb8899bd1dd9079c88fdf5a01be98354ec`.
|
||||
Reçu privé : `/home/fy59/swayfx-mosaic-targeted-7gge6h8b/reviews/targeted-final-review.json`,
|
||||
SHA256 `28f868a0d956e70290db0515f59404e9f930e7180a89e326bcabda9ff6ea47ae`.
|
||||
Le [supplément public de revue](../../tooling/probes/step20c-targeted-results/REVIEW.json)
|
||||
lie cette acceptation et les limites de sa finalisation administrative ; il est
|
||||
créé séparément par le parent. Les snapshots pré-review et leurs manifestes sont conservés.
|
||||
|
||||
La publication du dossier est autorisée et préparée, mais **non exécutée à cette
|
||||
édition**. L’état observé et les refs finales origin/github appartiendront au
|
||||
closeout privé LAB et à la restitution finale ; aucun SHA futur ou PASS de
|
||||
publication n’est inventé ici. Publication d’évidence et intégration/distribution
|
||||
production restent des actes distincts.
|
||||
|
||||
## Marqueurs de clôture à cette édition
|
||||
|
||||
| Marqueur | État et portée exacte |
|
||||
| --- | --- |
|
||||
| HISTORICAL_REPLAY | PASS, 6138 entrées/18 runs196 PNG, historique immuable |
|
||||
| FIXTURE_REVIEW | PASS/ACCEPTED indépendant pour les bytes des treize initiaux ; C3 possède son binding et sa revue préflight distincts |
|
||||
| OFFLINE_CORE | PASS 14 tests `offline-final.json` ; runtime NOT RUN par ces tests |
|
||||
| OFFLINE_FX | PASS 6 tests `fx-offline.json` ; runtime NOT RUN par ces tests |
|
||||
| TARGETED_REPLAY | PASS `replay-final.json`, données historiques réelles ; pas de nouveau runtime |
|
||||
| RUNTIME_VALIDATION_13 | PASS 681 checks de fidélité des preuves, aucun upgrade de résultat runtime |
|
||||
| TARGETED_MEASUREMENTS | PARTIALLY_ADVANCED ; FAIL entier FX et stops saved/input conservés |
|
||||
| RUNNER_EXIT | INCONCLUSIVE, 14 IPC terminal1 malgré tous processus 0 |
|
||||
| SCIENTIFIC_CLEANUP | PASS scope positif ; saved/input A/G et C3 INCONCLUSIVE, voir matrice |
|
||||
| OPTIONAL_C3 | BUILD/STAGE validés ; runtime/mesures INCONCLUSIVE, lifecycle partiellement observé, clipping INCONCLUSIVE |
|
||||
| FINAL_INDEPENDENT_REVIEW | ACCEPTED, audit PASS pour la fidélité expérimentale ; 0 BLOCKING,1 NON_BLOCKING,3 FUTURE_SCOPE ;43 tests et22 mutations rejetées |
|
||||
| PUBLICATION | Autorisée et préparée, non exécutée à cette édition ; refs finales dans closeout privé et restitution, aucun SHA futur inventé |
|
||||
| PRODUCTION_INTEGRATION | NOT AUTHORIZED ; STEP20C NEXT / NOT YET SUPPORTED |
|
||||
|
||||
Les checks et scripts runtime mentionnés sont des commandes **déjà enregistrées dans le LAB**. Cette tranche d’écriture ne les relance pas. La validation documentaire vérifie liens, cohérence des comptes/statuts et `git diff --check`. Ni commit/push, ni build/run/install/session live ne sont effectués par cette tranche.
|
||||
38
docs/design/STEP20C_TARGETED_EFFECTS_CACHE_DIAGNOSIS.md
Normal file
38
docs/design/STEP20C_TARGETED_EFFECTS_CACHE_DIAGNOSIS.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# STEP20C — diagnostic ciblé des effets et du cache
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. Le diagnostic C3 est exécuté : résultat INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST désigne `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB/HIST sont des artefacts externes locaux, pas des fichiers distribués. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) donne les identités exactes, la matrice des quatorze runs et les limites. Les sources de [fixture ciblé](../../tooling/probes/step20c-targeted/README.md) restent des entrées expérimentales ; elles n’ajoutent aucune dépendance de production. Les rapports historiques et leurs verdicts restent inchangés.
|
||||
|
||||
## Contrôles positifs et échec entier conservé
|
||||
|
||||
`FX-pristine`, `FX-A`, `FX-G` possèdent chacun seize PNG. Le fond XRGB haute fréquence, le filler ARGB transparent et le verre SHM connu, prémultiplié `0x88442010` (alpha 136, RGB 68/32/16), séparent l’effet du filtre de la composition alpha. Le classique est **EXERCISED** : 4096 pixels de ROI centrale prospective changent à source constante ; contraste adjacent 12,783069 → 0,090278. Les dumps sources A/B/A confirment A 1/A 3 byte-exacts. L’explication des anciennes images classiques uniformes par filler opaque est **SOURCE_AUDIT_ONLY** : les bytes SHM historiques n’ont pas été retenus.
|
||||
|
||||
| Retour optimisé A, image entière sans masque | pristine | A | G |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Pixels RGB différents | 37252 | 34323 | 34323 |
|
||||
| Bbox locale | [400,0,800,600] | [480,0,800,600] | [480,0,800,600] |
|
||||
| Delta maximal absolu | 6 | 6 | 6 |
|
||||
| ROI centrale prospective différente | 0 | 0 | 0 |
|
||||
|
||||
La restauration entière H1 est **FAIL** dans les trois variantes. Tous les deltas natifs sont non positifs (R/G jusqu’à -6, B -1). Aucun masque ni ROI choisi après observation ne remplace ce verdict. Les verres ont des domaines visibles différents pristine/Mosaic ; les comptages seuls ne démontrent pas une régression causée par le clip.
|
||||
|
||||
Les seize captures homologues A/G sont RGB exactes, sources SHM et géométrie/focus/état IPC normalisé également égaux. Cela réduit l’hypothèse d’un effet visible propre à la trace A dans ce scope ; cela ne prouve pas la neutralité temporelle ou GPU. Les optimizations ont leurs traces natives dans A seulement : commit background → dirty H1 → reconstruction [0,0,800,600], résultat1 → clear dirty → usage du même cache/FBO → output submit et damage plein. Les traces OPT de G/pristine sont **NOT OBSERVABLE** ; aucun événement A n’est extrapolé.
|
||||
|
||||
## Modèle, attribution et limite instrumentale
|
||||
|
||||
Le diagnostic hors ligne LAB `results/fx-diagnosis/DIAGNOSIS.md` et `diagnosis.json` emploie les noyaux fixes radius 5/trois passes, bilinéaire idéale/arrondi8 bits, état froid zéro sans fit. Le clamp sur texture entière donne68969 pixels dépendants de l’historique ; le clamp au domaine fraîchement écrit donne0. Le modèle produit des deltas positifs jusqu’à33, différents du natif négatif jusqu’à6. Cette divergence est conservée : causalité native **NOT PROVEN / INCONCLUSIVE**. Les tests `diagnose.py` et `verify.py` sont rapportés PASS pour187 hashes d’entrée, comptages indépendants, seize comparaisons A/G, ordre A et noyaux du modèle ; aucun runtime GPU n’a été exécuté par ce diagnostic.
|
||||
|
||||
L’observation manquante est le contenu natif des queues ping/pong, du domaine frais, du cache choisi et du buffer output. Une nouvelle escalade de calcul ne supplée pas cette observabilité ; le plus petit discriminant futur est un readback FBO borné lié au vrai buffer output, dans un nouveau budget autorisé. Aucun clamp production, changement ABI ou attribution P0 propre à Mosaic n’est justifié.
|
||||
|
||||
## Fermeture clients, ombres et damage
|
||||
|
||||
Dans les trois runs les neuf clients FX (glass/background/filler) sont explicitement fermés avant le compositeur ; codes 0/error0, callbacks SHM release réels et absence de nouveau commit après close sont conservés. H1 final est vide, H2 exact. Scientific cleanup PASS pour ce scope, mais ces releases SHM ne prouvent pas la lifetime GPU. Le runtime brut reste INCONCLUSIVE, IPC terminal1.
|
||||
|
||||
L’ombre pristine déborde sur21598 pixels H2 ; Mosaic n’en montre aucun sur H2. À l’intérieur H1, activer l’ombre ne change aucun RGB : ombre intérieure permise **NOT EXERCISED**, qualification complète **NOT PROVEN**. Les extents damage couvrent des différences stabilisées échantillonnées ; ni tous les frames, ni minimalité, ni absence exhaustive de stale pixels ne sont établis. Verdict architectural FX **PARTIALLY_FEASIBLE**, attribution du bord INCONCLUSIVE.
|
||||
|
||||
L’audit complémentaire LAB `parent/damage-envelopes.json` compare99 transitions de captures des treize runs initiaux
|
||||
adjacentes entières : 18 différences contenues dans les enveloppes physiques A,
|
||||
79 NOT OBSERVABLE et deux changements de dimensions NOT COMPARABLE. Les extents
|
||||
sur un intervalle large ne prouvent pas la région pixman exacte/minimale ni un
|
||||
buffer réellement présenté. Les autres runs n’héritent pas de la trace A.
|
||||
21
docs/design/STEP20C_TARGETED_INPUT_NATIVE_ORDERING.md
Normal file
21
docs/design/STEP20C_TARGETED_INPUT_NATIVE_ORDERING.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# STEP20C — input ciblé et ordre natif
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. Le diagnostic C3 est exécuté : résultat INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST désigne `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB/HIST sont des artefacts externes locaux, pas des fichiers distribués. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) donne les identités exactes, la matrice des quatorze runs et les limites. Les sources de [fixture ciblé](../../tooling/probes/step20c-targeted/README.md) restent des entrées expérimentales ; elles n’ajoutent aucune dépendance de production. Les rapports historiques et leurs verdicts restent inchangés.
|
||||
|
||||
## Géométrie appliquée pendant le clic
|
||||
|
||||
Le pristine a huit PNG et complète le contrôle standard full/empty/full, focus/layout et fermeture normale. A/G ont cinq PNG chacun ; les deux s’arrêtent au troisième clic après restauration full. Les boutons owner45/46 sont réellement livrés au point global (-314,30). La fixture avait capturé une origine (-318,25), mais le focus provoqué dans la fenêtre du clic déplace la caméra ; la dernière origine native est (-638,25) et le motion livré (324,5) lui correspond exactement.
|
||||
|
||||
La nouvelle lecture avant clic n’a pas couvert la mutation camera/focus pendant clic. L’arrêt `Ambiguous: logical pointer correlation` reste **INCONCLUSIVE** pour la campagne. Ce n’est ni une panne démontrée de routing produit, ni une preuve d’atomicité. La suite camera/layout et normal owner close A/G sont **NOT EXERCISED** ; leur scientific cleanup est INCONCLUSIVE, distinct de processus 0/reaped/runtime_removed. Le pristine garde son contrôle standard FEASIBLE ; son runtime brut est lui aussi INCONCLUSIVE sur IPC terminal1, sans exigence de PI privée dans le contrôle.
|
||||
|
||||
## Replay des commits et presents
|
||||
|
||||
La relecture de tous les57 commits du F historique trouve55 paires et2 `MISSING_PRESENT`, clés (HEADLESS-1,2) et (HEADLESS-2,2). Le compte10/12 du rapport initial portait un sous-ensemble ; le rapport historique reste intact. Le replay complémentaire est LAB `parent/offline-native-summary.json`.
|
||||
|
||||
Les treize runs initiaux contiennent 788 commits,758 paires et 30 missing. C3 ajoute 33/31/2 : total final 14 runs,821 commits,789 paires et 32 missing. Le matching utilise **(output, commit_seq)**, jamais un numéro sans output. Pristine ne possède pas d’instrumentation PI :0 ne signifie pas absence de commits natifs. Le backend headless diffère le present d’un commit accepté et peut annuler un callback lors du teardown ; source audit et pairage sont des propriétés distinctes.
|
||||
|
||||
Aucune paire ne lie ici les pixels physiques, l’identité du buffer GPU, son lock/release ou la génération atomique du hit. La fenêtre naturelle commit→mutation input→present discriminante reste **NOT EXERCISED**. Les callbacks de scène appliquée, événements wire client, IPC et native present ne forment pas automatiquement une génération commune. Damage complet et lifetime restent **NOT PROVEN**.
|
||||
|
||||
Les observations fraîches input du run G dynamique qualifient leurs points propres ; elles ne complètent pas la suite input-A/G interrompue. Un futur fixture doit accepter ou mesurer la mutation pendant la livraison sans supposer une origine capturée immuable. Preuves : LAB `runs/input-{pristine,A,G}/run/`, `parent/run-summary.json`, `reviews/runtime-validation-13.json`, `parent/native-lifetime-audit.json`.
|
||||
66
docs/design/STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md
Normal file
66
docs/design/STEP20C_TARGETED_SAVED_BUFFER_LIFECYCLE.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# STEP20C — lifecycle ciblé des saved buffers
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. Le diagnostic C3 est exécuté : résultat INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST désigne `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB/HIST sont des artefacts externes locaux, pas des fichiers distribués. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) donne les identités exactes, la matrice des quatorze runs et les limites. Les sources de [fixture ciblé](../../tooling/probes/step20c-targeted/README.md) restent des entrées expérimentales ; elles n’ajoutent aucune dépendance de production. Les rapports historiques et leurs verdicts restent inchangés.
|
||||
|
||||
## Configure réellement obtenu, gate incomplet
|
||||
|
||||
Deux runs distincts, `saved-A` et `saved-G`, ont chacun deux PNG de référence H2. La demande réelle `gaps inner current set 30` provoque un nouveau configure serial 39 après ACK 30 : 636×573 devient 636×513. Le client annonce HELD, aucun ACK 39 n’est enregistré. Le validateur partagé puis son replay confirment la propriété `HELD_WIRE_VALIDATED` ; le trigger de configure est FEASIBLE pour les données observées.
|
||||
|
||||
La fixture s’arrête néanmoins sur `Ambiguous: same ws1 owner and requested runtime gaps`, car elle exige le champ workspace IPC `gaps` absent. L’audit source confirme l’action runtime et les deux argv contiennent `-Dtxn-timeout=2500`. Aucun timeout naturel n’est observé : la connexion est détruite par le teardown du compositeur, et le client écrit `EXIT ... mapped=1 held=1 error=32`, malgré son code de processus 0. Le `cleanup_pass=true` mécanique ne devient donc pas scientific cleanup PASS. Résultat runtime, scientific cleanup et campagne : **INCONCLUSIVE**. Images pendant hold/timeout, normal owner close et identité native saved-node/render : **NOT EXERCISED / NOT OBSERVABLE**.
|
||||
|
||||
## Identités et propriété native
|
||||
|
||||
L’audit `parent/native-lifetime-audit.json` est **SOURCE_AUDIT_ONLY**. `view_save_buffer_iterator` crée un autre `wlr_scene_buffer` sous l’arbre saved, copie destination/source-box/transform et référence le buffer de la scène live. SceneFX déverrouille l’ancienne référence, invalide la texture cached et locke le nouveau `wlr_buffer`. Le saved tree est frère de content_tree ; retirer les saved nodes détruit leur arbre et réactive le live. La destruction d’un scene buffer libère sa référence. Ces chemins source ne sont pas une preuve de release GPU au runtime.
|
||||
|
||||
Il faut distinguer SHM client, wl_buffer release client, nœud saved natif, texture/cache, output-state buffer, commit/present et fin GPU. Ni A ni G n’offrent les identités natives saved/locks/releases recherchées. Les traces d’un autre binaire historique ne leur sont pas transférées. Lifetime GPU, références exhaustives, commit rejeté et cohérence atomique restent **NOT PROVEN**.
|
||||
|
||||
## C3 réellement consommé — observation native partielle
|
||||
|
||||
C3 (`saved-diagnostic-A`) utilise un troisième binaire privé avec un seul
|
||||
build Mosaic stage1, sans nouveau build SceneFX. LAB
|
||||
`diagnostic/build-stage.json` lie le SHA
|
||||
`9c0dc0e94ccc7fcbd7a6cddf14e90f1bb7b7bf385a0740e85ec7d0e1c1c1e705`
|
||||
et build ID `67a4bcb6a37e8ec691a0da5099d12275429a7076`.
|
||||
LAB `parent/c3-observations.json` et `parent/run-summary-final.json` enregistrent
|
||||
la tentative consommée, sans réparation de fixture ni relance.
|
||||
|
||||
Le runtime et la mesure sont **INCONCLUSIVE**, runner exit1 : le bounded wait
|
||||
expire après une durée totale de run de 3,682 s. Ce stop n’est **pas** le timeout
|
||||
naturel d’une transaction. Le prédicat figé `saved_identity` rejette
|
||||
`unique unreused saved node` : l’adresse de nœud est réellement réutilisée.
|
||||
Une première tree owner 10 précède la commande gaps runtime ; une nouvelle tree
|
||||
owner 10 est créée après cette commande. Exiger une adresse globalement unique
|
||||
était trop strict pour cette lifetime ; l’analyse hors ligne ne répare ni
|
||||
requalifie le prédicat original.
|
||||
|
||||
Après gaps, le wire retient configure 39 HELD sans ACK,636×573→636×513.
|
||||
`SD_CREATE` observe owner 10, tree `0x55f011797c80`, saved node
|
||||
`0x55f011792290`, source buffer `0x55f01170eae0`, destination 636×573 et
|
||||
locks 3→4. Un vrai draw H1 de ce nœud/source et un sample natif sont retenus :
|
||||
bbox globale[-318,25,636,573], intersection héritée[-318,25,318,573], clip
|
||||
viewport global[-800,0,800,600] ; le draw output-local va de(482,25) à(800,598).
|
||||
Ce sont des observations de création/rendu de saved node, distinctes des PNG
|
||||
client ou d’une identité de buffer réellement présenté.
|
||||
|
||||
`SD_NODE_DESTROY`, `SD_RELEASE` à locks 0 et `SD_BUFFER_DESTROY` apparaissent
|
||||
uniquement pendant le teardown après l’arrêt anticipé. Le client owner termine
|
||||
`EXIT error=32` malgré code de processus 0. Natural transaction timeout,
|
||||
normal owner close, PNG held puis live et contrôle H2 pendant hold :
|
||||
**NOT EXERCISED**. Scientific cleanup **INCONCLUSIVE**, GPU completion et
|
||||
identité source-SHM/output **NOT PROVEN**. Processus0/reaped/runtime_removed
|
||||
et IPC terminal1 restent enregistrés séparément.
|
||||
|
||||
Le découpage offline create→next destroy est descriptif, avec source pointer
|
||||
et ancestor tree ; il n’invente ni génération native ni identité valable à
|
||||
toute réutilisation d’adresse. **SAVED_NODE_LIFECYCLE : partiellement observé
|
||||
(création/rendu/teardown)** ; clipping **INCONCLUSIVE**, sans PNG held H2 ;
|
||||
native GPU lifetime **NOT PROVEN**. Aucun résultat C3 ne se transfère à A/G.
|
||||
La revue finale indépendante est **ACCEPTED**, audit PASS pour la fidélité du dossier expérimental. La publication documentaire est autorisée et préparée, non exécutée à cette édition.
|
||||
|
||||
Preuves A/G : LAB `runs/saved-{A,G}/run/`, `parent/run-summary.json`,
|
||||
`parent/native-lifetime-audit.json`, `reviews/runtime-validation-13.json`.
|
||||
Preuves C3 : LAB `runs/saved-diagnostic-A/run/`, `parent/c3-observations.json`,
|
||||
`parent/run-summary-final.json`. Total campagne final 14 runs/125 PNG/520 événements ;
|
||||
les treize runs initiaux et leurs preuves restent intacts.
|
||||
19
docs/design/STEP20C_TARGETED_SCALE_AND_POPUP_GATE.md
Normal file
19
docs/design/STEP20C_TARGETED_SCALE_AND_POPUP_GATE.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# STEP20C — gate ciblé scale et popups
|
||||
|
||||
> EXPERIMENTAL — édition du 2026-10-14, clôture documentaire des quatorze runs ciblés, diagnostic C3 inclus. Revue finale indépendante : ACCEPTED, audit PASS pour la fidélité de l’évidence expérimentale. Publication documentaire autorisée et préparée, non exécutée à cette édition. Le diagnostic C3 est exécuté : résultat INCONCLUSIVE, observations natives partielles sans transfert à A/G. STEP20A DONE ; STEP20B EXPERIMENTAL ; STEP20C NEXT ; STEP20D–G PLANNED. Multi-output de production : NOT YET SUPPORTED. Aucune intégration, installation ou décision UX.
|
||||
|
||||
L’autorité brute est le LAB privé `/home/fy59/swayfx-mosaic-targeted-7gge6h8b` ; HIST désigne `/home/fy59/swayfx-mosaic-overnight-mcolx0gq`. Les chemins LAB/HIST sont des artefacts externes locaux, pas des fichiers distribués. Le [rapport de clôture](STEP20C_TARGETED_CLOSURE_DECISION.md) donne les identités exactes, la matrice des quatorze runs et les limites. Les sources de [fixture ciblé](../../tooling/probes/step20c-targeted/README.md) restent des entrées expérimentales ; elles n’ajoutent aucune dépendance de production. Les rapports historiques et leurs verdicts restent inchangés.
|
||||
|
||||
## Contrat et preuves retenues
|
||||
|
||||
`scale-A` et `scale-G` mesurent séparément leur propre SHA ; neuf PNG par run, quatre observations de clic, deux vrais grabs. Le contrôle pristine de scale est historique : aucun nouveau run pristine scale n’est revendiqué. H1 est à origine négative, mode physique 1000×750, scale 1,25, transform normal et taille logique 800×600 ; H2 conserve la référence statique. Les cinq marqueurs de couleur sont validés dans le cadre PNG 1000×750, distinct du cadre logique IPC. La conversion n’est pas déduite de la seule taille du fichier.
|
||||
|
||||
La fixture vérifie d’abord le host traversant la frontière, puis crée les popups XDG. Les logs wire donnent `TOPLEVEL → POPUP_A → POPUP_B`, les serials de bouton réellement utilisés pour grab 35 puis 44, ACK 36 puis 45 et buffers clients 350×170 puis 300×130. L’origine appliquée client est (-318,25) ; A est (-218,105,350,170), B (-118,165,300,130) : les deux franchissent x=0. Les observations associent la fenêtre d’ouverture, l’owner natif, la hiérarchie wire, la géométrie et les pixels. Cette association reste bornée par le source audit ; aucun join natif direct host/owner ID n’a été instrumenté.
|
||||
|
||||
Le clic B visible est livré ; le point interdit ne livre aucun bouton B et déclenche le dismissal observé. H2 entier reste RGB exact à sa référence, y compris l’image finale. Mesures PASS, architecture FEASIBLE pour cet échantillon ; résultat runtime INCONCLUSIVE dans chaque run (IPC terminal exit1), processus exit0 et scientific cleanup PASS séparément. La politique de click-through sous grab reste indécise.
|
||||
|
||||
## Portée et limites
|
||||
|
||||
Une chaîne/deux grabs par run seulement ; allocation de retour standard désactivée : **NOT EXERCISED**. Les markers, captures, camera et root clip ne prouvent ni toutes les générations de transaction, ni tous les frames, ni les buffers GPU réellement présentés. Aucun nouveau statut de production ne suit de la réussite des mesures.
|
||||
|
||||
Sources de preuve LAB : `runs/scale-A/run/`, `runs/scale-G/run/`, `parent/run-summary.json`, `reviews/runtime-validation-13.{md,json}` (681 checks validés). Le budget scale est exactement deux runs/dix-huit captures. Les fichiers wire, images et hashes par run figurent dans le résumé lié ; la validation documentaire ne relance aucun compositeur.
|
||||
121
tooling/probes/step20c-targeted-diagnostic/README.md
Normal file
121
tooling/probes/step20c-targeted-diagnostic/README.md
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
# Optional C3 saved diagnostic — EXPERIMENTAL
|
||||
|
||||
This fixture is a separate fixed `saved-diagnostic-A` experiment. Core
|
||||
`step20c-targeted` final sources, plans, freeze and review are immutable.
|
||||
A/G saved runs remain INCONCLUSIVE: their actual serial39 636x573→636x513
|
||||
was held, but the old absent-IPC-`ws.gaps` predicate aborted before target
|
||||
captures and natural timeout. No qualification transfers to the new binary.
|
||||
STEP20C remains NEXT; production cross-output support is NOT YET SUPPORTED.
|
||||
|
||||
## Contract and source
|
||||
|
||||
`saved-passive.patch` applies only to the historical A private
|
||||
`mosaic-source/sway/tree/view.c`; base/new/patch hashes are recorded under
|
||||
same LAB `diagnostic/source-provenance.json`. The full source is private.
|
||||
Sway view saved-copy creation/removal owns all normal references and scene
|
||||
mutations. The patch observes existing lock counts before/after the existing
|
||||
set-buffer call; it adds no buffer lock, unlock, copy retention, ACK, timeout,
|
||||
scheduler, rendering, readback or timeline waiting. No public ABI changes.
|
||||
One calloc sidecar per actual saved copy observes output_sample, node destroy,
|
||||
source release and source destroy. It detaches sample on node destruction,
|
||||
nulls whichever object dies first, and frees exactly after both die. A NULL
|
||||
source needs only node destruction. Stable scalar addresses remain labels,
|
||||
never dereferenced after destruction. Source buffer destruction may precede
|
||||
node destruction because SceneFX retains its texture. Native release/destroy
|
||||
and a release timeline pointer/point do **not** prove GPU completion.
|
||||
Logging causes CPU timing overhead; instrumentation neutrality is NOT PROVEN.
|
||||
|
||||
Native saved tree logs bind owner/container ID, scene parent and content tree.
|
||||
Creation logs distinguish saved-node, original scene-node and raw source-buffer
|
||||
addresses, source crop, destination size and transform. output_sample logs the
|
||||
actual saved node global geometry, viewport, enable state and each applied
|
||||
ancestor clip at that sample (`sample_ns`). Existing unmodified SceneFX
|
||||
OPT_BUFFER_DRAW records bind that same node/output to actual draw extents.
|
||||
The validator measures the intersection of **that saved node**, its viewport
|
||||
and observed clips; another node's rectangle cannot substitute for it.
|
||||
|
||||
## Gate and global budget extension
|
||||
|
||||
`diagnostic.py` adds exactly the fixed fourteenth spec **in memory only** during
|
||||
this process's original `gate.locked`, `action_debit` and shared `Session` use.
|
||||
Original `gate.verify` runs before registration and after unregistering.
|
||||
`diagnostic-registration.json` persists the exact spec; `final_budget(lab)`
|
||||
requires it for extended reconciliation. It never edits the frozen module,
|
||||
original review or previous tokens/events. The original review does not accept
|
||||
this extension. Independent preparation review and a separate runtime review
|
||||
bind exact original freeze/review, diagnostic source/patch/tests, private source,
|
||||
clients, wlroots, the original A SceneFX static archive and uninstalled pc.
|
||||
The runtime freeze additionally binds the staged new binary.
|
||||
|
||||
Only the same LAB is accepted. All13 original tokens must precede diagnostic
|
||||
build/stage/run. One build token and one stage token are O_EXCL/fsynced before
|
||||
the action under a flock; diagnostic/budget.json is separate from runtime
|
||||
captures. Failed actions still consume their token. No retries/refunds/reset.
|
||||
Only one known `saved-diagnostic-A` runtime token is appended under the original
|
||||
global flock/fsynced reconciliation. Limits remain global14 runs/174 PNG,
|
||||
saved3 runs/30 PNG, per-run16 maximum; C3 itself uses at most10 PNG,2 clicks,
|
||||
1 camera,150 seconds. `Session` supplies isolated sockets, maps and cleanup.
|
||||
A final caller must use this extension's `final_budget`, since the frozen
|
||||
original validator intentionally knows only its thirteen original specs.
|
||||
|
||||
## Review and execution protocol
|
||||
|
||||
1. `prepare.py --lab /home/fy59/swayfx-mosaic-targeted-7gge6h8b` runs offline
|
||||
tests, persists registration and seals preparation bytes. It requires the
|
||||
C17 syntax receipt. It does not accept its own result.
|
||||
2. Independent review must write preparation-review.json with scope,
|
||||
ACCEPTED status, independent=true, blockers=[], exact freeze_sha256/files,
|
||||
report_file/report_sha256. No compositor build before that acceptance.
|
||||
3. Parent reserves `reserve_build_stage(lab,'build')` before the ONE Mosaic
|
||||
private build. Reuse **exactly** HIST/scene-build/libscenefx-0.5.a and
|
||||
HIST/scene-build/meson-uninstalled/scenefx-0.5-uninstalled.pc. Zero SceneFX
|
||||
builds or edits. Parent reserves stage before ONE DESTDIR stage and verifies
|
||||
its manifest. No install, live IPC, second lab or system library change.
|
||||
4. Parent seals runtime-freeze.json (scope/spec/files=bindings(lab,True)), then
|
||||
independent runtime-review.json with analogous exact-byte acceptance.
|
||||
5. Only then `run.py --lab SAME_LAB` may consume the optional token once.
|
||||
H1=-800,H2=0, normal scale1; real SHM crossing and at most one camera;
|
||||
beforehold applied state; gaps inner current set30; pending workspace
|
||||
rectangle/owner identity and actual held wire dimensions; native saved
|
||||
create/draw/sample before2500ms; held H1/H2 pair; natural2500ms timeout with
|
||||
client alive and unACKed serial; requested live geometry/saved node gone;
|
||||
stable H1/H2 pair; normal protocol close; final H1/H2 pair. Ten PNG total
|
||||
including two H2 static references. No held-serial ACK during cleanup.
|
||||
6. Postrun analysis uses the same pending_geometry, held_configure,
|
||||
saved_identity, saved_removal and native_pairs predicates as offline/runtime. Final global
|
||||
budget must use final_budget. Any missing required native evidence fails
|
||||
closed; partial observations cannot become GPU-lifetime qualification.
|
||||
|
||||
Offline native trace fixture in test_diagnostic.py is explicitly synthetic;
|
||||
wire/IPC positive and negative tests use actual saved-A/G consumed logs and
|
||||
snapshots read-only. No synthetic native test is runtime evidence. Complete
|
||||
intermediate damage, GPU/CPU completion, atomic generation, other output
|
||||
geometries, and instrumentation neutrality remain NOT PROVEN/NOT TESTED.
|
||||
|
||||
## Refused preparation correction C3
|
||||
|
||||
The previous preparation was refused for C3-CREATE-WINDOW and
|
||||
C3-REMOVE-WINDOW. Its exact source bytes, aliases, receipts and review are
|
||||
preserved in LAB/diagnostic/superseded-preparation-review-refused-v3.
|
||||
Creation must follow the requested command, precede unique owner/tree
|
||||
activation, and identify an unreused actual saved node. Every sample must
|
||||
follow activation and bind its exact node/source/output.
|
||||
|
||||
Natural removal uses the same saved_removal predicate in the wait, before
|
||||
live captures and in final/postrun validation. It requires the unmodified
|
||||
positive-waiter transaction timeout RAW line after activation, then the exact
|
||||
SD_REMOVE owner/tree/content, then each measured saved-node/source destruction.
|
||||
SD_REMOVE is emitted before synchronous node destruction in the unchanged
|
||||
passive C patch. Destruction must follow creation and precede the first live
|
||||
capture boundary and normal explicit-close request. The native timeout line
|
||||
has no monotonic ns; destruction occurs before the runner observes timeout,
|
||||
so runner observation is not a lower bound. The audited single queued
|
||||
transaction gives this fixed experiment its raw-order association; it is not
|
||||
a general transaction-generation or GPU-completion claim.
|
||||
|
||||
prepare.py copies current diagnostic sources into diagnostic/diagnostic-source,
|
||||
reuses unchanged passive C and its existing C17 receipt, writes source-bound
|
||||
offline results and creates a new O_EXCL preparation freeze after the refused
|
||||
receipts have been archived. It never creates an accepted review. The C3 runner
|
||||
journals named private runtime, run, log and socket paths after Session creation
|
||||
and startup without changing the frozen core.
|
||||
187
tooling/probes/step20c-targeted-diagnostic/diagnostic.py
Normal file
187
tooling/probes/step20c-targeted-diagnostic/diagnostic.py
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
"""EXPERIMENTAL optional C3; explicit extension outside the frozen core."""
|
||||
import contextlib,copy,fcntl,json,os,re,sys,time
|
||||
from pathlib import Path
|
||||
HERE=Path(__file__).resolve().parent
|
||||
CORE=HERE.parent/'step20c-targeted'
|
||||
sys.path.insert(0,str(CORE))
|
||||
import gate,plans
|
||||
from validators import held_configure,native_pairs
|
||||
from geometry import need,intersection
|
||||
from engine import Session,workspace,nodes
|
||||
SPEC=copy.deepcopy(plans.RUNS['saved-A'])
|
||||
SPEC.update(id='saved-diagnostic-A',case='saved-diagnostic',variant='diagnostic',status='EXPERIMENTAL',ceilings=['atomic generation NOT PROVEN','complete damage NOT PROVEN','GPU completion NOT PROVEN','STEP20C NEXT; production multi-output NOT YET SUPPORTED'])
|
||||
SPEC['limits'].update(capture=10,click=2,camera=1)
|
||||
SCOPE='STEP20C_SAVED_DIAGNOSTIC_V1'
|
||||
|
||||
@contextlib.contextmanager
|
||||
def registration(lab,verify=True):
|
||||
"""Register only in this process, after/before original byte verification.
|
||||
|
||||
The persistent registration is mandatory for subsequent final validation.
|
||||
This does not transfer the original review to the new fixed fourteenth run.
|
||||
"""
|
||||
lab=Path(lab)
|
||||
if verify:gate.verify(lab)
|
||||
need(SPEC['id'] not in plans.RUNS,'duplicate registration')
|
||||
persisted=gate.read(lab/'diagnostic-registration.json')
|
||||
need(persisted==dict(scope=SCOPE,spec=SPEC),'fixed persisted registration')
|
||||
plans.RUNS[SPEC['id']]=SPEC
|
||||
try:yield
|
||||
finally:
|
||||
del plans.RUNS[SPEC['id']]
|
||||
if verify:gate.verify(lab)
|
||||
|
||||
def final_budget(lab):
|
||||
with registration(lab):return gate.validate(gate.read(Path(lab)/'budget.json'))
|
||||
|
||||
def reserve_build_stage(lab,kind):
|
||||
"""Durable one-way reservation, only after independent preparation review."""
|
||||
lab=gate.owned(lab);need(kind in ('build','stage'),'fixed build/stage kind')
|
||||
verify_preparation(lab)
|
||||
with registration(lab):
|
||||
state=gate.validate(gate.read(lab/'budget.json'))
|
||||
need(set(state['runs'])==set(plans.RUNS)-{SPEC['id']},'thirteen original tokens consumed before diagnostic build/stage')
|
||||
folder=lab/'diagnostic'
|
||||
with (folder/'budget.lock').open('a+') as f:
|
||||
fcntl.flock(f,fcntl.LOCK_EX)
|
||||
path=folder/'budget.json'
|
||||
state=gate.read(path) if path.exists() else dict(scope=SCOPE,events=[])
|
||||
need(state['scope']==SCOPE and all(e['kind'] in ('build','stage') for e in state['events']),'diagnostic budget schema')
|
||||
need(not any(e['kind']==kind for e in state['events']),'no build/stage retry')
|
||||
if kind=='stage':need([e['kind'] for e in state['events']]==['build'],'build before stage')
|
||||
token=folder/(kind+'.token.json')
|
||||
gate.durable(token,dict(scope=SCOPE,kind=kind,ns=time.monotonic_ns()),True)
|
||||
state['events'].append(dict(kind=kind,ns=time.monotonic_ns()))
|
||||
gate.durable(path,state,not path.exists())
|
||||
return state
|
||||
|
||||
def bindings(lab,binary=False):
|
||||
lab=Path(lab);diag=lab/'diagnostic'
|
||||
paths=[p for p in HERE.iterdir() if p.is_file()]
|
||||
paths += [diag/'offline.json',diag/'offline.stdout',diag/'syntax-check.json',lab/'freeze.json',lab/'review.json',lab/'diagnostic-registration.json',diag/'source-provenance.json',plans.HIST/'scene-build/libscenefx-0.5.a',plans.HIST/'scene-build/meson-uninstalled/scenefx-0.5-uninstalled.pc',plans.WLROOTS]
|
||||
paths += [p for p in (diag/'mosaic-source').rglob('*') if p.is_file()]
|
||||
paths += [p for p in (diag/'diagnostic-source').rglob('*') if p.is_file()]
|
||||
if (diag/'correction-provenance.json').exists():paths += [diag/'correction-provenance.json']
|
||||
paths += [p for p in (lab/'clients').iterdir() if p.is_file()]
|
||||
if binary:paths += [diag/'stage/usr/bin/swayfx-mosaic']
|
||||
return {str(p):gate.sha(p) for p in sorted(set(paths))}
|
||||
|
||||
def verify_preparation(lab):
|
||||
gate.verify(lab);diag=Path(lab)/'diagnostic'
|
||||
f=gate.read(diag/'preparation-freeze.json');r=gate.read(diag/'preparation-review.json')
|
||||
need(f.get('scope')==SCOPE and f.get('spec')==SPEC and f.get('files')==bindings(lab),'preparation exact bytes')
|
||||
need(r.get('scope')==SCOPE and r.get('status')=='ACCEPTED' and r.get('independent') is True and r.get('blockers')==[] and r.get('freeze_sha256')==gate.sha(diag/'preparation-freeze.json') and r.get('files')==f['files'] and gate.sha(r['report_file'])==r['report_sha256'],'independent preparation review')
|
||||
|
||||
def verify_runtime(lab):
|
||||
gate.verify(lab);diag=Path(lab)/'diagnostic'
|
||||
f=gate.read(diag/'runtime-freeze.json');r=gate.read(diag/'runtime-review.json')
|
||||
need(f.get('scope')==SCOPE and f.get('spec')==SPEC and f.get('files')==bindings(lab,True),'runtime exact bytes')
|
||||
need(r.get('scope')==SCOPE and r.get('status')=='ACCEPTED' and r.get('independent') is True and r.get('blockers')==[] and r.get('freeze_sha256')==gate.sha(diag/'runtime-freeze.json') and r.get('files')==f['files'] and gate.sha(r['report_file'])==r['report_sha256'],'independent runtime review')
|
||||
b=gate.read(diag/'budget.json');need(b['scope']==SCOPE and [e['kind'] for e in b['events']]==['build','stage'],'exactly one build/stage')
|
||||
return diag/'stage/usr/bin/swayfx-mosaic'
|
||||
|
||||
def pending_geometry(initial,pending,owner_id,workspace_id,before,after,prior,request_ns):
|
||||
oldws=workspace(initial['tree'],'1');ws=workspace(pending['tree'],'1')
|
||||
need(oldws['id']==ws['id']==workspace_id and ws['output']==oldws['output']=='HEADLESS-1' and ws['layout']==oldws['layout']=='mosaic','same requested workspace')
|
||||
need('gaps' not in ws,'IPC gaps field is absent in audited source')
|
||||
old=next(n for n in nodes(oldws) if n['id']==owner_id)
|
||||
owners=[n for n in nodes(ws) if n['id']==owner_id];need(len(owners)==1,'same owner ancestry')
|
||||
target=owners[0];need(target['pid']==old['pid'] and target['app_id']==old['app_id']=='org.mosaic.SavedBufferProbe','same actual client')
|
||||
a=oldws['rect'];b=ws['rect'];need([b[k] for k in ('x','y','width','height')]==[a['x']+30,a['y']+30,a['width']-60,a['height']-60],'requested workspace rect changed by runtime gaps30')
|
||||
proof=held_configure(before,after,prior)
|
||||
need(proof['ns']>request_ns and proof['requested_size']==[target['window_rect']['width'],target['window_rect']['height']],'held wire after command matches requested dimensions')
|
||||
need(proof['initial_size']==[old['window_rect']['width'],old['window_rect']['height']],'initial applied dimensions')
|
||||
return dict(held=proof,workspace=ws,owner=target)
|
||||
|
||||
def records(text,tag):
|
||||
return [dict(re.findall(r'(\w+)=([^\s]+)',l),raw=l) for l in text.splitlines() if tag+' ' in l]
|
||||
|
||||
def saved_identity(text,owner,creation_after,require_destroy=False):
|
||||
trees=[r for r in records(text,'SD_TREE') if r['owner']==str(owner) and int(r['ns'])>creation_after]
|
||||
need(len(trees)==1 and trees[0]['saved_enabled']=='1' and trees[0]['content_enabled']=='0','unique actual saved owner tree')
|
||||
tree=trees[0]['tree']
|
||||
# WHY CONTRACT INVARIANT: addresses are labels, so reused/old trees or nodes
|
||||
# cannot prove this command's saved copies or this owner's activation.
|
||||
need(len([r for r in records(text,'SD_TREE') if r['tree']==tree])==1,'unique owner/tree activation')
|
||||
created=[r for r in records(text,'SD_CREATE') if r['tree']==tree]
|
||||
need(created,'actual saved copies')
|
||||
rows=[]
|
||||
for c in created:
|
||||
node=c['node']
|
||||
need(creation_after<int(c['ns'])<int(trees[0]['ns']),'actual creation after command before activation')
|
||||
need(len([r for r in records(text,'SD_CREATE') if r['node']==node])==1,'unique unreused saved node')
|
||||
need(node!=c['source_node'] and c['source'] not in ('(nil)','0x0'),'distinct saved/source scene identities')
|
||||
need(c['parent']==trees[0]['parent'],'actual saved parent')
|
||||
samples=[r for r in records(text,'SD_SAMPLE') if r['node']==node]
|
||||
draws=[r for r in records(text,'OPT_BUFFER_DRAW') if r['node']==node]
|
||||
need(samples and draws,'actual saved sample and native draw')
|
||||
dead=[r for r in records(text,'SD_NODE_DESTROY') if r['node']==node]
|
||||
need(len(dead)<=1,'unique saved node destruction')
|
||||
if require_destroy:need(len(dead)==1,'saved node removed naturally')
|
||||
for s in samples:
|
||||
need(s['source']==c['source'] and s['enabled']=='1' and s['node_enabled']=='1' and int(s['ns'])>int(trees[0]['ns']),'same live saved source after activation')
|
||||
need(not dead or int(s['ns'])<int(dead[0]['ns']),'sample after node destruction')
|
||||
same=[d for d in draws if d['output']==s['output'] and int(trees[0]['ns'])<int(d['ns'])<=int(s['ns'])]
|
||||
need(same,'same native node/output draw before sample')
|
||||
draw=same[-1]
|
||||
need(draw['global']==s['global'] and list(map(int,draw['dest'].split('x')))==list(map(int,s['dest'].split(','))),'native draw and saved sample geometry agree')
|
||||
need(draw['buffer'] in (c['source'],'(nil)'),'native draw source buffer identity or cleared texture source')
|
||||
ancestors=[a for a in records(text,'SD_ANCESTOR') if a['node']==node and a['output']==s['output'] and a.get('sample_ns')==s['ns']]
|
||||
need(ancestors,'applied ancestor clip sample')
|
||||
xy=list(map(int,s['global'].split(',')));dest=list(map(int,s['dest'].split(',')));bbox=[*xy,*dest]
|
||||
viewport=list(map(int,s['viewport'].split(',')));visible=intersection(bbox,viewport)
|
||||
for a in ancestors:
|
||||
if a['clip_valid']=='1':
|
||||
pos=list(map(int,a['global'].split(',')));clip=list(map(int,a['clip'].split(',')));visible=intersection(visible,[pos[0]+clip[0],pos[1]+clip[1],*clip[2:]])
|
||||
dbox=list(map(int,draw['draw'].split(',')))
|
||||
# SceneFX native draw extents are output-buffer coordinates. Fixed
|
||||
# C3 normal scale1 maps these directly to logical viewport space.
|
||||
drawn=[dbox[0]+viewport[0],dbox[1]+viewport[1],dbox[2]-dbox[0],dbox[3]-dbox[1]]
|
||||
need(intersection(drawn,visible)==drawn and drawn[2]>0 and drawn[3]>0,'native saved draw contained by measured applied intersection')
|
||||
need(s['output']=='HEADLESS-1' and visible[2]>0 and visible[3]>0 and bbox[0]<0<bbox[0]+bbox[2],'actual saved target crossing and H1 intersection')
|
||||
for d in draws:need(not dead or int(d['ns'])<int(dead[0]['ns']),'native draw after node destruction')
|
||||
releases=[r for r in records(text,'SD_RELEASE') if r['node']==node];destroyed=[r for r in records(text,'SD_BUFFER_DESTROY') if r['node']==node]
|
||||
need(len(destroyed)<=1,'unique source destruction')
|
||||
need(all(int(r['ns'])>int(c['ns']) for r in releases+destroyed),'source lifecycle after saved creation')
|
||||
need(not destroyed or all(int(r['ns'])<int(destroyed[0]['ns']) for r in releases),'release after source destroy')
|
||||
for sample in samples:
|
||||
gone=destroyed and int(destroyed[0]['ns'])<int(sample['ns'])
|
||||
need(sample['live_source'] in ('(nil)','0x0') if gone else sample['live_source']==c['source'],'source pointer cleared after buffer destruction')
|
||||
need(all(r['source']==c['source'] and r.get('gpu_complete')=='NOT_PROVEN' for r in releases+destroyed),'native release is not GPU proof')
|
||||
rows.append(dict(create=c,samples=samples,draws=draws,node_destroy=dead,release=releases,buffer_destroy=destroyed))
|
||||
return dict(tree=trees[0],nodes=rows,gpu_completion='NOT PROVEN',cpu_lifetime='signal observations only; no retained references')
|
||||
|
||||
|
||||
def saved_removal(text,identity,before_ns):
|
||||
"""Exact natural-timeout removal; also used on final/post-close logs.
|
||||
|
||||
before_ns is the first live-capture boundary, never the runner's timeout
|
||||
observation. The native timeout callback destroys nodes synchronously.
|
||||
"""
|
||||
lines=text.splitlines();tree=identity['tree'];created=identity['nodes']
|
||||
def position(row):
|
||||
hits=[i for i,l in enumerate(lines) if l==row['raw']]
|
||||
need(len(hits)==1,'unique raw native record position')
|
||||
return hits[0]
|
||||
activation=position(tree)
|
||||
# WHY CONTRACT INVARIANT: the audited single queued transaction emits its
|
||||
# unmodified timeout line before applying/removing saved buffers. No native
|
||||
# ns exists on that line; raw order proves causality, not GPU completion.
|
||||
timeouts=[i for i,l in enumerate(lines) if i>activation and re.search(r'Transaction .*timed out \(\d*[1-9]\d* waiting\)',l)]
|
||||
need(len(timeouts)==1,'unique natural timeout after target activation')
|
||||
removes=[r for r in records(text,'SD_REMOVE') if r['tree']==tree['tree']]
|
||||
need(len(removes)==1,'exact saved tree removal')
|
||||
remove=removes[0]
|
||||
need(remove['owner']==tree['owner'] and remove['content']==tree['content'],'exact removed owner/content')
|
||||
need(timeouts[0]<position(remove),'tree removal after native timeout')
|
||||
need(int(tree['ns'])<int(remove['ns'])<before_ns,'tree removed before first live capture/close')
|
||||
dead=[]
|
||||
for node in created:
|
||||
c=node['create'];matches=[r for r in records(text,'SD_NODE_DESTROY') if r['node']==c['node']]
|
||||
need(len(matches)==1,'exact measured saved node destroyed')
|
||||
r=matches[0]
|
||||
need(r['source']==c['source'],'destroyed saved source identity')
|
||||
need(position(remove)<position(r),'SD_REMOVE precedes synchronous node destruction')
|
||||
need(int(c['ns'])<int(remove['ns'])<=int(r['ns'])<before_ns,'target destruction in natural removal window')
|
||||
dead.append(r)
|
||||
return dict(timeout_raw=lines[timeouts[0]],timeout_line=timeouts[0],remove=remove,nodes=dead,before_ns=before_ns,gpu_completion='NOT PROVEN')
|
||||
24
tooling/probes/step20c-targeted-diagnostic/prepare.py
Normal file
24
tooling/probes/step20c-targeted-diagnostic/prepare.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Prepare review inputs only; never build, stage, accept, or launch."""
|
||||
import argparse,json,subprocess,shutil
|
||||
from diagnostic import *
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('--lab',type=Path,required=True);a=p.parse_args();lab=gate.owned(a.lab);gate.verify(lab)
|
||||
diag=lab/'diagnostic';need(diag.is_dir(),'existing same laboratory diagnostic directory')
|
||||
registration_path=lab/'diagnostic-registration.json'
|
||||
expected=dict(scope=SCOPE,spec=SPEC)
|
||||
if registration_path.exists():need(gate.read(registration_path)==expected,'unchanged fixed registration')
|
||||
else:gate.durable(registration_path,expected,True)
|
||||
# Copy only reviewed Python/README bytes; never regenerate the passive C.
|
||||
copy=diag/'diagnostic-source';copy.mkdir(exist_ok=True)
|
||||
for path in HERE.iterdir():
|
||||
if path.is_file():shutil.copy2(path,copy/path.name)
|
||||
env={**os.environ,'PYTHONDONTWRITEBYTECODE':'1'};cmd=[sys.executable,str(HERE/'test_diagnostic.py')]
|
||||
run=subprocess.run(cmd,env=env,capture_output=True,text=True);raw=run.stdout+run.stderr;(diag/'offline.stdout').write_text(raw)
|
||||
receipt=dict(command=cmd,exit=run.returncode,status='PASS' if run.returncode==0 else 'FAIL',executed=int(re.search(r'Ran (\d+) tests',raw)[1]),raw_sha256=gate.sha(diag/'offline.stdout'),sources={str(p):gate.sha(p) for p in HERE.iterdir() if p.is_file()})
|
||||
gate.durable(diag/'offline.json',receipt,True);need(run.returncode==0,'offline tests')
|
||||
need(gate.read(diag/'syntax-check.json')['exit']==0,'C17 syntax check')
|
||||
gate.durable(diag/'preparation-freeze.json',dict(scope=SCOPE,status='READY_FOR_INDEPENDENT_REVIEW',spec=SPEC,files=bindings(lab)),True)
|
||||
gate.verify(lab);print(json.dumps(dict(status='READY_FOR_INDEPENDENT_REVIEW',freeze_sha256=gate.sha(diag/'preparation-freeze.json'),runtime='NOT RUN',build='NOT RUN')))
|
||||
if __name__=='__main__':main()
|
||||
90
tooling/probes/step20c-targeted-diagnostic/run.py
Normal file
90
tooling/probes/step20c-targeted-diagnostic/run.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env python3
|
||||
"""One optional C3. Preparation and runtime independent reviews are required."""
|
||||
import argparse,re,time
|
||||
from diagnostic import *
|
||||
from cases import init_reference,stable_reference,exact
|
||||
|
||||
def campaign(s):
|
||||
init_reference(s,2);s.launch_client('owner','saved-client')
|
||||
s.cmd(f'[con_id={s.find("owner")["id"]}] focus');state=s.calibrate('owner');baseline=stable_reference(s)
|
||||
# Initial applied clip measured using native scene state; no extra PNG.
|
||||
applied=[r for r in records(s.log('compositor'),'PI_SCENE') if r['output']=='HEADLESS-1' and r['workspace']==str(state['workspace']['id'])]
|
||||
need(applied and applied[-1]['clip_valid']=='1' and applied[-1]['layout']=='5','initial applied Mosaic clip')
|
||||
clip=list(map(int,applied[-1]['clip'].split(',')));tile=list(map(int,applied[-1]['tile_scene'].split(',')))
|
||||
out=s.outputs[0]['logical'];need([out[0]+tile[0]+clip[0],out[1]+tile[1]+clip[1],*clip[2:]]==out,'initial actual applied output clip')
|
||||
s.save('initial-applied',dict(state=state,scene=applied[-1]))
|
||||
before=s.log('owner');prior=int(re.findall(r'ACK ns=\d+ serial=(\d+)',before)[-1])
|
||||
argv=Path(f'/proc/{s.comp.pid}/cmdline').read_bytes().split(b'\0');need(b'-Dtxn-timeout=2500' in argv,'real2500ms startup')
|
||||
source=(s.lab/'diagnostic/mosaic-source/sway/commands/gaps.c').read_text()
|
||||
need('argc == 4 && !config->reading' in source and 'arrange_workspace' in source,'runtime current gaps source audit')
|
||||
s.client_cmd('owner','hold_next_configure','COMMAND hold_next_configure DONE');cut=len(s.log('owner'));ccut=len(s.log('compositor'))
|
||||
s.cmd('workspace 1');request=time.monotonic_ns();s.cmd('gaps inner current set 30',True)
|
||||
pending=s.snapshot('saved-requested-pending');s.wait(lambda:'HELD ' in s.log('owner')[cut:])
|
||||
proof=pending_geometry(state['snapshot'],pending,state['owner']['id'],state['workspace']['id'],before,s.log('owner')[cut:],prior,request)
|
||||
need((time.monotonic_ns()-request)/1e9<2.1,'native held proof before timeout')
|
||||
def observed_saved():
|
||||
try:return saved_identity(s.log('compositor'),state['owner']['id'],request)
|
||||
except ValueError:return None
|
||||
native=s.wait(observed_saved,seconds=.5)
|
||||
need(all(int(row['ns'])<request+2_450_000_000 for node in native['nodes'] for row in node['samples']),'saved samples before timeout')
|
||||
held=s.pair_capture('held');need((time.monotonic_ns()-request)/1e9<2.45,'held pair before timeout');exact(baseline,held[1])
|
||||
s.wait(lambda:re.search(r'timed out \(\d*[1-9]\d* waiting\)',s.log('compositor')[ccut:]),seconds=3.5)
|
||||
timeout=time.monotonic_ns();need(timeout-request>=2_300_000_000 and s.proc['owner'].poll() is None,'natural timeout clientalive')
|
||||
held_configure(before,s.log('owner')[cut:],prior)
|
||||
def observed_removal():
|
||||
try:return saved_removal(s.log('compositor'),native,time.monotonic_ns())
|
||||
except ValueError:return None
|
||||
s.wait(observed_removal)
|
||||
live_boundary=time.monotonic_ns()
|
||||
removal=saved_removal(s.log('compositor'),native,live_boundary)
|
||||
s.record('saved-natural-removal',proof=removal,first_live_boundary_ns=live_boundary)
|
||||
live=s.owner('owner');need(live['owner']['window_rect']==proof['owner']['window_rect'],'applied requested live dimensions')
|
||||
after=s.pair_capture('natural-timeout');exact(baseline,after[1])
|
||||
time.sleep(.2);stable=s.pair_capture('stable-live');exact(after[0],stable[0]);exact(after[1],stable[1])
|
||||
# Read final passive trace after normal protocol close, never ACK held serial.
|
||||
close_request=time.monotonic_ns()
|
||||
s.record('saved-explicit-close-boundary',request_ns=close_request)
|
||||
s.close_client('owner','close');final=s.pair_capture('final');exact(baseline,final[1])
|
||||
identity=saved_identity(s.log('compositor'),state['owner']['id'],request,True)
|
||||
removal=saved_removal(s.log('compositor'),identity,min(live_boundary,close_request))
|
||||
held_configure(before,s.log('owner')[cut:],prior)
|
||||
s.save('saved-diagnostic',dict(status='PARTIALLY_FEASIBLE',request_ns=request,timeout_observed_ns=timeout,first_live_boundary_ns=live_boundary,explicit_close_request_ns=close_request,removal=removal,initial=state,pending=pending,proof=proof,native=identity,pairs=native_pairs(s.log('compositor')),argv=[v.decode() for v in argv],GPU='NOT PROVEN',complete_damage='NOT PROVEN',atomic_generation='NOT PROVEN',timing='passive logging CPU overhead; no neutrality claim'))
|
||||
return 'PARTIALLY_FEASIBLE'
|
||||
|
||||
def begin(lab,binary):
|
||||
need(not sys.flags.optimize,'assertions enabled')
|
||||
for p in Path('/proc').iterdir():
|
||||
if p.name.isdigit():
|
||||
try:exe=(p/'exe').resolve(strict=True)
|
||||
except (FileNotFoundError,PermissionError,ProcessLookupError):continue
|
||||
need(exe!=binary.resolve(),'diagnostic binary already running')
|
||||
folder=lab/'runs'/SPEC['id'];folder.mkdir(exist_ok=True);need(not (folder/'run').exists(),'no retry')
|
||||
def consume(state):
|
||||
need(set(state['runs'])==set(plans.RUNS)-{SPEC['id']},'all thirteen original tokens consumed first')
|
||||
need(SPEC['id'] not in state['runs'] and state['used']['run']==13 and state['campaign_runs']['saved']==2,'known fourteenth token only')
|
||||
need(state['used']['capture']+10<=174 and state['campaign_used']['saved']+10<=30,'planned caps')
|
||||
state['runs'][SPEC['id']]=dict(campaign='saved',planned=SPEC['limits'],reserved=dict.fromkeys(SPEC['limits'],0),consumed_ns=time.monotonic_ns(),freeze_sha256=gate.sha(lab/'diagnostic/runtime-freeze.json'))
|
||||
state['used']['run']+=1;state['campaign_runs']['saved']+=1
|
||||
gate.locked(lab,consume)
|
||||
ident=gate.read(lab/'identity.json')
|
||||
return dict(binary=str(binary),binary_sha256=gate.sha(binary),wlroots=str(plans.WLROOTS),wlroots_sha256=plans.WLROOTS_SHA,pristine_scene=str(plans.SCENE),pristine_scene_sha256=ident['scene_sha256'])
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('--lab',type=Path,required=True);a=p.parse_args();lab=gate.owned(a.lab)
|
||||
binary=verify_runtime(lab)
|
||||
with registration(lab):
|
||||
auth=begin(lab,binary);s=None;status='INCONCLUSIVE';failure=None
|
||||
try:
|
||||
s=Session(SPEC,auth,lab)
|
||||
s.record('diagnostic-private-paths',run=str(s.run),runtime=str(s.runtime),compositor_log=str(s.run/'compositor.log'))
|
||||
s.env['SAVED_DIAGNOSTIC']='1';s.start()
|
||||
s.record('diagnostic-private-sockets',runtime=str(s.runtime),swaysock=str(s.sock),wayland_display=s.env['WAYLAND_DISPLAY'])
|
||||
status=campaign(s)
|
||||
except Exception as e:failure=dict(type=type(e).__name__,message=str(e))
|
||||
finally:
|
||||
if s is not None:status=s.cleanup(status,failure)
|
||||
def finish(state):state['runs'][SPEC['id']].update(outcome=status,failure=failure)
|
||||
gate.locked(lab,finish)
|
||||
print(json.dumps(dict(id=SPEC['id'],status=status,failure=failure)))
|
||||
return 1 if failure else 0
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
152
tooling/probes/step20c-targeted-diagnostic/saved-passive.patch
Normal file
152
tooling/probes/step20c-targeted-diagnostic/saved-passive.patch
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
--- a/sway/tree/view.c
|
||||
+++ b/sway/tree/view.c
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
+#include <inttypes.h>
|
||||
#include <strings.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/config.h>
|
||||
@@ -1276,11 +1277,121 @@
|
||||
return view->urgent.tv_sec || view->urgent.tv_nsec;
|
||||
}
|
||||
|
||||
+/* EXPERIMENTAL diagnostic only. WHY: identify actual saved copies rather than
|
||||
+ * infer them from SHM pixels. CONTRACT: signal observation only; no reference,
|
||||
+ * ACK, scene mutation, rendering, readback, or timeline wait. INVARIANT: native
|
||||
+ * Sway/SceneFX ownership and ABI are unchanged. Logging perturbs CPU timing.
|
||||
+ * A release/destroy signal does not prove GPU completion. */
|
||||
+struct saved_diag {
|
||||
+ struct wlr_scene_buffer *saved;
|
||||
+ struct wlr_buffer *source;
|
||||
+ void *node_id, *source_id;
|
||||
+ struct wl_listener sample, node_destroy, release, buffer_destroy;
|
||||
+};
|
||||
+
|
||||
+static uint64_t saved_diag_ns(void) {
|
||||
+ struct timespec ts;
|
||||
+ clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
+ return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_free(struct saved_diag *d) {
|
||||
+ if (!d->saved && !d->source) {
|
||||
+ free(d);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_release(struct wl_listener *listener, void *data) {
|
||||
+ struct saved_diag *d = wl_container_of(listener, d, release);
|
||||
+ sway_log(SWAY_DEBUG, "SD_RELEASE ns=%" PRIu64 " node=%p source=%p locks=%zu gpu_complete=NOT_PROVEN",
|
||||
+ saved_diag_ns(), d->node_id, d->source_id, d->source->n_locks);
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_buffer_destroy(struct wl_listener *listener, void *data) {
|
||||
+ struct saved_diag *d = wl_container_of(listener, d, buffer_destroy);
|
||||
+ sway_log(SWAY_DEBUG, "SD_BUFFER_DESTROY ns=%" PRIu64 " node=%p source=%p gpu_complete=NOT_PROVEN",
|
||||
+ saved_diag_ns(), d->node_id, d->source_id);
|
||||
+ wl_list_remove(&d->release.link);
|
||||
+ wl_list_remove(&d->buffer_destroy.link);
|
||||
+ d->source = NULL;
|
||||
+ saved_diag_free(d);
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_node_destroy(struct wl_listener *listener, void *data) {
|
||||
+ struct saved_diag *d = wl_container_of(listener, d, node_destroy);
|
||||
+ sway_log(SWAY_DEBUG, "SD_NODE_DESTROY ns=%" PRIu64 " node=%p source=%p",
|
||||
+ saved_diag_ns(), d->node_id, d->source_id);
|
||||
+ wl_list_remove(&d->sample.link);
|
||||
+ wl_list_remove(&d->node_destroy.link);
|
||||
+ d->saved = NULL;
|
||||
+ saved_diag_free(d);
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_sample(struct wl_listener *listener, void *data) {
|
||||
+ struct saved_diag *d = wl_container_of(listener, d, sample);
|
||||
+ struct wlr_scene_output_sample_event *e = data;
|
||||
+ struct wlr_scene_buffer *s = d->saved;
|
||||
+ uint64_t sample_ns = saved_diag_ns();
|
||||
+ int x = 0, y = 0;
|
||||
+ bool enabled = wlr_scene_node_coords(&s->node, &x, &y);
|
||||
+ sway_log(SWAY_DEBUG, "SD_SAMPLE ns=%" PRIu64 " node=%p source=%p live_source=%p output=%s global=%d,%d dest=%d,%d src=%g,%g,%g,%g transform=%d enabled=%d node_enabled=%d viewport=%d,%d,%d,%d timeline=%p point=%" PRIu64 " direct=%d",
|
||||
+ sample_ns, d->node_id, d->source_id, d->source, e->output->output->name,
|
||||
+ x, y, s->dst_width, s->dst_height, s->src_box.x, s->src_box.y,
|
||||
+ s->src_box.width, s->src_box.height, s->transform, enabled, s->node.enabled,
|
||||
+ e->output->x, e->output->y, e->output->output->width, e->output->output->height,
|
||||
+ e->release_timeline, e->release_point, e->direct_scanout);
|
||||
+ for (struct wlr_scene_tree *p = s->node.parent; p; p = p->node.parent) {
|
||||
+ struct wlr_box clip = {0};
|
||||
+ int px = 0, py = 0;
|
||||
+ bool pe = wlr_scene_node_coords(&p->node, &px, &py);
|
||||
+ bool valid = wlr_scene_tree_get_clip(p, &clip);
|
||||
+ sway_log(SWAY_DEBUG, "SD_ANCESTOR ns=%" PRIu64 " sample_ns=%" PRIu64 " node=%p output=%s tree=%p global=%d,%d enabled=%d clip_valid=%d clip=%d,%d,%d,%d",
|
||||
+ saved_diag_ns(), sample_ns, d->node_id, e->output->output->name, p, px, py, pe,
|
||||
+ valid, clip.x, clip.y, clip.width, clip.height);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void saved_diag_attach(struct wlr_scene_buffer *saved,
|
||||
+ struct wlr_scene_buffer *original, size_t before) {
|
||||
+ if (!getenv("SAVED_DIAGNOSTIC")) {
|
||||
+ return;
|
||||
+ }
|
||||
+ struct saved_diag *d = calloc(1, sizeof(*d));
|
||||
+ if (!d) {
|
||||
+ sway_log(SWAY_ERROR, "SD_ALLOCATION_FAILED");
|
||||
+ return;
|
||||
+ }
|
||||
+ d->saved = saved;
|
||||
+ d->source = original->buffer;
|
||||
+ d->node_id = &saved->node;
|
||||
+ d->source_id = original->buffer;
|
||||
+ d->sample.notify = saved_diag_sample;
|
||||
+ d->node_destroy.notify = saved_diag_node_destroy;
|
||||
+ wl_signal_add(&saved->events.output_sample, &d->sample);
|
||||
+ wl_signal_add(&saved->node.events.destroy, &d->node_destroy);
|
||||
+ if (d->source) {
|
||||
+ d->release.notify = saved_diag_release;
|
||||
+ d->buffer_destroy.notify = saved_diag_buffer_destroy;
|
||||
+ wl_signal_add(&d->source->events.release, &d->release);
|
||||
+ wl_signal_add(&d->source->events.destroy, &d->buffer_destroy);
|
||||
+ }
|
||||
+ sway_log(SWAY_DEBUG, "SD_CREATE ns=%" PRIu64 " node=%p source_node=%p source=%p tree=%p parent=%p locks_before=%zu locks_after=%zu dest=%d,%d src=%g,%g,%g,%g transform=%d",
|
||||
+ saved_diag_ns(), d->node_id, &original->node, d->source_id,
|
||||
+ saved->node.parent, saved->node.parent->node.parent, before,
|
||||
+ d->source ? d->source->n_locks : 0, saved->dst_width, saved->dst_height,
|
||||
+ saved->src_box.x, saved->src_box.y, saved->src_box.width,
|
||||
+ saved->src_box.height, saved->transform);
|
||||
+}
|
||||
+
|
||||
void view_remove_saved_buffer(struct sway_view *view) {
|
||||
if (!sway_assert(view->saved_surface_tree, "Expected a saved buffer")) {
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (getenv("SAVED_DIAGNOSTIC")) {
|
||||
+ sway_log(SWAY_DEBUG, "SD_REMOVE ns=%" PRIu64 " owner=%zu tree=%p content=%p",
|
||||
+ saved_diag_ns(), (size_t)view->container->node.id, view->saved_surface_tree, view->content_tree);
|
||||
+ }
|
||||
wlr_scene_node_destroy(&view->saved_surface_tree->node);
|
||||
view->saved_surface_tree = NULL;
|
||||
wlr_scene_node_set_enabled(&view->content_tree->node, true);
|
||||
@@ -1306,7 +1417,9 @@
|
||||
wlr_scene_buffer_set_source_box(sbuf, &buffer->src_box);
|
||||
wlr_scene_node_set_position(&sbuf->node, sx, sy);
|
||||
wlr_scene_buffer_set_transform(sbuf, buffer->transform);
|
||||
+ size_t diagnostic_locks = buffer->buffer ? buffer->buffer->n_locks : 0;
|
||||
wlr_scene_buffer_set_buffer(sbuf, buffer->buffer);
|
||||
+ saved_diag_attach(sbuf, buffer, diagnostic_locks);
|
||||
wlr_scene_buffer_set_corner_radii(sbuf, buffer->corners);
|
||||
scene_descriptor_assign(&sbuf->node, SWAY_SCENE_DESC_SAVED_BUFFER, tree);
|
||||
}
|
||||
@@ -1333,6 +1446,11 @@
|
||||
|
||||
wlr_scene_node_set_enabled(&view->content_tree->node, false);
|
||||
wlr_scene_node_set_enabled(&view->saved_surface_tree->node, true);
|
||||
+ if (getenv("SAVED_DIAGNOSTIC")) {
|
||||
+ sway_log(SWAY_DEBUG, "SD_TREE ns=%" PRIu64 " owner=%zu tree=%p parent=%p content=%p saved_enabled=%d content_enabled=%d",
|
||||
+ saved_diag_ns(), (size_t)view->container->node.id, view->saved_surface_tree, view->scene_tree, view->content_tree,
|
||||
+ view->saved_surface_tree->node.enabled, view->content_tree->node.enabled);
|
||||
+ }
|
||||
}
|
||||
|
||||
bool view_is_transient_for(struct sway_view *child,
|
||||
144
tooling/probes/step20c-targeted-diagnostic/test_diagnostic.py
Normal file
144
tooling/probes/step20c-targeted-diagnostic/test_diagnostic.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
"""Offline only: real A/G wire and IPC, synthetic native identity mutations."""
|
||||
import copy,json,re,unittest,tempfile
|
||||
from unittest.mock import patch
|
||||
from diagnostic import *
|
||||
|
||||
TRACE='''SD_CREATE ns=101 node=0x1 source_node=0x2 source=0x3 tree=0x4 parent=0x5 locks_before=1 locks_after=2 dest=636,573 src=0,0,636,573 transform=0
|
||||
SD_TREE ns=102 owner=10 tree=0x4 parent=0x5 content=0x6 saved_enabled=1 content_enabled=0
|
||||
OPT_BUFFER_DRAW ns=103 output=HEADLESS-1 node=0x1 buffer=0x3 surface=(nil) global=-318,25 dest=636x573 source=636x573 draw=482,30,770,570
|
||||
SD_SAMPLE ns=104 node=0x1 source=0x3 live_source=0x3 output=HEADLESS-1 global=-318,25 dest=636,573 src=0,0,636,573 transform=0 enabled=1 node_enabled=1 viewport=-800,0,800,600 timeline=(nil) point=0 direct=0
|
||||
SD_ANCESTOR ns=105 sample_ns=104 node=0x1 output=HEADLESS-1 tree=0x5 global=-800,0 enabled=1 clip_valid=1 clip=30,30,740,540
|
||||
Transaction 0xaa timed out (1 waiting)
|
||||
SD_REMOVE ns=199 owner=10 tree=0x4 content=0x6
|
||||
SD_NODE_DESTROY ns=200 node=0x1 source=0x3
|
||||
SD_RELEASE ns=201 node=0x1 source=0x3 locks=0 gpu_complete=NOT_PROVEN
|
||||
SD_BUFFER_DESTROY ns=202 node=0x1 source=0x3 gpu_complete=NOT_PROVEN
|
||||
'''
|
||||
|
||||
class DiagnosticTests(unittest.TestCase):
|
||||
def real(self,rid='saved-A'):
|
||||
run=plans.DEFAULT_LAB/'runs'/rid/'run'
|
||||
before=(run/'owner.log').read_text().split('COMMAND hold_next_configure DONE')[0]
|
||||
full=(run/'owner.log').read_text();cut=full.index('COMMAND hold_next_configure DONE');after=full[cut:]
|
||||
prior=int(re.findall(r'ACK ns=\d+ serial=(\d+)',before)[-1]);events=[json.loads(l) for l in (run/'events.jsonl').read_text().splitlines()]
|
||||
request=next(e['ns'] for e in events if e['kind']=='ipc-request' and e['args']==['gaps inner current set 30'])
|
||||
a=gate.read(run/'owner-owner-snapshot.json');b=gate.read(run/'saved-requested-pending-snapshot.json')
|
||||
return [a,b,10,6,before,after,prior,request]
|
||||
def test_real_A_G(self):
|
||||
for rid in ('saved-A','saved-G'):
|
||||
p=pending_geometry(*self.real(rid));self.assertEqual(p['held']['serial'],39);self.assertEqual(p['held']['requested_size'],[636,513])
|
||||
def test_fictitious_gaps(self):
|
||||
args=self.real();workspace(args[1]['tree'],'1')['gaps']={'inner':30}
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_wrong_workspace(self):
|
||||
args=self.real();args[3]=999
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_wrong_owner(self):
|
||||
args=self.real();args[2]=9
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_wrong_requested_size(self):
|
||||
args=self.real();args[5]=args[5].replace('636x513','636x514')
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_unreceived_serial(self):
|
||||
args=self.real();args[5]=args[5].replace('.configure(39)','.configure(40)')
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_ack_rejected(self):
|
||||
args=self.real();args[5]+='\nxdg_surface#3.ack_configure(39)\n'
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_stale_command(self):
|
||||
args=self.real();args[7]=10**18
|
||||
with self.assertRaises(ValueError):pending_geometry(*args)
|
||||
def test_native_positive(self):
|
||||
self.assertEqual(saved_identity(TRACE,10,100,True)['gpu_completion'],'NOT PROVEN')
|
||||
def test_native_mutations(self):
|
||||
mutations=[TRACE.replace('source_node=0x2','source_node=0x1'),TRACE.replace('SD_SAMPLE ns=104 node=0x1','SD_SAMPLE ns=104 node=0x9'),TRACE.replace('live_source=0x3 output=HEADLESS-1','live_source=0x3 output=HEADLESS-2'),TRACE.replace('SD_SAMPLE ns=104 node=0x1 source=0x3','SD_SAMPLE ns=104 node=0x1 source=0x9'),TRACE.replace('OPT_BUFFER_DRAW ns=103','OPT_BUFFER_DRAW ns=203'),TRACE.replace('gpu_complete=NOT_PROVEN','gpu_complete=PROVEN'),TRACE.replace('SD_NODE_DESTROY','OTHER'),TRACE.replace('SD_CREATE','OTHER'),TRACE.replace('global=-318,25 dest=636,573','global=10,25 dest=636,573'),TRACE.replace('sample_ns=104','sample_ns=105'),TRACE.replace('SD_BUFFER_DESTROY ns=202','SD_BUFFER_DESTROY ns=103')]
|
||||
for text in mutations:
|
||||
with self.subTest(text=text),self.assertRaises(ValueError):saved_identity(text,10,100,True)
|
||||
def test_creation_window_and_reuse_negatives(self):
|
||||
mutations=[TRACE.replace('SD_CREATE ns=101','SD_CREATE ns=90'),
|
||||
TRACE.replace('SD_CREATE ns=101','SD_CREATE ns=102'),
|
||||
TRACE.replace('SD_TREE ns=102','SD_TREE ns=104'),
|
||||
TRACE.replace('OPT_BUFFER_DRAW ns=103','OPT_BUFFER_DRAW ns=102'),
|
||||
TRACE.replace('owner=10','owner=11'),
|
||||
TRACE.replace('SD_CREATE ns=101', 'SD_CREATE ns=101',1)+'SD_CREATE ns=300 node=0x1 source_node=0x9 source=0x8 tree=0x7 parent=0x5\n',
|
||||
TRACE+'SD_TREE ns=301 owner=11 tree=0x4 parent=0x5 content=0x6 saved_enabled=1 content_enabled=0\n']
|
||||
for text in mutations:
|
||||
with self.subTest(text=text),self.assertRaises(ValueError):saved_identity(text,10,100)
|
||||
def test_removal_positive_synchronous_before_runner_observation(self):
|
||||
identity=saved_identity(TRACE,10,100)
|
||||
proof=saved_removal(TRACE,identity,210)
|
||||
self.assertEqual(proof['nodes'][0]['ns'],'200')
|
||||
self.assertEqual(proof['gpu_completion'],'NOT PROVEN')
|
||||
def test_removal_exact_window_negatives(self):
|
||||
identity=saved_identity(TRACE,10,100)
|
||||
mutations=[TRACE.replace('SD_NODE_DESTROY ns=200','SD_NODE_DESTROY ns=90'),
|
||||
TRACE.replace('SD_NODE_DESTROY ns=200 node=0x1','SD_NODE_DESTROY ns=200 node=0x9'),
|
||||
TRACE.replace('SD_REMOVE ns=199 owner=10','SD_REMOVE ns=199 owner=11'),
|
||||
TRACE.replace('SD_REMOVE ns=199 owner=10 tree=0x4','SD_REMOVE ns=199 owner=10 tree=0x9'),
|
||||
TRACE.replace('content=0x6\nSD_NODE_DESTROY','content=0x9\nSD_NODE_DESTROY'),
|
||||
TRACE.replace('Transaction 0xaa timed out (1 waiting)\n',''),
|
||||
TRACE.replace('Transaction 0xaa timed out (1 waiting)\n','')+'Transaction 0xaa timed out (1 waiting)\n',
|
||||
TRACE.replace('SD_NODE_DESTROY ns=200','SD_NODE_DESTROY ns=220'),
|
||||
TRACE.replace('SD_REMOVE ns=199','SD_REMOVE ns=220'),
|
||||
TRACE.replace('SD_NODE_DESTROY ns=200 node=0x1 source=0x3','SD_NODE_DESTROY ns=200 node=0x1 source=0x9')]
|
||||
for text in mutations:
|
||||
with self.subTest(text=text),self.assertRaises(ValueError):saved_removal(text,identity,210)
|
||||
# A destruction emitted only by normal explicit close is too late.
|
||||
with self.assertRaises(ValueError):saved_removal(TRACE,identity,199)
|
||||
def test_removal_not_global_count(self):
|
||||
identity=saved_identity(TRACE,10,100)
|
||||
text=TRACE.replace('SD_NODE_DESTROY ns=200 node=0x1','SD_NODE_DESTROY ns=200 node=0x9')
|
||||
text+='SD_NODE_DESTROY ns=201 node=0x8 source=0x3\n'
|
||||
with self.assertRaises(ValueError):saved_removal(text,identity,210)
|
||||
def test_absent_release_is_still_not_gpu_proof(self):
|
||||
text='\n'.join(l for l in TRACE.splitlines() if 'SD_RELEASE' not in l and 'SD_BUFFER_DESTROY' not in l)
|
||||
identity=saved_identity(text,10,100,True)
|
||||
self.assertEqual(identity['gpu_completion'],'NOT PROVEN')
|
||||
self.assertEqual(saved_removal(text,identity,210)['gpu_completion'],'NOT PROVEN')
|
||||
def test_false_gpu_release_remains_rejected(self):
|
||||
with self.assertRaises(ValueError):saved_identity(TRACE.replace('gpu_complete=NOT_PROVEN','gpu_complete=PROVEN'),10,100,True)
|
||||
def budget(self):
|
||||
state=copy.deepcopy(gate.read(plans.DEFAULT_LAB/'budget.json'))
|
||||
# Model a fixed fourteen-token final state offline, without touching lab.
|
||||
for rid,spec in plans.RUNS.items():
|
||||
if rid not in state['runs']:
|
||||
state['runs'][rid]=dict(campaign=spec['campaign'],planned=spec['limits'],reserved=dict.fromkeys(spec['limits'],0),consumed_ns=1,freeze_sha256='offline')
|
||||
state['used']['run']+=1;state['campaign_runs'][spec['campaign']]+=1
|
||||
return state
|
||||
def test_budget_known_extension(self):
|
||||
plans.RUNS[SPEC['id']]=SPEC
|
||||
try:self.assertEqual(gate.validate(self.budget())['used']['run'],14)
|
||||
finally:del plans.RUNS[SPEC['id']]
|
||||
def test_budget_unknown_and_caps(self):
|
||||
plans.RUNS[SPEC['id']]=SPEC
|
||||
try:
|
||||
state=self.budget()
|
||||
for mutate in (lambda s:s['runs'].__setitem__('retry',copy.deepcopy(s['runs'][SPEC['id']])),lambda s:s['runs'][SPEC['id']]['planned'].__setitem__('capture',17),lambda s:s['used'].__setitem__('capture',175),lambda s:s['campaign_used'].__setitem__('saved',31),lambda s:s['campaign_runs'].__setitem__('saved',4)):
|
||||
s=copy.deepcopy(state);mutate(s)
|
||||
with self.assertRaises(ValueError):gate.validate(s)
|
||||
finally:del plans.RUNS[SPEC['id']]
|
||||
def test_registration_before_after_verify(self):
|
||||
with tempfile.TemporaryDirectory(prefix='saved-diag-offline-') as folder:
|
||||
path=Path(folder);(path/'diagnostic-registration.json').write_text(json.dumps(dict(scope=SCOPE,spec=SPEC)))
|
||||
with patch.object(gate,'verify') as verify:
|
||||
with registration(path):self.assertEqual(plans.RUNS[SPEC['id']],SPEC)
|
||||
self.assertNotIn(SPEC['id'],plans.RUNS);self.assertEqual(verify.call_count,2)
|
||||
def test_registration_duplicate_rejected(self):
|
||||
with tempfile.TemporaryDirectory(prefix='saved-diag-offline-') as folder:
|
||||
path=Path(folder);(path/'diagnostic-registration.json').write_text(json.dumps(dict(scope=SCOPE,spec=SPEC)))
|
||||
with registration(path,False):
|
||||
with self.assertRaises(ValueError):
|
||||
with registration(path,False):pass
|
||||
def test_missing_persisted_registration_rejected(self):
|
||||
with tempfile.TemporaryDirectory(prefix='saved-diag-offline-') as folder:
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
with registration(Path(folder),False):pass
|
||||
def test_retry_build_token_rejected(self):
|
||||
with tempfile.TemporaryDirectory(prefix='saved-diag-offline-') as folder:
|
||||
token=Path(folder)/'build.token.json';gate.durable(token,dict(kind='build'),True)
|
||||
with self.assertRaises(FileExistsError):gate.durable(token,dict(kind='build'),True)
|
||||
def test_no_extra_buffer_ref_or_synchronization(self):
|
||||
patch=(HERE/'saved-passive.patch').read_text();added='\n'.join(l[1:] for l in patch.splitlines() if l.startswith('+') and not l.startswith('+++'))
|
||||
for token in ('wlr_buffer_lock(', 'wlr_buffer_unlock(', 'wlr_scene_buffer_set_buffer(', 'ack_configure(', 'wait_timeline(', 'read_pixels('):self.assertNotIn(token,added)
|
||||
|
||||
if __name__=='__main__':unittest.main(verbosity=2)
|
||||
550
tooling/probes/step20c-targeted-results/ARTIFACTS.json
Normal file
550
tooling/probes/step20c-targeted-results/ARTIFACTS.json
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
{
|
||||
"schema": "STEP20C_TARGETED_RUN_ARTIFACTS_V1",
|
||||
"private_lab": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b",
|
||||
"runs": [
|
||||
{
|
||||
"id": "FX-A",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/FX-A/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "a1b0a22e61ab3ef0ca925a9841ea3e71dace75912ad480a969c953b9743807b9",
|
||||
"events.jsonl": "4981e3a1a13f7e8a973c62218911d179117bf593e3e5b75d1189217ebadaf39b",
|
||||
"proc-maps.txt": "1a723dfb8ec234f141ecfcccc43816c5c133ed13fdb512b16776b4cd402ad380",
|
||||
"startup-snapshot.json": "396d433f0e34c00bd3242f28d8cde4a9369a482605e57cc878a2cf5000eecd2a",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "69eba6596d2b2f89b22e738c3035e1078c6f75c7947b866250b9280fcc8650cc",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"background.log": "bc97dd73e8cb45b670dfe49cecd47bbc94a80cb6a1b5285c1514e447aaa9bb55",
|
||||
"background-1.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"fx-witness-roi.json": "04e58badf240e73a6184a9946d1bd150e09eee6b7edb70120f456d4dc731fd48",
|
||||
"background-witness-H1.png": "fc3685d847a8c25b54434db1285c7c474f3254aa5acf16a6682661f3b77bf47d",
|
||||
"fx-background-witness.json": "88021ccc2d1188e535c512520b79fafc4bcedc8be110cca2b96a5b2c4c4c8a27",
|
||||
"filler0.log": "0417d51f62161ca628a65779ad71aeed5c1d59c659b3c7bb662a825b8e9db8e3",
|
||||
"filler-1.shm": "b58814cca765b3bbc7b1b526539b3e1fbe1d66aaff5fe8bb354163898971c26c",
|
||||
"filler-2.shm": "e66aa1d60cebb39f28248fa7145331d4965b60092a5a7685f50ca28b7eb188ba",
|
||||
"filler-3.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass.log": "31f3ea939d1a57ee737ae8e17c7ec2ebaeb72dd2465704afacde1f051a26f0ee",
|
||||
"glass-1.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-2.shm": "6855e8298a2fc55c6ccd6c4afa7054a4b8e30a7c563d6ac5b92bd2472a843ceb",
|
||||
"filler-4.shm": "626db8bea999709c8faead0ec9d60025604676fcc44130abe6c1168b90989b3b",
|
||||
"glass-3.shm": "243c78278e7934990c715c170de24513320b91ce86a28492b68ccd0f81fd4c4c",
|
||||
"glass-owner-snapshot.json": "fbbe9d58406da83427fe50a925293060f54959898b5d2a667208c55951b9312a",
|
||||
"glass-geometry.json": "f1b9b4d39179ce727209cd5c0d956cb23514ab97c711368c672f87c4eb3a3870",
|
||||
"fx-shadow-rois.json": "78cf7d45e74ff2329d38fbb98d295850f2aeb6ad06173be800c95282fa9a8620",
|
||||
"FX-off-H1.png": "15a0ca1319d7e11d879b04a628bf3530ccf6514b58e41c058bae77511cbe951e",
|
||||
"shadow-on-H1.png": "15a0ca1319d7e11d879b04a628bf3530ccf6514b58e41c058bae77511cbe951e",
|
||||
"shadow-on-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"glass-4.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-5.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"filler-5.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass-6.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"glass-7.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"fx-classic-rois.json": "1b61ad19642a66c6fdeb975644a651aee6a8462836158970b9090f4aeb7ddcdc",
|
||||
"fx-classic-state.json": "3e9d0962455a79116a2176cbc3fced791d66999deaab7ecee80985397095512b",
|
||||
"classic-off-H1.png": "ab6e77a482a99a50c375870924013320f6b452bce6676e4d842f34c7337fa737",
|
||||
"classic-blur-H1.png": "ad806e851eaaa3e1692edc3def93c38ea2f297a06f45ffefa2369403eff65e15",
|
||||
"fx-classic.json": "cc732ad065a5992ab23c11544af2cf6bc1110557f25ef9811d80a84c15fe8b15",
|
||||
"glass-8.shm": "243c78278e7934990c715c170de24513320b91ce86a28492b68ccd0f81fd4c4c",
|
||||
"filler-6.shm": "626db8bea999709c8faead0ec9d60025604676fcc44130abe6c1168b90989b3b",
|
||||
"fx-rois.json": "a5ccb3d9a080bac30463195e73b46cd4e6da0d047535972b143fc758379cf54b",
|
||||
"optimized-A-state.json": "2b4977517262d612fd9ef2245dca8dfd1a1ef15c017bc0907383027bd156aec4",
|
||||
"optimized-A-H1.png": "4d890d7a11c5acd108aa370f5ec840c3572cf0f42aa71fdfc214e6ae504569fb",
|
||||
"optimized-A-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-2.shm": "be47ad731e58f79603c14693df12697c76919341392242337b5e40d3df112dbd",
|
||||
"optimized-B-state.json": "6c26cc2ebc798cc7c3799b525904c090293cecdf4e399790f3b7e9f28696ce03",
|
||||
"optimized-B-H1.png": "426c1db8e4fd16e629e4dd7c6c20300f4cc10f26e70a0291f595be2c57da8fb7",
|
||||
"optimized-B-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-3.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"optimized-A-return-state.json": "f1b9b4d39179ce727209cd5c0d956cb23514ab97c711368c672f87c4eb3a3870",
|
||||
"optimized-A-return-H1.png": "a28f85c8d417d230bafb45f8de091d0c5422af1d4707776e52f5c5e5272d5adb",
|
||||
"optimized-A-return-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"fx-optimized.json": "0b670aa9292fd239f5ecd16225f997ad788f7e226f66eb6f1aa4d278d327df9f",
|
||||
"filler-7.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"final-H1.png": "9ae07bfa0ec8e34b79617da370f2c1940af764595e37e208c9e0936920bba700",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"effects-evidence.json": "2fd2e7a2b2e7598700c12da2e880813d318f3486f30b707b95c358271115cb0a",
|
||||
"fx-postrun.json": "5c150d3d3a63d661959143f730d0f66c960b0ef4c0cc5ece601328683f6c2ecb",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "19b4e1aef3ff165cb631619847ccad19892d8d64ca559042ea5e89b856cb1858"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "FX-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/FX-G/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "9ecfdf3d335e35fb67152eb4dead0c3c50ad20560fa477125823247e36e88aa9",
|
||||
"events.jsonl": "761228d5b2daaf74f82b75c0a0889d589543d0a99684bb6a1a75d78579aa6c8b",
|
||||
"proc-maps.txt": "3ae481838b005abadf6254afae83bce66c6e4fa3906ad85d20d58e42f993eb24",
|
||||
"startup-snapshot.json": "83db94806a8abf22a71b63c0bec603cf82dee8a4a78f4c2efc8a6723cf6ba05f",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "dfcac2763822d73bcc09186ad920bbd98545294496b80d8a536d1329a4a3a35f",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"background.log": "5ec9f3c9f1a351ea04ab91299dd534047a660325f4cd38dfd10a09c42cc74f4b",
|
||||
"background-1.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"fx-witness-roi.json": "4871a4786b8ac53e30875eacee010fe072f22316ce5aa4ef95cbf613eef8392d",
|
||||
"background-witness-H1.png": "fc3685d847a8c25b54434db1285c7c474f3254aa5acf16a6682661f3b77bf47d",
|
||||
"fx-background-witness.json": "e1eeed8bbca8f015f8d625d2df039bbcefd6d045cad818043380474efbbcff36",
|
||||
"filler0.log": "f424728449ca82046c6ee3c88e1166997d2b2f22c5d0810a01deee7f83b9ee7e",
|
||||
"filler-1.shm": "b58814cca765b3bbc7b1b526539b3e1fbe1d66aaff5fe8bb354163898971c26c",
|
||||
"filler-2.shm": "e66aa1d60cebb39f28248fa7145331d4965b60092a5a7685f50ca28b7eb188ba",
|
||||
"filler-3.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass.log": "4fac7e3ecf91bd743bf83cce6a4287d095fc9a66ce2fa9b1cdf8f518afb653fd",
|
||||
"glass-1.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-2.shm": "6855e8298a2fc55c6ccd6c4afa7054a4b8e30a7c563d6ac5b92bd2472a843ceb",
|
||||
"filler-4.shm": "626db8bea999709c8faead0ec9d60025604676fcc44130abe6c1168b90989b3b",
|
||||
"glass-3.shm": "243c78278e7934990c715c170de24513320b91ce86a28492b68ccd0f81fd4c4c",
|
||||
"glass-owner-snapshot.json": "496a2e5ee0d1a81ddcaf5ff2dd7fc2c5d0e0d32739aea13566a86de1b5c9c3e5",
|
||||
"glass-geometry.json": "b31314a746cc957657bd9420e714c17abb35fbdd62124886e076f0a80c7f0ed4",
|
||||
"fx-shadow-rois.json": "78cf7d45e74ff2329d38fbb98d295850f2aeb6ad06173be800c95282fa9a8620",
|
||||
"FX-off-H1.png": "15a0ca1319d7e11d879b04a628bf3530ccf6514b58e41c058bae77511cbe951e",
|
||||
"shadow-on-H1.png": "15a0ca1319d7e11d879b04a628bf3530ccf6514b58e41c058bae77511cbe951e",
|
||||
"shadow-on-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"glass-4.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-5.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"filler-5.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass-6.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"glass-7.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"fx-classic-rois.json": "1b61ad19642a66c6fdeb975644a651aee6a8462836158970b9090f4aeb7ddcdc",
|
||||
"fx-classic-state.json": "a0b4da01d87154588ff27f4efeadee75b85a1a96b89428ea1da237feab758427",
|
||||
"classic-off-H1.png": "ab6e77a482a99a50c375870924013320f6b452bce6676e4d842f34c7337fa737",
|
||||
"classic-blur-H1.png": "ad806e851eaaa3e1692edc3def93c38ea2f297a06f45ffefa2369403eff65e15",
|
||||
"fx-classic.json": "98922e4a8b944fb2a199bc8fd9234bfed6aa56a321abf286bcd8ecd62d88254b",
|
||||
"glass-8.shm": "243c78278e7934990c715c170de24513320b91ce86a28492b68ccd0f81fd4c4c",
|
||||
"filler-6.shm": "626db8bea999709c8faead0ec9d60025604676fcc44130abe6c1168b90989b3b",
|
||||
"fx-rois.json": "3a55650498d0410ab18a34486336ea4e84f3f52ec4eebefae8990f52b5972756",
|
||||
"optimized-A-state.json": "963ab25ffa5b1c3f60472642e3c4f5b7fd99bfe394d1e71b5bb209ca0d249522",
|
||||
"optimized-A-H1.png": "4d890d7a11c5acd108aa370f5ec840c3572cf0f42aa71fdfc214e6ae504569fb",
|
||||
"optimized-A-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-2.shm": "be47ad731e58f79603c14693df12697c76919341392242337b5e40d3df112dbd",
|
||||
"optimized-B-state.json": "3bc86561c63dc90bbdca7ffe5e01c12fbacce3d8df21026bfa442956ad8a0745",
|
||||
"optimized-B-H1.png": "426c1db8e4fd16e629e4dd7c6c20300f4cc10f26e70a0291f595be2c57da8fb7",
|
||||
"optimized-B-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-3.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"optimized-A-return-state.json": "b31314a746cc957657bd9420e714c17abb35fbdd62124886e076f0a80c7f0ed4",
|
||||
"optimized-A-return-H1.png": "a28f85c8d417d230bafb45f8de091d0c5422af1d4707776e52f5c5e5272d5adb",
|
||||
"optimized-A-return-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"fx-optimized.json": "5dc44ad57daf51f79f27948bda0818272ffa092079b625314a1f891f22031a96",
|
||||
"filler-7.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"final-H1.png": "9ae07bfa0ec8e34b79617da370f2c1940af764595e37e208c9e0936920bba700",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"effects-evidence.json": "5edb5684d4eed85bbfd61a0f4feb7607854bae5e60780d464b333a0e90fadad7",
|
||||
"fx-postrun.json": "9eb8b71fd9e7c51c052d26660d5449998952d9921886df167538a0df14c3342a",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "b566975e520fb1a886d6cf0e86d0ebbee3467491ffdbc21c2d18833893e81164"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "FX-pristine",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/FX-pristine/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "4599dbf5c1375d5442573c3fbb46e5ccf4bc9c90709431b7d3cd76d772684c46",
|
||||
"events.jsonl": "2ab7c28271a64b8ca8ceaa8c003ce1a9bf1d0ccc02403b8947352050eda4ddd5",
|
||||
"proc-maps.txt": "22480d7fb775fe496cad4c0265466000f347e3d52ecf3bc1a63e77fcaefe2a37",
|
||||
"startup-snapshot.json": "c2e69e8e6a764ef0541689ee99a0b574822b08ff56d7490d19e9e3c35fba9b98",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "7362427815aa651b1cf9970d5c82226e0ebc34e53a0f997ed31697250852de23",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"background.log": "04f4e676d207b14ab96d0b3e01f82a4328c04b4996df630abb7cbf25b4d7293b",
|
||||
"background-1.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"fx-witness-roi.json": "ef96ce817c3ebad55746b37bfa60b62b11418383d75d27c401f77926674a7f30",
|
||||
"background-witness-H1.png": "fc3685d847a8c25b54434db1285c7c474f3254aa5acf16a6682661f3b77bf47d",
|
||||
"fx-background-witness.json": "30455b75259416efec47e567058e7f70396495c0fd5a602a45b3afdacc4ce505",
|
||||
"filler0.log": "022bd012c37d7de68e0d0fd73962597068bf9081ea6474b65640b92e4ba059de",
|
||||
"filler-1.shm": "b58814cca765b3bbc7b1b526539b3e1fbe1d66aaff5fe8bb354163898971c26c",
|
||||
"filler-2.shm": "e66aa1d60cebb39f28248fa7145331d4965b60092a5a7685f50ca28b7eb188ba",
|
||||
"filler-3.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass.log": "1402e52463af3b74d04bca8f42cd256418d2216a37b570e0da6adf10fcc8e5b1",
|
||||
"glass-1.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-2.shm": "34c7c537c50718c1488c124f520e04aa21b293418fbd096502dbf6f90816da18",
|
||||
"filler-4.shm": "b9163d03c43083a18e6101539b555cb5e363eed61fa4b3a3b54f50ae60eb5b52",
|
||||
"glass-3.shm": "0990d052eff4d1559eaf13357f4015db875e15b149964724ce282625956fe8b6",
|
||||
"glass-owner-snapshot.json": "fbbf631976de61611a380ed8a7e709e2f0270b03bec29d3dab1538201d55302e",
|
||||
"glass-geometry.json": "a2a66f5874797d422a072d78bf5eb5f1093a9d6b695de38be338df5d0695d3c1",
|
||||
"fx-shadow-rois.json": "8d953a9d768ef6ed03ea85317134949912b9783b6bead3c55980799afbcd2a0a",
|
||||
"FX-off-H1.png": "e216d62a3342c78f295d3213b5ea30bd1e8f3d5946bd81fb1af465af7d70b897",
|
||||
"shadow-on-H1.png": "e216d62a3342c78f295d3213b5ea30bd1e8f3d5946bd81fb1af465af7d70b897",
|
||||
"shadow-on-H2.png": "9b9cf60de6334d3ae07e5e41848f3b90c70091af2b09e7b9fcfd065787e687c7",
|
||||
"glass-4.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"glass-5.shm": "c15590b48910a820cea9eaedb84f489eed629757d95a7e5332dd6e3a1c2e06e8",
|
||||
"filler-5.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"glass-6.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"glass-7.shm": "a942d124a64aa3f8f2e7b90f7e8d63a688adcd203845c8dd418356bc0520051a",
|
||||
"fx-classic-rois.json": "1b61ad19642a66c6fdeb975644a651aee6a8462836158970b9090f4aeb7ddcdc",
|
||||
"fx-classic-state.json": "e680dd1acafe007a9af118be1a464d9666a4d2439b0aa880bdf9676f6ef38e83",
|
||||
"classic-off-H1.png": "ab6e77a482a99a50c375870924013320f6b452bce6676e4d842f34c7337fa737",
|
||||
"classic-blur-H1.png": "ad806e851eaaa3e1692edc3def93c38ea2f297a06f45ffefa2369403eff65e15",
|
||||
"fx-classic.json": "98922e4a8b944fb2a199bc8fd9234bfed6aa56a321abf286bcd8ecd62d88254b",
|
||||
"filler-6.shm": "b9163d03c43083a18e6101539b555cb5e363eed61fa4b3a3b54f50ae60eb5b52",
|
||||
"glass-8.shm": "0990d052eff4d1559eaf13357f4015db875e15b149964724ce282625956fe8b6",
|
||||
"fx-rois.json": "9f9d6e91fe03c8aa3555732f1b0f5fcdefbc447c7b8ab0ad9441145565179759",
|
||||
"optimized-A-state.json": "738232f395b41e803d32e6a2bc2f411df9f7b569687e2d907ea838fa388d3375",
|
||||
"optimized-A-H1.png": "598c62cc9fc833162bbf019c841f9e904d248d5482fac88e6890dce24606ad21",
|
||||
"optimized-A-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-2.shm": "be47ad731e58f79603c14693df12697c76919341392242337b5e40d3df112dbd",
|
||||
"optimized-B-state.json": "8da9d0242fb884043b07e41a2e04a1755c898c300954fcfe5bfda24d2845e372",
|
||||
"optimized-B-H1.png": "d3260dea391d0dc8fc19f32cadc9af2b61dded501665da27a94b8dba8ba7fe22",
|
||||
"optimized-B-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"background-3.shm": "4b718d9667fe5d0b6e0f36c72d25b7f43307f83698433828761926b097ccb67c",
|
||||
"optimized-A-return-state.json": "a2a66f5874797d422a072d78bf5eb5f1093a9d6b695de38be338df5d0695d3c1",
|
||||
"optimized-A-return-H1.png": "7e71bdc58ea74bcdc3f47a17b39e3e19a36c194fda2eff71a91df3ce0350aad3",
|
||||
"optimized-A-return-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"fx-optimized.json": "87168525f6ccb3aecb1df154376b57c13c538f23718d57916bab3647f34448dd",
|
||||
"filler-7.shm": "124617c1f65e92d3bc895fbd869e4bb16a30754b198f59e6e973949b9aaa1b01",
|
||||
"final-H1.png": "9ae07bfa0ec8e34b79617da370f2c1940af764595e37e208c9e0936920bba700",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"effects-evidence.json": "8c27efd4b8f9511ea24f4d04a5492e4316c423cde6a10513fb950a98c2042fe5",
|
||||
"fx-postrun.json": "fa715b8976023a80f87dfdf9bf2aeb9b9e00ff7bbd81b191d2ca926f4ff22821",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "8acf68ff01b4022f93ed3ec9d5f8237a22c9453c1c3ea012ad4c28da57025a44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "G-R90-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/G-R90-G/run",
|
||||
"files": {
|
||||
"marker-source.png": "2ffcdcfc7a14d060c15ae86bee9ed4d9163ba7cd42622945c0b1fe2b393957f7",
|
||||
"events.jsonl": "17ad871cb7f1f8bbb19a642ff6843f88f660c44d86d2c73424aeccfb05b48a74",
|
||||
"config": "4affb6b0ad280d7166f63239708847bf184fadb492de50ce3155d2f66c3b99c9",
|
||||
"compositor.log": "11d3059e96ccfc396966aa9a74d887875e8c5aaa3874b470f378aeac211a6405",
|
||||
"proc-maps.txt": "81ac06a4fd026095c3f9d2d4109bc6deefc04666ca87603c6d91b396f1ed302b",
|
||||
"startup-snapshot.json": "688078bd713708eace6634c596dfdde4889d8bf1a5da1d4406bb883b4378c986",
|
||||
"marker-background.log": "46eb1ec98daa090c2430295d0431607b19de36e86d33b3b2bdbab461638103a3",
|
||||
"marker-H1.png": "204c8f996e37d45cf6e305100fd30c68b96b3e0e10c37e399c9c2bd117002a15",
|
||||
"pointer.log": "890f2ba41f88e4e1bfbd94b9c0decb73bd762e0d8b679f406571ee2894ebb3e9",
|
||||
"reference.log": "c5cd6f199642018f40ad2554cf25869bb70cfae9c108e65d4daf7f4b595ad085",
|
||||
"filler0.log": "2c4f5a4fe79004e8bc9166b4d9315e26bf4b2ee54d838b2425e1f3f50754be5d",
|
||||
"pre-XDG-marker-host-snapshot.json": "edead704366a51cd950c0a158de134b62403beed58f6fe4806187d8e588cdb39",
|
||||
"marker-host-baseline.json": "e4e33c30bff701bf80031c710d1d946a5780cc87f4da3add23e8a02cc97cd33f",
|
||||
"owner.log": "7eea224ff118bc451f5f0453e19cc0208785d65a27c386e10151fa8e3bb6375a",
|
||||
"owner-owner-snapshot.json": "3edd3cf446672739825c4e52491f3b016260a92a5d48714ffe249244fda26969",
|
||||
"owner-geometry.json": "a552414b97fca2445a2373daa7926da1e8bbde2ce248384c2367642ec2b7e75b",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"owner-top.png": "06a57ee107d8e977097e89427e95f4b262e64640c30b5d6d7dfcd686cdd984c8",
|
||||
"popup-A.png": "19ce9dfa9e742c6b5485b7f99fe833f12ac6d3ef7f3c17c6f7a6c173ff034ab4",
|
||||
"mapped-H1.png": "6543284c04d97a2a33b6b1517caceed41709f0fd3f5b9308878c8b34c115fdaf",
|
||||
"mapped-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"chain.json": "c43d94bc87e2450c96630027f96a3fefd60551f6f35d2948c99e001a598b9c75",
|
||||
"dismissal.json": "9a3c7bbb03ca387177e1dbea3ebae75fcd9eaf489f0f8874fb29f3f4bd995224",
|
||||
"final-H1.png": "11ddbf5b32b8194f8d4da18fa733fe9eb37a806a441347a54acf0250d417f549",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "4262f8dafdd5f0bf6f6afaa2bcf31059573a5ddcf6d4f2ece3913ce583ec4230"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "G-dynamic-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/G-dynamic-G/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "171dea95ef9aaf9a161ac2aa7ca72397de72a2c1840dc3061e67f09665cb9d68",
|
||||
"events.jsonl": "e9f1d367621cb86f9e4e9819ea0500adf425fb0fbb57e6228f34d6ce2131ed77",
|
||||
"proc-maps.txt": "c38a0b5f7f7a7c47f84ea5e974e42458b3b5d7be85bc885befcbd7c0886645e6",
|
||||
"startup-snapshot.json": "5bfcf9c99b7595afdf351525aa316b6f37aab091ec53d67cee1e9765bb7b58e6",
|
||||
"pointer.log": "b18d87f514468e3f2291ff3db84ccd0785c7bf858f1d7449dd90ce9065e6ae58",
|
||||
"reference.log": "9a0a2af868fd88caa50fe075a25234f13d00544e22be6a798b3b40ba62552b46",
|
||||
"filler0.log": "9935cc8e45b1c636a414f00762c4b45de5f90fa9104b0751d838b3286283cf09",
|
||||
"filler1.log": "34cf91510dbd3dd18dec8cf53e5a48a3a26a08f4ac93eed582cb8d6696190a23",
|
||||
"owner.log": "f1c8418293b794b64f921cf264d97825e1b0615dddf73c3f836f9058ea82f61c",
|
||||
"owner-owner-snapshot.json": "569a6ceb86bb90e79cc2d725c8bcaf7fbfbf03df78104a85bd42bcca445d9411",
|
||||
"owner-geometry.json": "4e4a7683d603573de21dd2c7f49e03733ea2187850be609510d49db1c438d2cb",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"owner-top.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"popup-A.png": "35072322e2a22c1fd73e20c67593080266df0fe42b7b6320808f17fb47f98250",
|
||||
"mapped-H1.png": "1d502191e74f449a3cc9d89db52708a45e9c225d7be814fe839d1513c892dc72",
|
||||
"mapped-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"chain.json": "3db90c51a0f033e974d4b6081dbf9019105f4e581775332a123f90dc3103c0f5",
|
||||
"resize960.png": "6257eecea214da92d7107809fe5b54323cd6cf653e3083401c5028652f673aba",
|
||||
"resize800.png": "1d502191e74f449a3cc9d89db52708a45e9c225d7be814fe839d1513c892dc72",
|
||||
"migrationH2.png": "1f9f0839bdc2bbdc8964e17ffd004c274647b81d03bd1d08cc5968cbc00c9331",
|
||||
"migrationH2-other.png": "0e78e1e00e1b64efefcadff280b26c47573f6b85aa1a36b6d7773abfbc2088f9",
|
||||
"migrationH1.png": "1f9f0839bdc2bbdc8964e17ffd004c274647b81d03bd1d08cc5968cbc00c9331",
|
||||
"migrationH1-other.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"dynamic-ownership.json": "72dc8ddcaa684f706f302238923f46c9d26aadac07506bf73c5791389f0cce5d",
|
||||
"final-H1.png": "043ef1d76e3380c62b0814442eb1826694c0dea6bbccf588c82ca8e287b8d63b",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "857712c9efe206979bfef052b778920fe9a0fe33ff0412bccd45154af87ad4ef"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "G-hidden-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/G-hidden-G/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "fdd0406a31a035d220dd82a11ef14c71159d56aca645d27f9f7c1d336a208684",
|
||||
"events.jsonl": "27d4a8c0fe0a066e8523ca6122479de818e0359c39be5cbb92fa7bef299e24f7",
|
||||
"proc-maps.txt": "6b958f1491c56d3abbebec374b7534672c3f3ddc1a506de3e56bbbb8938c99db",
|
||||
"startup-snapshot.json": "94b846bfc1d54edd4fd351c16f113a34af8eb1693defe91310ade79cdb01ee34",
|
||||
"pointer.log": "2bb5052b339500ea3348441d8525e9edf32da82953d730afde3dfeffaa3da116",
|
||||
"reference.log": "71788e8999d4674130996b29f1bffd384dcbefe4378c6ab60b7fc87d4cfa9596",
|
||||
"filler0.log": "5c81c8014d4c73257eb86aa9c0b7f24bf6b574d4ba1edac2e845554153687a15",
|
||||
"filler1.log": "be9360a60528511c9bb43c8cb4191d83f6ace79b9dff9fa835aebe34759de681",
|
||||
"owner.log": "099ea388b23e527ff6b56da3f842400ca431e02b173a00b3dcddc33863fe9b90",
|
||||
"tail0.log": "a96f3699dc26f635e249ea3c06ca4c92197a42d4a8c4ac9f5f07b509c1324ae0",
|
||||
"tail1.log": "28792146ece84e022de61fb5b0f893f5490bd36c4b0ff3789d79b892b505e41a",
|
||||
"owner-owner-snapshot.json": "debfafe1456556f3e2e346afdd897c8b93c67694da46f4972ec0ca2435827dc2",
|
||||
"owner-geometry.json": "d5d8e11bb63da7cca0fd418ca871a2347debaea1d28fd41b44c0b188704d45c5",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"owner-top.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"popup-A.png": "35072322e2a22c1fd73e20c67593080266df0fe42b7b6320808f17fb47f98250",
|
||||
"mapped-H1.png": "1d502191e74f449a3cc9d89db52708a45e9c225d7be814fe839d1513c892dc72",
|
||||
"mapped-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"chain.json": "9f046b8bbdb426336bb2418f17f8856a0b38f0a16b693056539b32de277b6fb5",
|
||||
"fully-hidden-H1.png": "d3419ecee91bbd4b27dc9dbbcdddd256d8bb619a2be944e4659b14e3bf1537b0",
|
||||
"fully-hidden-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"returned-H1.png": "1d502191e74f449a3cc9d89db52708a45e9c225d7be814fe839d1513c892dc72",
|
||||
"returned-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"hidden-return.json": "aca1f30149f3613624cd6edbfad31ff8f5741c5d692ba4be677ccc7026e693fc",
|
||||
"final-H1.png": "043ef1d76e3380c62b0814442eb1826694c0dea6bbccf588c82ca8e287b8d63b",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "e8f7acb21ab8ad8ea50c7489843880b4f53644e9e685f523fcfc288b4e94e4d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "input-A",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/input-A/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "21e4b3fa9ca286fcd87bdb5dc29124db82a1e64dfa66796edc0fbdaf51864e2b",
|
||||
"events.jsonl": "b2f905f388c6d509d6903278427ab1fce621971ce213a95aedc55204e84ed802",
|
||||
"proc-maps.txt": "fe5e78525052bfa72c69d02bf4718278ba1194d6e2e19979ac79c5febd46b8f0",
|
||||
"startup-snapshot.json": "c6c0c2c1976df287666c4a3fa15824a5e2a8beae707e233d64399ff3610f8ea0",
|
||||
"pointer.log": "fe237edf7bb69048ce89981d665bd088c8e71b119febad1ff91c1797dfcbe7cf",
|
||||
"reference.log": "f509f287a549c7b3dfa70a3213215d9d727ef5c22ca8e1b27912d3675b4f027e",
|
||||
"filler0.log": "4e0598de2329ea342444b27d5fd513801a5c9e43ed0d2cd1c16250ce8e929db4",
|
||||
"owner.log": "96328f4c4ecba56fa45bf091089afcdb8d979dd4dd30c7b32a1b70640179d578",
|
||||
"owner-owner-snapshot.json": "c0c14c80f07806448cba8a580d849758ba06346a409d77c627e3b580ac3d1960",
|
||||
"owner-geometry.json": "5edb333831bdad267e016416812d37687bea153357cab20700ad78600202cbb3",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"input-full.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"input-full-input.json": "a9310b4e2e63988171fb83360140703500e13e4b8b188bfea561766f050faf78",
|
||||
"input-empty.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"input-empty-hit.json": "535d54c0e036d3909d96077ee65c780fd6b344cc94ce4ad86d7c8a905854016b",
|
||||
"input-full-restored.png": "6b894d918bcf019e1af9b01633bae8d5f243d5986d4c7ce2b5cb4baf86e2ac49",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "7df43df25e3f1c67a06b9b6b350451597817e7318c5ed56576b800160cb779c1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "input-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/input-G/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "06bde607ace63acb9666e4f81129d374e1cd312d7ec8531a152ef43b5fed8bdc",
|
||||
"events.jsonl": "53500793e945af552b572f8082a09e539a33e3d37fc786571009f83ea7e256bb",
|
||||
"proc-maps.txt": "5bc06fb6d78e08cde18f9a1c39320b07b6f199d4bfa07df5073438f076975537",
|
||||
"startup-snapshot.json": "d3afd4a7418e771c7f69329243d1fe2bc34c14d708324e5bd726514c095707b8",
|
||||
"pointer.log": "fe237edf7bb69048ce89981d665bd088c8e71b119febad1ff91c1797dfcbe7cf",
|
||||
"reference.log": "b3c7055ac62cf9cc9e26c7813e8c5738244b0da8135ab64ae75a63bd305596b0",
|
||||
"filler0.log": "3dda37af670fd0d1741a2ace0fd0d39f5bddf6ccbfbbd9efebcc1ddff45b7cbe",
|
||||
"owner.log": "dc923ad56b76616f5c8131c658f338fc8453447292f125b69a2a1abb36b0bf5f",
|
||||
"owner-owner-snapshot.json": "b0b6ee83cc18614c24cf33a67b02d0042f209664fdf4f4ea198a7ce518eaf1a0",
|
||||
"owner-geometry.json": "b8c8162b64931cad0eaaa9d80f82913c99294e909f7ce10fc957bae90fb08511",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"input-full.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"input-full-input.json": "95fdd1d18cd215cbbe32bc9d0ec31c0868297659a376eb503fa18446d2636f75",
|
||||
"input-empty.png": "c8d50e1a0e52074bf595a82a56d5db9f1790cf0cfd7e510c32ceceeba4295802",
|
||||
"input-empty-hit.json": "1aa983007e0aa4042b323c595f01f95528fe1fa978f7e601eba6fad6b3f96c37",
|
||||
"input-full-restored.png": "6b894d918bcf019e1af9b01633bae8d5f243d5986d4c7ce2b5cb4baf86e2ac49",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "e2c570306af5796cca2e5d175609c30c781495730526e386f3fcd22842e3b564"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "input-pristine",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/input-pristine/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "3b8d627618173d97ca70e460b05d63bbf76e5d18e001c69931369761a599745d",
|
||||
"events.jsonl": "aac792b7e5955ab526f2df5bd02e78928a0818bd5d265bf46cbd96f47ea6bb34",
|
||||
"proc-maps.txt": "91408c07681fcec99a6be26827de154010130f271c23f4938f81f1281b6ece18",
|
||||
"startup-snapshot.json": "712b37aeca088c1735c35a8a7d5c18463c88f13465c63c8917cd88404cc9b975",
|
||||
"pointer.log": "a6e268d9eb34998e6bb23c1d1892a8eb519d774d43f216dcd848fada3fc21ea5",
|
||||
"reference.log": "a1e10e4f67a827f64db7d01422c8aa656c6c1aebc5f5e57fbb767c8c0cfcfe64",
|
||||
"filler0.log": "31e9add25ae7023a1d90d5a5c399fad48ecec31ff5b3e52321c5e2ab257de5aa",
|
||||
"owner.log": "265d1d62f902e441f625c3feeb0ca17100721f8c5c19772ef5b01ecbdbb99ade",
|
||||
"owner-owner-snapshot.json": "7d539e5c351442f96a51a01399d953659ee25509b2ae5c18269e10e23c6620a2",
|
||||
"owner-geometry.json": "721042027f7a0c04b44ba5ebff820c41d072ba4c914c29ec12a5872e19fe890d",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"input-full.png": "4b4edf47fa1194970064c535874f41c1a14ec54e62a649ba6ef53a0e627d3306",
|
||||
"input-full-input.json": "91b82a56738e44fe37e08dee0129881b310598fa22716ecb7e3a38d1a8cc4cfb",
|
||||
"input-empty.png": "4b4edf47fa1194970064c535874f41c1a14ec54e62a649ba6ef53a0e627d3306",
|
||||
"input-empty-hit.json": "b01594a2e8977600b72c703b80dde2d9e83e668e30ac1662524f75d7ce90fd22",
|
||||
"input-full-restored.png": "a4bf16bd1ee95218dc251b10c7c198b6442a088a57cae8c5819fca8bdbb79a38",
|
||||
"input-full-restored-input.json": "6e138b324e545692b1c9516c1437438324e12828454feb43f1403c87ff1648c9",
|
||||
"input-focus-return.png": "4b4edf47fa1194970064c535874f41c1a14ec54e62a649ba6ef53a0e627d3306",
|
||||
"input-focus-return-input.json": "406e74ff84484b3c91909633e8b73d81550472707d925398f8bf9f97616a6c4d",
|
||||
"input-camera-standard.json": "c34f36dc65136b775b06d2c3107bd2bce00509995bbfbed0c3d92cd95a57926f",
|
||||
"final-H1.png": "2437fcf9c5b8d22608267b04d71978759e15fb80dc2b0815c1f08785606d2a03",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"ordering.json": "3667e4d01b494955cb531df015174438ff95359d753d10eb324a06cdc58379b8",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "1e290e2b08b4d32db0cd91f5ffacf9c8c660ef046a44b03c81e34b50022e1e4e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "saved-A",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/saved-A/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "35582ff061c83a4c4cd72ea0c085da23a2148b9bfa6cd625cdace22182e2a62c",
|
||||
"events.jsonl": "7840e7991521fed44b36dff5bc3a4dedf55f7bd54dd80cbf99e951183fd12cbf",
|
||||
"proc-maps.txt": "644ed380687c412aba5327921978c39b89447d3af424ce29f929657350a99261",
|
||||
"startup-snapshot.json": "b153ac04db4253cac2b9b96768a0737a9083a9df38f71503cfaf9e3d16e464cf",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "5e89194bf40cd62d69a50aedf1966a355782f720f628cf55fa7e0c04233fe8b4",
|
||||
"filler0.log": "c0be00b4083c47e80e30917e58bf31f25d3ddd9024d7b5de15707be1924a665a",
|
||||
"filler1.log": "f0ad968bdc050cd05a86fdffc9aebaa0fffef3b98e81a3061c8d43d21797211b",
|
||||
"owner.log": "2739ba7f8d34f4fbb78fbdb1e05dbf1b34abd2e736e5bfde2841315f3e26a923",
|
||||
"owner-owner-snapshot.json": "a26930c2b0adad692f7614595560bd127283181d25e347c9f5d67135861cbd8c",
|
||||
"owner-geometry.json": "5b3d8add11b13eda352dc208914b9a0064406ff9f8f89670111841346a070958",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"saved-requested-pending-snapshot.json": "4c009988df286ae76af388d2d98243c61b6f13276db7434eadd46601a2f0b437",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "e797815de3b23e66424b6d00b4b2639c6510f2efcf60af626da4df0b02c1c250"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "saved-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/saved-G/run",
|
||||
"files": {
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "cff5199c5c06cfee77ddae4937ecd99ebce09242f86443609fed12012b642267",
|
||||
"events.jsonl": "e9258ce207e9b2073b326d0a0794fb9c100fe26bd6528857118f5e172cb67063",
|
||||
"proc-maps.txt": "6ac5807ed418d69d0e56fb8be9dd1e1a1f4813db31c102c7d0aa248aeab355aa",
|
||||
"startup-snapshot.json": "a048b806bc43b856462353e195eb536a02c50e8b785e0c5aad4c6246ecd0e7a6",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "630ceea878eef2935bfbc7fe765256c6ce6defbd067f8ae22149206117ce1952",
|
||||
"filler0.log": "8b8b498fabe925cd2e1659d014fee4a6801011d16ed434bd1e001e704137437a",
|
||||
"filler1.log": "4a11b3ad473149343dfae447f7e288d030a8fbf88bc0fc2dd0529164ee55d079",
|
||||
"owner.log": "6309a039d27aca36c77d69db7ccd724d126e4463a392b4c6091d3b1743a77d6c",
|
||||
"owner-owner-snapshot.json": "a0dd3b9ee33d88c7488bc6a503b84f7379e2d65ac17224e9bea504ae6f91116a",
|
||||
"owner-geometry.json": "5f9e4a0f1536290575a11508657b48a496911d88174fcc282c6b6caae2045c04",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"saved-requested-pending-snapshot.json": "4505eae047274183149af21fe2c39eeee427b0b0f2ea6d9c5f4d2c40791b1dd2",
|
||||
"terminal-ipc.json": "c4d44ea275c98e70966926571f95b83a96776fdf06ebf987bc2b2fa9f9a85630",
|
||||
"outcome.json": "315cf9f1cc526d9780a18e7692a20b441b51a30aae00fe83a48ad33a1750320a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "scale-A",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/scale-A/run",
|
||||
"files": {
|
||||
"marker-source.png": "2ffcdcfc7a14d060c15ae86bee9ed4d9163ba7cd42622945c0b1fe2b393957f7",
|
||||
"events.jsonl": "1a5acacefb0b9d098d5250c03e57ae92ec4b4dc5aced799b361cce1ed5da1a4a",
|
||||
"config": "c9f351c52645e2cb502693da4611830db556dad40e8505e148bc716b5f89bfec",
|
||||
"compositor.log": "9ef49fd6870b1a20f17b57da6987b96e31e49b794d66a3a364f574d182612605",
|
||||
"proc-maps.txt": "a6be34e6fb0a84defcf3cdfe6a85f01c3c871348d910e35d7cd77f5696dd7f7e",
|
||||
"startup-snapshot.json": "4f38851513922f688c3fa24cad783628d95de3a3bef529be791323aa6ea6dc5d",
|
||||
"marker-background.log": "d915401b74aca571acc3145a93696735b71de371b805406ce21b9765b18380d9",
|
||||
"marker-H1.png": "204c8f996e37d45cf6e305100fd30c68b96b3e0e10c37e399c9c2bd117002a15",
|
||||
"pointer.log": "890f2ba41f88e4e1bfbd94b9c0decb73bd762e0d8b679f406571ee2894ebb3e9",
|
||||
"reference.log": "93c91e82caa874c25f089bfa290a617d2583881f43128ae81c4b3e99564c6eb7",
|
||||
"filler0.log": "63a5916fc0d2f7e3cef40cbfa86e4c2825a4732873dcc4867ff82c9346cbf790",
|
||||
"pre-XDG-marker-host-snapshot.json": "dcdb6594db8d2de36090ad34498988c71ae6d4a69250d65b34015a58aac538aa",
|
||||
"marker-host-baseline.json": "c4bd035b65521a0277abc6a447674bdf6b83ff998415810844eda6d4a2f14245",
|
||||
"owner.log": "550b53b8bce8e1ed0d2bc3543183e6859d114d84a6c2e4f7c1e2b8ca71ccf405",
|
||||
"owner-owner-snapshot.json": "0860660d84f5c47ca97959d49a91dbcaab1548920408d5402514cd2d48263320",
|
||||
"owner-geometry.json": "310611c2265267363c3cc55d04cce63eda7f54429f8d69f89397242aa6957e15",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"owner-top.png": "06a57ee107d8e977097e89427e95f4b262e64640c30b5d6d7dfcd686cdd984c8",
|
||||
"popup-A.png": "19ce9dfa9e742c6b5485b7f99fe833f12ac6d3ef7f3c17c6f7a6c173ff034ab4",
|
||||
"mapped-H1.png": "6543284c04d97a2a33b6b1517caceed41709f0fd3f5b9308878c8b34c115fdaf",
|
||||
"mapped-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"chain.json": "bc8fb22183f6ce8af860cb203c7d71c6e7b241a31eab5ba562a04d039e50f5bd",
|
||||
"dismissal.json": "5571b94fcd3a770229597d7dd22ed9d0ee780adf1360a0f6b8722e367fb8ed79",
|
||||
"final-H1.png": "11ddbf5b32b8194f8d4da18fa733fe9eb37a806a441347a54acf0250d417f549",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "14aa15e5266861d83b91f18cf58b77d980450597f87172f9ceeea556e9ff66f5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "scale-G",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/scale-G/run",
|
||||
"files": {
|
||||
"marker-source.png": "2ffcdcfc7a14d060c15ae86bee9ed4d9163ba7cd42622945c0b1fe2b393957f7",
|
||||
"events.jsonl": "80dfe8b69232f8f747d1a14ddf108682ef7916a24fa39129e77d4d4d1187f9b1",
|
||||
"config": "c9f351c52645e2cb502693da4611830db556dad40e8505e148bc716b5f89bfec",
|
||||
"compositor.log": "b2df5c1e5df3c9457adcd28ebc3492f4e32577962a447cee9e5701ed26564a18",
|
||||
"proc-maps.txt": "ba8c31a591279375e804a05594d1ff1e2184b851f44b710c2626f91c473fcda4",
|
||||
"startup-snapshot.json": "302ea15d98387fe3020b70b20fc468d71bcc63e06e5d224b0395101c4df37a89",
|
||||
"marker-background.log": "fd617ba6d7d873ac993ca58cef311bf855dae667c922166593422e6a8754585c",
|
||||
"marker-H1.png": "204c8f996e37d45cf6e305100fd30c68b96b3e0e10c37e399c9c2bd117002a15",
|
||||
"pointer.log": "890f2ba41f88e4e1bfbd94b9c0decb73bd762e0d8b679f406571ee2894ebb3e9",
|
||||
"reference.log": "054eca77ee1bdf847a8dbad5e809a5419f0bf663af94eaadddee697ea5e2b91b",
|
||||
"filler0.log": "2dfacfc7f2b7e7cada6b4e82152cd1fca8752a0bec0b1737d68b08e0f4e28e2f",
|
||||
"pre-XDG-marker-host-snapshot.json": "1a86543a9f9c8b77ceb21ead0d383b47094409fc601b734f29e9f9b73a5de866",
|
||||
"marker-host-baseline.json": "3fd87bd8a12eae05ebf05d6b1090c48c369136dcfebcb1b5f2f1431ce56679e3",
|
||||
"owner.log": "df8b2de07ca6cd0de7fbd0eb45cf3670aa33befa39962db4cecbfca4c13245d5",
|
||||
"owner-owner-snapshot.json": "30a5a16afda64a153463f0b3bb90f2d1d51531f2f03bf956c34fe3a2077f08b5",
|
||||
"owner-geometry.json": "2ad62319666d906ab4a86a7e23f5f4b0926a0cd428e718b538389701b77f7325",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"owner-top.png": "06a57ee107d8e977097e89427e95f4b262e64640c30b5d6d7dfcd686cdd984c8",
|
||||
"popup-A.png": "19ce9dfa9e742c6b5485b7f99fe833f12ac6d3ef7f3c17c6f7a6c173ff034ab4",
|
||||
"mapped-H1.png": "6543284c04d97a2a33b6b1517caceed41709f0fd3f5b9308878c8b34c115fdaf",
|
||||
"mapped-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"chain.json": "faa813c2a698d0356b74b44649912f2c5a05b1e0ea2f1fb7f15393b2cc445f65",
|
||||
"dismissal.json": "925033c205dda20ca46df08dd2dd11a85057bb4f05662450b9fdbb5cd75c755c",
|
||||
"final-H1.png": "11ddbf5b32b8194f8d4da18fa733fe9eb37a806a441347a54acf0250d417f549",
|
||||
"final-H2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "879a8500808032a4182ce370c5c0e835a849f3847a14b9c4861d2505e9b81311"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "saved-diagnostic-A",
|
||||
"prefix": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/runs/saved-diagnostic-A/run",
|
||||
"files": {
|
||||
"events.jsonl": "ddca83fe5397e880ce7110161680b7d41aaf73f56c22631c4cbf1830b90590a3",
|
||||
"config": "caf7cdff074714cb5b2ba35827558ce5a7defda125de034a7d42296f03b0528b",
|
||||
"compositor.log": "c938794a8ffb07d84a22885e6185e42828443c84b5b7f235c61972504626f880",
|
||||
"proc-maps.txt": "219f56cd5416deab1cc8e5523973cb431bdb5c24e0dd38954bc53bf20a00ee9a",
|
||||
"startup-snapshot.json": "fc971dd8e00ff1c57ead682a0a5b06e3e3a2dc4cc05f74e9d17869f0521fcb5b",
|
||||
"pointer.log": "b6402bc7876885515cb1dc9396155bb23cd51ef01d4258de9c6c49370e262511",
|
||||
"reference.log": "7089eee517ae8f651274a426a2fe17708543247f448bd6849dce076ee1049163",
|
||||
"filler0.log": "9b3fea8da49ca338691e66a0837486e97d77b0102beb3dbeaf3f36316e5aaaa2",
|
||||
"filler1.log": "08fd0c1c310354be6791535ee04d208819bf2c61592e0937a7afc3757a344a9b",
|
||||
"owner.log": "ab06b86f586c3550ebd817bdceffd66c0fc4d3db8c7047e532381826e9568ee6",
|
||||
"owner-owner-snapshot.json": "9f05f5790979d39d8f3c956ddeae07f9bd4e6a15b018e4385fc508e80d7b80e2",
|
||||
"owner-geometry.json": "ee860521c319294b2768140d046e47d3c69b0d574d690c2de41e2636ab5fb5c0",
|
||||
"H2-reference1.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"H2-reference2.png": "4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a",
|
||||
"reference-stability.json": "f6557d7b4e29b35adcaeafbd4391ebd72faf26d4d8a870c4f668a0d3236e1c78",
|
||||
"initial-applied.json": "f129a291ff6191d5607e2bfc02b5d8e47a9b4fabad3e9d5f7f7a5e24601025b5",
|
||||
"saved-requested-pending-snapshot.json": "a8586bf76fa89399f05fdb3a7d4fdb2a06028950bf9667edc49c480928147d61",
|
||||
"terminal-ipc.json": "accbe83ba60a7d349826055467de0064ed4dad87a200c9bf854a5bcdd61bf829",
|
||||
"outcome.json": "97f021073c5e1fc5a766b5b9af55b3e786e8913cd7939cd6c33c25efe27a3936"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
47
tooling/probes/step20c-targeted-results/README.md
Normal file
47
tooling/probes/step20c-targeted-results/README.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# STEP20C targeted closure evidence
|
||||
|
||||
EXPERIMENTAL / PARTIALLY_ADVANCED. STEP20C remains NEXT and production
|
||||
multi-output remains NOT YET SUPPORTED. This directory records the consumed
|
||||
targeted batch separately from its immutable pre-execution fixtures.
|
||||
|
||||
`RESULTS.json` separates measurements, raw runtime/runner status, scientific
|
||||
cleanup and architecture verdict for all fourteen attempts. `ARTIFACTS.json`
|
||||
binds the 460 retained run files, including 125 PNGs, by SHA-256. Images, logs,
|
||||
SHM, binaries, builds and the future packaging recipe remain in the private
|
||||
laboratory `/home/fy59/swayfx-mosaic-targeted-7gge6h8b`, outside Git. Historical
|
||||
evidence in `/home/fy59/swayfx-mosaic-overnight-mcolx0gq` was read only.
|
||||
|
||||
The [closure report](../../../docs/design/STEP20C_TARGETED_CLOSURE_DECISION.md)
|
||||
and [decision draft](../../../docs/design/STEP20C_PRODUCTION_INTEGRATION_DECISION_DRAFT.md)
|
||||
describe the observations, risks and remaining gates. Positive sampled results
|
||||
do not qualify all frames, GPU lifetime, atomic generations or a future ABI
|
||||
pair. Whole-H1 A-return inequality is an observed failure in pristine/A/G;
|
||||
its INCONCLUSIVE marker concerns causal diagnosis and integration readiness.
|
||||
|
||||
The original [core fixture](../step20c-targeted/README.md) and
|
||||
[diagnostic fixture](../step20c-targeted-diagnostic/README.md) retain their
|
||||
reviewed bytes, including known limitations exposed by consumed attempts:
|
||||
|
||||
- Saved A/G requested an IPC workspace gaps field absent from this binary.
|
||||
- Input A/G refreshed geometry before clicking, but focus changed the camera
|
||||
during the third click. The wire coordinates match the later applied origin.
|
||||
- C3 rejected legitimate reuse of a native node address. Its retained native
|
||||
creation/render/teardown observations do not replace the rejected runtime
|
||||
predicate or prove natural timeout removal.
|
||||
- All fourteen raw terminal IPC exit responses are failures despite recorded
|
||||
process exits zero. Cleanup and positive measurements are recorded separately.
|
||||
|
||||
Do not launch, repair and retry a consumed ID, reset a ledger, edit a historic
|
||||
receipt, or treat a synthetic offline trace as runtime evidence. The diagnostic
|
||||
binary is distinct from A/G. Its passive listener/log overhead is experimental.
|
||||
|
||||
Read-only verification of the compact records and retained files:
|
||||
|
||||
```sh
|
||||
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-targeted-results/verify_evidence.py
|
||||
```
|
||||
|
||||
This command hashes files only; it launches no compositor and does not write
|
||||
or reopen a run. Publication commits cannot contain their own future SHA.
|
||||
The final publication references and independent-review receipt are recorded
|
||||
in the private closeout manifest and final user report.
|
||||
2415
tooling/probes/step20c-targeted-results/RESULTS.json
Normal file
2415
tooling/probes/step20c-targeted-results/RESULTS.json
Normal file
File diff suppressed because it is too large
Load diff
20
tooling/probes/step20c-targeted-results/REVIEW.json
Normal file
20
tooling/probes/step20c-targeted-results/REVIEW.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"schema": "STEP20C_TARGETED_ACCEPTED_REVIEW_V1",
|
||||
"independent": true,
|
||||
"status": "ACCEPTED",
|
||||
"receipt_sha256": "28f868a0d956e70290db0515f59404e9f930e7180a89e326bcabda9ff6ea47ae",
|
||||
"report_sha256": "73f06404ccfaa985cd6e279e606debeb8899bd1dd9079c88fdf5a01be98354ec",
|
||||
"offline_tests": 43,
|
||||
"additional_negative_mutations_rejected": 22,
|
||||
"blocking": 0,
|
||||
"nonblocking": 1,
|
||||
"future_scope": 3,
|
||||
"private_report": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/reviews/targeted-final-review.md",
|
||||
"private_receipt": "/home/fy59/swayfx-mosaic-targeted-7gge6h8b/reviews/targeted-final-review.json",
|
||||
"reviewed_complete_diff_sha256": "436aa0565ec22021d38d24128165b8ac79a1586d0c97af60e9cce217018d7102",
|
||||
"immutable_fixture_files": 21,
|
||||
"scientific_status": "EXPERIMENTAL / PARTIALLY_ADVANCED",
|
||||
"recommendation": "PRIVATE_CANDIDATE_NEEDS_TARGETED_EVIDENCE",
|
||||
"publication": "pre-commit snapshot; actual final refs in private closeout and final user report",
|
||||
"administrative_changes": "Only accepted N01 wording, review outcome/provenance metadata, PNG accounting and final hash supplements; bounded delta review required before commit."
|
||||
}
|
||||
45
tooling/probes/step20c-targeted-results/verify_evidence.py
Normal file
45
tooling/probes/step20c-targeted-results/verify_evidence.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
"""Read-only integrity checks for retained targeted evidence.
|
||||
|
||||
WHY: published compact records must resolve to actual retained bytes.
|
||||
CONTRACT: this verifies integrity, never scientific readiness or a runtime gate.
|
||||
INVARIANT: no launch, ledger mutation, receipt rewrite or inferred buffer identity.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def sha(path):
|
||||
h = hashlib.sha256()
|
||||
with Path(path).open("rb") as stream:
|
||||
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
||||
h.update(block)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def verify(directory):
|
||||
directory = Path(directory)
|
||||
repo = directory.parents[2]
|
||||
results = json.loads((directory / "RESULTS.json").read_text())
|
||||
artifacts = json.loads((directory / "ARTIFACTS.json").read_text())
|
||||
bindings = list(results["provenance"])
|
||||
bindings += [{"path": str(repo / x["path"]), "sha256": x["sha256"]}
|
||||
for x in results["frozen_source_bindings"]]
|
||||
for run in artifacts["runs"]:
|
||||
bindings += [{"path": str(Path(run["prefix"]) / name), "sha256": digest}
|
||||
for name, digest in run["files"].items()]
|
||||
failures = []
|
||||
for binding in bindings:
|
||||
try:
|
||||
if sha(binding["path"]) != binding["sha256"]:
|
||||
failures.append(binding["path"])
|
||||
except OSError:
|
||||
failures.append(binding["path"])
|
||||
if failures:
|
||||
raise ValueError("Missing or changed retained files: " + ", ".join(failures))
|
||||
return {"status": "INTEGRITY_PASS", "bindings": len(bindings),
|
||||
"scientific_readiness": "NOT_ASSERTED"}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(json.dumps(verify(Path(__file__).resolve().parent), sort_keys=True))
|
||||
88
tooling/probes/step20c-targeted/README.md
Normal file
88
tooling/probes/step20c-targeted/README.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# STEP20C targeted fixtures
|
||||
|
||||
EXPERIMENTAL / PLANNED. These source fixtures repair bounded measurement
|
||||
procedures identified in the overnight evidence. STEP20C remains NEXT;
|
||||
production multi-output remains NOT YET SUPPORTED. No production integration,
|
||||
UX policy, package dependency, compositor build, installation or live socket
|
||||
operation is part of this fixture.
|
||||
|
||||
The new private laboratory is
|
||||
`/home/fy59/swayfx-mosaic-targeted-7gge6h8b` (owned mode 0700). The historical
|
||||
`/home/fy59/swayfx-mosaic-overnight-mcolx0gq` is read only: its 18 runs are
|
||||
exhausted. Historical verdicts remain unchanged. Public Python tests accept
|
||||
`--historical` so paths can be supplied explicitly.
|
||||
|
||||
`plans.py` declares 13 accessible attempts: scale A/G, held saved A/G, effects
|
||||
pristine/A/G, refreshed input pristine/A/G and G dynamic/hidden/R90. The
|
||||
independent ledger permits at most 14 attempts, at most 16 compositor PNGs
|
||||
per attempt, campaign PNG caps scale24/saved30/FX48/input36/G36, and total174.
|
||||
Current planned allocation is164. The unused saved diagnostic is disabled;
|
||||
it requires a separate parent decision, exact diagnostic identity and distinct
|
||||
review/freeze. No diagnostic attempt is consumed by preparation.
|
||||
|
||||
Every launch/action reserves first in the same locked persistent ledger.
|
||||
It uses `flock`, atomic replacement, file and directory `fsync`; a consumed
|
||||
run token persists on failure. There is no reset, refund or retry operation.
|
||||
Local click/motion/grab/chain/camera/mutation/configuration/spawn/capture limits
|
||||
are reconciled from every reservation. The watchdog stops active measurement
|
||||
at143 seconds and limits the total run logs to32MiB. Cleanup retains terminal
|
||||
IPC response, normal process codes, rescue status and150-second bound.
|
||||
|
||||
`engine.Session(spec, auth, lab)` exposes `owner`, `find`, `cmd`, `client_cmd`,
|
||||
`capture`, `pair_capture`, `click`, `close_client`, `debit`, `spawn`, `log`,
|
||||
`launch_client`, `wait`, `save`, `calibrate` and `inject`. Clients are under
|
||||
`LAB/clients`; raw run evidence is `LAB/runs/<id>/run`. All compositor/control
|
||||
IPC explicitly names its private socket; inherited display/library selections
|
||||
are removed.
|
||||
|
||||
Scale/R90 uses five marker pixels and the reviewed pre-owner layer-host
|
||||
baseline before identifying one new XDG root. The same shared root validator
|
||||
replays actual D2 and rejects host substitution, multiple candidates, missing
|
||||
host, incorrect ancestry and incoherent callback order. Replay qualifies
|
||||
association only; it does not invent missing historical input/final evidence.
|
||||
|
||||
Held saved uses source-audited `gaps inner current set 30` and startup
|
||||
`-Dtxn-timeout=2500`. It requires mapped real SHM, a previous actual ACK,
|
||||
a new received configure held without ACK, and a natural waiting transaction
|
||||
timeout with the client alive. Actual argv plus source and elapsed timeout
|
||||
corroborate2500ms; no native configured-value log exists. A/G expose no saved
|
||||
node/render identity. SHM and pixels cannot fill that gap, so saved clipping
|
||||
remains INCONCLUSIVE / SOURCE ONLY.
|
||||
|
||||
Input recomputes painted global coordinates after region restore, focus,
|
||||
camera and layout mutations. It requires fresh local pointer coordinates,
|
||||
actual client wire/button serial and target. The empty region intentionally
|
||||
uses the previous global point to compare no owner delivery. Historical F
|
||||
analysis processes ALL exact output/commit_seq pairs and reports missing
|
||||
presents. No atomic generation, presented buffer identity or GPU lifetime is
|
||||
inferred. Dynamic G samples fresh popup input after each resize/migration;
|
||||
legitimate popup_done is retained and fresh toplevel input is sampled without
|
||||
recreating a popup chain. Hidden G retains the same chain on return.
|
||||
|
||||
Preparation and validation are offline:
|
||||
|
||||
```sh
|
||||
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-targeted/prepare.py --lab LAB
|
||||
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-targeted/test_targeted.py --historical HIST --output LAB/offline.json
|
||||
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-targeted/replay.py --historical HIST --output LAB/replay.json
|
||||
```
|
||||
|
||||
Preparation verifies retained binary/client/protocol hashes and privately
|
||||
compiles only the new FX client. Generated protocol headers/C, binaries, SHM,
|
||||
logs, captures and runtime directories remain outside Git. `identity.json`
|
||||
records copied client source SHA and provenance closure. `gate.seal(LAB)`
|
||||
requires14 passing core tests and5 passing FX tests, executed commands, raw output and exact source bindings, plus typed actual D2/F/E2 replay receipts and binds all fixture/import/client/tool/
|
||||
binary/library/source evidence. A separate independent reviewer must write
|
||||
`LAB/review.json` with scope `STEP20C_TARGETED_FINAL_BYTES_V1`, exact freeze SHA
|
||||
and file bindings, accepted read-only independent review, empty blockers and
|
||||
bound report bytes. The author does not create that acceptance.
|
||||
|
||||
Only after independent acceptance and explicit runtime authorization:
|
||||
|
||||
```sh
|
||||
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-targeted/run.py --lab LAB scale-A
|
||||
```
|
||||
|
||||
Each invocation is one unique attempt. A missing or changed acceptance fails
|
||||
before a run token, process or runtime exists. This fixture does not launch an
|
||||
entire campaign automatically. Unexercised matrix cells remain NOT TESTED.
|
||||
220
tooling/probes/step20c-targeted/cases.py
Normal file
220
tooling/probes/step20c-targeted/cases.py
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
"""Small campaign scenarios over the same reviewed Session; no historical runner copy."""
|
||||
import re,time
|
||||
from PIL import ImageChops
|
||||
from engine import *
|
||||
from geometry import *
|
||||
|
||||
def init_reference(s,prefix_fillers=1):
|
||||
s.cmd('workspace 2');s.launch_client('reference','static-reference');rid=s.find('reference')['id'];s.cmd(f'[con_id={rid}] border none')
|
||||
s.cmd('workspace 1')
|
||||
for i in range(prefix_fillers):s.launch_client('filler'+str(i),'static-reference')
|
||||
s.cmd('layout mosaic' if s.spec['mode']=='mosaic' else 'layout splith')
|
||||
return rid
|
||||
|
||||
def stable_reference(s):
|
||||
s.inject('move',[s.outputs[0]['logical'][0]+10,s.outputs[0]['logical'][1]+590]);time.sleep(.15)
|
||||
a=s.capture('H2-reference1','HEADLESS-2');time.sleep(.6);b=s.capture('H2-reference2','HEADLESS-2');exact(a,b)
|
||||
need(all(v==(48,48,56) for v in a.get_flattened_data()),'static uniform H2');s.save('reference-stability',dict(status='PASS',exact=exact(a,b)));return a
|
||||
|
||||
def marker_host_baseline(s):
|
||||
"""D3-only pre-XDG association: source + creation timing + cardinality.
|
||||
|
||||
This does not observe native owner IDs or host child count. No root is
|
||||
selected by clip/index after the owner exists.
|
||||
"""
|
||||
from transition import observed_epochs
|
||||
need(s.spec.get('marker',False) and s.spec['mode']=='mosaic' and 'owner' not in s.proc,'prospective pre-owner marker baseline')
|
||||
marker=s.proc.get('marker-background');need(marker is not None and marker.poll() is None,'live marker layer client')
|
||||
start=next(e['ns'] for e in s.events if e['kind']=='spawn' and e['name']=='marker-background')
|
||||
end=time.monotonic_ns();trace=s.log('compositor')
|
||||
creations=[l for l in trace.splitlines() if 'new layer surface: namespace ' in l]
|
||||
need(len(creations)==1 and 'namespace wallpaper layer 0 ' in creations[0],'one wallpaper layer creation')
|
||||
snapshot=s.snapshot('pre-XDG-marker-host')
|
||||
need(not any(n.get('app_id')=='org.mosaic.NestedGrabProbe' for n in nodes(snapshot['tree'])),'no popup owner before baseline')
|
||||
epochs=observed_epochs(trace,'HEADLESS-1',start,end);tree=None;observed=[]
|
||||
for e in epochs:
|
||||
need(e['scene'] is not None,'complete baseline callback')
|
||||
roots=e['roots']
|
||||
if not roots:
|
||||
need(tree is None,'marker host disappeared before owner');continue
|
||||
need(len(roots)==1,'unique pre-XDG host')
|
||||
r=roots[0]
|
||||
need(r.get('local_index')=='1' and r.get('enabled')=='1' and r.get('clip_valid')=='0' and r.get('clip')=='0,0,0,0','source-backed ordinary layer host')
|
||||
if tree is None:tree=r['tree']
|
||||
need(r['tree']==tree,'stable pre-XDG host')
|
||||
observed.append(e)
|
||||
need(len(observed)>=2,'two complete pre-XDG host observations')
|
||||
baseline=dict(tree=tree,window=[start,end],epochs=epochs,layer_creation=creations[0],marker_pid=marker.pid,snapshot=snapshot,
|
||||
correlation='single layer constructor + pre-owner timing + stable cardinality; no native layer ID or child count')
|
||||
s.save('marker-host-baseline',baseline);s.marker_host=baseline
|
||||
return baseline
|
||||
|
||||
def associated_root(roots,baseline=None,commit_ns=None):
|
||||
if baseline is None:
|
||||
need(len(roots)==1 and roots[0].get('local_index')=='1','unique first popup root');return roots[0]
|
||||
need(commit_ns is not None and commit_ns>baseline['window'][1],'root callback after pre-XDG baseline')
|
||||
need(len(roots)==2 and len({r.get('tree') for r in roots})==2,'one known layer host plus one new XDG root')
|
||||
need([r.get('local_index') for r in roots]==['1','2'],'native host order retained')
|
||||
known=[r for r in roots if r.get('tree')==baseline['tree']]
|
||||
need(len(known)==1 and known[0].get('enabled')=='1' and known[0].get('clip_valid')=='0' and known[0].get('clip')=='0,0,0,0','same unchanged known layer host')
|
||||
return next(r for r in roots if r['tree']!=baseline['tree'])
|
||||
|
||||
def root_state(s,state,origin,window_start,expect_hidden=False,previous=None,expected_tree=None):
|
||||
from transition import observed_epochs
|
||||
from ipc_predicates import ancestry
|
||||
end=time.monotonic_ns();output=state['workspace']['output']
|
||||
out=next(o['logical'] for o in s.outputs if o['name']==output)
|
||||
need(state['workspace']['layout']=='mosaic' and origin==state['origin'],'current Mosaic origin')
|
||||
path=ancestry(state['snapshot']['tree'],state['owner']['id'])
|
||||
need(path and path[-1]['id']==state['owner']['id'],'exact IPC owner ancestry')
|
||||
need([n['id'] for n in path if n.get('type')=='workspace']==[state['workspace']['id']] and
|
||||
[n['name'] for n in path if n.get('type')=='output']==[output],'exact workspace output ancestry')
|
||||
live=[n for n in nodes(state['snapshot']['tree']) if n.get('app_id')==state['owner']['app_id'] and n.get('visible')]
|
||||
need(len(live)==1 and live[0]['id']==state['owner']['id'],'unique live XDG owner')
|
||||
prot=protocol(s.log('owner'));need(len(prot['grabs'])==2,'two real grabs')
|
||||
epochs=observed_epochs(s.log('compositor'),output,window_start,end)
|
||||
rows=[];trees=set();applied=False
|
||||
for e in epochs:
|
||||
c,sc,roots=e['commit'],e['scene'],e['roots']
|
||||
need(c.get('has_buffer') in ('0','1') and sc is not None and sc.get('workspace')==str(state['workspace']['id']) and sc.get('layout')=='5','complete current callback workspace/layout')
|
||||
owners=[o for o in e['owners'] if o.get('id')==str(state['owner']['id'])]
|
||||
need(len(owners)==1 and owners[0].get('scene_valid')=='1','exact applied owner')
|
||||
r=associated_root(roots,getattr(s,'marker_host',None),int(c['ns']))
|
||||
o=owners[0];trees.add(r['tree'])
|
||||
need(len(trees)==1 and (expected_tree is None or r['tree']==expected_tree),'same live root')
|
||||
need(int(c['ns'])<int(sc['ns'])<int(o['ns'])<int(r['ns']),'callback record order')
|
||||
scene=list(map(int,o['scene'].split(',')))+list(map(int,o['applied_size'].split(',')))
|
||||
target=scene==state['scene']
|
||||
old=previous is not None and scene==previous['scene']
|
||||
need(target or (old and not applied),'unexpected or stale applied owner geometry')
|
||||
chosen=state if target else previous
|
||||
need(o['current']==','.join(str(chosen['owner']['rect'][k] if k!='y' else chosen['owner']['rect'][k]-chosen['owner']['deco_rect']['height']) for k in ('x','y','width','height')) or
|
||||
list(map(int,o['current'].split(',')))==exterior_ipc(chosen['owner']),'current owner geometry')
|
||||
win=chosen['owner']['window_rect'];actual=[scene[0]+win['x'],scene[1]+chosen['owner']['deco_rect']['height']+win['y']]
|
||||
need(actual==chosen['origin'],'applied content origin')
|
||||
box=list(map(int,r['clip'].split(',')));global_box=[box[0]+actual[0],box[1]+actual[1],*box[2:]]
|
||||
hidden=intersection(scene,out)[2]==0 or intersection(scene,out)[3]==0
|
||||
need(r['enabled']=='1' and r['clip_valid']=='1','enabled clipped root')
|
||||
need((box[2]==0 or box[3]==0) if hidden else global_box==out,'every comparable root clip')
|
||||
tile=list(map(int,sc['tile_scene'].split(',')));clip=list(map(int,sc['clip'].split(',')))
|
||||
need(sc['clip_valid']=='1' and [out[0]+tile[0]+clip[0],out[1]+tile[1]+clip[1],*clip[2:]]==out,'applied tiling viewport')
|
||||
if target:
|
||||
need(hidden==expect_hidden,'target visibility');applied=True
|
||||
rows.append(dict(state='applied-target' if target else 'old-applied',owner=o,scene=sc,root=r,commit=c,local_clip=box,global_clip=global_box,raw=e['raw'],all_roots=roots,known_layer_host=getattr(s,'marker_host',{}).get('tree')))
|
||||
need(applied,'target applied callback missing')
|
||||
return dict(tree=next(iter(trees)),states=rows,window=[window_start,end],ids=prot['ids'],marker_baseline=getattr(s,'marker_host',None),correlation='bounded unique live XDG hierarchy and exact IPC ancestry; no native parent ID or atomic generation')
|
||||
|
||||
def open_chain(s,tail_fillers=0):
|
||||
if s.spec.get('marker',False) and s.spec['mode']=='mosaic':marker_host_baseline(s)
|
||||
s.debit('chain');s.launch_client('owner',s.spec['client'],s.spec['placement'])
|
||||
for i in range(tail_fillers):s.launch_client('tail'+str(i),'static-reference')
|
||||
s.cmd(f'[con_id={s.find("owner")["id"]}] focus');state=s.calibrate('owner');baseline=stable_reference(s)
|
||||
im=s.capture('owner-top','HEADLESS-1');rect=[*state['origin'],state['owner']['window_rect']['width'],state['owner']['window_rect']['height']]
|
||||
xy=solid_point(im,COLORS['TOPLEVEL'],s.outputs[0],s.frames['HEADLESS-1'],rect)
|
||||
need(contains([*state['origin'],420,575 if s.spec['campaign']=='D1' else 320],xy),'opening native bounds')
|
||||
ta,ba=s.click('owner',xy,'left',True);s.wait(lambda:'POPUP_A MAP ' in s.log('owner'));time.sleep(.2)
|
||||
aim=s.capture('popup-A','HEADLESS-1');prov=Provenance(state['owner']['id'],state['workspace']['id'],'bounded-opening-window',state['evidence'])
|
||||
xyA=solid_point(aim,COLORS['POPUP_A'],s.outputs[0],s.frames['HEADLESS-1'])
|
||||
tb,bb=s.click('owner',xyA,'left',True);s.wait(lambda:'POPUP_B MAP ' in s.log('owner'));time.sleep(.2)
|
||||
window=time.monotonic_ns();time.sleep(.15);p=protocol(s.log('owner'));g=geometry(s.log('owner'),state['origin'],prov)
|
||||
s.delivery('owner',rect,xy,ta,ba,'TOPLEVEL',p['grabs'][0]['serial']);s.delivery('owner',g['A'],xyA,tb,bb,'POPUP_A',p['grabs'][1]['serial'])
|
||||
need(all(crossing(g[k],s.spec['axis'],s.spec['boundary']) for k in ('A','B')),'actual root and child crossing NOT EXERCISED')
|
||||
left,right=s.pair_capture('mapped')
|
||||
for name in ('POPUP_A','POPUP_B'):
|
||||
need(count(left,COLORS[name])>0,'permitted popup pixels missing')
|
||||
if s.spec['mode']=='pristine':need(count(right,COLORS[name])>0,'standard popup continuation missing')
|
||||
if s.spec['mode']=='mosaic':
|
||||
exact(baseline,right)
|
||||
root=root_state(s,state,state['origin'],window)
|
||||
else:root=dict(status='NOT OBSERVABLE',meaning='unmodified control has no private clip instrumentation')
|
||||
s.save('chain',dict(protocol=p,geometry=g,state=state,root=root,H2_exact=s.spec['mode']=='mosaic',color_counts={n:[count(left,c),count(right,c)] for n,c in COLORS.items()}))
|
||||
return state,baseline,p,g,left,right
|
||||
|
||||
def popup_campaign(s):
|
||||
init_reference(s);state,baseline,p,g,left,right=open_chain(s)
|
||||
xy=solid_point(left,COLORS['POPUP_B'],s.outputs[0],s.frames['HEADLESS-1'],g['B']);tails,buttons=s.click('owner',xy);s.delivery('owner',g['B'],xy,tails,buttons,'POPUP_B')
|
||||
forbidden=intersection(g['B'],s.outputs[1]['logical']);need(forbidden[2]>6 and forbidden[3]>6,'H2 crossing interior missing')
|
||||
xy=[forbidden[0]+forbidden[2]//2,forbidden[1]+forbidden[3]//2]
|
||||
if s.spec['mode']=='pristine':
|
||||
# The point must be real standard paint, not just a requested extent.
|
||||
xy=solid_point(right,COLORS['POPUP_B'],s.outputs[1],s.frames['HEADLESS-2'],g['B']);tails,buttons=s.click('owner',xy);s.delivery('owner',g['B'],xy,tails,buttons,'POPUP_B')
|
||||
else:
|
||||
tails,buttons=s.click('owner',xy);ds=dismissal(tails['owner'],buttons['owner']);s.save('dismissal',dict(proof=ds,reference_buttons=buttons.get('reference'),interpretation='outside grab dismissal; no universal click-through claim'))
|
||||
need(not any('target=POPUP_A ' in l or 'target=POPUP_B ' in l for v in buttons.values() for l in v),'forbidden popup delivery')
|
||||
s.close_client('owner');time.sleep(.2);final=s.pair_capture('final');exact(baseline,final[1]);need(not any(count(im,COLORS[n]) for im in final for n in ('POPUP_A','POPUP_B')),'popup residual')
|
||||
return 'PASS'
|
||||
|
||||
def hidden_campaign(s):
|
||||
init_reference(s,2);state,baseline,p,g,left,right=open_chain(s,2)
|
||||
xy=solid_point(left,COLORS['POPUP_B'],s.outputs[0],'logical',g['B']);tails,buttons=s.click('owner',xy);s.delivery('owner',g['B'],xy,tails,buttons,'POPUP_B')
|
||||
delta=state['scene'][0]+state['scene'][2]-s.outputs[0]['logical'][0]+16;start=time.monotonic_ns();s.scroll('owner',delta);hidden=s.owner('owner')
|
||||
need(intersection(hidden['scene'],s.outputs[0]['logical'])[2]==0,'owner not completely hidden')
|
||||
images=s.pair_capture('fully-hidden');need(not any(count(im,COLORS[n]) for im in images for n in ('POPUP_A','POPUP_B')),'hidden popup residual');exact(baseline,images[1])
|
||||
root=root_state(s,hidden,hidden['origin'],start,True,previous=state);cut=len(s.log('owner'));s.inject('move',[-790,590]);need('target=POPUP_A ' not in s.log('owner')[cut:] and 'target=POPUP_B ' not in s.log('owner')[cut:],'hidden popup pointer enter')
|
||||
return_start=time.monotonic_ns();s.scroll('owner',-delta);restored=s.owner('owner');need(restored['origin']==state['origin'],'same owner origin restored')
|
||||
images=s.pair_capture('returned');exact(baseline,images[1]);returned_root=root_state(s,restored,restored['origin'],return_start,previous=hidden,expected_tree=root['tree']);fresh=protocol(s.log('owner'));need(fresh['ids']==p['ids'] and fresh['grabs']==p['grabs'],'unchanged live chain')
|
||||
xy=solid_point(images[0],COLORS['POPUP_B'],s.outputs[0],'logical',g['B']);tails,buttons=s.click('owner',xy);s.delivery('owner',g['B'],xy,tails,buttons,'POPUP_B')
|
||||
s.save('hidden-return',dict(status='PASS',hidden=hidden,empty_root=root,returned=restored,returned_root=returned_root,ids=p['ids']))
|
||||
s.close_client('owner');final=s.pair_capture('final');exact(baseline,final[1]);return 'PASS'
|
||||
|
||||
|
||||
def saved_campaign(s):
|
||||
from validators import held_configure
|
||||
init_reference(s,2);s.launch_client('owner','saved-client');s.cmd(f'[con_id={s.find("owner")["id"]}] focus');state=s.calibrate('owner');baseline=stable_reference(s)
|
||||
before=s.log('owner');serials=re.findall(r'ACK ns=\d+ serial=(\d+)',before);need(serials,'initial ACK');prior=int(serials[-1]);need('COMMIT ns=' in before,'initial mapped SHM')
|
||||
# Parse source contract + /proc argv; observed elapsed timeout corroborates
|
||||
# the assigned 2500ms value, without inventing a native saved-node record.
|
||||
argv=Path(f'/proc/{s.comp.pid}/cmdline').read_bytes().split(b'\0');need(b'-Dtxn-timeout=2500' in argv,'actual startup timeout option')
|
||||
s.client_cmd('owner','hold_next_configure','COMMAND hold_next_configure DONE');cut=len(s.log('owner'));ccut=len(s.log('compositor'));request=time.monotonic_ns()
|
||||
s.cmd('workspace 1');request=time.monotonic_ns();s.cmd('gaps inner current set 30',True);pending=s.snapshot('saved-requested-pending');pending_owner=s.find('owner');pending_ws=workspace(pending['tree'],'1');need(pending_owner['id']==state['owner']['id'] and pending_ws['id']==state['workspace']['id'] and pending_ws.get('gaps',{}).get('inner')==30,'same ws1 owner and requested runtime gaps')
|
||||
s.wait(lambda:'HELD ' in s.log('owner')[cut:]);proof=held_configure(before,s.log('owner')[cut:],prior);need(proof['ns']>request,'held configure after runtime geometry command');need(proof['requested_size']==[pending_owner['window_rect']['width'],pending_owner['window_rect']['height']],'wire requested size matches pending IPC geometry')
|
||||
elapsed=(time.monotonic_ns()-request)/1e9;need(elapsed<2.1,'held observation must precede natural timeout')
|
||||
held=s.pair_capture('held');need((time.monotonic_ns()-request)/1e9<2.45,'held capture finished before deadline')
|
||||
s.wait(lambda:'timed out (' in s.log('compositor')[ccut:],seconds=3.5)
|
||||
timeout_ns=time.monotonic_ns();need(re.search(r'timed out \(\d*[1-9]\d* waiting\)',s.log('compositor')[ccut:]),'transaction actually waiting at natural timeout');need(timeout_ns-request>=2_300_000_000,'observed timeout consistent with2500ms');need(s.proc['owner'].poll() is None,'client alive at natural timeout')
|
||||
proof=held_configure(before,s.log('owner')[cut:],prior);after=s.pair_capture('natural-timeout');exact(baseline,held[1]);exact(baseline,after[1])
|
||||
s.save('saved-observability',dict(status='INCONCLUSIVE',request_ns=request,timeout_observed_ns=timeout_ns,held=proof,startup_argv=[v.decode() for v in argv],initial_state=state,pending_snapshot=pending,pending_owner=pending_owner,requested_workspace=pending_ws,
|
||||
source_timeout_ms=2500,natural_timeout=[l for l in s.log('compositor')[ccut:].splitlines() if 'timed out (' in l],saved_node_identity='NOT OBSERVABLE',saved_render_identity='NOT PROVEN',saved_clipping='SOURCE_ONLY; SHM not a native saved-node identity'))
|
||||
s.close_client('owner','close');final=s.pair_capture('final');exact(baseline,final[1]);return 'INCONCLUSIVE'
|
||||
|
||||
def input_campaign(s):
|
||||
from validators import native_pairs
|
||||
init_reference(s);s.launch_client('owner','region-client','both_cross');s.cmd(f'[con_id={s.find("owner")["id"]}] focus');s.calibrate('owner');baseline=stable_reference(s)
|
||||
point=s.fresh_delivery('owner','input-full')
|
||||
s.client_cmd('owner','region_empty_top','COMMAND region_empty_top DONE');time.sleep(.15)
|
||||
empty_state=s.owner('owner');empty=s.capture('input-empty','HEADLESS-1')
|
||||
# Deliberately unchanged global point is the empty-region comparison.
|
||||
tails,buttons=s.click('owner',point);need(not buttons.get('owner'),'empty region owner button');s.save('input-empty-hit',dict(point=point,state=empty_state,buttons=buttons,tails=tails))
|
||||
s.client_cmd('owner','region_full_top','COMMAND region_full_top DONE');time.sleep(.15);s.fresh_delivery('owner','input-full-restored')
|
||||
s.cmd(f'[con_id={s.find("filler0")["id"]}] focus',True);s.cmd(f'[con_id={s.find("owner")["id"]}] focus',True);time.sleep(.2);s.fresh_delivery('owner','input-focus-return')
|
||||
if s.spec['mode']=='mosaic':
|
||||
s.scroll('owner',20);s.fresh_delivery('owner','input-camera')
|
||||
s.cmd(f'[con_id={s.find("owner")["id"]}] layout splith',True);time.sleep(.35);s.fresh_delivery('owner','input-standard')
|
||||
else:
|
||||
s.save('input-camera-standard',dict(camera='NOT APPLICABLE: unmodified pristine control',standard='already splith'))
|
||||
s.close_client('owner');final=s.pair_capture('final');exact(baseline,final[1]);s.save('ordering',dict(status='INCONCLUSIVE',pairs=native_pairs(s.log('compositor')),native_hit='NOT OBSERVABLE',atomic_generation='NOT PROVEN',buffer_lifetime='NOT PROVEN'))
|
||||
return 'INCONCLUSIVE'
|
||||
|
||||
def dynamic_campaign(s):
|
||||
init_reference(s,2);state,baseline,p,g,left,right=open_chain(s);owner_id=state['owner']['id'];ws_id=state['workspace']['id'];order=state['workspace']['mosaic']['rows'][0]['children'];stages=[]
|
||||
for out,tag,mode in [('HEADLESS-1','resize960',960),('HEADLESS-1','resize800',800),('HEADLESS-2','migrationH2',None),('HEADLESS-1','migrationH1',None)]:
|
||||
if mode:
|
||||
s.cmd(f'output HEADLESS-1 resolution {mode}x600 position {-mode} 0',True);s.outputs[0]={**s.outputs[0],'logical':[-mode,0,mode,600],'mode':[mode,600]}
|
||||
else:s.cmd('workspace 1');s.cmd(f'move workspace to output {out}',True)
|
||||
start=time.monotonic_ns();time.sleep(.35);current=s.owner('owner');need(current['owner']['id']==owner_id and current['workspace']['id']==ws_id and current['workspace']['output']==out,'exact migrated identity/output')
|
||||
need(current['workspace']['mosaic']['rows'][0]['children']==order,'logical order retained');image=s.capture(tag,out)
|
||||
done=re.findall(r'POPUP_[AB] POPUP_DONE',s.log('owner'))
|
||||
if done:
|
||||
win=current['owner']['window_rect'];rect=[*current['origin'],min(win['width'],420),min(win['height'],320)];output=next(o for o in s.outputs if o['name']==out);point=solid_point(image,COLORS['TOPLEVEL'],output,s.frames[out],rect);tails,buttons=s.click('owner',point);delivery=s.delivery('owner',rect,point,tails,buttons,'TOPLEVEL');live=dict(status='POPUP NOT EXERCISED; TOPLEVEL SAMPLED',reason='legitimate popup_done; no chain recreation',done=done,point=point)
|
||||
else:
|
||||
fresh=protocol(s.log('owner'));need(fresh['ids']==p['ids'] and fresh['grabs']==p['grabs'],'same live chain')
|
||||
prov=Provenance(owner_id,ws_id,'fresh-stage',current['evidence']);geo=geometry(s.log('owner'),current['origin'],prov)
|
||||
output=next(o for o in s.outputs if o['name']==out);point=solid_point(image,COLORS['POPUP_B'],output,s.frames[out],geo['B']);tails,buttons=s.click('owner',point);delivery=s.delivery('owner',geo['B'],point,tails,buttons,'POPUP_B')
|
||||
root=root_state(s,current,current['origin'],start);live=dict(status='SAMPLED',geometry=geo,point=point,delivery=delivery,root_clip=root)
|
||||
if mode is None:
|
||||
other=next(o for o in s.outputs if o['name']!=out);vacated=s.capture(tag+'-other',other['name']);need(not any(count(vacated,COLORS[n]) for n in ('POPUP_A','POPUP_B')),'old output popup residual')
|
||||
stages.append(dict(tag=tag,state=current,live=live))
|
||||
s.save('dynamic-ownership',dict(status='PARTIALLY_FEASIBLE',stages=stages,atomic_generation='NOT PROVEN'))
|
||||
s.close_client('owner');final=s.pair_capture('final');exact(baseline,final[1]);return 'PASS'
|
||||
|
||||
CAMPAIGN={'scale':popup_campaign,'saved':saved_campaign,'input':input_campaign,'G':lambda s: {'dynamic':dynamic_campaign,'hidden':hidden_campaign,'R90':popup_campaign}[s.spec['case']](s)}
|
||||
205
tooling/probes/step20c-targeted/engine.py
Normal file
205
tooling/probes/step20c-targeted/engine.py
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
"""Bounded owned headless session, usable only after the separate matrix review gate."""
|
||||
import json,os,re,shutil,signal,subprocess,tempfile,threading,time
|
||||
from pathlib import Path
|
||||
from PIL import Image,ImageDraw
|
||||
from geometry import *
|
||||
from gate import BASE,sha,clean_environment,action_debit
|
||||
import sys
|
||||
sys.path.insert(1,str(BASE))
|
||||
from ipc_predicates import nodes,workspace
|
||||
from predicates import protocol,geometry,pair,dismissal
|
||||
from lifecycle import opening_pair
|
||||
from model import Provenance
|
||||
COLORS={'TOPLEVEL':(35,68,204),'POPUP_A':(224,192,32),'POPUP_B':(32,208,160)}
|
||||
|
||||
class Session:
|
||||
def __init__(self,spec,auth,lab):
|
||||
self.spec=spec;self.auth=auth;self.lab=Path(lab);self.folder=self.lab/'runs'/spec['id'];self.run=self.folder/'run';self.run.mkdir();self.coordinate_epoch=0;self.proofs={}
|
||||
self.runtime=Path(tempfile.mkdtemp(prefix='m20-',dir='/tmp'));self.runtime.chmod(0o700)
|
||||
self.env=clean_environment();self.env.update(XDG_RUNTIME_DIR=str(self.runtime),WLR_BACKENDS='headless',WLR_HEADLESS_OUTPUTS='2',OPT_TRACE='1')
|
||||
self.outputs=[dict(o) for o in spec['outputs']];self.frames={o['name']:'logical' for o in self.outputs}
|
||||
self.proc={};self.handles=[];self.started=time.monotonic();self.finished=threading.Event();self.expired=False;self.events=[];self.pointer=None
|
||||
def start(self):
|
||||
spec=self.spec;auth=self.auth
|
||||
cfg='\n'.join(f"output {o['name']} resolution {o['mode'][0]}x{o['mode'][1]} scale {o['scale']} transform {o['transform']} position {o['logical'][0]} {o['logical'][1]}" for o in self.outputs)
|
||||
cfg+='\nworkspace 1 output HEADLESS-1\nworkspace 2 output HEADLESS-2\nfocus_follows_mouse no\nseat seat0 hide_cursor 100\nshadows disable\nblur disable\n'
|
||||
if spec.get('marker',False):
|
||||
marker=Image.new('RGB',(800,600),(30,30,46));draw=ImageDraw.Draw(marker)
|
||||
for k,box in [('TL',(15,15,44,44)),('TR',(755,15,784,44)),('BL',(15,555,44,584)),('BR',(755,555,784,584)),('C',(385,285,414,314))]:draw.rectangle(box,fill=MARKERS[k])
|
||||
marker.save(self.run/'marker-source.png');self.marker_source=self.run/'marker-source.png';self.record('generated-content-PNG',path=str(self.marker_source),counts_as_capture=False)
|
||||
(self.run/'config').write_text(cfg);self.watch=threading.Thread(target=self.watchdog,daemon=True);self.watch.start()
|
||||
self.comp=self.spawn('compositor',[auth['binary'],'-d',*(['-Dtxn-timeout=2500'] if spec['campaign']=='saved' else []),'-c',self.run/'config'])
|
||||
self.sock=self.wait(lambda:next(iter(self.runtime.glob('sway-ipc.*.sock')),None));display=self.wait(lambda:next((p for p in self.runtime.glob('wayland-*') if p.is_socket()),None))
|
||||
self.env.update(WAYLAND_DISPLAY=display.name,SWAYSOCK=str(self.sock));need(Path(f'/proc/{self.comp.pid}/exe').resolve()==Path(auth['binary']).resolve(),'actual executable')
|
||||
maps=Path(f'/proc/{self.comp.pid}/maps').read_text();(self.run/'proc-maps.txt').write_text(maps)
|
||||
paths={s.split()[-1] for s in maps.splitlines() if len(s.split())>=6 and s.split()[-1].startswith('/')}
|
||||
wl=[Path(p).resolve() for p in paths if 'libwlroots' in p];need(wl==[Path(auth['wlroots'])] and sha(wl[0])==auth['wlroots_sha256'],'mapped wlroots')
|
||||
scene=[Path(p).resolve() for p in paths if 'libscenefx' in p]
|
||||
if spec['mode']=='mosaic':need(not scene,'static SceneFX')
|
||||
else:need(scene==[Path(auth['pristine_scene'])] and sha(scene[0])==auth['pristine_scene_sha256'],'mapped pristine SceneFX')
|
||||
render=[s for s in self.log('compositor').splitlines() if any(x in s for x in ('Creating scenefx FX renderer','GL renderer:','GL vendor:','Using OpenGL ES'))]
|
||||
need(any('Creating scenefx FX renderer' in s for s in render) and any('GL renderer:' in s for s in render),'actual renderer')
|
||||
self.record('actual-renderer',lines=render);self.snapshot('startup')
|
||||
if spec.get('marker',False):
|
||||
self.spawn('marker-background',['swaybg','-o','HEADLESS-1','-i',self.marker_source,'-m','fill']);time.sleep(.35)
|
||||
im=self.capture('marker-H1','HEADLESS-1',orientation_pending=True);m=marker_frame(im,self.outputs[0]['scale'],self.outputs[0]['transform']=='90');self.frames['HEADLESS-1']=m['frame'];self.record('marker-frame',**m)
|
||||
self.pointer=self.spawn('pointer',[self.lab/'clients/pointer-daemon']);self.wait(lambda:'POINTER_READY' in self.log('pointer'))
|
||||
def record(self,kind,**fields):
|
||||
e=dict(kind=kind,ns=time.monotonic_ns(),**fields);self.events.append(e)
|
||||
with (self.run/'events.jsonl').open('a') as f:f.write(json.dumps(e)+'\n')
|
||||
def save(self,name,value):
|
||||
(self.run/(name+'.json')).write_text(json.dumps(value,indent=2)+'\n')
|
||||
def debit(self,*kinds):action_debit(self.lab,self.spec['id'],*kinds)
|
||||
def spawn(self,name,argv,debug=False):
|
||||
need(not self.expired,'expired before spawn');self.debit('spawn');f=(self.run/(name+'.log')).open('w');self.handles.append(f)
|
||||
p=subprocess.Popen(list(map(str,argv)),stdin=subprocess.PIPE,stdout=f,stderr=subprocess.STDOUT,text=True,start_new_session=True,env={**self.env,**({'WAYLAND_DEBUG':'1'} if debug else {})})
|
||||
self.proc[name]=p;self.record('spawn',name=name,pid=p.pid,argv=list(map(str,argv)));return p
|
||||
def log(self,name):return (self.run/(name+'.log')).read_text(errors='replace')
|
||||
def wait(self,fn,seconds=5):
|
||||
end=min(self.started+143,time.monotonic()+seconds)
|
||||
while time.monotonic()<end:
|
||||
need(not self.expired,'watchdog')
|
||||
if hasattr(self,'comp'):need(self.comp.poll() is None,'unexpected compositor exit')
|
||||
v=fn()
|
||||
if v:return v
|
||||
time.sleep(.02)
|
||||
raise Ambiguous('bounded wait timeout')
|
||||
def watchdog(self):
|
||||
while not self.finished.wait(.1):
|
||||
if time.monotonic()-self.started>143 or sum(p.stat().st_size for p in self.run.glob('*.log'))>32*1024*1024:
|
||||
self.expired=True
|
||||
for p in list(self.proc.values()):
|
||||
try:os.killpg(p.pid,signal.SIGTERM)
|
||||
except ProcessLookupError:pass
|
||||
return
|
||||
def ipc(self,*args,strict=True):
|
||||
need(self.sock.is_relative_to(self.runtime) and self.sock.is_socket(),'private socket')
|
||||
self.record('ipc-request',args=args)
|
||||
p=subprocess.run(['swaymsg','-s',str(self.sock),*args],env=self.env,capture_output=True,text=True,timeout=4)
|
||||
self.record('ipc-reply',args=args,exit=p.returncode,stdout=p.stdout,stderr=p.stderr)
|
||||
if strict:need(p.returncode==0,'IPC command failure')
|
||||
return json.loads(p.stdout) if p.returncode==0 else None
|
||||
def cmd(self,command,business=False):
|
||||
self.invalidate('IPC '+command);self.debit('mutation' if business else 'configuration');reply=self.ipc(command);need(all(r['success'] for r in reply),'command rejected')
|
||||
def snapshot(self,tag,validate=True):
|
||||
snap=dict(tree=self.ipc('-t','get_tree'),outputs=self.ipc('-t','get_outputs'),workspaces=self.ipc('-t','get_workspaces'),ns=time.monotonic_ns())
|
||||
if validate:expected_outputs(snap['outputs'],self.outputs)
|
||||
self.save(tag+'-snapshot',snap);return snap
|
||||
def find(self,name):
|
||||
pid=self.proc[name].pid;rows=[n for n in nodes(self.ipc('-t','get_tree')) if n.get('pid')==pid];need(len(rows)<=1,'client owner ambiguity');return rows[0] if rows else None
|
||||
def launch_client(self,name,client,*args):
|
||||
p=self.spawn(name,[self.lab/'clients'/client,*args],True);self.wait(lambda:self.find(name));time.sleep(.25);return p
|
||||
def capture(self,tag,out,orientation_pending=False):
|
||||
self.debit('capture');spec=next(o for o in self.outputs if o['name']==out);p=self.run/(tag+'.png');need(not p.exists(),'capture unique')
|
||||
t=time.monotonic_ns();r=subprocess.run(['grim','-s',str(spec['scale']),'-o',out,str(p)],env=self.env,capture_output=True,text=True,timeout=4)
|
||||
self.record('capture',tag=tag,output=out,start_ns=t,end_ns=time.monotonic_ns(),exit=r.returncode,path=str(p),sha256=sha(p) if p.exists() else None)
|
||||
need(r.returncode==0,'capture failure');im=Image.open(p).convert('RGB')
|
||||
logical=tuple(round(v*spec['scale']) for v in spec['logical'][2:]);physical=tuple(spec['mode'])
|
||||
need(im.size==logical or (orientation_pending and im.size==physical) or (self.frames[out]=='physical90' and im.size==physical),'PNG size')
|
||||
return im
|
||||
def pair_capture(self,tag):return [self.capture(tag+'-H1','HEADLESS-1'),self.capture(tag+'-H2','HEADLESS-2')]
|
||||
def inject(self,action,point,grab=False):
|
||||
need(action in ('move','left','right'),'injection action');outs=self.ipc('-t','get_outputs');active=[o for o in outs if o['active']]
|
||||
rects=[[o['rect'][k] for k in ('x','y','width','height')] for o in active];need(any(contains(r,point) for r in rects),'logical point outside output')
|
||||
minx=min(r[0] for r in rects);miny=min(r[1] for r in rects);w=max(r[0]+r[2] for r in rects)-minx;h=max(r[1]+r[3] for r in rects)-miny
|
||||
self.debit('move',*(['click'] if action!='move' else []),*(['grab'] if grab else []))
|
||||
sent=[point[0]-minx,point[1]-miny];marker=f'INJECT_DONE {action} {sent[0]},{sent[1]}';before=self.log('pointer').count(marker)
|
||||
self.pointer.stdin.write(f'{action} {sent[0]} {sent[1]} {w} {h}\n');self.pointer.stdin.flush();self.wait(lambda:self.log('pointer').count(marker)>before)
|
||||
self.record('injection',action=action,global_logical=point,sent=sent,logical_extent=[w,h],grab=grab);time.sleep(.12)
|
||||
def click(self,name,point,action='right',grab=False):
|
||||
before={n:len(self.log(n)) for n in self.proc if n not in ('compositor','pointer','background')};t=time.monotonic_ns();self.inject(action,point,grab)
|
||||
tails={n:self.log(n)[i:] for n,i in before.items()};lines={n:[s for s in v.splitlines() if s.startswith(('POINTER_BUTTON ','BUTTON '))] for n,v in tails.items()}
|
||||
self.record('click-observation',name=name,point=point,start_ns=t,tails=tails,buttons=lines)
|
||||
return tails,lines
|
||||
def delivery(self,name,rect,point,tails,lines,target,opening_serial=None):
|
||||
need(not any(v for n,v in lines.items() if n!=name),'wrong client received popup button')
|
||||
proof=opening_pair(lines[name],target,opening_serial) if opening_serial else pair(lines[name],target)
|
||||
rows=re.findall(rf'POINTER_(?:ENTER|MOTION) target={target} .*?x=([\d.-]+) y=([\d.-]+)',tails[name]);need(rows,'fresh pointer local coordinates')
|
||||
local=list(map(float,rows[-1]));need(local==[point[0]-rect[0],point[1]-rect[1]],'logical pointer correlation')
|
||||
for e in proof:need(re.search(rf'wl_pointer#\d+\.button\({e[1]}, \d+, {e[2]}, {e[3]}\)',tails[name]) is not None,'button actual wire')
|
||||
return proof
|
||||
def owner(self,name):
|
||||
snap=self.snapshot(name+'-owner');owner=self.find(name);need(owner is not None and owner.get('visible'),'owner visibility')
|
||||
ws=workspace(snap['tree'],'1');need(any(n['id']==owner['id'] for n in nodes(ws)),'owner workspace ancestry')
|
||||
if self.spec['mode']=='mosaic':origin,scene,raw=actual_origin(owner,self.log('compositor'))
|
||||
else:origin=assigned_origin(owner);scene=exterior_ipc(owner);raw='current IPC assigned exterior inverse; applied scene NOT OBSERVABLE; paint/pointer corroboration required'
|
||||
data=dict(owner=owner,workspace=ws,origin=origin,scene=scene,evidence=raw,snapshot=snap);self.save(name+'-geometry',data);return data
|
||||
def calibrate(self,name):
|
||||
state=self.owner(name)
|
||||
if self.spec['mode']=='mosaic' and self.spec['axis']==0:
|
||||
delta=int(state['origin'][0]+state['owner']['window_rect']['width']//2)
|
||||
if delta:self.scroll(name,delta)
|
||||
state=self.owner(name);need(crossing([*state['origin'],state['owner']['window_rect']['width'],state['owner']['window_rect']['height']],0,0),'owner real x0 crossing')
|
||||
return state
|
||||
def scroll(self,name,delta):
|
||||
self.debit('camera');self.cmd(f'[con_id={self.find(name)["id"]}] layout mosaic scroll {int(delta)}');time.sleep(.35)
|
||||
self.record('camera',owner=self.find(name)['id'],delta=int(delta))
|
||||
def client_cmd(self,name,cmd,marker=None):
|
||||
self.invalidate('client '+cmd);self.debit('configuration' if cmd.startswith('close') else 'mutation');before=len(self.log(name));self.record('client-request',name=name,command=cmd)
|
||||
self.proc[name].stdin.write(cmd+'\n');self.proc[name].stdin.flush()
|
||||
if marker:self.wait(lambda:marker in self.log(name)[before:])
|
||||
def close_client(self,name,command='close_owner'):
|
||||
self.client_cmd(name,command);code=self.proc[name].wait(timeout=3);need(code==0,'normal client exit');self.wait(lambda:self.find(name) is None)
|
||||
def invalidate(self,reason):
|
||||
self.coordinate_epoch+=1;self.proofs.clear();self.record('coordinate-invalidation',epoch=self.coordinate_epoch,reason=reason)
|
||||
def painted_point(self,name,tag,target='TOPLEVEL',rectangle=None):
|
||||
state=self.owner(name);out=next(o for o in self.outputs if o['name']==state['workspace']['output'])
|
||||
image=self.capture(tag,out['name']);win=state['owner']['window_rect']
|
||||
rect=rectangle or [*state['origin'],min(win['width'],420),min(win['height'],320)]
|
||||
point=solid_point(image,COLORS[target],out,self.frames[out['name']],rect)
|
||||
self.proofs[tuple(point)]=dict(epoch=self.coordinate_epoch,state=state,rectangle=rect,target=target)
|
||||
self.record('painted-point',name=name,point=point,epoch=self.coordinate_epoch,rectangle=rect,target=target)
|
||||
return state,rect,point,image
|
||||
def fresh_delivery(self,name,tag,target='TOPLEVEL'):
|
||||
state,rect,point,image=self.painted_point(name,tag,target)
|
||||
proof=self.proofs[tuple(point)];need(proof['epoch']==self.coordinate_epoch,'stale selected point')
|
||||
tails,buttons=self.click(name,point)
|
||||
delivery=self.delivery(name,rect,point,tails,buttons,target)
|
||||
self.save(tag+'-input',dict(state=state,rectangle=rect,point=point,delivery=delivery,epoch=self.coordinate_epoch))
|
||||
return point
|
||||
def cleanup(self,measurement_status,failure=None):
|
||||
terminal=None;rescue=False
|
||||
if hasattr(self,'comp') and self.comp.poll() is None and hasattr(self,'sock') and self.sock.is_socket():
|
||||
try:
|
||||
p=subprocess.run(['swaymsg','-s',str(self.sock),'exit'],env=self.env,capture_output=True,text=True,timeout=2)
|
||||
terminal=dict(ipc_exit=p.returncode,stdout=p.stdout,stderr=p.stderr)
|
||||
self.save('terminal-ipc',terminal)
|
||||
except Exception as e:
|
||||
terminal=dict(ipc_error=str(e));self.save('terminal-ipc',terminal)
|
||||
if terminal is not None and 'ipc_exit' in terminal:
|
||||
try:self.comp.wait(timeout=1)
|
||||
except Exception as e:
|
||||
terminal['wait_error']=str(e);self.save('terminal-ipc',terminal)
|
||||
codes=[]
|
||||
# One shared cleanup deadline prevents N owned clients multiplying waits.
|
||||
cleanup_end=time.monotonic()+2
|
||||
if self.pointer and self.pointer.poll() is None and self.pointer.stdin and not self.pointer.stdin.closed:self.pointer.stdin.close()
|
||||
for name,p in reversed(list(self.proc.items())):
|
||||
if p.poll() is None:
|
||||
try:p.wait(timeout=max(.01,cleanup_end-time.monotonic()))
|
||||
except subprocess.TimeoutExpired:pass
|
||||
residual=[p for p in self.proc.values() if p.poll() is None]
|
||||
if residual:
|
||||
rescue=True
|
||||
for p in residual:
|
||||
try:os.killpg(p.pid,signal.SIGKILL)
|
||||
except ProcessLookupError:pass
|
||||
kill_end=time.monotonic()+1
|
||||
for p in residual:p.wait(timeout=max(.01,kill_end-time.monotonic()))
|
||||
for name,p in self.proc.items():
|
||||
codes.append(dict(name=name,pid=p.pid,exit=p.returncode))
|
||||
if p.stdin and not p.stdin.closed:p.stdin.close()
|
||||
self.finished.set();self.watch.join(timeout=1)
|
||||
for h in self.handles:h.close()
|
||||
for p in self.proc.values():
|
||||
try:os.killpg(p.pid,0)
|
||||
except ProcessLookupError:pass
|
||||
else:rescue=True;os.killpg(p.pid,signal.SIGKILL)
|
||||
reaped=all(not Path('/proc',str(p.pid)).exists() for p in self.proc.values());need(reaped,'owned process residual');shutil.rmtree(self.runtime)
|
||||
seconds=time.monotonic()-self.started
|
||||
protocol_errors=[n for n in self.proc if n not in ('compositor','pointer') and re.search(r'wl_display[^\n]*\.error\(|protocol error|invalid_popup_parent|not_the_topmost_popup',self.log(n),re.I)]
|
||||
cleanup_pass=bool(not rescue and reaped and seconds<=150 and not self.expired and not protocol_errors and all(p['exit']==0 for p in codes))
|
||||
transport_pass=terminal is not None and terminal.get('ipc_exit')==0 and 'wait_error' not in terminal and 'ipc_error' not in terminal
|
||||
final_status=measurement_status if cleanup_pass and transport_pass else 'INCONCLUSIVE'
|
||||
self.save('outcome',dict(status=final_status,measurements_status=measurement_status,failure=failure,terminal=terminal,processes=codes,rescue=rescue,reaped=reaped,runtime_removed=not self.runtime.exists(),seconds=seconds,watchdog=self.expired,protocol_errors=protocol_errors,cleanup_pass=cleanup_pass,transport_status='PASS' if transport_pass else 'INCONCLUSIVE'))
|
||||
return final_status
|
||||
333
tooling/probes/step20c-targeted/fx-client.c
Normal file
333
tooling/probes/step20c-targeted/fx-client.c
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "layer-shell-client.h"
|
||||
#include "xdg-shell-client.h"
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
/* WHY: one persistent background supplies real A/B commits below blur_tree.
|
||||
* CONTRACT: fixed opaque background, premultiplied ARGB glass and static H2.
|
||||
* INVARIANT: no animation, synthetic configure, popup or held transaction. */
|
||||
static struct wl_display *display;
|
||||
static struct wl_compositor *compositor;
|
||||
static struct wl_shm *shm;
|
||||
static struct xdg_wm_base *wm;
|
||||
static struct zwlr_layer_shell_v1 *shell;
|
||||
static struct wl_output *h1;
|
||||
static struct wl_surface *surface;
|
||||
static struct xdg_surface *xdg;
|
||||
static struct xdg_toplevel *top;
|
||||
static struct zwlr_layer_surface_v1 *layer;
|
||||
static const char *mode;
|
||||
static int width = 420, height = 320;
|
||||
static unsigned commits, live_buffers, releases;
|
||||
static bool close_received;
|
||||
static char pattern = 'A';
|
||||
static volatile sig_atomic_t running = 1;
|
||||
struct pixels {
|
||||
struct wl_buffer *buffer;
|
||||
void *map;
|
||||
size_t size;
|
||||
struct pixels *next;
|
||||
};
|
||||
static struct pixels *buffers;
|
||||
static long long stamp(void) {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return (long long)t.tv_sec * 1000000000LL + t.tv_nsec;
|
||||
}
|
||||
static void free_pixels(struct pixels *p) {
|
||||
struct pixels **it = &buffers;
|
||||
while (*it && *it != p)
|
||||
it = &(*it)->next;
|
||||
if (*it)
|
||||
*it = p->next;
|
||||
wl_buffer_destroy(p->buffer);
|
||||
munmap(p->map, p->size);
|
||||
free(p);
|
||||
--live_buffers;
|
||||
}
|
||||
static void release(void *data, struct wl_buffer *b) {
|
||||
fprintf(stderr, "RELEASE ns=%lld buffer=%u\n", stamp(),
|
||||
wl_proxy_get_id((struct wl_proxy *)b));
|
||||
++releases;
|
||||
free_pixels(data);
|
||||
}
|
||||
static const struct wl_buffer_listener buffer_listener = {.release = release};
|
||||
static void draw(void) {
|
||||
/* CONTRACT: exactly one runner command per reserved A/B image.
|
||||
* INVARIANT: configures cannot draw, and the sequence is A/B/A only. */
|
||||
if (!strcmp(mode, "background") &&
|
||||
(width != 800 || height != 600 || commits >= 3 ||
|
||||
pattern != (commits == 1 ? 'B' : 'A')))
|
||||
exit(2);
|
||||
if (width <= 0 || height <= 0 || width > 4096 || height > 4096 ||
|
||||
live_buffers >= 8)
|
||||
exit(2);
|
||||
size_t size = (size_t)width * (size_t)height * 4;
|
||||
/* CONTRACT: each mapping stays immutable until native wl_buffer.release.
|
||||
* Bounds keep pool/stride integers valid, with at most eight outstanding. */
|
||||
char name[512];
|
||||
const char *runtime = getenv("XDG_RUNTIME_DIR");
|
||||
if (!runtime || snprintf(name, sizeof(name), "%s/blur-shm-XXXXXX", runtime) >=
|
||||
(int)sizeof(name))
|
||||
exit(2);
|
||||
int fd = mkstemp(name);
|
||||
if (fd < 0)
|
||||
exit(2);
|
||||
unlink(name);
|
||||
if (ftruncate(fd, (off_t)size) < 0)
|
||||
exit(2);
|
||||
struct pixels *p = calloc(1, sizeof(*p));
|
||||
if (!p)
|
||||
exit(2);
|
||||
p->map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
p->size = size;
|
||||
if (p->map == MAP_FAILED)
|
||||
exit(2);
|
||||
uint32_t *pixels = p->map;
|
||||
for (int y = 0; y < height; ++y)
|
||||
for (int x = 0; x < width; ++x) {
|
||||
uint32_t color = 0x00303038;
|
||||
if (!strcmp(mode, "background"))
|
||||
color = pattern == 'A' ? (x / 8 % 2 ? 0x000f192d : 0x00f5f5f5)
|
||||
: (x / 8 % 2 ? 0x00b02040 : 0x0020c0e0);
|
||||
else if (!strcmp(mode, "glass"))
|
||||
color = 0x88442010;
|
||||
else if (!strcmp(mode, "filler"))
|
||||
color = 0x00000000;
|
||||
pixels[(size_t)y * (size_t)width + (size_t)x] = color;
|
||||
}
|
||||
/* WHY: retained bytes let the shared validator verify A/B/A source identity.
|
||||
* CONTRACT: dumps are outside Git in the owned run, not generated fixtures. */
|
||||
const char *dumpdir = getenv("MOSAIC_FX_SHM_DIR");
|
||||
char dump[1024];
|
||||
if (!dumpdir || snprintf(dump, sizeof(dump), "%s/%s-%u.shm", dumpdir,
|
||||
mode, commits + 1) >= (int)sizeof(dump)) exit(2);
|
||||
FILE *raw = fopen(dump, "wb");
|
||||
if (!raw || fwrite(p->map, 1, size, raw) != size || fclose(raw)) exit(2);
|
||||
fprintf(stderr, "SHM_SOURCE ns=%lld mode=%s index=%u path=%s bytes=%zu "
|
||||
"stride=%d format=%s alpha=%u colors=%s premultiplied=1\n",
|
||||
stamp(), mode, commits + 1, dump, size, width * 4,
|
||||
(!strcmp(mode, "glass") || !strcmp(mode, "filler")) ? "ARGB8888" : "XRGB8888",
|
||||
!strcmp(mode, "glass") ? 136 : !strcmp(mode, "filler") ? 0 : 255,
|
||||
!strcmp(mode, "background") ? (pattern == 'A' ? "00f5f5f5,000f192d" : "0020c0e0,00b02040") :
|
||||
!strcmp(mode, "glass") ? "88442010" : !strcmp(mode, "filler") ? "00000000" : "00303038");
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int)size);
|
||||
p->buffer = wl_shm_pool_create_buffer(
|
||||
pool, 0, width, height, width * 4,
|
||||
(!strcmp(mode, "glass") || !strcmp(mode, "filler"))
|
||||
? WL_SHM_FORMAT_ARGB8888
|
||||
: WL_SHM_FORMAT_XRGB8888);
|
||||
p->next = buffers;
|
||||
buffers = p;
|
||||
++live_buffers;
|
||||
wl_buffer_add_listener(p->buffer, &buffer_listener, p);
|
||||
wl_surface_attach(surface, p->buffer, 0, 0);
|
||||
wl_surface_damage_buffer(surface, 0, 0, width, height);
|
||||
wl_surface_commit(surface);
|
||||
fprintf(stderr,
|
||||
"CLIENT_COMMIT ns=%lld mode=%s surface=%u buffer=%u index=%u "
|
||||
"pattern=%c size=%dx%d damage=0,0,%d,%d\n",
|
||||
stamp(), mode, wl_proxy_get_id((struct wl_proxy *)surface),
|
||||
wl_proxy_get_id((struct wl_proxy *)p->buffer), ++commits, pattern,
|
||||
width, height, width, height);
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(fd);
|
||||
}
|
||||
static void ping(void *d, struct xdg_wm_base *b, uint32_t s) {
|
||||
xdg_wm_base_pong(b, s);
|
||||
}
|
||||
static const struct xdg_wm_base_listener wm_listener = {.ping = ping};
|
||||
static void top_configure(void *d, struct xdg_toplevel *t, int32_t w, int32_t h,
|
||||
struct wl_array *a) {
|
||||
if (w > 0)
|
||||
width = w;
|
||||
if (h > 0)
|
||||
height = h;
|
||||
}
|
||||
static void top_close(void *d, struct xdg_toplevel *t) { running = 0; }
|
||||
static const struct xdg_toplevel_listener top_listener = {
|
||||
.configure = top_configure, .close = top_close};
|
||||
static void configure(void *d, struct xdg_surface *s, uint32_t serial) {
|
||||
xdg_surface_ack_configure(s, serial);
|
||||
draw();
|
||||
}
|
||||
static const struct xdg_surface_listener xdg_listener = {.configure =
|
||||
configure};
|
||||
/* CONTRACT: configures ACK geometry, never submit an unreserved image.
|
||||
* WHY: duplicate layer configures must not spend autonomous mutations.
|
||||
* INVARIANT: the runner reserves then sends every A/B draw command. */
|
||||
static void layer_configure(void *d, struct zwlr_layer_surface_v1 *s,
|
||||
uint32_t serial, uint32_t w, uint32_t h) {
|
||||
if (w == 0 || h == 0 || w > 4096 || h > 4096)
|
||||
exit(2);
|
||||
if (commits && ((int)w != width || (int)h != height))
|
||||
exit(2);
|
||||
width = (int)w;
|
||||
height = (int)h;
|
||||
zwlr_layer_surface_v1_ack_configure(s, serial);
|
||||
fprintf(stderr, "BACKGROUND_CONFIGURED ns=%lld serial=%u size=%dx%d\n",
|
||||
stamp(), serial, width, height);
|
||||
}
|
||||
static void layer_close(void *d, struct zwlr_layer_surface_v1 *s) {
|
||||
running = 0;
|
||||
}
|
||||
static const struct zwlr_layer_surface_v1_listener layer_listener = {
|
||||
.configure = layer_configure, .closed = layer_close};
|
||||
static void output_name(void *d, struct wl_output *o, const char *name) {
|
||||
if (!strcmp(name, "HEADLESS-1"))
|
||||
h1 = o;
|
||||
}
|
||||
static void output_geometry(void *d, struct wl_output *o, int32_t x, int32_t y,
|
||||
int32_t w, int32_t h, int32_t sp, const char *m,
|
||||
const char *n, int32_t tr) {}
|
||||
static void output_mode(void *d, struct wl_output *o, uint32_t flags, int32_t w,
|
||||
int32_t h, int32_t refresh) {}
|
||||
static void output_done(void *d, struct wl_output *o) {}
|
||||
static void output_scale(void *d, struct wl_output *o, int32_t scale) {}
|
||||
static void output_description(void *d, struct wl_output *o, const char *desc) {
|
||||
}
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.geometry = output_geometry,
|
||||
.mode = output_mode,
|
||||
.done = output_done,
|
||||
.scale = output_scale,
|
||||
.name = output_name,
|
||||
.description = output_description};
|
||||
static void global(void *d, struct wl_registry *r, uint32_t id,
|
||||
const char *name, uint32_t v) {
|
||||
if (!strcmp(name, "wl_compositor"))
|
||||
compositor =
|
||||
wl_registry_bind(r, id, &wl_compositor_interface, v < 4 ? v : 4);
|
||||
else if (!strcmp(name, "wl_shm"))
|
||||
shm = wl_registry_bind(r, id, &wl_shm_interface, 1);
|
||||
else if (!strcmp(name, "xdg_wm_base"))
|
||||
wm = wl_registry_bind(r, id, &xdg_wm_base_interface, v < 3 ? v : 3);
|
||||
else if (!strcmp(name, "zwlr_layer_shell_v1"))
|
||||
shell =
|
||||
wl_registry_bind(r, id, &zwlr_layer_shell_v1_interface, v < 2 ? v : 2);
|
||||
else if (!strcmp(name, "wl_output") && v >= 4) {
|
||||
struct wl_output *o = wl_registry_bind(r, id, &wl_output_interface, 4);
|
||||
wl_output_add_listener(o, &output_listener, NULL);
|
||||
}
|
||||
}
|
||||
static void removed(void *d, struct wl_registry *r, uint32_t id) {}
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = global, .global_remove = removed};
|
||||
static void stop(int s) { running = 0; }
|
||||
/* WHY: only the runner's explicit close command proves orderly client shutdown.
|
||||
* CONTRACT: protocol close callbacks and process signals stop the loop without
|
||||
* setting close_received; arbitrary commands are ignored. */
|
||||
static void handle_command(const char *cmd) {
|
||||
if (!strcmp(mode, "background") && (cmd[0] == 'A' || cmd[0] == 'B') &&
|
||||
cmd[1] == '\n') {
|
||||
pattern = cmd[0];
|
||||
draw();
|
||||
fprintf(stderr, "COMMAND %c DONE ns=%lld\n", pattern, stamp());
|
||||
} else if (!strcmp(cmd, "close\n")) {
|
||||
close_received = true;
|
||||
fprintf(stderr, "CLOSE_RECEIVED ns=%lld mode=%s\n", stamp(), mode);
|
||||
running = 0;
|
||||
}
|
||||
}
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return 2;
|
||||
mode = argv[1];
|
||||
if (strcmp(mode, "background") && strcmp(mode, "glass") &&
|
||||
strcmp(mode, "filler") && strcmp(mode, "reference"))
|
||||
return 2;
|
||||
signal(SIGTERM, stop);
|
||||
display = wl_display_connect(NULL);
|
||||
if (!display)
|
||||
return 1;
|
||||
struct wl_registry *r = wl_display_get_registry(display);
|
||||
wl_registry_add_listener(r, ®istry_listener, NULL);
|
||||
if (wl_display_roundtrip(display) < 0 || wl_display_roundtrip(display) < 0)
|
||||
return 1;
|
||||
if (!compositor || !shm || !wm)
|
||||
return 2;
|
||||
xdg_wm_base_add_listener(wm, &wm_listener, NULL);
|
||||
surface = wl_compositor_create_surface(compositor);
|
||||
if (!strcmp(mode, "background")) {
|
||||
if (!shell || !h1)
|
||||
return 2;
|
||||
layer = zwlr_layer_shell_v1_get_layer_surface(
|
||||
shell, surface, h1, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
|
||||
"mosaic-dynamic-background");
|
||||
zwlr_layer_surface_v1_add_listener(layer, &layer_listener, NULL);
|
||||
zwlr_layer_surface_v1_set_size(layer, 0, 0);
|
||||
zwlr_layer_surface_v1_set_anchor(layer,
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(layer, -1);
|
||||
zwlr_layer_surface_v1_set_keyboard_interactivity(layer, 0);
|
||||
} else {
|
||||
xdg = xdg_wm_base_get_xdg_surface(wm, surface);
|
||||
xdg_surface_add_listener(xdg, &xdg_listener, NULL);
|
||||
top = xdg_surface_get_toplevel(xdg);
|
||||
xdg_toplevel_add_listener(top, &top_listener, NULL);
|
||||
const char *app = !strcmp(mode, "reference") ? "org.mosaic.StaticReference"
|
||||
: !strcmp(mode, "glass") ? "org.mosaic.BlurGlass"
|
||||
: "org.mosaic.BlurFiller";
|
||||
xdg_toplevel_set_app_id(top, app);
|
||||
xdg_toplevel_set_title(top, app);
|
||||
}
|
||||
wl_surface_commit(surface);
|
||||
while (running) {
|
||||
if (wl_display_dispatch_pending(display) < 0)
|
||||
break;
|
||||
if (wl_display_flush(display) < 0 && errno != EAGAIN)
|
||||
break;
|
||||
struct pollfd fds[2] = {
|
||||
{.fd = wl_display_get_fd(display), .events = POLLIN},
|
||||
{.fd = STDIN_FILENO, .events = POLLIN}};
|
||||
int n = poll(fds, 2, 100);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (fds[0].revents & (POLLIN | POLLERR | POLLHUP))
|
||||
if (wl_display_dispatch(display) < 0)
|
||||
break;
|
||||
if (fds[1].revents & POLLIN) {
|
||||
char cmd[64];
|
||||
if (!fgets(cmd, sizeof(cmd), stdin))
|
||||
break;
|
||||
handle_command(cmd);
|
||||
}
|
||||
}
|
||||
int error = wl_display_get_error(display);
|
||||
|
||||
if (layer)
|
||||
zwlr_layer_surface_v1_destroy(layer);
|
||||
if (top)
|
||||
xdg_toplevel_destroy(top);
|
||||
if (xdg)
|
||||
xdg_surface_destroy(xdg);
|
||||
wl_surface_destroy(surface);
|
||||
if (!error && wl_display_roundtrip(display) < 0) error = wl_display_get_error(display);
|
||||
fprintf(stderr, "OBJECTS_DESTROYED ns=%lld mode=%s live_buffers=%u releases=%u\n",
|
||||
stamp(), mode, live_buffers, releases);
|
||||
wl_display_flush(display);
|
||||
while (buffers)
|
||||
free_pixels(buffers);
|
||||
wl_registry_destroy(r);
|
||||
wl_display_disconnect(display);
|
||||
fprintf(stderr, "EXIT ns=%lld mode=%s error=%d commits=%u normalclose=%d releases=%u\n",
|
||||
stamp(), mode, error, commits, close_received, releases);
|
||||
return error || !close_received ? 1 : 0;
|
||||
}
|
||||
135
tooling/probes/step20c-targeted/fx.py
Normal file
135
tooling/probes/step20c-targeted/fx.py
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
"""EXPERIMENTAL bounded FX campaign: 16 PNGs, no compositor implementation.
|
||||
|
||||
WHY: earlier whole-H1 equality aborted before normal client close. Differences
|
||||
are evidence, never an exception preventing the lifetime measurement. Geometry
|
||||
and ROIs are recorded prospectively; no anomaly-dependent mask is allowed.
|
||||
"""
|
||||
import hashlib
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
import fx_validators as v
|
||||
|
||||
|
||||
def center_roi(s, name):
|
||||
from geometry import assigned_origin, actual_origin, intersection, global_png, need
|
||||
owner=s.find(name)
|
||||
floating=owner.get('floating','auto_off').endswith('on')
|
||||
origin=actual_origin(owner,s.log('compositor'))[0] if s.spec['mode']=='mosaic' and not floating else assigned_origin(owner)
|
||||
win=owner['window_rect']; rect=intersection([*origin,win['width'],win['height']],s.outputs[0]['logical'])
|
||||
need(rect[2]>=80 and rect[3]>=80,'visible fixed FX center')
|
||||
p=global_png([rect[0]+rect[2]//2,rect[1]+rect[3]//2],s.outputs[0],s.frames['HEADLESS-1'])
|
||||
return [p[0]-32,p[1]-32,p[0]+32,p[1]+32]
|
||||
|
||||
|
||||
def preset(s, name):
|
||||
# CONTRACT: edges/outside are fixed before the first relevant image; center
|
||||
# is chosen from fresh applied owner geometry, never from a pixel anomaly.
|
||||
rois=dict(center=center_roi(s,name),left=[0,0,32,600],right=[768,0,800,600],
|
||||
top=[0,0,800,32],bottom=[0,568,800,600],outside=[0,100,32,500],witness=[32,32,96,96])
|
||||
return rois
|
||||
|
||||
|
||||
def spawn_fx(s,name,mode):
|
||||
old=s.env.get('MOSAIC_FX_SHM_DIR');s.env['MOSAIC_FX_SHM_DIR']=str(s.run)
|
||||
try:
|
||||
p=s.spawn(name,[s.lab/'clients/fx-client',mode],True)
|
||||
finally:
|
||||
if old is None:s.env.pop('MOSAIC_FX_SHM_DIR',None)
|
||||
else:s.env['MOSAIC_FX_SHM_DIR']=old
|
||||
if mode!='background':s.wait(lambda:s.find(name));time.sleep(.25)
|
||||
return p
|
||||
|
||||
|
||||
def source_hash(s,mode):
|
||||
rows=v.sources(s.run,s.log(mode))['rows']
|
||||
v.require(rows,'SHM source recorded')
|
||||
return rows[-1]['sha256']
|
||||
|
||||
|
||||
def effects_campaign(s):
|
||||
from cases import init_reference, stable_reference
|
||||
from geometry import need
|
||||
need(s.spec['campaign']=='FX','explicit FX campaign')
|
||||
need(s.outputs[0]['logical']==[-800,0,800,600] and s.outputs[1]['logical']==[0,0,800,600]
|
||||
and all(o['scale']==1 and o['transform']=='normal' for o in s.outputs),'fixed FX geometry')
|
||||
s.cmd('output HEADLESS-1 bg #1e1e2e solid_color')
|
||||
init_reference(s,0);baseline=stable_reference(s) # 2 PNG
|
||||
bg=spawn_fx(s,'background','background')
|
||||
s.wait(lambda:'BACKGROUND_CONFIGURED' in s.log('background'))
|
||||
s.client_cmd('background','A','COMMAND A DONE');time.sleep(.2)
|
||||
witness_box=[32,32,96,96]
|
||||
s.save('fx-witness-roi',dict(roi=witness_box,established_ns=time.monotonic_ns()))
|
||||
witness=s.capture('background-witness-H1','HEADLESS-1') # 1 PNG
|
||||
witnessed=v.adjacent(witness,witness_box)>20
|
||||
s.save('fx-background-witness',dict(roi=witness_box,high_frequency_visible=witnessed,
|
||||
source=v.sources(s.run,s.log('background')),zorder='background layer below transparent filler and glass'))
|
||||
spawn_fx(s,'filler0','filler');s.cmd(f'[con_id={s.find("filler0")["id"]}] border none')
|
||||
spawn_fx(s,'glass','glass');gid=s.find('glass')['id'];s.cmd(f'[con_id={gid}] border none')
|
||||
s.cmd(f'[con_id={gid}] focus');s.calibrate('glass')
|
||||
for cmd in ('gaps inner 24','blur_xray disable','blur_radius 5','blur_passes 3',
|
||||
'blur_noise 0','blur_brightness 1','blur_contrast 1','blur_saturation 1',
|
||||
'shadow_offset 20 0','shadow_blur_radius 16','shadow_color #000000A0'):
|
||||
s.cmd(cmd)
|
||||
s.save('fx-shadow-rois',preset(s,'glass'));s.owner('glass')
|
||||
off=s.capture('FX-off-H1','HEADLESS-1')
|
||||
s.cmd(f'[con_id={gid}] shadows enable',True);time.sleep(.25)
|
||||
shadow=s.capture('shadow-on-H1','HEADLESS-1');shadow_h2=s.capture('shadow-on-H2','HEADLESS-2') # 3 PNG
|
||||
shadow_result=dict(status='EXERCISED' if v.diff(off,shadow)['pixels'] else 'SHADOW_NOT_EXERCISED',
|
||||
actual_RGB=v.diff(off,shadow),spill=v.diff(baseline,shadow_h2),
|
||||
meaning='pristine crossing spill control versus Mosaic sampled adjacent-output absence',
|
||||
enabled_command=True,complete_shadow_geometry='NOT PROVEN')
|
||||
s.cmd(f'[con_id={gid}] shadows disable',True)
|
||||
s.cmd(f'[con_id={gid}] floating enable',True)
|
||||
s.cmd(f'[con_id={gid}] resize set width 300 px height 200 px')
|
||||
s.cmd(f'[con_id={gid}] move absolute position -650 200');time.sleep(.25)
|
||||
classic_rois=preset(s,'glass');s.save('fx-classic-rois',classic_rois)
|
||||
floating=s.find('glass');s.save('fx-classic-state',floating)
|
||||
need(floating['rect']['x']>=-800 and floating['rect']['x']+floating['rect']['width']<=0,'classic wholly H1')
|
||||
before=source_hash(s,'glass');classic_off=s.capture('classic-off-H1','HEADLESS-1')
|
||||
trace_start=len(s.log('compositor'));s.cmd(f'[con_id={gid}] blur enable',True);time.sleep(.25)
|
||||
classic_on=s.capture('classic-blur-H1','HEADLESS-1') # 2 PNG
|
||||
native=[l for l in s.log('compositor')[trace_start:].splitlines() if 'OPT_BLUR_USE ' in l and 'optimized=0' in l]
|
||||
path=dict(selection='source floating overlap -> classic, blur_xray disabled',native=native,
|
||||
nonempty_region=bool(v.diff(classic_off,classic_on,classic_rois['center'])['pixels']),
|
||||
region_evidence='actual changed fixed interior RGB; native filter extents NOT OBSERVABLE')
|
||||
classic_result=v.classic(classic_off,classic_on,classic_rois['center'],before==source_hash(s,'glass'),path,witnessed)
|
||||
s.save('fx-classic',classic_result)
|
||||
s.cmd(f'[con_id={gid}] floating disable',True);time.sleep(.25);s.calibrate('glass')
|
||||
s.cmd(f'[con_id={gid}] blur disable',True);s.cmd(f'[con_id={gid}] blur enable',True);time.sleep(.25)
|
||||
opt_rois=preset(s,'glass');s.save('fx-rois',dict(optimized=opt_rois,classic=classic_rois,
|
||||
established_ns=time.monotonic_ns(),mask=None))
|
||||
states=[];images=[]
|
||||
for tag,command in (('optimized-A',None),('optimized-B','B'),('optimized-A-return','A')):
|
||||
if command:s.client_cmd('background',command,'COMMAND '+command+' DONE');time.sleep(.25)
|
||||
states.append(s.owner('glass'));s.save(tag+'-state',states[-1])
|
||||
images.append(s.pair_capture(tag)) # 6 PNG
|
||||
restoration=v.restoration(images[0][0],images[1][0],images[2][0],opt_rois)
|
||||
# Whole-H1 failures deliberately do not abort normal close.
|
||||
source=v.sources(s.run,s.log('background'))
|
||||
opt=dict(restoration=restoration,source=source,native=v.cache(s.log('compositor')),
|
||||
source_selection='settled tiled owner -> optimized; animation path must be inspected in retained trace',
|
||||
state_ids=[st['owner']['id'] for st in states],wholeH2=[v.diff(baseline,p[1]) for p in images])
|
||||
s.save('fx-optimized',opt)
|
||||
close=[]
|
||||
for name in ('glass','background','filler0'):
|
||||
s.client_cmd(name,'close')
|
||||
code=s.proc[name].wait(timeout=3)
|
||||
if name!='background':s.wait(lambda:s.find(name) is None)
|
||||
alive=s.comp.poll() is None
|
||||
s.record('fx-normal-close',name=name,exit=code,compositor_alive=alive)
|
||||
close.append((name,code,alive))
|
||||
time.sleep(.2);final=s.pair_capture('final') # 2 PNG, total 16
|
||||
h1_gone=all(c==(30,30,46) for c in final[0].getdata())
|
||||
h2=v.diff(baseline,final[1])
|
||||
closes={name:v.normalclose(s.log(name),code,alive,h1_gone) for name,code,alive in close}
|
||||
result=dict(status='PARTIALLY_FEASIBLE' if all(x['status']=='PASS' for x in closes.values()) else 'INCONCLUSIVE',
|
||||
classic=classic_result,optimized=opt,wholeH1=restoration['wholeH1'],wholeH2_final=h2,
|
||||
damage=dict(status='NOT PROVEN',raw=[l for l in s.log('compositor').splitlines() if 'DAMAGE' in l],
|
||||
complete_frames='NOT PROVEN'),normalclose=closes,shadow=shadow_result,
|
||||
unknown_GPU_lifetime='NOT PROVEN',capture_count=16,
|
||||
production='NOT YET SUPPORTED; experimental fixture only')
|
||||
if not source['ABA_byte_exact'] or not h2['exact'] or not witnessed:result['status']='INCONCLUSIVE'
|
||||
s.save('effects-evidence',result)
|
||||
s.save('fx-postrun',v.validate_run(s.run))
|
||||
return result['status']
|
||||
172
tooling/probes/step20c-targeted/fx_validators.py
Normal file
172
tooling/probes/step20c-targeted/fx_validators.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
"""EXPERIMENTAL shared FX predicates; no compositor or graphics launcher.
|
||||
|
||||
The same functions validate synthetic negative tests, retained evidence and live
|
||||
captures. Whole images are authoritative: fixed ROIs explain, never mask, defects.
|
||||
Client SHM object IDs are connection-local and never output/cache identities.
|
||||
"""
|
||||
import hashlib
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageChops
|
||||
|
||||
|
||||
def require(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def rgb(image):
|
||||
return Image.open(image).convert('RGB') if isinstance(image, (str, Path)) else image.convert('RGB')
|
||||
|
||||
|
||||
def diff(a, b, roi=None, mask=None):
|
||||
require(mask is None, 'pixel masks are forbidden')
|
||||
a, b = rgb(a), rgb(b)
|
||||
require(a.size == b.size, 'different image dimensions')
|
||||
if roi is not None:
|
||||
require(len(roi) == 4 and all(type(v) is int for v in roi), 'ROI integers')
|
||||
x, y, r, t = roi
|
||||
require(0 <= x < r <= a.width and 0 <= y < t <= a.height, 'ROI outside image or empty')
|
||||
a, b = a.crop(roi), b.crop(roi)
|
||||
delta = ImageChops.difference(a, b)
|
||||
hist = [c.histogram() for c in delta.split()]
|
||||
data = delta.tobytes()
|
||||
return dict(pixels=sum(any(data[i:i+3]) for i in range(0, len(data), 3)),
|
||||
bbox=list(delta.getbbox()) if delta.getbbox() else None,
|
||||
perchannel=[dict(changed=sum(h[1:]), total_abs=sum(i*n for i,n in enumerate(h)),
|
||||
max_abs=max((i for i,n in enumerate(h) if n), default=0)) for h in hist],
|
||||
size=list(a.size), roi=roi, exact=a.tobytes() == b.tobytes())
|
||||
|
||||
|
||||
def adjacent(image, roi):
|
||||
image = rgb(image)
|
||||
diff(image, image, roi) # validates the prospective ROI without padding
|
||||
im = image.crop(roi)
|
||||
require(im.width > 1, 'adjacent metric ROI width')
|
||||
total = sum(sum(abs(a-b) for a,b in zip(im.getpixel((x,y)), im.getpixel((x+1,y))))
|
||||
for y in range(im.height) for x in range(im.width-1))
|
||||
return total/(im.height*(im.width-1)*3)
|
||||
|
||||
|
||||
def classic(off, on, roi, source_same, path, witness):
|
||||
change = diff(off, on, roi)
|
||||
before, after = adjacent(off, roi), adjacent(on, roi)
|
||||
exercised = bool(source_same and path.get('nonempty_region') and witness
|
||||
and change['pixels'] and after < before)
|
||||
return dict(status='EXERCISED' if exercised else 'CLASSIC_BLUR_NOT_EXERCISED',
|
||||
difference=change, adjacent_off=before, adjacent_on=after, source_same=source_same,
|
||||
path=path, background_witness=witness,
|
||||
meaning='same-source off/on distinguishes filtering from alpha compositing')
|
||||
|
||||
|
||||
def restoration(a, b, returned, rois):
|
||||
# CONTRACT: whole-H1 differences must survive even if center restoration passes.
|
||||
return dict(wholeH1=diff(a, returned), changed_AB=diff(a,b),
|
||||
rois={name:dict(AB=diff(a,b,box), AA=diff(a,returned,box)) for name,box in rois.items()},
|
||||
status='EXACT' if diff(a, returned)['exact'] else 'WHOLE_H1_DIFFERENT')
|
||||
|
||||
|
||||
def cache(trace):
|
||||
rows=[l for l in trace.splitlines() if any(k in l for k in
|
||||
('OPT_DIRTY_SET ', 'OPT_REGEN_ATTEMPT ', 'OPT_REGEN_RESULT ', 'OPT_DIRTY_CLEAR ', 'OPT_BLUR_USE '))]
|
||||
episodes=[]; dirty={}; attempts={}; regenerated={}; cleared={}
|
||||
for line in rows:
|
||||
f=dict(re.findall(r'(\w+)=([^\s]+)',line));node=f.get('node');output=f.get('output')
|
||||
if 'OPT_DIRTY_SET ' in line and f.get('enabled')=='1' and f.get('size')=='800x600':
|
||||
dirty[node]=line
|
||||
elif 'OPT_REGEN_ATTEMPT ' in line and node in dirty and f.get('dirty')=='1':
|
||||
attempts[node]=(output,line)
|
||||
elif 'OPT_REGEN_RESULT ' in line and node in attempts and f.get('result')=='1' and output==attempts[node][0]:
|
||||
regenerated[node]=(output,line)
|
||||
elif 'OPT_DIRTY_CLEAR ' in line and node in regenerated and f.get('dirty')=='0' and output==regenerated[node][0]:
|
||||
cleared[output]=dict(node=node,dirty=dirty[node],attempt=attempts[node][1],
|
||||
result=regenerated[node][1],clear=line)
|
||||
elif 'OPT_BLUR_USE ' in line and output in cleared and f.get('optimized')=='1' and f.get('chosen') not in (None,'(nil)','0x0'):
|
||||
ep={**cleared[output], 'use':line};episodes.append(ep)
|
||||
return dict(status='NATIVE_OBSERVED' if episodes else 'CACHE_NOT_EXERCISED' if rows else 'NOT OBSERVABLE',
|
||||
rows=rows, episodes=episodes,identity='node-correlated regeneration then output-correlated cache use; client IDs remain separate',
|
||||
causal_dirty_regeneration_ABA='NOT PROVEN by aggregate trace presence')
|
||||
|
||||
|
||||
def sources(run, log):
|
||||
rows=[]
|
||||
for line in log.splitlines():
|
||||
if not line.startswith('SHM_SOURCE '):
|
||||
continue
|
||||
fields=dict(re.findall(r'(\w+)=([^\s]+)',line))
|
||||
p=Path(fields['path'])
|
||||
require(p.resolve().parent == Path(run).resolve(), 'SHM outside owned run')
|
||||
raw=p.read_bytes()
|
||||
require(len(raw)==int(fields['bytes']), 'SHM byte count')
|
||||
stride=int(fields['stride'])
|
||||
require(stride>0 and stride%4==0 and len(raw)%stride==0, 'SHM stride/size')
|
||||
width,height=stride//4,len(raw)//stride
|
||||
endian='<' if sys.byteorder=='little' else '>'
|
||||
if fields['mode']=='background':
|
||||
require(width==800 and height==600 and fields['format']=='XRGB8888', 'background format/geometry')
|
||||
colors=[int(x,16) for x in fields['colors'].split(',')]
|
||||
require(len(colors)==2, 'background palette')
|
||||
row=b''.join(struct.pack(endian+'I',colors[x//8%2]) for x in range(width))
|
||||
require(raw==row*height, 'background high-frequency source bytes')
|
||||
elif fields['mode'] in ('glass','filler'):
|
||||
color=0x88442010 if fields['mode']=='glass' else 0
|
||||
require(fields['format']=='ARGB8888' and raw==struct.pack(endian+'I',color)*(width*height),
|
||||
'glass/filler premultiplied source bytes')
|
||||
fields.update(sha256=hashlib.sha256(raw).hexdigest(), actual_bytes=len(raw),
|
||||
width=width,height=height,byteorder=sys.byteorder)
|
||||
rows.append(fields)
|
||||
bg=[r for r in rows if r['mode']=='background']
|
||||
valid=(len(bg)==3 and bg[0]['sha256']==bg[2]['sha256'] and bg[0]['sha256']!=bg[1]['sha256'])
|
||||
return dict(rows=rows, ABA_byte_exact=valid, format_endianness='native uint32_t; little-endian expected and separately recorded')
|
||||
|
||||
|
||||
def normalclose(log, code, compositor_alive, gone):
|
||||
lines=log.splitlines(); close=[(i,l) for i,l in enumerate(lines) if l.startswith('CLOSE_RECEIVED ')]
|
||||
destroy=[(i,l) for i,l in enumerate(lines) if l.startswith('OBJECTS_DESTROYED ')]
|
||||
exits=[(i,l) for i,l in enumerate(lines) if l.startswith('EXIT ')]
|
||||
releases=[l for l in lines if l.startswith('RELEASE ')]
|
||||
commit_after=bool(close and any(l.startswith('CLIENT_COMMIT ') for l in lines[close[0][0]+1:]))
|
||||
ok=(code==0 and compositor_alive and gone and len(close)==len(destroy)==len(exits)==1
|
||||
and close[0][0]<destroy[0][0]<exits[0][0] and 'error=0 ' in exits[0][1]
|
||||
and 'normalclose=1 ' in exits[0][1] and bool(releases) and not commit_after)
|
||||
return dict(status='PASS' if ok else 'FAIL', code=code, compositor_alive=compositor_alive,
|
||||
pixels_gone=gone, command_received=[l for _,l in close], objects_destroyed=[l for _,l in destroy],
|
||||
exits=[l for _,l in exits], release_callbacks=releases, commit_after_close=commit_after,
|
||||
GPU_lifetime='NOT PROVEN; SHM releases and normal object teardown are separate observations')
|
||||
|
||||
|
||||
def validate_run(run):
|
||||
"""Post-run entry also usable on retained old runs; missing proof stays absent."""
|
||||
import json
|
||||
run=Path(run)
|
||||
names=('optimized-A','optimized-B','optimized-A-return')
|
||||
result={'schema':'experimental-fx-v1','historical':not (run/'fx-rois.json').exists()}
|
||||
rois=json.loads((run/'fx-rois.json').read_text())['optimized'] if (run/'fx-rois.json').exists() else {'center':[300,250,364,314]}
|
||||
if all((run/(name+'-H1.png')).exists() for name in names):
|
||||
result['optimized']=restoration(*(run/(name+'-H1.png') for name in names),rois)
|
||||
for output in ('H1','H2'):
|
||||
a,b=run/('classic-off-'+output+'.png'),run/('classic-blur-'+output+'.png')
|
||||
if a.exists() and b.exists():result['classic_'+output]=diff(a,b)
|
||||
ref=run/'H2-reference1.png'
|
||||
if ref.exists():result['wholeH2']={p.name:diff(ref,p) for p in sorted(run.glob('*-H2.png'))}
|
||||
trace=(run/'compositor.log').read_text(errors='replace')
|
||||
result['cache']=cache(trace)
|
||||
result['clients']={name:normalclose((run/(name+'.log')).read_text(errors='replace'),
|
||||
None,False,False) for name in ('glass','background') if (run/(name+'.log')).exists()}
|
||||
result['normalclose']='NOT PROVEN offline without explicit recorded live-compositor/pixel proof'
|
||||
if (run/'effects-evidence.json').exists() and (run/'events.jsonl').exists() and (run/'final-H1.png').exists():
|
||||
events=[json.loads(l) for l in (run/'events.jsonl').read_text().splitlines()]
|
||||
close={e['name']:e for e in events if e['kind']=='fx-normal-close'}
|
||||
final=rgb(run/'final-H1.png');gone=all(c==(30,30,46) for c in final.getdata())
|
||||
result['clients']={name:normalclose((run/(name+'.log')).read_text(errors='replace'),
|
||||
e['exit'],e['compositor_alive'],gone) for name,e in close.items()}
|
||||
result['normalclose']='PASS' if set(close)=={'glass','background','filler0'} and all(
|
||||
r['status']=='PASS' for r in result['clients'].values()) else 'FAIL'
|
||||
evidence=json.loads((run/'effects-evidence.json').read_text())
|
||||
result['classic']=classic(run/'classic-off-H1.png',run/'classic-blur-H1.png',
|
||||
json.loads((run/'fx-rois.json').read_text())['classic']['center'],
|
||||
evidence['classic']['source_same'],evidence['classic']['path'],evidence['classic']['background_witness'])
|
||||
result['sources']=sources(run,(run/'background.log').read_text(errors='replace'))
|
||||
return result
|
||||
109
tooling/probes/step20c-targeted/gate.py
Normal file
109
tooling/probes/step20c-targeted/gate.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
"""Fail-closed independent acceptance, persistent tokens, one atomic ledger."""
|
||||
import fcntl,hashlib,json,os,stat,sys,time
|
||||
from pathlib import Path
|
||||
from plans import *
|
||||
HERE=Path(__file__).resolve().parent
|
||||
SCOPE='STEP20C_TARGETED_FINAL_BYTES_V1'
|
||||
def sha(p):return hashlib.sha256(Path(p).read_bytes()).hexdigest()
|
||||
def read(p):return json.loads(Path(p).read_text())
|
||||
def need(ok,msg):
|
||||
if not ok:raise ValueError(msg)
|
||||
def durable(p,data,exclusive=False):
|
||||
p=Path(p);raw=(json.dumps(data,indent=2)+'\n').encode()
|
||||
if exclusive:
|
||||
fd=os.open(p,os.O_CREAT|os.O_EXCL|os.O_WRONLY|os.O_NOFOLLOW,0o600)
|
||||
with os.fdopen(fd,'wb') as f:f.write(raw);f.flush();os.fsync(f.fileno())
|
||||
else:
|
||||
tmp=p.with_name(p.name+'.new');fd=os.open(tmp,os.O_CREAT|os.O_EXCL|os.O_WRONLY|os.O_NOFOLLOW,0o600)
|
||||
with os.fdopen(fd,'wb') as f:f.write(raw);f.flush();os.fsync(f.fileno())
|
||||
os.replace(tmp,p)
|
||||
fd=os.open(p.parent,os.O_DIRECTORY);os.fsync(fd);os.close(fd)
|
||||
def clean_environment():
|
||||
# Strip every inherited display/IPC and private library selection.
|
||||
from importlib.util import spec_from_file_location,module_from_spec
|
||||
spec=spec_from_file_location('targeted_environment',BASE/'support.py');m=module_from_spec(spec);spec.loader.exec_module(m)
|
||||
return m.environment()
|
||||
def owned(lab):
|
||||
lab=Path(lab).resolve();need(lab==DEFAULT_LAB and lab.stat().st_uid==os.getuid() and stat.S_IMODE(lab.stat().st_mode)==0o700,'registered owned0700 lab');return lab
|
||||
def initialize(lab):
|
||||
lab=owned(lab);durable(lab/'budget.json',dict(scope=SCOPE,runs={},events=[],used=dict(run=0,capture=0),campaign_used=dict.fromkeys(CAPS,0),campaign_runs=dict.fromkeys(CAPS,0)),True)
|
||||
def validate(state):
|
||||
need(state.get('scope')==SCOPE,'ledger scope');events=state['events'];runs=state['runs']
|
||||
need(state['used']==dict(run=len(runs),capture=sum(e['kind']=='capture' for e in events)),'global reconciliation')
|
||||
need(len(runs)<=14 and state['used']['capture']<=174,'global cap')
|
||||
for campaign in CAPS:
|
||||
ids=[r for r,s in runs.items() if s['campaign']==campaign]
|
||||
need(state['campaign_runs'][campaign]==len(ids)<=RUN_CAPS[campaign],'campaign run reconciliation')
|
||||
captures=sum(e['kind']=='capture' and e['id'] in ids for e in events)
|
||||
need(state['campaign_used'][campaign]==captures<=CAPS[campaign],'campaign capture reconciliation')
|
||||
for rid,s in runs.items():
|
||||
need(rid in RUNS and s['campaign']==RUNS[rid]['campaign'] and s['planned']==RUNS[rid]['limits'],'run immutable plan')
|
||||
counts={k:sum(e['id']==rid and e['kind']==k for e in events) for k in s['planned']}
|
||||
need(s['reserved']==counts and all(type(v)is int and 0<=v<=s['planned'][k] for k,v in counts.items()),'local reconciliation')
|
||||
need(counts['capture']<=16,'per-run cap')
|
||||
need(all(e['sequence']==i and type(e['ns'])is int and e['ns']>0 and e['id'] in runs and e['kind'] in runs[e['id']]['planned'] for i,e in enumerate(events)),'event schema')
|
||||
return state
|
||||
def locked(lab,operation):
|
||||
with (lab/'budget.lock').open('a+') as f:
|
||||
fcntl.flock(f,fcntl.LOCK_EX);state=validate(read(lab/'budget.json'));result=operation(state);validate(state);durable(lab/'budget.json',state);return result
|
||||
def action_debit(lab,rid,*kinds):
|
||||
lab=owned(lab)
|
||||
def update(s):
|
||||
need(rid in s['runs'] and kinds,'consumed run token');r=s['runs'][rid]
|
||||
need(all(k in r['planned'] and r['reserved'][k]+kinds.count(k)<=r['planned'][k] for k in kinds),'local action cap')
|
||||
count=kinds.count('capture');need(s['used']['capture']+count<=174 and s['campaign_used'][r['campaign']]+count<=CAPS[r['campaign']],'global capture cap')
|
||||
for k in kinds:
|
||||
r['reserved'][k]+=1;s['events'].append(dict(id=rid,kind=k,ns=time.monotonic_ns(),sequence=len(s['events'])))
|
||||
if k=='capture':s['used']['capture']+=1;s['campaign_used'][r['campaign']]+=1
|
||||
locked(lab,update)
|
||||
def frozen_paths(lab):
|
||||
# Exhaustive source closure declared at preparation; recursive fixture bytes
|
||||
# also bind new FX files and any later helper additions.
|
||||
ident=read(lab/'identity.json')
|
||||
paths=[p for p in HERE.iterdir() if p.is_file() and (p.suffix in ('.py','.c') or p.name=='README.md')]
|
||||
paths += [Path(p) for p in ident['closure']]
|
||||
paths += [lab/'identity.json',lab/'offline.json',lab/'replay.json',lab/'fx-offline.json']
|
||||
paths += [Path(read(lab/name)['raw_output']) for name in ('offline.json','fx-offline.json')]
|
||||
paths += [p for p in (lab/'clients').iterdir() if p.is_file()]
|
||||
return sorted(set(paths))
|
||||
def source_bindings():
|
||||
return {str(p):sha(p) for p in sorted(HERE.iterdir()) if p.is_file() and (p.suffix in ('.py','.c') or p.name=='README.md')}
|
||||
def test_receipt(lab,name,minimum):
|
||||
r=read(lab/name);need(r.get('status')=='PASS' and type(r.get('executed'))is int and r['executed']>=minimum and r.get('exit')==0,'complete executed test receipt '+name)
|
||||
need(isinstance(r.get('command'),list) and len(r['command'])>=2 and r.get('source_bindings')==source_bindings(),'test command/exact sources '+name)
|
||||
need(Path(r['raw_output']).is_relative_to(lab) and sha(r['raw_output'])==r['raw_sha256'] and Path(r['raw_output']).stat().st_size>0,'raw test receipt '+name)
|
||||
need(not r.get('failures') and not r.get('errors'),'test failures '+name);return r
|
||||
def replay_receipt(lab):
|
||||
r=read(lab/'replay.json');need(r.get('status')=='PASS' and r.get('source_bindings')==source_bindings(),'replay exact sources')
|
||||
need(isinstance(r.get('evidence'),dict) and len(r['evidence'])>=7 and all(sha(p)==h for p,h in r['evidence'].items()),'replay raw source bindings')
|
||||
d=r['D2'];need(d.get('historical_verdict')=='INCONCLUSIVE unchanged; input/dismissal/final NOT EXERCISED' and len(d['association']['states'])>=1 and len(d['preowner']['epochs'])>=2 and d['association']['tree']!=d['preowner']['tree'],'actual D2 association replay')
|
||||
f=r['F'];actual=__import__('validators').native_pairs(Path(f['source']).read_text());need(f['sha256']==sha(f['source']) and f['pairs']==actual and len(actual['analyzed'])==actual['total_commits'] and actual['total_commits']>=57,'ALL actual F commits replay')
|
||||
e=r['E2'];need(e['status']=='SOURCE_ONLY; historical held NOT EXERCISED' and e['runtime_command']=='gaps inner current set 30' and e['argc']==4 and e['arrange_workspace'] is True,'E2 source defect replay')
|
||||
need(sha(e['source'])==e['sha256'] and 'argc == 4 && !config->reading' in Path(e['source']).read_text(),'E2 actual source binding');return r
|
||||
def receipts(lab):
|
||||
test_receipt(lab,'offline.json',14);test_receipt(lab,'fx-offline.json',5);replay_receipt(lab)
|
||||
def seal(lab):
|
||||
lab=owned(lab);receipts(lab)
|
||||
durable(lab/'freeze.json',dict(scope=SCOPE,status='READY_FOR_REVIEW',files={str(p):sha(p) for p in frozen_paths(lab)},plans=RUNS),True)
|
||||
def verify(lab,review=True):
|
||||
lab=owned(lab);receipts(lab);f=read(lab/'freeze.json');need(f['scope']==SCOPE and f['plans']==RUNS and f['files']=={str(p):sha(p) for p in frozen_paths(lab)},'frozen exact final bytes')
|
||||
if review:
|
||||
r=read(lab/'review.json');need(r.get('scope')==SCOPE and r.get('status')=='ACCEPTED' and r.get('independent') is True and r.get('read_only') is True and r.get('blockers')==[] and r.get('author')!='targeted_fixtures','independent acceptance required')
|
||||
need(r.get('freeze_sha256')==sha(lab/'freeze.json') and r.get('files')==f['files'] and sha(r['report_file'])==r['report_sha256'],'review exact-byte binding')
|
||||
return f
|
||||
def begin(lab,rid):
|
||||
lab=owned(lab);need(rid in RUNS and not sys.flags.optimize,'fixed run and assertions');verify(lab)
|
||||
ident=read(lab/'identity.json');v=RUNS[rid]['variant'];binary,digest=BINARIES[v];need(sha(binary)==digest and sha(WLROOTS)==WLROOTS_SHA and sha(SCENE)==ident['scene_sha256'],'exact binary/library')
|
||||
for proc in Path('/proc').iterdir():
|
||||
if proc.name.isdigit():
|
||||
try:exe=(proc/'exe').resolve(strict=True)
|
||||
except (FileNotFoundError,PermissionError,ProcessLookupError):continue
|
||||
need(exe!=binary.resolve(),'same exact binary already running')
|
||||
folder=lab/'runs'/rid;need(not (folder/'run').exists(),'run already exists')
|
||||
# No tool ever refunds or clears this durable consumed entry.
|
||||
def update(s):
|
||||
campaign=RUNS[rid]['campaign'];need(rid not in s['runs'] and s['used']['run']<14 and s['campaign_runs'][campaign]<RUN_CAPS[campaign],'no retry; run cap')
|
||||
planned=RUNS[rid]['limits'];need(s['used']['capture']+planned['capture']<=174 and s['campaign_used'][campaign]+planned['capture']<=CAPS[campaign],'available planned capture cap')
|
||||
s['runs'][rid]=dict(campaign=campaign,planned=planned,reserved=dict.fromkeys(planned,0),consumed_ns=time.monotonic_ns(),freeze_sha256=sha(lab/'freeze.json'));s['used']['run']+=1;s['campaign_runs'][campaign]+=1
|
||||
locked(lab,update)
|
||||
return dict(binary=str(binary),binary_sha256=digest,wlroots=str(WLROOTS),wlroots_sha256=WLROOTS_SHA,pristine_scene=str(SCENE),pristine_scene_sha256=ident['scene_sha256'])
|
||||
66
tooling/probes/step20c-targeted/geometry.py
Normal file
66
tooling/probes/step20c-targeted/geometry.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"""Explicit logical global, IPC assignment, physical mode and PNG-frame adapters."""
|
||||
from dataclasses import dataclass
|
||||
import re
|
||||
from PIL import Image
|
||||
|
||||
class Ambiguous(ValueError):pass
|
||||
def need(ok,msg):
|
||||
if not ok:raise Ambiguous(msg)
|
||||
def box_end(r):return [r[0]+r[2],r[1]+r[3]]
|
||||
def contains(r,p):return r[0]<=p[0]<r[0]+r[2] and r[1]<=p[1]<r[1]+r[3]
|
||||
def crossing(r,axis,boundary):return r[axis]<boundary<r[axis]+r[axis+2]
|
||||
def intersection(a,b):
|
||||
x=max(a[0],b[0]);y=max(a[1],b[1]);return [x,y,max(0,min(a[0]+a[2],b[0]+b[2])-x),max(0,min(a[1]+a[3],b[1]+b[3])-y)]
|
||||
def assigned_origin(owner):
|
||||
# IPC rect already excludes top decoration (ipc-json.c899–906).
|
||||
return [owner['rect']['x']+owner['window_rect']['x'],owner['rect']['y']+owner['window_rect']['y']]
|
||||
def exterior_ipc(owner):
|
||||
r=owner['rect'];d=owner['deco_rect']['height'];return [r['x'],r['y']-d,r['width'],r['height']+d]
|
||||
def actual_origin(owner,trace):
|
||||
rows=[s for s in trace.splitlines() if 'PI_OWNER output=' in s and f' id={owner["id"]} ' in s]
|
||||
need(rows,'applied owner trace absent');m=re.search(r'scene_valid=1 scene=(-?\d+),(-?\d+) applied_size=(\d+),(\d+)',rows[-1]);need(m is not None,'applied owner malformed')
|
||||
r=list(map(int,m.groups()));w=owner['window_rect'];return [r[0]+w['x'],r[1]+owner['deco_rect']['height']+w['y']],r,rows[-1]
|
||||
MARKERS={'TL':(255,32,32),'TR':(32,255,32),'BL':(32,32,255),'BR':(255,255,32),'C':(192,32,255)}
|
||||
def marker_frame(image,scale,rotated):
|
||||
positions={k:[] for k in MARKERS};lookup={v:k for k,v in MARKERS.items()}
|
||||
for y in range(image.height):
|
||||
for x in range(image.width):
|
||||
k=lookup.get(image.getpixel((x,y)))
|
||||
if k:positions[k].append((x,y))
|
||||
need(all(len(v)>=100 for v in positions.values()),'marker color missing')
|
||||
c={k:[sum(p[i] for p in v)/len(v) for i in (0,1)] for k,v in positions.items()}
|
||||
logical=image.size==(round(800*scale),round(600*scale)) and c['TL'][0]<c['TR'][0] and c['TL'][1]<c['BL'][1]
|
||||
physical=rotated and image.size==(round(600*scale),round(800*scale)) and c['TL'][0]>c['BL'][0] and c['TL'][1]<c['TR'][1]
|
||||
need(logical or physical,'PNG orientation unestablished')
|
||||
return dict(frame='logical' if logical else 'physical90',centers=c,counts={k:len(v) for k,v in positions.items()},size=list(image.size))
|
||||
def png_global(px,output,frame):
|
||||
scale=output['scale'];x,y=px;ox,oy,w,h=output['logical']
|
||||
if frame=='physical90':x,y=y,round(h*scale)-1-x
|
||||
need(frame in ('logical','physical90'),'unknown PNG frame')
|
||||
# Sample integer logical centers only; resample at the chosen center later.
|
||||
return [ox+int(x/scale),oy+int(y/scale)]
|
||||
def global_png(p,output,frame):
|
||||
x=(p[0]-output['logical'][0])*output['scale'];y=(p[1]-output['logical'][1])*output['scale']
|
||||
if frame=='physical90':x,y=output['logical'][3]*output['scale']-1-y,x
|
||||
return [round(x),round(y)]
|
||||
def solid_point(image,color,output,frame,rectangle=None,margin=3):
|
||||
for y in range(margin,image.height-margin,3):
|
||||
for x in range(margin,image.width-margin,3):
|
||||
if image.getpixel((x,y))!=color:continue
|
||||
p=png_global((x,y),output,frame)
|
||||
if rectangle is not None and not contains(rectangle,p):continue
|
||||
pp=global_png(p,output,frame)
|
||||
if not (margin<=pp[0]<image.width-margin and margin<=pp[1]<image.height-margin):continue
|
||||
if all(image.getpixel((xx,yy))==color for yy in range(pp[1]-margin,pp[1]+margin+1) for xx in range(pp[0]-margin,pp[0]+margin+1)):
|
||||
return p
|
||||
raise Ambiguous('no measured solid logical interior')
|
||||
def count(image,color):return sum(v==color for v in image.get_flattened_data())
|
||||
def exact(a,b):need(a.size==b.size and a.tobytes()==b.tobytes(),'whole RGB differs');return dict(equal=True,pixels=a.width*a.height)
|
||||
def expected_outputs(outputs,spec):
|
||||
active=[o for o in outputs if o['active']];need(len(active)==2,'active output count')
|
||||
for want in spec:
|
||||
rows=[o for o in active if o['name']==want['name']];need(len(rows)==1,'output identity')
|
||||
o=rows[0];need([o['rect'][k] for k in ('x','y','width','height')]==want['logical'],'logical output geometry')
|
||||
need(o['scale']==want['scale'] and o['transform']==want['transform'],'scale/IPC transform string')
|
||||
need([o['current_mode'][k] for k in ('width','height')]==want['mode'],'physical mode')
|
||||
return active
|
||||
31
tooling/probes/step20c-targeted/plans.py
Normal file
31
tooling/probes/step20c-targeted/plans.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""Independent EXPERIMENTAL plans; old 18-run ledger remains read only."""
|
||||
from pathlib import Path
|
||||
HIST=Path('/home/fy59/swayfx-mosaic-overnight-mcolx0gq')
|
||||
DEFAULT_LAB=Path('/home/fy59/swayfx-mosaic-targeted-7gge6h8b')
|
||||
ROOT=Path(__file__).resolve().parents[3]
|
||||
BASE=ROOT/'tooling/probes/step20c-static-e2-completion'
|
||||
MATRIX=ROOT/'tooling/probes/step20c-overnight/matrix'
|
||||
PRISTINE=Path('/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n/pristine-build/sway/sway')
|
||||
SCENE=Path('/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n/scene0-build/libscenefx-0.5.so').resolve()
|
||||
BINARIES={
|
||||
'A':(HIST/'stage-static/usr/bin/swayfx-mosaic','979dcd95ab43fa1e465d6e9d262485b73d186cedacd0f957059dd24f482ce6f4'),
|
||||
'G':(HIST/'release-shape/stage-static/usr/bin/swayfx-mosaic','8063478b2d5948da3eb8b1a329978882dc1d045cf36932cc2145a78af20ba76a'),
|
||||
'pristine':(PRISTINE,'8ac865481bc0487344210cd0e16d8e6c7655b29db887cd58ddc11b0ca22fe494')}
|
||||
WLROOTS=Path('/usr/lib/libwlroots-0.20.so').resolve()
|
||||
WLROOTS_SHA='7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837'
|
||||
CAPS={'scale':24,'saved':30,'FX':48,'input':36,'G':36}
|
||||
RUN_CAPS={'scale':2,'saved':3,'FX':3,'input':3,'G':3}
|
||||
NORMAL=[dict(name='HEADLESS-1',logical=[-800,0,800,600],mode=[800,600],scale=1,transform='normal'),dict(name='HEADLESS-2',logical=[0,0,800,600],mode=[800,600],scale=1,transform='normal')]
|
||||
SCALE=[{**NORMAL[0],'mode':[1000,750],'scale':1.25},NORMAL[1]]
|
||||
ROTATE=[{**NORMAL[0],'mode':[750,1000],'scale':1.25,'transform':'90'},NORMAL[1]]
|
||||
RUNS={}
|
||||
def plan(campaign,variant,case,outputs=NORMAL,marker=False,capture=12):
|
||||
rid=f'{campaign}-{variant}' if case==campaign else f'{campaign}-{case}-{variant}'
|
||||
RUNS[rid]=dict(id=rid,campaign=campaign,case=case,variant=variant,mode='pristine' if variant=='pristine' else 'mosaic',outputs=outputs,marker=marker,client='nested-client',placement='static_cross',axis=0,boundary=0,
|
||||
limits=dict(capture=capture,click=14,move=20,grab=2,chain=1,camera=4,mutation=28,configuration=64,spawn=12),duration_s=150,active_watchdog_s=143,
|
||||
status='PLANNED',ceilings=['atomic generation NOT PROVEN','native saved identity NOT OBSERVABLE','complete damage/lifetime NOT PROVEN','STEP20C NEXT; production multi-output NOT YET SUPPORTED'])
|
||||
for v in ('A','G'):plan('scale',v,'scale',SCALE,True,12);plan('saved',v,'saved',capture=10)
|
||||
for v in ('pristine','A','G'):plan('input',v,'input',capture=12);plan('FX',v,'FX',capture=16)
|
||||
for c in ('dynamic','hidden','R90'):plan('G','G',c,ROTATE if c=='R90' else NORMAL,c=='R90',{'dynamic':14,'hidden':12,'R90':10}[c])
|
||||
# Diagnostic is a separate reserved run, disabled until the parent records a decision.
|
||||
DIAGNOSTIC_ID='saved-diagnostic-A'
|
||||
47
tooling/probes/step20c-targeted/prepare.py
Normal file
47
tooling/probes/step20c-targeted/prepare.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Offline only: copy verified retained clients, compile FX, preserve closure."""
|
||||
import argparse,json,shutil,subprocess,sys
|
||||
from gate import *
|
||||
def prepare(lab):
|
||||
lab=owned(lab);need(not (lab/'identity.json').exists(),'preparation already completed')
|
||||
historical=read(HIST/'matrix/compile.json')['files'];dest=lab/'clients';dest.mkdir(exist_ok=True);transfers=[]
|
||||
for name in ('nested-client','pointer-daemon','region-client','saved-client','static-reference','nested-client.c','pointer-daemon.c','region-client.c','saved-client.c','static-reference.c','xdg-shell-client.h','xdg-shell-protocol.c','virtual-pointer-client.h','virtual-pointer-protocol.c','layer-shell-client.h','layer-shell-protocol.c','wlr-layer-shell-unstable-v1.xml'):
|
||||
src=HIST/'matrix/clients'/name;need(sha(src)==historical[str(src)],'historical client exact SHA '+name);target=dest/name
|
||||
need(not target.exists(),'never overwrite prepared client '+name);shutil.copy2(src,target);transfers.append(dict(source=str(src),source_sha256=sha(src),destination=str(target),sha256=sha(target)))
|
||||
for v,(binary,digest) in BINARIES.items():need(sha(binary)==digest,'exact '+v+' binary')
|
||||
need(sha(WLROOTS)==WLROOTS_SHA,'exact wlroots')
|
||||
commands=[];fx=HERE/'fx-client.c'
|
||||
need(fx.exists(),'FX source required before preparation')
|
||||
flags=subprocess.run(['pkg-config','--cflags','--libs','wayland-client'],capture_output=True,text=True,check=True,timeout=10).stdout.split()
|
||||
argv=['cc','-std=c17','-O2','-Wall','-Wextra','-I',str(dest),str(fx),str(dest/'xdg-shell-protocol.c'),str(dest/'layer-shell-protocol.c'),'-o',str(dest/'fx-client'),*flags]
|
||||
result=subprocess.run(argv,capture_output=True,text=True,timeout=30);commands.append(dict(argv=argv,exit=result.returncode,stdout=result.stdout,stderr=result.stderr));need(result.returncode==0,'FX client compilation')
|
||||
closure=set(p for p in BASE.iterdir() if p.is_file())
|
||||
closure.update(MATRIX/n for n in ('engine.py','cases.py','geometry.py','protocols.py','prepare.py','gate.py','tests.py'))
|
||||
closure.update(Path(t['source']) for t in transfers)
|
||||
closure.update([HIST/'matrix/compile.json',HIST/'matrix/freeze.json',HIST/'matrix/review.json',HIST/'matrix/executed-v2-archive/freeze.json',HIST/'matrix/executed-v2-archive/review.json',HIST/'matrix/executed-v2-archive/archive-map.json'])
|
||||
# Include all retained source files, patches and provenance that establish
|
||||
# binaries/libraries, plus all archive originals imported by old reviews.
|
||||
for folder in (HIST/'mosaic-source',HIST/'swayfx-source',HIST/'scene-source',HIST/'wlroots-source',HIST/'release-shape/mosaic-source'):
|
||||
if folder.exists():closure.update(p for p in folder.rglob('*') if p.is_file() and '.git' not in p.parts and not any(x.startswith('build') for x in p.relative_to(folder).parts))
|
||||
for receipt in (HIST/'phase-a.json',HIST/'parent/native-source-audit.json',HIST/'release-shape/build.json',lab/'parent/historical-verification.json'):
|
||||
if receipt.exists():closure.add(receipt)
|
||||
for frozen in (HIST/'matrix/freeze.json',HIST/'horizontal/freeze.json'):
|
||||
for name in read(frozen)['files']:
|
||||
p=Path(name)
|
||||
if p.exists():closure.add(p)
|
||||
closure.update(p for p,_ in BINARIES.values());closure.update([WLROOTS,SCENE,fx,Path(sys.executable).resolve()])
|
||||
import PIL
|
||||
closure.update(p for p in Path(PIL.__file__).parent.rglob('*') if p.is_file() and p.suffix in ('.py','.so'))
|
||||
closure.update(Path(shutil.which(t)).resolve() for t in ('swaymsg','grim','swaybg','cc','pkg-config','wayland-scanner'))
|
||||
for rid in RUNS:(lab/'runs'/rid).mkdir(parents=True)
|
||||
initialize(lab)
|
||||
audit={}
|
||||
for variant,source in [('A',HIST/'mosaic-source'),('G',HIST/'release-shape/mosaic-source')]:
|
||||
rows={name:(source/name).read_text() for name in ('sway/commands/gaps.c','sway/main.c','sway/server.c','sway/desktop/transaction.c','sway/desktop/layer_shell.c')}
|
||||
need('argc == 4 && !config->reading' in rows['sway/commands/gaps.c'] and 'arrange_workspace(ws);' in rows['sway/commands/gaps.c'],'runtime gaps source')
|
||||
need('server.txn_timeout_ms = atoi' in rows['sway/main.c'] and 'if (!server->txn_timeout_ms)' in rows['sway/server.c'] and 'server.txn_timeout_ms);' in rows['sway/desktop/transaction.c'],'timeout source')
|
||||
audit[variant]=dict(paths={str(source/name):sha(source/name) for name in rows},gaps='gaps inner current set 30',startup='-Dtxn-timeout=2500; applied value requires argv plus actual elapsed timeout; native value log absent',marker='layer_shell.c constructor source bound; native IDs/child count absent')
|
||||
durable(lab/'identity.json',dict(scope=SCOPE,status='PREPARED_FOR_REVIEW',runtime='NOT RUN',closure=sorted(map(str,closure)),transfers=transfers,commands=commands,scene_sha256=sha(SCENE),source_audit=audit,clients={str(p):sha(p) for p in dest.iterdir() if p.is_file()},saved_diagnostic='DISABLED; parent decision and distinct reviewed build required'),True)
|
||||
print('PREPARED offline only; compositor NOT RUN; independent review PENDING')
|
||||
if __name__=='__main__':
|
||||
p=argparse.ArgumentParser();p.add_argument('--lab',type=Path,required=True);a=p.parse_args();prepare(a.lab)
|
||||
18
tooling/probes/step20c-targeted/replay.py
Normal file
18
tooling/probes/step20c-targeted/replay.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Read-only D2 association replay and ALL native F commits; no verdict upgrade."""
|
||||
import argparse,json
|
||||
from gate import durable,sha,source_bindings
|
||||
from plans import HIST
|
||||
from validators import native_pairs
|
||||
from test_targeted import HistoricalTests
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('--historical',type=__import__('pathlib').Path,default=HIST);p.add_argument('--output',type=__import__('pathlib').Path,required=True);a=p.parse_args()
|
||||
import test_targeted
|
||||
test_targeted.DATA=a.historical;s,state,raw,client,b=HistoricalTests().fixture()
|
||||
from cases import root_state
|
||||
root=root_state(s,state,state['origin'],b['window'][1]);log=a.historical/'matrix/F-mosaic/run/compositor.log';pairs=native_pairs(log.read_text())
|
||||
evidence={str(p):sha(p) for p in (a.historical/'matrix/D2-mosaic/run').iterdir() if p.name in ('compositor.log','owner.log','events.jsonl','startup-snapshot.json','owner-geometry.json')};evidence[str(log)]=sha(log);gaps=a.historical/'mosaic-source/sway/commands/gaps.c';evidence[str(gaps)]=sha(gaps)
|
||||
durable(a.output,dict(status='PASS',source_bindings=source_bindings(),evidence=evidence,E2=dict(status='SOURCE_ONLY; historical held NOT EXERCISED',runtime_command='gaps inner current set 30',argc=4,arrange_workspace='arrange_workspace(ws);' in gaps.read_text(),source=str(gaps),sha256=sha(gaps)),D2=dict(association=root,preowner=b,historical_verdict='INCONCLUSIVE unchanged; input/dismissal/final NOT EXERCISED'),F=dict(source=str(log),sha256=sha(log),pairs=pairs),runtime='NOT RUN'),True)
|
||||
print('OFFLINE_REPLAY_PASS D2 historical verdict unchanged; F ALL commits='+str(pairs['total_commits']))
|
||||
if __name__=='__main__':main()
|
||||
27
tooling/probes/step20c-targeted/run.py
Normal file
27
tooling/probes/step20c-targeted/run.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env python3
|
||||
"""One newly authorized exact-byte run; no retries or implicit campaigns."""
|
||||
import argparse,json
|
||||
from gate import *
|
||||
from engine import Session
|
||||
from cases import CAMPAIGN
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('--lab',type=Path,required=True);p.add_argument('run_id',choices=RUNS);a=p.parse_args();lab=owned(a.lab)
|
||||
auth=begin(lab,a.run_id);s=None;status='INCONCLUSIVE';failure=None
|
||||
try:
|
||||
s=Session(RUNS[a.run_id],auth,lab);s.start()
|
||||
if s.spec['campaign']=='FX':
|
||||
from fx import effects_campaign
|
||||
status=effects_campaign(s)
|
||||
else:status=CAMPAIGN[s.spec['campaign']](s)
|
||||
except Exception as e:failure=dict(type=type(e).__name__,message=str(e))
|
||||
finally:
|
||||
if s is not None:status=s.cleanup(status,failure)
|
||||
observed={}
|
||||
if s:
|
||||
observed=dict(capture=sum(e['kind']=='capture' for e in s.events),spawn=sum(e['kind']=='spawn' for e in s.events),move=sum(e['kind']=='injection' for e in s.events),click=sum(e['kind']=='injection' and e['action']!='move' for e in s.events),grab=sum(e['kind']=='injection' and e.get('grab',False) for e in s.events))
|
||||
def finish(state):
|
||||
row=state['runs'][a.run_id];need(all(v<=row['reserved'][k] for k,v in observed.items()),'observed reservation reconciliation');row.update(observed=observed,outcome=status,failure=failure)
|
||||
locked(lab,finish);verify(lab)
|
||||
print(json.dumps(dict(id=a.run_id,status=status,failure=failure)));return 1 if failure else 0
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
168
tooling/probes/step20c-targeted/test_fx.py
Normal file
168
tooling/probes/step20c-targeted/test_fx.py
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
"""Bounded offline validator regression tests and retained E3 evidence audit."""
|
||||
import hashlib
|
||||
import json
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
import fx_validators as v
|
||||
|
||||
|
||||
class FXTests(unittest.TestCase):
|
||||
def test_fx_close_command_drives_actual_c_handler(self):
|
||||
source = Path(__file__).with_name('fx-client.c').resolve()
|
||||
lab_clients = Path('/home/fy59/swayfx-mosaic-targeted-7gge6h8b/clients')
|
||||
harness = r'''#define main fx_client_program_main
|
||||
#include "SOURCE_PATH"
|
||||
#undef main
|
||||
int main(void) {
|
||||
mode = "glass";
|
||||
running = 1;
|
||||
close_received = false;
|
||||
handle_command("close-extra\n");
|
||||
if (!running || close_received) return 1;
|
||||
handle_command("close");
|
||||
if (!running || close_received) return 2;
|
||||
top_close(NULL, NULL);
|
||||
if (running || close_received) return 3;
|
||||
running = 1;
|
||||
layer_close(NULL, NULL);
|
||||
if (running || close_received) return 4;
|
||||
running = 1;
|
||||
stop(SIGTERM);
|
||||
if (running || close_received) return 5;
|
||||
running = 1;
|
||||
handle_command("close\n");
|
||||
if (running || !close_received) return 6;
|
||||
return 0;
|
||||
}
|
||||
'''.replace('SOURCE_PATH', str(source))
|
||||
cflags = shlex.split(subprocess.run(
|
||||
['pkg-config', '--cflags', '--libs', 'wayland-client'],
|
||||
check=True, capture_output=True, text=True).stdout)
|
||||
with tempfile.TemporaryDirectory(prefix='fx-close-test-') as temp:
|
||||
harness_path = Path(temp) / 'fx-close-harness.c'
|
||||
binary = Path(temp) / 'fx-close-harness'
|
||||
harness_path.write_text(harness)
|
||||
compile_argv = [
|
||||
'cc', '-std=c17', '-O2', '-I', str(lab_clients),
|
||||
str(harness_path), str(lab_clients / 'xdg-shell-protocol.c'),
|
||||
str(lab_clients / 'layer-shell-protocol.c'), '-o', str(binary),
|
||||
*cflags,
|
||||
]
|
||||
subprocess.run(compile_argv, check=True, capture_output=True, text=True)
|
||||
result = subprocess.run([str(binary)], check=False, capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stderr.count('CLOSE_RECEIVED '), 1)
|
||||
self.assertIn('CLOSE_RECEIVED ', result.stderr)
|
||||
|
||||
def test_whole_difference_survives_exact_center(self):
|
||||
a=Image.new('RGB',(8,8)); b=a.copy(); b.putpixel((7,7),(2,3,4))
|
||||
result=v.restoration(a,b,b,{'center':[1,1,4,4]})
|
||||
self.assertEqual(result['wholeH1']['pixels'],1)
|
||||
self.assertEqual(result['wholeH1']['bbox'],[7,7,8,8])
|
||||
self.assertTrue(result['rois']['center']['AA']['exact'])
|
||||
self.assertEqual(result['wholeH1']['perchannel'][2]['total_abs'],4)
|
||||
|
||||
def test_masks_negative_and_padding_rejected(self):
|
||||
a=Image.new('RGB',(8,8))
|
||||
for box in ([-1,0,4,4],[0,0,9,4],[0,0,0,4]):
|
||||
with self.assertRaises(ValueError):v.diff(a,a,box)
|
||||
with self.assertRaises(ValueError):v.diff(a,a,mask=[1,1,7,7])
|
||||
|
||||
def test_classic_requires_nonempty_actual_filter_and_same_source(self):
|
||||
a=Image.new('RGB',(8,8)); b=Image.new('RGB',(8,8),(80,80,80))
|
||||
for x in range(8):
|
||||
for y in range(8):a.putpixel((x,y),(255,255,255) if x%2 else (0,0,0))
|
||||
for same,path,witness in ((False,{'nonempty_region':True},True),
|
||||
(True,{'nonempty_region':False},True),(True,{'nonempty_region':True},False)):
|
||||
self.assertEqual(v.classic(a,b,[0,0,8,8],same,path,witness)['status'],'CLASSIC_BLUR_NOT_EXERCISED')
|
||||
self.assertEqual(v.classic(a,a,[0,0,8,8],True,{'nonempty_region':True},True)['status'],'CLASSIC_BLUR_NOT_EXERCISED')
|
||||
self.assertEqual(v.classic(a,b,[0,0,8,8],True,{'nonempty_region':True},True)['status'],'EXERCISED')
|
||||
|
||||
def test_unexercised_cache_rejected(self):
|
||||
self.assertEqual(v.cache('')['status'],'NOT OBSERVABLE')
|
||||
self.assertEqual(v.cache('OPT_BLUR_USE output=HEADLESS-1 optimized=1 chosen=(nil)')['status'],'CACHE_NOT_EXERCISED')
|
||||
trace='OPT_DIRTY_SET node=0xa enabled=1 size=800x600\nOPT_REGEN_ATTEMPT output=HEADLESS-1 node=0xa dirty=1\nOPT_REGEN_RESULT output=HEADLESS-1 node=0xa result=1\nOPT_DIRTY_CLEAR output=HEADLESS-1 node=0xa dirty=0\nOPT_BLUR_USE output=HEADLESS-1 optimized=1 chosen=0xb'
|
||||
self.assertEqual(v.cache(trace)['status'],'NATIVE_OBSERVED')
|
||||
self.assertEqual(v.cache(trace.replace('node=0xa result=1','node=0xc result=1'))['status'],'CACHE_NOT_EXERCISED')
|
||||
|
||||
def test_false_normalclose_rejected(self):
|
||||
log='CLIENT_COMMIT ns=1\nRELEASE ns=2 buffer=3\nCLOSE_RECEIVED ns=3\nOBJECTS_DESTROYED ns=4\nEXIT ns=5 error=0 commits=1 normalclose=1 releases=1\n'
|
||||
self.assertEqual(v.normalclose(log,0,True,True)['status'],'PASS')
|
||||
for text,code,alive,gone in ((log,1,True,True),(log,0,False,True),(log,0,True,False),
|
||||
(log.replace('error=0','error=32'),0,True,True),
|
||||
(log.replace('OBJECTS_DESTROYED','CLIENT_COMMIT'),0,True,True),
|
||||
(log.replace('RELEASE ns=2 buffer=3\n',''),0,True,True)):
|
||||
self.assertEqual(v.normalclose(text,code,alive,gone)['status'],'FAIL')
|
||||
|
||||
|
||||
def audit(historical, lab):
|
||||
"""Read HIST only; write new offline evidence solely below the supplied LAB."""
|
||||
hist, lab=Path(historical).resolve(),Path(lab).resolve()
|
||||
v.require(hist!=lab and not lab.is_relative_to(hist),'separate new LAB')
|
||||
out=lab/'results'/'fx-offline';out.mkdir(parents=True,exist_ok=True)
|
||||
results={}
|
||||
for variant in ('pristine','mosaic'):
|
||||
run=hist/'matrix'/('E3-'+variant)/'run'
|
||||
result=v.validate_run(run)
|
||||
geom=json.loads((run/'glass-geometry.json').read_text())
|
||||
origin=geom['origin']; win=geom['owner']['window_rect']
|
||||
x=max(-800,origin[0]);r=min(0,origin[0]+win['width']);y=max(0,origin[1]);t=min(600,origin[1]+win['height'])
|
||||
center=[(x+r)//2+800,(y+t)//2];roi=[center[0]-32,center[1]-32,center[0]+32,center[1]+32]
|
||||
result['historical_center_reconstructed_from_retained_geometry']=roi
|
||||
result['historical_center']=v.diff(run/'optimized-A-H1.png',run/'optimized-A-return-H1.png',roi)
|
||||
events=[json.loads(l) for l in (run/'events.jsonl').read_text().splitlines()]
|
||||
close=[e for e in events if e['kind']=='client-request' and e.get('command','').startswith('close')]
|
||||
exitrows={name:[l for l in (run/(name+'.log')).read_text().splitlines() if l.startswith('EXIT ')] for name in ('glass','background')}
|
||||
terminal=json.loads((run/'terminal-ipc.json').read_text())
|
||||
trace=(run/'compositor.log').read_text(errors='replace')
|
||||
result['shutdown_chronology']=dict(last_capture_ns=max(e['end_ns'] for e in events if e['kind']=='capture'),
|
||||
explicit_client_close_requests=close,client_exits=exitrows,terminal_ipc=terminal,
|
||||
compositor_shutdown_lines=[l for l in trace.splitlines() if any(k in l.lower() for k in ('shutting down','destroying','exiting'))][-12:],
|
||||
inference='error32 after failed equality and runner teardown; normal close NOT EXERCISED; GPU/client lifetime defect NOT PROVEN',
|
||||
exact_native_compositor_exit_ns='NOT OBSERVABLE in retained log; stderr textual shutdown order alone is insufficient')
|
||||
result['input_files']={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(run.iterdir()) if p.is_file()}
|
||||
(out/(variant+'.json')).write_text(json.dumps(result,indent=2)+'\n');results[variant]=result
|
||||
(out/'AUDIT.md').write_text('''# Experimental retained E3 FX audit
|
||||
|
||||
HIST is read-only. Shared validators report complete RGB differences, including
|
||||
bbox and per-channel count/sum/max. Central exact RGB does not establish whole
|
||||
H1 restoration. Old client exits error32 follow runner teardown after the
|
||||
whole-image predicate failed; no explicit normal close was sent. Native exact
|
||||
compositor-exit ns is absent, so no precise GPU lifetime chronology is invented.
|
||||
|
||||
The old filler0 is static-reference (opaque XRGB 0x00303038), under floating
|
||||
glass at (-650,200); it hides the striped wallpaper. The classic off/on entire
|
||||
H1/H2 images are identical. Actual classic filtering was NOT EXERCISED. The
|
||||
new client substitutes a transparent ARGB filler and retains source bytes.
|
||||
Glass ARGB 0x88442010 has alpha 136 and RGB 68/32/16 <= alpha (premultiplied).
|
||||
Background XRGB has 8-pixel alternating stripes. No opaque region is requested
|
||||
by the client. Background is a layer-shell background on HEADLESS-1; floating
|
||||
glass is above tiled transparent filler. RGB off/on comparison with immutable
|
||||
sources distinguishes filter activity from compositing alone.
|
||||
|
||||
Source-selected blur: sway/desktop/output.c could_container_overlap returns
|
||||
true for floating/animated owners; should_optimize_blur = blur_xray OR NOT
|
||||
could_container_overlap. SceneFX fx_pass.c fx_render_pass_add_blur calls
|
||||
get_main_buffer_blur for classic, then logs chosen before final texture draw.
|
||||
A chosen pointer proves neither nonempty final filter region nor pixel effect.
|
||||
Classic EXERCISED requires same SHM source and actual changing RGB plus reduced
|
||||
adjacent contrast in the prospectively fixed center. Without that evidence the
|
||||
status remains CLASSIC_BLUR_NOT_EXERCISED. OPT native events are cache-only;
|
||||
client wire buffer IDs cannot be equated to output/cache pointers. Aggregate
|
||||
native trace presence cannot establish causal A/B/A dirty chronology.
|
||||
|
||||
No compositor launched. Complete frame/damage/GPU lifetime is NOT PROVEN.
|
||||
''')
|
||||
return {k:dict(wholeH1=r['optimized']['wholeH1'],center=r['historical_center'],
|
||||
classic=r['classic_H1']) for k,r in results.items()}
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)==4 and sys.argv[1]=='--audit':
|
||||
print(json.dumps(audit(sys.argv[2],sys.argv[3]),indent=2))
|
||||
else:unittest.main()
|
||||
100
tooling/probes/step20c-targeted/test_targeted.py
Normal file
100
tooling/probes/step20c-targeted/test_targeted.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
"""Offline source, persistent budget and actual D2/F evidence negatives."""
|
||||
import argparse,copy,json,re,sys,tempfile,time,unittest
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock,patch
|
||||
import gate
|
||||
from plans import RUNS,HIST
|
||||
from geometry import *
|
||||
from validators import held_configure,native_pairs
|
||||
from cases import marker_host_baseline,root_state,associated_root
|
||||
from transition import observed_epochs
|
||||
DATA=HIST
|
||||
class PureTests(unittest.TestCase):
|
||||
def test_compile_sources(self):
|
||||
for p in gate.HERE.glob('*.py'):compile(p.read_text(),str(p),'exec')
|
||||
def test_fixed_allocation(self):
|
||||
self.assertEqual(len(RUNS),13);self.assertLessEqual(sum(s['limits']['capture'] for s in RUNS.values()),174)
|
||||
for campaign,cap in gate.CAPS.items():self.assertLessEqual(sum(s['limits']['capture'] for s in RUNS.values() if s['campaign']==campaign),cap)
|
||||
self.assertTrue(all(s['limits']['capture']<=16 for s in RUNS.values()))
|
||||
def test_halfopen_and_scale(self):
|
||||
o=RUNS['scale-A']['outputs'][0]
|
||||
for p in ([-700,100],[-500,300],[-200,400]):self.assertEqual(png_global(global_png(p,o,'logical'),o,'logical'),p)
|
||||
self.assertFalse(contains([-800,0,800,600],[0,300]))
|
||||
def test_stale_invalidation(self):
|
||||
from engine import Session
|
||||
s=Session.__new__(Session);s.coordinate_epoch=4;s.proofs={(1,2):dict(epoch=4)};s.record=Mock();s.invalidate('focus')
|
||||
self.assertEqual(s.coordinate_epoch,5);self.assertEqual(s.proofs,{})
|
||||
def test_held_serial(self):
|
||||
before='ACK ns=1 serial=30 size=420x320\nxdg_surface#5.ack_configure(30)\nwl_shm_pool#6.create_buffer(8)\nCOMMIT ns=2'
|
||||
after='xdg_surface#5.configure(44)\nXDG_CONFIGURE ns=4 serial=44 size=300x200 hold=1 previous=0\nHELD ns=5 serial=44'
|
||||
self.assertEqual(held_configure(before,after,30)['serial'],44)
|
||||
for b,a,p in [(before,after+'\nxdg_surface#5.ack_configure(44)',30),(before,after.replace('.configure(44)','.configure(999)'),30),(before,after.replace('serial=44','serial=30').replace('configure(44)','configure(30)'),30),(before,after.replace('HELD','ABSENT'),30),(before.replace('ACK ns=1 serial=30','ABSENT'),after,30)]:
|
||||
with self.assertRaises(ValueError):held_configure(b,a,p)
|
||||
def test_pair_all_not12(self):
|
||||
text='\n'.join(f'PI_OUTPUT_COMMIT output=H1 commit_seq={i} ns={i*10}\nPI_OUTPUT_PRESENT output=H1 commit_seq={i} ns={i*10+1} presented=1' for i in range(1,20))
|
||||
r=native_pairs(text);self.assertEqual(r['paired'],19);self.assertEqual(r['missing'],0)
|
||||
r=native_pairs(text.replace('PI_OUTPUT_PRESENT output=H1 commit_seq=19','OMITTED output=H1 commit_seq=19'));self.assertEqual(r['missing'],1)
|
||||
with self.assertRaises(ValueError):native_pairs(text+'\nPI_OUTPUT_COMMIT output=H1 commit_seq=1 ns=500')
|
||||
def test_review_refusal_no_token(self):
|
||||
with patch.object(gate,'owned',return_value=Path('/missing')),patch.object(gate,'verify',side_effect=ValueError('review absent')),patch.object(gate,'locked') as locked:
|
||||
with self.assertRaises(ValueError):gate.begin('/missing','scale-A')
|
||||
locked.assert_not_called()
|
||||
def test_ledger_atomic_no_retry_and_reconciliation(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
lab=Path(d);state=dict(scope=gate.SCOPE,runs={},events=[],used=dict(run=0,capture=0),campaign_used=dict.fromkeys(gate.CAPS,0),campaign_runs=dict.fromkeys(gate.CAPS,0));gate.durable(lab/'budget.json',state,True)
|
||||
with patch.object(gate,'owned',return_value=lab):
|
||||
def consume(s):
|
||||
p=RUNS['scale-A']['limits'];s['runs']['scale-A']=dict(campaign='scale',planned=p,reserved=dict.fromkeys(p,0));s['used']['run']=1;s['campaign_runs']['scale']=1
|
||||
gate.locked(lab,consume);gate.action_debit(lab,'scale-A','capture','configuration','click')
|
||||
s=gate.read(lab/'budget.json');self.assertEqual(s['used']['capture'],1);self.assertEqual(s['runs']['scale-A']['reserved']['click'],1)
|
||||
bad=copy.deepcopy(s);bad['events'].pop()
|
||||
with self.assertRaises(ValueError):gate.validate(bad)
|
||||
gate.action_debit(lab,'scale-A',*(['capture']*11));before=(lab/'budget.json').read_bytes()
|
||||
with self.assertRaises(ValueError):gate.action_debit(lab,'scale-A','capture')
|
||||
self.assertEqual(before,(lab/'budget.json').read_bytes())
|
||||
def test_incomplete_receipt_rejected(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
lab=Path(d);gate.durable(lab/'offline.json',{'status':'PASS'},True)
|
||||
with self.assertRaises(ValueError):gate.test_receipt(lab,'offline.json',14)
|
||||
gate.durable(lab/'replay.json',{'status':'PASS'},True)
|
||||
with self.assertRaises(ValueError):gate.replay_receipt(lab)
|
||||
def test_geometry_held_unchanged_rejected(self):
|
||||
before='ACK ns=1 serial=30 size=420x320\nxdg_surface#5.ack_configure(30)\nwl_shm_pool#6.create_buffer(8)\nCOMMIT ns=2'
|
||||
after='xdg_surface#5.configure(44)\nXDG_CONFIGURE ns=4 serial=44 size=420x320 hold=1 previous=0\nHELD ns=5 serial=44'
|
||||
with self.assertRaises(ValueError):held_configure(before,after,30)
|
||||
class HistoricalTests(unittest.TestCase):
|
||||
def fixture(self):
|
||||
run=DATA/'matrix/D2-mosaic/run';events=[json.loads(l) for l in (run/'events.jsonl').read_text().splitlines()];owner_start=next(e['ns'] for e in events if e['kind']=='spawn' and e['name']=='owner');trace=(run/'compositor.log').read_text()
|
||||
before=[]
|
||||
for l in trace.splitlines():
|
||||
m=re.search(r'\bns=(\d+)',l)
|
||||
if m and int(m[1])>=owner_start:break
|
||||
before.append(l)
|
||||
session=SimpleNamespace(spec={'marker':True,'mode':'mosaic'},proc={'marker-background':Mock(pid=77)},events=[e for e in events if e['ns']<owner_start],log=lambda n:'\n'.join(before),snapshot=lambda tag:json.loads((run/'startup-snapshot.json').read_text()),save=Mock());session.proc['marker-background'].poll.return_value=None
|
||||
with patch('cases.time.monotonic_ns',return_value=owner_start-1):baseline=marker_host_baseline(session)
|
||||
state=json.loads((run/'owner-geometry.json').read_text())
|
||||
epoch=next(e for e in observed_epochs(trace,'HEADLESS-1',0,999999999999999999) if e['scene'] and e['scene'].get('layout')=='5' and len(e['roots'])==2 and any(o.get('id')=='9' and list(map(int,o['scene'].split(',')))==state['scene'][:2] for o in e['owners']))
|
||||
raw='\n'.join(epoch['raw']);client=(run/'owner.log').read_text().split('POPUP_B DESTROY')[0].split('POPUP_B POPUP_DONE')[0];session.outputs=[dict(name='HEADLESS-1',logical=[-800,0,800,600])];session.log=lambda n:raw if n=='compositor' else client
|
||||
return session,state,raw,client,baseline
|
||||
def test_actual_D2_association(self):
|
||||
s,state,raw,client,b=self.fixture();r=root_state(s,state,state['origin'],b['window'][1]);self.assertNotEqual(r['tree'],b['tree']);self.assertEqual(len(r['states'][0]['all_roots']),2)
|
||||
def test_host_membership_negatives(self):
|
||||
s,state,raw,client,b=self.fixture();roots=observed_epochs(raw,'HEADLESS-1',0,999999999999999999)[0]['roots']
|
||||
for bad in ([roots[1]],roots+[dict(roots[1],tree='unknown')],[dict(roots[0],tree='unknown'),roots[1]],[dict(roots[0],clip_valid='1'),roots[1]],[roots[0],dict(roots[1],tree=roots[0]['tree'])],list(reversed(roots))):
|
||||
with self.assertRaises(ValueError):associated_root(bad,b,b['window'][1]+1)
|
||||
with self.assertRaises(ValueError):associated_root(roots,b,b['window'][1])
|
||||
def test_clip_owner_ancestry_negatives(self):
|
||||
s,state,raw,client,b=self.fixture();root=observed_epochs(raw,'HEADLESS-1',0,999999999999999999)[0]['roots'][1];clip=root['clip'].split(',');clip[0]=str(int(clip[0])+1);badclip=raw.replace('clip='+root['clip'],'clip='+','.join(clip));later=re.sub(r'ns=(\d+)',lambda m:'ns='+str(int(m[1])+100000),raw)
|
||||
for bad in (raw.replace(' id=9 ',' id=99 '),raw.replace('workspace=6','workspace=99'),badclip+'\n'+later):
|
||||
s.log=lambda n:bad if n=='compositor' else client
|
||||
with self.assertRaises(ValueError):root_state(s,state,state['origin'],b['window'][1])
|
||||
state=copy.deepcopy(state);state['workspace']['output']='HEADLESS-2'
|
||||
with self.assertRaises((ValueError,StopIteration)):root_state(s,state,state['origin'],b['window'][1])
|
||||
def test_all_historical_F_commits(self):
|
||||
raw=(DATA/'matrix/F-mosaic/run/compositor.log').read_text();r=native_pairs(raw);self.assertEqual(r['total_commits'],raw.count('PI_OUTPUT_COMMIT '));self.assertGreater(r['total_commits'],12);self.assertEqual(len(r['analyzed']),r['total_commits']);self.assertGreaterEqual(r['missing'],2)
|
||||
if __name__=='__main__':
|
||||
p=argparse.ArgumentParser();p.add_argument('--historical',type=Path,default=HIST);p.add_argument('--output',type=Path,required=True);a=p.parse_args();DATA=a.historical
|
||||
import io
|
||||
raw=io.StringIO();suite=unittest.TestSuite(unittest.defaultTestLoader.loadTestsFromTestCase(c) for c in (PureTests,HistoricalTests));result=unittest.TextTestRunner(stream=raw,verbosity=2).run(suite);log=a.output.with_suffix('.log');log.write_text(raw.getvalue());print(raw.getvalue())
|
||||
gate.durable(a.output,dict(status='PASS' if result.wasSuccessful() else 'FAIL',executed=result.testsRun,exit=0 if result.wasSuccessful() else 1,command=[sys.executable,*sys.argv],source_bindings=gate.source_bindings(),raw_output=str(log),raw_sha256=gate.sha(log),failures=[(str(t),e) for t,e in result.failures],errors=[(str(t),e) for t,e in result.errors],runtime='NOT RUN'),True);raise SystemExit(not result.wasSuccessful())
|
||||
32
tooling/probes/step20c-targeted/validators.py
Normal file
32
tooling/probes/step20c-targeted/validators.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""Shared offline/runtime evidence predicates; absent wire evidence fails closed."""
|
||||
import re
|
||||
from geometry import need
|
||||
|
||||
def held_configure(before,after,prior_serial):
|
||||
need(type(prior_serial)is int and prior_serial>0,'prior serial required')
|
||||
need(re.search(rf'ACK ns=\d+ serial={prior_serial}\b',before) and re.search(rf'ack_configure\({prior_serial}\)',before),'initial actual ACK required')
|
||||
need('wl_shm_pool#' in before and '.create_buffer(' in before and 'COMMIT ns=' in before,'real initial SHM required')
|
||||
held=re.findall(r'HELD ns=(\d+) serial=(\d+)',after);need(len(held)==1,'unique real HELD configure')
|
||||
ns,serial=map(int,held[0]);need(serial!=prior_serial,'new held serial')
|
||||
need(re.search(rf'xdg_surface#\d+\.configure\({serial}\)',after),'received actual configure wire')
|
||||
need(re.search(rf'XDG_CONFIGURE ns=\d+ serial={serial}\b.*hold=1',after),'client received hold state')
|
||||
old=re.findall(r'ACK ns=\d+ serial='+str(prior_serial)+r' size=(\d+)x(\d+)',before);new=re.findall(r'XDG_CONFIGURE ns=\d+ serial='+str(serial)+r' size=(\d+)x(\d+)',after)
|
||||
need(old and new and old[-1]!=new[-1],'new geometry configure required')
|
||||
need(not re.search(rf'ack_configure\({serial}\)|ACK ns=\d+ serial={serial}\b',after),'held serial must remain unACKed')
|
||||
return dict(ns=ns,serial=serial,prior_serial=prior_serial,initial_size=list(map(int,old[-1])),requested_size=list(map(int,new[-1])),status='HELD_WIRE_VALIDATED',native_saved_identity='NOT OBSERVABLE')
|
||||
|
||||
def native_pairs(text):
|
||||
commits=[];presents={};seen=set()
|
||||
for raw in text.splitlines():
|
||||
if not ('PI_OUTPUT_COMMIT ' in raw or 'PI_OUTPUT_PRESENT ' in raw):continue
|
||||
f=dict(re.findall(r'(\w+)=([^\s]+)',raw));need(all(k in f for k in ('output','commit_seq','ns')),'native pair fields');key=(f['output'],int(f['commit_seq']))
|
||||
if 'PI_OUTPUT_COMMIT ' in raw:
|
||||
need(key not in seen,'duplicate native commit');seen.add(key);commits.append((key,f,raw))
|
||||
else:
|
||||
need(key not in presents,'duplicate native present');presents[key]=(f,raw)
|
||||
rows=[]
|
||||
for key,f,raw in commits:
|
||||
p=presents.get(key)
|
||||
if p:need(int(p[0]['ns'])>int(f['ns']),'present order')
|
||||
rows.append(dict(output=key[0],seq=key[1],commit=raw,present=p[1] if p else None,presented=p[0].get('presented') if p else None,status='PAIRED' if p else 'MISSING_PRESENT'))
|
||||
return dict(total_commits=len(commits),analyzed=rows,paired=sum(r['status']=='PAIRED' for r in rows),missing=sum(r['status']=='MISSING_PRESENT' for r in rows),unmatched_presents=[dict(output=k[0],seq=k[1],raw=v[1]) for k,v in presents.items() if k not in seen],atomic_generation='NOT PROVEN',buffer_identity='NOT PROVEN',physical_presentation='NOT PROVEN')
|
||||
Loading…
Reference in a new issue