test(mosaic): preserve reviewed CORE-C V2 headless fixtures

This commit is contained in:
fy59 2026-10-15 07:50:23 +02:00
parent 1053ab2a47
commit c0a822a079
33 changed files with 5077 additions and 0 deletions

View file

@ -0,0 +1,24 @@
# Private CORE C V2 build recipe — EXPERIMENTAL
Run only after exact source/C independent review of the assembled source. This recipe creates no production install. Source reconstruction is exact; binary bit-for-bit reproducibility across compilers/timestamps is NOT PROVEN. Require >=20GiB filesystem free, new LAB solely below /var/tmp, redirected TMP/cache/data, no inherited display/session/loader routing, RLIMIT_CORE0, parallel jobs<=8. Use the assembled `scene` and `mosaic` directories, not a Mosaic checkout as pristine.
From an already owned LAB with sources assembled using the kit:
```sh
meson setup "$LAB/build-scene" "$ASSEMBLED/scene" --prefix=/usr --wrap-mode=nodownload -Ddefault_library=static -Dexamples=false
meson compile -C "$LAB/build-scene" -j8
```
Supply PKG_CONFIG_PATH="$LAB/build-scene/meson-uninstalled" for Mosaic setup only. Its pkg-config executable wrapper must invoke the real pkg-config using argv and add --static to --libs requests so the static archive dependency closure is linked; do not modify system pkg-config or install SceneFX. Retain wrapper bytes/argv/raw statuses and resolved dependency paths. Use default compiler for both libraries; record version and headers. A shell wrapper equivalent for these controlled invocations is `exec /usr/bin/pkg-config --static "$@"`; the executed campaign used a Python execv wrapper which appended --static only for --libs. Check the actual Ninja link command for the private archive and native symbols; a successful setup alone is insufficient.
```sh
PKG_CONFIG="$PRIVATE_PKG_CONFIG_WRAPPER" PKG_CONFIG_PATH="$LAB/build-scene/meson-uninstalled" meson setup "$LAB/build-mosaic" "$ASSEMBLED/mosaic" --prefix=/usr --bindir=bin --wrap-mode=nodownload -Dmosaic-package=true -Dsd-bus-provider=libsystemd -Dswaybar=false -Dswaynag=false -Dman-pages=disabled -Ddefault-wallpaper=false -Dc_args=-Wno-error=switch
meson compile -C "$LAB/build-mosaic" -j8
meson test -C "$LAB/build-mosaic" mosaic-model --print-errorlogs
```
The private c_args compatibility exception keeps -Wswitch warnings visible. GCC16.2.1 plus the installed newer libinput enum SCROLL_CIRCULAR caused the original -Werror build failure at upstream ipc-json.c1175. scroll_method is initialized to unknown before that switch, so no source change was made. Original failure and final warning remain evidence. It is not a general permission to suppress compiler failures.
Verify readelf/nm/ldd-r, no SceneFX DT_NEEDED/RPATH/RUNPATH, exact wlroots SHA7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837 and actual factory binding from wlroots to the executable before runtime. Stage only Mosaic with `DESTDIR="$LAB/stage" meson install -C "$LAB/build-mosaic" --no-rebuild`; add the three exact pinned LICENSE texts and conservative INCORPORATED-NOTICES. Exactly binary0755 plus four notices0644 are allowed under the ticket paths. No symlinks, library or system package. LEGAL_NOT_APPROVED.
This recipe does not reserve a build/run or authorize bypassing budgets/publication/review. Every new build identity requires its own measured SHA/BuildID and reviewer receipt. Retained pristine is independently qualified, never built from these Mosaic sources. No compositor --version or live IPC is part of build validation.

View file

@ -0,0 +1,157 @@
# STEP20C CORE-C V2 graphics source fixture
EXPERIMENTAL. Source implementation and offline controls; graphics preflight is
PENDING_INDEPENDENT_REVIEW. No compositor, Wayland client, IPC, screenshot or real
ledger reservation has been executed while preparing this subtree. STEP20C NEXT;
production multi-output NOT_YET_SUPPORTED; PRODUCTION_AUTHORIZED FALSE.
This is a new derivation, not recovery of old lab evidence. Surviving versioned
core-recovery geometry, wire parser, input, lifecycle, saved validators, C clients
and scenario code are reused with declared V2 changes. Original paths and hashes
are in parent-provenance.json. Synthetic wire-fixture is solely a protocol parser
control; it never qualifies a new binary. No historical replay or binary hash is
an input. Protocol XML is source; generated protocol C/headers and binaries remain
outside the kit. XML copyright/license headers are retained.
## Offline reproduction
Use a canonical, UID-owned direct `/var/tmp/<new-lab>` directory, its owned scratch,
cache, data, pycache, results, logs, graphics-tests folders, and a wrapper redirecting
TMPDIR/TMP/TEMP/XDG_CACHE_HOME/XDG_DATA_HOME/PYTHONPYCACHEPREFIX/CCACHE_DIR into LAB.
Place this subtree as LAB/graphics-kit. Python3, Pillow, C17 compiler, pkg-config,
wayland-client development files and wayland-scanner are prerequisites.
```sh
LAB/run-env python LAB/graphics-kit/prepare.py --lab LAB
LAB/run-env python LAB/graphics-kit/offline/test_graphics_v2.py
LAB/run-env python LAB/graphics-kit/freeze.py --lab LAB
```
Replace LAB with its absolute path. prepare.py creates graphics-tests/client-build
exclusively, generates protocol bindings using system scanner and records versions,
commands, raw statuses and source/output hashes in results/graphics-client-compile.json.
It never executes a client. Tests create only graphics-tests/OFFLINE_TEST_ONLY
ledger fixtures and mock transports for actual Session/run paths. SMX_TEST_LAB
selects the lab when source is placed elsewhere inside a full kit. freeze.py writes
results/graphics-source-freeze.json, never into source inputs. No old absolute lab
or historical raw PNG is needed.
## Runtime admission contract — NOT RUN
Only the parent orchestrator initializes Ledger(lab) and spends real budget after
independent build review, source-kit publication and per-scenario review. The
single-case CLI accepts run ID and --lab/--manifest/--review/--publication. No all
cases or retry mode exists. APIs: initialize/admit/action_debit/complete, no
reset/refund. Reserved failures stay consumed. All action debits precede action.
Immutable manifest schema graphics-v2-frozen-inputs requires ticket, lab, author,
source_root, files (ALL relative source SHA256), plans=plans.RUNS, limits=plans.LIMITS,
identities, kit_manifest, kit_manifest_sha256. Exclude mutable captures, logs,
ledgers, reviews, generated artifacts and self. The separately hashed full-kit
manifest binds core recipes/patches/tests as well: ticket, source_root, files,
source_commit. Addition/removal/modification invalidates admission.
Per-case review: decision ACCEPTED, independent true, reviewer different from
author, manifest_sha256, authorized_runs. Identity: binary, binary_sha256, wlroots,
wlroots_sha256, build_review ACCEPTED, source_qualification ACCEPTED; pristine also
pristine_scene/pristine_scene_sha256. No old binary hash is assumed. Publication:
ticket, decision VERIFIED, source_commit, kit_manifest_sha256, source_digest
(gate.digest of graphics files map), origin_sha/github_sha both equal full-kit
source_commit, offline_test_only false. Parent records direct git ls-remote
observations and associates published commit to kit bytes; runner does no network.
All bytes and input/review/publication hashes are rebound before each action.
OFFLINE_TEST_ONLY cannot authorize a Session. Stable flock inode, no-follow,
UID/link/type checks, atomic fsync replacements, token and monotonic duration
protect against duplicate spend/stale use.
Environment allowlist clears inherited display/runtime/socket/loader/backend and
activation. Only mode0700 /tmp/smx-unique holds sockets. Logs/PNG/source marker
PNG/SHM/cache/temp stay in LAB. C clients check LAB/scratch lengths before mkstemp;
launcher requires canonical owned scratch. Every swaymsg uses private explicit -s.
Owned PID/groups, raw stdout/stderr, /proc/PID/exe SHA/maps, loaded wlroots exact
7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837, SceneFX mapping,
actual renderer and EGL startup log lines are recorded (empty EGL is NOT_OBSERVABLE).
Watchdog kills only owned groups. Normal close/SHM release/Wayland error0 are
scientific closure. Forced mechanical cleanup never qualifies it. Terminal IPC,
client/compositor and outer runner raw exits remain distinct.
## Frozen intent and limits
| ID | Captures | Scenario/admission before independent review |
| --- | ---: | --- |
| P0 | 10 | pristine standard reduced homologous chain, B close/A survives |
| P1 | 10 | NOT_ADMITTED: no comparable fullscreen offline certificate |
| C1 | 18 | horizontal B/forbidden dismissal, new second chain, splith return |
| C2 | 12 | vertical y600 actual root/nested configure geometry |
| C3 | 12 | H1 physical1000x750 scale1.25 logical800x600 negative origin; marker |
| C4 | 12 | H1 physical750x1000 scale1.25 transform90, IPC/PNG marker |
| C5 | 12 | hidden motion only until return, same objects/grabs, fresh B input |
| C6 | 12 | real SHM held configure, txn-timeout5000 argv, natural timeout/ACK |
| C7 | 14 | 800→960→800, H1→H2→H1 stable IDs, input after each mutation |
| C8 | 12 | NOT_ADMITTED: same fullscreen certificate missing as P1 |
| O1 | 8 | NOT_ADMITTED: first-allocation diagnostic source/binary unavailable |
| O2 | 8 | NOT_ADMITTED: second-allocation diagnostic source/binary unavailable |
| G2 | 16 | NOT_ADMITTED: new GPU hook/observability unavailable |
| R1 | 14 | NOT_ADMITTED: independent discriminant unspecified; never retry |
Caps sum170, global180, max14runs,18captures/run,150s/run. C7 spends opening6 plus
four mutation pairs8; final post-close pixel capture explicitly NOT_TESTED.
Legitimate popup_done is recorded; no dead popup gets clicked, its input is
NOT_EXERCISED. All runtime results NOT_RUN; sampled success at most
PARTIALLY_FEASIBLE, never production readiness. No final OOM/popup policy chosen.
C1 uses A350x170/B300x130 configured/native popup sizes and requires real crossing,
not requested placement alone. P0 reuses mapped images to stay within10. Before
and after second spawn, workspace1/H1/Mosaic tiled ancestry/PID are checked;
second ownerID/PID must be fresh. floating=null is handled with actual tiled
branch membership and nested ancestry. SHM dimensions, configure destination,
decoration fields and current origins stay distinct. Fresh pointer-local input
and paint corroborate current IPC candidates. Whole H2 RGB is exact zero tolerance
and no mask, except expected standard overflow. Source marker PNG is separate from
screenshot count; actual marker screenshot is debited. Root/nested configure ACK
map and actual pointer press→grab serial are checked independently. Dismissal is
not invisible delivery or universal click-through.
Core source retains three passive formats SPIKE_CLIP, PROBE_POPUP_CLIP and
PROBE_POPUP_HIDDEN_OWNER; temporal neutrality NOT_PROVEN. NULL/zero both print0x0;
no identity/generation is inferred. SPIKE_DAMAGE/PI/OPT absent. Native commit/present,
complete damage, saved-tree identity, buffer identity, GPU completion and atomic
generation remain NOT_OBSERVABLE/NOT_PROVEN absent distinct native measurement.
evidence.native_present rejects fake/cross-run records; never manufactures one.
evidence.fullscreen_certificate is offline-only and cannot itself enable P1/C8.
Offline handler quota controls exercise the actual sequencing with explicit fake
I/O, not native scientific measurements: P0=10, C1=16, C2=8, C3/C4=8+1 startup
marker screenshot, C5=12, C6=10, C7=14. All fake spawn/configuration/mutation/input/
chain/camera actions are checked against the same local caps. Real protocol,
serial, closure, source/publication and geometry adversarial tests are separate.
Initial vertical quota fixture failure is retained in the lab log; its source
fixture correction is disclosed in results/graphics-offline.json.
The swaybg marker helper is explicitly terminated/reaped immediately after the
calibration capture. Its raw helper-exit status is retained separately; expected
helper SIGTERM is never a scientific XDG close/SHM-release claim. A direct test
exercises this actual helper retirement path without launching swaybg.
## Bounded R-runtime repair — OFFLINE ONLY
The watchdog owns TERM at elapsed143s and autonomous KILL no later than146s
(or after a two-second grace for log-limit expiry). Main cleanup uses the same
absolute146s deadline, with reaping bounded by147s. Process registration and
watchdog expiry share a lock. The offline real Python child ignores TERM in its
own session/group; KILL is observed without invoking main cleanup. This is a
mechanical watchdog test, not native compositor cleanup evidence.
C7 now rejects a wrong reconstructed clamp at every resize/migration. The pinned
mosaic.c row calloc leaves minimum_cell_width zero; no production setter exists;
arrange.c and mosaic.c use640. This is independently corroborated by all three
actual direct-child IPC widths640 and zero-gap x positions, at viewport widths
below1920. The predicate rejects a different shape instead of guessing a policy.
Expected scroll is min(previous scroll,1920-current viewport width). Every sampled
mutation image rejects popup-colored pixels outside the current output viewport;
H2 must additionally equal the whole static reference after both resizes and
return toH1. Each surviving chain requires a newly sampled B interior and fresh
pointer-local delivery; dismissal records NOT_EXERCISED input without clicking a
destroyed popup. Source identity/publication binding and all original caps remain.
These are pending IPC plus sampled paint/input predicates, not native applied
state or generation/damage proof. Runtime remains NOT_RUN pending delta review.

View file

@ -0,0 +1,159 @@
"""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]+10]);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 root_state(s,state,origin,window_start,expect_hidden=False,previous=None,expected_tree=None):
# WHY/CONTRACT/INVARIANT: no PI/native scene identity exists in CORE.
# Pixel/input evidence qualifies sampled clipping only, never generation.
return dict(status='NOT OBSERVABLE',native_tree_identity='NOT OBSERVABLE',
applied_generation='NOT OBSERVABLE',owner_id=state['owner']['id'],
workspace_id=state['workspace']['id'],window=[window_start,time.monotonic_ns()])
def open_chain(s,tail_fillers=0):
s.cmd('workspace 1');s.cmd('layout mosaic' if s.spec['mode']=='mosaic' else 'layout splith');s.expected_layout='mosaic' if s.spec['mode']=='mosaic' else 'splith'
pre=s.snapshot('before-chain-'+str(sum(e['kind']=='spawn' and e['name']=='owner' for e in s.events)))
validators.selected_workspace(pre,'1','HEADLESS-1',s.expected_layout)
s.debit('chain');s.launch_client('owner',s.spec['client'],s.spec['placement'])
s.owner('owner') # Reject wrong map before any click; never move mapped popup chains.
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=s.reference if hasattr(s,'reference') else stable_reference(s);s.reference=baseline
im=s.capture('owner-top-'+str(sum(e['kind']=='spawn' and e['name']=='owner' for e in s.events)),'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['axis']==1 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-'+str(sum(e['kind']=='spawn' and e['name']=='owner' for e in s.events)),'HEADLESS-1');prov=Provenance(state['owner']['id'],state['workspace']['id'],'NOT OBSERVABLE',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=validators.grab(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'])
[validators.crosses(g[k],s.spec['axis'],s.spec['boundary']) for k in ('A','B')]
left,right=s.pair_capture('mapped-'+str(sum(e['kind']=='spawn' and e['name']=='owner' for e in s.events)))
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':validators.rgb(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 'PARTIALLY_FEASIBLE'
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')
validators.hidden_survival(s.log('owner'),p,[])
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');validators.hidden_survival(s.log('owner'),p,[e for e in s.events if e['kind']=='injection' and start<=e['ns']<=return_start]);exact(baseline,images[1]);returned_root=root_state(s,restored,restored['origin'],return_start,previous=hidden,expected_tree=root.get('tree'));fresh=validators.grab(s.log('owner'));need(fresh['ids']==p['ids'] and fresh['grabs']==p['grabs'],'unchanged live chain')
g=geometry(s.log('owner'),restored['origin'],Provenance(restored['owner']['id'],restored['workspace']['id'],'NOT OBSERVABLE','fresh return geometry'));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 'PARTIALLY_FEASIBLE'
def sample_surviving(s,images,tag):
if 'POPUP_DONE ' in s.log('owner'):
s.save(tag+'-input',dict(status='NOT_EXERCISED',reason='legitimate popup dismissal, no new chain reserved'));return
state=s.owner('owner');prot=validators.grab(s.log('owner'));geo=geometry(s.log('owner'),state['origin'],Provenance(state['owner']['id'],state['workspace']['id'],'NOT OBSERVABLE','mutation paint+pointer'))
index=next(i for i,o in enumerate(s.outputs) if o['name']==state['workspace']['output'])
try:point=solid_point(images[index],COLORS['POPUP_B'],s.outputs[index],s.frames[s.outputs[index]['name']],geo['B'])
except ValueError:
s.save(tag+'-input',dict(status='NOT_EXERCISED',reason='B has no measured visible interior'));return
tails,buttons=s.click('owner',point);s.delivery('owner',geo['B'],point,tails,buttons,'POPUP_B');s.save(tag+'-input',dict(status='PASS',point=point,protocol=prot))
def dynamic_geometry(snap,previous=None):
# WHY: scroll IPC alone does not demonstrate the resize clamp.
# CONTRACT: pinned arrange.c105-131 / mosaic.c125-153, zero inner gap,
# three direct tiled children; calloc row state has no minimum-width setter
# and uses640. Corroborate that minimum with every actual IPC child width.
# INVARIANT: this is a pending IPC candidate, never native applied geometry.
ws=workspace(snap['tree'],'1');row=ws['mosaic']['rows'][0]
children=ws['nodes'];ids=[c['id'] for c in children]
need(len(children)==3 and row['children']==ids,'dynamic direct row reconstruction')
viewport=[ws['rect'][k] for k in ('x','y','width','height')]
width=viewport[2];need(0<width<3*640,'dynamic minimum not distinguishable from fitting')
need(all(c['rect']['width']==640 for c in children),'actual minimum-width reconstruction')
need([c['rect']['x'] for c in children]==[viewport[0]+i*640 for i in range(3)],'actual zero-gap row reconstruction')
maximum=3*640-width;scroll=row['scroll_x'];need(0<=scroll<=maximum,'dynamic camera outside clamp')
result=dict(workspace_id=ws['id'],output=ws['output'],children=ids,viewport=viewport,
minimum_width=640,content_width=1920,max_scroll=maximum,scroll=scroll,
geometry_status='IPC_PENDING_CANDIDATE; native generation NOT OBSERVABLE')
if previous is not None:
need(ws['id']==previous['workspace_id'] and ids==previous['children'],'dynamic workspace/order changed')
expected=min(previous['scroll'],maximum)
need(scroll==expected,'reconstructed camera clamp mismatch')
result.update(expected_scroll=expected,clamp='PASS')
return result
def dynamic_pixels(images,outputs,frames,viewport,reference=None):
# WHY/CONTRACT: each mutation must reject old-output and outside-clip paint.
# INVARIANT: sampled RGB exclusion cannot prove complete native damage.
for image,out in zip(images,outputs):
for y in range(image.height):
for x in range(image.width):
if image.getpixel((x,y)) in (COLORS['POPUP_A'],COLORS['POPUP_B']):
need(contains(viewport,png_global((x,y),out,frames[out['name']])),'dynamic popup pixel outside current viewport')
if reference is not None:exact(reference,images[1])
return dict(exclusion='PASS',whole_H2='PASS' if reference is not None else 'NOT_APPLICABLE: current owner workspace on H2',complete_damage='NOT OBSERVABLE')
def dynamic_campaign(s):
init_reference(s,2);s.cmd('gaps inner 0');state,baseline,p,g,left,right=open_chain(s)
owner_id=state['owner']['id'];previous=dynamic_geometry(state['snapshot']);stages=[]
mutations=[('output HEADLESS-1 resolution 960x600 position -960 0','resized960','HEADLESS-1'),
('output HEADLESS-1 resolution 800x600 position -800 0','resized-back','HEADLESS-1'),
('move workspace to output HEADLESS-2','migrated-H2','HEADLESS-2'),
('move workspace to output HEADLESS-1','migrated-back-H1','HEADLESS-1')]
for command,tag,out in mutations:
s.cmd('workspace 1');s.cmd(command,True);s.expected_output=out
if tag=='resized960':s.outputs[0]={**s.outputs[0],'logical':[-960,0,960,600],'mode':[960,600]}
elif tag=='resized-back':s.outputs[0]=dict(s.spec['outputs'][0])
time.sleep(.35);snap=s.snapshot(tag);current=dynamic_geometry(snap,previous)
need(current['output']==out and s.find('owner')['id']==owner_id,'dynamic exact owner/output')
expected_viewport=next(o['logical'] for o in s.outputs if o['name']==out)
need(current['viewport']==expected_viewport,'dynamic viewport/output reconstruction')
pictures=s.pair_capture(tag)
pixels=dynamic_pixels(pictures,s.outputs,s.frames,current['viewport'],baseline if out=='HEADLESS-1' else None)
# An alive chain must supply fresh paint and local pointer input; an
# actual XDG dismissal is recorded without injecting on destroyed popups.
if 'POPUP_DONE ' not in s.log('owner'):
fresh=s.owner('owner');geo=geometry(s.log('owner'),fresh['origin'],Provenance(owner_id,current['workspace_id'],'NOT OBSERVABLE','fresh mutation IPC + paint + pointer'))
index=next(i for i,o in enumerate(s.outputs) if o['name']==out)
point=solid_point(pictures[index],COLORS['POPUP_B'],s.outputs[index],s.frames[out],geo['B'])
tails,buttons=s.click('owner',point);s.delivery('owner',geo['B'],point,tails,buttons,'POPUP_B')
need(validators.grab(s.log('owner'))['ids']==p['ids'],'dynamic popup IDs changed')
input_proof=dict(status='PASS',point=point)
else:input_proof=dict(status='NOT_EXERCISED',reason='XDG dismissal; no injection on destroyed popup')
stages.append(dict(tag=tag,geometry=current,pixels=pixels,input=input_proof));previous=current
s.save('dynamic-ownership',dict(status='PASS',stages=stages,ids_before=p['ids'],atomic_generation='NOT PROVEN',complete_damage='NOT OBSERVABLE'))
s.close_client('owner')
for name in list(s.proc):
if name.startswith('filler'):s.close_client(name,'close')
s.save('dynamic-final-limit',dict(status='NOT_TESTED',reason='14 capture cap used by opening and four fresh mutation states; no post-close capture'));return 'PARTIALLY_FEASIBLE'

View file

@ -0,0 +1,298 @@
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.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 <unistd.h>
#include <wayland-client.h>
#include "xdg-shell-client.h"
/* EXPERIMENTAL CONTRACT: every popup owns distinct XDG objects. B's actual
* parent is A's xdg_surface; logs name object IDs as well as colors. */
struct surface {
const char *name;
struct wl_surface *wl;
struct xdg_surface *xdg;
struct xdg_popup *popup;
bool configured, mapped, done;
int width, height, anchor_x, anchor_y;
uint32_t color;
};
static struct wl_display *display;
static struct wl_compositor *compositor;
static struct wl_shm *shm;
static struct xdg_wm_base *wm;
static struct wl_seat *seat;
static struct wl_pointer *pointer;
static struct xdg_toplevel *top_role;
static struct surface top = {.name="TOPLEVEL", .width=420, .height=320, .color=0x002344cc};
static struct surface a = {.name="POPUP_A", .width=300, .height=170, .color=0x00e0c020};
static struct surface b = {.name="POPUP_B", .width=300, .height=130, .color=0x0020d0a0};
static volatile sig_atomic_t running = 1;
static struct surface *entered;
/* Observe client-side SHM release separately from native GPU retirement.
* Keep protocol buffer alive until release; no backing memory is reused. */
static unsigned shm_created, shm_released;
static void buffer_release(void *data, struct wl_buffer *buffer) {
(void)data;
++shm_released;
fprintf(stderr,"SHM_RELEASE buffer=%u released=%u created=%u\n",
wl_proxy_get_id((struct wl_proxy *)buffer),shm_released,shm_created);
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {.release=buffer_release};
static void draw(struct surface *s) {
size_t bytes = (size_t)s->width * (size_t)s->height * 4;
char path[4096];
const char *scratch = getenv("TMPDIR");
const char *lab = getenv("SMX_LAB");
/* WHY: SHM belongs to LAB, never the short socket-only runtime.
* CONTRACT: launcher supplies canonical LAB/scratch; fail before mkstemp. */
char expected[4096];
int expected_len = lab ? snprintf(expected, sizeof(expected), "%s/scratch", lab) : -1;
int path_len = scratch ? snprintf(path, sizeof(path), "%s/smx-shm-XXXXXX", scratch) : -1;
if (!lab || strncmp(lab, "/var/tmp/", 9) || strstr(lab, "/../") ||
expected_len < 0 || expected_len >= (int)sizeof(expected) ||
!scratch || strcmp(scratch, expected) || path_len < 0 ||
path_len >= (int)sizeof(path)) {
fprintf(stderr, "invalid LAB scratch for SHM\n");
exit(1);
}
int fd = mkstemp(path);
if (fd < 0 || ftruncate(fd, (off_t)bytes) < 0) { perror("buffer"); exit(1); }
unlink(path);
uint32_t *pixels = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pixels == MAP_FAILED) { perror("mmap"); exit(1); }
for (size_t i=0; i<bytes/4; ++i) pixels[i] = s->color;
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int)bytes);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, s->width, s->height,
s->width*4, WL_SHM_FORMAT_XRGB8888);
++shm_created;
wl_buffer_add_listener(buffer,&buffer_listener,NULL);
wl_surface_attach(s->wl, buffer, 0, 0);
wl_surface_damage_buffer(s->wl, 0, 0, s->width, s->height);
wl_surface_commit(s->wl);
wl_shm_pool_destroy(pool);
munmap(pixels, bytes);
close(fd);
s->mapped = true;
fprintf(stderr, "%s MAP wl=%u xdg=%u\n", s->name,
wl_proxy_get_id((struct wl_proxy *)s->wl), wl_proxy_get_id((struct wl_proxy *)s->xdg));
}
static void on_ping(void *data, struct xdg_wm_base *base, uint32_t serial) {
xdg_wm_base_pong(base, serial);
}
static const struct xdg_wm_base_listener wm_listener = {.ping=on_ping};
static void on_xdg_configure(void *data, struct xdg_surface *xdg, uint32_t serial) {
struct surface *s=data;
fprintf(stderr, "%s XDG_CONFIGURE serial=%u ack\n", s->name, serial);
xdg_surface_ack_configure(xdg, serial);
s->configured=true;
if (!s->mapped && !s->done) draw(s);
}
static const struct xdg_surface_listener xdg_listener = {.configure=on_xdg_configure};
static void on_top_configure(void *data, struct xdg_toplevel *role, int32_t w,
int32_t h, struct wl_array *states) {
fprintf(stderr, "TOPLEVEL ROLE_CONFIGURE w=%d h=%d\n", w,h);
}
static void on_top_close(void *data, struct xdg_toplevel *role) {
fprintf(stderr, "TOPLEVEL CLOSE_REQUEST\n"); running=0;
}
static const struct xdg_toplevel_listener top_listener = {
.configure=on_top_configure, .close=on_top_close,
};
static void on_popup_configure(void *data, struct xdg_popup *role, int32_t x,
int32_t y, int32_t w, int32_t h) {
struct surface *s=data;
fprintf(stderr, "%s ROLE_CONFIGURE x=%d y=%d w=%d h=%d\n",s->name,x,y,w,h);
}
static void on_popup_done(void *data, struct xdg_popup *role) {
struct surface *s=data;
s->done=true;
s->mapped=false;
fprintf(stderr, "%s POPUP_DONE role=%u\n",s->name,wl_proxy_get_id((struct wl_proxy *)role));
}
static const struct xdg_popup_listener popup_listener = {
.configure=on_popup_configure, .popup_done=on_popup_done,
};
/* WHY: XDG requires child-first destruction even if the compositor sends
* dismissals for multiple levels in one dispatch batch. */
static void destroy_popup(struct surface *s) {
if (!s->popup) return;
fprintf(stderr,"%s DESTROY role=%u xdg=%u wl=%u\n",s->name,
wl_proxy_get_id((struct wl_proxy *)s->popup),
wl_proxy_get_id((struct wl_proxy *)s->xdg),
wl_proxy_get_id((struct wl_proxy *)s->wl));
xdg_popup_destroy(s->popup);
xdg_surface_destroy(s->xdg);
wl_surface_destroy(s->wl);
s->popup=NULL; s->xdg=NULL; s->wl=NULL; s->mapped=false;
if (entered==s) entered=NULL;
}
static void collect_dismissals(void) {
if (b.done) destroy_popup(&b);
if (a.done) {
destroy_popup(&b);
destroy_popup(&a);
}
}
static void open_popup(struct surface *s, struct surface *parent, uint32_t serial) {
if (s->popup || !parent->mapped || !serial) return;
s->wl=wl_compositor_create_surface(compositor);
s->xdg=xdg_wm_base_get_xdg_surface(wm,s->wl);
xdg_surface_add_listener(s->xdg,&xdg_listener,s);
struct xdg_positioner *pos=xdg_wm_base_create_positioner(wm);
xdg_positioner_set_size(pos,s->width,s->height);
xdg_positioner_set_anchor_rect(pos,s->anchor_x,s->anchor_y,1,1);
xdg_positioner_set_anchor(pos,XDG_POSITIONER_ANCHOR_TOP_LEFT);
xdg_positioner_set_gravity(pos,XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
s->popup=xdg_surface_get_popup(s->xdg,parent->xdg,pos);
xdg_popup_add_listener(s->popup,&popup_listener,s);
fprintf(stderr,"%s CREATE wl=%u xdg=%u role=%u parent=%s parent_xdg=%u\n",
s->name,wl_proxy_get_id((struct wl_proxy *)s->wl),
wl_proxy_get_id((struct wl_proxy *)s->xdg),
wl_proxy_get_id((struct wl_proxy *)s->popup),parent->name,
wl_proxy_get_id((struct wl_proxy *)parent->xdg));
fprintf(stderr,"%s GRAB_REQUEST origin=wl_pointer.button target=%s serial=%u used=%u\n",
s->name,parent->name,serial,serial);
xdg_popup_grab(s->popup,seat,serial);
wl_surface_commit(s->wl); /* Initial bufferless commit requests configure. */
xdg_positioner_destroy(pos);
}
static struct surface *which(struct wl_surface *wl) {
if (wl==top.wl) return &top;
if (wl==a.wl && wl) return &a;
if (wl==b.wl && wl) return &b;
return NULL;
}
static void on_enter(void *data,struct wl_pointer *ptr,uint32_t serial,
struct wl_surface *wl,wl_fixed_t x,wl_fixed_t y) {
entered=which(wl);
fprintf(stderr,"POINTER_ENTER target=%s wl=%u serial=%u x=%.2f y=%.2f\n",
entered?entered->name:"OTHER",wl_proxy_get_id((struct wl_proxy *)wl),serial,
wl_fixed_to_double(x),wl_fixed_to_double(y));
}
static void on_leave(void *data,struct wl_pointer *ptr,uint32_t serial,
struct wl_surface *wl) {
struct surface *s=which(wl);
fprintf(stderr,"POINTER_LEAVE target=%s serial=%u\n",s?s->name:"OTHER",serial);
if (entered==s) entered=NULL;
}
static void on_motion(void *data,struct wl_pointer *ptr,uint32_t time,
wl_fixed_t x,wl_fixed_t y) {
fprintf(stderr,"POINTER_MOTION target=%s x=%.2f y=%.2f\n",
entered?entered->name:"OTHER",wl_fixed_to_double(x),wl_fixed_to_double(y));
}
static void on_button(void *data,struct wl_pointer *ptr,uint32_t serial,
uint32_t time,uint32_t button,uint32_t state) {
fprintf(stderr,"POINTER_BUTTON target=%s serial=%u button=%u state=%u\n",
entered?entered->name:"OTHER",serial,button,state);
if (state!=WL_POINTER_BUTTON_STATE_PRESSED || button!=272) return;
if (entered==&top && !a.popup) open_popup(&a,&top,serial);
else if (entered==&a && a.mapped && !b.popup) open_popup(&b,&a,serial);
}
static void on_axis(void *data,struct wl_pointer *ptr,uint32_t t,uint32_t axis,wl_fixed_t v) {}
static void on_frame(void *data,struct wl_pointer *ptr) {}
static const struct wl_pointer_listener pointer_listener={
.enter=on_enter,.leave=on_leave,.motion=on_motion,.button=on_button,
.axis=on_axis,.frame=on_frame,
};
static void on_caps(void *data,struct wl_seat *s,uint32_t caps) {
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !pointer) {
pointer=wl_seat_get_pointer(s);
wl_pointer_add_listener(pointer,&pointer_listener,NULL);
}
}
static void on_seat_name(void *data,struct wl_seat *s,const char *name) {}
static const struct wl_seat_listener seat_listener={.capabilities=on_caps,.name=on_seat_name};
static void on_global(void *data,struct wl_registry *reg,uint32_t name,
const char *interface,uint32_t version) {
if (!strcmp(interface,wl_compositor_interface.name))
compositor=wl_registry_bind(reg,name,&wl_compositor_interface,version<4?version:4);
else if (!strcmp(interface,wl_shm_interface.name))
shm=wl_registry_bind(reg,name,&wl_shm_interface,1);
else if (!strcmp(interface,xdg_wm_base_interface.name))
wm=wl_registry_bind(reg,name,&xdg_wm_base_interface,version<3?version:3);
else if (!strcmp(interface,wl_seat_interface.name)) {
seat=wl_registry_bind(reg,name,&wl_seat_interface,version<5?version:5);
wl_seat_add_listener(seat,&seat_listener,NULL);
}
}
static void on_removed(void *data,struct wl_registry *reg,uint32_t name) {}
static const struct wl_registry_listener registry_listener={.global=on_global,.global_remove=on_removed};
static void stop(int sig) { running=0; }
int main(int argc,char **argv) {
signal(SIGTERM,stop);
const char *placement=argc>1?argv[1]:"b_cross";
/* EXPERIMENTAL: only placement changes; serial/grab/lifecycle stay historical.
* Both 1x1 anchors lie inside their parent SHM window geometry. */
if (!strcmp(placement,"static_cross")) {
a.anchor_x=100; a.anchor_y=80; a.width=350;
b.anchor_x=100; b.anchor_y=60; b.width=300;
} else if (!strcmp(placement,"visible")) {
a.anchor_x=50; a.anchor_y=80; a.width=250;
b.anchor_x=20; b.anchor_y=60; b.width=170;
} else if (!strcmp(placement,"both_cross")) {
a.anchor_x=350; a.anchor_y=80; a.width=350;
b.anchor_x=160; b.anchor_y=60; b.width=300;
} else if (!strcmp(placement,"b_cross")) {
a.anchor_x=200; a.anchor_y=80; a.width=300;
b.anchor_x=220; b.anchor_y=60; b.width=300;
} else { fprintf(stderr,"invalid placement\n"); return 2; }
display=wl_display_connect(NULL);
if (!display) { fprintf(stderr,"cannot connect Wayland\n"); return 1; }
struct wl_registry *registry=wl_display_get_registry(display);
wl_registry_add_listener(registry,&registry_listener,NULL);
wl_display_roundtrip(display); wl_display_roundtrip(display);
if (!compositor || !shm || !wm || !seat || !pointer) {
fprintf(stderr,"missing Wayland globals/pointer\n"); return 1;
}
xdg_wm_base_add_listener(wm,&wm_listener,NULL);
top.wl=wl_compositor_create_surface(compositor);
top.xdg=xdg_wm_base_get_xdg_surface(wm,top.wl);
xdg_surface_add_listener(top.xdg,&xdg_listener,&top);
top_role=xdg_surface_get_toplevel(top.xdg);
xdg_toplevel_add_listener(top_role,&top_listener,NULL);
xdg_toplevel_set_title(top_role,"Mosaic Nested Grab Probe");
xdg_toplevel_set_app_id(top_role,"org.mosaic.NestedGrabProbe");
fprintf(stderr,"TOPLEVEL CREATE wl=%u xdg=%u role=%u placement=%s\n",
wl_proxy_get_id((struct wl_proxy *)top.wl),
wl_proxy_get_id((struct wl_proxy *)top.xdg),
wl_proxy_get_id((struct wl_proxy *)top_role),placement);
wl_surface_commit(top.wl);
while (running) {
wl_display_flush(display);
struct pollfd fds[2]={{.fd=wl_display_get_fd(display),.events=POLLIN},
{.fd=STDIN_FILENO,.events=POLLIN}};
int ready=poll(fds,2,500);
if (ready<0) { if (errno==EINTR) continue; perror("poll"); break; }
if (fds[0].revents & (POLLIN|POLLERR|POLLHUP)) {
if (wl_display_dispatch(display)<0) break;
collect_dismissals();
}
if (fds[1].revents & POLLIN) {
char cmd[64];
if (fgets(cmd,sizeof(cmd),stdin)) {
if (!strncmp(cmd,"close_b",7)) { destroy_popup(&b); fprintf(stderr,"COMMAND close_b DONE\n"); }
else if (!strncmp(cmd,"close_owner",11)) { fprintf(stderr,"CLOSE_RECEIVED\nCOMMAND close_owner\n"); running=0; }
}
}
}
destroy_popup(&b); destroy_popup(&a);
fprintf(stderr,"TOPLEVEL DESTROY\n");
xdg_toplevel_destroy(top_role); xdg_surface_destroy(top.xdg); wl_surface_destroy(top.wl);
wl_display_roundtrip(display);
fprintf(stderr,"SHM_CLOSURE created=%u released=%u\n",shm_created,shm_released);
wl_display_flush(display);
/* WHY/CONTRACT/INVARIANT: exit0 does not prove protocol error0. */
fprintf(stderr,"EXIT error=%d\n",wl_display_get_error(display));
wl_display_disconnect(display);
return 0;
}

View file

@ -0,0 +1,57 @@
#define _DEFAULT_SOURCE
#include <linux/input-event-codes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-client.h>
#include "virtual-pointer-client.h"
static struct zwlr_virtual_pointer_manager_v1 *manager;
static void global(void *data, struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version) {
if (!strcmp(interface, zwlr_virtual_pointer_manager_v1_interface.name))
manager=wl_registry_bind(registry,name,&zwlr_virtual_pointer_manager_v1_interface,
version < 2 ? version : 2);
}
static void removed(void *data, struct wl_registry *registry, uint32_t name) {}
int main(void) {
struct wl_display *display=wl_display_connect(NULL);
if (!display) return 1;
struct wl_registry *registry=wl_display_get_registry(display);
struct wl_registry_listener listener={global,removed};
wl_registry_add_listener(registry,&listener,NULL);
wl_display_roundtrip(display);
if (!manager) return 2;
struct zwlr_virtual_pointer_v1 *pointer=
zwlr_virtual_pointer_manager_v1_create_virtual_pointer(manager,NULL);
wl_display_roundtrip(display);
fprintf(stderr,"POINTER_READY\n");fflush(stderr);
char line[128];
uint32_t stamp=1000;
while (fgets(line,sizeof(line),stdin)) {
char action[16];int x,y;
unsigned width,height;
if (sscanf(line,"%15s %d %d %u %u",action,&x,&y,&width,&height)!=5 || !width || !height || x<0 || y<0 || (unsigned)x>=width || (unsigned)y>=height || (strcmp(action,"move") && strcmp(action,"left") && strcmp(action,"right"))) return 3;
fprintf(stderr,"INJECT %s %d,%d\n",action,x,y);fflush(stderr);
zwlr_virtual_pointer_v1_motion_absolute(pointer,stamp++,x,y,width,height);
zwlr_virtual_pointer_v1_frame(pointer);
wl_display_flush(display);usleep(250000);
if (!strcmp(action,"left") || !strcmp(action,"right")) {
uint32_t button=!strcmp(action,"left") ? BTN_LEFT : BTN_RIGHT;
zwlr_virtual_pointer_v1_button(pointer,stamp++,button,WL_POINTER_BUTTON_STATE_PRESSED);
zwlr_virtual_pointer_v1_frame(pointer);
wl_display_flush(display);usleep(80000);
zwlr_virtual_pointer_v1_button(pointer,stamp++,button,WL_POINTER_BUTTON_STATE_RELEASED);
zwlr_virtual_pointer_v1_frame(pointer);
wl_display_flush(display);
}
wl_display_roundtrip(display);
fprintf(stderr,"INJECT_DONE %s %d,%d\n",action,x,y);fflush(stderr);
}
zwlr_virtual_pointer_v1_destroy(pointer);
zwlr_virtual_pointer_manager_v1_destroy(manager);
wl_registry_destroy(registry);
wl_display_disconnect(display);
return 0;
}

View file

@ -0,0 +1,253 @@
#define _POSIX_C_SOURCE 200809L
#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>
#include "xdg-shell-client.h"
/* WHY: the compositor must wait on a real, responsive XDG client.
* CONTRACT: hold only a received configure; ACK the latest received serial.
* INVARIANT: Wayland dispatch and ping replies continue while ACK is held. */
static struct wl_display *display;
static struct wl_compositor *compositor;
static struct wl_shm *shm;
static struct xdg_wm_base *wm;
static struct wl_surface *surface;
static struct xdg_surface *xdg;
static struct xdg_toplevel *toplevel;
static struct wl_seat *seat;
static struct wl_pointer *pointer;
static volatile sig_atomic_t running = 1;
static bool mapped, hold_next, held;
static uint32_t latest_serial;
static int32_t width = 420, height = 320, configured_width = 420, configured_height = 320;
static unsigned generation;
static long long stamp(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec;
}
/* Observe client-side SHM release separately from native GPU retirement.
* Keep protocol buffer alive until release; no backing memory is reused. */
static unsigned shm_created, shm_released;
static void buffer_release(void *data, struct wl_buffer *buffer) {
(void)data;
++shm_released;
fprintf(stderr,"SHM_RELEASE buffer=%u released=%u created=%u\n",
wl_proxy_get_id((struct wl_proxy *)buffer),shm_released,shm_created);
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {.release=buffer_release};
static void draw(void) {
if (configured_width > 0) width = configured_width;
if (configured_height > 0) height = configured_height;
if (width <= 0 || height <= 0 || width > 4096 || height > 4096) {
fprintf(stderr, "INVALID_SIZE %d %d\n", width, height);
exit(2);
}
size_t bytes = (size_t)width * (size_t)height * 4;
char name[4096];
const char *scratch = getenv("TMPDIR");
const char *lab = getenv("SMX_LAB");
/* WHY: SHM belongs to LAB, never the short socket-only runtime.
* CONTRACT: launcher supplies canonical LAB/scratch; fail before mkstemp. */
char expected[4096];
int expected_len = lab ? snprintf(expected, sizeof(expected), "%s/scratch", lab) : -1;
int path_len = scratch ? snprintf(name, sizeof(name), "%s/smx-shm-XXXXXX", scratch) : -1;
if (!lab || strncmp(lab, "/var/tmp/", 9) || strstr(lab, "/../") ||
expected_len < 0 || expected_len >= (int)sizeof(expected) ||
!scratch || strcmp(scratch, expected) || path_len < 0 ||
path_len >= (int)sizeof(name)) {
fprintf(stderr, "invalid LAB scratch for SHM\n");
exit(1);
}
int fd = mkstemp(name);
if (fd < 0 || ftruncate(fd, (off_t)bytes) < 0) { perror("shm"); exit(2); }
unlink(name);
uint32_t *pixels = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pixels == MAP_FAILED) { perror("mmap"); exit(2); }
uint32_t color = (generation++ % 2) ? 0x0020d0a0 : 0x002344cc;
#ifdef STATIC_REFERENCE
/* CONTRACT: H2 uses one opaque SHM color across every real configure. */
color = 0x00303038;
#endif
for (size_t i = 0; i < bytes / 4; ++i) pixels[i] = color;
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int)bytes);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height,
width * 4, WL_SHM_FORMAT_XRGB8888);
++shm_created;
wl_buffer_add_listener(buffer,&buffer_listener,NULL);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage_buffer(surface, 0, 0, width, height);
wl_surface_commit(surface);
fprintf(stderr, "COMMIT ns=%lld serial=%u size=%dx%d color=%08x\n",
stamp(), latest_serial, width, height, color);
wl_shm_pool_destroy(pool);
munmap(pixels, bytes);
close(fd);
mapped = true;
}
static void ack_and_commit(void) {
if (!latest_serial) return;
xdg_surface_ack_configure(xdg, latest_serial);
fprintf(stderr, "ACK ns=%lld serial=%u size=%dx%d\n",
stamp(), latest_serial, configured_width, configured_height);
draw();
held = false;
}
static void ping(void *data, struct xdg_wm_base *base, uint32_t serial) {
xdg_wm_base_pong(base, serial);
fprintf(stderr, "PONG ns=%lld serial=%u\n", stamp(), serial);
}
static const struct xdg_wm_base_listener wm_listener = {.ping = ping};
static void role_configure(void *data, struct xdg_toplevel *role,
int32_t w, int32_t h, struct wl_array *states) {
if (w > 0) configured_width = w;
if (h > 0) configured_height = h;
fprintf(stderr, "ROLE_CONFIGURE ns=%lld size=%dx%d\n", stamp(), w, h);
}
static void role_close(void *data, struct xdg_toplevel *role) { running = 0; }
static const struct xdg_toplevel_listener role_listener = {
.configure = role_configure, .close = role_close,
};
static void configure(void *data, struct xdg_surface *s, uint32_t serial) {
latest_serial = serial;
fprintf(stderr, "XDG_CONFIGURE ns=%lld serial=%u size=%dx%d hold=%d previous=%d\n",
stamp(), serial, configured_width, configured_height, hold_next || held, held);
if (hold_next || held) {
held = true;
hold_next = false;
fprintf(stderr, "HELD ns=%lld serial=%u\n", stamp(), serial);
} else {
ack_and_commit();
}
}
static const struct xdg_surface_listener surface_listener = {.configure = configure};
static void pointer_enter(void *data, struct wl_pointer *p, uint32_t serial,
struct wl_surface *s, wl_fixed_t x, wl_fixed_t y) {
fprintf(stderr, "ENTER ns=%lld x=%.2f y=%.2f\n", stamp(),
wl_fixed_to_double(x), wl_fixed_to_double(y));
}
static void pointer_leave(void *data, struct wl_pointer *p, uint32_t serial,
struct wl_surface *s) { fprintf(stderr, "LEAVE ns=%lld\n", stamp()); }
static void pointer_motion(void *data, struct wl_pointer *p, uint32_t time,
wl_fixed_t x, wl_fixed_t y) {
fprintf(stderr, "MOTION ns=%lld x=%.2f y=%.2f\n", stamp(),
wl_fixed_to_double(x), wl_fixed_to_double(y));
}
static void pointer_button(void *data, struct wl_pointer *p, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state) {
fprintf(stderr, "BUTTON ns=%lld serial=%u button=%u state=%u\n",
stamp(), serial, button, state);
}
static void pointer_axis(void *data, struct wl_pointer *p, uint32_t t,
uint32_t axis, wl_fixed_t value) {}
static void pointer_frame(void *data, struct wl_pointer *p) {}
static const struct wl_pointer_listener pointer_listener = {
.enter = pointer_enter, .leave = pointer_leave, .motion = pointer_motion,
.button = pointer_button, .axis = pointer_axis, .frame = pointer_frame,
};
static void capabilities(void *data, struct wl_seat *s, uint32_t caps) {
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !pointer) {
pointer = wl_seat_get_pointer(s);
wl_pointer_add_listener(pointer, &pointer_listener, NULL);
}
}
static void seat_name(void *data, struct wl_seat *s, const char *name) {}
static const struct wl_seat_listener seat_listener = {
.capabilities = capabilities, .name = seat_name,
};
static void global(void *data, struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version) {
if (!strcmp(interface, wl_compositor_interface.name))
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version < 4 ? version : 4);
else if (!strcmp(interface, wl_shm_interface.name))
shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
else if (!strcmp(interface, xdg_wm_base_interface.name))
wm = wl_registry_bind(registry, name, &xdg_wm_base_interface, version < 3 ? version : 3);
else if (!strcmp(interface, wl_seat_interface.name)) {
seat = wl_registry_bind(registry, name, &wl_seat_interface, version < 5 ? version : 5);
wl_seat_add_listener(seat, &seat_listener, NULL);
}
}
static void global_remove(void *data, struct wl_registry *registry, uint32_t name) {}
static const struct wl_registry_listener registry_listener = {
.global = global, .global_remove = global_remove,
};
static void stop(int signum) { running = 0; }
int main(void) {
signal(SIGTERM, stop);
display = wl_display_connect(NULL);
if (!display) { fprintf(stderr, "CONNECT_FAILED\n"); return 1; }
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_roundtrip(display);
wl_display_roundtrip(display);
if (!compositor || !shm || !wm) { fprintf(stderr, "MISSING_GLOBAL\n"); return 2; }
xdg_wm_base_add_listener(wm, &wm_listener, NULL);
surface = wl_compositor_create_surface(compositor);
xdg = xdg_wm_base_get_xdg_surface(wm, surface);
xdg_surface_add_listener(xdg, &surface_listener, NULL);
toplevel = xdg_surface_get_toplevel(xdg);
xdg_toplevel_add_listener(toplevel, &role_listener, NULL);
#ifdef STATIC_REFERENCE
xdg_toplevel_set_title(toplevel, "Mosaic Static Reference");
xdg_toplevel_set_app_id(toplevel, "org.mosaic.StaticReference");
#else
xdg_toplevel_set_title(toplevel, "Mosaic Saved Buffer Probe");
xdg_toplevel_set_app_id(toplevel, "org.mosaic.SavedBufferProbe");
#endif
wl_surface_commit(surface);
fprintf(stderr, "READY ns=%lld\n", stamp());
while (running) {
wl_display_flush(display);
struct pollfd fds[2] = {
{.fd = wl_display_get_fd(display), .events = POLLIN},
{.fd = STDIN_FILENO, .events = POLLIN},
};
int ready = poll(fds, 2, 100);
if (ready < 0) { if (errno == EINTR) continue; perror("poll"); 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;
if (!strncmp(cmd, "hold_next_configure", 19)) {
hold_next = true;
fprintf(stderr, "COMMAND hold_next_configure DONE ns=%lld\n", stamp());
} else if (!strncmp(cmd, "release_configure", 17)) {
if (held) ack_and_commit();
fprintf(stderr, "COMMAND release_configure DONE ns=%lld\n", stamp());
} else if (!strncmp(cmd, "close", 5)) {
fprintf(stderr,"CLOSE_RECEIVED\n");
running = 0;
fprintf(stderr, "COMMAND close DONE ns=%lld\n", stamp());
}
}
}
fprintf(stderr, "EXIT ns=%lld mapped=%d held=%d error=%d\n",
stamp(), mapped, held, wl_display_get_error(display));
xdg_toplevel_destroy(toplevel);
xdg_surface_destroy(xdg);
wl_surface_destroy(surface);
wl_display_roundtrip(display);
fprintf(stderr,"SHM_CLOSURE created=%u released=%u\n",shm_created,shm_released);
wl_display_flush(display);
wl_display_disconnect(display);
return 0;
}

View file

@ -0,0 +1,5 @@
/* WHY: a deterministic H2 reference cannot contain Kitty's blinking cursor.
* CONTRACT: use the same real XDG configure/ACK loop with fixed opaque SHM.
* INVARIANT: once configured and stable, this client changes no pixels. */
#define STATIC_REFERENCE 1
#include "saved-client.c"

View file

@ -0,0 +1,308 @@
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.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 <unistd.h>
#include <wayland-client.h>
#include "xdg-shell-client.h"
/* EXPERIMENTAL CONTRACT: every popup owns distinct XDG objects. B's actual
* parent is A's xdg_surface; logs name object IDs as well as colors. */
struct surface {
const char *name;
struct wl_surface *wl;
struct xdg_surface *xdg;
struct xdg_popup *popup;
bool configured, mapped, done;
int width, height, anchor_x, anchor_y;
uint32_t color;
};
static struct wl_display *display;
static struct wl_compositor *compositor;
static struct wl_shm *shm;
static struct xdg_wm_base *wm;
static struct wl_seat *seat;
static struct wl_pointer *pointer;
static struct xdg_toplevel *top_role;
static struct surface top = {.name="TOPLEVEL", .width=420, .height=320, .color=0x002344cc};
static struct surface a = {.name="POPUP_A", .width=300, .height=170, .color=0x00e0c020};
static struct surface b = {.name="POPUP_B", .width=300, .height=130, .color=0x0020d0a0};
static volatile sig_atomic_t running = 1;
static struct surface *entered;
/* Observe client-side SHM release separately from native GPU retirement.
* Keep protocol buffer alive until release; no backing memory is reused. */
static unsigned shm_created, shm_released;
static void buffer_release(void *data, struct wl_buffer *buffer) {
(void)data;
++shm_released;
fprintf(stderr,"SHM_RELEASE buffer=%u released=%u created=%u\n",
wl_proxy_get_id((struct wl_proxy *)buffer),shm_released,shm_created);
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {.release=buffer_release};
static void draw(struct surface *s) {
size_t bytes = (size_t)s->width * (size_t)s->height * 4;
char path[4096];
const char *scratch = getenv("TMPDIR");
const char *lab = getenv("SMX_LAB");
/* WHY: SHM belongs to LAB, never the short socket-only runtime.
* CONTRACT: launcher supplies canonical LAB/scratch; fail before mkstemp. */
char expected[4096];
int expected_len = lab ? snprintf(expected, sizeof(expected), "%s/scratch", lab) : -1;
int path_len = scratch ? snprintf(path, sizeof(path), "%s/smx-shm-XXXXXX", scratch) : -1;
if (!lab || strncmp(lab, "/var/tmp/", 9) || strstr(lab, "/../") ||
expected_len < 0 || expected_len >= (int)sizeof(expected) ||
!scratch || strcmp(scratch, expected) || path_len < 0 ||
path_len >= (int)sizeof(path)) {
fprintf(stderr, "invalid LAB scratch for SHM\n");
exit(1);
}
int fd = mkstemp(path);
if (fd < 0 || ftruncate(fd, (off_t)bytes) < 0) { perror("buffer"); exit(1); }
unlink(path);
uint32_t *pixels = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pixels == MAP_FAILED) { perror("mmap"); exit(1); }
for (size_t i=0; i<bytes/4; ++i) pixels[i] = s->color;
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int)bytes);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, s->width, s->height,
s->width*4, WL_SHM_FORMAT_XRGB8888);
++shm_created;
wl_buffer_add_listener(buffer,&buffer_listener,NULL);
wl_surface_attach(s->wl, buffer, 0, 0);
wl_surface_damage_buffer(s->wl, 0, 0, s->width, s->height);
wl_surface_commit(s->wl);
wl_shm_pool_destroy(pool);
munmap(pixels, bytes);
close(fd);
s->mapped = true;
fprintf(stderr, "%s MAP wl=%u xdg=%u\n", s->name,
wl_proxy_get_id((struct wl_proxy *)s->wl), wl_proxy_get_id((struct wl_proxy *)s->xdg));
}
static void on_ping(void *data, struct xdg_wm_base *base, uint32_t serial) {
xdg_wm_base_pong(base, serial);
}
static const struct xdg_wm_base_listener wm_listener = {.ping=on_ping};
static void on_xdg_configure(void *data, struct xdg_surface *xdg, uint32_t serial) {
struct surface *s=data;
fprintf(stderr, "%s XDG_CONFIGURE serial=%u ack\n", s->name, serial);
xdg_surface_ack_configure(xdg, serial);
s->configured=true;
if (!s->mapped && !s->done) draw(s);
}
static const struct xdg_surface_listener xdg_listener = {.configure=on_xdg_configure};
static void on_top_configure(void *data, struct xdg_toplevel *role, int32_t w,
int32_t h, struct wl_array *states) {
fprintf(stderr, "TOPLEVEL ROLE_CONFIGURE w=%d h=%d\n", w,h);
}
static void on_top_close(void *data, struct xdg_toplevel *role) {
fprintf(stderr, "TOPLEVEL CLOSE_REQUEST\n"); running=0;
}
static const struct xdg_toplevel_listener top_listener = {
.configure=on_top_configure, .close=on_top_close,
};
static void on_popup_configure(void *data, struct xdg_popup *role, int32_t x,
int32_t y, int32_t w, int32_t h) {
struct surface *s=data;
fprintf(stderr, "%s ROLE_CONFIGURE x=%d y=%d w=%d h=%d\n",s->name,x,y,w,h);
}
static void on_popup_done(void *data, struct xdg_popup *role) {
struct surface *s=data;
s->done=true;
s->mapped=false;
fprintf(stderr, "%s POPUP_DONE role=%u\n",s->name,wl_proxy_get_id((struct wl_proxy *)role));
}
static const struct xdg_popup_listener popup_listener = {
.configure=on_popup_configure, .popup_done=on_popup_done,
};
/* WHY: XDG requires child-first destruction even if the compositor sends
* dismissals for multiple levels in one dispatch batch. */
static void destroy_popup(struct surface *s) {
if (!s->popup) return;
fprintf(stderr,"%s DESTROY role=%u xdg=%u wl=%u\n",s->name,
wl_proxy_get_id((struct wl_proxy *)s->popup),
wl_proxy_get_id((struct wl_proxy *)s->xdg),
wl_proxy_get_id((struct wl_proxy *)s->wl));
xdg_popup_destroy(s->popup);
xdg_surface_destroy(s->xdg);
wl_surface_destroy(s->wl);
s->popup=NULL; s->xdg=NULL; s->wl=NULL; s->mapped=false;
if (entered==s) entered=NULL;
}
static void collect_dismissals(void) {
if (b.done) destroy_popup(&b);
if (a.done) {
destroy_popup(&b);
destroy_popup(&a);
}
}
static void open_popup(struct surface *s, struct surface *parent, uint32_t serial) {
if (s->popup || !parent->mapped || !serial) return;
s->wl=wl_compositor_create_surface(compositor);
s->xdg=xdg_wm_base_get_xdg_surface(wm,s->wl);
xdg_surface_add_listener(s->xdg,&xdg_listener,s);
struct xdg_positioner *pos=xdg_wm_base_create_positioner(wm);
xdg_positioner_set_size(pos,s->width,s->height);
xdg_positioner_set_anchor_rect(pos,s->anchor_x,s->anchor_y,1,1);
xdg_positioner_set_anchor(pos,XDG_POSITIONER_ANCHOR_TOP_LEFT);
xdg_positioner_set_gravity(pos,XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
s->popup=xdg_surface_get_popup(s->xdg,parent->xdg,pos);
xdg_popup_add_listener(s->popup,&popup_listener,s);
fprintf(stderr,"%s CREATE wl=%u xdg=%u role=%u parent=%s parent_xdg=%u\n",
s->name,wl_proxy_get_id((struct wl_proxy *)s->wl),
wl_proxy_get_id((struct wl_proxy *)s->xdg),
wl_proxy_get_id((struct wl_proxy *)s->popup),parent->name,
wl_proxy_get_id((struct wl_proxy *)parent->xdg));
fprintf(stderr,"%s GRAB_REQUEST origin=wl_pointer.button target=%s serial=%u used=%u\n",
s->name,parent->name,serial,serial);
xdg_popup_grab(s->popup,seat,serial);
wl_surface_commit(s->wl); /* Initial bufferless commit requests configure. */
xdg_positioner_destroy(pos);
}
static struct surface *which(struct wl_surface *wl) {
if (wl==top.wl) return &top;
if (wl==a.wl && wl) return &a;
if (wl==b.wl && wl) return &b;
return NULL;
}
static void on_enter(void *data,struct wl_pointer *ptr,uint32_t serial,
struct wl_surface *wl,wl_fixed_t x,wl_fixed_t y) {
entered=which(wl);
fprintf(stderr,"POINTER_ENTER target=%s wl=%u serial=%u x=%.2f y=%.2f\n",
entered?entered->name:"OTHER",wl_proxy_get_id((struct wl_proxy *)wl),serial,
wl_fixed_to_double(x),wl_fixed_to_double(y));
}
static void on_leave(void *data,struct wl_pointer *ptr,uint32_t serial,
struct wl_surface *wl) {
struct surface *s=which(wl);
fprintf(stderr,"POINTER_LEAVE target=%s serial=%u\n",s?s->name:"OTHER",serial);
if (entered==s) entered=NULL;
}
static void on_motion(void *data,struct wl_pointer *ptr,uint32_t time,
wl_fixed_t x,wl_fixed_t y) {
fprintf(stderr,"POINTER_MOTION target=%s x=%.2f y=%.2f\n",
entered?entered->name:"OTHER",wl_fixed_to_double(x),wl_fixed_to_double(y));
}
static void on_button(void *data,struct wl_pointer *ptr,uint32_t serial,
uint32_t time,uint32_t button,uint32_t state) {
fprintf(stderr,"POINTER_BUTTON target=%s serial=%u button=%u state=%u\n",
entered?entered->name:"OTHER",serial,button,state);
if (state!=WL_POINTER_BUTTON_STATE_PRESSED || button!=272) return;
if (entered==&top && !a.popup) open_popup(&a,&top,serial);
else if (entered==&a && a.mapped && !b.popup) open_popup(&b,&a,serial);
}
static void on_axis(void *data,struct wl_pointer *ptr,uint32_t t,uint32_t axis,wl_fixed_t v) {}
static void on_frame(void *data,struct wl_pointer *ptr) {}
static const struct wl_pointer_listener pointer_listener={
.enter=on_enter,.leave=on_leave,.motion=on_motion,.button=on_button,
.axis=on_axis,.frame=on_frame,
};
static void on_caps(void *data,struct wl_seat *s,uint32_t caps) {
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !pointer) {
pointer=wl_seat_get_pointer(s);
wl_pointer_add_listener(pointer,&pointer_listener,NULL);
}
}
static void on_seat_name(void *data,struct wl_seat *s,const char *name) {}
static const struct wl_seat_listener seat_listener={.capabilities=on_caps,.name=on_seat_name};
static void on_global(void *data,struct wl_registry *reg,uint32_t name,
const char *interface,uint32_t version) {
if (!strcmp(interface,wl_compositor_interface.name))
compositor=wl_registry_bind(reg,name,&wl_compositor_interface,version<4?version:4);
else if (!strcmp(interface,wl_shm_interface.name))
shm=wl_registry_bind(reg,name,&wl_shm_interface,1);
else if (!strcmp(interface,xdg_wm_base_interface.name))
wm=wl_registry_bind(reg,name,&xdg_wm_base_interface,version<3?version:3);
else if (!strcmp(interface,wl_seat_interface.name)) {
seat=wl_registry_bind(reg,name,&wl_seat_interface,version<5?version:5);
wl_seat_add_listener(seat,&seat_listener,NULL);
}
}
static void on_removed(void *data,struct wl_registry *reg,uint32_t name) {}
static const struct wl_registry_listener registry_listener={.global=on_global,.global_remove=on_removed};
static void stop(int sig) { running=0; }
int main(int argc,char **argv) {
signal(SIGTERM,stop);
const char *placement=argc>1?argv[1]:"b_cross";
/* CONTRACT: vertical positioner anchors remain inside the toplevel's
* effective window geometry, which defaults to its buffer bounds. */
if (!strncmp(placement,"v_",2)) top.height=575;
if (!strcmp(placement,"visible")) {
a.anchor_x=50; a.anchor_y=80; a.width=250;
b.anchor_x=20; b.anchor_y=60; b.width=170;
} else if (!strcmp(placement,"v_visible")) {
a.anchor_x=50; a.anchor_y=80; a.width=250;
b.anchor_x=20; b.anchor_y=60; b.width=170;
} else if (!strcmp(placement,"v_b_cross")) {
/* WHY: only B's requested rectangle reaches below y=600 when the
* tiled toplevel content begins near y=25. Configure and pixels
* remain the authority for the actual crossing. */
a.anchor_x=50; a.anchor_y=350; a.width=250;
b.anchor_x=20; b.anchor_y=155; b.width=170;
} else if (!strcmp(placement,"v_both_cross")) {
a.anchor_x=50; a.anchor_y=480; a.width=250;
b.anchor_x=20; b.anchor_y=80; b.width=170;
} else if (!strcmp(placement,"both_cross")) {
a.anchor_x=350; a.anchor_y=80; a.width=350;
b.anchor_x=160; b.anchor_y=60; b.width=300;
} else if (!strcmp(placement,"b_cross")) {
a.anchor_x=200; a.anchor_y=80; a.width=300;
b.anchor_x=220; b.anchor_y=60; b.width=300;
} else { fprintf(stderr,"invalid placement\n"); return 2; }
display=wl_display_connect(NULL);
if (!display) { fprintf(stderr,"cannot connect Wayland\n"); return 1; }
struct wl_registry *registry=wl_display_get_registry(display);
wl_registry_add_listener(registry,&registry_listener,NULL);
wl_display_roundtrip(display); wl_display_roundtrip(display);
if (!compositor || !shm || !wm || !seat || !pointer) {
fprintf(stderr,"missing Wayland globals/pointer\n"); return 1;
}
xdg_wm_base_add_listener(wm,&wm_listener,NULL);
top.wl=wl_compositor_create_surface(compositor);
top.xdg=xdg_wm_base_get_xdg_surface(wm,top.wl);
xdg_surface_add_listener(top.xdg,&xdg_listener,&top);
top_role=xdg_surface_get_toplevel(top.xdg);
xdg_toplevel_add_listener(top_role,&top_listener,NULL);
xdg_toplevel_set_title(top_role,"Mosaic Nested Grab Probe");
xdg_toplevel_set_app_id(top_role,"org.mosaic.NestedGrabProbe");
fprintf(stderr,"TOPLEVEL CREATE wl=%u xdg=%u role=%u placement=%s\n",
wl_proxy_get_id((struct wl_proxy *)top.wl),
wl_proxy_get_id((struct wl_proxy *)top.xdg),
wl_proxy_get_id((struct wl_proxy *)top_role),placement);
wl_surface_commit(top.wl);
while (running) {
wl_display_flush(display);
struct pollfd fds[2]={{.fd=wl_display_get_fd(display),.events=POLLIN},
{.fd=STDIN_FILENO,.events=POLLIN}};
int ready=poll(fds,2,500);
if (ready<0) { if (errno==EINTR) continue; perror("poll"); break; }
if (fds[0].revents & (POLLIN|POLLERR|POLLHUP)) {
if (wl_display_dispatch(display)<0) break;
collect_dismissals();
}
if (fds[1].revents & POLLIN) {
char cmd[64];
if (fgets(cmd,sizeof(cmd),stdin)) {
if (!strncmp(cmd,"close_b",7)) { destroy_popup(&b); fprintf(stderr,"COMMAND close_b DONE\n"); }
else if (!strncmp(cmd,"close_owner",11)) { fprintf(stderr,"CLOSE_RECEIVED\nCOMMAND close_owner\n"); running=0; }
}
}
}
destroy_popup(&b); destroy_popup(&a);
fprintf(stderr,"TOPLEVEL DESTROY\n");
xdg_toplevel_destroy(top_role); xdg_surface_destroy(top.xdg); wl_surface_destroy(top.wl);
wl_display_roundtrip(display);
fprintf(stderr,"SHM_CLOSURE created=%u released=%u\n",shm_created,shm_released);
wl_display_flush(display);
/* WHY/CONTRACT/INVARIANT: exit0 does not prove protocol error0. */
fprintf(stderr,"EXIT error=%d\n",wl_display_get_error(display));
wl_display_disconnect(display);
return 0;
}

View file

@ -0,0 +1,275 @@
"""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 sha,clean_environment,Ledger,canonical_lab
import sys
from ipc_predicates import nodes,workspace
from predicates import protocol,geometry,pair,dismissal
import validators
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):
need(not auth.get('offline'), 'OFFLINE_TEST_ONLY cannot launch');self.spec=spec;self.auth=auth;self.lab=canonical_lab(auth['lab']);self.ledger=Ledger(self.lab);self.folder=self.lab/'graphics-runs'/spec['id'];self.run=self.folder/'run';self.run.mkdir(parents=True)
need(os.statvfs('/tmp').f_bavail*os.statvfs('/tmp').f_frsize>=256*1024*1024,'runtime /tmp free space');self.runtime=Path(tempfile.mkdtemp(prefix='smx-',dir='/tmp'));self.runtime.chmod(0o700)
self.env=clean_environment(self.lab);self.env.update(XDG_RUNTIME_DIR=str(self.runtime),WLR_BACKENDS='headless',WLR_HEADLESS_OUTPUTS='2')
self.outputs=[dict(o) for o in spec['outputs']];self.frames={o['name']:'logical' for o in self.outputs}
self.proc_lock=threading.RLock();self.proc={};self.closed=[];self.helper_exits=[];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['id'] in ('C3','C4'):
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)
need(cfg==self.spec['config'],'sealed config bytes');(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=5000'] if spec['id']=='C6' 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() and sha(Path(f'/proc/{self.comp.pid}/exe'))==auth['binary_sha256'],'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['binary']=='core':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.save('runtime-identity',dict(pid=self.comp.pid,executable=str(Path(f'/proc/{self.comp.pid}/exe').resolve()),binary_sha256=sha(Path(f'/proc/{self.comp.pid}/exe')),wlroots=[dict(path=str(p),sha256=sha(p)) for p in wl],renderer=render,egl=[line for line in self.log('compositor').splitlines() if 'EGL' in line],egl_source='compositor startup log; NOT_OBSERVABLE if empty',source_manifest=self.auth['manifest_sha256']));self.record('actual-renderer',lines=render);self.snapshot('startup')
if spec['id'] in ('C3','C4'):
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.close_helper('marker-background')
self.pointer=self.spawn('pointer',[self.lab/'graphics-tests/client-build/pointer-daemon']);self.wait(lambda:'POINTER_READY' in self.log('pointer'))
def close_helper(self,name):
# WHY: swaybg is a calibration helper, not an XDG SHM test client.
# CONTRACT: retire its owned group after the marker screenshot; retain
# raw status separately. Never reinterpret SIGTERM as scientific close.
need(name=='marker-background','unknown helper role');p=self.proc[name]
if p.poll() is None:
try:os.killpg(p.pid,signal.SIGTERM)
except ProcessLookupError:pass
code=p.wait(timeout=2)
proof=dict(name=name,pid=p.pid,exit=code,expected_termination='owned helper SIGTERM after calibration',scientific_client=False)
self.helper_exits.append(proof);self.record('helper-exit',**proof)
need(code in (0,-signal.SIGTERM),'unexpected calibration helper exit')
need(not Path('/proc',str(p.pid)).exists(),'calibration helper residual')
if p.stdin and not p.stdin.closed:p.stdin.close()
del self.proc[name]
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):self.ledger.action_debit(self.auth,*kinds)
def spawn(self,name,argv,debug=False):
self.debit('spawn');need(not self.expired,'expired before spawn');f=(self.run/(name+'.log')).open('w');self.handles.append(f)
requested_argv=list(map(str,argv));prlimit=shutil.which('prlimit')
need(prlimit is not None,'util-linux prlimit unavailable; refusing unbounded child')
# WHY: a child core dump can exhaust the bounded graphics LAB.
# CONTRACT: every owned child starts with a zero soft and hard core limit.
# INVARIANT: exec keeps the child PID stable for /proc identity checks.
actual_argv=[prlimit,'--core=0:0','--',*requested_argv]
# WHY/CONTRACT/INVARIANT: registration and expiry are atomic: no child
# can escape the watchdog's owned-group snapshot by racing its deadline.
with getattr(self,'proc_lock',threading.RLock()):
need(not self.expired,'expired before process creation')
p=subprocess.Popen(actual_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,requested_argv=requested_argv,actual_argv=actual_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 remaining(self,deadline=146):
return max(.001,self.started+deadline-time.monotonic())
def signal_owned(self,sig):
with getattr(self,'proc_lock',threading.RLock()):
for p in list(self.proc.values()):
try:os.killpg(p.pid,sig)
except ProcessLookupError:pass
def watchdog(self):
# WHY: main-thread protocol closure may block or fail.
# CONTRACT: autonomous TERM at143, KILL by146, below150s/run.
# INVARIANT: only registered private session groups are signalled;
# the main cleanup shares this absolute deadline, never N grace periods.
while not self.finished.wait(.02):
if time.monotonic()>=self.started+143 or any(p.stat().st_size>32*1024*1024 for p in self.run.glob('*.log')):
with getattr(self,'proc_lock',threading.RLock()):self.expired=True
self.signal_owned(signal.SIGTERM)
grace_end=min(self.started+146,time.monotonic()+2)
if not self.finished.wait(max(0,grace_end-time.monotonic())):
self.signal_owned(signal.SIGKILL)
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.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/'graphics-tests/client-build'/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)
validators.window(t,time.monotonic_ns(),[e['ns'] for e in self.events if e['kind']=='injection' and e['ns']>=t]);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]));validators.applied(rect[:2],rect[:2],[point[0]-local[0],point[1]-local[1]],'applied')
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')
rows=[n for n in nodes(snap['tree']) if n.get('pid')==self.proc[name].pid]
need(len(rows)==1,'owner identity/ambiguity');owner=rows[0]
ws=workspace(snap['tree'],'1')
path=__import__('ipc_predicates').ancestry(snap['tree'],owner['id'])
validators.owner_context(owner,path,self.proc[name].pid,'1',getattr(self,'expected_output','HEADLESS-1'),getattr(self,'expected_layout','mosaic' if self.spec['mode']=='mosaic' else 'splith'))
# WHY: standard_return changes layout after the initial campaign mode.
# CONTRACT: camera applies only to current Mosaic tiled descendants;
# floating branches and fullscreen group ancestry remain exempt.
# WHY/CONTRACT: root/output/workspace IPC descriptors may have floating=null.
# INVARIANT: null means no floating flag; branch membership still counts,
# and this geometry remains a pending candidate, never native-applied.
eligible=validators.camera_eligible(path,ws)
origin=assigned_origin(owner);scene=exterior_ipc(owner)
if eligible:
scroll=int(ws['mosaic']['rows'][0]['scroll_x']);origin[0]-=scroll;scene[0]-=scroll
# INVARIANT: IPC never becomes native-applied without fresh paint and pointer corroboration.
raw='current-layout IPC candidate; native paint and fresh pointer-local corroboration required, generation NOT OBSERVABLE'
data=dict(geometry_status='IPC_PENDING_CANDIDATE; requires fresh paint/pointer after every mutation',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.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'):
# WHY: exit0 alone cannot prove SHM release or an explicit normal close.
# CONTRACT: retain each PID's validation, including retired same-name owners.
# INVARIANT: a failed closure is durable evidence, never laundered by cleanup.
p=self.proc[name];proof=dict(name=name,pid=p.pid,status='INCONCLUSIVE',failure=None)
try:
if p.poll() is None:self.client_cmd(name,command)
code=p.wait(timeout=min(3,self.remaining()));raw=self.log(name)
archive=self.run/f'{name}-closed-{p.pid}.log';archive.write_text(raw)
proof.update(exit=code,log=str(archive),sha256=sha(archive),close_received='CLOSE_RECEIVED' in raw,shm_closure=re.findall(r'SHM_CLOSURE created=(\d+) released=(\d+)',raw),wayland_errors=re.findall(r'EXIT[^\n]*error=(\d+)',raw))
validators.client_exit(raw,code);self.wait(lambda:self.find(name) is None)
proof['status']='PASS'
except Exception as error:
proof['failure']=f'{type(error).__name__}: {error}'
proof.setdefault('exit',p.poll())
raise
finally:
self.closed.append(proof);self.record('client-closed',**proof)
def cleanup(self,measurement_status,failure=None):
terminal=None;rescue=False;closures=[]
# Close test clients while their Wayland server still exists. Mechanical
# rescue and terminal IPC can never substitute for scientific closure.
for name in reversed(list(self.proc)):
if name in ('compositor','pointer') or any(c['pid']==self.proc[name].pid for c in self.closed):continue
if self.expired or time.monotonic()>=self.started+143:break
try:
self.close_client(name,'close_owner' if name=='owner' and self.spec['client']!='saved-client' and self.spec['id']!='C6' else 'close')
except Exception:pass # close_client retains the explicit validation failure.
# WHY/CONTRACT/INVARIANT: archived and already-exited clients count equally;
# an empty list of newly closed processes must not erase prior failures.
closures=[dict(c) for c in self.closed]
tracked=[p.pid for n,p in self.proc.items() if n not in ('compositor','pointer')]
closure_coverage=all(any(c['pid']==pid for c in closures) for pid in tracked)
if hasattr(self,'comp') and self.comp.poll() is None and hasattr(self,'sock') and self.sock.is_socket() and not self.expired and time.monotonic()<self.started+145:
try:
self.debit('configuration')
p=subprocess.run(['swaymsg','-s',str(self.sock),'exit'],env=self.env,capture_output=True,text=True,timeout=min(2,self.remaining()))
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=min(1,self.remaining()))
except Exception as e:
terminal['wait_error']=str(e);self.save('terminal-ipc',terminal)
codes=[dict(name=c['name'],pid=c['pid'],exit=c['exit']) for c in self.closed if not any(p.pid==c['pid'] for p in self.proc.values())]
# One shared cleanup deadline prevents N owned clients multiplying waits.
cleanup_end=min(self.started+146,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=min(self.started+147,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(closure_coverage and all(c['status']=='PASS' for c in closures) and 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') in (0,1) and 'wait_error' not in terminal and 'ipc_error' not in terminal
final_status=measurement_status if failure is None and cleanup_pass and transport_pass else 'INCONCLUSIVE'
self.save('outcome',dict(status=final_status,measurements_pass=measurement_status,architecture_verdict='INCONCLUSIVE',evidence_provenance=self.auth,untested_matrix_cells=['ATOMIC_GENERATION','COMPLETE_DAMAGE','NATIVE_BUFFER_IDENTITY','GPU_LIFETIME'],scientific_cleanup='PASS' if cleanup_pass else 'INCONCLUSIVE',runtime_exit=codes,measurements_status=measurement_status,failure=failure,terminal=terminal,helper_exits=getattr(self,'helper_exits',[]),explicit_client_closures=self.closed,mechanical_cleanup='PASS' if reaped and not rescue and not self.runtime.exists() else 'INCONCLUSIVE',client_closures=closures,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'))
self.ledger.complete(self.auth,dict(status=final_status,runner_failure=failure,terminal=terminal,processes=codes,scientific_cleanup=cleanup_pass,mechanical_rescue=rescue));return final_status

View file

@ -0,0 +1,29 @@
"""Mandatory raw evidence validators; declarations never synthesize native facts."""
from gate import need
from validators import fullscreen_ancestor
def fullscreen_certificate(pristine,core):
# Offline-only certificate: no calibration client or full-screen run is started.
for record in (pristine,core):
ancestor=fullscreen_ancestor(record["owner_path"])
need(record["native_xdg"] is True and record["configure_ack"]>0,"normal XDG configure/ACK")
children=ancestor["nodes"]
need(len(children)>=2 and record["owner_id"] in {x["id"] for x in children},"nonleaf direct children")
need(record["configure"][0]>0 and record["configure"][1]>0,"configure dimensions")
a,b=record["popup_A"],record["popup_B"]
need(a[0]<record["boundary"]<a[0]+a[2] and b[0]<record["boundary"]<b[0]+b[2],"real plausible crossing")
need(pristine["configure"]==core["configure"] and pristine["child_configures"]==core["child_configures"],"noncomparable fullscreen children/configure")
return dict(status="OFFLINE_CERTIFICATE_ONLY",runtime="NOT_RUN")
def native_present(commits,presents):
# Correlation requires an actual native event and exact run/output/sequence key.
keys=set()
for event in commits:
need(event.get("source")=="native-output-commit" and event.get("native_event") is True,"fake commit")
key=(event["run"],event["output"],event["commit_seq"]);need(key not in keys,"duplicate commit key");keys.add(key)
seen=set()
for event in presents:
need(event.get("source")=="native-output-present" and event.get("native_event") is True,"fake present")
key=(event["run"],event["output"],event["commit_seq"])
need(key in keys and key not in seen,"unmatched/duplicate native present");seen.add(key)
return dict(matched=len(seen),unmatched_commits=len(keys-seen),gpu_completion="NOT_PROVEN",native_buffer_identity="NOT_PROVEN",atomic_generation="NOT_PROVEN")

View file

@ -0,0 +1,15 @@
#!/usr/bin/env python3
"""Freeze source-only bytes. No ledger initialization/admission/reservation."""
import argparse
from pathlib import Path
from gate import canonical_lab,sha,durable,TICKET
from plans import RUNS,LIMITS
def freeze(lab):
lab=canonical_lab(lab);root=Path(__file__).resolve().parent
files={str(p.relative_to(root)):sha(p) for p in sorted(root.rglob("*")) if p.is_file()}
if any(name.endswith((".pyc",".png",".so",".o")) or "__pycache__" in name for name in files):raise ValueError("generated artifact in source kit")
result=dict(schema="graphics-v2-source-freeze",ticket=TICKET,source_root=str(root),files=files,plans=RUNS,limits=LIMITS,preflight="PENDING_INDEPENDENT_REVIEW",runtime="NOT_RUN",real_reservations=0)
durable(lab/"results/graphics-source-freeze.json",result);return result
if __name__=="__main__":
p=argparse.ArgumentParser();p.add_argument("--lab",required=True);a=p.parse_args();freeze(a.lab)

View file

@ -0,0 +1,132 @@
"""V2 reviewed admission and durable debit. No reset/refund or ledger CLI.
WHY: reservation failure is consumed; immutable input SHA and run token bind
all later actions. The lock inode remains stable across atomic JSON replaces.
OFFLINE_TEST_ONLY ledgers are never accepted as native-run authorizations.
"""
import fcntl,hashlib,json,os,re,stat,time,uuid
from pathlib import Path
from plans import RUNS,LIMITS
TICKET="SWAYFX_MOSAIC_STEP20C_REBUILD_FROM_GIT_COREC_OOM_GPU_NIGHT_SHIFT_V1"
WL_SHA="7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837"
def need(v,m):
if not v:raise ValueError(m)
def sha(p):return hashlib.sha256(Path(p).read_bytes()).hexdigest()
def encoded(value):return (json.dumps(value,sort_keys=True,indent=2)+"\n").encode()
def digest(value):return hashlib.sha256(encoded(value)).hexdigest()
def canonical_lab(lab):
p=Path(lab);need(p.is_absolute() and str(p)==str(p.resolve()) and p.parent==Path("/var/tmp"),"canonical direct /var/tmp LAB required")
st=p.stat();need(st.st_uid==os.getuid() and stat.S_ISDIR(st.st_mode),"LAB owner/type")
return p
def clean_environment(lab):
lab=canonical_lab(lab)
need((lab/"scratch").resolve()==lab/"scratch" and (lab/"scratch").stat().st_uid==os.getuid(),"canonical owned scratch required")
# Allowlist avoids inherited loader, backend, activation and desktop authority.
e={k:os.environ[k] for k in ("PATH","LANG","LC_ALL","TZ") if k in os.environ}
e.update(TMPDIR=str(lab/"scratch"),TMP=str(lab/"scratch"),TEMP=str(lab/"scratch"),SMX_LAB=str(lab),XDG_CACHE_HOME=str(lab/"cache"),XDG_DATA_HOME=str(lab/"data"),PYTHONPYCACHEPREFIX=str(lab/"pycache"),CCACHE_DIR=str(lab/"cache/ccache"))
return e
def durable(path,value,exclusive=False):
p=Path(path);tmp=p.with_name(p.name+".tmp-"+uuid.uuid4().hex)
try:
with tmp.open("xb") as f:f.write(encoded(value));f.flush();os.fsync(f.fileno())
if exclusive:os.link(tmp,p);tmp.unlink()
else:os.replace(tmp,p)
fd=os.open(p.parent,os.O_RDONLY|os.O_DIRECTORY)
try:os.fsync(fd)
finally:os.close(fd)
finally:
if tmp.exists():tmp.unlink()
class Ledger:
def __init__(self,lab,path=None,offline=False):
self.lab=canonical_lab(lab);self.offline=offline
self.path=Path(path) if path else self.lab/"budget.json"
need(self.path.parent.resolve().is_relative_to(self.lab),"ledger outside LAB")
need(not self.path.is_symlink(),"ledger symlink")
if offline:need("OFFLINE_TEST_ONLY" in self.path.parts,"offline fixture namespace required")
else:need(self.path==self.lab/"budget.json","real ledger fixed path")
self.lock=self.path.with_name(self.path.name+".lock")
def transaction(self,fn,initialize=False):
fd=os.open(self.lock,os.O_RDWR|os.O_CREAT|os.O_NOFOLLOW,0o600)
try:
st=os.fstat(fd);need(st.st_uid==os.getuid() and stat.S_ISREG(st.st_mode) and st.st_nlink==1 and not st.st_mode&0o077,"stable lock owner/type/link")
fcntl.flock(fd,fcntl.LOCK_EX)
need(os.stat(self.lock,follow_symlinks=False).st_ino==st.st_ino,"lock inode changed")
if initialize:need(not self.path.exists(),"ledger already initialized");d=None
else:
s=self.path.lstat();need(s.st_uid==os.getuid() and stat.S_ISREG(s.st_mode) and s.st_nlink==1,"ledger owner/type/link")
d=json.loads(self.path.read_text());need(d["ticket"]==TICKET and d["lab"]==str(self.lab) and d["uid"]==os.getuid(),"old ticket/LAB/UID")
need(d["namespace"]==("OFFLINE_TEST_ONLY" if self.offline else "REAL") and d["limits"]==LIMITS,"namespace/limits")
value,new=fn(d);durable(self.path,new,exclusive=initialize);return value
finally:os.close(fd)
def initialize(self):
return self.transaction(lambda _: (None,dict(ticket=TICKET,lab=str(self.lab),uid=os.getuid(),namespace="OFFLINE_TEST_ONLY" if self.offline else "REAL",limits=LIMITS,runs=[])),True)
def admit(self,rid,manifest,review,publication):
auth=validate_review(self.lab,manifest,review,publication,rid,offline=self.offline)
def reserve(d):
spec=RUNS[rid];need(not any(r["id"]==rid for r in d["runs"]),"consumed run")
need(len(d["runs"])<14 and sum(r["capture_limit"] for r in d["runs"])+spec["capture_limit"]<=180,"global budget")
token=uuid.uuid4().hex;r=dict(id=rid,token=token,started_ns=time.monotonic_ns(),capture_limit=spec["capture_limit"],action_limits=spec["action_limits"],actions={},status="RESERVED",bindings=auth)
d["runs"].append(r);return dict(auth,token=token,run_id=rid,lab=str(self.lab),offline=self.offline),d
return self.transaction(reserve)
def action_debit(self,auth,*kinds):
# Revalidate all frozen source/review/publication/binary bytes before each action.
fresh=validate_review(self.lab,auth["manifest"],auth["review"],auth["publication"],auth["run_id"],offline=self.offline)
def update(d):
rows=[r for r in d["runs"] if r["id"]==auth["run_id"]];need(len(rows)==1,"missing reservation");r=rows[0]
need(r["token"]==auth["token"] and r["bindings"]==fresh and r["status"]=="RESERVED","token/stale bindings/completed")
need(time.monotonic_ns()-r["started_ns"]<150_000_000_000,"duration exhausted")
actions=dict(r["actions"])
for kind in kinds:
limit=r["capture_limit"] if kind=="capture" else r["action_limits"].get(kind,0)
need(actions.get(kind,0)<limit,"local "+kind+" exhausted");actions[kind]=actions.get(kind,0)+1
r["actions"]=actions;return None,d
return self.transaction(update)
def complete(self,auth,outcome):
def finish(d):
rows=[r for r in d["runs"] if r["id"]==auth["run_id"]];need(len(rows)==1,"missing reservation");r=rows[0]
need(r["token"]==auth["token"] and r["status"]=="RESERVED","token/completed")
r.update(status="COMPLETED",finished_ns=time.monotonic_ns(),outcome=outcome);return None,d
self.transaction(finish)
def validate_review(lab,manifest,review,publication,rid,offline=False):
lab=canonical_lab(lab);manifest=Path(manifest);review=Path(review);publication=Path(publication)
m=json.loads(manifest.read_text());r=json.loads(review.read_text());p=json.loads(publication.read_text())
need(m.get("ticket")==TICKET and m.get("lab")==str(lab),"old ticket/LAB manifest")
need(m.get("schema")=="graphics-v2-frozen-inputs" and m.get("limits")==LIMITS and m.get("plans")==RUNS,"manifest schema/plans/caps")
need(r.get("decision")=="ACCEPTED" and r.get("independent") is True and r.get("reviewer")!=m.get("author") and r.get("reviewer"),"independent review absent")
need(r.get("manifest_sha256")==sha(manifest) and rid in r.get("authorized_runs",[]),"stale review/case not admitted")
need(RUNS[rid]["admission"]!="NOT_ADMITTED","scenario NOT_ADMITTED: "+RUNS[rid].get("reason",""))
root=Path(m["source_root"]);need(root.resolve()==root and root.is_relative_to(lab),"source root outside LAB")
need(m.get("files"),"empty inputs")
for rel,h in m["files"].items():
path=root/rel;need(not Path(rel).is_absolute() and path.resolve().is_relative_to(root) and path.is_file(),"input path")
need(not any(v in path.parts for v in ("runs","results","logs","build","__pycache__")) and path not in (manifest,review,publication),"mutable/self input")
need(sha(path)==h,"frozen source changed: "+rel)
actual={str(x.relative_to(root)) for x in root.rglob("*") if x.is_file()}
need(actual==set(m["files"]),"unfrozen source addition/removal")
# Full source-only kit (including core recipes/patches/tests) has a separate,
# immutable manifest outside the source tree. Parent records remote observation;
# matching hex strings alone do not bind source bytes to that observation.
kit_manifest=Path(m["kit_manifest"])
need(sha(kit_manifest)==m["kit_manifest_sha256"],"full kit manifest changed")
kit=json.loads(kit_manifest.read_text());kit_root=Path(kit["source_root"])
need(kit_root.resolve()==kit_root and kit_root.is_relative_to(lab) and kit.get("ticket")==TICKET,"full kit root/ticket")
need(root.is_relative_to(kit_root),"graphics outside full kit")
need(not kit_manifest.is_relative_to(kit_root),"full kit manifest self-cycle")
need(kit.get("files"),"empty full kit")
for rel,h in kit["files"].items():
file=kit_root/rel
need(not Path(rel).is_absolute() and file.resolve().is_relative_to(kit_root) and sha(file)==h,"full kit source changed")
need({str(x.relative_to(kit_root)) for x in kit_root.rglob("*") if x.is_file()}==set(kit["files"]),"full kit added/removed source")
need(p.get("kit_manifest_sha256")==sha(kit_manifest) and p.get("source_commit")==kit.get("source_commit")==p.get("origin_sha"),"publication not bound to full source kit")
source_digest=digest(m["files"])
need(p.get("ticket")==TICKET and p.get("source_digest")==source_digest and p.get("decision")=="VERIFIED" and p.get("origin_sha")==p.get("github_sha") and re.fullmatch(r"[0-9a-f]{40}",p.get("origin_sha","")),"source kit unpublished")
need(p.get("offline_test_only",False)==offline,"publication namespace")
auth=m["identities"][RUNS[rid]["binary"]]
need(sha(auth["binary"])==auth["binary_sha256"],"binary changed")
need(sha(auth["wlroots"])==auth["wlroots_sha256"]==WL_SHA,"wlroots changed")
need(auth.get("build_review")=="ACCEPTED" and auth.get("source_qualification")=="ACCEPTED","binary/source qualification pending")
return dict(auth,manifest=str(manifest),review=str(review),publication=str(publication),manifest_sha256=sha(manifest),review_sha256=sha(review),publication_sha256=sha(publication),source_digest=source_digest)

View file

@ -0,0 +1,62 @@
"""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]
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

View file

@ -0,0 +1,21 @@
"""Pure tree identity helpers only; IPC geometry is pending candidate."""
def nodes(node):
yield node
for child in node.get('nodes', []) + node.get('floating_nodes', []):
yield from nodes(child)
def workspace(tree, name):
rows = [n for n in nodes(tree) if n.get('type') == 'workspace' and n.get('name') == name]
assert len(rows) == 1, 'workspace identity'
return rows[0]
def ancestry(tree, con_id, path=()):
if tree.get('id') == con_id:
return path + (tree,)
for child in tree.get('nodes', []) + tree.get('floating_nodes', []):
found = ancestry(child, con_id, path + (tree,))
if found:
return found
return ()

View file

@ -0,0 +1,64 @@
"""Pure E2 input/lifecycle predicates shared with offline negative tests."""
import re
from model import require
from predicates import COLORS, paint, equal, pair, point
def opening_pair(lines,target,serial):
actual=[]
for line in lines:
m=re.fullmatch(r'POINTER_BUTTON target=(\w+) serial=(\d+) button=(\d+) state=(\d+)',line)
require(m is not None,'opening-button-format');actual.append([m[1],*map(int,m.groups()[1:])])
require(len(actual)==2 and all(e[0]==target for e in actual) and
[e[2:] for e in actual]==[[272,1],[272,0]] and actual[0][1]==serial and
0<actual[0][1]<actual[1][1]<=0xffffffff,'real-left-opening-pair')
return actual
def explicit_child_close(before,after,ids,request_ns,done_ns):
"""Client destroy must follow a recorded explicit request; no popup_done."""
require(type(request_ns) is int and request_ns<done_ns,'explicit-close-request-order')
require(after.startswith(before),'append-only-client-protocol')
tail=after[len(before):]
require('POPUP_DONE ' not in after,'close-must-not-be-dismissal')
b=ids['POPUP_B'];a=ids['POPUP_A']
destroy=f'POPUP_B DESTROY role={b[2]} xdg={b[1]} wl={b[0]}'
require(tail.count(destroy)==1 and tail.count('COMMAND close_b DONE')==1 and
tail.index(destroy)<tail.index('COMMAND close_b DONE'),'explicit-child-destroy-DONE')
for obj,stem in [(b[2],'xdg_popup'),(b[1],'xdg_surface'),(b[0],'wl_surface')]:
require(tail.count(f'{stem}#{obj}.destroy()')==1,'child-protocol-destroy')
require(after.count(f'POPUP_A MAP wl={a[0]} xdg={a[1]}')==1 and
'POPUP_A DESTROY ' not in after and 'TOPLEVEL DESTROY' not in after,'same-A-remains-mapped')
return dict(status='PASS',request_ns=request_ns,done_ns=done_ns,B=b,A=a,
meaning='explicit client close, no compositor popup_done')
def a_survival(image,before,after,ids,buttons,global_point,rect):
a=ids['POPUP_A']
require(paint(image,'POPUP_B')['count']==0 and paint(image,'POPUP_A')['count']>0,'child-zero-residual-A-painted')
require(before.startswith('') and after.startswith(before),'A-input-protocol-appended')
require('POPUP_A DESTROY ' not in after and 'POPUP_A POPUP_DONE ' not in after and
after.count(f'POPUP_A MAP wl={a[0]} xdg={a[1]}')==1,'same-A-live-after-input')
require(rect[0]<=global_point[0]<rect[0]+rect[2] and rect[1]<=global_point[1]<rect[1]+rect[3], 'A-recomputed-point-bounds')
return dict(status='PASS',pair=pair(buttons,'POPUP_A'),ids=a,point=global_point)
def normal_owner_close(before,after,ids,code):
require(code==0 and after.startswith(before),'normal-client-exit')
tail=after[len(before):]
require(tail.count('COMMAND close_owner')==1 and tail.count('TOPLEVEL DESTROY')==1 and
'POPUP_DONE ' not in tail,'normal-owner-close-command')
a=ids['POPUP_A'];top=ids['TOPLEVEL']
require(tail.count(f'POPUP_A DESTROY role={a[2]} xdg={a[1]} wl={a[0]}')==1 and
tail.index('COMMAND close_owner')<tail.index('POPUP_A DESTROY ')<tail.index('TOPLEVEL DESTROY'),
'normal-owner-child-first-destruction')
for obj,stem in [(a[2],'xdg_popup'),(a[1],'xdg_surface'),(a[0],'wl_surface'),
(top[2],'xdg_toplevel'),(top[1],'xdg_surface'),(top[0],'wl_surface')]:
require(tail.count(f'{stem}#{obj}.destroy()')==1,'owner-protocol-destroy')
return dict(status='PASS',client_exit=code,ids=ids)
def final_restoration(baseline,final):
cmp=equal(baseline,final)
require(cmp['equal'] and all(paint(final,n)['count']==0 for n in ('POPUP_A','POPUP_B')),'whole-H2-final-exact')
return dict(status='PASS',comparison=cmp)

View file

@ -0,0 +1,194 @@
"""EXPERIMENTAL typed half-open geometry. Pure: no processes or sockets.
Source contracts are recorded in the offline gate, not inferred from RGB.
Every conversion is explicit and keeps assignment/owner/generation provenance.
"""
from dataclasses import dataclass
from enum import Enum
class Invalid(ValueError):
pass
class Space(str, Enum):
NATIVE = 'NativeSHM'
CONFIGURE = 'XDGConfigure'
CONTENT = 'AppliedContent'
GLOBAL = 'SceneGlobal'
POPUP = 'PopupLocal'
VIEWPORT = 'GlobalViewport'
PNG = 'OutputPNG'
def require(value, contract):
if not value:
raise Invalid(contract)
@dataclass(frozen=True)
class Provenance:
owner: int
workspace: int
generation: str
evidence: str
state: str = 'applied'
@dataclass(frozen=True)
class Rect:
space: Space
x: int
y: int
width: int
height: int
provenance: Provenance
def __post_init__(self):
require(isinstance(self.space, Space), 'tag-required')
require(all(type(v) is int for v in (self.x, self.y, self.width, self.height)), 'integer-geometry')
require(self.width >= 0 and self.height >= 0, 'nonnegative-size')
require(bool(self.provenance.evidence), 'evidence-required')
@property
def end(self):
return (self.x + self.width, self.y + self.height)
def contains(self, xy):
return self.x <= xy[0] < self.end[0] and self.y <= xy[1] < self.end[1]
def values(self):
return [self.x, self.y, self.width, self.height]
@dataclass(frozen=True)
class Native:
rectangle: Rect
buffer_id: int
stride: int
format: int
commit_serial: int
@dataclass(frozen=True)
class Applied:
scene: Rect
window: Rect
configured: Rect
native: Native
border_left: int
border_top: int
titlebar: int
configure_ack: int
view_offset: tuple = (0, 0)
@dataclass(frozen=True)
class Output:
name: str
rectangle: Rect
scale: float
transform: str
def same(a, b):
require(a.owner == b.owner, 'owner-identity')
require(a.workspace == b.workspace, 'workspace-identity')
require(a.generation == b.generation, 'applied-generation')
require(a.state == b.state == 'applied', 'pending-not-applied')
def content(applied):
s, w, c, n = applied.scene, applied.window, applied.configured, applied.native
require(s.space is Space.GLOBAL and w.space is Space.CONTENT and c.space is Space.CONFIGURE,
'assignment-spaces')
require(n.rectangle.space is Space.NATIVE, 'native-space')
for r in (w, c, n.rectangle):
same(s.provenance, r.provenance)
require(n.buffer_id > 0 and n.stride == n.rectangle.width * 4 and n.format in (0, 1), 'native-buffer-identity')
require(0 < n.commit_serial <= 0xffffffff, 'commit-serial')
require(0 < applied.configure_ack <= 0xffffffff, 'assigned-configure-ack')
require((w.width, w.height) == (c.width, c.height), 'configure-assignment')
require(applied.border_left == w.x and applied.border_top == applied.titlebar + w.y,
'titlebar-content-offset')
require(w.width + 2 * applied.border_left == s.width and
w.height + applied.border_top + applied.border_left == s.height, 'assigned-destination')
return Rect(Space.GLOBAL, s.x + applied.border_left + applied.view_offset[0],
s.y + applied.border_top + applied.view_offset[1], w.width, w.height, s.provenance)
def intersect(rect, boundary):
require(rect.space is Space.GLOBAL and boundary.space in (Space.GLOBAL, Space.VIEWPORT), 'global-intersection')
same(rect.provenance, boundary.provenance)
x, y = max(rect.x, boundary.x), max(rect.y, boundary.y)
return Rect(Space.GLOBAL, x, y, max(0, min(rect.end[0], boundary.end[0]) - x),
max(0, min(rect.end[1], boundary.end[1]) - y), rect.provenance)
def to_png(rect, output):
require(rect.space is Space.GLOBAL and output.rectangle.space is Space.GLOBAL, 'global-to-png-spaces')
require(output.scale == 1.0, 'unmeasured-output-scale')
require(output.transform == 'normal', 'unmeasured-output-transform')
same(rect.provenance, output.rectangle.provenance)
visible = intersect(rect, output.rectangle)
return Rect(Space.PNG, min(max(visible.x - output.rectangle.x,0),output.rectangle.width), min(max(visible.y - output.rectangle.y,0),output.rectangle.height),
visible.width, visible.height, rect.provenance)
def from_png(rect, output):
require(rect.space is Space.PNG and output.rectangle.space is Space.GLOBAL, 'png-to-global-spaces')
require(output.scale == 1.0 and output.transform == 'normal', 'unmeasured-png-transform')
same(rect.provenance, output.rectangle.provenance)
require(0 <= rect.x <= rect.end[0] <= output.rectangle.width and
0 <= rect.y <= rect.end[1] <= output.rectangle.height, 'png-bounds')
return Rect(Space.GLOBAL, rect.x + output.rectangle.x, rect.y + output.rectangle.y,
rect.width, rect.height, rect.provenance)
def verify_paint(rect, output, bbox, count, clip=None):
expected = to_png(intersect(rect, clip) if clip is not None else rect, output)
actual = [] if bbox is None else list(bbox)
box=[expected.x, expected.y, *expected.end] if expected.width and expected.height else []
require(actual == box, 'paint-origin-intersection')
require(count == expected.width * expected.height, 'paint-area')
return expected
def popup(parent, configured, parent_xdg, expected_parent_xdg, ack, mapped):
require(parent.space is Space.GLOBAL and configured.space is Space.POPUP, 'popup-spaces')
same(parent.provenance, configured.provenance)
require(parent_xdg == expected_parent_xdg and expected_parent_xdg > 0, 'xdg-parent')
require(0 < ack <= 0xffffffff, 'popup-ack')
require(mapped is True, 'popup-map')
return Rect(Space.GLOBAL, parent.x + configured.x, parent.y + configured.y,
configured.width, configured.height, parent.provenance)
def crossing(rect, boundary_x):
require(rect.space is Space.GLOBAL, 'crossing-space')
return 'EXERCISED' if rect.x < boundary_x < rect.end[0] else 'NOT EXERCISED'
def local_clip_to_global(local, origin, provenance):
require(local.space is Space.CONTENT, 'clip-local-space')
same(local.provenance, provenance)
return Rect(Space.VIEWPORT, local.x + origin[0], local.y + origin[1],
local.width, local.height, provenance)
def pointer_local(xy, rect, actual):
require(rect.space is Space.GLOBAL and rect.contains(xy), 'pointer-global-bounds')
require(list(actual) == [xy[0] - rect.x, xy[1] - rect.y], 'pointer-local-correlation')
return list(actual)
def fresh_chain(old, new):
require(old['owner'] != new['owner'] and old['pid'] != new['pid'], 'fresh-E2-identity')
require(len(set(old['serials'] + new['serials'])) == 4 and
max(old['serials']) < min(new['serials']), 'fresh-E2-serials')
def fresh_standard(mosaic, standard):
require(mosaic.provenance.owner == standard.provenance.owner and
mosaic.provenance.workspace == standard.provenance.workspace, 'standard-owner')
require(mosaic.provenance.generation != standard.provenance.generation, 'fresh-standard-generation')
return standard
def constraints(flags, requested, configured):
require(type(flags) is int and 0 <= flags <= 63, 'positioner-flags')
require(flags != 0 or requested == configured, 'zero-flags-no-adjustment')
return {'flags': flags, 'request': requested, 'actual': configured, 'prediction_only': True}

View file

@ -0,0 +1,374 @@
"""OFFLINE_TEST_ONLY: actual runtime modules, synthetic protocol/tree/process I/O.
No old raw evidence, client execution, compositor, IPC or real budget access.
"""
import copy,io,json,os,re,resource,shutil,sys,tempfile,threading,time,unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import Mock,patch
LAB=Path(os.environ["SMX_TEST_LAB"]).resolve() if "SMX_TEST_LAB" in os.environ else Path(__file__).resolve().parents[2]
KIT=Path(__file__).resolve().parents[1];sys.path.insert(0,str(KIT))
import gate,plans,validators as v,saved_validators as sv,geometry,engine,cases,run,evidence
from ipc_predicates import ancestry
class V2(unittest.TestCase):
def rejects(self,fn,*args,**kw):
with self.assertRaises((ValueError,AssertionError,RuntimeError)):fn(*args,**kw)
def setUp(self):
root=Path(os.environ.get("SMX_OFFLINE_SCRATCH",str(LAB/"graphics-tests/OFFLINE_TEST_ONLY")));root.mkdir(parents=True,exist_ok=True)
self.temp=tempfile.TemporaryDirectory(dir=root);self.addCleanup(self.temp.cleanup);self.root=Path(self.temp.name)
def fixture(self):
source=self.root/"source";source.mkdir();(source/"input.py").write_text("# synthetic source binding\n")
binary=self.root/"binary";binary.write_bytes(b"OFFLINE_TEST_ONLY not executable")
auth=dict(binary=str(binary),binary_sha256=gate.sha(binary),wlroots="/usr/lib/libwlroots-0.20.so",wlroots_sha256=gate.WL_SHA,build_review="ACCEPTED",source_qualification="ACCEPTED")
kit_manifest=self.root/"kit-manifest.json"
manifest=self.root/"inputs.json";review=self.root/"review.json";publication=self.root/"publication.json"
m=dict(schema="graphics-v2-frozen-inputs",ticket=gate.TICKET,lab=str(LAB),author="offline-author",source_root=str(source),files={"input.py":gate.sha(source/"input.py")},limits=plans.LIMITS,plans=plans.RUNS,identities=dict(core=auth,pristine=auth))
def seal():
gate.durable(kit_manifest,dict(ticket=gate.TICKET,source_root=str(source),files=m["files"],source_commit="f"*40))
m.update(kit_manifest=str(kit_manifest),kit_manifest_sha256=gate.sha(kit_manifest))
gate.durable(manifest,m);gate.durable(review,dict(decision="ACCEPTED",independent=True,reviewer="offline-reviewer",manifest_sha256=gate.sha(manifest),authorized_runs=list(plans.RUNS)))
gate.durable(publication,dict(ticket=gate.TICKET,decision="VERIFIED",source_digest=gate.digest(m["files"]),origin_sha="f"*40,github_sha="f"*40,offline_test_only=True,kit_manifest_sha256=gate.sha(kit_manifest),source_commit="f"*40))
seal();ledger=gate.Ledger(LAB,self.root/"budget.json",offline=True);ledger.initialize()
return ledger,manifest,review,publication,m,seal
def tree(self):
owner=dict(id=40,pid=100,type="con",floating=None,nodes=[],floating_nodes=[],fullscreen_mode=0)
branch=dict(id=30,type="con",floating=None,nodes=[owner],floating_nodes=[],fullscreen_mode=0)
ws=dict(id=20,type="workspace",name="1",output="HEADLESS-1",layout="mosaic",floating=None,nodes=[branch],floating_nodes=[])
out=dict(id=10,type="output",name="HEADLESS-1",floating=None,nodes=[ws],floating_nodes=[])
root=dict(id=1,type="root",nodes=[out],floating_nodes=[])
return root,owner,ancestry(root,40)
def test_caps_and_non_admitted(self):
self.assertEqual(len(plans.RUNS),14);self.assertEqual(sum(plans.CAPS.values()),170)
self.assertEqual(max(plans.CAPS.values()),18)
l,m,r,p,_,_=self.fixture()
for rid in ("P1","C8","O1","O2","G2","R1"):self.rejects(l.admit,rid,m,r,p)
self.assertEqual(json.loads(l.path.read_text())["runs"],[])
def test_real_gate_consumption_token_caps_completion(self):
l,m,r,p,_,_=self.fixture();auth=l.admit("C1",m,r,p)
self.rejects(l.admit,"C1",m,r,p);self.rejects(l.initialize)
self.rejects(l.action_debit,dict(auth,token="stale"),"capture")
for _ in range(18):l.action_debit(auth,"capture")
before=l.path.read_bytes();self.rejects(l.action_debit,auth,"capture");self.assertEqual(before,l.path.read_bytes())
l.complete(auth,dict(status="INCONCLUSIVE",runner_exit=1));self.rejects(l.action_debit,auth,"move");self.rejects(l.complete,auth,{})
def test_global_and_per_action_debits_atomic(self):
l,m,r,p,_,_=self.fixture();auth=l.admit("C2",m,r,p)
for _ in range(plans.RUNS["C2"]["action_limits"]["grab"]):l.action_debit(auth,"grab")
before=l.path.read_bytes();self.rejects(l.action_debit,auth,"move","grab");self.assertEqual(before,l.path.read_bytes())
def fill(d):
d["runs"]=[dict(id="used"+str(i),capture_limit=18) for i in range(10)];return None,d
l.transaction(fill);self.rejects(l.admit,"C1",m,r,p)
def test_source_review_binary_and_publication_bindings(self):
l,m,r,p,data,seal=self.fixture();auth=l.admit("C1",m,r,p)
source=Path(data["source_root"])/"input.py";old=source.read_bytes();source.write_bytes(b"changed")
self.rejects(l.action_debit,auth,"move");source.write_bytes(old)
binary=Path(auth["binary"]);old=binary.read_bytes();binary.write_bytes(b"changed");self.rejects(l.action_debit,auth,"move");binary.write_bytes(old)
rr=json.loads(r.read_text());rr["reviewer"]="different";gate.durable(r,rr);self.rejects(l.action_debit,auth,"move");seal()
pp=json.loads(p.read_text());pp["github_sha"]="e"*40;gate.durable(p,pp);self.rejects(l.action_debit,auth,"move");seal()
data["ticket"]="OLD_TICKET";seal();self.rejects(l.action_debit,auth,"move")
def test_fullkit_publication_source_binding(self):
l,m,r,p,data,seal=self.fixture();auth=l.admit("C1",m,r,p)
km=Path(data["kit_manifest"]);km.write_text("{}")
self.rejects(l.action_debit,auth,"move")
seal();pub=json.loads(p.read_text());pub["source_commit"]="a"*40;gate.durable(p,pub)
self.rejects(l.action_debit,auth,"move")
def test_old_lab_uid_limits_lock_symlink_and_source_addition(self):
l,m,r,p,data,seal=self.fixture()
data["lab"]="/var/tmp/old-lab";seal();self.rejects(l.admit,"C1",m,r,p);data["lab"]=str(LAB);seal()
new=Path(data["source_root"])/"unreviewed.py";new.write_text("new");self.rejects(l.admit,"C1",m,r,p);new.unlink()
data["identities"]["core"]["wlroots_sha256"]="bad";seal();self.rejects(l.admit,"C1",m,r,p)
d=json.loads(l.path.read_text());d["limits"]["runs"]=15;gate.durable(l.path,d);self.rejects(l.admit,"C1",m,r,p)
other=self.root/"other";other.write_text("");l.lock.unlink();l.lock.symlink_to(other)
with self.assertRaises(OSError):l.transaction(lambda d:(None,d))
def test_environment_and_socket_paths(self):
with patch.dict(os.environ,{k:"daily" for k in ("DISPLAY","WAYLAND_DISPLAY","SWAYSOCK","XDG_RUNTIME_DIR","LD_PRELOAD","LD_LIBRARY_PATH","WLR_BACKENDS","EGL_PLATFORM","DBUS_SESSION_BUS_ADDRESS")}):
env=gate.clean_environment(LAB);self.assertNotIn("SWAYSOCK",env);self.assertNotIn("LD_PRELOAD",env);self.assertEqual(env["TMPDIR"],str(LAB/"scratch"))
s=engine.Session.__new__(engine.Session);s.runtime=Path("/tmp/smx-offline");s.sock=Path("/tmp/daily.sock");s.record=Mock();s.env={}
with patch.object(engine.subprocess,"run") as launch:
self.rejects(s.ipc,"exit");launch.assert_not_called()
self.rejects(engine.Session,plans.RUNS["C1"],dict(offline=True))
def test_spawn_wraps_argv_and_records_requested_and_actual(self):
s=engine.Session.__new__(engine.Session);s.run=self.root;s.handles=[];s.proc={};s.expired=False;s.env={};s.debit=Mock();s.record=Mock()
child=Mock(pid=12345);requested=[sys.executable,"-c","pass"]
with patch.object(engine.shutil,"which",return_value="/usr/bin/prlimit"),patch.object(engine.subprocess,"Popen",return_value=child) as popen:
self.assertIs(s.spawn("mocked",requested),child)
argv=popen.call_args.args[0]
self.assertEqual(argv,["/usr/bin/prlimit","--core=0:0","--",*requested])
event=s.record.call_args
self.assertEqual(event.kwargs["requested_argv"],requested)
self.assertEqual(event.kwargs["actual_argv"],argv)
self.assertEqual(event.args[0],"spawn")
def test_spawn_real_non_graphic_child_core_limit_and_parent_unchanged(self):
prlimit=shutil.which("prlimit")
self.assertIsNotNone(prlimit,"util-linux prlimit required")
parent_limit=resource.getrlimit(resource.RLIMIT_CORE)
s=engine.Session.__new__(engine.Session);s.run=self.root;s.handles=[];s.proc={};s.expired=False;s.env={};s.debit=Mock();s.events=[]
s.record=lambda kind,**fields:s.events.append(dict(kind=kind,**fields))
code="import json,os,resource; print(json.dumps({'pid':os.getpid(),'core':resource.getrlimit(resource.RLIMIT_CORE)}))"
child=s.spawn("corelimit-child",[sys.executable,"-c",code])
self.assertEqual(child.wait(timeout=5),0)
observed=json.loads((self.root/"corelimit-child.log").read_text())
self.assertEqual(observed["core"],[0,0])
self.assertEqual(observed["pid"],child.pid)
self.assertEqual(resource.getrlimit(resource.RLIMIT_CORE),parent_limit)
event=s.events[0]
self.assertEqual(event["requested_argv"],[sys.executable,"-c",code])
self.assertEqual(event["actual_argv"][:3],[prlimit,"--core=0:0","--"])
def test_watchdog_autonomous_kill_term_resistant_private_group(self):
import signal,subprocess
s=engine.Session.__new__(engine.Session);s.run=self.root;s.handles=[];s.proc={};s.proc_lock=threading.RLock();s.expired=False;s.env={};s.debit=Mock();s.record=Mock();s.finished=threading.Event()
code="import os,signal,time; signal.signal(signal.SIGTERM,signal.SIG_IGN); print('READY',flush=True); time.sleep(30)"
p=s.spawn('resistant',[sys.executable,'-c',code])
self.addCleanup(lambda:p.poll() is None and os.killpg(p.pid,signal.SIGKILL))
end=time.monotonic()+3
while 'READY' not in (self.root/'resistant.log').read_text() and time.monotonic()<end:time.sleep(.01)
self.assertIn('READY',(self.root/'resistant.log').read_text())
self.assertEqual(os.getpgid(p.pid),p.pid)
# Simulate the last seconds; no main cleanup is called to rescue the watchdog.
s.started=time.monotonic()-143.1;start=time.monotonic()
watch=threading.Thread(target=s.watchdog);watch.start();watch.join(timeout=4)
self.assertFalse(watch.is_alive());self.assertEqual(p.wait(timeout=1),-signal.SIGKILL)
self.assertTrue(s.expired);self.assertLess(time.monotonic()-start,3)
self.assertLess(time.monotonic()-s.started,147)
with self.assertRaises(ProcessLookupError):os.killpg(p.pid,0)
p.stdin.close()
for h in s.handles:h.close()
def test_watchdog_expired_registration_cannot_launch(self):
s=engine.Session.__new__(engine.Session);s.run=self.root;s.handles=[];s.proc={};s.proc_lock=threading.RLock();s.expired=False;s.env={};s.record=Mock()
# Expiry occurs after the first check, during the debit, before atomic spawn.
s.debit=lambda *_:setattr(s,'expired',True)
with patch.object(engine.subprocess,'Popen') as launch:
self.rejects(s.spawn,'late',[sys.executable,'-c','pass']);launch.assert_not_called()
def test_close_wait_uses_absolute_deadline(self):
s=engine.Session.__new__(engine.Session);s.started=time.monotonic()-145.5;s.proc={'owner':Mock()};s.proc['owner'].poll.return_value=None;s.closed=[];s.record=Mock();s.client_cmd=Mock()
s.proc['owner'].wait.side_effect=engine.subprocess.TimeoutExpired('private',.5)
with self.assertRaises(engine.subprocess.TimeoutExpired):s.close_client('owner')
self.assertLessEqual(s.proc['owner'].wait.call_args.kwargs['timeout'],.5)
self.assertEqual(s.closed[0]['status'],'INCONCLUSIVE')
def dynamic_snapshot(self,width=800,scroll=1000,output='HEADLESS-1'):
x=-width if output=='HEADLESS-1' else 0
return dict(tree=dict(type='workspace',name='1',id=20,output=output,rect=dict(x=x,y=0,width=width,height=600),mosaic=dict(rows=[dict(children=[1,2,3],scroll_x=scroll)]),nodes=[dict(id=i+1,rect=dict(x=x+i*640,y=20,width=640,height=580)) for i in range(3)]))
def test_dynamic_reconstructed_clamp_resize_migration_and_negatives(self):
initial=cases.dynamic_geometry(self.dynamic_snapshot())
resized=cases.dynamic_geometry(self.dynamic_snapshot(960,960),initial)
self.assertEqual(resized['expected_scroll'],960);self.assertEqual(resized['minimum_width'],640)
back=cases.dynamic_geometry(self.dynamic_snapshot(800,960),resized)
moved=cases.dynamic_geometry(self.dynamic_snapshot(800,960,'HEADLESS-2'),back)
self.assertEqual(moved['output'],'HEADLESS-2')
self.rejects(cases.dynamic_geometry,self.dynamic_snapshot(960,1000),initial)
for mutate in (lambda w:w['nodes'][0]['rect'].update(width=639),lambda w:w['nodes'][1]['rect'].update(x=123),lambda w:w['mosaic']['rows'][0].update(children=[3,2,1]),lambda w:w.update(id=21)):
snap=self.dynamic_snapshot(960,960);mutate(snap['tree']);self.rejects(cases.dynamic_geometry,snap,initial)
def test_dynamic_pixels_whole_h2_old_output_and_exclusion_negatives(self):
from PIL import Image
outputs=copy.deepcopy(plans.RUNS['C7']['outputs']);frames={o['name']:'logical' for o in outputs}
baseline=Image.new('RGB',(800,600),(48,48,56));images=[baseline.copy(),baseline.copy()]
images[0].putpixel((790,50),engine.COLORS['POPUP_B'])
cases.dynamic_pixels(images,outputs,frames,[-800,0,800,600],baseline)
images[1].putpixel((0,50),engine.COLORS['POPUP_B']);self.rejects(cases.dynamic_pixels,images,outputs,frames,[-800,0,800,600],baseline)
images[1]=baseline.copy();images[1].putpixel((799,599),(0,0,1));self.rejects(cases.dynamic_pixels,images,outputs,frames,[-800,0,800,600],baseline)
images[1]=baseline.copy();self.rejects(cases.dynamic_pixels,images,outputs,frames,[0,0,800,600])
images[0]=baseline.copy();images[1].putpixel((1,50),engine.COLORS['POPUP_B']);cases.dynamic_pixels(images,outputs,frames,[0,0,800,600])
def test_tree_tiled_branch_none_and_wrong_owner(self):
tree,node,path=self.tree();ws=path[-3];self.assertTrue(v.camera_eligible(path,ws));v.owner_context(node,path,100,"1","HEADLESS-1","mosaic")
self.rejects(v.owner_context,node,path,101,"1","HEADLESS-1","mosaic")
self.rejects(v.owner_context,node,path,100,"1","HEADLESS-2","mosaic")
self.rejects(v.owner_context,dict(node,id=999),path,100,"1","HEADLESS-1","mosaic")
parent=path[-2];parent["nodes"].remove(node);parent["floating_nodes"].append(node)
self.assertFalse(v.camera_eligible(path,ws));self.rejects(v.owner_context,node,path,100,"1","HEADLESS-1","mosaic")
def test_wire_actual_button_grab_and_native_sizes(self):
raw=(KIT/"wire-fixture.txt").read_text();proof=v.grab(raw)
for bad in (raw.replace("origin=wl_pointer.button","origin=fake"),raw.replace("POPUP_B MAP ","BAD MAP "),raw.replace("used="+str(proof["grabs"][0]["serial"]),"used=999999"),re.sub(r"wl_pointer#\d+\.button\([^\n]+", "removed-wire-button",raw),re.sub(r"(create_buffer\(new id wl_buffer#\d+, 0, )\d+, \d+, \d+, 1\)",r"\g<1>999, 999, 3996, 1)",raw)):
self.rejects(v.grab,bad)
self.rejects(v.hidden_survival,raw,proof,[dict(action="left")]);v.hidden_survival(raw,proof,[dict(action="move")])
def test_vertical_scaled_rotated_exact_rgb(self):
v.crosses([50,505,350,170],1,600);self.rejects(v.crosses,[50,505,350,170],0,0)
o=plans.RUNS["C2"]["outputs"][1];self.assertEqual(geometry.png_global((30,40),o,"logical"),[30,640])
self.assertEqual(plans.RUNS["C3"]["outputs"][0]["mode"],[1000,750]);self.assertEqual(plans.RUNS["C4"]["outputs"][0]["transform"],"90")
from PIL import Image
a=Image.new("RGB",(20,20));b=a.copy();b.putpixel((19,19),(0,0,1));self.rejects(v.rgb,a,b);self.rejects(v.rgb,a,a,True);v.rgb(a,a)
def test_saved_phase_actual_validator_and_closure(self):
before="ACK ns=1 serial=10 size=640x480\nxdg_surface#1.ack_configure(10)\nwl_shm_pool#4.create_buffer(\nCOMMIT ns=2\n"
held="HELD ns=100 serial=11\nxdg_surface#1.configure(11)\nXDG_CONFIGURE ns=100 serial=11 size=580x420 hold=1\n"
proof=sv.held_configure(before,held,10)
after=held+"xdg_surface#1.ack_configure(11)\nACK ns=400 serial=11\nCOMMIT ns=401 serial=11\n"
sv.released_configure(proof,after,300,200);self.rejects(sv.held_configure,before,after,10);self.rejects(sv.released_configure,proof,after,500,200)
good="CLOSE_RECEIVED\nSHM_CLOSURE created=2 released=2\nEXIT error=0";v.client_exit(good,0)
for bad in (good.replace("released=2","released=1"),good.replace("error=0","error=32"),good.replace("CLOSE_RECEIVED","")):self.rejects(v.client_exit,bad,0)
def test_no_fake_present_or_fullscreen(self):
tree,node,path=self.tree();self.rejects(v.fullscreen_ancestor,path)
event=dict(run="C1",output="HEADLESS-1",commit_seq=1,native_event=True,source="native-output-commit")
present=dict(event,source="native-output-present");self.assertEqual(evidence.native_present([event],[present])["matched"],1)
self.rejects(evidence.native_present,[event],[dict(present,native_event=False)])
self.rejects(evidence.native_present,[event],[dict(present,run="C2")])
path[-2]["fullscreen_mode"]=1;path[-2]["nodes"].append(dict(id=41))
record=dict(owner_path=path,native_xdg=True,configure_ack=1,owner_id=40,configure=[800,600],child_configures=[[800,300],[800,300]],popup_A=[-10,0,350,170],popup_B=[-5,20,300,130],boundary=0)
evidence.fullscreen_certificate(record,record)
bad=copy.deepcopy(record);bad["popup_B"][0]=20;self.rejects(evidence.fullscreen_certificate,record,bad)
bad=copy.deepcopy(record);bad["configure"]=[800,500];self.rejects(evidence.fullscreen_certificate,record,bad)
def test_runner_dispatch_failures_and_no_launch_before_admission(self):
# execute is the real dispatch/orchestration; only transport and ledger are fake.
s=Mock();s.proc={};s.cleanup.side_effect=lambda status,failure:status
ledger=Mock();ledger.admit.return_value={}
with patch.object(run,"Ledger",return_value=ledger),patch.object(cases,"popup_campaign",return_value="PARTIALLY_FEASIBLE") as campaign:
result=run.execute("C2",LAB,"m","r","p",session_factory=lambda *_:s)
self.assertEqual(result["runner_exit"],0);campaign.assert_called_once_with(s);s.start.assert_called_once()
s.reset_mock();s.start.side_effect=ValueError("source changed")
with patch.object(run,"Ledger",return_value=ledger):
result=run.execute("C2",LAB,"m","r","p",session_factory=lambda *_:s)
self.assertEqual(result["runner_exit"],1);self.assertIn("source changed",result["failure"])
ledger.admit.side_effect=ValueError("no review");factory=Mock()
with patch.object(run,"Ledger",return_value=ledger):self.rejects(run.execute,"C2",LAB,"m","r","p",session_factory=factory)
factory.assert_not_called()
def closure_execute(self,bad=None,archived=False,exited=False,scenario_failure=False):
good='CLOSE_RECEIVED\nSHM_CLOSURE created=2 released=2\nEXIT error=0'
class Process:
def __init__(self,pid,done=False):self.pid=pid;self.returncode=0 if done else None;self.stdin=io.StringIO()
def poll(self):return self.returncode
def wait(self,timeout=None):self.returncode=0;return 0
s=engine.Session.__new__(engine.Session);s.spec=plans.RUNS['C2'];s.auth={};s.ledger=Mock()
s.run=self.root/'run';s.run.mkdir();s.runtime=self.root/'runtime';s.runtime.mkdir()
s.closed=[];s.handles=[];s.events=[];s.started=time.monotonic();s.finished=threading.Event();s.expired=False;s.pointer=None;s.env={}
s.watch=Mock();s.sock=Mock();s.sock.is_socket.return_value=True
s.comp=Process(999999991);s.proc={'compositor':s.comp,'reference':Process(999999992,exited)}
(s.run/'reference.log').write_text(good if archived else bad or good);s.start=Mock();s.find=Mock(return_value=None);s.debit=Mock()
def campaign(session):
if archived:
old=Process(999999993);s.proc['owner']=old;(s.run/'owner.log').write_text(bad)
try:s.close_client('owner')
except engine.Ambiguous:pass
s.proc['owner']=Process(999999994);(s.run/'owner.log').write_text(good)
if scenario_failure:raise ValueError('scenario failed')
return 'PARTIALLY_FEASIBLE'
def terminal(*args,**kwargs):s.comp.returncode=0;return SimpleNamespace(returncode=0,stdout='',stderr='')
with patch.object(run,'Ledger',return_value=Mock()),patch.object(cases,'popup_campaign',side_effect=campaign),patch.object(engine.subprocess,'run',side_effect=terminal),patch.object(engine.os,'killpg',side_effect=ProcessLookupError):
result=run.execute('C2',LAB,'m','r','p',session_factory=lambda *_:s)
return result,json.loads((s.run/'outcome.json').read_text())
def test_actual_session_normal_scientific_mechanical_close(self):
result,out=self.closure_execute();self.assertEqual(result['runner_exit'],0);self.assertEqual(out['scientific_cleanup'],'PASS');self.assertEqual(out['mechanical_cleanup'],'PASS')
def test_actual_session_shm_failure_not_laundered(self):
result,out=self.closure_execute('CLOSE_RECEIVED\nSHM_CLOSURE created=2 released=1\nEXIT error=0')
self.assertEqual(result['runner_exit'],1);self.assertEqual(out['scientific_cleanup'],'INCONCLUSIVE');self.assertEqual(out['mechanical_cleanup'],'PASS');self.assertIn('SHM release',out['failure'])
def test_actual_session_archived_same_name_failure(self):
result,out=self.closure_execute('CLOSE_RECEIVED\nSHM_CLOSURE created=2 released=1\nEXIT error=0',archived=True)
self.assertEqual(result['runner_exit'],1);owners=[c for c in out['client_closures'] if c['name']=='owner'];self.assertEqual([c['status'] for c in owners],['INCONCLUSIVE','PASS'])
def test_actual_session_already_exited_invalid_client(self):
result,out=self.closure_execute('SHM_CLOSURE created=2 released=2\nEXIT error=0',exited=True)
self.assertEqual(result['runner_exit'],1);self.assertEqual(out['scientific_cleanup'],'INCONCLUSIVE')
def test_actual_session_scenario_failure(self):
result,out=self.closure_execute(scenario_failure=True);self.assertEqual(result['runner_exit'],1);self.assertEqual(out['scientific_cleanup'],'PASS');self.assertIn('scenario failed',out['failure'])
def test_open_chain_selects_and_checks_before_and_after_spawn(self):
session=Mock();session.spec=plans.RUNS['C1'];session.events=[]
session.owner.side_effect=ValueError('wrong mapped H2 owner');session.snapshot.return_value={}
with patch.object(v,'selected_workspace') as selected:
self.rejects(cases.open_chain,session)
self.assertEqual(session.cmd.call_args_list[0].args,('workspace 1',));self.assertEqual(session.cmd.call_args_list[1].args,('layout mosaic',));selected.assert_called_once();session.owner.assert_called_once_with('owner');session.click.assert_not_called()
def test_actual_delivery_requires_press_wire_and_grab_serial(self):
s=engine.Session.__new__(engine.Session)
lines={'owner':['POINTER_BUTTON target=TOPLEVEL serial=20 button=272 state=1','POINTER_BUTTON target=TOPLEVEL serial=21 button=272 state=0']}
tail={'owner':'POINTER_MOTION target=TOPLEVEL x=5 y=6\nwl_pointer#4.button(20, 10, 272, 1)\nwl_pointer#4.button(21, 11, 272, 0)'}
s.delivery('owner',[100,200,40,40],[105,206],tail,lines,'TOPLEVEL',20)
self.rejects(s.delivery,'owner',[100,200,40,40],[105,206],tail,lines,'TOPLEVEL',22)
self.rejects(s.delivery,'owner',[100,200,40,40],[105,206],{'owner':'POINTER_MOTION target=TOPLEVEL x=5 y=6'},lines,'TOPLEVEL',20)
self.rejects(s.delivery,'owner',[100,200,40,40],[105,206],tail,{'owner':lines['owner'][1:]},'TOPLEVEL',20)
def quota_scenario(self,rid):
# Actual open_chain/horizontal/standard-return handlers; replace measured I/O
# and scientific predicates, never duplicate their action/capture sequencing.
from PIL import Image
from collections import Counter
from contextlib import ExitStack
class FakeSession:
def __init__(self):
self.spec=plans.RUNS[rid];self.outputs=copy.deepcopy(self.spec['outputs']);self.frames={o['name']:'logical' for o in self.outputs};self.actions=Counter();self.events=[];self.proc={};self.sequence=0;self.tag='';self.closed=[];self.scroll_x=0;self.expected_output='HEADLESS-1';self.auth={};self.comp=SimpleNamespace(pid=999999995)
def debit(self,*kinds):
self.actions.update(kinds)
for k in kinds:
cap=self.spec['capture_limit'] if k=='capture' else self.spec['action_limits'][k]
if self.actions[k]>cap:raise ValueError('actual handler quota '+k)
def cmd(self,command,business=False):
self.debit('mutation' if business else 'configuration')
if command.startswith('move workspace to output '):self.expected_output=command.split()[-1]
def launch_client(self,name,*args):
self.debit('spawn');self.sequence+=1;self.events.append(dict(kind='spawn',name=name));self.proc[name]=SimpleNamespace(pid=self.sequence,poll=lambda:None,returncode=0)
def find(self,name):return dict(id=self.proc[name].pid,pid=self.proc[name].pid)
def owner(self,name):
n=self.find(name);n.update(window_rect=dict(width=640,height=575));return dict(owner=n,origin=[-320-self.scroll_x,0],scene=[-320-self.scroll_x,0,640,575],workspace=dict(id=20,output=self.expected_output),evidence='synthetic quota only',snapshot={})
calibrate=owner
def snapshot(self,tag):return dict(tree=dict(type='workspace',name='1',id=20,output=self.expected_output,mosaic=dict(rows=[dict(children=[1,2,3])]),nodes=[]))
def log(self,name):
if rid=='C6':
if name=='compositor':return 'Transaction 1 timed out (1 waiting)'
return 'ACK ns=1 serial=10 size=640x480\nCOMMIT ns=2 serial=10 size=640x480 color=303038\nHELD ns=3 serial=11\nACK ns=9 serial=11'
return (KIT/'wire-fixture.txt').read_text()
def capture(self,tag,out):
self.debit('capture');self.tag=tag;image=Image.new('RGB',(800,600),(48,48,56));image.info['tag']=tag;return image
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):
self.debit('move',*(['click'] if action!='move' else []),*(['grab'] if grab else []));self.events.append(dict(kind='injection',action=action,ns=time.monotonic_ns()))
def scroll(self,name,delta):self.debit('camera');self.cmd('synthetic scroll');self.scroll_x+=delta
def click(self,name,point,action='right',grab=False):self.inject(action,point,grab);return {'owner':''},{'owner':[]}
def delivery(self,*args):pass
def wait(self,*args,**kwargs):
if rid=='C6' and kwargs.get('seconds')==6:clock[0]+=5_000_000_000
def save(self,*args,**kwargs):pass
def close_client(self,*args):self.debit('configuration')
def client_cmd(self,*args):self.debit('configuration')
s=FakeSession();geo=dict(A=[-20,50,350,170],B=[-10,100,300,130])
if rid=='C2':geo=dict(A=[50,570,250,170],B=[70,590,170,130])
prot=v.grab((KIT/'wire-fixture.txt').read_text())
def counts(image,color):
if 'final' in image.info['tag'] or 'fully-hidden' in image.info['tag'] or image.info['tag']=='migrated-H2-H1':return 0
if 'B-closed' in image.info['tag'] and color==engine.COLORS['POPUP_B']:return 0
return 1
clock=[100_000_000]
with ExitStack() as stack:
for module,name,value in [(cases,'geometry',lambda *_:geo),(cases,'solid_point',lambda *_:[-250,100]),(run,'solid_point',lambda *_:[-250,100]),(cases,'count',counts),(run,'count',counts),(cases,'exact',lambda *_:True),(v,'selected_workspace',lambda *_:None),(v,'crosses',lambda *_:None),(v,'standard_spill',lambda *_:None),(v,'rgb',lambda *_:True),(cases,'dismissal',lambda *_:dict(status='synthetic quota only'))]:stack.enter_context(patch.object(module,name,side_effect=value))
import lifecycle
for name in ('explicit_child_close','a_survival','normal_owner_close'):stack.enter_context(patch.object(lifecycle,name))
stack.enter_context(patch.object(time,'sleep'))
if rid=='C1':run.horizontal(s)
elif rid=='C6':
import saved
def tick():clock[0]+=100_000_000;return clock[0]
stack.enter_context(patch.object(saved.time,'monotonic_ns',side_effect=tick))
stack.enter_context(patch.object(saved.Path,'read_bytes',return_value=b'compositor\0-Dtxn-timeout=5000\0'))
stack.enter_context(patch.object(saved,'pending_geometry',return_value=dict(held=dict(ns=1,serial=11))))
stack.enter_context(patch.object(saved,'held_configure',return_value=dict(ns=1,serial=11)))
stack.enter_context(patch.object(saved,'timeout_line',return_value='synthetic quota only'))
stack.enter_context(patch.object(saved,'released_configure',return_value=dict(status='synthetic quota only')))
saved.run(s)
elif rid=='C5':cases.hidden_campaign(s)
elif rid=='C7':
candidate=dict(workspace_id=20,output='HEADLESS-1',children=[1,2,3],viewport=[-800,0,800,600],scroll=0)
def dynamic_candidate(*args):
return dict(candidate,output=s.expected_output,viewport=next(o['logical'] for o in s.outputs if o['name']==s.expected_output))
stack.enter_context(patch.object(cases,'dynamic_geometry',side_effect=dynamic_candidate))
stack.enter_context(patch.object(cases,'dynamic_pixels',return_value=dict(status='synthetic quota only')))
s.owner=lambda name:dict(owner=dict(id=s.find(name)['id'],window_rect=dict(width=640,height=575)),origin=[-320,0],workspace=dict(id=20,output=s.expected_output),scene=[-320,0,640,575],snapshot={},evidence='synthetic quota only')
cases.dynamic_campaign(s)
elif rid=='P0':
cases.init_reference(s);state,baseline,p,g,left,right=cases.open_chain(s);run.standard_return(s,state,baseline,p,g,[left,right])
else:cases.popup_campaign(s)
return dict(s.actions)
def test_actual_p0_c1_handlers_capture_and_action_caps(self):
self.assertEqual(self.quota_scenario('P0')['capture'],10)
self.assertEqual(self.quota_scenario('C1')['capture'],16)
def test_actual_saved_handler_capture_caps(self):
self.assertEqual(self.quota_scenario('C6')['capture'],10)
def test_actual_hidden_dynamic_handlers_capture_caps(self):
self.assertEqual(self.quota_scenario('C5')['capture'],12)
self.assertEqual(self.quota_scenario('C7')['capture'],14)
def test_actual_other_popup_handlers_capture_caps(self):
self.assertEqual(self.quota_scenario('C2')['capture'],8)
self.assertEqual(self.quota_scenario('C3')['capture'],8)
self.assertEqual(self.quota_scenario('C4')['capture'],8)
# Their real Session.start adds exactly one calibrated-marker screenshot.
def test_marker_helper_is_reaped_separate_from_shm_client_closure(self):
s=engine.Session.__new__(engine.Session);s.helper_exits=[];s.record=Mock();p=Mock();p.pid=999999996;p.poll.return_value=None;p.wait.return_value=-15;p.stdin=io.StringIO();s.proc={'marker-background':p}
with patch.object(engine.os,'killpg') as kill:s.close_helper('marker-background')
kill.assert_called_once_with(p.pid,engine.signal.SIGTERM);p.wait.assert_called_once_with(timeout=2)
self.assertEqual(s.proc,{});self.assertEqual(s.helper_exits[0]['exit'],-15);self.assertFalse(s.helper_exits[0]['scientific_client'])
if __name__=="__main__":unittest.main(verbosity=2)

View file

@ -0,0 +1,115 @@
{
"baseline": "339dda45bc81b953e2f0afadf28765149e3a1ba1",
"deltas": [
"New V2 explicit canonical LAB and fixed14-run plan; old gate/run/prepare/replay/seal not copied",
"Durable full-kit+review+publication+binary binding and offline-only ledger namespace; no reset/refund",
"Socket-only /tmp/smx runtime, scrubbed environment, LAB-backed checked-length C SHM paths",
"Actual second-chain pre/post workspace/layout/PID/tiling validation and fresh ownerID/PID",
"P0 ten captures; C1 sixteen; C2 eight; C3/C4 nine including marker; C5 twelve; C6 ten; C7 fourteen with postclose pixels explicitly NOT_TESTED",
"Fullscreen/OOM/GPU/discriminant NOT_ADMITTED pending specific proof/hooks",
"Scientific closure includes archived same-name/already-exited clients and separates mechanical forced cleanup",
"No old raw replay; native generation/saved identity/complete damage/present/buffer/GPU claims NOT_PROVEN absent actual native evidence"
],
"historical_raw": "MISSING_NOT_RECOVERABLE",
"new_runtime": "NOT_RUN",
"parents": {
"cases.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "7ef309e39b7ac814246a0822428334cfce35d0b5c641ca7b220b0f4475709e4b",
"source": "tooling/probes/step20c-core-recovery/graphics/cases.py"
},
"clients/nested-client.c": {
"sha256": "c4baa574baf04c944f5b8b0012b434369a30afdbf3f989d6f26e554783f82d86",
"source": "tooling/probes/step20c-core-recovery/graphics/clients/nested-client.c"
},
"clients/pointer-daemon.c": {
"sha256": "8e4eaad95882d0d73866f801899007240b01cb6e15a712e820b3e3f71a78bbe5",
"source": "tooling/probes/step20c-minimal-core-gate/graphics/clients/pointer-daemon.c"
},
"clients/saved-client.c": {
"sha256": "3c78af047af5834957fee16a25e42f0bd6f02e85e4385a52116e9d5beb63e912",
"source": "tooling/probes/step20c-core-recovery/graphics/clients/saved-client.c"
},
"clients/static-reference.c": {
"sha256": "e346a85ded3345b232cd6edca5a1ac57aebfd548a60e12b3c47a5cf515e6c50e",
"source": "tooling/probes/step20c-minimal-core-gate/graphics/clients/static-reference.c"
},
"clients/vertical-client.c": {
"sha256": "63b7e1615a452a87f4d790e46456a7cc66d58cc2755ca2801fc1ab23c8e9b179",
"source": "tooling/probes/step20c-core-recovery/graphics/clients/vertical-client.c"
},
"engine.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "c6fd4118dd1def6f2dede2eaa4a6c1461a47b3fcd2ce8d6a40577b381ffd24e5",
"source": "tooling/probes/step20c-core-recovery/graphics/engine.py"
},
"geometry.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "76a80e98887d3a3707ee942b48a49c1850cdc4aeeb28237d9fea33fa3470fb12",
"source": "tooling/probes/step20c-core-recovery/graphics/geometry.py"
},
"ipc_predicates.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "5354ba53e1b3f8d0026f4475beebee58d093a81db7d26304cad7085ae3efd352",
"source": "tooling/probes/step20c-core-recovery/graphics/ipc_predicates.py"
},
"lifecycle.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "df0c11027b3b8b0ef371ddb6ec4bcfd28dac09835644d0c3ce6e273d5e565e92",
"source": "tooling/probes/step20c-core-recovery/graphics/lifecycle.py"
},
"model.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "a578fc589fb092dae3ccdcf8c4eec12a97e515f721decc4c968078dedcb2367a",
"source": "tooling/probes/step20c-core-recovery/graphics/model.py"
},
"pixels.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "d315ddad978238ffbf1c8e4d712d4608ba23564703332d814f627f57f7b6e7f5",
"source": "tooling/probes/step20c-core-recovery/graphics/pixels.py"
},
"predicates.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "222a94764bfe6d76f0b7bcdab4b28b4d90cccb479af49b87e778813f0bdc3a71",
"source": "tooling/probes/step20c-core-recovery/graphics/predicates.py"
},
"protocols/wlr-virtual-pointer-unstable-v1.xml": {
"classification": "REUSED_VERSIONED_SOURCE",
"sha256": "3ff6d540be0bc5228195bf072bde42117ea17945a5c2061add5d3cf97d6bb524",
"source": "tooling/probes/step20c-valid-grab/wlr-virtual-pointer-unstable-v1.xml"
},
"protocols/xdg-shell.xml": {
"classification": "SYSTEM_PROTOCOL_SOURCE",
"sha256": "7ba7f9c8473deee674cb1f154a18abd0bb0cc072604fc055b0c15e459fc4c7df",
"source": "/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml"
},
"saved.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "f3e969781c1f0c90094babad0dffb08f63544a03da4c084d2fb4c3bdb37d9abf",
"source": "tooling/probes/step20c-core-recovery/graphics/saved.py"
},
"saved_validators.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "b412fedc24869274c8b1506a2800c8d4815c93df859785c6e96f719d692014af",
"source": "tooling/probes/step20c-core-recovery/graphics/saved_validators.py"
},
"validators.py": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "dfc3e0c6a57b032a311a7ccfc3ac0f30447f9029fa933819bd65f2610d763908",
"source": "tooling/probes/step20c-core-recovery/graphics/validators.py"
},
"wire-fixture.txt": {
"classification": "REUSED_VERSIONED_SOURCE_WITH_DECLARED_V2_DELTAS",
"sha256": "c6c9fc072f78fbcf9cfdeebcc5becdbdfb61824352495a0e767d7d390267f640",
"source": "tooling/probes/step20c-core-recovery/graphics/wire-fixture.txt"
}
},
"retained_core_traces": {
"PI_OPT": "REMOVED",
"PROBE_POPUP_CLIP": "owner=%p local=%d,%d %dx%d",
"PROBE_POPUP_HIDDEN_OWNER": "owner=%p applied=%d,%d %dx%d viewport=%d,%d %dx%d",
"SPIKE_CLIP": "tree=%p rect=%d,%d %dx%d",
"SPIKE_DAMAGE": "REMOVED",
"temporal_neutrality": "NOT_PROVEN"
}
}

View file

@ -0,0 +1,21 @@
"""Exact binary RGB masks with explicit output origin, clip and occlusion.
Screenshots prove color/visible geometry only, never native-buffer identity.
"""
from PIL import Image,ImageChops,ImageDraw
from model import *
COLORS=dict(TOPLEVEL=(35,68,204),POPUP_A=(224,192,32),POPUP_B=(32,208,160))
def color_geometry(im,target,rect,output,clip,occluders=()):
require(im.size==(output.rectangle.width,output.rectangle.height),'replay-output-size')
visible=intersect(rect,clip) if clip else rect
expected=Image.new('L',im.size,0);draw=ImageDraw.Draw(expected)
box=to_png(visible,output)
if box.width and box.height:draw.rectangle((box.x,box.y,box.end[0]-1,box.end[1]-1),fill=255)
for occ in occluders:
ob=to_png(occ,output)
if ob.width and ob.height:draw.rectangle((ob.x,ob.y,ob.end[0]-1,ob.end[1]-1),fill=0)
actual=Image.new('L',im.size);actual.putdata([255 if px==COLORS[target] else 0 for px in im.get_flattened_data()])
require(ImageChops.difference(expected,actual).getbbox() is None,'replay-paint-'+target)
return dict(count=sum(actual.histogram()[1:]),bbox=actual.getbbox())

View file

@ -0,0 +1,22 @@
"""Frozen V2 intent. Admission is independent of intent; no calibration/retry runs."""
from copy import deepcopy
CAPS=dict(P0=10,P1=10,C1=18,C2=12,C3=12,C4=12,C5=12,C6=12,C7=14,C8=12,O1=8,O2=8,G2=16,R1=14)
LIMITS=dict(runs=14,captures=180,captures_per_run=18,duration_s=150)
def output(name,logical,mode=None,scale=1,transform='normal'):
return dict(name=name,logical=logical,mode=mode or logical[2:],scale=scale,transform=transform)
H=[output('HEADLESS-1',[-800,0,800,600]),output('HEADLESS-2',[0,0,800,600])]
RUNS={rid:dict(id=rid,binary='pristine' if rid in ('P0','P1') else 'core',mode='pristine' if rid in ('P0','P1') else 'mosaic',outputs=deepcopy(H),client='nested-client',placement='static_cross',axis=0,boundary=0,capture_limit=cap,action_limits=dict(spawn=12,configuration=70,mutation=26,move=24,click=12,grab=4,camera=6,chain=2),admission='PENDING_INDEPENDENT_REVIEW') for rid,cap in CAPS.items()}
RUNS['C2'].update(outputs=[output('HEADLESS-1',[0,0,800,600]),output('HEADLESS-2',[0,600,800,600])],client='vertical-client',placement='v_both_cross',axis=1,boundary=600)
RUNS['C3']['outputs'][0]=output('HEADLESS-1',[-800,0,800,600],[1000,750],1.25)
RUNS['C4']['outputs'][0]=output('HEADLESS-1',[-800,0,800,600],[750,1000],1.25,'90')
# Geometry certificates and distinct diagnostics are prerequisite source evidence.
for rid in ('P1','C8'):
RUNS[rid].update(admission='NOT_ADMITTED',reason='No offline equal-child nonleaf fullscreen configure/crossing certificate; no empirical calibration authorized')
for rid in ('O1','O2','G2','R1'):
RUNS[rid].update(admission='NOT_ADMITTED',reason='Separately reviewed diagnostic/discriminant source hook and exact binary unavailable')
assert len(RUNS)==14 and sum(CAPS.values())==170 and max(CAPS.values())==18
def config(spec):
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 spec['outputs'])
return 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'
for spec in RUNS.values():spec['config']=config(spec)

View file

@ -0,0 +1,124 @@
"""Shared offline/live predicates: facts precede scientific classification.
CONTRACT: full RGB comparisons have no mask/tolerance; grabs require real logs.
INVARIANT: dismissal, client destruction, clipping and layout remain distinct.
"""
import re
from model import Rect,Space,Provenance,Output,popup,crossing,local_clip_to_global,require
from pixels import color_geometry,COLORS
from PIL import Image,ImageChops
class Defect(RuntimeError):
"""A directly measured scientific contract failure, distinct from fixture ambiguity."""
def paint(im,target):
im=im.convert('RGB');assert im.size==(800,600)
mask=Image.new('L',im.size);mask.putdata([255 if p==COLORS[target] else 0 for p in im.get_flattened_data()])
return dict(count=sum(mask.histogram()[1:]),bbox=mask.getbbox())
def point(im,target,origin):
box=paint(im,target)['bbox'];assert box,('no measured paint',target)
# WHY: A may be occluded by B; bbox center alone is not a valid hit point.
x1,y1,x2,y2=box
for y in range(y1+10,y2-10,5):
for x in range(x1+10,x2-10,5):
if all(im.getpixel((xx,yy))==COLORS[target] for yy in range(y-8,y+9) for xx in range(x-8,x+9)):
return [x+origin,y]
raise AssertionError('no solid measured interior '+target)
def equal(a,b):
assert a.size==b.size==(800,600)
rows=[(i%800,i//800,x,y) for i,(x,y) in enumerate(zip(a.get_flattened_data(),b.get_flattened_data())) if x!=y]
return dict(equal=not rows,changed=len(rows),bbox=ImageChops.difference(a,b).getbbox(),pixels=rows)
def reference(a,b):
result=equal(a,b)
assert result['equal'] and all(c==(48,48,56) for c in a.get_flattened_data()),'unstable reference'
return result
def configured(text,name):
rows=re.findall(rf'{name} ROLE_CONFIGURE x=(-?\d+) y=(-?\d+) w=(\d+) h=(\d+)',text)
assert rows,(name,'no configure')
return list(map(int,rows[-1]))
def geometry(text,origin,provenance=None):
a=configured(text,'POPUP_A');b=configured(text,'POPUP_B')
require(provenance is not None,'popup-owner-provenance-required')
p=provenance
top=Rect(Space.GLOBAL,*origin,0,0,p)
ids={n:list(map(int,re.search(rf'{n} CREATE wl=(\d+) xdg=(\d+) role=(\d+)',text).groups())) for n in ('TOPLEVEL','POPUP_A','POPUP_B')}
result={}
parent=top
for key,name,parent_name,c in [('A','POPUP_A','TOPLEVEL',a),('B','POPUP_B','POPUP_A',b)]:
parent_id=int(re.search(rf'{name} CREATE .*parent_xdg=(\d+)',text)[1])
ack=int(re.findall(rf'{name} XDG_CONFIGURE serial=(\d+) ack',text)[-1])
parent=popup(parent,Rect(Space.POPUP,*c,p),parent_id,ids[parent_name][1],ack,name+' MAP ' in text)
result[key]=parent.values()
result.update(configured_A=a,configured_B=b,origin=origin,provenance=dict(owner=p.owner,workspace=p.workspace,generation=p.generation,evidence=p.evidence,state=p.state),
crossing={key:crossing(Rect(Space.GLOBAL,*result[key],p),0) for key in ('A','B')})
return result
def mapped(text):
for name in ['POPUP_A','POPUP_B']:
assert text.count(name+' MAP ')==1 and name+' POPUP_DONE ' not in text and name+' DESTROY ' not in text,(name,'not mapped')
def protocol(text):
assert not re.search(r'wl_display[^\n]*\.error\(|protocol error|invalid_popup_parent|not_the_topmost_popup',text,re.I),'protocol error'
mapped(text)
ids={}
for name in ['TOPLEVEL','POPUP_A','POPUP_B']:
m=re.search(rf'{name} CREATE wl=(\d+) xdg=(\d+) role=(\d+)',text);assert m
ids[name]=list(map(int,m.groups()))
assert len({n for v in ids.values() for n in v})==9,'object identities reused'
grabs=[]
for name,parent in [('POPUP_A','TOPLEVEL'),('POPUP_B','POPUP_A')]:
create=re.search(rf'{name} CREATE .*parent={parent} parent_xdg=(\d+)',text);assert create
assert int(create[1])==ids[parent][1], 'wrong XDG parent'
debug_parent=re.search(rf'xdg_surface#{ids[name][1]}\.get_popup\(new id xdg_popup#{ids[name][2]}, xdg_surface#{ids[parent][1]}, xdg_positioner#\d+\)',text)
require(debug_parent is not None,'debug-parent-request')
m=re.search(rf'{name} GRAB_REQUEST origin=wl_pointer.button target={parent} serial=(\d+) used=(\d+)',text);assert m
serial,used=map(int,m.groups());assert serial==used and 0<serial<=0xffffffff
button=f'POINTER_BUTTON target={parent} serial={serial} button=272 state=1'
assert text.index(button)<m.start(),'grab serial not from earlier button'
debug_button=re.search(rf'wl_pointer#\d+\.button\({serial}, \d+, 272, 1\)',text)
require(debug_button is not None and debug_button.start()<m.start(),'debug-real-button-serial')
role=text.index(name+' ROLE_CONFIGURE ');cfg=re.search(rf'{name} XDG_CONFIGURE serial=(\d+) ack',text);assert cfg
mp=text.index(name+' MAP ')
assert m.start()<role<cfg.start()<mp,'configure ACK map order'
popup_role=ids[name][2];xdg=ids[name][1];wl=ids[name][0]
# WAYLAND_DEBUG is independent corroboration, not just fixture claims.
request=re.search(rf'xdg_popup#{popup_role}\.grab\(wl_seat#\d+, {serial}\)',text);assert request
ack=re.search(rf'xdg_surface#{xdg}\.ack_configure\({cfg[1]}\)',text);assert ack
attach=re.search(rf'wl_surface#{wl}\.attach\(',text);assert attach
commits=list(re.finditer(rf'wl_surface#{wl}\.commit\(\)',text));assert len(commits)>=2
assert request.start()<commits[0].start()<role<ack.start()<attach.start()<commits[1].start()<mp
actual=configured(text,name)
require(re.search(rf'xdg_popup#{popup_role}\.configure\({actual[0]}, {actual[1]}, {actual[2]}, {actual[3]}\)',text) is not None,'debug-popup-configure')
require(re.search(rf'xdg_surface#{xdg}\.configure\({cfg[1]}\)',text) is not None,'debug-xdg-configure')
native_attach=re.search(rf'wl_surface#{wl}\.attach\(wl_buffer#(\d+), 0, 0\)',text[ack.start():mp])
require(native_attach is not None,'popup-native-attach')
native_buffer=int(native_attach[1])
native_create=re.search(rf'create_buffer\(new id wl_buffer#{native_buffer}, 0, {actual[2]}, {actual[3]}, {actual[2]*4}, 1\)',text[role:mp])
require(native_create is not None,'popup-native-configured-size')
if parent=='POPUP_A':assert text.index('POPUP_A MAP ')<text.index(button)
grabs.append(dict(popup=name,parent=parent,serial=serial,used=used,origin='wl_pointer.button',ids=ids[name],ack=int(cfg[1]),native_buffer=native_buffer,native_size=actual[2:]))
assert grabs[0]['serial']<grabs[1]['serial'], 'distinct ordered serials'
return dict(ids=ids,grabs=grabs,hierarchy='TOPLEVEL -> POPUP_A -> POPUP_B',status='PASS')
def pair(lines,target):
events=[]
for line in lines:
m=re.fullmatch(r'POINTER_BUTTON target=(\w+) serial=(\d+) button=(\d+) state=(\d+)',line);assert m
events.append([m[1],*map(int,m.groups()[1:])])
if len(events)!=2 or any(e[0]!=target for e in events) or [e[2:] for e in events]!=[[273,1],[273,0]]:
raise Defect('wrong actual button recipient/pair: '+str(events))
assert 0<events[0][1]<events[1][1]<=0xffffffff
return events
def dismissal(text,buttons):
if any('target=POPUP_A ' in b or 'target=POPUP_B ' in b for b in buttons):
raise Defect('invisible popup received actual button')
done=re.findall(r'(POPUP_[AB]) POPUP_DONE ',text)
destroyed=re.findall(r'(POPUP_[AB]) DESTROY ',text)
assert done==['POPUP_B','POPUP_A'] and destroyed==['POPUP_B','POPUP_A'],('dismissal order',done,destroyed)
return dict(done=done,destroyed=destroyed,invisible_buttons=buttons,status='PASS',meaning='outside dismissal distinct from invisible hit')

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""Generate protocols and compile C17 clients, without executing any client."""
import argparse,json,shlex,subprocess
from pathlib import Path
from gate import canonical_lab,clean_environment,durable,sha,need
def prepare(lab):
lab=canonical_lab(lab);src=Path(__file__).resolve().parent;build=lab/"graphics-tests/client-build";build.mkdir(parents=True,exist_ok=False)
env=clean_environment(lab);commands=[]
def invoke(argv):
r=subprocess.run(list(map(str,argv)),env=env,capture_output=True,text=True,timeout=30)
commands.append(dict(argv=list(map(str,argv)),exit=r.returncode,stdout=r.stdout,stderr=r.stderr))
durable(lab/"results/graphics-client-compile.json",dict(status="PENDING" if r.returncode==0 else "FAIL",commands=commands,runtime="NOT_RUN"))
need(r.returncode==0,"client build command failed");return r.stdout.strip()
versions={name:invoke([name,"--version"]) for name in ("cc","wayland-scanner","pkg-config")}
flags=shlex.split(invoke(["pkg-config","--cflags","--libs","wayland-client"]))
for protocol,xml in (("xdg-shell","xdg-shell.xml"),("virtual-pointer","wlr-virtual-pointer-unstable-v1.xml")):
invoke(["wayland-scanner","client-header",src/"protocols"/xml,build/(protocol+"-client.h")])
invoke(["wayland-scanner","private-code",src/"protocols"/xml,build/(protocol+"-protocol.c")])
for name,protocol in (("nested-client","xdg-shell"),("vertical-client","xdg-shell"),("saved-client","xdg-shell"),("static-reference","xdg-shell"),("pointer-daemon","virtual-pointer")):
invoke(["cc","-std=c17","-O2","-Wall","-Wextra","-I",build,src/"clients"/(name+".c"),build/(protocol+"-protocol.c"),"-o",build/name,*flags])
durable(lab/"results/graphics-client-compile.json",dict(status="PASS",commands=commands,versions=versions,inputs={str(p.relative_to(src)):sha(p) for folder in ("clients","protocols") for p in (src/folder).iterdir()},generated={str(p.relative_to(build)):sha(p) for p in build.iterdir()},runtime="NOT_RUN"))
if __name__=="__main__":
p=argparse.ArgumentParser();p.add_argument("--lab",required=True);a=p.parse_args();prepare(a.lab)

View file

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_virtual_pointer_unstable_v1">
<copyright>
Copyright © 2019 Josef Gajdusek
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<interface name="zwlr_virtual_pointer_v1" version="2">
<description summary="virtual pointer">
This protocol allows clients to emulate a physical pointer device. The
requests are mostly mirror opposites of those specified in wl_pointer.
</description>
<enum name="error">
<entry name="invalid_axis" value="0"
summary="client sent invalid axis enumeration value" />
<entry name="invalid_axis_source" value="1"
summary="client sent invalid axis source enumeration value" />
</enum>
<request name="motion">
<description summary="pointer relative motion event">
The pointer has moved by a relative amount to the previous request.
Values are in the global compositor space.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="dx" type="fixed" summary="displacement on the x-axis"/>
<arg name="dy" type="fixed" summary="displacement on the y-axis"/>
</request>
<request name="motion_absolute">
<description summary="pointer absolute motion event">
The pointer has moved in an absolute coordinate frame.
Value of x can range from 0 to x_extent, value of y can range from 0
to y_extent.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="x" type="uint" summary="position on the x-axis"/>
<arg name="y" type="uint" summary="position on the y-axis"/>
<arg name="x_extent" type="uint" summary="extent of the x-axis"/>
<arg name="y_extent" type="uint" summary="extent of the y-axis"/>
</request>
<request name="button">
<description summary="button event">
A button was pressed or released.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="button" type="uint" summary="button that produced the event"/>
<arg name="state" type="uint" enum="wl_pointer.button_state" summary="physical state of the button"/>
</request>
<request name="axis">
<description summary="axis event">
Scroll and other axis requests.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="axis" type="uint" enum="wl_pointer.axis" summary="axis type"/>
<arg name="value" type="fixed" summary="length of vector in touchpad coordinates"/>
</request>
<request name="frame">
<description summary="end of a pointer event sequence">
Indicates the set of events that logically belong together.
</description>
</request>
<request name="axis_source">
<description summary="axis source event">
Source information for scroll and other axis.
</description>
<arg name="axis_source" type="uint" enum="wl_pointer.axis_source" summary="source of the axis event"/>
</request>
<request name="axis_stop">
<description summary="axis stop event">
Stop notification for scroll and other axes.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="axis" type="uint" enum="wl_pointer.axis" summary="the axis stopped with this event"/>
</request>
<request name="axis_discrete">
<description summary="axis click event">
Discrete step information for scroll and other axes.
This event allows the client to extend data normally sent using the axis
event with discrete value.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="axis" type="uint" enum="wl_pointer.axis" summary="axis type"/>
<arg name="value" type="fixed" summary="length of vector in touchpad coordinates"/>
<arg name="discrete" type="int" summary="number of steps"/>
</request>
<request name="destroy" type="destructor" since="1">
<description summary="destroy the virtual pointer object"/>
</request>
</interface>
<interface name="zwlr_virtual_pointer_manager_v1" version="2">
<description summary="virtual pointer manager">
This object allows clients to create individual virtual pointer objects.
</description>
<request name="create_virtual_pointer">
<description summary="Create a new virtual pointer">
Creates a new virtual pointer. The optional seat is a suggestion to the
compositor.
</description>
<arg name="seat" type="object" interface="wl_seat" allow-null="true"/>
<arg name="id" type="new_id" interface="zwlr_virtual_pointer_v1"/>
</request>
<request name="destroy" type="destructor" since="1">
<description summary="destroy the virtual pointer manager"/>
</request>
<!-- Version 2 additions -->
<request name="create_virtual_pointer_with_output" since="2">
<description summary="Create a new virtual pointer">
Creates a new virtual pointer. The seat and the output arguments are
optional. If the seat argument is set, the compositor should assign the
input device to the requested seat. If the output argument is set, the
compositor should map the input device to the requested output.
</description>
<arg name="seat" type="object" interface="wl_seat" allow-null="true"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="id" type="new_id" interface="zwlr_virtual_pointer_v1"/>
</request>
</interface>
</protocol>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""WHY/CONTRACT/INVARIANT: reserve once, reviewed bytes only, no retry."""
import argparse,time,re
from gate import Ledger,need
from plans import RUNS
from engine import Session
import cases,validators
from geometry import *
from ipc_predicates import ancestry
def normal_remaining(s):
for n in list(s.proc):
if n not in ('owner','compositor','pointer') and s.proc[n].poll() is None:s.close_client(n,'close')
def standard_return(s,state,baseline,p,g,existing_images=None):
oid=state['owner']['id'];s.expected_layout='splith'
if existing_images is None:s.cmd(f'[con_id={oid}] layout splith',True);time.sleep(.4)
state=s.owner('owner');prot=validators.grab(s.log('owner'));need(prot['ids']==p['ids'],'live second chain preserved')
geo=cases.geometry(s.log('owner'),state['origin'],cases.Provenance(oid,state['workspace']['id'],'NOT OBSERVABLE','pointer+paint corroboration'))
images=existing_images if existing_images is not None else s.pair_capture('standard-live');validators.standard_spill(images,COLORS)
for target,key,cmd in [('POPUP_B','B','close_b'),('POPUP_A','A',None)]:
state=s.owner('owner');geo=cases.geometry(s.log('owner'),state['origin'],cases.Provenance(oid,state['workspace']['id'],'NOT OBSERVABLE','fresh current pointer/paint candidate'));before_input=s.log('owner');im=images[1];xy=solid_point(im,COLORS[target],s.outputs[1],s.frames['HEADLESS-2'],geo[key]);tails,buttons=s.click('owner',xy);s.delivery('owner',geo[key],xy,tails,buttons,target)
if target=='POPUP_A':
from lifecycle import a_survival
a_survival(images[1],before_input,s.log('owner'),p['ids'],buttons['owner'],xy,geo['A'])
if cmd:
before=s.log('owner');request=time.monotonic_ns();s.client_cmd('owner',cmd,'COMMAND close_b DONE');time.sleep(.2)
from lifecycle import explicit_child_close
explicit_child_close(before,s.log('owner'),p['ids'],request,time.monotonic_ns())
images=s.pair_capture('B-closed-A-survives');need(count(images[1],COLORS['POPUP_A'])>0 and count(images[1],COLORS['POPUP_B'])==0,'A not alive/B residual')
before_close=s.log('owner');s.close_client('owner')
from lifecycle import normal_owner_close
normal_owner_close(before_close,s.log('owner'),p['ids'],s.proc['owner'].returncode)
final=s.pair_capture('standard-final');validators.rgb(baseline,final[1])
return 'PARTIALLY_FEASIBLE'
def horizontal(s):
cases.init_reference(s);state,baseline,p,g,left,right=cases.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,'forbidden interior');point=[forbidden[0]+forbidden[2]//2,forbidden[1]+forbidden[3]//2]
tails,buttons=s.click('owner',point);proof=cases.dismissal(tails['owner'],buttons['owner']);s.save('dismissal',proof);s.close_client('owner');s.save('first-chain-protocol-log',dict(raw=s.log('owner')))
# Two independent real chains; no resurrected dismissed popup.
old_id=state['owner']['id'];old_pid=state['owner']['pid'];state,baseline2,p,g,left,right=cases.open_chain(s);need(state['owner']['id']!=old_id and state['owner']['pid']!=old_pid,'second chain must have fresh owner/PID');return standard_return(s,state,baseline2,p,g)
COLORS=cases.COLORS
def execute(rid,lab,manifest,review,publication,session_factory=Session):
auth=Ledger(lab).admit(rid,manifest,review,publication);s=None;status='INCONCLUSIVE';failure=None
try:
s=session_factory(RUNS[rid],auth);s.start()
if rid=='C1':status=horizontal(s)
elif rid=='C5':status=cases.hidden_campaign(s)
elif rid=='C6':
from saved import run
status=run(s)
elif rid=='C7':status=cases.dynamic_campaign(s)
elif rid=='P0':
cases.init_reference(s);state,baseline,p,g,left,right=cases.open_chain(s)
status=standard_return(s,state,baseline,p,g,[left,right])
elif rid in ('C2','C3','C4'):status=cases.popup_campaign(s)
else:raise ValueError('NOT_ADMITTED scenario')
normal_remaining(s)
except Exception as error:
failure=f'{type(error).__name__}: {error}';status='INCONCLUSIVE'
finally:
if s is not None:status=s.cleanup(status,failure)
else:Ledger(lab).complete(auth,dict(status='INCONCLUSIVE',failure=failure,session_constructed=False))
return dict(status=status,failure=failure,runner_exit=0 if status=='PARTIALLY_FEASIBLE' else 1)
def main():
p=argparse.ArgumentParser(description='One independently admitted run; never all-cases or retry')
p.add_argument('run_id',choices=RUNS);p.add_argument('--lab',required=True);p.add_argument('--manifest',required=True);p.add_argument('--review',required=True);p.add_argument('--publication',required=True)
a=p.parse_args();result=execute(a.run_id,a.lab,a.manifest,a.review,a.publication);print(result);return result['runner_exit']
if __name__=='__main__':raise SystemExit(main())

View file

@ -0,0 +1,30 @@
"""One actual held→natural-timeout episode, exact binary, EXPERIMENTAL."""
import re,time
from pathlib import Path
import cases,engine
from geometry import need
from saved_validators import pending_geometry,held_configure,saved_identity,natural_retirement,rgb_exact,timeout_line,released_configure
def run(s):
cases.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=cases.stable_reference(s)
initial=s.snapshot('initial-applied');before=s.log('owner');acks=re.findall(r'ACK ns=\d+ serial=(\d+)',before);need(acks,'initial actual ACK');prior=int(acks[-1])
argv=Path(f'/proc/{s.comp.pid}/cmdline').read_bytes().split(b'\0');need(b'-Dtxn-timeout=5000' in argv,'actual startup timeout5000')
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(initial,pending,state['owner']['id'],state['workspace']['id'],before,s.log('owner')[cut:],prior,request)
held_start=time.monotonic_ns();held=s.pair_capture('held');held_end=time.monotonic_ns();need(held_start>proof['held']['ns'] and held_end<request+4_700_000_000,'held capture before expiration')
commits=re.findall(r'COMMIT ns=\d+ serial=\d+ size=\d+x\d+ color=([0-9a-f]+)',before);need(commits,'actual retained SHM color');value=int(commits[-1],16);color=((value>>16)&255,(value>>8)&255,value&255)
rgb_exact(baseline,held[1]);need(any(p==color for p in held[0].getdata()),'owner retained SHM color visible H1')
native=None
if False:native=saved_identity(s.log('compositor'),state['owner']['id'],request)
s.wait(lambda:re.search(r'Transaction .*timed out \(\d*[1-9]\d* waiting\)',s.log('compositor')[ccut:]),seconds=6)
observed=time.monotonic_ns();need(s.proc['owner'].poll() is None,'owner alive natural timeout');hold=held_configure(before,s.log('owner')[cut:],prior)
timeout=timeout_line(s.log('compositor')[ccut:],-1,True,request,observed,2**63)
after_start=time.monotonic_ns();after=s.pair_capture('natural-timeout');rgb_exact(baseline,after[1]);release=time.monotonic_ns();s.client_cmd('owner','release_configure','COMMAND release_configure DONE');s.wait(lambda:re.search(r'ACK ns=\d+ serial='+str(proof['held']['serial'])+r'\b',s.log('owner')[cut:]));live=s.pair_capture('restored-live');rgb_exact(baseline,live[1])
if native:
native=saved_identity(s.log('compositor'),state['owner']['id'],request,True)
retirement=natural_retirement(s.log('compositor'),native,after_start,time.monotonic_ns(),True,before,s.log('owner')[cut:],prior)
else:retirement={'status':'NOT OBSERVABLE; CORE has no native saved identity'}
# WHY CONTRACT INVARIANT: CPU destruction is measured separately from GPU
# completion, and process exit0 alone never qualifies Wayland cleanup.
s.save('saved-evidence',dict(request_ns=request,held_start_ns=held_start,held_end_ns=held_end,timeout_observed_ns=observed,timeout_native=timeout,geometry=proof,native=native,retirement=retirement,held_wire=hold,post_release=released_configure(hold,s.log('owner')[cut:],release,observed,s.proc['owner'].poll() is None),gpu_completion='NOT PROVEN',native_generation='NOT PROVEN',binary=s.auth))
s.close_client('owner','close');final=s.pair_capture('final');rgb_exact(baseline,final[1]);return 'PARTIALLY_FEASIBLE'

View file

@ -0,0 +1,55 @@
"""Local pure CORE saved evidence; no diagnostic/historical import."""
import re
from geometry import need,intersection
from ipc_predicates import workspace,nodes
from PIL import ImageChops
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 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 rgb_exact(a,b):
need(a.mode==b.mode=='RGB' and a.size==b.size,'whole RGB contract')
need(ImageChops.difference(a,b).getbbox() is None,'whole RGB equal; no masked channel/ROI');return True
def timeout_line(text,activation_line,client_alive,request_ns,observed_ns,cleanup_ns):
need(client_alive and request_ns+4_700_000_000<=observed_ns<cleanup_ns,'natural timeout window/client alive')
matches=[(i,l) for i,l in enumerate(text.splitlines()) if i>activation_line and re.search(r'Transaction .*timed out \(\d*[1-9]\d* waiting\)',l)]
need(len(matches)==1,'native natural timeout required');return matches[0]
def saved_identity(*args,**kwargs):raise ValueError("CORE native saved identity NOT OBSERVABLE")
def natural_retirement(*args,**kwargs):raise ValueError("CORE retirement NOT OBSERVABLE")
def released_configure(held,after,release_ns,timeout_ns,client_alive=True):
"""POST-RELEASE accepts the ACK forbidden in the immutable HOLD prefix."""
need(client_alive and held['ns']<timeout_ns<release_ns,'HOLD timeout release phase order')
serial=held['serial']
a=re.findall(rf'ACK ns=(\d+) serial={serial}\b',after)
c=re.findall(rf'COMMIT ns=(\d+) serial={serial}\b',after)
need(len(a)==1 and len(c)==1,'unique released ACK/commit')
ack,commit=int(a[0]),int(c[0])
need(release_ns<ack<=commit,'release precedes live ACK and commit')
need(re.search(rf'ack_configure\({serial}\)',after),'released ACK actual wire')
return dict(serial=serial,release_ns=release_ns,ack_ns=ack,commit_ns=commit,status='POST_RELEASE_LIVE')

View file

@ -0,0 +1,74 @@
"""Imported live/offline scientific predicates, not a parallel test model."""
import re
from geometry import need,exact,crossing,expected_outputs
from predicates import protocol
def client_exit(log,code):
if 'TOPLEVEL CREATE ' in log:
order=re.findall(r'(POPUP_[AB]|TOPLEVEL) DESTROY',log)
need(order in (['POPUP_B','POPUP_A','TOPLEVEL'],['TOPLEVEL']),'popup child-first destruction order')
need(log.index('CLOSE_RECEIVED')<log.index('TOPLEVEL DESTROY'),'close precedes destruction')
need('CLOSE_RECEIVED' in log,'explicit close receipt absent')
releases=re.findall(r'SHM_CLOSURE created=(\d+) released=(\d+)',log)
need(len(releases)==1 and int(releases[0][0])>0 and releases[0][0]==releases[0][1],'client SHM release incomplete/unobserved')
need(code==0,'client nonzero');errors=re.findall(r'EXIT[^\n]*error=(\d+)',log)
need(bool(errors) and all(e=='0' for e in errors),'client error/nonobservable exit')
need(not re.search(r'protocol error|wl_display[^\n]*\.error\(',log,re.I),'wire error')
def window(start,end,events):
need(start<end and len(events)==1 and start<=events[0]<=end,'ambiguous event window')
def owner(node,owner_id,workspace_id,path):
need(node['id']==owner_id and [n['id'] for n in path if n['type']=='workspace']==[workspace_id],'wrong owner ancestry')
def rgb(reference,actual,masked=False):
need(not masked,'H2 occlusion/mask forbidden');return exact(reference,actual)
def grab(log):return protocol(log)
def applied(geometry,paint_origin,pointer_origin,state):
need(state=='applied' and geometry==paint_origin==pointer_origin,'pending/uncorroborated origin')
def crosses(rect,axis,boundary):need(crossing(rect,axis,boundary),'crossing not exercised')
def shadow(before,after):need(before.tobytes()!=after.tobytes(),'shadow not exercised')
def saved_identity(identity,binary_sha):
need(identity['binary_sha256']==binary_sha,'wrong binary saved identity')
need(identity.get('native') is True,'saved identity not observable')
def camera_eligible(path,ws):
# Null flags are legitimate on IPC descriptors; branch membership remains
# authoritative even when a child omits its floating flag.
floating=any((n.get('floating') or 'auto_off').endswith('on') for n in path)
floating |= any(c in p.get('floating_nodes',[]) for p,c in zip(path,path[1:]))
return ws.get('layout')=='mosaic' and not floating and not any(n.get('type')=='con' and n.get('fullscreen_mode') for n in path)
def owner_context(node,path,pid,workspace_name,output,layout):
need(path and path[-1]==node and node.get('pid')==pid,'owner path/pid mismatch')
ws=[n for n in path if n.get('type')=='workspace'];outs=[n for n in path if n.get('type')=='output']
need(len(ws)==len(outs)==1,'owner ancestry must include workspace/output')
need(ws[0].get('name')==workspace_name and ws[0].get('output')==output and outs[0].get('name')==output and ws[0].get('layout')==layout,'wrong mapped workspace/output/layout')
need(not any(c in p.get('floating_nodes',[]) for p,c in zip(path,path[1:])),'owner floating ancestry')
need(not any((n.get('floating') or 'auto_off').endswith('on') for n in path),'owner floating flag')
owner(node,node['id'],ws[0]['id'],path)
return ws[0]
def selected_workspace(snapshot,name,output,layout):
from ipc_predicates import workspace
ws=workspace(snapshot['tree'],name)
need(ws.get('output')==output and ws.get('layout')==layout,'pre-map workspace/output/layout')
rows=[r for r in snapshot['workspaces'] if r.get('name')==name]
need(len(rows)==1 and rows[0].get('focused') and rows[0].get('output')==output,'pre-map workspace not selected')
return ws
def fullscreen_ancestor(path):
rows=[n for n in path[:-1] if n.get('type')=='con' and n.get('fullscreen_mode') and n.get('nodes')]
need(rows,'nonleaf current fullscreen ancestor NOT EXERCISED')
return rows[-1]
def hidden_survival(log,initial,injections):
need(not any(e.get('action')!='move' for e in injections),'hide/return contaminated by dismissal click')
fresh=grab(log)
need(fresh['ids']==initial['ids'] and fresh['grabs']==initial['grabs'],'same live grabbed chain required')
return fresh
def standard_spill(images,colors):
# Native clip identity is unavailable on CORE: demonstrate effective removal
# through both continued popup paints, then freshly corroborated pointer input.
need(all(any(px==colors[n] for px in images[1].get_flattened_data()) for n in ('POPUP_A','POPUP_B')),'standard continuation for both A/B NOT EXERCISED')
def evidence_identity(record,binary_sha):
need(record.get('binary_sha256')==binary_sha and record.get('measurement_kind')=='raw','wrong SHA or superficial status')

View file

@ -0,0 +1,221 @@
[22:46:38.282527] {Default Queue} -> wl_display#1.get_registry(new id wl_registry#2)
[22:46:38.282546] {Default Queue} -> wl_display#1.sync(new id wl_callback#3)
[22:46:38.282664] {Display Queue} wl_display#1.delete_id(3)
[22:46:38.282677] {Default Queue} wl_registry#2.global(1, "wl_fixes", 1)
[22:46:38.282685] {Default Queue} wl_registry#2.global(2, "wl_shm", 2)
[22:46:38.282692] {Default Queue} -> wl_registry#2.bind(2, "wl_shm", 1, new id [unknown]#4)
[22:46:38.282699] {Default Queue} wl_registry#2.global(3, "zwp_linux_dmabuf_v1", 5)
[22:46:38.282703] {Default Queue} wl_registry#2.global(4, "wp_linux_drm_syncobj_manager_v1", 1)
[22:46:38.282708] {Default Queue} wl_registry#2.global(5, "wl_compositor", 6)
[22:46:38.282712] {Default Queue} -> wl_registry#2.bind(5, "wl_compositor", 4, new id [unknown]#5)
[22:46:38.282716] {Default Queue} wl_registry#2.global(6, "wl_subcompositor", 1)
[22:46:38.282720] {Default Queue} wl_registry#2.global(7, "wl_data_device_manager", 3)
[22:46:38.282724] {Default Queue} wl_registry#2.global(8, "zwlr_gamma_control_manager_v1", 1)
[22:46:38.282728] {Default Queue} wl_registry#2.global(9, "zxdg_output_manager_v1", 3)
[22:46:38.282732] {Default Queue} wl_registry#2.global(10, "ext_idle_notifier_v1", 2)
[22:46:38.282736] {Default Queue} wl_registry#2.global(11, "zwp_idle_inhibit_manager_v1", 1)
[22:46:38.282740] {Default Queue} wl_registry#2.global(12, "zwlr_layer_shell_v1", 5)
[22:46:38.282744] {Default Queue} wl_registry#2.global(13, "xdg_wm_base", 5)
[22:46:38.282751] {Default Queue} -> wl_registry#2.bind(13, "xdg_wm_base", 3, new id [unknown]#6)
[22:46:38.282756] {Default Queue} wl_registry#2.global(14, "zwp_tablet_manager_v2", 1)
[22:46:38.282760] {Default Queue} wl_registry#2.global(15, "org_kde_kwin_server_decoration_manager", 1)
[22:46:38.282764] {Default Queue} wl_registry#2.global(16, "zxdg_decoration_manager_v1", 1)
[22:46:38.282768] {Default Queue} wl_registry#2.global(17, "zwp_relative_pointer_manager_v1", 1)
[22:46:38.282772] {Default Queue} wl_registry#2.global(18, "zwp_pointer_constraints_v1", 1)
[22:46:38.282776] {Default Queue} wl_registry#2.global(19, "wp_presentation", 2)
[22:46:38.282780] {Default Queue} wl_registry#2.global(20, "wp_alpha_modifier_v1", 1)
[22:46:38.282784] {Default Queue} wl_registry#2.global(21, "zwlr_output_manager_v1", 4)
[22:46:38.282788] {Default Queue} wl_registry#2.global(22, "zwlr_output_power_manager_v1", 1)
[22:46:38.282792] {Default Queue} wl_registry#2.global(23, "zwp_input_method_manager_v2", 1)
[22:46:38.282796] {Default Queue} wl_registry#2.global(24, "zwp_text_input_manager_v3", 1)
[22:46:38.282799] {Default Queue} wl_registry#2.global(25, "ext_foreign_toplevel_list_v1", 1)
[22:46:38.282803] {Default Queue} wl_registry#2.global(26, "zwlr_foreign_toplevel_manager_v1", 3)
[22:46:38.282807] {Default Queue} wl_registry#2.global(27, "ext_session_lock_manager_v1", 1)
[22:46:38.282812] {Default Queue} wl_registry#2.global(28, "ext_workspace_manager_v1", 1)
[22:46:38.282816] {Default Queue} wl_registry#2.global(29, "zwlr_export_dmabuf_manager_v1", 1)
[22:46:38.282820] {Default Queue} wl_registry#2.global(30, "zwlr_screencopy_manager_v1", 3)
[22:46:38.282824] {Default Queue} wl_registry#2.global(31, "ext_image_copy_capture_manager_v1", 1)
[22:46:38.282828] {Default Queue} wl_registry#2.global(32, "ext_output_image_capture_source_manager_v1", 1)
[22:46:38.282832] {Default Queue} wl_registry#2.global(33, "zwlr_data_control_manager_v1", 2)
[22:46:38.282836] {Default Queue} wl_registry#2.global(34, "ext_data_control_manager_v1", 1)
[22:46:38.282840] {Default Queue} wl_registry#2.global(35, "wp_security_context_manager_v1", 1)
[22:46:38.282844] {Default Queue} wl_registry#2.global(36, "wp_viewporter", 1)
[22:46:38.282848] {Default Queue} wl_registry#2.global(37, "wp_single_pixel_buffer_manager_v1", 1)
[22:46:38.282852] {Default Queue} wl_registry#2.global(38, "wp_content_type_manager_v1", 1)
[22:46:38.282856] {Default Queue} wl_registry#2.global(39, "wp_fractional_scale_manager_v1", 1)
[22:46:38.282860] {Default Queue} wl_registry#2.global(40, "ext_foreign_toplevel_image_capture_source_manager_v1", 1)
[22:46:38.282872] {Default Queue} wl_registry#2.global(41, "wp_tearing_control_manager_v1", 1)
[22:46:38.282886] {Default Queue} wl_registry#2.global(42, "zxdg_exporter_v1", 1)
[22:46:38.282890] {Default Queue} wl_registry#2.global(43, "zxdg_importer_v1", 1)
[22:46:38.282894] {Default Queue} wl_registry#2.global(44, "zxdg_exporter_v2", 1)
[22:46:38.282898] {Default Queue} wl_registry#2.global(45, "zxdg_importer_v2", 1)
[22:46:38.282903] {Default Queue} wl_registry#2.global(46, "xdg_activation_v1", 1)
[22:46:38.282907] {Default Queue} wl_registry#2.global(47, "xdg_toplevel_tag_manager_v1", 1)
[22:46:38.282911] {Default Queue} wl_registry#2.global(48, "wp_cursor_shape_manager_v1", 2)
[22:46:38.282915] {Default Queue} wl_registry#2.global(49, "wp_color_representation_manager_v1", 1)
[22:46:38.282919] {Default Queue} wl_registry#2.global(50, "zwp_virtual_keyboard_manager_v1", 1)
[22:46:38.282923] {Default Queue} wl_registry#2.global(51, "zwlr_virtual_pointer_manager_v1", 2)
[22:46:38.282927] {Default Queue} wl_registry#2.global(52, "zwp_keyboard_shortcuts_inhibit_manager_v1", 1)
[22:46:38.282931] {Default Queue} wl_registry#2.global(53, "zwp_pointer_gestures_v1", 3)
[22:46:38.282935] {Default Queue} wl_registry#2.global(54, "ext_transient_seat_manager_v1", 1)
[22:46:38.282939] {Default Queue} wl_registry#2.global(55, "wl_seat", 9)
[22:46:38.282944] {Default Queue} -> wl_registry#2.bind(55, "wl_seat", 5, new id [unknown]#7)
[22:46:38.282948] {Default Queue} wl_registry#2.global(57, "zwp_primary_selection_device_manager_v1", 1)
[22:46:38.282953] {Default Queue} wl_registry#2.global(58, "wl_output", 4)
[22:46:38.282957] {Default Queue} wl_registry#2.global(59, "wl_output", 4)
[22:46:38.282961] {Default Queue} wl_callback#3.done(16)
[22:46:38.282966] {Default Queue} -> wl_display#1.sync(new id wl_callback#3)
[22:46:38.283205] {Display Queue} wl_display#1.delete_id(3)
[22:46:38.283217] {Default Queue} discarded wl_shm#4.format(0)
[22:46:38.283222] {Default Queue} discarded wl_shm#4.format(1)
[22:46:38.283227] {Default Queue} discarded wl_shm#4.format(875709016)
[22:46:38.283231] {Default Queue} discarded wl_shm#4.format(875708993)
[22:46:38.283235] {Default Queue} discarded wl_shm#4.format(875710274)
[22:46:38.283239] {Default Queue} discarded wl_shm#4.format(842094674)
[22:46:38.283242] {Default Queue} discarded wl_shm#4.format(842088786)
[22:46:38.283246] {Default Queue} discarded wl_shm#4.format(892426322)
[22:46:38.283249] {Default Queue} discarded wl_shm#4.format(892420434)
[22:46:38.283253] {Default Queue} discarded wl_shm#4.format(909199186)
[22:46:38.283257] {Default Queue} discarded wl_shm#4.format(808665688)
[22:46:38.283260] {Default Queue} discarded wl_shm#4.format(808665665)
[22:46:38.283264] {Default Queue} discarded wl_shm#4.format(1213351746)
[22:46:38.283268] {Default Queue} discarded wl_shm#4.format(1211384408)
[22:46:38.283271] {Default Queue} discarded wl_shm#4.format(1211384385)
[22:46:38.283275] {Default Queue} discarded wl_shm#4.format(942950210)
[22:46:38.283279] {Default Queue} discarded wl_shm#4.format(942948952)
[22:46:38.283282] {Default Queue} discarded wl_shm#4.format(942948929)
[22:46:38.283286] {Default Queue} wl_seat#7.name("seat0")
[22:46:38.283291] {Default Queue} wl_seat#7.capabilities(1)
[22:46:38.283296] {Default Queue} -> wl_seat#7.get_pointer(new id wl_pointer#8)
[22:46:38.283300] {Default Queue} wl_callback#3.done(16)
[22:46:38.283305] {Default Queue} -> wl_compositor#5.create_surface(new id wl_surface#3)
[22:46:38.283310] {Default Queue} -> xdg_wm_base#6.get_xdg_surface(new id xdg_surface#9, wl_surface#3)
[22:46:38.283319] {Default Queue} -> xdg_surface#9.get_toplevel(new id xdg_toplevel#10)
[22:46:38.283324] {Default Queue} -> xdg_toplevel#10.set_title("Mosaic Nested Grab Probe")
[22:46:38.283328] {Default Queue} -> xdg_toplevel#10.set_app_id("org.mosaic.NestedGrabProbe")
TOPLEVEL CREATE wl=3 xdg=9 role=10 placement=v_both_cross
[22:46:38.283338] {Default Queue} -> wl_surface#3.commit()
[22:46:38.283679] {Default Queue} xdg_wm_base#6.ping(17)
[22:46:38.283698] {Default Queue} -> xdg_wm_base#6.pong(17)
[22:46:38.283708] {Default Queue} xdg_toplevel#10.configure(0, 0, array[0])
TOPLEVEL ROLE_CONFIGURE w=0 h=0
[22:46:38.283716] {Default Queue} xdg_surface#9.configure(18)
TOPLEVEL XDG_CONFIGURE serial=18 ack
[22:46:38.283724] {Default Queue} -> xdg_surface#9.ack_configure(18)
[22:46:38.284502] {Default Queue} -> wl_shm#4.create_pool(new id wl_shm_pool#11, fd 5, 966000)
[22:46:38.284513] {Default Queue} -> wl_shm_pool#11.create_buffer(new id wl_buffer#12, 0, 420, 575, 1680, 1)
[22:46:38.284520] {Default Queue} -> wl_surface#3.attach(wl_buffer#12, 0, 0)
[22:46:38.284525] {Default Queue} -> wl_surface#3.damage_buffer(0, 0, 420, 575)
[22:46:38.284530] {Default Queue} -> wl_surface#3.commit()
[22:46:38.284534] {Default Queue} -> wl_buffer#12.destroy()
[22:46:38.284538] {Default Queue} -> wl_shm_pool#11.destroy()
TOPLEVEL MAP wl=3 xdg=9
[22:46:38.285508] discarded [unknown]#12.[event 0](0 fd, 8 byte)
[22:46:38.285514] {Display Queue} wl_display#1.delete_id(12)
[22:46:38.285519] {Display Queue} wl_display#1.delete_id(11)
[22:46:38.285524] {Default Queue} xdg_toplevel#10.configure(636, 573, array[20])
TOPLEVEL ROLE_CONFIGURE w=636 h=573
[22:46:38.285532] {Default Queue} xdg_surface#9.configure(19)
TOPLEVEL XDG_CONFIGURE serial=19 ack
[22:46:38.285539] {Default Queue} -> xdg_surface#9.ack_configure(19)
[22:46:38.583097] {Default Queue} wl_pointer#8.enter(24, wl_surface#3, 238.00000000, 275.00000000)
POINTER_ENTER target=TOPLEVEL wl=3 serial=24 x=238.00 y=275.00
[22:46:38.583124] {Default Queue} wl_pointer#8.frame()
[22:46:38.583129] {Default Queue} wl_pointer#8.leave(25, wl_surface#3)
POINTER_LEAVE target=TOPLEVEL serial=25
[22:46:38.583137] {Default Queue} wl_pointer#8.frame()
[22:46:39.867771] {Default Queue} wl_pointer#8.enter(30, wl_surface#3, 3.00000000, 5.00000000)
POINTER_ENTER target=TOPLEVEL wl=3 serial=30 x=3.00 y=5.00
[22:46:39.867787] {Default Queue} wl_pointer#8.frame()
[22:46:39.867792] {Default Queue} wl_pointer#8.frame()
[22:46:39.968604] {Default Queue} wl_pointer#8.leave(31, wl_surface#3)
POINTER_LEAVE target=TOPLEVEL serial=31
[22:46:39.968649] {Default Queue} wl_pointer#8.frame()
[22:46:40.117908] {Default Queue} wl_pointer#8.enter(32, wl_surface#3, 3.00000000, 5.00000000)
POINTER_ENTER target=TOPLEVEL wl=3 serial=32 x=3.00 y=5.00
[22:46:40.117939] {Default Queue} wl_pointer#8.frame()
[22:46:40.117943] {Default Queue} wl_pointer#8.button(33, 1002, 272, 1)
POINTER_BUTTON target=TOPLEVEL serial=33 button=272 state=1
[22:46:40.117951] {Default Queue} -> wl_compositor#5.create_surface(new id wl_surface#11)
[22:46:40.117956] {Default Queue} -> xdg_wm_base#6.get_xdg_surface(new id xdg_surface#12, wl_surface#11)
[22:46:40.117960] {Default Queue} -> xdg_wm_base#6.create_positioner(new id xdg_positioner#13)
[22:46:40.117964] {Default Queue} -> xdg_positioner#13.set_size(250, 170)
[22:46:40.117967] {Default Queue} -> xdg_positioner#13.set_anchor_rect(50, 480, 1, 1)
[22:46:40.117970] {Default Queue} -> xdg_positioner#13.set_anchor(5)
[22:46:40.117973] {Default Queue} -> xdg_positioner#13.set_gravity(8)
[22:46:40.117976] {Default Queue} -> xdg_surface#12.get_popup(new id xdg_popup#14, xdg_surface#9, xdg_positioner#13)
POPUP_A CREATE wl=11 xdg=12 role=14 parent=TOPLEVEL parent_xdg=9
POPUP_A GRAB_REQUEST origin=wl_pointer.button target=TOPLEVEL serial=33 used=33
[22:46:40.117984] {Default Queue} -> xdg_popup#14.grab(wl_seat#7, 33)
[22:46:40.117988] {Default Queue} -> wl_surface#11.commit()
[22:46:40.117991] {Default Queue} -> xdg_positioner#13.destroy()
[22:46:40.117994] {Default Queue} wl_pointer#8.frame()
[22:46:40.118126] {Display Queue} wl_display#1.delete_id(13)
[22:46:40.118129] {Default Queue} xdg_popup#14.configure(50, 480, 250, 170)
POPUP_A ROLE_CONFIGURE x=50 y=480 w=250 h=170
[22:46:40.118135] {Default Queue} xdg_surface#12.configure(34)
POPUP_A XDG_CONFIGURE serial=34 ack
[22:46:40.118140] {Default Queue} -> xdg_surface#12.ack_configure(34)
[22:46:40.118286] {Default Queue} -> wl_shm#4.create_pool(new id wl_shm_pool#13, fd 5, 170000)
[22:46:40.118298] {Default Queue} -> wl_shm_pool#13.create_buffer(new id wl_buffer#15, 0, 250, 170, 1000, 1)
[22:46:40.118313] {Default Queue} -> wl_surface#11.attach(wl_buffer#15, 0, 0)
[22:46:40.118317] {Default Queue} -> wl_surface#11.damage_buffer(0, 0, 250, 170)
[22:46:40.118320] {Default Queue} -> wl_surface#11.commit()
[22:46:40.118322] {Default Queue} -> wl_buffer#15.destroy()
[22:46:40.118325] {Default Queue} -> wl_shm_pool#13.destroy()
POPUP_A MAP wl=11 xdg=12
[22:46:40.118959] discarded [unknown]#15.[event 0](0 fd, 8 byte)
[22:46:40.118962] {Display Queue} wl_display#1.delete_id(15)
[22:46:40.118965] {Display Queue} wl_display#1.delete_id(13)
[22:46:40.197365] {Default Queue} wl_pointer#8.button(35, 1003, 272, 0)
POINTER_BUTTON target=TOPLEVEL serial=35 button=272 state=0
[22:46:40.197412] {Default Queue} wl_pointer#8.frame()
[22:46:40.298184] {Default Queue} wl_pointer#8.leave(36, wl_surface#3)
POINTER_LEAVE target=TOPLEVEL serial=36
[22:46:40.298225] {Default Queue} wl_pointer#8.frame()
[22:46:40.585174] {Default Queue} wl_pointer#8.enter(37, wl_surface#3, 3.00000000, 5.00000000)
POINTER_ENTER target=TOPLEVEL wl=3 serial=37 x=3.00 y=5.00
[22:46:40.585201] {Default Queue} wl_pointer#8.frame()
[22:46:40.585208] {Default Queue} wl_pointer#8.leave(38, wl_surface#3)
POINTER_LEAVE target=TOPLEVEL serial=38
[22:46:40.585221] {Default Queue} wl_pointer#8.frame()
[22:46:40.585227] {Default Queue} wl_pointer#8.enter(39, wl_surface#11, 4.00000000, 5.00000000)
POINTER_ENTER target=POPUP_A wl=11 serial=39 x=4.00 y=5.00
[22:46:40.585240] {Default Queue} wl_pointer#8.frame()
[22:46:40.585246] {Default Queue} wl_pointer#8.frame()
[22:46:40.685838] {Default Queue} wl_pointer#8.leave(40, wl_surface#11)
POINTER_LEAVE target=POPUP_A serial=40
[22:46:40.685909] {Default Queue} wl_pointer#8.frame()
[22:46:40.835646] {Default Queue} wl_pointer#8.enter(41, wl_surface#11, 4.00000000, 5.00000000)
POINTER_ENTER target=POPUP_A wl=11 serial=41 x=4.00 y=5.00
[22:46:40.835675] {Default Queue} wl_pointer#8.frame()
[22:46:40.835682] {Default Queue} wl_pointer#8.button(42, 1005, 272, 1)
POINTER_BUTTON target=POPUP_A serial=42 button=272 state=1
[22:46:40.835696] {Default Queue} -> wl_compositor#5.create_surface(new id wl_surface#13)
[22:46:40.835704] {Default Queue} -> xdg_wm_base#6.get_xdg_surface(new id xdg_surface#15, wl_surface#13)
[22:46:40.835712] {Default Queue} -> xdg_wm_base#6.create_positioner(new id xdg_positioner#16)
[22:46:40.835719] {Default Queue} -> xdg_positioner#16.set_size(170, 130)
[22:46:40.835726] {Default Queue} -> xdg_positioner#16.set_anchor_rect(20, 80, 1, 1)
[22:46:40.835733] {Default Queue} -> xdg_positioner#16.set_anchor(5)
[22:46:40.835738] {Default Queue} -> xdg_positioner#16.set_gravity(8)
[22:46:40.835745] {Default Queue} -> xdg_surface#15.get_popup(new id xdg_popup#17, xdg_surface#12, xdg_positioner#16)
POPUP_B CREATE wl=13 xdg=15 role=17 parent=POPUP_A parent_xdg=12
POPUP_B GRAB_REQUEST origin=wl_pointer.button target=POPUP_A serial=42 used=42
[22:46:40.835761] {Default Queue} -> xdg_popup#17.grab(wl_seat#7, 42)
[22:46:40.835768] {Default Queue} -> wl_surface#13.commit()
[22:46:40.835775] {Default Queue} -> xdg_positioner#16.destroy()
[22:46:40.835781] {Default Queue} wl_pointer#8.frame()
[22:46:40.835930] {Display Queue} wl_display#1.delete_id(16)
[22:46:40.835937] {Default Queue} xdg_popup#17.configure(20, 80, 170, 130)
POPUP_B ROLE_CONFIGURE x=20 y=80 w=170 h=130
[22:46:40.835949] {Default Queue} xdg_surface#15.configure(43)
POPUP_B XDG_CONFIGURE serial=43 ack
[22:46:40.835960] {Default Queue} -> xdg_surface#15.ack_configure(43)
[22:46:40.836118] {Default Queue} -> wl_shm#4.create_pool(new id wl_shm_pool#16, fd 5, 88400)
[22:46:40.836128] {Default Queue} -> wl_shm_pool#16.create_buffer(new id wl_buffer#18, 0, 170, 130, 680, 1)
[22:46:40.836135] {Default Queue} -> wl_surface#13.attach(wl_buffer#18, 0, 0)
[22:46:40.836142] {Default Queue} -> wl_surface#13.damage_buffer(0, 0, 170, 130)
[22:46:40.836149] {Default Queue} -> wl_surface#13.commit()
[22:46:40.836155] {Default Queue} -> wl_buffer#18.destroy()
[22:46:40.836168] {Default Queue} -> wl_shm_pool#16.destroy()
POPUP_B MAP wl=13 xdg=15

View file

@ -0,0 +1,116 @@
{
"reviewer": "/root/v2_build_review",
"identity": "COREC_V2_REDERIVED",
"scope": "D5 independent exact private build/ELF/current pair/stage/compiled client identities and bounded retained pristine control; no compositor main/client execution, IPC, headless, ledger reservation, rebuild or Git mutation",
"verdict": "PASS",
"gate_results": {
"COREC_V2_PRIVATE_BUILD": "PASS",
"COREC_V2_PRIVATE_ELF_ABI": "PASS_BOUNDED_EXACT_CURRENT_PAIR",
"COREC_V2_PRIVATE_STAGE": "PASS",
"COREC_V2_BUILD_REVIEW": "ACCEPTED"
},
"blocking_findings": [],
"nonblocking_findings": [
{
"classification": "HISTORICAL_LIMITATION",
"file": "inputs/run-env-before-desktop-clear.sh; logs/run-command.py",
"symbol": "inherited subprocess environment",
"exact_requirement": "D5 environnement sans h\u00e9ritage de session",
"evidence": "Original wrapper retained SWAYSOCK/WAYLAND_DISPLAY/DISPLAY sentinels; historical command receipts lack full environment. No compositor/client main or IPC consumer executed in this build scope; no session access observed. Historical clear is NOT_PROVEN. Prospective wrapper corrected by parent, independently retested and clean_environment allowlist rejects session/loader/backend sentinels.",
"correction_direction": "Preserve historical NOT_PROVEN; use corrected wrapper and independently reviewed allowlist for future commands. No rebuild or identity replacement is justified by this traceability limitation."
}
],
"identities": {
"source_review_sha256": "26aa862c741196fdbb8d7cdf5509301e49f763cdd22ffa7bcb1a4bbf09c66f90",
"archive_sha256": "769b56c4a11bef13f0abdcfd189b11af954eebbfa69fd06c972e01508d8d376b",
"binary_sha256": "91f48aae2675331e0a2c60ec2fedf983745c521c75232c704a6516a4140801fb",
"build_id": "d5d304533f2c8db9d738365e9bd7f2c96779ef8d",
"wlroots_sha256": "7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837",
"pristine_sha256": "b7fa32116e3c42706b9b02da7df12f27e76d82dd253deb8bdec81519eed145f6",
"pristine_build_id": "ba9751c82e73d4043b7651354f20936d070c2227"
},
"evidence": {
"source_files_verified": 502,
"overlap_count": 85,
"wlroots_relocations_bound_to_executable": 64,
"stage": "5 exact regular files; binary0755 and notices0644; pinned license bytes verified; legal PARTIAL_NOT_APPROVED",
"clients": "7 input files and 9 generated files match receipt; five C17 compiler exits0; old receipt paths relocated to graphics-tests/client-build disclosed",
"pristine_files": 395,
"pristine_qualification": "QUALIFIED_BOUNDED_RETAINED_CONTROL: current 395 pinned sources exact, retained build metadata and binary identities exact; original compile-time manifest absent, not bit-rebuild proof; runtime /proc mapping and renderer NOT_RUN"
},
"native_bits_inspection": [
"factory disassembly: parent assertion; calloc128 -> checked NULL; calloc64 -> free unpublished tree and NULL on failure; scene_tree_init and destroy-listener registration only afterwards",
"setter disassembly: reserved-sidecar lookup; abort on unreserved/embedded root; no calloc; storage pointer private",
"private set/get/sidecar absent from executable dynsym; no scenefx DT_NEEDED; no RPATH/RUNPATH; link command names exact private static archive before shared wlroots",
"85 exact overlap inventory; 64 wlroots overlap symbols with dynamic relocations resolved to executable in loader trace; remaining21 have no wlroots dynamic relocation; ldd-r and explicit LD_TRACE_LOADED_OBJECTS1/LD_WARNyes/LD_BIND_NOWyes/LD_DEBUGbindings exit0, no unresolved symbol",
"Accepted source/C review binds NULL/embedded-root caller audit, full native types and unchanged public layout; 502 current source bytes/modes reverified rather than re-auditing unrelated code"
],
"compiler_policy": {
"scene": "C23 native build; werror true; examples false; default_library static",
"mosaic": "C11 native build; werror true with only c_args=-Wno-error=switch",
"clients": "five C17 compile exits0, no execution",
"initial_failure": "Preserved GCC16.2.1 LIBINPUT_CONFIG_SCROLL_CIRCULAR Werror switch failure; attempt2 warning remains. ipc-json.c1174 initializes scroll_method unknown; unhandled enum does not read an uninitialized pointer. No source mutation."
},
"negative_controls": {
"file": "negative-controls.json",
"sha256": "0767205142e82a9836b848cf18c6ba8ef50d7ff0cc044059f09d71abaf298858",
"status": "PASS five direct review-validator rejections; actual modified source copy resides only review-build, never a build input; independent static magic rejects ELF shared object",
"boundary": "These are reviewer identity checks, not proof of runtime launcher/reservation correctness; separate graphics review owns those gates"
},
"pristine_control": "QUALIFIED_BOUNDED_RETAINED_CONTROL; current395 pinned source files independently compared against git fd71a6bdc061bd633b488ae7b83e8a6981d22f86, retained cached source/build directory agrees, original/copied binary SHA and BuildID exact. Historical compile-time source manifest absent; no claim of immutable compile-time source provenance or bit rebuild. Runtime mapping/renderer NOT_RUN.",
"recipe_review": "BUILD_RECIPE.md consistent with assembled scene/mosaic paths, accepted source precondition, private static link closure, warning policy, model check and 5-file DESTDIR contract; no rebuild requested or performed",
"commands_run": [
"git status --short --branch; git log -3 --oneline; git diff --stat; git diff --check",
"LAB/run-env python review-build/validate.py",
"readelf -n/-d/--dyn-syms/-rW; nm archive and wlroots; objdump factory/setter",
"ldd -r with LD_DEBUG=bindings (loader trace only)",
"explicit binary argv under LD_TRACE_LOADED_OBJECTS=1 LD_WARN=yes LD_BIND_NOW=yes LD_DEBUG=bindings (loader trace only, no compositor init/main)",
"LAB/run-env Python sentinel env checks and direct gate.clean_environment check; git show pin:file comparisons"
],
"verification_notes": [
"Reviewer initial C17 selector mistakenly included cc --version and failed; selector corrected to actual compile commands; final five commands pass. This was a reviewer harness error, not a client/build defect.",
"Parent initial build failure retained; accepted attempt2 and model PASS verified from logs and final Meson introspection, no build/model rerun necessary."
],
"limitations": [
"No compositor main/init, Wayland client, IPC, native graphics/OOM/damage/runtime test executed. Runtime wlroots /proc mapping NOT_RUN; loader mapping is separate evidence.",
"ABI qualification limited to the exact linked pair and reviewed native source/header contract, not future libraries or full semantic/runtime behavior.",
"Graphics Python repair and publication binding remain separate; compiled client input identities alone do not accept scenario behavior.",
"Legal PARTIAL_NOT_APPROVED; no distribution authorization."
],
"headless_authorization": "NOT_AUTHORIZED_BY_THIS_REVIEW_ALONE; require independent final graphics fixture/scenario review, publication binding, resource and runtime guards; no reservation made",
"input_hashes": {
"results/core-build.json": "7ca04d1b719c0a977b8fd94e0b4c58e7107bc9b1532ece9adbdf88c4b09d81f8",
"private-build-recipe.json": "bea6e3e3e10705a77981bd70d744fe51ddf3a283b58e4ece47e820bf5f1ce757",
"BUILD_RECIPE.md": "e68766c02f93feaf8128dbd57e645ec3c93b650d077a90b6e1cb2476e804f859",
"sources/manifest.json": "0058cf56348f3c70dffbdea85e85a73b923c4d830c86efe859048b58ce8ce7e3",
"review-source-c/source-c-review.json": "26aa862c741196fdbb8d7cdf5509301e49f763cdd22ffa7bcb1a4bbf09c66f90",
"results/pristine-candidate.json": "4df5ddf322595598cc5bd227650e18c10f99ea34a75873364f1e5df8508c2f67",
"results/pristine-elf.json": "1f27292aec0701a987c44e8f8c1a9808139a7e02f9500f87dbc0dd9a45e35e07",
"results/graphics-client-compile.json": "d1b1c2ebb13994ecc85f2ba166734637f8848dca6e99cd9acab3bb89c4bddc22",
"results/wrapper-environment-correction.json": "3c2a685587782c6cd0a91c0317e9be9aef27ddb45048918cb7f092ac021ec853",
"run-env": "51ed9377c74510c1e7bd9d4278920fd2f37cb79ec56c513a63a23f069edcb756",
"inputs/run-env-before-desktop-clear.sh": "717a90063329433b90fba966c8338ed94be98ac3ca0418bd4e2192eafabe0c2c",
"inputs/ticket.md": "8a082b63ea28a06a192f002a985642ba4108edf41ce32d0a1245980797af0dad"
},
"artifact_hashes": {
"loader-bindings.log": "fa6fa27ef4d1812a795d5896beb766d6c9bb1cc9ee3c42c065bfea3da2ff4f21",
"loader-list.log": "28a042ca26f1ed4385a2bf3a085a2434d4303be4adc33e7dc3cfe9086c064535",
"archive-symbols.txt": "e13aea4515dbe6f7706b1b15045646d243d35b0870b709fa43a09dfde40f8043",
"wlroots-symbols.txt": "729e5b57302da74d90adb1da7cd092b68d0abd69761c6bf2cea2df57f9ccbe61",
"factory-disassembly.txt": "5c822f765729dbd32550f9f1f39083a1ba0756b9b08f3ab44d7788a512a894c8",
"setter-disassembly.txt": "39fa43770608db5016d1fa9c6f15ea0a8e02a7e0f77254caa0a37145f197d860",
"overlap-symbols.json": "6c6f0c0fe19460c0ce3456bb3ee1ac43ab1fe736f17295390585eeb58c2c2c04",
"environment-before.json": "dd87762bcc48cd5304f780fed330198c98925363d5e881a316ec2e40e00bd48e",
"validate.py": "b4a80f13b7e6b87bf170ebe176fa197a012d7f919042205d2e07e8580d1eb297",
"negative-controls.json": "0767205142e82a9836b848cf18c6ba8ef50d7ff0cc044059f09d71abaf298858",
"overlap-bindings.json": "963d10e0059eebe9b77b92262f8a785951c55cc423737a0e64eaf2593bd56781",
"validation.json": "c3287d45c82967af9ec739ca809bd77eda7f2006aee2c573b93773983c8a3cdb",
"environment-after.json": "1004c9f5cc5914aaa42c2236d58406b1f3726e72f8dd0f8d0a19e108bc10a628",
"explicit-loader-trace.stdout": "faa5cfea9253ba0b59d8091a41a94e24bcf1f5cd4be595788a8288275f98fe01",
"explicit-loader-trace.stderr": "a32f0ea3475edc81597d00d39e901ccea267db561cb999ef6eb0fb573439cd20",
"core-scene-options.json": "b470a74b0269b5caf3154253464ea59e6a3746f6e2af3f3208b0ae3cf743bab7",
"core-mosaic-options.json": "439515b193d5bda2e790988c6a1a8dc9f9fbfa502a37d932e083ee6a0ad6d941",
"mutated-source-NOT-A-BUILD-INPUT.c": "103e4b9eda942c7616d26c2e3f2d1dea25beb1bc3428c219ead3bb4021cb547e"
},
"changes": "Only review-build artifacts created/updated by reviewer. No source/doc/fixture edit, commit, push or Git mutation. Parent prospective wrapper correction reviewed."
}

View file

@ -0,0 +1,78 @@
{
"schema": "corec-v2-graphics-independent-delta-review",
"decision": "ACCEPTED",
"audit": "PASS",
"scope": "B1/B2 correction and direct regressions only; SOURCE/OFFLINE",
"reviewer": "independent R-runtime reviewer",
"baseline_sha256": "be6666d6b2c6fd6ea73d989f53190d6a851d32d267527fe58a1eb15c889578d6",
"source_freeze_sha256": "a905cd571e92668d8352f13ca2b7eef5b19ce7baf0f2c497855ac3c81c8e64fb",
"repair_receipt_sha256": "4845ea64e43830b686940e62950e830f9e98e14e01612f9de9f2ff45fd237ffe",
"source_files_verified": 28,
"changed_files": [
"README.md",
"cases.py",
"engine.py",
"offline/test_graphics_v2.py"
],
"blocking_findings": [],
"resolved": {
"B1": "Watchdog independently escalates TERM to KILL with absolute146 deadline; spawn registration/expiry lock; cleanup absolute deadlines. Real nongraphic TERM-resistant owned group test passes without main cleanup.",
"B2": "Actual640 widths/zero-gap row reconstruction; each resize/migration checks min(previous_scroll,1920-viewport_width), stable owner/workspace/order/output; sampled popup viewport exclusion and wholeH2 on H1; fresh B input or explicit dismissal NOT_EXERCISED."
},
"tests": {
"command": "LAB/run-env Python unittest loader; original32 tests with only temporary fixture location redirected in memory to LAB/review-graphics/OFFLINE_TEST_ONLY",
"tests": 32,
"failures": 0,
"errors": 0,
"result": "PASS",
"log": "delta-offline-tests.log",
"log_sha256": "32d6d619f9a7ccf0676fedbf52258fd9a9c04f84df37febc46b40661ab8a43d6"
},
"additional_negatives": {
"file": "delta-negative-controls.json",
"sha256": "827d30d43691c6e90a993a3698f0ab06c6af1c6d4c835ce7f8f2375999b6a90b",
"result": "PASS",
"checks": [
"late TERM145.92 / KILL146.00 absolute deadline",
"wrong scroll900 within legal max960 rejected (expected960)",
"one-pixel wrong row position rejected"
]
},
"conditional_source_offline_admissible": [
"P0",
"C1",
"C2",
"C3",
"C4",
"C5",
"C6",
"C7"
],
"admission_conditions": [
"Verified source-only publication binds exact graphics/full kit bytes and source_commit==origin==github",
"Accepted exact build/source identities",
"Fresh proper frozen manifest and per-case independent review binding the repaired bytes",
"Real ledger admission by parent only; no retroactive authorization"
],
"not_admitted": [
"P1",
"C8",
"O1",
"O2",
"G2",
"R1"
],
"limitations": [
"All native runtime NOT_RUN by this reviewer",
"Synthetic protocols/pixels do not qualify native behavior",
"C7 post-close capture NOT_TESTED at14cap",
"Nonsaturating clamp may remain so, numeric evidence must state it",
"Native generation/full damage/saved-buffer/GPU lifetime not proven"
],
"real_reservations": 0,
"native_runs": 0,
"source_edits": false,
"commit_push_by_reviewer": false,
"git_diff_check": "PASS",
"working_tree_observed": "clean"
}

View file

@ -0,0 +1,70 @@
{
"schema": "corec-v2-graphics-independent-source-offline-review",
"decision": "CORRECTION_REQUIRED",
"reviewer": "independent R-runtime reviewer",
"source_freeze_sha256": "be6666d6b2c6fd6ea73d989f53190d6a851d32d267527fe58a1eb15c889578d6",
"source_files_verified": 28,
"offline_tests": {
"command": "LAB/run-env Python unittest loader of graphics-kit/offline/test_graphics_v2.py; V2.setUp redirects only temporary fixtures into LAB/review-graphics/OFFLINE_TEST_ONLY; source modules unchanged",
"tests": 27,
"failures": 0,
"errors": 0,
"log_sha256": "e9f994eccd1e04cf7263f694745c59d46347bce2e8f2d813f4d270af5d130431"
},
"negative_controls": {
"file": "negative-controls.json",
"sha256": "a34f071e8cbf1de5a9358d54d561475849cd0a7afa7370a4051b7c5a9b836944"
},
"blockers": [
{
"id": "B1",
"severity": "HIGH / BLOCKING",
"file": "graphics-kit/engine.py",
"symbol": "Session.watchdog / Session.cleanup",
"lines": [
91,
98,
202,
205
],
"requirement": "Ticket section4: duree150s/run; owned-process watchdog confinement",
"evidence": "watchdog_at_144 returns after SIGTERM only. SIGKILL is reached only from main-thread cleanup, after sequential close_client waits and other cleanup waits. No autonomous hard deadline or escalation exists.",
"smallest_correction": "Keep watchdog active through bounded TERM grace and SIGKILL before the150s ceiling; make cleanup use the same absolute deadline and test TERM-resistant owned process/group offline."
},
{
"id": "B2",
"severity": "HIGH / BLOCKING for C7 admission",
"file": "graphics-kit/cases.py",
"symbol": "dynamic_campaign",
"lines": [
95,
97,
98,
103,
105
],
"requirement": "Ticket F7: reconstructed camera clamp and old/new clips/residual pixels after resize and migration",
"evidence": "clamp is assigned NOT_PROVEN unconditionally. Both resize captures only feed sample_surviving (B input); no residual/whole-H2 check or reconstructed clamp assertion is applied before dynamic-ownership PASS and PARTIALLY_FEASIBLE.",
"smallest_correction": "Implement offline-reviewed clamp and per-mutation rendered-region predicates within frozen caps, or mark C7 NOT_ADMITTED pending its narrower review; do not claim complete F7 qualification."
}
],
"accepted_components": [
"Exact28-file source freeze verified",
"27 offline tests pass",
"prlimit core0:0 real non-graphic child test passes with stablePID and unchanged parent limits; argv traces validated; no preexec_fn",
"budgets/reuse/completion/token/source/pub bindings negative controls pass",
"additional UID/duration/publication/symlink negatives pass",
"P1,C8,O1,O2,G2,R1 NOT_ADMITTED",
"native generation/damage/saved/buffer/GPU limitations declared honestly"
],
"non_blocking": [
"C7 post-close capture NOT_TESTED is explicit; no additional capture budget requested",
"Synthetic transports do not prove native input, graphics or cleanup"
],
"runtime": "NOT_RUN",
"real_reservations": 0,
"native_builds": 0,
"sources_edited": false,
"commit_push": false,
"scope": "No production/live IPC/headless/capture/GPU execution"
}

View file

@ -0,0 +1,54 @@
{
"baseline_sha256": "be6666d6b2c6fd6ea73d989f53190d6a851d32d267527fe58a1eb15c889578d6",
"blockers_addressed": [
"B1",
"B2"
],
"caps": {
"C7": 14,
"global_captures": 180,
"planned_captures": 170,
"runs": 14
},
"captures": 0,
"commit_push": false,
"decision": "PENDING_INDEPENDENT_DELTA_REVIEW",
"files_changed": [
"README.md",
"cases.py",
"engine.py",
"offline/test_graphics_v2.py"
],
"limitations": [
"IPC_PENDING_CANDIDATE; native applied generation NOT OBSERVABLE",
"Sampled pixels cannot prove complete damage",
"Post-close C7 capture NOT_TESTED; no extra budget",
"A nonsaturating expected clamp is recorded as such by numeric old/new values; no extra camera mutation",
"Offline synthetic cases do not qualify native C7"
],
"native_builds": 0,
"new_freeze": "/var/tmp/swayfx-mosaic-corec-v2-i516p6po/results/graphics-source-freeze-repaired.json",
"new_freeze_sha256": "a905cd571e92668d8352f13ca2b7eef5b19ce7baf0f2c497855ac3c81c8e64fb",
"offline_tests": {
"errors": 0,
"exit": 0,
"failures": 0,
"log": "/var/tmp/swayfx-mosaic-corec-v2-i516p6po/repair-graphics/offline-final.log",
"log_sha256": "fff3f5ec74611f5bcad65c8b8029e6b185b9a2d5e91ee25221c78d0f0c493a28",
"tests": 32
},
"original_failures_preserved": [
"offline-attempt1.log: fixture path lacked OFFLINE_TEST_ONLY; 7 errors",
"offline-attempt2.log: synthetic quota state missing snapshot; 1 error",
"offline-attempt3.log: repeated synthetic snapshot keyword; SyntaxError"
],
"production_changes": false,
"real_reservations": 0,
"runtime": "NOT_RUN",
"schema": "corec-v2-graphics-bounded-repair",
"solution": {
"B1": "Atomic registration/expiry; independent TERM143 and KILL<=146; shared absolute cleanup deadline146 and reap147; private group only",
"B2": "Pinned calloc/fallback640 corroborated with three actual IPC widths and zero-gap positions; per-mutation clamp min(previous,content-viewport), owner/ws/order/output identity, popup-color exclusion, H2 whole reference on H1, fresh surviving B paint/pointer input or dismissal NOT_EXERCISED"
},
"source_identity_publication_native_limits": "UNCHANGED"
}