02 / KNOWLEDGE RECORDS
Resolved problems and reusable findings
KB-SS-001RESOLVEDPOWERSHELL
Case-insensitive variable collision corrupted Android launch automation
Context. A valid Android build reached the point where automation should launch the activity, but the component string became corrupted.
Root cause. PowerShell variable names are case-insensitive. Two semantically different values had been named $Activity and $activity, so one overwrote the other.
Resolution. Remove case-only variable distinctions and validate critical runners against automatic/reserved variables and casing collisions before mutation or execution.
Reusable lesson. In PowerShell, casing is presentation rather than identity. Naming standards are a correctness control, not merely style.
KB-SS-002DIAGNOSTIC STANDARDANDROID LIFECYCLE
Surface loss can be a platform/lifecycle problem rather than a renderer failure
Observation. During RP5 bring-up, Android/Retroid UI layers could take foreground focus around native startup and affect the SDL surface.
Resolution. Treat Android focus, surface lifecycle, keyguard and OEM Game Assistant/notification overlays as a separate platform subsystem. Capture focus/surface evidence before redesigning rendering code.
Reusable lesson. Prove ownership and lifecycle state at the platform boundary before attributing a visible failure to the renderer.
KB-SS-003RESOLVEDAUDIO
One physical audio-device owner
Symptom. Intro/raw audio could be audible while SDL_mixer reported the audio device as already open, leaving gameplay mixer behavior ambiguous.
Root cause. More than one subsystem could compete for physical audio-device ownership.
Resolution. The stable Android architecture uses one SDL_mixer-owned physical device and routes music, SFX and auxiliary streams through mixer/postmix paths.
Reusable lesson. Shared platform resources need one explicit owner. Parallel physical devices are not a substitute for proper mixing.
KB-SS-004RESOLVEDANDROID IME
Committed text is not a synthetic controller key
Problem. The original player-name editor assumes desktop keyboard input, while Android presents text through an IME.
Resolution. Consume committed characters from SDL_TEXTINPUT; leave navigation/editing keys on the key-event path. The implementation also avoids logging the entered name itself.
Reusable lesson. Text and key buttons are different input domains. Reconstructing IME text from fake key presses creates state and encoding problems.
KB-SS-005VALIDATEDCONTROLS
Right stick must serve camera look and legacy pointer interaction
Problem. System Shock benefits from modern free-look controls but still depends on a mouse-oriented MFD/UI.
Resolution. Right-stick camera look is the default. View/Select explicitly toggles the right stick into fine cursor mode and back. Touchscreen input remains an optional pointer path rather than a requirement.
Reusable lesson. Preserve distinct gameplay and UI interaction models when a legacy interface genuinely needs both.
KB-SS-006RESOLVEDMUSIC CLOCK
Do not replay scheduler lateness as fast music
Symptom. Gameplay music could transiently accelerate or lose layer timing after a host scheduling stall.
Root cause. Overdue XMI events were able to drain rapidly against an absolute millisecond track clock.
Resolution. Use SDL's monotonic high-resolution performance counter and, after abnormal lateness, shift the origins of all active XMI layers together instead of bursting overdue events.
Validation. Gameplay-music manual QA passed after this policy.
Reusable lesson. Real-time media clocks should preserve future intervals after stalls rather than "catch up" at maximum speed.
KB-SS-007CURRENT DECISIONPRESENTATION
4:3 presentation retained as the current baseline
Context. A 16:9 expansion prototype was evaluated during development.
Decision. The current port does not expose a switchable widescreen mode. It retains the original-style 1024x768 4:3 no-stretch presentation as the only public presentation mode.
Visual boundary. The Android IME keyboard shown during text entry is the only platform-specific visual addition to the original game presentation.
Reusable lesson. A technically workable presentation experiment does not need to become a shipped feature when visual consistency and fidelity are better served by the reference format.
KB-SS-008PARTIAL / OPENHD ASSETS
The remaster algorithm must fit the runtime color model
Finding. The Android game renderer remains indexed 8-bit software rendering. Scale4x on sprite/UI material can select existing source colors exactly, while bicubic WORLD/STATIC output creates intermediate RGB colors that require lossy palette quantization.
Decision. Original resources remain authoritative. WORLD/STATIC HD is blocked until a truecolor-versus-quantized path is explicitly evaluated. A sprite/UI runtime experiment was also rejected after manual quality QA and is not part of the canonical baseline.
Reusable lesson. Offline image quality is insufficient evidence if the runtime renderer cannot represent the result faithfully.
KB-SS-009RESOLVED RULERESOURCE IDENTITY
A resource ID is only unique inside the scope where uniqueness was proven
Problem. Compound references can collide across separate System Shock resource namespaces. The same class of issue appears in font analysis when resource IDs are considered without the source resource file.
Resolution. Use composite identity: relevant resource namespace/file plus reference or ID, and where necessary geometry/type/flags. Ambiguous runtime matches fall back to the original resource.
Reusable lesson. Never promote a convenient identifier to a global primary key without testing its uniqueness domain.
KB-SS-010STANDARDVALIDATION
A zero exit code is not a build-quality gate
Rule. The expected artifact must exist and pass semantic checks. APK QA should verify architecture/native libraries and commercial-data exclusion before installation. Runtime machine evidence must remain distinct from manual visual/audio/controller approval.
Reusable lesson. Validate the artifact and behavior you actually care about, not merely the process that was supposed to produce them.
KB-SS-011RESOLVEDREPRODUCIBILITY
A no-tags clone cannot assume a release tag is locally available
Context. The first independent dependency bootstrap from public source release v0.1.0-pre.1.
Symptom. SDL cloned and pinned correctly, but SDL_mixer failed when the helper tried to check out release-2.8.1.
Root cause. The helper cloned with --no-tags and then referenced a tag it had never explicitly fetched.
Resolution. Test whether the requested ref resolves locally; explicitly fetch the matching tag when needed; pin SDL_mixer release-2.8.1 to commit 171eb2d420d5643e4ee11514a06e04a41a463bbd.
Validation. A targeted rerun passed, followed by a completely new v0.1.0-pre.2 clone with no existing dependency cache. SDL and SDL_mixer were downloaded from scratch and the bootstrap completed with FRESH_PRE2_BOOTSTRAP=PASS.
Reusable lesson. Dependency pinning must verify that the pinned object is actually obtainable from a clean repository state.
KB-SS-012RESOLVEDRELEASE ENGINEERING
A public signed APK needs an end-user data path, not a debug-only deployment path
Context. The first signed non-debuggable v0.1.0-pre.3 candidate passed build, package, ABI and signing verification, but the existing data-copy workflow depended on Android run-as.
Impact. A release APK that requires debug-only run-as cannot provide a normal end-user installation path even if the game binary itself is valid.
Resolution. Add a first-run launcher that uses Android's Storage Access Framework to let the user select a compatible res folder containing data and sound. Copy through a staging directory into app-private storage and keep rollback behavior if activation fails.
Validation. A separate non-debuggable release-QA package, signed with the stable release certificate, imported 56 data files and 96 sound files on the Retroid Pocket 5, launched the game, passed the smoke test, removed its temporary package/data afterward and preserved the baseline installation. The final signed release was rebuilt from the merged source and published as v0.1.0-pre.3.
Reusable lesson. Distribution architecture is part of runtime architecture. A release gate must validate how legitimate user-owned data reaches a non-debuggable build, not only whether the APK compiles and signs.