Ship script gates wave 4 behind AXP_DEBLOB_WAVE4, documents secrets cert path, and adds deblob appliers plus tests; docs capture Swissquote fix and parity. Co-authored-by: Cursor <cursoragent@cursor.com>
25 KiB
sunfish-a16-rom Constitution
Project: Android 16 custom ROM for Google Pixel 4a (sunfish) —
AXP.OS Magisk resurrection track (AXP_Resurection).
This project resurrects AXP.OS Pro capability on LineageOS 23.2 / Android 16 for sunfish (Magisk like GOLDEN). Functionality and application compatibility first, then hardening. The project must remain debuggable and reproducible.
This constitution is specific to AXP_Resurection. Sibling sunfish-a16-rom
is the KernelSU standby track. It does not inherit SSYSTEMS, company
GitLab, Redmine, or buildout-saar governance.
Version: 0.3.1 | Ratified: 2026-08-09 | Last Amended: 2026-10-07
Core Principles
I. Independence from SSYSTEMS governance
This is a personal project. Code, Spec Kit, documentation, Git hosting, and workflow are owned by this project.
Do not apply SSYSTEMS AGENTS.md, Redmine tickets, r{ticket}_* branch rules,
mandatory company MRs, production-read-only company policy, client conventions,
company GitLab, or corporate CI unless an explicit later decision says otherwise.
pm-test01 (or any company hypervisor) may host rom-dev01 with permission.
That is infrastructure only. It is not part of this project's logical
architecture or governance.
II. Spec-as-source
For each feature, specs/NNN-*/spec.md is the only human-edited requirements
source. plan.md and tasks.md are derived artifacts and must be regenerated
after meaningful spec changes (/speckit-plan, /speckit-tasks).
Unresolved technical decisions must be investigated in the relevant feature spec. Do not invent implementation details in the constitution, commits, or agent improvisation.
III. Functionality first, hardening second
Compatibility with the known-good AXP.OS workflow on this sunfish device is the MVP gate. Hardening must not knowingly break that baseline without the regression being isolated, documented, and reversible.
AXP.OS Pro parity intent: the product goal is to reproduce AXP.OS Pro functionality, except features that are obsolete, incompatible with LineageOS 23.2 / Android 16 / sunfish, or deliberately substituted (for example Magisk → KernelSU-Next; AXP backup tooling → NeoBackup as an external user tool).
Degoogle as far as a free replacement keeps the function. microG plus the
project-patched Play Store stay. Location uses the LineageOS 23.2 stack so a
fix stays accurate and fast; do not apply AXP's location lockdown or delete
the IZat/XTRA/xtwifi blobs. A settings switch, default off, may stop LPP
(and the LPPE session it carries) plus the loc_launcher service that
starts XTRA and IZat.
docs/axp-pro-parity.md and docs/hardening-backlog.md are non-normative
product/backlog trackers. A row becomes a requirement only when promoted into a
feature spec.md. For an active feature, this constitution plus that feature's
spec.md remain authoritative if a backlog row conflicts.
IV. Small, attributable, reversible changes
Prefer minimal patches with clear upstream attribution. Never change several high-risk subsystems at once when the result cannot be attributed to one change. Keep a known-good flashable build for each completed stage.
V. Prefer native, auditable ROM functionality
Prefer ROM-native features over LSPosed, Zygisk, or root modules when a feature can reasonably be implemented in the ROM. Do not make unrestricted signature spoofing a general platform capability.
Core architecture
- Base ROM: LineageOS 23.2 / Android 16 for sunfish.
- Base kernel / device stack: the stack compatible with that LineageOS 23.2 sunfish build.
- Do not substitute an old GrapheneOS, stock Android 13, or unrelated prebuilt kernel image.
- Port applicable historical GrapheneOS sunfish kernel hardening into the current kernel where still relevant. (Last GrapheneOS sunfish line was Android 13 — useful as historical reference only; GOLDEN today runs AXP on Android 15, which is a different stack.)
- Use modern GrapheneOS Android 16 implementations as the preferred reference for framework-level hardening where they can be cleanly adapted.
- Use modern GrapheneOS kernel hardening as a technique/reference source as well: identify the security property provided by current implementations and evaluate whether an equivalent can be safely adapted or backported to the LineageOS sunfish 4.14 kernel. Do not directly transplant patches that depend on newer GKI/kernel/hardware facilities.
- Audit the AXP.OS sunfish kernel patch stack, including AXP-specific changes as well as patches inherited from DivestOS, GrapheneOS or upstream. Prefer the original upstream source when provenance can be established and avoid applying duplicate/equivalent fixes already present in LineageOS.
- Port applicable security/privacy patches from AXP.OS and DivestOS.
- Use AXP.OS as the principal compatibility reference (microG, patched Phonesky/Google Play, signature spoofing, call recording, privacy behaviour).
- Use msg-GrapheneOS only as a reference for concepts such as KernelSU/SukiSU integration, SUSFS, root-on-boot modes, signing, and OTA design.
Reference source order
| Role | Source |
|---|---|
| Base | LineageOS 23.2 |
| Compatibility / privacy behaviour | AXP.OS |
| Modern + historical sunfish hardening | GrapheneOS |
| Upstream/historical patches behind AXP | DivestOS |
DivestOS is a recognised reference, not a fourth ROM base.
Compatibility baseline
There are two Pixel 4a (sunfish) devices — see docs/device-roles.md:
- GOLDEN — daily-driver AXP.OS with working banks/microG/Phonesky/Insular; do not flash experimental project ROMs on it.
- LAB — dedicated flash/test device; all experimental images go here.
The GOLDEN AXP installation is the live compatibility oracle (essential
state documented in 002; may be re-queried via adb later). Broader product
intent is AXP.OS Pro feature parity per docs/axp-pro-parity.md.
The new ROM must reproduce at minimum (MVP hard gates):
- working microG;
- working patched Google Play / Phonesky;
- working push notifications;
- Insular managed profile;
- Yuh working inside Insular;
- Swissquote working inside Insular;
- application installation and updates through patched Google Play;
- banking applications running without root privileges.
Yuh and Swissquote inside Insular are hard-gates of the compatibility MVP. N26 and Revolut are later optional targets and must not block the MVP.
MVP levels
| Level | Through | Meaning |
|---|---|---|
| Compatibility MVP | 007 |
microG, patched Phonesky, managed profile, Yuh and Swissquote PASS, Play install/update; banking apps never receive root |
| Daily-driver MVP | 010 |
Compatibility MVP plus accepted KernelSU integration, native call recording, FLAG_SECURE and accepted usability/privacy features |
007 owns banking acceptance. A rootless snapshot of our current ROM is recorded
before adding root; PASS is not a prerequisite. 006 is deferred. Root is not
accepted unless both Yuh and Swissquote pass on the tested stack. If experiments
fail, keep the feature incomplete or withdraw root; do not claim compatibility.
Signing/AVB (011) repeats banking regression; hardening follows in 012–013.
Island is the current LAB managed-profile tool; historical Insular references
remain valid as reference workflows, not a requirement to install both tools.
Exact package versions, signatures, Magisk/DenyList state, UIDs, and related
inventory belong in 002-axp-reference-capture. Do not invent those values here.
Google compatibility stack
Expected package architecture:
com.google.android.gms= microG Services Corecom.google.android.gsf= GSF Proxycom.android.vending= patched Google Play / Phonesky
Do not install FakeStore or microG Companion if it conflicts with the real
patched com.android.vending.
Patched Phonesky must be integrated as a privileged system application with the required permission / default-permission XML configuration.
Signature spoofing must be native, restricted to explicitly authorized packages/signers, and auditable. It must not depend on LSPosed. microG and patched Phonesky must continue working when optional root/Zygisk-style functionality is unavailable.
Phonesky is an external/proprietary input. Do not commit Google proprietary APKs
to Git. 004-microg-phonesky-integration defines the reproducible obtain →
patch → sign → priv-app procedure. Phonesky signing strategy must be decided
before shipping an updatable Play Store build.
Concrete spoofing implementation is decided in
005-restricted-signature-spoofing after studying LineageOS 23.2, microG, and
AXP. Prefer package/signer-restricted support over an open generic fake-signature
permission.
Banking / Insular workflow
Preserve the known-good AXP golden banking flow as the initial compatibility
test (exact package/process names from 002):
- Install the banking application via Aurora Store.
- Do not open the application.
- Add it to Magisk DenyList before the first process start (include relevant processes, not only the package name).
- Clone/install it into the Island work profile (GOLDEN measured tool).
- First launch occurs inside Island.
- Patched Google Play is also available inside Island.
- If the banking app requires a Play Store update, perform that update from inside the work profile.
- Re-test login, biometrics, push, confirmations, and reboot behaviour.
Insular should initially remain an ordinary user application for easier testing and upgrades. It may later become a normal preinstalled system app, but not a privileged app unless a concrete audited requirement exists.
Managed Mainland must remain optional and disabled by default.
microG, GSF Proxy, and patched Phonesky should eventually be automatically available in managed profiles.
Root architecture
Ship root for this track (AXP_Resurection / 009): Magisk, matching
AXP.OS / GOLDEN (newest Magisk stable that works on sunfish / LOS 23.2;
AXP-like preinstalled but not fully activated layout; DenyList-class hiding
so banking apps never receive root).
KernelSU-Next / SusFS work from the sibling sunfish-a16-rom track remains
out of ship here. Existing functional KernelSU kernels MAY be recycled
for debug/reference only (009 FR-016) and MUST NOT gate Magisk acceptance.
Required properties:
- root is explicitly granted only as Magisk intends (owner-approved apps);
- banking applications never receive root (DenyList-class);
- managed-profile UIDs must be tested independently from owner-profile UIDs;
- Magisk version pins follow newest-stable-then-pin policy (fetch fresh upstreams; never ship from shallow/stale host copies).
Do not introduce Zygisk or LSPosed for ROM features that can be native (spoofing, call recording, FLAG_SECURE). Magisk modules only where AXP/GOLDEN parity truly requires them.
An optional boot mode with root unavailable may be implemented later as a diagnostic/fallback mechanism.
Relationship to sibling KernelSU track
The sunfish-a16-rom workspace/repo keeps the earlier KernelSU / split
roadmap on standby. This constitution applies only to AXP_Resurection.
Do not silently reintroduce KernelSU as the default ship root in this tree.
Features integrated directly in the ROM
Prefer native ROM functionality for:
- unrestricted call recording independent of region. Use AXP.OS / EXTENDROM /
iodéOS as behavioural and implementation references, but re-investigate
Android 16 / LineageOS 23.2 Dialer, CarrierConfig, and framework paths before
porting. Do not assume AXP's older (e.g. Android 11/13) restriction-toggle
overlays apply unchanged to Android 16 (
008); - native configurable
FLAG_SECUREoverride (009):- Android's normal
FLAG_SECUREbehaviour remains the default; - user-selectable global override only (no per-app lists);
- covers screenshots and screen recording/capture;
- no LSPosed, Zygisk, or root-module dependency;
- Android's normal
- configurable hosts/DNS/privacy support;
- automatic reboot after configurable inactivity;
- configurable automatic Wi-Fi/Bluetooth shutdown where practical.
Do not require LSPosed for call recording or FLAG_SECURE.
FLAG_SECURE override is a project-specific requirement (not an AXP Pro
catalog feature). Track it under project-specific additions in
docs/axp-pro-parity.md, not as AXP parity.
Hardening strategy
Hardening is incremental. Every significant hardening change must:
- be isolated in a comprehensible commit;
- document its upstream/reference source;
- remain revertible;
- pass boot and basic hardware tests;
- pass the compatibility regression suite before being accepted.
Preferred source order for modern framework hardening:
- modern GrapheneOS Android 16 implementation;
- AXP.OS / DivestOS implementation;
- historical GrapheneOS sunfish implementation where hardware-specific.
Do not attempt to emulate hardware protections unsupported by the Pixel 4a.
Document EOL limits in 013 / hardening work: patches we can backport in-tree
versus proprietary vendor/modem firmware we cannot replace. Never blindly copy
patches; establish what problem they solve, whether Android 16 / LineageOS
already solves it, and whether they remain applicable to sunfish.
Candidate ideas live in non-normative docs/hardening-backlog.md until promoted
into a feature spec.
Build targets and signing
- Development target:
userdebug. - Release target:
user(when signing / AVB / release work lands). - Early phases: development/test-keys.
- Project-owned platform/release/AVB keys: introduced in
011-signing-avb-otaafter a stable functional ROM exists. - Exception: any key that must remain stable early for updateability (especially patched Phonesky signing) must be decided before distributing an updatable first version.
userdebug is the default development build. Banking compatibility failures
observed on userdebug must not be considered definitive until retested on
a user / release-like test build where build type or test-key state may affect
application behaviour. Final production signing, AVB, and relocking still belong
to 011, which must re-run the full Yuh + Swissquote regression on the
really signed/relocked ROM.
Experimental flashing happens only on LAB and requires an unlocked
bootloader on that device. LAB and GOLDEN lock/bootloader state are measured in
002; if LAB is locked, unlocking LAB is a prerequisite before the first 003
flash. Never unlock/wipe/flash GOLDEN for project experiments. After the ROM is
stable:
- generate dedicated ROM signing keys;
- implement reproducible release signing;
- configure Android Verified Boot with project-owned keys;
- support factory/recovery images and OTA generation;
- test bootloader relocking with the custom trust chain.
KernelSU compiled into a project-signed kernel is compatible with the project signing model; do not treat root presence itself as an AVB failure.
Private signing material must never be committed to Git. Public certificates
(e.g. *.x509.pem) may be versioned when useful for documentation/reproducibility.
Any signing key whose identity must remain stable across updates (Phonesky, platform/release, AVB, OTA, etc.) must have an encrypted/offline backup before the first build that depends on that key is distributed or adopted as a baseline.
OTA is considered architecturally so doors stay open, but is not implemented and
does not block early builds. Real OTA/signing/AVB work belongs to
011-signing-avb-ota.
Host boundary: rom-dev01 is a prerequisite
Provisioning of the Proxmox VM, public IP selection, Hetzner/vswitch details,
PVE lifecycle, and SSYSTEMS Salt saltenv=base bootstrap are out of scope
for this repository.
Assume once development starts on the host:
rom-dev01exists;- Ubuntu Server 24.04 LTS is installed;
- one reachable public IPv4 address (public NIC only; no required
10.100.67.0/18NIC); - SSH administration works;
- SSYSTEMS base provisioning is complete.
This project must not manage pm-test01, company Salt states, or company
governance from this repository.
Isolation posture (guest)
Goal: keep rom-dev01 as isolated as practical from SSYSTEMS internal
infrastructure while accepting that the public vSwitch/VLAN may be shared with
other lab/gateway VMs.
Required posture from the ROM project's perspective:
- Public NIC only — no additional NIC on SSYSTEMS internal networks
(e.g.
10.100.67.0/18) unless a later documented exception appears. - No dependency on internal SSYSTEMS services for normal ROM work: internal DNS, LDAP/SSO, company VPN, company GitLab, NFS/CIFS to corporate storage, or company Zabbix as a required path.
- Project UIs (Gitea, Semaphore) must not need to be exposed to the whole Internet; prefer localhost / SSH tunnel / existing tight SSH access.
- Guest firewall should favour default-deny inbound beyond SSH administration and should block or avoid unnecessary traffic toward known SSYSTEMS internal ranges once those ranges are known to the operator.
- DNS for day-to-day project use should not require SSYSTEMS internal resolvers.
- Sharing the public VLAN/subnet with gateway VMs is acceptable and does not by itself place this project under SSYSTEMS product governance.
- Hypervisor/storage (
pm-test01) remain unavoidable physical hosting; they are not a license to couple the guest into internal ops services.
Concrete public IPs, PVE bridges, and company Salt firewall templates stay
outside this repository. Feature 001 implements/verifies the guest-side
posture on the already-provisioned host.
Capacity assumptions (do not oversize builds)
Initial host capacity to plan around:
- 6 vCPU
- 52 GB RAM
- 2 TB disk (expandable if required)
- 32 GB VM swap
Builds must support conservative parallelism and tolerate swap when required. Do not assume additional resources are available.
Project account
Do not hard-code laptop admin usernames as architectural requirements. After the host exists, the project may create/use a dedicated account:
android-build
for Android source trees and builds.
Laptop vs host roles
Laptop:
- Cursor UI / Remote SSH client;
- adb / fastboot workstation;
- Pixel physically attached for flashing/testing;
- small local checkouts where useful.
rom-dev01:
- Android source trees,
.repo,out/, ccache; - Gitea, Semaphore, Ansible;
- build scripts, logs, artifacts under
/srv/rom/.
Do not design the normal workflow around remote USB passthrough.
Tooling ownership inside this project
Once rom-dev01 exists:
- Ansible (+ Semaphore UI) owns ROM workflow: sync, patches, builds, cleanup, manifest capture, artifact collection, publication.
- Semaphore must not hide undocumented build behaviour and must not be exposed directly to the Internet; access via existing network/SSH constraints.
- Gitea is private project Git hosting on the VM; not company GitLab.
- The first LineageOS build should be performed manually before fully automating the workflow.
Salt used by SSYSTEMS to create the VM remains outside this project. This repo does not encode company Salt VM creation.
Git / Gitea model
Use a private Gitea instance on rom-dev01 with multiple repositories, not one
giant monorepo. Preserve Android/repo natural layout. Fork only repositories
that this project actually modifies.
Initial repositories:
sunfish-a16-rom— Spec Kit, constitution, roadmap, global documentation (this meta repository; laptop staging is temporary until Gitea exists)sunfish-rom-manifest— repo manifestssunfish-rom-build— scripts / Ansible / Semaphore / build toolingsunfish-rom-patches— patchsets / tracking
Later, only when needed: kernel fork, frameworks/base, Settings, Dialer,
vendor/config.
Do not commit:
.repo;out/;- ccache;
- complete upstream Android source trees;
- private signing keys (including Phonesky signing keys);
- personal phone dumps containing credentials or identifiers;
- proprietary Google APKs.
Initially a single developer. Do not design multi-developer permissions/CI until needed.
Project-owned Gitea repositories must have an off-VM backup or mirror. The build VM must not be the only copy of project history (laptop clones, Borg, or another agreed target are acceptable).
Artifacts initially live under /srv/rom/artifacts/ and are copied with rsync
to the laptop for flashing. Significant releases may later use Gitea Releases
(ROM ZIP, needed images, hashes, manifest, build metadata). Intermediate build
outputs are not published.
Reproducibility
Every meaningful build must capture at least:
- exact manifest;
- source revisions;
- project patch revisions;
- build variant;
- relevant configuration;
- SHA-256 hashes;
- compressed build log.
Prefer small, source-attributed commits over large opaque patch dumps.
Development stages
Progress in this order unless a documented technical dependency requires otherwise:
- Document the GOLDEN AXP oracle and label GOLDEN vs LAB (
002) — essential capture + verify Yuh/Swissquote on GOLDEN; no NeoBackup/wipe of GOLDEN. - Build and boot vanilla LineageOS 23.2 on LAB only (
003). - Integrate microG, GSF Proxy, patched Phonesky, and restricted native
signature spoofing on LAB (
004–005). - Record current rootless LAB banking outcomes in
007preflight; defer006. - Integrate KernelSU-Next and verified module unmount on LAB (
007), followed by optional SUSFS and evaluated attestation experiments. Both banks must PASS to accept root and the Compatibility MVP. - Native call recording and configurable
FLAG_SECURE(008–009). - Remaining AXP Pro usability/privacy features (
010; matrix spans004–013, see non-normativedocs/axp-pro-parity.md). - Signing, AVB, OTA + full banking regression on signed/relocked LAB ROM
(
011). - Incremental userspace then kernel hardening (
012–013; candidates in non-normativedocs/hardening-backlog.md). - Optional later: alternative KernelSU, root-disabled boot, extra banking apps.
Before stressing LAB: document official Google factory-image emergency rescue
for LAB (002/003). GOLDEN remains a live AXP reference — not something we
wipe and rebuild for day-to-day bring-up. NeoBackup is optional personal
preference only, not a project gate.
001-development-environment starts after rom-dev01 exists. It specifies
the ROM development environment on that host (packages, android-build,
repo/git, ccache, /srv/rom, Gitea, Semaphore, Ansible, Spec Kit, Remote SSH
workflow). It does not specify Proxmox VM creation.
For 005-restricted-signature-spoofing: first verify what LineageOS 23.2 already
provides for restricted microG spoofing; extend only as needed for patched
Phonesky — do not assume a from-scratch spoofing stack.
Testing rule
Never change several high-risk subsystems simultaneously when the result cannot be attributed to one change.
Regression testing should include, as applicable to the stage:
boot; encryption/PIN; calls/mobile data; Wi-Fi; Bluetooth; GPS; camera; audio; NFC; sensors; microG Self-Check; Google Play login/install/update; push; Insular work profile; Yuh; Swissquote; biometrics; banking confirmations; reboot; KernelSU application profiles where applicable.
Project identity
The result is a LineageOS-based custom ROM with selected compatibility, privacy, and hardening features. It must not be presented as official GrapheneOS, LineageOS, AXP.OS, DivestOS, or iodéOS.
Public marketing/ROM brand naming is deferred and must not contaminate
repository, spec, or architecture names. The technical project name remains
sunfish-a16-rom.
Spec Kit and documentation language
Primary technical documentation and the constitution are written in English. Personal notes may be Spanish. Do not maintain duplicated bilingual docs.
Use a clean upstream Spec Kit. Do not copy SSYSTEMS Spec Kit constitutions, company project-create flows, or company runtime configuration.
Create feature specs only when ready to work them. Keep a non-binding roadmap
in specs/README.md for later features; do not create empty stub directories for
all future numbers in advance.
Governance
- This constitution supersedes conflicting informal notes for project rules.
- Feature requirements live in
spec.mdfiles; amend those rather than overloading this document with implementation detail. docs/axp-pro-parity.mdanddocs/hardening-backlog.mdare non-normative until promoted into a feature spec.- Amendments to this constitution require an explicit documented change and version/date bump.
AGENTS.mdexplains agent working rules for this repository only; it must not duplicate this constitution.
Amendment 0.2.0 — 2026-09-15
Owner-authorized remediation of C1/C2: defer the rootless PASS gate, retain a
measured pre-root snapshot, and assign both-bank acceptance to 007. This
changes sequencing, not LAB-only protection or the prohibition on banking root.
Amendment 0.2.1 — 2026-09-15
Upstream freshness for root stack and similar deps: integrate from newest
compatible stable/tagged upstream (full git history), verify version codes
against the matching manager before long builds; pin only after LAB works.
Triggered by stale shallow ReSukiSU mirror yielding KSU_VERSION=30701.
Amendment 0.3.1 — 2026-10-07
Owner: degoogle where a free alternative keeps the function; microG and the patched Play Store stay. Location stays on the LineageOS 23.2 code (accurate and fast), not AXP's location cuts. Moving apps such as OpenEUICC track the latest upstream, not the revision frozen in an AXP zip.