41 KiB
STEP20C SceneFX static distribution and upstream contract
EXPERIMENTAL / PRESERVED HISTORICAL EVIDENCE / no production integration.
Protocol recorded before new tests. Phase A frozen and published at
bb3a112550f45667e501d05d5a08aa8f7d0c02c6; both remotes equal, clean worktree.
STEP20A DONE; STEP20B EXPERIMENTAL; STEP20C NEXT; STEP20D–G PLANNED.
Production multi-output NOT YET SUPPORTED.
Authority, protocol and decision boundary
Packaging, Architecture, Upstream, Development, Known limitations and Roadmap remain authoritative. No UX, production source, recipe, pin, cumulative patch or system dependency change is authorized. Production strategy: NONE — USER DECISION REQUIRED.
Reuse historical ABI evidence: current stock package CURRENT_PACKAGE_STAGE_PASS; private shared with stock SceneFX INCOMPATIBLE_WITH_STOCK_SCENEFX; static ELF resolves without SceneFX DT_NEEDED, with shared wlroots. Historical verdict PARTIALLY_FEASIBLE. 85 common symbols are not 85 defects; 34 actual wlroots scene bindings have 31 external providers and three wlroots providers. No visibility policy is authorized. Sizes/offsets and loader success do not establish full semantic ABI.
Pins: SwayFX 0.6 fd71a6bdc061bd633b488ae7b83e8a6981d22f86;
experimental Mosaic cd550382b311efdbfe3ed892f4e1d281d852e754;
SceneFX 0.5 37ccd723bef49e6891156ffafce8f549f01446cc;
wlroots 0.20.2 d783533489e1f75d6886c2ab5c5960090ef268f8.
No newer source is substituted.
Read-only historical laboratory:
/home/fy59/swayfx-mosaic-abi-package-tp22xfwm.
New laboratory: /home/fy59/swayfx-mosaic-static-contract-7_vlvpjw. Commands, return codes and all generated results
remain there. Historical manifests are verified, never regenerated.
Planned non-graphical checks
Map source references and ELF definitions into A public used SceneFX, B private clip, C overlap with wlroots, D remaining dynamic and E executable-local symbols. Record visibility, version, actual retained binding, owner and risk. Inspect exported/dynamic tables, relocations and transitive package owners. Read pinned headers, implementations, renderer/build/protocol contracts.
One static staging uses the qualified binary, not a newly built compositor.
Historical static prefix /usr/local requires a fresh private Meson install
plan on identical source bytes with /usr prefix; reuse the verified binary
without rebuild/strip, normal DESTDIR installation only. Inspect every entry
including directories, regular files, links, mode, uid/gid and hashes.
One-file shape says nothing about graphics, legal compliance or release readiness.
Audit exact source license texts and source-level notices for incorporated components. Compare N1 embedded/extractable notice, N2 package metadata and N3 separate installed notice. An optional disposable ELF-section roundtrip tests N1 mechanics only. Never evade a license condition to retain one file.
Propose explicit dependency/version gates, manual security ownership and reproducible source/patch/build provenance plus qualified rollback. Prepare an upstream API dossier without contact, submission or public-field changes. Compare maintained upstream API, private static, distinct private shared and no new SceneFX primitive. Recommendations are not authorizations.
Classification
FEASIBLE requires staging and relevant binding characterization plus explicit dependency/maintenance contracts. PARTIALLY_FEASIBLE retains unresolved notice, maintenance, version or ownership questions. INCONCLUSIVE means missing essential staging/binding evidence. BLOCKED means a reproducible invariant failure without validated candidate in scope. Unchosen license or packaging policy is not automatically a code defect. No graphical campaign is allowed.
Completed campaign and staging
SWAYFX_MOSAIC_STATIC_DISTRIBUTION_CONTRACT_PROBE=PARTIALLY_FEASIBLE
Architecture: STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION. Immediate experimental candidate: private static SceneFX. Conditional long-term maintenance direction: an upstream-maintained clipping API. Production strategy: NONE — USER DECISION REQUIRED. No option is integrated.
STATIC_STAGE_FILE_SHAPE_PASS is measured, not inferred. One normal Meson
DESTDIR install returned 0. Complete non-directory manifest:
| Path | Kind | Mode | Actual uid:gid | Bytes | SHA-256 |
|---|---|---|---|---|---|
/usr/bin/swayfx-mosaic |
regular ELF | 0755 | 1000:1000 | 6,760,600 | ccd47ce5b74c132e19bcd46d022a80e90e8a944acc3db521a89427ee7913c614 |
Directories /usr and /usr/bin are recorded in the complete JSON manifest.
No symlink, library, header, config, service, notice or second regular file.
The future package would own this path as root:root; no ownership change was
attempted. This is not an Arch package or legal distribution qualification.
The historical build has prefix /usr/local, bindir bin, debug build,
strip=false, mosaic-package=true, swaybar/swaynag=false, man-pages=disabled,
default-wallpaper=false. SceneFX alone has default_library=static; the
compositor's default_library=shared does not make its explicit archive dynamic.
The private new plan used the same package flags and static uninstalled
pkg-config provider, changing only prefix to /usr for staging. Sources were
copied and byte-verified against the sealed historical tree. The exact
qualified binary was copied into that plan's build-relative target location.
Meson setup performs its normal dependency/compiler configuration probes;
no SceneFX or compositor source was compiled or linked again. Install used
--no-rebuild, without tags or manual placement into DESTDIR. The staged hash
still matches the historical binary. Its embedded /usr/local configuration
strings were not rebuilt into /usr: runtime path suitability is NOT TESTED.
This intentional limitation is why this result qualifies file shape only.
Preparation initially failed because the fixture assumed a subprojects
directory absent from the historical archive. That Python failure preceded
Meson setup/install. The fixture was corrected to copy only existing inputs;
the retained preparation was resumed. Exactly one install attempt occurred.
The persistent stage-install-started.json prohibits a second attempt; the
historical laboratory and manifests were not changed.
ELF loading and the five symbol groups
The private binary is ELF64, little-endian x86-64. No RPATH or RUNPATH.
Both clipping functions are FUNC/GLOBAL/DEFAULT, unversioned, in .symtab;
nm reports ordinary T definitions. They are absent from .dynsym and
have no unresolved dynamic relocation. They are executable definitions,
not ELF LOCAL symbols. Their call sites include private transaction tiled
and popup clipping, with get calls also in private output instrumentation.
No public structure field was introduced by the preserved sidecar patch.
SceneFX is absent from DT_NEEDED and the retained recursive loader graph;
libwlroots-0.20.so remains shared. Retained ldd -r returned 0 with no
undefined-symbol diagnostics. Strong undefined imports in the ELF are normal
shared-library references, not 891 loader failures. Weak optional imports are
reported separately. New readelf header/dynamic/full-symbol/relocation/version
and nm outputs are preserved; actual provider records are reused from the
sealed trusted loader diagnostics. No compositor entry point was run.
The standalone historical graph contains no SceneFX shared library alongside the embedded archive. A future plugin, preload or additional dependency could introduce one; that graph is NOT TESTED. Static embedding does not isolate the process namespace. No export, rename, hidden-visibility or linker-policy change was made or recommended without a separate experiment/authorization.
| Group | Definition and evidence | Current owner/provider | Convention and upgrade risk |
|---|---|---|---|
| A | 73 public SceneFX symbols required as strong imports by shared experimental compositor; static definitions and source references recorded individually | SceneFX implementation embedded in static executable; this set covers compiled SwayFX/Mosaic, not only newly added layout code | Unversioned C scene/effects/renderer functions, unstable public types; new header/body semantics need audit |
| B | wlr_scene_tree_set_clip, wlr_scene_tree_get_clip; strong private shared imports, executable ordinary definitions |
Private SceneFX sidecar; direct static call resolution | No official upstream API/version/error guarantee; private prototype only |
| C | 85 names defined by pristine SceneFX and wlroots and exported by the static executable | Scene, EGL, color and matrix functions; actual providers separately recorded | Matching names alone establish overlap; only observed bindings prove selection; unobserved routes remain uncertain |
| D | 891 distinct strong undefined dynamic symbol base names in static executable, with versions/visibility preserved | Shared wlroots, Wayland, rendering and other system providers selected by retained loader records | ELF version requirements and SONAME do not prove semantic compatibility; all recursive versions matter |
| E | 1,275 ELF LOCAL definitions, including clip sidecar helpers and compositor internals; full table retained | Executable internal implementations | Local helpers have no dynamic ABI; they do not isolate the 85 shared scene/renderer exports |
scene-symbol-ownership.json includes groups, source locations, definitions/
reference candidates, full ELF records, consumer/provider pairs and risk per
symbol. A source occurrence is explicitly evidence of a reference candidate;
ELF tables determine definition/import status. Missing runtime records mean
NOT OBSERVED, not an invented provider. exported-symbols.json retains the
complete table, including actual symbol versions. Public WLR/SceneFX scene
functions have no ELF symbol-version compatibility namespace in this pair.
Versioned libc/etc imports are retained rather than relabeled unversioned.
Some helpers such as wlr_scene_subsurface_tree_set_clip remain dynamic
wlroots imports; that existing surface/subsurface primitive is distinct from
the two private inherited generic tree functions.
Interposition: intentional integration versus unresolved semantics
The preserved stock/private/static diagnostics each observe 34 wlroots scene bindings. The exact same three remain in wlroots:
wlr_scene_subsurface_tree_createwlr_scene_surface_try_from_bufferwlr_scene_surface_create
The other 31 bind to system/private SceneFX in shared controls and to the static executable in the candidate. Their exact names follow below. This pattern is coherent with ordinary SceneFX integration, already present in stock; it is not a newly demonstrated clipping failure.
Pinned wlroots-source/types/scene/xdg_shell.c:66,
layer_shell_v1.c:128, drag_icon.c:49, subsurface_tree.c:246 and
surface.c:432 show why mixed ownership matters: wlroots helpers construct
SceneFX tree/buffer objects through interposed constructors, then manage
surface listeners and protocol lifecycle. Renderer/color/EGL structs and
callbacks similarly cross library boundaries. Preserving compatible object
and function semantics is necessary for these routes. This necessity follows
from source paths; no hide/rename counterfactual was tested. The minimum
safe export set is therefore NOT ESTABLISHED.
The 31 measured bindings are intentional/coherent for the tested pair at the loader level, and helper construction routes substantiate their integration role. Complete semantic necessity of every binding and all remaining overlap paths is uncertain. Unobserved EGL/color/matrix routes must not be called qualified merely because the names match. Any other wlroots version or distro build is NOT QUALIFIED. A hypothetical distinct SONAME also does not fix this process-wide behavior by itself.
wlr_scene_buffer_create
wlr_scene_buffer_from_node
wlr_scene_buffer_send_frame_done
wlr_scene_buffer_set_buffer
wlr_scene_buffer_set_buffer_with_options
wlr_scene_buffer_set_color_encoding
wlr_scene_buffer_set_color_range
wlr_scene_buffer_set_dest_size
wlr_scene_buffer_set_opacity
wlr_scene_buffer_set_opaque_region
wlr_scene_buffer_set_primaries
wlr_scene_buffer_set_source_box
wlr_scene_buffer_set_transfer_function
wlr_scene_buffer_set_transform
wlr_scene_get_scene_output
wlr_scene_node_coords
wlr_scene_node_destroy
wlr_scene_node_place_above
wlr_scene_node_place_below
wlr_scene_node_set_enabled
wlr_scene_node_set_position
wlr_scene_output_build_state
wlr_scene_output_create
wlr_scene_output_destroy
wlr_scene_output_needs_frame
wlr_scene_output_send_frame_done
wlr_scene_output_set_position
wlr_scene_rect_from_node
wlr_scene_timer_finish
wlr_scene_tree_create
wlr_scene_tree_from_node
Dependency contract and conditional future recipe
The static executable's complete direct DT_NEEDED list is:
libcairo.so.2 libdrm.so.2 libjson-c.so.5 libevdev.so.2 libinput.so.10
libudev.so.1 libm.so.6 libpango-1.0.so.0 libgobject-2.0.so.0 libglib-2.0.so.0
libpcre2-8.so.0 libpixman-1.so.0 libwlroots-0.20.so libwayland-server.so.0
libxkbcommon.so.0 libEGL.so.1 libgbm.so.1 libGLESv2.so.2 liblcms2.so.2
libxcb.so.1 libxcb-icccm.so.4 libpangocairo-1.0.so.0 libc.so.6
Only SceneFX is statically embedded. EGL/GBM/GLESv2/lcms2 become direct DT_NEEDED instead of arriving through SceneFX. libdrm and pixman were already direct ELF needs, but are only makedepends in the current recipe. Static embedding must not rely on removing SceneFX while accidentally losing runtime providers previously brought in by it. The retained recursive graph also has Wayland client, Vulkan, seatd/libseat, display-info, liftoff, libudev, XCB extensions and renderer/allocator libraries. Their ownership remains with shared providers; GPU driver modules loaded later are outside loader-only proof.
| Provider in observed system | Candidate future runtime declaration | Reason |
|---|---|---|
| wlroots0.20 | retain, qualify exact build/version matrix | still shared; cannot freeze ordinary SwayFX upgrades |
| wayland | retain | server direct, client/transitive and protocol generation |
| libglvnd | add explicit runtime/build availability | direct EGL and GLESv2 |
| mesa | add explicit runtime/build availability | observed libgbm provider; actual renderer/driver gates remain |
| lcms2 | add explicit runtime/build availability when enabled | direct color-management provider in this build |
| libdrm, pixman | promote to runtime depends | direct DT_NEEDED, currently only makedepends |
| glib2, glibc, xcb-util-wm | make direct ownership explicit in proposed recipe review | GObject/GLib, libc/libm, libxcb-icccm; presently supplied transitively/base system |
| cairo, json-c, libevdev, libinput, systemd-libs, libxcb, libxkbcommon, pango, pcre2 | retain | direct providers and current enabled features |
| gdk-pixbuf2, ttf-font | retain pending runtime feature audit | absence in DT_NEEDED alone does not authorize removal of feature/data requirements |
| scenefx | conditionally remove runtime dependency only after static architecture approval | no SceneFX DT_NEEDED; replace with verified embedded-source build provenance |
| git, meson, ninja, pkgconf, python, wayland-protocols | retain build tools/inputs | source/patch/build/protocol generation |
| kitty, grim | retain future check requirements | not executed in this non-graphical ticket |
This is a proposal, not an applied recipe. Package names describe observed Arch owners, not universal providers. Requalify clean dependency closure, feature toggles, strip/notice retention, reproducibility, staging and separate graphics checks before changing the recipe. No PKGBUILD byte changed.
Version and shared-structure contract
Only pinned SceneFX 0.5 source plus observed wlroots 0.20.2-1 binary is
qualified for these non-graphical checks. Installed headers match the pinned
wlroots source for 121 non-generated files; runtime/version metadata agree.
That does not reconstruct the entire distro build patch set and toolchain.
The Meson range >=0.20.0,<0.21.0 is a dependency acceptance expression,
not a demonstrated compatibility range. 0.20.0, 0.20.1, another 0.20.2 build,
later 0.20 releases and 0.21 are NOT TESTED.
WLR_USE_UNSTABLE exposes public scene nodes, tree, buffers, output, output_state, surfaces, renderer/buffer implementations, listeners, signals, color transform, EGL and render-pass conventions. The historical observer measures identical size/alignment for 17 selected structs and six offsets across installed, pristine and private headers. Examples: scene_node 112/8, tree 128/8, scene_buffer 472/8, output 624/8, surface 968/8; tree.children offset 112, node.parent 8, buffer.buffer 112. It does not show equality between native wlroots scene layouts and extended SceneFX structures, nor exhaustive layouts, callbacks, enum tags, ownership or semantics.
SceneFX requires Wayland server >=1.24, protocols >=1.41, libdrm >=2.4.129, xkbcommon >=1.8 and pixman >=0.43; compositor requirements differ in places. Generated XDG and other Wayland protocol code and scanner inputs are part of reproduction. The observed wlroots enables DRM, X11, libinput, Xwayland, GLES2, Vulkan, GBM, udmabuf, session and color management. SceneFX selects its FX/GLES renderer and observed lcms2 path. Build flags, generated config headers, protocol versions and actual compiler dependencies must accompany source pins. No additional renderer or protocol combination was tested here.
Candidate qualification matrix for each new shared wlroots build:
| Gate | Required evidence | This ticket |
|---|---|---|
| 1 header/source | API, callbacks, enum and lifecycle diffs; exact distro patches | pinned pair only, subset retained |
| 2 symbols | definitions/imports, versions, all consumer/provider bindings | pinned pair only; visibility isolation untested |
| 3 struct layouts | sizes/alignments/offsets for every crossing type and callback ABI | historical 17 structs/six offsets only |
| 4 clean build | fixed SceneFX/Mosaic sources and patch order, toolchain/features | historical build PASS; no new compositor build |
| 5 loader | complete recursive graph, strong/weak relocations, no duplicate SceneFX | historical trusted graph PASS |
| 6 unit/model | actual production model and library contracts | historical mosaic-model 1/1 in three builds; new version NOT TESTED |
| 7 private stage | complete manifest, notices/strip and provenance | current candidate file shape PASS only |
| 8 separately authorized graphics | standard/Mosaic/control, popups, effects, saved buffers, damage, input, scale/rotation/migration/generation | NOT TESTED for static candidate in this ticket |
Do not pin global wlroots to prevent normal SwayFX upgrades. If Mosaic's pair becomes unqualified, withhold its candidate release, rebuild/requalify or use standard SwayFX. File independence is established; update independence is not.
Candidate security ownership and reproducibility
Bundled SceneFX no longer receives fixes when the system scenefx package is updated. The Mosaic distributor/maintainer must explicitly accept ownership for monitoring and rebuilding embedded code, with a named reviewer and release owner. Nobody is assigned by this ticket; an unowned policy is an open gate. Upstream remains a source of fixes, not the security updater of this executable.
Proposed manual workflow, requiring adoption before distribution:
- Record SceneFX commit/tag provenance, Git object identity and SHA-256 source inventory; list exact private patches in order and their digests. Preserve SwayFX/Mosaic/wlroots pins, actual system package/build identities, scanner, protocols, toolchain, flags, generated config and link commands.
- An assigned maintainer reviews upstream releases/commits and security advisories affecting SceneFX and copied wlroots scene/renderer code; assess relevance and exposure. A second reviewer checks the fix and private clip interaction. Set a reporting channel and triage/release response expectations.
- Review a candidate source revision and rebase private patches explicitly; no silent cherry-pick, ABI substitution or automatic update. A fix may alter renderer paths, layouts or interposition and require redesign.
- Rebuild only in a controlled private environment with fixed dependency sources/build metadata and no fallback downloads. Recheck symbol/layout/ loader/dependency gates, model tests, staging/notices and separately authorized graphics. Two clean builds with path/timestamp controls are needed before claiming bit reproducibility; not performed here.
- Record artifact/source/notices hashes, review approvals and matrix results. Publish only under a separate release authorization. Retain the previous qualified artifact and full build manifest for rollback, including compatible dependency identities. No updater or release package is created here.
The cost is recurring SceneFX plus copied-wlroots security triage, patch rebases, shared-wlroots qualification, legal-notice inventory and graphics/release testing. It is more than rebuilding one compositor after a source change. A reproducible procedure is proposed; bit-identical artifacts and security response are NOT ESTABLISHED. Source provenance is necessary but does not itself certify security.
Rollback must never restore system SceneFX/wlroots or overwrite /usr/bin/sway.
Replacing/removing only Mosaic preserves ordinary package ownership. An older
Mosaic artifact may fail with newer shared wlroots/renderer providers; it is
not automatically a working rollback. Retain/requalify compatible manifests,
or fall back to the separately maintained standard SwayFX session. Actual
install/update/uninstall/rollback remain NOT TESTED.
Licenses, incorporated components and notice options
Pinned SwayFX, SceneFX and wlroots root licenses contain MIT copyright,
permission and warranty notices. SceneFX's root notice names Drew DeVault and
Jari Vetoniemi; wlroots additionally names its contributors. Preserve complete
texts, not merely license=('MIT'). The licenses and source notice candidates
are retained verbatim in private license-notices.json; no notice dump enters Git.
Compiled-source provenance, generated protocol comments, archive symbol input,
compile commands and linker plan are retained separately. The proof does not
claim every archive member is extracted into the final executable.
Important additional condition: generated protocol code carries its own copyright/permission text. XDG includes Kristian Høgsberg, Rafael Antognolli, Jasper St. Pierre, Intel, Samsung and Red Hat notices. Generated wlr-layer-shell and output-power code use permission/warranty language that includes supporting documentation and restrictions on advertising with copyright-holder names. An umbrella MIT label alone does not cover this inventory. The existing asset license and tinywl example notices appear in the broad source inventory but are not thereby proven incorporated: wallpaper/examples are disabled. Shared EGL, GBM, GLESv2, lcms2, Wayland, pixman/libdrm and wlroots are not newly copied as static libraries; their package license metadata is contextual evidence, not a declaration that all their source is embedded.
The disposable .mosaic_notices objcopy probe includes exact root license and
generated protocol texts. A byte-for-byte section extraction passed. This is
an oversized candidate inventory, not a completed incorporated-code notice
closure, public notice interface or approved compliance solution. The copied
binary was never executed or staged. Original and staged qualified binaries
are unchanged. Strip/signing/package transformations and accessible notice
delivery still need tests. No public/source API or visibility policy changes.
| Option | Feasibility/accessibility | One-file contract | Risk and required decision |
|---|---|---|---|
| N1 embedded section/metadata | add/extract byte identity PASS on disposable ELF; document extraction with binutils without compositor execution | structurally compatible | complete notice closure, end-user discoverability, strip/retention and legal sufficiency not established; user adoption/review required |
| N2 package metadata/source archive | normal license metadata identifies a license; it does not automatically deliver its full notices |
structurally compatible installed manifest | raw binary transfer and package/source separation can lose notices; actual complete notice-delivery design and legal review required; metadata label alone insufficient |
| N3 separate installed license/notice | conventional readable file, no specialized ELF extraction | incompatible with current exact-one-file rule | requires explicit user packaging-contract decision plus complete notices/review; preferred practical distribution direction if rule can be changed |
Do not drop notice obligations to preserve one installed file. A credible N1 candidate exists technically; a sufficiently solid one-file compliance solution is NOT YET QUALIFIED. Conditional recommendation: allow a distinct installed notice file (N3) for clarity and discoverability if the user authorizes that contract change. This ticket neither changes the contract nor asserts final legal compliance. The protocol-specific supporting-documentation condition needs assessment for any N1/N2 route.
Primary references inspected: pinned SceneFX license, Meson DESTDIR/no-rebuild, GNU objcopy sections and Arch PKGBUILD license metadata. Local pinned source texts and retained generated comments govern the inventory. This is a technical/legal-obligation dossier, not legal clearance.
Separate upstream API dossier — not submitted
An API could express a generic inherited scene-tree clip, not Mosaic popup ownership or UX. Known experimental signatures, retained only as candidates:
void wlr_scene_tree_set_clip(struct wlr_scene_tree *tree,
const struct wlr_box *clip);
bool wlr_scene_tree_get_clip(struct wlr_scene_tree *tree,
struct wlr_box *clip);
No signature is frozen. In particular a void setter cannot report the private sidecar's allocation failure. A maintained API may need a result/error enum or another upstream-owned storage/lifecycle design. No such code, fields or ABI change is implemented here. Public structures must not grow without maintainer agreement on ABI/version policy and all cross-library consumers.
| Topic | Demonstrated private/source behavior | Proposed maintained contract / required tests |
|---|---|---|
| coordinates | copied tree-local integer wlr_box; descendant traversal intersects ancestor clips | logical tree-local half-open rectangle, explicit conversion to output/buffer; checked addition/narrowing/overflow |
| ownership | sidecar owns copied box; tree pointer borrowed; destroy listener frees sidecar | caller may discard box after successful set; tree owns clip lifetime; main scene-thread use only, no independent worker authority |
| NULL | setter clears, absent clear is no-op; getter asserts non-NULL output | NULL rectangle removes own clip; invalid tree/out pointer must have documented error/assertion policy; get absent returns false and define untouched out value |
| empty/negative | zero dimensions accepted; negative dimensions asserted | zero area excludes descendant pixels/hits; negative sizes rejected explicitly; no silent signed overflow or allocation failure |
| update/idempotence | same box memcmp returns early; clear/update invokes scene_node_update | compare semantic coordinates rather than struct padding; same effective clip idempotent; allocation error preserves old state and reported status |
| moving/reparenting | traversal follows parent chain and local→global coordinates | own clip moves with tree; inherited effective clip recomputed on reparent; old/new output damage invalidated; cyclic/invalid reparent rejected by existing ownership rules |
| destruction | listener removes and frees sidecar | no references/listeners after tree destruction; recursive destruction, clear-before-destroy, failed allocation and destruction during callbacks tested |
| inheritance | intersections in private descendant render/hit traversal | getter distinguishes own clip from effective inherited clip; empty ancestor dominates; nested trees and negative origins tested |
| rendering/hit | sampled historical tiled/popup render/hit behavior only | same applied effective bounds for render and hit; other node types, occlusion and buffer-local coordinates must agree |
| damage | private node update and sampled damage; complete proof absent | invalidate exposed/vacated regions on set/clear/move/reparent/output changes; all-frame stale-pixel coverage and cache invalidation |
| effects | sampled shadows/blur; shared edge limitation unresolved | define whether clip limits final coverage versus blur source sampling, shadows/rounded corners/optimized cache; preserve ordinary effects semantics |
| saved buffers | sampled historical held/timeout paths, no complete GPU lifetime proof | consistent applied geometry for saved nodes; destroy/release/ACK/timeout and cross-output lifetime tests |
| rotation/scaling | separate sampled historical probes, not static-candidate graphics | output-transform and fractional rounding policy, damage expansion, conservative raster bounds with exact logical hit contract |
| performance | private linear global sidecar lookup | scalable lookup/storage, bounded per-frame work, no unbounded allocator churn; benchmark deep trees/many clips, cache mutation coherency |
| ABI/version | two private functions, unchanged measured public header layouts | maintained feature/version exposure, compile/link guards, cross-wlroots compatibility policy; exact paired-version qualification |
Mosaic must separately retain tiled-owner identity, root/nested popup hierarchy, applied workspace/output viewport and owner visibility. The private empty clip for a fully hidden owner is Mosaic-owned policy evidence, not a generic SceneFX requirement to know workspaces or XDG grab semantics. Offscreen hide, dismiss or reposition remains undecided UX. No universal click-through promise: valid grabs still have their ordinary dismissal behavior, compared with stock. SceneFX cannot alone assign a Sway transaction generation or popup owner.
Questions for a future authorized maintainer discussion: is inherited tree clip an acceptable primitive? Which coordinate and empty/error policy? Can own/effective queries remain separate? Where may storage live without incompatible public layouts? Which consumers must retain interposed providers? What damage/effects/ saved-buffer semantics can be guaranteed? How should capabilities, ABI and wlroots pairs be versioned? What tests/benchmarks belong upstream? Would an error-reporting setter be preferable? No contact, issue, PR or submission occurs.
Required future tests include C API syntax/invalid arguments, box overflow and allocation failures, idempotence, nested clips, reparent and destruction, render/hit agreement, complete damage and effects/cache/saved-buffer coverage, scaling/rotation/migration, shared-object crossings and performance. A successful compile or signature proposal does not close those tests.
Architectural decision matrix
| Dimension | A maintained upstream API | B private static SceneFX | C distinct private dynamic identity | D no SceneFX extension |
|---|---|---|---|---|
| evidence | private primitive only; upstream acceptance unknown | pinned build/ELF/bindings and one stage PASS | private same-SONAME selection observed; distinct identity NOT TESTED | alternative clipping mechanism not demonstrated |
| maintenance | upstream primitive if accepted; Mosaic owner/viewport still ours | embedded source/security/rebase/version owner required | private library/security/rebase/version owner required | broader Mosaic rendering/input maintenance possible |
| system dependencies | supported maintained SceneFX/wlroots pair | shared wlroots/graphics, no shared SceneFX need | shared wlroots plus private SceneFX file | existing SceneFX/wlroots, unknown new needs |
| SwayFX coexistence | standard packages intact, normal upstream transition | standard binary/libraries intact; file shape PASS | extra private path must be approved | possible filesystem independence, architecture unproved |
| ABI/interposition | official contract still to negotiate; existing integration persists | 85 overlaps; 31 measured wlroots routes into executable | distinct SONAME separates lookup, not namespace/struct semantics | no new clip exports, existing unstable APIs still matter |
| upgrades | paired versions and release qualification | no automatic SceneFX fixes, wlroots upgrades unqualified | private fixes plus shared wlroots qualification | unknown forward-port cost |
| packaging | possible one binary, notices remain | one binary staged; notice/security contracts open | extra library and notices require contract change | unknown final shape |
| licenses/security | preserve notices; upstream plus Mosaic release owners | complete embedded notices and project security owner | notices plus private-library security owner | inventory remains; project owns alternate mechanism |
| rollback | old release only with compatible dependencies; stock fallback | old embedded code may be vulnerable/incompatible; stock fallback | must roll binary/private library together, shared graph still matters | unqualified alternate rollback |
| delivery complexity | external agreement, maintained release and integration | controlled source/archive/patch/provenance/notices builds | private identity/path/RUNPATH/transitive binding contract | largest unexplored implementation risk |
| residual risks | API acceptance and graphical gates | semantics, versions, notices, ownership and graphics | same plus double library/lookup risk | popup stacking/hits/effects/damage/saved buffers/generation |
| minimum next step | authorize discussion after local API/notice review | user contract decisions, then separately scoped version/notice tests | user new-file contract then bounded identity/binding prototype | architecture study; no renderer implementation authorized |
B is the best demonstrated immediate experimental candidate: no new owned SceneFX library file, no absent system clip symbol dependency, explicit ELF and staging evidence. A is the conditional best long-term maintenance orientation, because a maintained generic primitive could avoid perpetual private patches. This is an engineering recommendation, not evidence of upstream commitment. C is not qualified by the existing same-SONAME build; D is not established by output scissor or surface cropping alone.
Required user decisions: candidate architecture or continued investigation; N1/N2/N3 notice route and any packaging-contract change; named security/release owner and response policy; supported exact wlroots build qualification policy without blocking standard upgrades; acceptable rollback/support boundary; permission for any upstream contact; scope of separately authorized graphics, version, reproducibility and delivery tests. No production choice is applied.
Reproduction, validation and unclosed gates
Historical source/evidence manifests remain unchanged and fully verified with the explicit README snapshot mapping from phase A. This campaign reuses ELF and actual bindings, without rerunning historical builds or loader tracing. The new audit fixture preserves its own command/return-code/raw records. It allows repeat static analyses before sealing, but has an exclusive staging attempt marker and refuses sealed results.
For an independent future reconstruction, archive exact pinned Mosaic and SceneFX objects; apply preserved patches in order:
SceneFX: step20c-valid-grab/scenefx-popup-plus-base.patch
step20c-temporal-damage/scenefx-timing.patch
step20c-optimized-blur-cache/scenefx-cache-trace.patch
Mosaic: step20c-valid-grab/mosaic-popup-plus-base.patch
step20c-valid-grab/hidden-guard.patch
step20c-temporal-damage/mosaic-output-timing.patch
step20c-presentation-identity/presentation-events.patch
step20c-optimized-blur-cache/sway-source-trace.patch
Use the historical fixture's exact Meson static-chain flags, setting Mosaic
prefix /usr/bindir bin initially, with the static SceneFX uninstalled
pkg-config directory only for that build. Keep wlroots shared and archive its
pinned source for audits. Verify each patch/digest and qualified installed
header/build inputs. No stock/shared chain is needed. A future reproduction
requires its own authorization and provenance rather than expecting the old
laboratory to exist or silently accepting a different library build. Do not
run historical prepare.py just to analyze symbols: it builds unnecessary chains.
The qualified-source regeneration path is independent of historical binaries;
bit identity and reproducibility across machines remain NOT TESTED.
Current result files include complete staging/ELF/export/ownership/interposition, transitive dependencies, versions, security, licenses/notice options, upstream API, architectural matrix, unresolved gates and summary. Private source/evidence manifests seal the final inventories, excluding themselves and this report's integrity appendix to avoid cyclic digests. No generated file enters Git.
NOT TESTED: static-candidate graphics/GPU/readback, another wlroots version or build, distinct-SONAME/private-path delivery, all-frame damage/effects/cache/ saved-buffer lifetimes, applied-generation consistency, upgrade/rollback, strip/sign/package notice retention, complete legal compliance and bit reproducibility. Historical graphical subset results are not transferred into a new static distribution qualification. STEP20C remains NEXT.
Final ELF count: 88 dynamic definitions, comprising the 85 common SceneFX/
wlroots exports plus libc-related optarg, optind, stderr data records.
These data records are not additional SceneFX functions. Seven generated
protocol notice records are preserved from compiled inputs.
Final checks PASS: Python AST, existing shell/recipe syntax, local Markdown links, source-only fixture/whitespace, complete stage/hash, retained ELF/bindings, structured policy dossiers, protected sources/recipe/patch/UX/AGENTS, unchanged canonical packaging contract, installed sway/SceneFX/wlroots hashes and no LAB processes/sockets. Meson model results are historical, not reexecuted. The parent performed one closeout dossier/fixture review; this is not an independent subagent review. Failures and corrections are explicitly retained.
Final inventory integrity and local state
Source manifest: 1892 entries, SHA-256
5ad64eaf0aec2290689c46b7754eb4563980396ba2a06e852d1c8e903086f138.
Evidence manifest: 143 entries, SHA-256
85d034f4075436bbdda302afdfa94955365aa51adcfb7e8b04ed6bb28377f649.
Both new manifests are sealed and reverified; original 1,463/204 historical
manifests remain unchanged. The report itself and complete diff are excluded
from those inventories to avoid cyclic digests. Phase A HEAD remains
bb3a112550f45667e501d05d5a08aa8f7d0c02c6 on local, origin and github.
Phase B remains unstaged/uncommitted/unpublished: report/fixture plus
Architecture, Known Limitations, Packaging evidence appendix, Roadmap, README
and Changelog only. No protected production/system/session change, installation,
package creation/publication, upstream submission or STEP20D work occurred.
Recommended next smallest step: user review of notice route (N3 recommended conditionally), security/release ownership and exact wlroots qualification policy, then a separately scoped test authorization. No production integration is authorized by this dossier.
SWAYFX_MOSAIC_STATIC_DISTRIBUTION_CONTRACT_PROBE=PARTIALLY_FEASIBLE
STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION
Subsequent user decisions — 2026-10-13
After this campaign, the user approved private static SceneFX for the immediate
STEP20C candidate, separate complete license notices for a future candidate,
project responsibility for embedded SceneFX maintenance, and strict qualification
of each SceneFX/wlroots pair. These decisions authorize documentation and private
prototypes only; the current package, production patch and source remain unchanged.
No individual owner or response SLA is assigned. The historical verdict and
architectural conclusion above are unchanged. A separate runtime/package gate
must build a real /usr binary and qualify loaded libraries and sampled clipping.
The evidence-freeze audit verified all 1,892 source and 143 evidence entries
before changing publication wording. Original manifests were neither regenerated
nor overwritten. For later verification, map the seven updated documentation
entries through /home/fy59/swayfx-mosaic-static-contract-freeze-v1/snapshot-map.json;
all other entries use their original paths. Snapshot bytes are retained outside
Git, with original hashes verified by verify-freeze.py.