docs(mosaic): preserve SceneFX static distribution contract evidence
This commit is contained in:
parent
bb3a112550
commit
4f4f3fefcd
10 changed files with 1125 additions and 0 deletions
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
### STEP20C experimental evidence
|
||||
|
||||
- Preserved static distribution contract: one hash-qualified static executable staged through private Meson metadata at /usr/bin/swayfx-mosaic, exact-one-file shape PASS without recompilation. Existing scene interposition is characterized, version/security/notice obligations and an unsubmitted upstream API dossier are explicit. PARTIALLY_FEASIBLE, contract decision required; no recipe, packaging contract, production or system change. Historical verdict retained; later user decisions authorize a separate private gate only.
|
||||
|
||||
- Preserved SceneFX/wlroots ABI/package audit: current stock build and exact-one-file staging PASS; experimental shared clip functions absent from stock despite common SONAME. Private static build/loader passes, but wlroots interposition, notices, security and version-maintenance gates remain. PARTIALLY_FEASIBLE; architectural decision required. No integration or system change; the historical ABI evidence is published separately from any later distribution-contract investigation.
|
||||
|
||||
- Preserved optimized-edge gate: four completed controls reproduce the same boundary differences in pristine SceneFX, private splith and Mosaic without OPT traces. Same-binary Mosaic trace-off/on and pristine/private standard match full RGB at six states; central freshness, H2 stability and sampled clipping hold. PARTIALLY_FEASIBLE, architecture UNDECIDED: reduced-domain FBO history has source/model support but no native causal observation. Separate ABI/package audit justified; optional bounded GPU study remains unexecuted. No production change; historical graphical campaign closed.
|
||||
|
|
|
|||
|
|
@ -353,3 +353,18 @@ SceneFX shared dependency, but shared wlroots interposition, updates, security
|
|||
maintenance and license notices remain gates. A distinct private shared library
|
||||
would require a new file-ownership decision; upstream API acceptance is unknown.
|
||||
No integration or packaging contract is approved. The historical audit is frozen as evidence; STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||
|
||||
The preserved [static distribution contract dossier](design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md)
|
||||
is **EXPERIMENTAL / PARTIALLY_FEASIBLE**, conclusion
|
||||
**STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION**. One private Meson DESTDIR
|
||||
stage of the hash-qualified static executable contains exactly
|
||||
`/usr/bin/swayfx-mosaic`; this proves file shape only. The 85 overlapping
|
||||
exports and 31/34 wlroots scene bindings into the executable remain explicit
|
||||
paired-version constraints, not automatically defects. Only the pinned
|
||||
SceneFX 0.5 / observed wlroots 0.20.2 pair has non-graphical evidence.
|
||||
Notices (including generated protocols), security ownership, upgrades, rollback
|
||||
and graphical semantics remain gates. A disposable notice-section extraction
|
||||
passes mechanically; legal distribution compliance is not approved.
|
||||
The upstream API dossier is preserved and not submitted. Production strategy:
|
||||
**NONE — USER DECISION REQUIRED**. Packaging/UX contracts are unchanged;
|
||||
STEP20C stays NEXT and production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -294,3 +294,18 @@ SceneFX shared dependency, but shared wlroots interposition, updates, security
|
|||
maintenance and license notices remain gates. A distinct private shared library
|
||||
would require a new file-ownership decision; upstream API acceptance is unknown.
|
||||
No integration or packaging contract is approved. The historical audit is frozen as evidence; STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||
|
||||
The preserved [static distribution contract dossier](design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md)
|
||||
is **EXPERIMENTAL / PARTIALLY_FEASIBLE**, conclusion
|
||||
**STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION**. One private Meson DESTDIR
|
||||
stage of the hash-qualified static executable contains exactly
|
||||
`/usr/bin/swayfx-mosaic`; this proves file shape only. The 85 overlapping
|
||||
exports and 31/34 wlroots scene bindings into the executable remain explicit
|
||||
paired-version constraints, not automatically defects. Only the pinned
|
||||
SceneFX 0.5 / observed wlroots 0.20.2 pair has non-graphical evidence.
|
||||
Notices (including generated protocols), security ownership, upgrades, rollback
|
||||
and graphical semantics remain gates. A disposable notice-section extraction
|
||||
passes mechanically; legal distribution compliance is not approved.
|
||||
The upstream API dossier is preserved and not submitted. Production strategy:
|
||||
**NONE — USER DECISION REQUIRED**. Packaging/UX contracts are unchanged;
|
||||
STEP20C stays NEXT and production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -52,3 +52,14 @@ not establish shared-wlroots update safety or a one-file notice policy.
|
|||
A distinct private dynamic library would add an owned file and require a new
|
||||
explicit packaging decision. No option is adopted; the contract above remains
|
||||
authoritative and unchanged. The historical evidence is frozen, PARTIALLY_FEASIBLE.
|
||||
|
||||
## Preserved static distribution contract evidence
|
||||
|
||||
The [static dossier](design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md)
|
||||
records STATIC_STAGE_FILE_SHAPE_PASS from one private stage, with no library
|
||||
or notice file installed. It proposes dependency/security/version/notice
|
||||
policies, without changing this package contract or PKGBUILD. Embedded notices
|
||||
are technically extractable in a disposable copy; complete/legal delivery is
|
||||
unqualified. A separate installed notice (N3) would need an explicit user
|
||||
decision changing the exact-one-file rule. PARTIALLY_FEASIBLE; no production
|
||||
strategy adopted. The historical evidence is preserved; it does not authorize production integration.
|
||||
|
|
|
|||
|
|
@ -209,3 +209,21 @@ No integration or packaging contract is approved. The historical audit is frozen
|
|||
|
||||
The [ABI/package source fixture](../tooling/probes/step20c-scenefx-abi-package/README.md)
|
||||
records build-only reconstruction and non-graphical diagnostic commands.
|
||||
|
||||
The preserved [static distribution contract dossier](design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md)
|
||||
is **EXPERIMENTAL / PARTIALLY_FEASIBLE**, conclusion
|
||||
**STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION**. One private Meson DESTDIR
|
||||
stage of the hash-qualified static executable contains exactly
|
||||
`/usr/bin/swayfx-mosaic`; this proves file shape only. The 85 overlapping
|
||||
exports and 31/34 wlroots scene bindings into the executable remain explicit
|
||||
paired-version constraints, not automatically defects. Only the pinned
|
||||
SceneFX 0.5 / observed wlroots 0.20.2 pair has non-graphical evidence.
|
||||
Notices (including generated protocols), security ownership, upgrades, rollback
|
||||
and graphical semantics remain gates. A disposable notice-section extraction
|
||||
passes mechanically; legal distribution compliance is not approved.
|
||||
The upstream API dossier is preserved and not submitted. Production strategy:
|
||||
**NONE — USER DECISION REQUIRED**. Packaging/UX contracts are unchanged;
|
||||
STEP20C stays NEXT and production multi-output NOT YET SUPPORTED.
|
||||
|
||||
The [static-contract source fixture](../tooling/probes/step20c-scenefx-static-contract/README.md)
|
||||
preserves the bounded audit/staging procedure; all generated results stay external.
|
||||
|
|
|
|||
|
|
@ -298,3 +298,18 @@ SceneFX shared dependency, but shared wlroots interposition, updates, security
|
|||
maintenance and license notices remain gates. A distinct private shared library
|
||||
would require a new file-ownership decision; upstream API acceptance is unknown.
|
||||
No integration or packaging contract is approved. The historical audit is frozen as evidence; STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||
|
||||
The preserved [static distribution contract dossier](design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md)
|
||||
is **EXPERIMENTAL / PARTIALLY_FEASIBLE**, conclusion
|
||||
**STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION**. One private Meson DESTDIR
|
||||
stage of the hash-qualified static executable contains exactly
|
||||
`/usr/bin/swayfx-mosaic`; this proves file shape only. The 85 overlapping
|
||||
exports and 31/34 wlroots scene bindings into the executable remain explicit
|
||||
paired-version constraints, not automatically defects. Only the pinned
|
||||
SceneFX 0.5 / observed wlroots 0.20.2 pair has non-graphical evidence.
|
||||
Notices (including generated protocols), security ownership, upgrades, rollback
|
||||
and graphical semantics remain gates. A disposable notice-section extraction
|
||||
passes mechanically; legal distribution compliance is not approved.
|
||||
The upstream API dossier is preserved and not submitted. Production strategy:
|
||||
**NONE — USER DECISION REQUIRED**. Packaging/UX contracts are unchanged;
|
||||
STEP20C stays NEXT and production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
600
docs/design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md
Normal file
600
docs/design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
# 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](../PACKAGING.md), [Architecture](../ARCHITECTURE.md),
|
||||
[Upstream](../UPSTREAM.md), [Development](../DEVELOPMENT.md),
|
||||
[Known limitations](../KNOWN_LIMITATIONS.md) and [Roadmap](../ROADMAP.md)
|
||||
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](STEP20C_SCENEFX_ABI_PACKAGE_FEASIBILITY.md):
|
||||
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_create`
|
||||
- `wlr_scene_surface_try_from_buffer`
|
||||
- `wlr_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.
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
1. 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.
|
||||
2. 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.
|
||||
3. 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.
|
||||
4. 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.
|
||||
5. 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](https://github.com/wlrfx/scenefx/blob/37ccd723bef49e6891156ffafce8f549f01446cc/LICENSE),
|
||||
[Meson DESTDIR/no-rebuild](https://mesonbuild.com/Installing.html),
|
||||
[GNU objcopy sections](https://sourceware.org/binutils/docs/binutils/objcopy.html)
|
||||
and [Arch PKGBUILD license metadata](https://man.archlinux.org/man/PKGBUILD.5.en).
|
||||
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:
|
||||
|
||||
```c
|
||||
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:
|
||||
|
||||
```text
|
||||
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`.
|
||||
115
tooling/probes/step20c-scenefx-static-contract/README.md
Normal file
115
tooling/probes/step20c-scenefx-static-contract/README.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# Static SceneFX distribution contract fixture
|
||||
|
||||
**EXPERIMENTAL / PRESERVED HISTORICAL EVIDENCE / not production or a package recipe.**
|
||||
Read the [contract dossier](../../../docs/design/STEP20C_SCENEFX_STATIC_DISTRIBUTION_CONTRACT.md).
|
||||
All builds, binaries, notices, logs and JSON inventories stay in an external LAB.
|
||||
No compositor entry point, desktop IPC, installation, package publication,
|
||||
system library modification or symbol visibility experiment is allowed.
|
||||
|
||||
## Protocol before execution
|
||||
|
||||
Verify immutable historical manifests, using the exact historical README
|
||||
snapshot identified by the ABI freeze report. Reuse trusted qualified static
|
||||
binary after SHA-256 and Meson-option checks. The old build prefix is
|
||||
`/usr/local`: never change its sealed sources or build metadata. Prepare a
|
||||
new private Meson installation plan from byte-verified copies of the same
|
||||
source tree with `--prefix=/usr --bindir=bin` and identical package options.
|
||||
Reuse the original qualified executable at its expected build-relative path
|
||||
with identical hash. Run exactly one `meson install --no-rebuild --destdir
|
||||
LAB/stage-static`. No compilation, linking, stripping or retesting of old
|
||||
compositor builds is needed. Record the metadata adaptation separately.
|
||||
|
||||
If metadata setup fails, retain its failure; do not improvise manual staging
|
||||
or rerun the historical chain. A future independent reproduction may build
|
||||
only the static chain from pinned sources and private patches listed in the
|
||||
[ABI fixture](../step20c-scenefx-abi-package/README.md), with `/usr` prefix
|
||||
from the beginning. The historical laboratory is not a required future input.
|
||||
|
||||
Audit readelf/nm outputs, retained actual loader bindings and source call
|
||||
sites; never infer provider selection from a matching symbol name.
|
||||
Notice embedding, if exercised, uses a disposable copy and objcopy only;
|
||||
byte-for-byte extraction establishes technical feasibility, not legal approval.
|
||||
Do not stage that altered copy or add a notice policy to production.
|
||||
Budget: one static DESTDIR stage, zero graphical runs, zero shared builds,
|
||||
at most one necessary static reconstruction (not required if reuse succeeds).
|
||||
|
||||
## Completed local campaign
|
||||
|
||||
LAB: `/home/fy59/swayfx-mosaic-static-contract-7_vlvpjw`.
|
||||
Historical README mapping:
|
||||
`/home/fy59/swayfx-mosaic-abi-freeze-i6x1osil/historical-fixture-README.md`.
|
||||
PARTIALLY_FEASIBLE; STATIC_DISTRIBUTION_REQUIRES_CONTRACT_DECISION;
|
||||
production strategy NONE — USER DECISION REQUIRED. Phase B stays local.
|
||||
|
||||
One stage passed with exactly one regular `/usr/bin/swayfx-mosaic`, no symlink,
|
||||
library or notice. SHA-256
|
||||
`ccd47ce5b74c132e19bcd46d022a80e90e8a944acc3db521a89427ee7913c614`.
|
||||
The normal Meson plan uses `/usr`; the reused executable retains its historical
|
||||
build strings/options. Runtime path/graphics qualification is not claimed.
|
||||
Initial Python preparation failed on an absent optional `subprojects` directory
|
||||
before setup/staging. The source-copy assumption was corrected and preparation
|
||||
resumed; one setup and one install were executed, with zero compositor rebuilds.
|
||||
|
||||
```sh
|
||||
python tooling/probes/step20c-scenefx-static-contract/audit.py LAB \
|
||||
--historical HISTORICAL_LAB --historical-readme HISTORICAL_README --stage
|
||||
```
|
||||
|
||||
This historical-reuse mode verifies exact sealed manifest identities and trusted
|
||||
binaries, records commands/return codes, inventories symbols/provider consumers,
|
||||
dependencies/source notice candidates, and stages once. `--stage` must never
|
||||
be run again after `stage-install-started.json` exists. Omitting `--stage`
|
||||
allows repeated static analysis before sealing only. The sole notice probe
|
||||
modifies a disposable copy with objcopy, not production or the staged executable.
|
||||
After sealing, only `--verify` is permitted; it rechecks every new inventory
|
||||
entry without writing. Historical manifests use their README snapshot mapping.
|
||||
|
||||
## Independent reproduction without the old laboratory
|
||||
|
||||
Use local Git object stores with the four exact pins in the report. Materialize
|
||||
new SceneFX and Mosaic sources with `git archive` at their respective commits;
|
||||
archive pinned wlroots for comparison. Apply the eight private patches in the
|
||||
report's ordered list with `git apply --check` before each application. Use the
|
||||
same installed wlroots/header/build identities, compiler/scanner/protocol and
|
||||
renderer features; otherwise mark the new matrix unqualified, not equivalent.
|
||||
The report is reproducible from these source inputs, not dependent on retaining
|
||||
the old executable or `/home/fy59` paths. Future execution needs its own budget
|
||||
and authorization; these commands were **not run in this ticket**:
|
||||
|
||||
```sh
|
||||
meson setup "$TASKLAB/scene-build" "$TASKLAB/scene-source" \
|
||||
-Ddefault_library=static -Dexamples=false -Dwerror=false
|
||||
meson compile -C "$TASKLAB/scene-build" -j 8
|
||||
PKG_CONFIG_PATH="$TASKLAB/scene-build/meson-uninstalled" \
|
||||
meson setup "$TASKLAB/mosaic-build" "$TASKLAB/mosaic-source" \
|
||||
--prefix=/usr --bindir=bin -Dwerror=false -Dsd-bus-provider=libsystemd \
|
||||
-Dmosaic-package=true -Dswaybar=false -Dswaynag=false \
|
||||
-Dman-pages=disabled -Ddefault-wallpaper=false
|
||||
PKG_CONFIG_PATH="$TASKLAB/scene-build/meson-uninstalled" \
|
||||
meson compile -C "$TASKLAB/mosaic-build" -j 8
|
||||
meson test -C "$TASKLAB/mosaic-build" mosaic-model --print-errorlogs
|
||||
meson install -C "$TASKLAB/mosaic-build" --no-rebuild \
|
||||
--destdir "$TASKLAB/stage-static"
|
||||
readelf -hW -dW -Ws -rW -VW "$TASKLAB/mosaic-build/sway/swayfx-mosaic"
|
||||
nm --format=posix "$TASKLAB/mosaic-build/sway/swayfx-mosaic"
|
||||
```
|
||||
|
||||
On trusted binaries only, retain loader `--list` and relocation/binding
|
||||
inspection in diagnostic mode (no compositor entry point), as in the preserved
|
||||
ABI fixture. Inspect complete stage entries with lstat, not just regular-file
|
||||
counts. Capture actual consumer/provider pairs; preserve package owners and
|
||||
complete root/generated-protocol notices. The existing historical-reuse audit
|
||||
intentionally refuses a different sealed identity; a new reproduction needs
|
||||
its own validated manifests and may use these standard diagnostics directly.
|
||||
Never execute the historical prepare.py full stock/shared chain just to obtain
|
||||
static symbol evidence. No bit reproducibility or legal clearance is implied.
|
||||
|
||||
## Publication freeze
|
||||
|
||||
The historical verdict is unchanged. Subsequent decisions on private static
|
||||
linking, separate notices, project maintenance and exact-pair qualification
|
||||
authorize a distinct private runtime gate, not production integration.
|
||||
Verify the sealed manifests with `verify-freeze.py LAB --snapshot-map MAP`
|
||||
after publication wording changes. MAP is the external pre-freeze snapshot
|
||||
mapping recorded in the dossier; it must contain only entries whose exact
|
||||
original bytes still match the sealed manifest. No manifests are rewritten.
|
||||
301
tooling/probes/step20c-scenefx-static-contract/audit.py
Normal file
301
tooling/probes/step20c-scenefx-static-contract/audit.py
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Bounded non-graphical audit and single Meson DESTDIR stage of trusted artifacts.
|
||||
|
||||
WHY: source, ELF visibility and actual binding evidence answer different questions.
|
||||
CONTRACT: historical LAB is read-only; only new external LAB receives results.
|
||||
INVARIANT: never run the compositor; never rebuild, install live, or change symbols.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('lab', type=Path)
|
||||
p.add_argument('--historical', type=Path, required=True)
|
||||
p.add_argument('--historical-readme', type=Path, required=True)
|
||||
p.add_argument('--stage', action='store_true')
|
||||
p.add_argument('--verify', action='store_true')
|
||||
a = p.parse_args()
|
||||
lab, old = a.lab.resolve(), a.historical.resolve()
|
||||
repo = Path(__file__).resolve().parents[3]
|
||||
assert not old.is_relative_to(lab) and not lab.is_relative_to(old)
|
||||
assert lab.is_dir() and old.is_dir() and lab != old
|
||||
assert lab.is_relative_to(Path.home()) and not lab.is_relative_to(repo)
|
||||
if a.verify:
|
||||
assert not a.stage
|
||||
for kind in ['source', 'evidence']:
|
||||
manifest = lab/'results'/(kind+'-sha256.txt')
|
||||
lines = manifest.read_text().splitlines()
|
||||
for line in lines:
|
||||
digest, filename = line.split(' ', 1)
|
||||
assert hashlib.sha256(Path(filename).read_bytes()).hexdigest() == digest, filename
|
||||
print(kind, len(lines), hashlib.sha256(manifest.read_bytes()).hexdigest(), 'PASS')
|
||||
raise SystemExit(0)
|
||||
assert not (lab/'results/evidence-sha256.txt').exists(), 'sealed: verify only'
|
||||
raw, results = lab/'raw', lab/'results'
|
||||
raw.mkdir(exist_ok=True); results.mkdir(exist_ok=True)
|
||||
env = {k: v for k, v in os.environ.items() if k not in (
|
||||
'SWAYSOCK', 'I3SOCK', 'WAYLAND_DISPLAY', 'DISPLAY', 'XDG_RUNTIME_DIR',
|
||||
'LD_LIBRARY_PATH', 'LD_PRELOAD', 'PKG_CONFIG_PATH')}
|
||||
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
|
||||
env.update(LC_ALL='C', PYTHONDONTWRITEBYTECODE='1', MESON_ROOT_CMD='/bin/false')
|
||||
commands = json.loads((results/'commands.json').read_text()) if (results/'commands.json').exists() else []
|
||||
|
||||
def sha(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
def save(name, value):
|
||||
(results/(name+'.json')).write_text(json.dumps(value, indent=2)+'\n')
|
||||
|
||||
def read(name):
|
||||
return json.loads((old/'results'/(name+'.json')).read_text())
|
||||
|
||||
def run(label, args, extra=None):
|
||||
# Only explicitly requested diagnostics, Meson setup/install and objcopy.
|
||||
# Command output is file-backed, with bounded execution and owned group.
|
||||
label = f'{len(commands):03}-'+label
|
||||
entry = {'args': list(map(str, args)), 'env_override': extra or {}, 'label': label}
|
||||
with (raw/(label+'.out')).open('wb') as out, (raw/(label+'.err')).open('wb') as err:
|
||||
proc = subprocess.Popen(entry['args'], env={**env, **(extra or {})},
|
||||
stdout=out, stderr=err, start_new_session=True)
|
||||
try:
|
||||
proc.wait(timeout=120)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(proc.pid, signal.SIGTERM)
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(proc.pid, signal.SIGKILL); proc.wait()
|
||||
try:
|
||||
os.killpg(proc.pid, signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
entry['timed_out'] = True
|
||||
entry['returncode'] = proc.returncode
|
||||
commands.append(entry); save('commands', commands)
|
||||
assert proc.returncode == 0, (label, entry)
|
||||
assert (raw/(label+'.out')).stat().st_size < 32*1024*1024
|
||||
output = (raw/(label+'.out')).read_text()
|
||||
(raw/(label.split('-', 1)[1]+'.out')).write_text(output)
|
||||
return output
|
||||
|
||||
integrity = {}
|
||||
for kind, count, digest in [
|
||||
('source', 1463, 'a27fa33d57d3423e09f02430f04cfed643762d876099b7f88489229115c4a1e5'),
|
||||
('evidence', 204, '86f7654c8ad962053644ce2c4c13eb9f026d6618b171e0cc3a8fc3034eb380d5')]:
|
||||
manifest = old/'results'/(kind+'-sha256.txt')
|
||||
assert sha(manifest) == digest
|
||||
lines = manifest.read_text().splitlines(); assert len(lines) == count
|
||||
for line in lines:
|
||||
expected, filename = line.split(' ', 1)
|
||||
path = Path(filename)
|
||||
if path == repo/'tooling/probes/step20c-scenefx-abi-package/README.md':
|
||||
path = a.historical_readme
|
||||
assert sha(path) == expected, filename
|
||||
integrity[kind] = {'count': count, 'sha256': digest, 'verified': True}
|
||||
save('historical-integrity', integrity)
|
||||
elf = read('static-binary-elf'); binary = Path(elf['path'])
|
||||
assert sha(binary) == elf['sha256'] and binary.stat().st_size < 128*1024*1024
|
||||
for name in ['static-binary-elf', 'experimental-binary-elf', 'system-wlroots-elf',
|
||||
'pristine-scenefx-symbols']:
|
||||
item = read(name); assert sha(Path(item['path'])) == item['sha256'], name
|
||||
for tag, args in [('header', ['readelf', '-hW']), ('dynamic', ['readelf', '-dW']),
|
||||
('symbols', ['readelf', '-Ws']), ('relocations', ['readelf', '-rW']),
|
||||
('versions', ['readelf', '-VW']), ('nm', ['nm', '--format=posix'])]:
|
||||
run('static-'+tag, [*args, binary])
|
||||
# Copy retained diagnostic records, do not reexecute the historical ABI campaign.
|
||||
for name in ['static-bindings', 'static-relocations', 'loader-static-default']:
|
||||
shutil.copyfile(old/'raw'/(name+'.json'), raw/('historical-'+name+'.json'))
|
||||
load = read('loader-resolution')
|
||||
assert load['static-relocations']['returncode'] == 0
|
||||
assert 'undefined symbol:' not in load['static-relocations']['stdout']
|
||||
assert 'libscenefx' not in load['static-default']['stdout']
|
||||
save('static-elf', {**elf, 'relocations': 'PASS historical trusted loader diagnostics',
|
||||
'graphics': 'NOT TESTED', 'loader_records_reused': True})
|
||||
|
||||
# Full ELF tables distinguish local/global/default visibility from dynsym membership.
|
||||
def symbols(path):
|
||||
out = {}
|
||||
for line in path.read_text().splitlines():
|
||||
f = line.split()
|
||||
if len(f) >= 8 and f[0].rstrip(':').isdigit():
|
||||
name = f[7].split('@')[0]
|
||||
rec = dict(type=f[3], bind=f[4], visibility=f[5], index=f[6],
|
||||
version=f[7].split('@', 1)[1] if '@' in f[7] else None)
|
||||
out.setdefault(name, []).append(rec)
|
||||
return out
|
||||
sym = symbols(raw/'static-symbols.out')
|
||||
scene = set(read('pristine-scenefx-symbols')['defined'])
|
||||
wl = set(read('system-wlroots-elf')['defined'])
|
||||
shared = read('experimental-binary-elf')
|
||||
clip = {'wlr_scene_tree_set_clip', 'wlr_scene_tree_get_clip'}
|
||||
local_names = {n for n, records in sym.items() if any(x['bind']=='LOCAL' and x['index']!='UND' for x in records)}
|
||||
scan_names = set(sym) | scene | clip
|
||||
source_refs = {}
|
||||
for path in sorted((old/'mosaic-private/sway').rglob('*.c')):
|
||||
for lineno, line in enumerate(path.read_text().splitlines(), 1):
|
||||
for name in set(re.findall(r'\b[A-Za-z_][A-Za-z0-9_]*\b', line)) & scan_names:
|
||||
source_refs.setdefault(name, []).append({'file': str(path.relative_to(old)),
|
||||
'line': lineno, 'text': line.strip()})
|
||||
definition_refs = {}
|
||||
actual_definitions = {}
|
||||
for tree in ['scene-private', 'wlroots-source', 'mosaic-private']:
|
||||
for path in sorted((old/tree).rglob('*.c')):
|
||||
content = path.read_text()
|
||||
for match in re.finditer(r'(?m)^[ \t]*(?:[A-Za-z_]\w*[\s*]+)+([A-Za-z_]\w*)\s*\([^;{}]*\)\s*\{', content):
|
||||
name = match[1]
|
||||
if name in scan_names:
|
||||
actual_definitions.setdefault(name, []).append({'file': str(path.relative_to(old)), 'line': content[:match.start()].count('\n')+1})
|
||||
for lineno, line in enumerate(path.read_text().splitlines(), 1):
|
||||
for name in set(re.findall(r'\b[A-Za-z_][A-Za-z0-9_]*\b', line)) & scan_names:
|
||||
definition_refs.setdefault(name, []).append({'file': str(path.relative_to(old)),
|
||||
'line': lineno, 'text': line.strip()})
|
||||
bindings = {}
|
||||
for mode in ['stock-bindings', 'private-bindings', 'static-bindings']:
|
||||
data = read('loader-resolution')[mode]
|
||||
for line in (data['stdout']+'\n'+data['stderr']).splitlines():
|
||||
match = re.search(r"binding file (.*?) \[0\] to (.*?) \[0\].*symbol `([^']+)'", line)
|
||||
if not match:
|
||||
continue
|
||||
rec = {'consumer': match[1], 'provider': match[2]}
|
||||
rows = bindings.setdefault(match[3], {}).setdefault(mode, [])
|
||||
if rec not in rows:
|
||||
rows.append(rec)
|
||||
public = sorted((set(shared['undefined']) & scene) - clip)
|
||||
common = sorted(scene & wl)
|
||||
assert len(common) == 85
|
||||
ownership = []
|
||||
local_names = {n for n, records in sym.items() if any(x['bind']=='LOCAL' and x['index']!='UND' for x in records)}
|
||||
for name in sorted(set(public) | set(common) | clip | set(elf['undefined']) | local_names):
|
||||
actual = bindings.get(name, {})
|
||||
ownership.append({'name': name, 'groups': [g for g, yes in [
|
||||
('A', name in public), ('B', name in clip), ('C', name in common),
|
||||
('D', name in elf['undefined']), ('E', name in local_names)] if yes],
|
||||
'definitions': actual_definitions.get(name, []),
|
||||
'definition_reference_source_candidates': definition_refs.get(name, []),
|
||||
'compositor_source_references': source_refs.get(name, []),
|
||||
'elf': sym.get(name, []), 'dynamic_export': name in elf['defined'],
|
||||
'expected_owner': 'SceneFX private clip' if name in clip else 'SceneFX scene/renderer' if name in scene else 'shared provider from retained loader graph' if name in elf['undefined'] else 'executable internal implementation',
|
||||
'observed_providers': actual,
|
||||
'selection': 'direct executable definition (non-dynsym)' if name in clip else ('MEASURED retained bindings (includes callers other than wlroots; see scene counts)' if actual else 'NOT OBSERVED at runtime; ELF definition/reference only'),
|
||||
'abi_convention': 'unversioned WLR_USE_UNSTABLE C ABI and shared scene/renderer types' if name in scene or name in clip or name.startswith('wlr_') else 'ELF table version recorded; no new ABI assertion',
|
||||
'classification': 'private prototype only; ABI not maintained' if name in clip else 'provider records retained; scene helper necessity inferred from source, not isolation experiment' if actual and name in common else 'current definition/reference characterized; full semantic ABI NOT ESTABLISHED',
|
||||
'upgrade_risk': 'any new wlroots version/build NOT QUALIFIED'})
|
||||
save('scene-symbol-ownership', {'group_A_scope': 'link-required public SceneFX functions across compiled SwayFX/Mosaic; per-source references distinguish Mosaic-specific paths', 'groups': {'A': public, 'B': sorted(clip), 'C': common,
|
||||
'D': elf['undefined'], 'E': sorted(n for n, records in sym.items() if any(x['bind']=='LOCAL' and x['index']!='UND' for x in records))}, 'symbols': ownership})
|
||||
save('exported-symbols', {'dynamic_definitions': elf['defined'], 'dynamic_undefined': elf['undefined'], 'full_table': sym})
|
||||
save('interposition-matrix', {'observed': bindings, 'scene_wlroots_counts': read('scene-symbol-bindings'),
|
||||
'overlap': common, 'visibility_changes': 'NONE', 'new_version': 'NOT TESTED',
|
||||
'warning': 'matching names are not defects; hiding them may break wlroots helper delegation'})
|
||||
transitive = read('transitive-dependencies')
|
||||
stock = read('stock-binary-elf')
|
||||
save('transitive-dependencies', {'static_DT_NEEDED': elf['DT_NEEDED'],
|
||||
'stock_DT_NEEDED': stock['DT_NEEDED'], 'new_direct': sorted(set(elf['DT_NEEDED'])-set(stock['DT_NEEDED'])),
|
||||
'removed_direct': sorted(set(stock['DT_NEEDED'])-set(elf['DT_NEEDED'])),
|
||||
'historical_recursive_package_owners': transitive,
|
||||
'note': 'historical union includes SceneFX for shared cases; static graph comes from historical loader-static-default.json',
|
||||
'proposal_only': 'keep existing runtime dependencies except scenefx conditionally; add libglvnd, mesa, lcms2; promote libdrm/pixman to runtime; review glib2, glibc, xcb-util-wm direct owners; no PKGBUILD change'})
|
||||
|
||||
# Exact root licenses plus source-level notice candidates remain external.
|
||||
notices = []
|
||||
for tree in ['stock', 'scene-private', 'wlroots-source']:
|
||||
for path in sorted((old/tree).rglob('*')):
|
||||
if not path.is_file() or 'subprojects' in path.relative_to(old/tree).parts:
|
||||
continue
|
||||
if path.name.upper().startswith(('LICENSE', 'COPYING', 'NOTICE')):
|
||||
notices.append({'path': str(path.relative_to(old)), 'sha256': sha(path), 'text': path.read_text(errors='replace'), 'kind': 'license_file'})
|
||||
elif path.suffix in ['.c', '.h', '.frag', '.vert', '.xml']:
|
||||
text = path.read_text(errors='replace')
|
||||
if re.search(r'copyright|SPDX-License|permission is hereby|redistribution and use', text, re.I):
|
||||
notices.append({'path': str(path.relative_to(old)), 'sha256': sha(path), 'text': text, 'kind': 'source_notice_candidate; inclusion needs link-object provenance review'})
|
||||
# Link-input provenance also includes generated protocol code with its own notices.
|
||||
# Root MIT files alone are insufficient for a complete distribution notice bundle.
|
||||
incorporated = []
|
||||
for build_name in ['static-build', 'scene-static-build']:
|
||||
build_path = old/build_name
|
||||
compile_commands = json.loads((build_path/'compile_commands.json').read_text())
|
||||
shutil.copyfile(build_path/'compile_commands.json', raw/(build_name+'-compile-commands.json'))
|
||||
shutil.copyfile(build_path/'build.ninja', raw/(build_name+'-build.ninja'))
|
||||
for command in compile_commands:
|
||||
path = (build_path/command['file']).resolve()
|
||||
if not path.is_file():
|
||||
continue
|
||||
incorporated.append({'path': str(path), 'sha256': sha(path),
|
||||
'object': command.get('output'), 'build': build_name,
|
||||
'note': 'compile input, final archive extraction not proven by this alone'})
|
||||
if path.is_relative_to(build_path) and path.suffix == '.c':
|
||||
text = path.read_text()
|
||||
comments = re.findall(r'/\*.*?\*/', text, re.S)
|
||||
payload = '\n'.join(c for c in comments if re.search(r'copyright|permission|redistribution', c, re.I))
|
||||
if payload:
|
||||
notices.append({'path': str(path.relative_to(old)), 'sha256': sha(path),
|
||||
'text': payload, 'kind': 'generated_protocol_notice'})
|
||||
save('incorporated-source-inventory', incorporated)
|
||||
run('archive-symbols', ['nm', '-A', '--defined-only', old/'scene-static-build/libscenefx-0.5.a'])
|
||||
save('license-notices', {'root_licenses': read('licenses')['source_licenses'],
|
||||
'source_notice_candidates': notices, 'system_packages': read('licenses'),
|
||||
'incorporation': 'only SceneFX archive embedded; wlroots shared; SwayFX/common/protocol code included; no static system dependency claimed',
|
||||
'compliance': 'NOT APPROVED; exact source notices retained, final object/notice closure still required'})
|
||||
# Probe N1 solely on a disposable executable; never staged or executed.
|
||||
notice_file = lab/'notice-candidate.txt'
|
||||
notice_file.write_text('\n\n'.join(x['path']+'\n'+x['text'] for x in notices if x['kind'] in ['license_file', 'generated_protocol_notice']))
|
||||
notice_bin = lab/'notice-copy'
|
||||
run('notice-add', ['objcopy', '--add-section', '.mosaic_notices='+str(notice_file),
|
||||
'--set-section-flags', '.mosaic_notices=readonly,contents', binary, notice_bin])
|
||||
extracted = lab/'notice-extracted.txt'
|
||||
run('notice-extract', ['objcopy', '--dump-section', '.mosaic_notices='+str(extracted), notice_bin, lab/'notice-extract-copy'])
|
||||
assert extracted.read_bytes() == notice_file.read_bytes()
|
||||
save('notice-distribution-options', {'N1': {'mechanics': 'PASS objcopy/extraction roundtrip on disposable copy', 'sha256': sha(extracted), 'staged': False, 'strip_retention': 'NOT TESTED', 'legal': 'NOT APPROVED', 'one_file': True, 'remaining': 'complete notice inventory, accessible extraction without executing compositor, retention through strip/sign/package, legal review'},
|
||||
'N2': {'mechanics': 'license metadata identifies license; does not contain complete notices automatically', 'one_file': True, 'risk': 'package/source separation or raw executable transfer loses notices', 'legal': 'NOT APPROVED'},
|
||||
'N3': {'mechanics': 'conventional installed notice file', 'one_file': False, 'decision': 'USER packaging contract change required', 'legal': 'complete inventory/review still required'}})
|
||||
|
||||
if a.stage:
|
||||
# One-shot marker persists even on failure. Historical build remains untouched.
|
||||
marker = lab/'stage-started.json'
|
||||
assert not (lab/'stage-install-started.json').exists(), 'staging attempt already consumed'
|
||||
if not marker.exists():
|
||||
with marker.open('x') as out:
|
||||
json.dump({'budget': 1, 'binary': str(binary), 'sha256': sha(binary)}, out)
|
||||
source, build = lab/'stage-source', lab/'stage-plan'
|
||||
if not source.exists():
|
||||
shutil.copytree(old/'mosaic-private', source)
|
||||
# Git archives need not contain a subprojects directory; never assume one.
|
||||
original = old/'mosaic-private'
|
||||
for path in original.rglob('*'):
|
||||
if path.is_file() and 'subprojects' not in path.relative_to(original).parts:
|
||||
assert sha(path) == sha(source/path.relative_to(original))
|
||||
flags = ['--prefix=/usr', '--bindir=bin', '-Dwerror=false', '-Dsd-bus-provider=libsystemd',
|
||||
'-Dmosaic-package=true', '-Dswaybar=false', '-Dswaynag=false', '-Dman-pages=disabled', '-Ddefault-wallpaper=false']
|
||||
run('stage-plan-setup', ['meson', 'setup', build, source, *flags],
|
||||
{'PKG_CONFIG_PATH': str(old/'scene-static-build/meson-uninstalled')})
|
||||
plan = json.loads((build/'meson-info/intro-installed.json').read_text())
|
||||
assert plan == {str(build/'sway/swayfx-mosaic'): '/usr/bin/swayfx-mosaic'}, plan
|
||||
target = build/'sway/swayfx-mosaic'; shutil.copy2(binary, target)
|
||||
assert sha(target) == elf['sha256']
|
||||
with (lab/'stage-install-started.json').open('x') as out:
|
||||
json.dump({'budget': 1}, out)
|
||||
run('stage-static', ['meson', 'install', '-C', build, '--destdir', lab/'stage-static', '--no-rebuild'])
|
||||
entries = []
|
||||
for path in sorted((lab/'stage-static').rglob('*')):
|
||||
s = path.lstat(); kind = 'symlink' if stat.S_ISLNK(s.st_mode) else 'directory' if stat.S_ISDIR(s.st_mode) else 'regular' if stat.S_ISREG(s.st_mode) else 'other'
|
||||
entries.append({'path': '/'+str(path.relative_to(lab/'stage-static')), 'kind': kind,
|
||||
'mode': oct(stat.S_IMODE(s.st_mode)), 'uid': s.st_uid, 'gid': s.st_gid,
|
||||
'bytes': s.st_size, 'sha256': sha(path) if kind=='regular' else None,
|
||||
'target': os.readlink(path) if kind=='symlink' else None})
|
||||
files = [x for x in entries if x['kind']!='directory']
|
||||
passed = len(files)==1 and files[0]['path']=='/usr/bin/swayfx-mosaic' and files[0]['kind']=='regular' and files[0]['sha256']==elf['sha256']
|
||||
save('static-stage-manifest', {'status': 'STATIC_STAGE_FILE_SHAPE_PASS' if passed else 'STATIC_STAGE_FILE_SHAPE_FAIL',
|
||||
'entries': entries, 'complete_non_directory_manifest': files, 'plan': plan,
|
||||
'build_options': json.loads((build/'meson-info/intro-buildoptions.json').read_text()),
|
||||
'metadata_adaptation_only': True, 'compositor_compiles': 0, 'intended_package_owner': 'swayfx-mosaic',
|
||||
'intended_install_uid_gid': 'root:root under future packaging; actual staging remains user-owned',
|
||||
'notices_present': False, 'libraries_installed': False})
|
||||
assert passed
|
||||
print('PASS static analysis, retained binding verification and notice mechanics; stage executed' if a.stage else 'PASS static analysis only; no new staging')
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Verify immutable historical manifests after publication wording changes.
|
||||
|
||||
WHY: documentation snapshots preserve evidence without rewriting sealed hashes.
|
||||
CONTRACT: explicit mappings replace only files recorded in the source manifest.
|
||||
INVARIANT: verification is read-only; every original digest must still match.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('lab', type=Path)
|
||||
p.add_argument('--snapshot-map', type=Path, required=True)
|
||||
a = p.parse_args()
|
||||
mapping = json.loads(a.snapshot_map.read_text())
|
||||
seen = set()
|
||||
for kind, count, expected in [
|
||||
('source', 1892, '5ad64eaf0aec2290689c46b7754eb4563980396ba2a06e852d1c8e903086f138'),
|
||||
('evidence', 143, '85d034f4075436bbdda302afdfa94955365aa51adcfb7e8b04ed6bb28377f649')]:
|
||||
manifest = a.lab/'results'/(kind+'-sha256.txt')
|
||||
assert hashlib.sha256(manifest.read_bytes()).hexdigest() == expected
|
||||
lines = manifest.read_text().splitlines()
|
||||
assert len(lines) == count
|
||||
for line in lines:
|
||||
digest, name = line.split(' ', 1)
|
||||
if kind == 'source' and name in mapping:
|
||||
seen.add(name)
|
||||
name = mapping[name]
|
||||
assert hashlib.sha256(Path(name).read_bytes()).hexdigest() == digest, name
|
||||
print(kind, count, expected, 'PASS')
|
||||
assert seen == set(mapping), 'mapping must contain only sealed source entries'
|
||||
Loading…
Reference in a new issue