12 KiB
Next native packaging experiment
Initial read-only audit, 19 September 2026, followed by the coordinator’s completed experiment below. Packaging remains unqualified. The documented -exitAfterInit empty-control experiment reproduced the same shutdown errors. The proposal and commands below are retained as historical rationale, not a recommendation to repeat exit-flag trials or proceed to the conditional successor follow-up.
What the failures establish
The empty-addon comparison removed all successor scripts, worlds and resources, retained only five project descriptors, and loaded just Workbench, vanilla and the empty private Core project. It reproduced the successor's exact shutdown error set. This excludes a requirement for successor gameplay/content in reproducing these particular errors; it does not distinguish a Workbench defect from Proton, private-prefix settings or the headless display environment.
The later five-addon 13:17 archive independently records the same result for Core, AI, Intel, Map and Chat: native exit 0, completion_observed=native-child-exited, confirmed cleanup, real native package output, but candidate_created=false. Every console has the same 25 error lines: one resource-leak header and 24 UI resource entries. Removing timestamps solely for comparison gives the same sorted-set SHA-256 as the empty control:
0cb40e173c7a02f72123cfc568016556f05fe80457f06cabf6423cc6ce309c60
The 13:17 archive was read from the actual repository; it was not reconstructed from current sources. Its captured 183 authored files and 151 PAK entries describe that checkpoint, not today's addon set. The structural payload audit passes while native packaging qualification remains false.
The Core raw console, lines 179–198, establishes this order:
| Native time | Event |
|---|---|
| 13:17:04.352 | Packaging done, result 1 |
| 13:17:04.356 | Packaging project successful |
| 13:17:04.359 | Workbench startup completed |
| 13:17:04.419–.420 | Game destroyed |
| 13:17:04.450 | Resource-leak error block |
Its SHA-256 is 16f4a97052e6e373a769a4dc3884ba6f607f7e31eeb798ab64e26a3c07bb845e. The errors occur before the recorded native exit. Later display cleanup cannot explain them as a prematurely terminated pack operation. The earlier non-silent run's runner timeout was a separate, already corrected mistake: it waited for Gamescope after Workbench exited. Simply removing -wbSilent has already failed to eliminate the leak set.
Current native_package.py, run_project, waits for the recorded exact native command's exit and an idle private prefix before declaring natural completion. Cleanup then stops the remaining owned display; raw logs are collected afterward. candidate_ok still requires error-free evidence, unchanged source, successful cleanup and nonempty PAK output. No further ownership correction is established by these packaging logs. Old versus current shared-prefix cleanup implementations are separate provenance and must remain captured in a new run.
Installed supported interface
Primary local documentation is Workbench/docs/EnfusionScriptAPI/html/Page_CLI.html under the installed Arma Reforger Tools directory. The audited file SHA-256 is b1fd25c1d02e3ac687bb310496f700acaf451f66d26c572afa9ac5fd343822d1.
- Line 381 documents public
-exitAfterInit: Workbench exits after full initialization and execution of initialization CLI commands. - Line 379 documents
-wbSilentas initializing the engine/modules without windows, then exiting. It does not promise leak-free teardown. - Lines 459–463 document
-packAddon, output directory and compression/build cache directory. These invoke native XPacker. - Line 385 documents
-forceSettings ABSOLUTE_FILE_PATH, an alternate settings file. This is a possible later settings-isolation control, not evidence that settings caused the leak; no valid replacement settings file was established here.
The installed generated ResourceManager API (GameLib/generated/WorkbenchAPI/Modules/ResourceManager.c) exposes resource registration/rebuild/wait/selection operations, not an addon-packing or UI-unload method. Resource rebuild is not equivalent to native PAK packaging. No supported script cleanup hook or separate command-line XPacker executable was established. Injecting speculative UI teardown, disabling game-script initialization or relying on a resource-build command would not resolve this qualification honestly.
One bounded next experiment
- Reuse the archived empty control's exact authored descriptor bytes in a new exclusive temporary session. Keep binary, Proton launcher, addon identities, private prefix/profile, ResourceManager, native pack/output/cache flags, hidden display and muted audio fixed and recorded. Verify idle prefix and own the existing lock. Do not use the user's Workbench settings/profile.
- Replace
-wbSilentwith-exitAfterInit; do not combine them or add-run. Capture the exact command and both source boundaries. The new flag does not guarantee hidden windows, so the existing private display containment remains mandatory. - Retain the bounded timeout, exact-child exit recorder and all console/error/crash/launcher logs through native shutdown and owned cleanup. A timeout or forced exit is a failed experiment even if a PAK marker appeared. Compare full errors, loaded projects, native exit and startup/pack/shutdown order with the empty baseline.
- If the empty control is clean, repeat the same lifecycle on a frozen successor project containing real resources. An empty control need not emit a PAK and cannot itself qualify an addon. Successor qualification still requires actual nonempty native PAK/RDB/project output, exact captured payload identities, clean shutdown, and separate packed-only runtime checks.
If the same errors recur, retain that failure and stop treating exit flags as an established remedy. A same-build empty-control reproduction on an isolated supported Windows tool environment would then distinguish the local compatibility environment from the tool itself; that comparison has not been run here. Supply the frozen minimal control and complete logs for an upstream defect report. No global vanilla asset edits, error suppression, early termination or release-gate exception follows from reproduction without successor content. All seventeen release requirements remain independently required.
Opt-in runner implementation (not executed)
tools/native_package.py --exit-after-init now selects this experiment. It is mutually exclusive with --silent-workbench, including direct Python calls. Existing no-option behavior remains unchanged (no lifecycle flag); existing --silent-workbench still supplies -wbSilent. Exact native argv and the explicit exit_after_init_experiment boolean are recorded in launch/report evidence. The flag does not change containment, copying, prefix locking, deadlines, native exit accounting, errors, hashes or candidate rules.
The following commands are execution instructions for the coordinator, not evidence of a run. Use a fresh session name and an idle private prefix; do not run concurrently with another runner sharing it. The first command uses the existing frozen empty source and checks its complete authored inventory against the archived control before the normal runner copies it into its exclusive session:
python3 - <<'PY'
import argparse, json, sys
from pathlib import Path
sys.path.insert(0, '/home/jakub/devel/escapistsrereintroduced/tools')
import native_package as package
source = Path('/tmp/erri-empty-package-control-source-20260919')
archive = Path('/home/jakub/devel/escapistsrereintroduced/docs/evidence/package-control-2026-09-19-110404')
expected = json.loads((archive/'authored-before.json').read_text())
if package.inventory(source) != expected:
raise SystemExit('Frozen empty control differs from archived authored input')
args = argparse.Namespace(
steam=Path('/home/jakub/.local/share/Steam'),
compat=Path('/tmp/erri-headless-compat'),
session=Path('/tmp/erri-package-empty-exit-after-init-20260919'),
project='core', timeout=120, silent_workbench=False,
exit_after_init=True, continue_on_failure=False)
raise SystemExit(package.run(args, root=source))
PY
An empty control without a nonempty PAK still returns nonzero even if shutdown is clean. Inspect that distinction without weakening the check. Only after an informative clean control, the real-resource follow-up from the successor source is:
python3 /home/jakub/devel/escapistsrereintroduced/tools/native_package.py \
--project core --exit-after-init --timeout 120 \
--compat /tmp/erri-headless-compat \
--session /tmp/erri-package-core-exit-after-init-20260919
The runner captures and copies the current successor authored source before native launch, then checks the original/copy boundaries; freeze that source for the run. A successful Core attempt is not all-five packaging qualification. Both commands preserve failures and require independent archival before interpreting outputs.
Offline regression command: python3 tests/test_native_package.py. The tests exercise default/silent compatibility, exclusive CLI/direct-call modes, propagation through all five dependency invocations, exact native command/status binding, retained shutdown-error hashes, missing native status and timeout cleanup. All native process/audio calls in those cases are test doubles; they provide no native packaging evidence.
Completed empty-control result and cleanup correction
The coordinator ran /tmp/erri-package-empty-exit-after-init-20260919 at 20:15 on 19 September. Workbench exited with code 0 after the real native packing operation, but its raw console again contains exactly the prior 25 shutdown errors (comparison hash above). This documented exit-mode variation did not fix the leak. No successor follow-up or further exit-flag trials are justified by that result.
The runner also recorded completion_observed=native-or-launcher-exited-prefix-active and cleanup_confirmed=false, identifying PID 856003 after bare normal shutdown. This is an additional runner integration omission, separate from the native UI errors: packaging still called headless_game.cleanup, while the other native runners had adopted cleanup_owned_run. The latter first performs owned normal shutdown, then invokes the existing exact-canonical-prefix adopted-winedevice.exe cleanup, and finally requires idle verification. Its PID-pinned ownership checks and refusal of any unrelated/unknown live process remain unchanged.
The staged packaging adapter now calls that same shared helper under its existing prefix lock and records its complete cleanup_report. It does not change the pre-cleanup completion result: a prefix-active exit stays unqualified even if post-run orphan cleanup succeeds. Native errors, direct exit status, raw hashes and any earlier runner error remain retained. Noncanonical private prefixes receive normal shutdown and idle verification only. No helper is invoked after a failed process launch.
The coordinator subsequently supplied post-run-cleanup.json: only adopted device PID 856003 was targeted, TERM and then KILL were recorded, and cleanup was confirmed. The original failed report remains byte-for-byte intact with cleanup_confirmed=false; this later cleanup is separate operational evidence, not retroactive packaging success.
The prepared standalone archive is /tmp/erri-package-exit-after-init-archive. It contains original reports, exact launch/child-status records, complete raw console/script/error/launcher logs, five authored descriptor bytes, their captured source maps, tiny actual native package outputs, the separate post-run cleanup proof, and a read-only review.json. archive-sha256.json covers all 22 retained files except itself. Native cache directories, generated source caches, mounted vanilla content and profile settings are excluded. The original recorded raw-log/package hashes, command/status association and all authored maps were independently verified before copying. The coordinator may copy this directory into a fresh evidence destination; preserve the original absolute session paths within reports and do not reclassify the result. This is a historical packaging control archive, not a smoke-runtime archive_native.py qualification.