OPEN KNOWLEDGEPROBLEMSDECISIONSSTANDARDSLESSONS

Engineering knowledge base

I want the useful output of this port to be more than an APK. This page keeps the operational knowledge: what failed, what was observed, what caused it, what was changed, how it was validated and what should be reused - or avoided - in future ports.

LIVING DOCUMENTv0.1.0-pre.3 release/importer gates resolvedResolved and unresolved work remain visibleLast consolidated 20 August 2026

01 / METHOD

Knowledge as an engineering deliverable

Each record follows an operational structure similar to a technical knowledge or communication cell: context, observation, impact, proven cause, resolution or workaround, validation and reusable lesson. Direct observation is kept separate from inference, and failed experiments are not rewritten out of the history.

Evidence before narrative

A machine pass, a screenshot, a real-device observation and a hypothesis are different kinds of evidence. They are recorded separately so one cannot silently replace another.

Resolved does not mean forgotten

A resolved problem remains useful if its root cause can prevent the same failure in another port. The record stays public instead of disappearing when the bug is closed.

Rejected work is knowledge

An experiment that fails a fidelity or architecture gate is preserved as a negative result. This prevents future work from repeating a superficially attractive approach that has already been disproven.

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.

03 / ENGINEERING STANDARDS

Rules promoted from experience

Platform ownership

Android physical surface is platform-owned; logical render size is engine-owned. Treat OEM overlays/lifecycle as platform evidence before renderer diagnosis.

Reversibility

Keep a known-good baseline. Presentation, HD and other experiments should remain isolated until they pass their own quality gates.

Controller semantics

Map SDL GameController actions rather than raw Android/Linux event codes, and document any action whose semantics differ from the original engine.

Text-input separation

Committed text belongs on SDL_TEXTINPUT; navigation/editing keys stay on key events. Do not log personally entered text when diagnostic counts are sufficient.

Single audio owner

One physical mixer device owns the platform audio endpoint; subsystems mix through it instead of opening competing devices.

Source and asset boundary

Redistributable code and user-owned commercial data remain separate. Source archives, APKs and public knowledge must not silently absorb proprietary resources.

Build evidence

Pin source baselines, validate scripts before mutation, verify produced artifacts semantically and keep generated build trees out of controlled source.

Release signing

Public APKs use a stable private signing key kept outside Git. Record the certificate digest, reject generic Android debug certificates and preserve the key for future compatible upgrades.

Release data path

Validate a real user-facing path for separately owned game data on the actual non-debuggable build. Developer-only ADB or run-as workflows are not a consumer release path.

Target evidence

Real-device measurements and manual QA are authoritative for target-specific behavior. Host simulation cannot certify physical-device presentation or controls.

Negative knowledge

Rejected experiments remain documented with the reason for rejection, so future work starts from accumulated evidence rather than repeating history.

04 / OPEN CONCERNS

Problems not hidden by the working baseline

OPEN-SS-002Broad Android compatibility

RP5 is the validated reference target. Other Android handhelds and phones may differ in controller maps, lifecycle/OEM overlays, storage providers and display behavior.

OPEN-SS-003WORLD/STATIC HD

The indexed renderer cannot represent bicubic RGB output exactly. Truecolor versus explicit quantization remains an architecture/quality decision.

OPEN-SS-004Font remaster

The validated offline dump contains 36 fonts and 5,696 glyphs. Contour/vector candidates remain research until they pass identity, layout and readability gates.

The previous end-user importer, public release identity/signing and final fresh-clone/release gates were resolved during the v0.1.0-pre.3 release process and are retained in the resolved records rather than listed as open work.

05 / TEMPLATE

Future knowledge-record format

StatusOpen · Monitoring · Workaround · Resolved · Rejected · Standard
EnvironmentDevice, OS, source baseline and dependency versions relevant to the observation.
ContextWhat was being attempted and why.
ObservationWhat was actually seen or measured, without silently converting inference into fact.
ImpactWhat the problem blocks, degrades or puts at risk.
Root causeOnly proven cause; otherwise explicitly "Unknown" with hypotheses kept separate.
Resolution / workaroundChange, decision or safe temporary path.
ValidationMachine gates and manual target QA recorded separately.
Reusable lessonThe rule future work should follow because of this evidence.
ReferencesRelevant source files, commits, external documentation and rejected experiments.

06 / CONTRIBUTE KNOWLEDGE

External evidence is welcome

If you reproduce a problem, test another Android device, find a documentation error or have a technical suggestion, use the structured public feedback forms. Useful external evidence can become part of this knowledge base.