AXP Magisk resurrection track: Speckit 009 port AXP/LOS22 to LOS23.
Ship Magisk like GOLDEN; KernelSU optional recycle only; parallel to sunfish-a16-rom standby.
This commit is contained in:
commit
12d2179c20
150 files changed
+26263
No files matched your search
@@ -0,0 +1,9 @@
|
||||
# Contracts: N/A for 001
|
||||
|
||||
Feature `001-development-environment` is host/Git/service bootstrap.
|
||||
|
||||
It does **not** expose a project-owned HTTP API, CLI contract for external
|
||||
consumers, or IPC schema that needs `contracts/` files.
|
||||
|
||||
Service access is operational (SSH tunnel to Gitea/Semaphore UIs) and is
|
||||
documented in `plan.md` / `quickstart.md` instead.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Data model (operational): 001-development-environment
|
||||
|
||||
This is **not** an application domain model. It records host/Git/service
|
||||
entities for planning clarity. No ORM, no API schemas.
|
||||
|
||||
## Entities
|
||||
|
||||
### Host (`rom-dev01`)
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| OS | Ubuntu 24.04 LTS (precondition) |
|
||||
| Capacity | ~6 vCPU / 52 GB / 2 TB / 32 GB swap |
|
||||
| Network | Public IPv4 NIC; no required internal NIC |
|
||||
| Management | External Salt `saltenv=base` + project config |
|
||||
|
||||
### Account `android-build`
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| Type | Unprivileged login user |
|
||||
| Owns | `/srv/rom/{src,references,tooling,ccache,artifacts,logs}` (as documented) |
|
||||
| Must not | Need root to compile; own Gitea/Semaphore system dirs |
|
||||
|
||||
### Meta working tree
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `/home/android-build/sunfish-a16-rom` | Spec Kit + specs + docs (Cursor Remote SSH) |
|
||||
|
||||
### Path root `/srv/rom`
|
||||
|
||||
| Child | Purpose | Populated in 001? |
|
||||
|-------|---------|-------------------|
|
||||
| `src/` | Future Android trees | Empty (no sync) |
|
||||
| `references/` | Future AXP/reference | Empty |
|
||||
| `tooling/` | Project tooling helpers (not Spec Kit checkout) | Partial OK |
|
||||
| `ccache/` | CCACHE_DIR | Yes (dir + env) |
|
||||
| `artifacts/` | Laptop handoff | Dummy file for smoke |
|
||||
| `logs/` | Bootstrap/preflight logs | Yes |
|
||||
| `secrets/` | Restricted placeholder | Empty; no keygen |
|
||||
|
||||
### GiteaInstance
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| Bind | Loopback / non-public |
|
||||
| Repos | `sunfish-a16-rom`, `sunfish-rom-manifest`, `sunfish-rom-build`, `sunfish-rom-patches` |
|
||||
| Canonical | Yes after first successful push of meta repo |
|
||||
|
||||
### GitMirror (off-VM)
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| Location | Laptop bare mirrors (initial) |
|
||||
| Direction | Laptop pulls (`clone --mirror` / `remote update`); no VM→laptop SSH |
|
||||
| Scope | All four project repos |
|
||||
| Success | At least one verified mirror cycle |
|
||||
|
||||
### AnsibleController / SemaphoreInstance
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| Host | `rom-dev01` |
|
||||
| First job | Environment smoke playbook |
|
||||
| Exposure | Same private access model as Gitea |
|
||||
|
||||
## Relationships
|
||||
|
||||
```text
|
||||
AdminSSH ──manages──► Host packages/systemd/firewall
|
||||
android-build ──writes──► /srv/rom (build-related trees)
|
||||
GiteaInstance ──hosts──► four Repositories
|
||||
Laptop ──mirrors──► Repositories (bare)
|
||||
SemaphoreInstance ──runs──► Ansible smoke playbook on Host
|
||||
Laptop Cursor ──RemoteSSH──► Host workspace
|
||||
Laptop ──rsync──► /srv/rom/artifacts (pull)
|
||||
```
|
||||
|
||||
## State transitions (meta Git)
|
||||
|
||||
1. `laptop-staging-only`
|
||||
2. `copied-to-host` (pre-Gitea)
|
||||
3. `gitea-canonical` (push complete)
|
||||
4. `mirrored-off-vm` (SC-007)
|
||||
|
||||
Do not destroy state (1) until (3) and (4) succeed.
|
||||
@@ -0,0 +1,476 @@
|
||||
# Implementation Plan: Development environment on rom-dev01
|
||||
|
||||
**Branch**: `001-development-environment` | **Date**: 2026-08-09 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/001-development-environment/spec.md`
|
||||
|
||||
**Mode**: Documentation/design only until `rom-dev01` exists with working SSH.
|
||||
No implementation, host mutation, or Android sync/build in this planning phase.
|
||||
|
||||
## Summary
|
||||
|
||||
Feature `001` prepares an already-existing Ubuntu 24.04 host (`rom-dev01`) as the
|
||||
ROM development environment: unprivileged `android-build` account, `/srv/rom`
|
||||
layout, Lineage/AOSP host toolchain + ccache, Spec Kit meta-repo bootstrap,
|
||||
private Gitea (four repos) with off-VM Git history mirror, Ansible + Semaphore
|
||||
smoke orchestration, thin-client laptop workflow, and guest isolation posture.
|
||||
|
||||
It does **not** create the Proxmox VM, sync LineageOS, build Android, or touch
|
||||
the Pixel. Those belong to human Salt/PVE prep (`rom-dev01` prerequisite) and
|
||||
features `002`/`003`+.
|
||||
|
||||
**Unlocks**: after P1, host is usable for work; after P2, Gitea is canonical and
|
||||
orchestration smoke works → ready for `002` then `003`.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Bash / Ansible YAML; Ubuntu Server 24.04 LTS on host;
|
||||
Spec Kit docs in Markdown (English).
|
||||
|
||||
**Primary Dependencies**: apt packages per current LineageOS/AOSP host build
|
||||
docs at implementation time; `repo`; `git` + `git-lfs`; `ccache`; Gitea;
|
||||
Ansible; Semaphore UI; OpenSSH.
|
||||
|
||||
**Storage**: Host filesystem paths under `/srv/rom/` (no project-owned LVM/fstab
|
||||
changes). Secrets directory restricted/empty in `001`.
|
||||
|
||||
**Testing**: Observable shell/service checks (clean-login tool smoke, systemd
|
||||
active, local curl, rsync SHA256, restart survival). No Android instrumentation.
|
||||
|
||||
**Target Platform**: Single VM `rom-dev01` (~6 vCPU / 52 GB RAM / 2 TB /
|
||||
32 GB swap) + thin laptop (Cursor Remote SSH, adb/fastboot, rsync).
|
||||
|
||||
**Project Type**: Infrastructure / host bootstrap for Android ROM development.
|
||||
|
||||
**Performance Goals**: Toolchain available in a clean `android-build` login;
|
||||
services survive restart; no public exposure of Gitea/Semaphore. Build `-j`
|
||||
tuning is **out of scope** (owned by `003`).
|
||||
|
||||
**Constraints**:
|
||||
- VM/PVE/IP/Salt `saltenv=base` provisioning is external; do not fight managed
|
||||
config silently.
|
||||
- Never build Android as root; never `chmod 777`.
|
||||
- Never flush firewall / risk active SSH path.
|
||||
- Do not bind Gitea/Semaphore to `0.0.0.0` without an explicit protected design
|
||||
(default: loopback / non-public + SSH tunnel).
|
||||
- No secrets in Git or build logs.
|
||||
- Do not delete laptop staging tree before Gitea + mirror verified.
|
||||
|
||||
**Scale/Scope**: One developer; four Gitea repos; one smoke Ansible playbook;
|
||||
no distributed CI / registry / Kubernetes.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Independence from SSYSTEMS governance | PASS | No Redmine/GitLab/company MR workflow; no Salt VM creation from this repo |
|
||||
| Spec-as-source | PASS | Plan derived from `001/spec.md` + constitution `0.1.5` |
|
||||
| Parity/hardening docs non-normative | PASS | Not used as requirements for `001` |
|
||||
| Host boundary: VM is prerequisite | PASS | Preconditions assume host exists; non-goals forbid PVE/qm/Salt states |
|
||||
| Isolation posture (guest) | PASS | Public-NIC workflow; UIs not world-exposed; SSH preserved |
|
||||
| No Android trees on laptop | PASS | Thin-client + `/srv/rom` on host |
|
||||
| Secrets not in Git | PASS | Explicit secrets handling |
|
||||
| Magisk/KSU/microG/signing out of `001` | PASS | Listed in DO NOT |
|
||||
| Capacity honesty | PASS | Plan around 6/52/2T/32; parallelism deferred to `003` |
|
||||
|
||||
**Post-design re-check**: PASS — artifacts (`research.md`, `quickstart.md`,
|
||||
operational `data-model.md`) stay inside `001` scope; no invented API contracts.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/001-development-environment/
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0
|
||||
├── data-model.md # Operational entities only (no app domain model)
|
||||
├── quickstart.md # Validation / cold-start guide
|
||||
├── contracts/ # N/A for 001 (see contracts/README.md)
|
||||
└── tasks.md # Created later by /speckit-tasks — NOT this command
|
||||
```
|
||||
|
||||
### Host layout (target on rom-dev01)
|
||||
|
||||
```text
|
||||
/srv/rom/
|
||||
├── src/ # future Android trees (empty in 001; no repo sync)
|
||||
├── references/ # future AXP/reference captures (empty OK)
|
||||
├── tooling/ # project scripts / ansible / helper tooling
|
||||
├── ccache/ # CCACHE_DIR for android-build
|
||||
├── artifacts/ # handoff to laptop (dummy file for smoke)
|
||||
├── logs/ # install/bootstrap logs
|
||||
└── secrets/ # restricted; empty; no key generation in 001
|
||||
|
||||
# service data (exact paths chosen at implement time; document them)
|
||||
# e.g. /var/lib/gitea, /etc/gitea, semaphore data dir
|
||||
|
||||
# Canonical meta Spec Kit working tree (Cursor Remote SSH edits here):
|
||||
/home/android-build/sunfish-a16-rom
|
||||
|
||||
# /srv/rom/tooling/ = project tooling only (scripts helpers, etc.)
|
||||
# — NOT the Spec Kit meta checkout
|
||||
```
|
||||
|
||||
### Repository roles (Gitea)
|
||||
|
||||
| Repo | Contents |
|
||||
|------|----------|
|
||||
| `sunfish-a16-rom` | Spec Kit + specs + docs (meta) |
|
||||
| `sunfish-rom-build` | Scripts + Ansible + Semaphore/build automation |
|
||||
| `sunfish-rom-manifest` | Repo manifests (empty at first) |
|
||||
| `sunfish-rom-patches` | Patchsets / tracking (empty at first) |
|
||||
|
||||
Do **not** mix executable automation into the Spec Kit meta repo.
|
||||
|
||||
### Meta repository content (laptop staging → Gitea)
|
||||
|
||||
```text
|
||||
/home/android-build/sunfish-a16-rom/ # Spec Kit + docs only
|
||||
├── .specify/
|
||||
├── specs/
|
||||
├── docs/
|
||||
├── AGENTS.md
|
||||
└── …
|
||||
```
|
||||
|
||||
**Structure Decision**: Infrastructure feature — host paths + Git/service
|
||||
bootstrap. No application `src/` tree inside Spec Kit for `001`.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> No constitution violations requiring justification.
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|--------------------------------------|
|
||||
| — | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 1. Summary (expanded)
|
||||
|
||||
`001` makes `rom-dev01` a usable ROM workstation and private Git home without
|
||||
performing ROM builds. Completion means: clean `android-build` toolchain smoke
|
||||
passes; `/srv/rom` owned correctly; Spec Kit tree lives on host; Gitea holds
|
||||
four repos and is canonical; laptop has an off-VM bare mirror; Ansible+Semaphore
|
||||
run one smoke playbook; thin-client + isolation docs/checks pass; no PVE/Salt
|
||||
fight, no Pixel/LOS work.
|
||||
|
||||
## 2. Constitution check / source of truth
|
||||
|
||||
Authoritative for this plan:
|
||||
|
||||
1. `.specify/memory/constitution.md` **v0.1.5**
|
||||
2. `specs/001-development-environment/spec.md`
|
||||
3. `AGENTS.md`
|
||||
|
||||
Non-normative (do not treat as `001` requirements):
|
||||
`docs/axp-pro-parity.md`, `docs/hardening-backlog.md`.
|
||||
|
||||
## 3. Preconditions
|
||||
|
||||
Assume already true before `/speckit-implement`:
|
||||
|
||||
- `rom-dev01` exists (human + SSYSTEMS Salt/PVE)
|
||||
- Ubuntu Server 24.04 LTS
|
||||
- One reachable public IPv4 (public NIC only)
|
||||
- SSH administration works
|
||||
- `saltenv=base` already applied
|
||||
- Capacity approximately: 6 vCPU / 52 GB RAM / 2 TB disk / 32 GB swap
|
||||
|
||||
Do **not** create, resize, or re-IP the VM from this project.
|
||||
|
||||
## 4. Non-goals / boundaries
|
||||
|
||||
**DO NOT** (plan / tasks / implement):
|
||||
|
||||
- create or configure the Proxmox VM; emit `qm`/PVE provisioning;
|
||||
- choose or hard-code the public IPv4;
|
||||
- write SSYSTEMS Salt states; modify `pm-test01`;
|
||||
- assume company internal DNS/VPN/LDAP/GitLab/NFS/Zabbix is required;
|
||||
- start LineageOS `repo sync` or any Android build;
|
||||
- touch/backup/flash the Pixel (NeoBackup belongs to `002`);
|
||||
- introduce microG, Phonesky, KernelSU, Magisk, SUSFS, or hardening;
|
||||
- generate ROM/AVB/Phonesky signing keys;
|
||||
- put `.repo`, `out/`, or ccache on the laptop;
|
||||
- require Ansible on the laptop;
|
||||
- expose Gitea or Semaphore to the public Internet;
|
||||
- design GitLab/Jenkins/Kubernetes/registry/distributed runners;
|
||||
- turn Semaphore into the Android build pipeline yet;
|
||||
- invent an API/data model merely to satisfy a template;
|
||||
- hard-code facts that must be measured on `rom-dev01`;
|
||||
- duplicate requirements owned by `002`/`003`+.
|
||||
|
||||
**Implement-time DO NOT** (operational):
|
||||
|
||||
- run Android builds as root; `chmod 777` project trees;
|
||||
- blindly dist-upgrade; replace apt sources without need;
|
||||
- overwrite Salt/base-managed config silently;
|
||||
- flush firewall/nftables; risk active SSH management path;
|
||||
- bind Gitea/Semaphore to `0.0.0.0` without explicit protected design;
|
||||
- commit passwords/tokens/private keys; plaintext secrets in Ansible in Git;
|
||||
- delete laptop staging before Gitea + mirror verified;
|
||||
- delete/overwrite working data only to fake idempotency;
|
||||
- download full Lineage tree; compile Lineage; connect/flash Pixel;
|
||||
- automate ROM builds through Semaphore yet.
|
||||
|
||||
**Conflict rule**: If base-managed configuration conflicts with project needs,
|
||||
**stop and report** — do not silently replace or fight it; do not “fix”
|
||||
unrelated infrastructure opportunistically.
|
||||
|
||||
## 5. Host preflight (before modifying the host)
|
||||
|
||||
First implement steps are **observational**. Capture and store under
|
||||
`/srv/rom/logs/preflight/` (or create layout first then log):
|
||||
|
||||
- Ubuntu version / kernel
|
||||
- CPU / RAM / swap
|
||||
- filesystem free space (esp. for `/` and future `/srv/rom`)
|
||||
- network interfaces / default route (confirm no required internal NIC)
|
||||
- SSH reachability
|
||||
- existing users / groups
|
||||
- existing firewall (nft/ufw/iptables) summary — **do not flush**
|
||||
- listening ports / services
|
||||
- apt sources summary
|
||||
- hints of Salt/base-managed files if obvious
|
||||
|
||||
Produce a short baseline note in the meta repo docs or `/srv/rom/logs` for later
|
||||
diff. Especially important because `saltenv=base` already touched the machine.
|
||||
|
||||
## 6. Account and permission model
|
||||
|
||||
| Actor | Role |
|
||||
|-------|------|
|
||||
| Existing admin SSH user | packages, systemd, system config, firewall changes (carefully) |
|
||||
| `android-build` | Android sources/builds (later), ccache, artifacts, build tooling; SSH pubkey login from laptop; Cursor Remote SSH user; **never** build as root; **no sudo required to compile** |
|
||||
| `gitea` (service user) | Gitea data/config ownership |
|
||||
| `semaphore` (service user/context) | Semaphore data/config ownership |
|
||||
|
||||
Rules:
|
||||
|
||||
- No `chmod -R 777 /srv/rom`
|
||||
- Group memberships only as needed (e.g. `android-build` owns `/srv/rom` trees
|
||||
it writes; services own their state dirs)
|
||||
- Admin elevates only for system packaging/services
|
||||
|
||||
## 7. `/srv/rom` filesystem layout
|
||||
|
||||
Create with explicit owners/modes (exact modes chosen at implement; document):
|
||||
|
||||
```text
|
||||
/srv/rom/
|
||||
├── src/
|
||||
├── references/
|
||||
├── tooling/
|
||||
├── ccache/
|
||||
├── artifacts/
|
||||
├── logs/
|
||||
└── secrets/ # empty, restricted; do not generate keys in 001
|
||||
```
|
||||
|
||||
- Do **not** manage partitions/LVM/fstab from this project.
|
||||
- Do not populate `references/` (that is `002`) or generate secrets.
|
||||
- `artifacts/` must be writable by `android-build` for dummy + later builds.
|
||||
|
||||
## 8. Android host toolchain (no sync/build)
|
||||
|
||||
- Install host packages using **current primary LineageOS/AOSP build
|
||||
documentation at implementation time** (do not freeze a stale 50-package list
|
||||
in this plan).
|
||||
- Record what was installed (log + short note in meta repo / `/srv/rom/logs`).
|
||||
- Ensure `git`, `git-lfs`, `repo`, `python3`, and Java/toolchain prerequisites
|
||||
required by that documentation.
|
||||
- Configure `ccache`: location (`/srv/rom/ccache`), ownership (`android-build`),
|
||||
size cap, environment (`CCACHE_DIR`, etc.). **Not** tied to inventing `-j`
|
||||
from vCPU/RAM here.
|
||||
- FR-007: document capacity (6/52/32) and that **conservative `-j` / OOM tuning
|
||||
belongs to `003`**, with a one-line recommended starting point only if needed
|
||||
for docs — no build execution in `001`.
|
||||
- Smoke from a **clean login**: primary check is **direct SSH from the laptop as
|
||||
`android-build`** (after pubkey setup) → verify tools. Optional local admin
|
||||
check: `sudo -iu android-build` on the host if needed. **No `repo sync`**.
|
||||
|
||||
## 9. Spec Kit staging bootstrap (before Gitea)
|
||||
|
||||
Egg/chicken sequence (mandatory):
|
||||
|
||||
```text
|
||||
laptop staging:
|
||||
/home/aventura/Workspaces/sunfish-a16-rom
|
||||
↓ rsync/scp/git bundle (preserve .git)
|
||||
rom-dev01 working copy
|
||||
↓
|
||||
install Gitea
|
||||
↓
|
||||
create empty Gitea repo sunfish-a16-rom
|
||||
↓
|
||||
push meta repo
|
||||
↓
|
||||
create sunfish-rom-manifest, sunfish-rom-build, sunfish-rom-patches
|
||||
↓
|
||||
Gitea becomes canonical remote
|
||||
↓
|
||||
host working tree at /home/android-build/sunfish-a16-rom
|
||||
uses Gitea as origin (after push)
|
||||
```
|
||||
|
||||
Do **not** assume `git clone …gitea…` before Gitea exists.
|
||||
Do **not** delete laptop staging until Gitea push + off-VM mirror verified.
|
||||
|
||||
## 10. Gitea
|
||||
|
||||
- Install on `rom-dev01` with persistent data dirs and systemd unit.
|
||||
- Default **UI** access: **loopback / non-public bind + SSH tunnel** from laptop
|
||||
(decision fixed for `001` unless implement discovers a hard conflict — then
|
||||
stop/report).
|
||||
- **Git transport**: document the concrete mechanism at implement time after
|
||||
inspecting the host (HTTP via the same SSH tunnel and/or Git-over-SSH also
|
||||
tunnelled are valid). Do **not** blindly modify OpenSSH managed by
|
||||
`saltenv=base`, and do **not** assume or open a second public SSH port
|
||||
(e.g. `:2222`) for Gitea.
|
||||
- Create admin credentials with restricted local storage; never commit secrets.
|
||||
- Verify: service active; local curl succeeds; direct public Internet access to
|
||||
UI **not** required / not open.
|
||||
|
||||
## 11. Canonical Git transition
|
||||
|
||||
Repos:
|
||||
|
||||
1. `sunfish-a16-rom` — Spec Kit + specs + docs; push existing history
|
||||
2. `sunfish-rom-manifest` — empty
|
||||
3. `sunfish-rom-build` — scripts + Ansible + Semaphore/build automation (seed
|
||||
minimal structure when ready)
|
||||
4. `sunfish-rom-patches` — empty
|
||||
|
||||
Document remotes for host + laptop clones. Company GitLab must not be used.
|
||||
|
||||
## 12. Off-VM Git mirror (P2)
|
||||
|
||||
First implementation (sufficient for `001` SC-007): **laptop-initiated pull**
|
||||
of bare mirrors. The laptop opens the connection (via SSH tunnel / documented
|
||||
Git URL); `rom-dev01` must **not** need inbound SSH to the laptop.
|
||||
|
||||
```text
|
||||
# On laptop (conceptual):
|
||||
git clone --mirror <gitea-repo-url-via-tunnel>
|
||||
cd <repo>.git && git remote update
|
||||
```
|
||||
|
||||
Borg / full Gitea DR is **later**. Requirement is Git history redundancy.
|
||||
|
||||
## 13. Ansible bootstrap (P2)
|
||||
|
||||
- Install Ansible on `rom-dev01` for **project environment** automation.
|
||||
- Keep playbooks and automation in **`sunfish-rom-build`** (not in the Spec Kit
|
||||
meta repo `sunfish-a16-rom`).
|
||||
- No plaintext secrets in Git.
|
||||
|
||||
## 14. Semaphore bootstrap (P2)
|
||||
|
||||
- Install Semaphore as UI over Ansible.
|
||||
- Same exposure model as Gitea (loopback/tunnel).
|
||||
- First integration: **unprivileged** environment smoke playbook only — e.g.
|
||||
gather facts + assert `/srv/rom`, `android-build`, and toolchain checks.
|
||||
**No sudo password / privileged secrets in Semaphore for this smoke.**
|
||||
Privileged automation is a later explicit decision.
|
||||
- **Not** an Android build pipeline.
|
||||
|
||||
## 15. Isolation / firewall / service exposure
|
||||
|
||||
Keep guest isolation posture from constitution/`001` spec:
|
||||
|
||||
- Public NIC only for project workflow
|
||||
- Gitea/Semaphore not world-exposed
|
||||
- Document firewall/DNS expectations
|
||||
|
||||
Implementation safety:
|
||||
|
||||
- never flush/replace existing firewall blindly;
|
||||
- never close current SSH path before a tested replacement;
|
||||
- keep a rollback path;
|
||||
- prefer additive allow rules.
|
||||
|
||||
## 16. Laptop thin-client workflow
|
||||
|
||||
Document and smoke:
|
||||
|
||||
1. Direct SSH from laptop as `android-build` (pubkey); Cursor Remote SSH →
|
||||
`/home/android-build/sunfish-a16-rom` with `User android-build`
|
||||
2. Dummy artifact in `/srv/rom/artifacts` → `rsync` to laptop → SHA256 match
|
||||
3. adb/fastboot remain on laptop; Pixel USB on laptop; no USB passthrough design
|
||||
|
||||
## 17. Verification matrix (FR/SC → evidence)
|
||||
|
||||
| ID | Implementation focus | Observable verification |
|
||||
|----|----------------------|-------------------------|
|
||||
| FR-001 | Create `android-build` + home/workspace docs + SSH pubkey | `id android-build`; `ssh android-build@rom-dev01` from laptop |
|
||||
| FR-002 | LOS/AOSP host deps + ccache | clean SSH login as `android-build`: `git`, `repo`, `ccache -s`, etc. |
|
||||
| FR-003 | `/srv/rom` tree + ownership | `namei -l` / `stat` shows owners; writable artifacts |
|
||||
| FR-004 | Gitea + four repos | local UI/API; four repos listed |
|
||||
| FR-005 | Ansible + Semaphore smoke | Semaphore runs smoke playbook successfully |
|
||||
| FR-006 | Thin-client docs | doc exists; Remote SSH + rsync smoke done |
|
||||
| FR-007 | Capacity / defer `-j` to `003` | short doc records 6/52/32 and defers build jobs |
|
||||
| FR-008 | Spec Kit on host | tree present; after P2, cloned/pushed via Gitea |
|
||||
| FR-009 | Isolation posture | checklist: NIC, binds, firewall notes; SSH still works |
|
||||
| FR-010 | Off-VM Git mirror | laptop bare mirror of four repos once |
|
||||
| SC-001 | Toolchain smoke | clean `android-build` session has tools for later `003` |
|
||||
| SC-002 | Artifacts handoff | dummy file rsync SHA256 match |
|
||||
| SC-003 | Four Gitea repos | listed on Gitea; not company GitLab |
|
||||
| SC-004 | Cold-start workflow doc | quickstart path SSH→workspace→(later build)→rsync→flash |
|
||||
| SC-005 | No PVE management | no qm/PVE playbooks in repo/tasks evidence |
|
||||
| SC-006 | Isolation checklist | passes without requiring VPN/internal DNS |
|
||||
| SC-007 | Mirror demonstrated | off-VM mirror exists and was verified once |
|
||||
|
||||
## 18. Handoff
|
||||
|
||||
**`001` complete** means environment ready for `002` (phone capture) and later
|
||||
`003` (LOS vanilla build) — **not** “start building Lineage now”.
|
||||
|
||||
Do not begin `/speckit-plan` for `002`/`003` until `001` doc cycle + implement
|
||||
are done (avoid document saturation).
|
||||
|
||||
## P1 / P2 sequencing
|
||||
|
||||
### P1 — host usable without Gitea
|
||||
|
||||
1. Host preflight baseline
|
||||
2. Create `android-build`
|
||||
3. Configure developer SSH public-key access for `android-build`
|
||||
4. Verify direct SSH login from the laptop as `android-build`
|
||||
5. Create `/srv/rom` + permissions
|
||||
6. Install build prerequisites (current LOS/AOSP docs)
|
||||
7. `repo` / `git` / `git-lfs` / ccache config
|
||||
8. Copy laptop staging meta repo to host path `/home/android-build/sunfish-a16-rom` (preserve `.git`)
|
||||
9. Clean-shell toolchain smoke via SSH as `android-build`
|
||||
10. Cursor Remote SSH smoke (`User android-build`)
|
||||
11. Dummy artifact → rsync → laptop (SHA256)
|
||||
|
||||
### P2 — reproducible / comfortable
|
||||
|
||||
1. Install Gitea (loopback/tunnel)
|
||||
2. Create four repos
|
||||
3. Push meta repo; set Gitea canonical
|
||||
4. Off-VM bare mirrors on laptop
|
||||
5. Install Ansible
|
||||
6. First smoke playbook
|
||||
7. Install Semaphore
|
||||
8. Run smoke playbook from Semaphore
|
||||
9. Isolation / access / firewall validation (SSH-safe)
|
||||
10. Service restart (+ reboot survival where practical)
|
||||
|
||||
Finish P2 before formally starting `002`.
|
||||
|
||||
## Phase outputs
|
||||
|
||||
| Artifact | Role |
|
||||
|----------|------|
|
||||
| [research.md](./research.md) | Decisions: Gitea/Semaphore access, mirror, deps source, ccache |
|
||||
| [data-model.md](./data-model.md) | Operational entities only |
|
||||
| [quickstart.md](./quickstart.md) | Cold-start validation |
|
||||
| [contracts/](./contracts/) | N/A |
|
||||
|
||||
Next command after human review of these files: `/speckit-tasks` (still no VM).
|
||||
Then `/speckit-analyze`. Stop before `/speckit-implement` until SSH to
|
||||
`rom-dev01` works.
|
||||
@@ -0,0 +1,132 @@
|
||||
# Quickstart / validation: 001-development-environment
|
||||
|
||||
Use after `/speckit-implement` on a real `rom-dev01`. Until the VM exists, treat
|
||||
this as the acceptance script shape.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Host: `a15.ssystems.de` (`49.13.104.83`), SSH port **37037**, guest name `rom-dev01`
|
||||
- Laptop key: `~/.ssh/id_ed25519_rom_dev01` + Host aliases in
|
||||
`misc/config.d/a15-rom-dev01` (see `docs/001-host-runbook.md`)
|
||||
- Laptop has `rsync`, `ssh`, Cursor Remote SSH, `adb`/`fastboot`
|
||||
|
||||
## P1 validation path
|
||||
|
||||
### 1. Preflight captured
|
||||
|
||||
```bash
|
||||
ssh rom-dev01-root 'less /srv/rom/logs/preflight/preflight-latest.txt'
|
||||
```
|
||||
|
||||
### 2. Build user workspace
|
||||
|
||||
```bash
|
||||
ssh rom-dev01 'whoami; hostname; test -f ~/sunfish-a16-rom/specs/001-development-environment/spec.md && echo SPEC_OK'
|
||||
```
|
||||
|
||||
### 3. Toolchain smoke (clean shell)
|
||||
|
||||
```bash
|
||||
ssh rom-dev01 'bash -l -c "git --version; git lfs version; repo --version; python3 --version; ccache -s"'
|
||||
```
|
||||
|
||||
Expected: all commands succeed without sudo. See `/srv/rom/logs/toolchain-smoke.txt`.
|
||||
|
||||
### 4. Layout
|
||||
|
||||
```bash
|
||||
namei -l /srv/rom /srv/rom/artifacts /srv/rom/ccache
|
||||
touch /srv/rom/artifacts/.write_test && rm /srv/rom/artifacts/.write_test
|
||||
```
|
||||
|
||||
### 5. Meta repo present on host (pre-Gitea OK)
|
||||
|
||||
```bash
|
||||
test -d /home/android-build/sunfish-a16-rom/.git
|
||||
test -f /home/android-build/sunfish-a16-rom/specs/001-development-environment/spec.md
|
||||
```
|
||||
|
||||
### 6. Cursor Remote SSH
|
||||
|
||||
From laptop: open host workspace; edit a trivial file; confirm it is on the VM
|
||||
disk (not only local).
|
||||
|
||||
### 7. Artifact rsync smoke
|
||||
|
||||
On host:
|
||||
|
||||
```bash
|
||||
echo '001-smoke' > /srv/rom/artifacts/dummy-001.txt
|
||||
sha256sum /srv/rom/artifacts/dummy-001.txt
|
||||
```
|
||||
|
||||
On laptop:
|
||||
|
||||
```bash
|
||||
rsync -avz USER@ROM_DEV01:/srv/rom/artifacts/dummy-001.txt ./
|
||||
sha256sum ./dummy-001.txt # must match
|
||||
```
|
||||
|
||||
## P2 validation path
|
||||
|
||||
### 8. Gitea private access
|
||||
|
||||
```bash
|
||||
ssh -L 3000:127.0.0.1:3000 rom-dev01-root
|
||||
# browser: http://127.0.0.1:3000/ (user sunfish-admin; password in host /srv/rom/secrets/)
|
||||
```
|
||||
|
||||
Gitea binds **only** `127.0.0.1:3000`. Git over HTTP to that URL (no public `:2222`).
|
||||
|
||||
### 9. Four repos
|
||||
|
||||
In Gitea: `sunfish-a16-rom`, `sunfish-rom-manifest`, `sunfish-rom-build`,
|
||||
`sunfish-rom-patches` (under `sunfish-admin/`).
|
||||
|
||||
### 10. Ansible CLI smoke
|
||||
|
||||
```bash
|
||||
ssh rom-dev01 'cd ~/sunfish-rom-build && ansible-playbook -i ansible/inventory.ini ansible/smoke.yml'
|
||||
```
|
||||
|
||||
### 11. Semaphore smoke (unprivileged)
|
||||
|
||||
```bash
|
||||
ssh -L 3001:127.0.0.1:3001 rom-dev01-root
|
||||
# http://127.0.0.1:3001/ project sunfish-rom / template env-smoke
|
||||
```
|
||||
|
||||
Semaphore clones canonical `sunfish-rom-build` from Gitea and runs the smoke
|
||||
playbook without sudo. Evidence: `/srv/rom/logs/semaphore-smoke.txt`.
|
||||
|
||||
### 12. Off-VM mirrors
|
||||
|
||||
Laptop path: `/home/aventura/Archives/sunfish-rom-mirrors/*.git` (rsync from
|
||||
`/srv/rom/artifacts/gitea-mirrors/` on host).
|
||||
|
||||
```bash
|
||||
# refresh mirrors (host builds mirrors; laptop pulls via rsync — no token on laptop)
|
||||
rsync -a android-build@a15.ssystems.de:/srv/rom/artifacts/gitea-mirrors/ \
|
||||
~/Archives/sunfish-rom-mirrors/
|
||||
git -C ~/Archives/sunfish-rom-mirrors/sunfish-a16-rom.git fsck
|
||||
```
|
||||
|
||||
### 13. Restart survival
|
||||
|
||||
```bash
|
||||
ssh rom-dev01-root 'systemctl restart gitea semaphore; curl -fsS -o /dev/null http://127.0.0.1:3000/; curl -fsS -o /dev/null http://127.0.0.1:3001/'
|
||||
```
|
||||
|
||||
Evidence: `/srv/rom/logs/restart-smoke.txt`.
|
||||
|
||||
### 14. Isolation checklist
|
||||
|
||||
- No required internal NIC for workflow
|
||||
- Gitea/Semaphore binds only `127.0.0.1`
|
||||
- SSH still works after service restarts
|
||||
- Day-to-day docs do not require company VPN/internal DNS/LDAP/GitLab
|
||||
|
||||
## Done means
|
||||
|
||||
`001` complete → start **`002`** (AXP capture).
|
||||
Do **not** start Lineage `repo sync` / build as part of `001` success.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Research: 001-development-environment
|
||||
|
||||
Phase 0 decisions for planning. Implementation may refine versions using live
|
||||
primary docs on `rom-dev01`.
|
||||
|
||||
## R1 — Gitea access model
|
||||
|
||||
**Decision**: Bind Gitea to loopback (or other non-public address) and access via
|
||||
SSH local port forward from the laptop. Do not require public HTTPS exposure.
|
||||
|
||||
**Rationale**: Constitution/`001` require private project Git without unnecessary
|
||||
Internet exposure; single developer; SSH already required for admin/Remote SSH.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Public HTTPS + firewall allowlist — rejected for `001` (more moving parts;
|
||||
accidental exposure risk).
|
||||
- VPN-only bind — rejected as a *required* path (may exist externally; project
|
||||
must not depend on company VPN).
|
||||
|
||||
## R2 — Semaphore access model
|
||||
|
||||
**Decision**: Same as Gitea — loopback/non-public + SSH tunnel. First job is an
|
||||
**unprivileged** localhost/environment smoke playbook only (facts + path/tool
|
||||
asserts). No sudo credentials in Semaphore for `001` smoke.
|
||||
|
||||
**Rationale**: Semaphore is orchestration UI, not a public portal; Android build
|
||||
pipeline is explicitly out of scope for `001`; avoid baking privileged secrets
|
||||
into the first integration.
|
||||
|
||||
**Alternatives considered**: Public Semaphore — rejected. Full ROM pipeline in
|
||||
Semaphore — deferred past `003` manual first build. Privileged playbooks —
|
||||
later explicit decision.
|
||||
|
||||
## R3 — Off-VM Git history backup
|
||||
|
||||
**Decision**: Laptop-initiated **bare mirrors** (`git clone --mirror` /
|
||||
`git remote update`) of the four Gitea repos for `001` (SC-007). Laptop pulls;
|
||||
VM does not SSH into the laptop. Borg/full Gitea DR later.
|
||||
|
||||
**Rationale**: Spec requires off-VM copy of project Git history, not a complete
|
||||
backup platform. Pull-from-laptop avoids opening inbound access on the laptop.
|
||||
|
||||
**Alternatives considered**: Borg-only — optional later. Push-from-VM to laptop
|
||||
— rejected (would require laptop inbound SSH).
|
||||
|
||||
## R4 — Lineage/AOSP host dependencies
|
||||
|
||||
**Decision**: At implement time, follow **current primary LineageOS / AOSP host
|
||||
build documentation** for Ubuntu; record installed package set in logs. Do not
|
||||
freeze a long package list in the plan.
|
||||
|
||||
**Rationale**: Dependency lists drift; stale pins cause false confidence.
|
||||
|
||||
**Alternatives considered**: Copy a historical package list from blogs —
|
||||
rejected.
|
||||
|
||||
## R5 — `repo` installation source
|
||||
|
||||
**Decision**: Install Google's `repo` launcher via the method recommended by
|
||||
current Lineage/AOSP docs (typically curl to `~/bin/repo` or distro package if
|
||||
still adequate); verify `repo --version` as `android-build`.
|
||||
|
||||
**Rationale**: Align with upstream bring-up docs used for `003`.
|
||||
|
||||
## R6 — ccache policy vs build parallelism
|
||||
|
||||
**Decision**: `001` configures `CCACHE_DIR=/srv/rom/ccache` (or equivalent),
|
||||
ownership for `android-build`, and a disk size cap. Document host capacity
|
||||
(6 vCPU / 52 GB / 32 GB swap). **Defer `-j` / OOM tuning to `003`.**
|
||||
|
||||
**Rationale**: ccache is storage/env; parallel link/compile jobs belong to the
|
||||
first real build feature.
|
||||
|
||||
**Alternatives considered**: Encoding `-j$(nproc)` defaults in `001` — rejected
|
||||
as premature and confusing with FR-007 (document capacity; don't run builds).
|
||||
|
||||
## R7 — Meta-repo bootstrap before Gitea
|
||||
|
||||
**Decision**: Copy laptop staging Git tree to host path
|
||||
`/home/android-build/sunfish-a16-rom` first (rsync/scp/bundle preserving
|
||||
`.git`), install Gitea, create repos, push, then mark Gitea canonical. Keep
|
||||
laptop staging until mirror verified. Ansible/automation lives in
|
||||
`sunfish-rom-build`, not in the meta Spec Kit tree.
|
||||
|
||||
**Rationale**: Avoid chicken/egg `git clone` against non-existent Gitea; keep
|
||||
Cursor edit path single and clear.
|
||||
|
||||
## R7b — Gitea Git transport vs OpenSSH base
|
||||
|
||||
**Decision**: UI via loopback + SSH tunnel. Exact Git clone/push transport
|
||||
chosen at implement after host inspection (tunneled HTTP and/or tunneled Git
|
||||
SSH are valid). Do not assume a public secondary SSH port for Gitea; do not
|
||||
blindly edit `saltenv=base`-managed sshd.
|
||||
|
||||
## R8 — Coexistence with `saltenv=base`
|
||||
|
||||
**Decision**: Preflight + stop/report on conflicts with base-managed config.
|
||||
Project Ansible may manage **project** paths/services; must not silently rewrite
|
||||
Salt-owned system policy.
|
||||
|
||||
**Rationale**: Host is dual-touched (SSYSTEMS base then project). Fighting Salt
|
||||
causes flapping.
|
||||
|
||||
## R9 — data-model / contracts
|
||||
|
||||
**Decision**: No application domain model or HTTP API contracts for `001`.
|
||||
Operational entities only in `data-model.md`. `contracts/` marked N/A.
|
||||
|
||||
**Rationale**: Infrastructure bootstrap feature; inventing APIs would be template
|
||||
noise.
|
||||
@@ -0,0 +1,230 @@
|
||||
# Feature Specification: Development environment on rom-dev01
|
||||
|
||||
**Feature Branch**: `001-development-environment`
|
||||
|
||||
**Created**: 2026-08-09
|
||||
|
||||
**Status**: Draft
|
||||
|
||||
**Input**: Provision the ROM development environment on an already-existing
|
||||
`rom-dev01` host and establish the laptop ↔ VM ↔ Pixel workflow defined by the
|
||||
project constitution.
|
||||
|
||||
## Context / non-goals
|
||||
|
||||
**Assumed already true before this feature starts:**
|
||||
|
||||
- `rom-dev01` exists (Ubuntu Server 24.04 LTS);
|
||||
- one reachable public IPv4 address (public NIC only);
|
||||
- SSH administration works;
|
||||
- SSYSTEMS base provisioning (`saltenv=base`) is complete.
|
||||
|
||||
**Explicitly out of scope:**
|
||||
|
||||
- Proxmox / `pm-test01` VM creation;
|
||||
- public subnet/IP selection;
|
||||
- company Salt states, Redmine, or SSYSTEMS governance;
|
||||
- LineageOS source sync or first ROM build (see `003`);
|
||||
- AXP capture (see `002`).
|
||||
|
||||
**Isolation posture (in scope for guest config/docs):**
|
||||
|
||||
- Keep the host usable without SSYSTEMS internal network services.
|
||||
- Do not add an internal NIC from this feature.
|
||||
- Bind Gitea/Semaphore so they need not be world-exposed.
|
||||
- Document guest firewall / egress expectations (block or avoid unnecessary
|
||||
traffic to SSYSTEMS internal ranges; SSH from laptop must work).
|
||||
- Sharing the public VLAN with lab/gateway VMs is acceptable.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Reachable ROM build host workspace (Priority: P1)
|
||||
|
||||
As the developer, I can SSH from my laptop into `rom-dev01` and use a dedicated
|
||||
`android-build` account with a documented home/workspace layout for Android
|
||||
work.
|
||||
|
||||
**Why this priority**: Without a stable host account and layout, no later build
|
||||
feature can proceed.
|
||||
|
||||
**Independent Test**: SSH as the project build user, create a file under the
|
||||
documented workspace, confirm ownership and paths.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `rom-dev01` is up, **When** I connect via SSH from the laptop,
|
||||
**Then** authentication succeeds without requiring this project to change
|
||||
PVE/network provisioning.
|
||||
2. **Given** SSH works, **When** the `android-build` account is provisioned,
|
||||
**Then** it exists with a documented home and build-related directories.
|
||||
3. **Given** the account exists, **When** I inspect `/srv/rom` (or the agreed
|
||||
layout), **Then** directories for sources, artifacts, logs, and tooling are
|
||||
present with clear ownership.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Android build toolchain prerequisites (Priority: P1)
|
||||
|
||||
As the developer, the host has the packages and tools needed to sync and build
|
||||
LineageOS for sunfish (repo, git, git-lfs, JDK, build deps, ccache), sized for
|
||||
6 vCPU / 52 GB RAM / 32 GB swap.
|
||||
|
||||
**Why this priority**: Vanilla LOS build (`003`) depends on this.
|
||||
|
||||
**Independent Test**: `repo`/`git`/`ccache` respond; documented package set is
|
||||
installed; ccache directory exists and is writable by `android-build`.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `android-build` session, **When** I run `repo --version` and
|
||||
`git --version`, **Then** both succeed.
|
||||
2. **Given** build dependencies are installed, **When** I check ccache config
|
||||
and cache dir, **Then** ccache is usable by `android-build`.
|
||||
3. **Given** constrained host resources, **When** build parallelism defaults are
|
||||
documented, **Then** they are conservative (not assuming 16 vCPU / 64 GB).
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Project Git and orchestration services (Priority: P2)
|
||||
|
||||
As the developer, private Gitea and Semaphore (over Ansible) run on `rom-dev01`
|
||||
for project repos and ROM workflow orchestration, without exposing those UIs
|
||||
unnecessarily to the public Internet. Project Git history must not exist only
|
||||
on the build VM.
|
||||
|
||||
**Why this priority**: Needed before multi-repo ROM automation; can follow basic
|
||||
toolchain if sequenced. Losing `out/` is fine; losing specs/patches/history is
|
||||
not.
|
||||
|
||||
**Independent Test**: Gitea serves locally/over SSH tunnel; initial repos
|
||||
`sunfish-a16-rom`, `sunfish-rom-manifest`, `sunfish-rom-build`,
|
||||
`sunfish-rom-patches` exist or are documented to create; Semaphore can run a
|
||||
trivial Ansible playbook; off-VM backup/mirror procedure documented and proven
|
||||
once.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Gitea is installed, **When** I access it via the approved path
|
||||
(SSH tunnel or existing access policy), **Then** I can create/browse private
|
||||
project repositories.
|
||||
2. **Given** Ansible is installed, **When** Semaphore is configured, **Then** it
|
||||
drives Ansible without hiding undocumented build steps.
|
||||
3. **Given** public IP exists, **When** reviewing listening services, **Then**
|
||||
Gitea/Semaphore are not required to be open to the whole Internet for normal
|
||||
operation.
|
||||
4. **Given** the four project repositories, **When** backup/mirror is configured,
|
||||
**Then** an off-VM copy exists (laptop clone, Borg, or other agreed target)
|
||||
so `rom-dev01` is not the only copy of project history.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Guest isolation from SSYSTEMS internals (Priority: P2)
|
||||
|
||||
As the developer, normal ROM work on `rom-dev01` does not require company
|
||||
internal DNS, VPN, LDAP, GitLab, NFS, or Zabbix, and project UIs are not
|
||||
exposed more than necessary.
|
||||
|
||||
**Why this priority**: Limits blast radius and keeps the personal project
|
||||
logically separate even though the hypervisor is shared lab hardware.
|
||||
|
||||
**Independent Test**: From the VM, confirm no required route/NIC into internal
|
||||
SSYSTEMS networks for the workflow; Gitea/Semaphore reachable via approved
|
||||
non-public path; checklist documents firewall/DNS posture.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the provisioned guest, **When** I inspect network interfaces,
|
||||
**Then** only the public NIC is required for this project's workflow.
|
||||
2. **Given** Gitea and Semaphore are installed, **When** I review listen
|
||||
addresses / access docs, **Then** they are not required to be open to the
|
||||
whole Internet.
|
||||
3. **Given** guest firewall/DNS docs, **When** I follow them, **Then** day-to-day
|
||||
ROM work does not depend on SSYSTEMS internal resolvers or VPN.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - Laptop remains a thin client (Priority: P2)
|
||||
|
||||
As the developer, Cursor Remote SSH uses `rom-dev01` as the heavy workspace;
|
||||
the Pixel stays USB-attached to the laptop; artifacts are `rsync`'d for
|
||||
flashing.
|
||||
|
||||
**Why this priority**: Enforces the disk/space strategy and flashing model.
|
||||
|
||||
**Independent Test**: Documented Remote SSH workflow; sample artifact path
|
||||
`/srv/rom/artifacts` syncs to the laptop with `rsync`.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Cursor on the laptop, **When** I open the project via Remote SSH,
|
||||
**Then** I edit/build on `rom-dev01` without keeping `.repo`/`out` on the
|
||||
laptop.
|
||||
2. **Given** a dummy artifact in `/srv/rom/artifacts`, **When** I `rsync` it to
|
||||
the laptop, **Then** the file arrives for local `adb`/`fastboot` use.
|
||||
3. **Given** the Pixel is attached to the laptop, **When** following the
|
||||
workflow docs, **Then** no USB passthrough to the VM is required.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Host reboots: services and mount/layout expectations are documented.
|
||||
- Disk pressure on 2 TB: cleanup conventions for `out/` and old artifacts.
|
||||
- SSH admin user ≠ `android-build`: project must not hard-depend on laptop
|
||||
usernames (`aventura` / `ubuntu`).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Provide dedicated `android-build` account and documented workspace.
|
||||
- **FR-002**: Install Android/LineageOS build prerequisites and ccache.
|
||||
- **FR-003**: Create `/srv/rom` layout (sources, artifacts, logs, tooling) or
|
||||
document an equivalent and use it consistently.
|
||||
- **FR-004**: Install and configure private Gitea for project repositories,
|
||||
including meta repo `sunfish-a16-rom` plus `sunfish-rom-manifest`,
|
||||
`sunfish-rom-build`, and `sunfish-rom-patches`.
|
||||
- **FR-005**: Install Ansible; configure Semaphore as UI over Ansible for ROM
|
||||
workflow (initially may only prove a smoke playbook).
|
||||
- **FR-006**: Document Cursor Remote SSH + `rsync` artifact + laptop
|
||||
adb/fastboot workflow.
|
||||
- **FR-007**: Document conservative build parallelism defaults for 6 vCPU /
|
||||
52 GB / swap 32 GB.
|
||||
- **FR-008**: Ensure Spec Kit project for `sunfish-a16-rom` is available on the
|
||||
host (push/clone the meta repo from this staging tree or Gitea once published).
|
||||
- **FR-009**: Document and apply guest isolation posture: public-NIC-only
|
||||
workflow; no required dependency on SSYSTEMS internal DNS/VPN/LDAP/GitLab/NFS/
|
||||
Zabbix; Gitea/Semaphore not world-exposed by default; guest firewall guidance
|
||||
to avoid unnecessary traffic to internal SSYSTEMS ranges (without encoding
|
||||
concrete company IPs as project secrets/config in Git unless necessary).
|
||||
- **FR-010**: Provide an off-VM backup or mirror of project-owned Gitea
|
||||
repositories so the build VM is not the only copy of project history
|
||||
(mechanism may be laptop clones, Borg, or another agreed target).
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **rom-dev01**: pre-existing Ubuntu 24.04 build host.
|
||||
- **android-build**: project build account.
|
||||
- **/srv/rom**: canonical on-host data layout.
|
||||
- **Gitea / Semaphore / Ansible**: project-owned services on the VM.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: From a clean SSH session as `android-build`, toolchain commands
|
||||
required for `003` are available without further ad-hoc package hunting.
|
||||
- **SC-002**: `/srv/rom/artifacts` (or documented equivalent) is writable and
|
||||
used as the artifact handoff point to the laptop.
|
||||
- **SC-003**: Gitea hosts (or is ready to host) the **four** initial project
|
||||
repos (`sunfish-a16-rom`, `sunfish-rom-manifest`, `sunfish-rom-build`,
|
||||
`sunfish-rom-patches`) without using company GitLab.
|
||||
- **SC-004**: Written workflow doc allows a cold start: SSH → workspace →
|
||||
(later) build → rsync → flash on laptop-attached Pixel.
|
||||
- **SC-005**: No playbook or doc in this feature creates or reconfigures the
|
||||
Proxmox VM itself.
|
||||
- **SC-006**: Isolation checklist passes: no internal NIC required; project UIs
|
||||
accessible without public Internet exposure; workflow docs do not require
|
||||
SSYSTEMS VPN/internal DNS for normal use.
|
||||
- **SC-007**: Off-VM backup/mirror of the four Gitea project repos is documented
|
||||
and demonstrated at least once.
|
||||
@@ -0,0 +1,208 @@
|
||||
# Tasks: Development environment on rom-dev01
|
||||
|
||||
**Input**: Design documents from `/specs/001-development-environment/`
|
||||
|
||||
**Prerequisites**: plan.md (required), spec.md, research.md, data-model.md,
|
||||
quickstart.md, contracts/ (N/A)
|
||||
|
||||
**Tests**: Observational verify steps embedded in tasks (no separate TDD suite).
|
||||
|
||||
**Organization**: Setup → Foundational (preflight) → User stories by priority →
|
||||
Polish. **Do not run these tasks until `rom-dev01` SSH works.** Generating this
|
||||
file is documentation-only.
|
||||
|
||||
**Canonical paths**:
|
||||
- Meta Spec Kit tree: `/home/android-build/sunfish-a16-rom`
|
||||
- Data root: `/srv/rom/`
|
||||
- Automation repo (after Gitea): `sunfish-rom-build` (not the meta repo)
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete dependencies)
|
||||
- **[Story]**: US1…US5 from spec.md
|
||||
- Every task includes a path and an observable verify hint
|
||||
|
||||
## Path Conventions
|
||||
|
||||
Host paths are absolute on `rom-dev01`. Docs/logs also land under
|
||||
`/home/android-build/sunfish-a16-rom/docs/` or `/srv/rom/logs/` as noted.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (docs readiness — can be done on laptop before VM)
|
||||
|
||||
- [x] T001 Confirm active feature is `specs/001-development-environment` via `.specify/feature.json` and that constitution is `0.1.7` in `.specify/memory/constitution.md`
|
||||
- [x] T002 [P] Create host-facing doc stub `docs/001-host-runbook.md` in meta repo (preflight results, paths, Gitea tunnel notes — fill during implement)
|
||||
- [x] T003 [P] Create FR/SC evidence checklist stub `docs/001-verification-matrix.md` mapping each FR-*/SC-* from `specs/001-development-environment/spec.md` to blank evidence fields
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (blocking — host preflight before stories)
|
||||
|
||||
**Goal**: Observe `rom-dev01` without fighting `saltenv=base`; abort on conflict.
|
||||
|
||||
- [x] T004 On `rom-dev01` as admin, capture preflight baseline into `/srv/rom/logs/preflight/` (create `/srv/rom/logs` with safe perms if needed): Ubuntu/kernel, CPU/RAM/swap, disk free, interfaces/routes, users, firewall summary (**do not flush**), listening ports, apt sources → also summarize in `docs/001-host-runbook.md`
|
||||
- [x] T005 Record coexistence rule in `docs/001-host-runbook.md`: if base-managed config conflicts with project needs, **stop and report**; do not silently replace Salt-managed settings
|
||||
- [x] T006 Verify SSH admin path still works after any read-only inspection; note rollback contacts/commands in `docs/001-host-runbook.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Reachable build workspace (P1)
|
||||
|
||||
**Story goal**: `android-build` exists with SSH key login from laptop; `/srv/rom` owned correctly; meta tree at fixed path.
|
||||
|
||||
**Independent test**: `ssh android-build@rom-dev01` from laptop; `/srv/rom/artifacts` writable; `/home/android-build/sunfish-a16-rom` contains Spec Kit tree (after T013).
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T007 [US1] Create unprivileged user `android-build` with home `/home/android-build` (admin); document uid/gid in `docs/001-host-runbook.md`
|
||||
- [x] T008 [US1] Configure SSH public-key access for `android-build` using the developer's existing public key only (do not copy private keys; do not modify global sshd/`saltenv=base` policy unless required). Verify from the laptop that `ssh android-build@rom-dev01` succeeds. Document Cursor `Host` entry (`User android-build`) in `docs/001-host-runbook.md`
|
||||
- [x] T009 [US1] Create `/srv/rom/{src,references,tooling,ccache,artifacts,logs,secrets}` with ownership for `android-build` on writable trees; `secrets/` restricted/empty — document modes in `docs/001-host-runbook.md`
|
||||
- [x] T010 [US1] Verify: `namei -l /srv/rom /srv/rom/artifacts` and `sudo -iu android-build touch /srv/rom/artifacts/.write_test` succeeds; no `chmod 777`
|
||||
- [x] T011 [US1] Document account model (admin vs `android-build` vs service users) in `docs/001-host-runbook.md` — never build Android as root
|
||||
- [x] T012 [US1] Copy laptop staging Git tree to `/home/android-build/sunfish-a16-rom` preserving `.git` (rsync/scp/bundle); verify `test -f /home/android-build/sunfish-a16-rom/specs/001-development-environment/spec.md`
|
||||
- [x] T013 [US1] Ensure `/srv/rom/tooling` is **not** used as Spec Kit checkout; note distinction in `docs/001-host-runbook.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Android host toolchain (P1)
|
||||
|
||||
**Story goal**: Clean-login toolchain ready for later `003` (no `repo sync` / build).
|
||||
|
||||
**Independent test**: `ssh android-build@rom-dev01` → `git`, `git lfs`, `repo`, `python3`, `ccache -s`, and LOS-doc Java/prereqs succeed.
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T014 [US2] As admin, install host packages per **current** primary LineageOS/AOSP Ubuntu build documentation; record exact package list in `/srv/rom/logs/toolchain-packages.txt`
|
||||
- [x] T015 [US2] Install/configure `repo` for `android-build` per current docs; verify `ssh android-build@rom-dev01 'repo --version'`
|
||||
- [x] T016 [US2] Ensure `git` + `git-lfs` for `android-build`; verify `ssh android-build@rom-dev01 'git lfs version'`
|
||||
- [x] T017 [US2] Configure ccache: `CCACHE_DIR=/srv/rom/ccache`, ownership `android-build`, size cap; document env in `/home/android-build/.bashrc` or `/home/android-build/.profile` and `docs/001-host-runbook.md`
|
||||
- [x] T018 [US2] Verify: `ssh android-build@rom-dev01 'ccache -s'` shows configured cache dir
|
||||
- [x] T019 [US2] Document FR-007 capacity (6 vCPU / 52 GB / 32 GB swap) and **defer `-j`/OOM tuning to `003`** in `docs/001-host-runbook.md` — do not run a Lineage build
|
||||
- [x] T020 [US2] Clean-shell toolchain smoke checklist executed; paste command outputs into `/srv/rom/logs/toolchain-smoke.txt` and tick FR-002/SC-001 in `docs/001-verification-matrix.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 5 — Laptop thin client (P1/P2 overlap — do after US1–US2)
|
||||
|
||||
**Story goal**: Cursor Remote SSH as `android-build` + artifact rsync proven; Pixel stays on laptop USB.
|
||||
|
||||
**Independent test**: Remote SSH edit on host as `android-build`; dummy artifact SHA256 matches after rsync; laptop has `adb`/`fastboot` binaries.
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T021 [US5] Document Cursor Remote SSH → `/home/android-build/sunfish-a16-rom` with `User android-build` in `docs/001-host-runbook.md` and update `specs/001-development-environment/quickstart.md` if needed
|
||||
- [x] T022 [US5] Create `/srv/rom/artifacts/dummy-001.txt` as `android-build`; record `sha256sum` in `/srv/rom/logs/rsync-smoke.txt`
|
||||
- [x] T023 [US5] From laptop, `rsync` dummy artifact; verify SHA256 match; record laptop path in `/srv/rom/logs/rsync-smoke.txt` and `docs/001-verification-matrix.md` (SC-002)
|
||||
- [x] T024 [US5] On laptop only: run `adb --version` and `fastboot --version` (do **not** connect or flash the Pixel); record versions in `docs/001-host-runbook.md`. Document adb/fastboot-on-laptop / no USB passthrough rule (SC-004 partial)
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 3 — Gitea, Ansible, Semaphore, off-VM mirror (P2)
|
||||
|
||||
**Story goal**: Private Gitea with four repos; canonical meta remote; `sunfish-rom-build` committed+pushed; laptop pull mirrors; unprivileged Semaphore smoke from canonical repo.
|
||||
|
||||
**Independent test**: Four repos on Gitea; meta history pushed; `sunfish-rom-build` fetch shows smoke playbook commit; laptop `git clone --mirror` works; Semaphore runs unprivileged smoke.
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T025 [US3] Install Gitea on `rom-dev01` with systemd + persistent data; bind UI to loopback/non-public; document unit/paths in `docs/001-host-runbook.md`
|
||||
- [x] T026 [US3] Store Gitea admin credentials only in restricted host location under `/srv/rom/secrets/` or service-native secret path — **never** commit to Git; document location (not secrets) in `docs/001-host-runbook.md`
|
||||
- [x] T027 [US3] Verify: local `curl` to Gitea UI succeeds; confirm not relying on public Internet exposure; record bind address in `docs/001-host-runbook.md`
|
||||
- [x] T028 [US3] Document Git transport chosen after host inspection (HTTP via SSH tunnel and/or tunneled Git SSH); **do not** open public `:2222` or blindly edit `saltenv=base` sshd — write choice in `docs/001-host-runbook.md`
|
||||
- [x] T029 [US3] Create Gitea repos: `sunfish-a16-rom`, `sunfish-rom-manifest`, `sunfish-rom-build`, `sunfish-rom-patches`
|
||||
- [x] T030 [US3] Push `/home/android-build/sunfish-a16-rom` history to Gitea `sunfish-a16-rom`; set `origin` to Gitea; verify remote in that directory
|
||||
- [x] T031 [US3] Seed minimal structure in a working tree of `sunfish-rom-build` for Ansible (e.g. `ansible/` playbooks path) — **not** inside Spec Kit meta repo
|
||||
- [x] T032 [US3] Install Ansible on `rom-dev01`; document version in `docs/001-host-runbook.md`
|
||||
- [x] T033 [US3] Add unprivileged smoke playbook under `sunfish-rom-build` (gather_facts + asserts for `/srv/rom`, `android-build`, toolchain); **no become/sudo secrets**
|
||||
- [x] T034 [US3] Run smoke playbook successfully via `ansible-playbook` CLI; log output to `/srv/rom/logs/ansible-smoke.txt`
|
||||
- [x] T035 [US3] Commit and push the initial `sunfish-rom-build` structure and smoke playbook to its canonical Gitea repository; verify the pushed commit is visible from a fresh fetch/clone (document clone URL/path in `docs/001-host-runbook.md`)
|
||||
- [x] T036 [US3] Install Semaphore; bind like Gitea (loopback/tunnel); no public exposure; document in `docs/001-host-runbook.md`
|
||||
- [x] T037 [US3] Wire Semaphore so it executes the smoke playbook **originating from the canonical `sunfish-rom-build` repository**, using the simplest private mechanism supported by the actual installation (token/HTTP/SSH — decide at implement). Run once successfully; evidence in `/srv/rom/logs/semaphore-smoke.txt` (FR-005). Still unprivileged / no sudo password in Semaphore
|
||||
- [x] T038 [US3] From **laptop**, create bare mirrors with `git clone --mirror` for all four repos (laptop initiates connection); run `git remote update` + `git fsck`; document mirror paths in `docs/001-host-runbook.md` (FR-010/SC-007)
|
||||
- [x] T039 [US3] Confirm laptop staging `/home/aventura/Workspaces/sunfish-a16-rom` is **retained** until T030+T035+T038 verified; only then optionally mark staging as non-canonical in `docs/001-host-runbook.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: User Story 4 — Guest isolation (P2)
|
||||
|
||||
**Story goal**: Isolation checklist passes without breaking SSH.
|
||||
|
||||
**Independent test**: Public-NIC-only workflow; UIs non-public; SSH still works; no VPN/internal DNS required in docs.
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T040 [US4] Document interfaces/routes: project workflow requires only public NIC — `docs/001-host-runbook.md` + evidence in `docs/001-verification-matrix.md` (SC-006)
|
||||
- [x] T041 [US4] Apply isolation/firewall guidance **additively** if needed: never flush nftables/iptables; never close active SSH before tested alternative; record before/after in `/srv/rom/logs/firewall-notes.txt`
|
||||
- [x] T042 [US4] Re-verify Gitea/Semaphore binds remain non-public; SSH admin + `android-build` + tunnel still work — update `docs/001-verification-matrix.md` FR-009/SC-006
|
||||
- [x] T043 [US4] Confirm day-to-day runbook does not require SSYSTEMS VPN/internal DNS/LDAP/GitLab/NFS/Zabbix — `docs/001-host-runbook.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: Polish & cross-cutting
|
||||
|
||||
- [x] T044 [P] Fill all FR-*/SC-* evidence rows in `docs/001-verification-matrix.md` (including SC-005: no PVE/qm/Salt VM tasks were performed)
|
||||
- [x] T045 [P] Align `specs/001-development-environment/quickstart.md` with final ports/paths/tunnel commands actually used
|
||||
- [x] T046 Restart Gitea (+ Semaphore) via systemd; confirm recovery; optional reboot when safe; note results in `/srv/rom/logs/restart-smoke.txt`
|
||||
- [x] T047 Declare handoff in `docs/001-host-runbook.md`: **`001` complete → proceed to `002`**, do not start Lineage sync/build
|
||||
- [x] T048 Verify that no credentials/tokens/private keys are present in the **current trees OR committed history** of `sunfish-a16-rom` and `sunfish-rom-build`. Review current files plus reachable Git history; if a secret was ever committed, remove it from history and rotate/revoke it before closing `001`. Method may be manual/`git log -p`/`git rev-list` review (no mandatory Gitleaks/TruffleHog)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & story order
|
||||
|
||||
```text
|
||||
Phase 1 (laptop docs)
|
||||
↓
|
||||
Phase 2 preflight (host)
|
||||
↓
|
||||
US1 user + SSH key + /srv/rom + meta copy
|
||||
↓
|
||||
US2 toolchain ──────────────┐
|
||||
↓ │
|
||||
US5 thin-client smokes ←───┘ (needs artifacts + meta path + android-build SSH)
|
||||
↓
|
||||
US3 Gitea → repos → Ansible in sunfish-rom-build → commit/push → Semaphore → laptop mirrors
|
||||
↓
|
||||
US4 isolation hardening/validation
|
||||
↓
|
||||
Polish / handoff → STOP until implement; next feature 002 after 001 done
|
||||
```
|
||||
|
||||
**MVP (minimum useful host)**: complete through US2 + US5 (T007–T024) even if Gitea delayed — but **formal `001` done** requires P2 (US3+US4+polish) per plan.
|
||||
|
||||
## Parallel opportunities
|
||||
|
||||
- T002/T003 on laptop before VM
|
||||
- After T009: T011 docs can parallel T012 copy if disk ready
|
||||
- T014–T016 package/`repo`/`git-lfs` partly serial (apt) then T017 ccache
|
||||
- T044/T045 polish docs in parallel after evidence exists
|
||||
|
||||
## FR/SC coverage map
|
||||
|
||||
| ID | Tasks |
|
||||
|----|-------|
|
||||
| FR-001 | T007–T011, T008 |
|
||||
| FR-002 | T014–T018, T020 |
|
||||
| FR-003 | T009–T010, T013 |
|
||||
| FR-004 | T025–T030 |
|
||||
| FR-005 | T031–T037 |
|
||||
| FR-006 | T021–T024 |
|
||||
| FR-007 | T019 |
|
||||
| FR-008 | T012, T030 |
|
||||
| FR-009 | T040–T043 |
|
||||
| FR-010 | T038–T039 |
|
||||
| SC-001 | T020 |
|
||||
| SC-002 | T022–T023 |
|
||||
| SC-003 | T029–T030 |
|
||||
| SC-004 | T021, T024, T047 |
|
||||
| SC-005 | T005, T044 |
|
||||
| SC-006 | T040–T043 |
|
||||
| SC-007 | T038 |
|
||||
|
||||
## Implementation strategy
|
||||
|
||||
1. Do **not** execute host tasks until SSH to `rom-dev01` works.
|
||||
2. After analyze approval: STOP until VM exists, then `/speckit-implement`.
|
||||
3. Follow P1 then P2; stop/report on Salt conflicts.
|
||||
4. Do not plan `002` until `001` implement + verification complete.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Contracts: N/A for 002
|
||||
|
||||
No HTTP/API contracts. Device observation + documentation only.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Data model: 002-axp-reference-capture
|
||||
|
||||
Operational entities only (no application domain model).
|
||||
|
||||
## DeviceRole
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| role | `GOLDEN` \| `LAB` |
|
||||
| serial_or_label | Measured; may be redacted in public docs |
|
||||
| bootloader_state | Measured (`fastboot getvar unlocked` / UI) |
|
||||
| build_fingerprint | From `getprop` |
|
||||
| flash_policy | GOLDEN=forbidden; LAB=allowed |
|
||||
|
||||
## GoldenInventory
|
||||
|
||||
Essential package/config rows: name, version, cert fingerprint (short), path,
|
||||
notes, `re-query` flag.
|
||||
|
||||
## BankingFlow
|
||||
|
||||
Ordered steps 1–8 from spec; redacted (no passwords/OTPs/PII).
|
||||
|
||||
## LabRescueBundle
|
||||
|
||||
Factory zip path on host, SHA-256, Google source URL, flash steps, wipe warning.
|
||||
|
||||
## ReferenceArchive
|
||||
|
||||
Host path `/srv/rom/references/axp/archive/` — sunfish-scoped AXP materials.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Implementation Plan: AXP.OS GOLDEN reference capture
|
||||
|
||||
**Branch**: `002-axp-reference-capture` | **Date**: 2026-09-13 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/002-axp-reference-capture/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Identify GOLDEN vs LAB sunfish, write LAB Google factory-image emergency
|
||||
rescue, capture essential live GOLDEN AXP inventory + banking flow (redacted),
|
||||
and store raw artifacts under `/srv/rom/references/axp/` on `rom-dev01` while
|
||||
committing only redacted docs to `sunfish-a16-rom`. Parallel: rsync existing
|
||||
laptop AXP archive per `docs/axp-sunfish-preservation.md` (does not replace
|
||||
live `adb`).
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Bash + `adb`/`fastboot` inventory scripts; Markdown docs
|
||||
|
||||
**Primary Dependencies**: OpenSSH to `rom-dev01`; Android platform-tools on
|
||||
laptop; optional wget/curl for factory images on host
|
||||
|
||||
**Storage**: `/srv/rom/references/axp/` (raw); Git = redacted summaries only
|
||||
|
||||
**Testing**: Observational checklists (getprop/dumpsys excerpts); no unit suite
|
||||
|
||||
**Target Platform**: Two physical sunfish + `rom-dev01` Ubuntu 24.04
|
||||
|
||||
**Project Type**: Device documentation / reference capture
|
||||
|
||||
**Performance Goals**: N/A — correctness and non-invention of device facts
|
||||
|
||||
**Constraints**: Never flash GOLDEN; no secrets/APKs in Git; NeoBackup not a gate;
|
||||
bootloader state measured not assumed; gaps marked “re-query GOLDEN”
|
||||
|
||||
**Scale/Scope**: One developer; essential inventory for `004`–`006` hard-gates
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- Independence from SSYSTEMS: yes (Gitea/host paths only)
|
||||
- GOLDEN do-not-flash: enforced in docs + FR-006
|
||||
- No Magisk-as-production-path invention: Magisk recorded as GOLDEN oracle only
|
||||
- Secrets/APKs off Git: FR-005 / SC-005
|
||||
- Prefer primary sources: Google factory images page; live `adb` over blogs
|
||||
|
||||
**Post-design**: Still pass — plan does not invent package versions.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/002-axp-reference-capture/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/ # N/A (README only)
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source / artifact layout
|
||||
|
||||
```text
|
||||
# In-repo (redacted)
|
||||
docs/device-roles.md # update serials/labels + lock notes
|
||||
docs/002-golden-inventory.md # essential inventory + banking flow
|
||||
docs/002-lab-stock-rescue.md # LAB factory rescue
|
||||
docs/axp-pro-parity.md # cross-links only (non-normative)
|
||||
|
||||
# On rom-dev01 (raw; not Git)
|
||||
/srv/rom/references/axp/
|
||||
├── archive/ # rsync from ~/Archives/AXP.OS
|
||||
├── golden/ # adb pulls, APK copies, dumpsys (restricted)
|
||||
├── lab/ # factory image zip + checksums
|
||||
└── logs/ # capture session logs
|
||||
```
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| — | — | — |
|
||||
|
||||
## Phases
|
||||
|
||||
### P0 — Docs + archive seed (no phone required)
|
||||
|
||||
1. Freeze plan/research/tasks.
|
||||
2. Rsync laptop `~/Archives/AXP.OS` → `/srv/rom/references/axp/archive/`.
|
||||
3. Draft LAB stock rescue from current Google sunfish factory image listing;
|
||||
download image+hash to `/srv/rom/references/axp/lab/` when network allows.
|
||||
|
||||
### P1 — Device roles + measured identity (phones required)
|
||||
|
||||
1. Connect GOLDEN and LAB; record serials/labels; `getprop` + fastboot lock.
|
||||
2. Update `docs/device-roles.md` + `docs/002-golden-inventory.md` stubs with
|
||||
measured facts only.
|
||||
|
||||
### P2 — Essential GOLDEN inventory + banking flow
|
||||
|
||||
1. Scripted `adb` collection into `/srv/rom/references/axp/golden/` (redact
|
||||
before any Git paste).
|
||||
2. Write banking install order from GOLDEN observation.
|
||||
3. Cross-link parity matrix rows that become known.
|
||||
|
||||
### Gate before `003`
|
||||
|
||||
LAB rescue doc reviewed; GOLDEN explicitly do-not-flash; FR-006 satisfied.
|
||||
**No** Lineage sync in this feature.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Quickstart: 002-axp-reference-capture
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `001` done (`rom-dev01`, `android-build`, `/srv/rom`)
|
||||
- Laptop: `adb` / `fastboot`
|
||||
- Both phones labeled (or serials ready)
|
||||
|
||||
## Path
|
||||
|
||||
1. Confirm no device attached confusion: `adb devices -l`
|
||||
2. Capture GOLDEN then LAB (or vice versa) — never flash GOLDEN
|
||||
3. Store raw under `/srv/rom/references/axp/golden/` (rsync from laptop pulls)
|
||||
4. Update redacted `docs/002-golden-inventory.md` + banking flow
|
||||
5. Verify LAB rescue zip + hash on host before any `003` flash
|
||||
|
||||
## Gate before 003
|
||||
|
||||
- [ ] GOLDEN marked do-not-flash in docs
|
||||
- [ ] LAB factory rescue doc + image hash present
|
||||
- [ ] Essential inventory + banking flow (gaps = re-query, not invented)
|
||||
@@ -0,0 +1,47 @@
|
||||
# Research: 002-axp-reference-capture
|
||||
|
||||
## R1 — Live GOLDEN vs offline AXP archive
|
||||
|
||||
**Decision**: Treat live GOLDEN `adb` as the compatibility oracle. Offline archive
|
||||
under `/srv/rom/references/axp/archive/` is supporting reference (docs/git/
|
||||
images), never a substitute for measured device state.
|
||||
|
||||
**Rationale**: Spec FR-003/SC-003; constitution two-device model.
|
||||
|
||||
## R2 — NeoBackup / wipe GOLDEN
|
||||
|
||||
**Decision**: Out of scope / not a gate (spec + `docs/device-roles.md`).
|
||||
|
||||
## R3 — LAB factory rescue source
|
||||
|
||||
**Decision (measured 2026-09-13)**: Target build `TQ3A.230805.001.S1` /
|
||||
`sunfish-tq3a.230805.001.s1-factory-82902ea9.zip`, SHA-256
|
||||
`82902ea98c80f1a22706279a30d2bc46aa55cbe60703c9a02ba043bd052c6d99`.
|
||||
|
||||
Google CDN URL for that zip now returns **404**; sunfish section on
|
||||
`developers.google.com/android/images` is effectively pruned. Download from
|
||||
Internet Archive item `sunfish-tq3a.230805.001.s1` and **verify SHA-256** against
|
||||
the historical Google/Calyx hash before treating it as a rescue image.
|
||||
|
||||
**Alternatives**: Other community mirrors only if IA fails; same hash required.
|
||||
|
||||
## R4 — Raw artifact location
|
||||
|
||||
**Decision**: `/srv/rom/references/axp/{archive,golden,lab,logs}/` on
|
||||
`rom-dev01`. Git holds redacted Markdown only.
|
||||
|
||||
## R5 — Inventory depth
|
||||
|
||||
**Decision**: Essential checklist from spec US2; missing items marked
|
||||
`re-query GOLDEN` — never invent versions/UIDs.
|
||||
|
||||
## R6 — Magisk on GOLDEN
|
||||
|
||||
**Decision**: Record Magisk/DenyList as **oracle facts**. Project production
|
||||
root path remains KernelSU-Next in later features; Magisk is not promoted as
|
||||
our stage.
|
||||
|
||||
## R7 — Parallelism with archive rsync
|
||||
|
||||
**Decision**: Start laptop→host AXP archive rsync as soon as `001` host is
|
||||
ready; does not block writing LAB rescue docs; does not wait for phone `adb`.
|
||||
@@ -0,0 +1,183 @@
|
||||
# Feature Specification: AXP.OS GOLDEN reference capture
|
||||
|
||||
**Feature Branch**: `002-axp-reference-capture`
|
||||
|
||||
**Created**: 2026-08-09
|
||||
|
||||
**Status**: P1 complete (gate to `003`); archive rsync may still finish in background
|
||||
|
||||
**Input**: Document and sample the **GOLDEN** daily-driver AXP.OS sunfish as a
|
||||
live compatibility oracle; label GOLDEN vs LAB; prepare **LAB** stock factory
|
||||
rescue. Experimental flashing stays on LAB only (`docs/device-roles.md`).
|
||||
|
||||
## Context / non-goals
|
||||
|
||||
- There are **two** sunfish devices: **GOLDEN** (**AXP.OS 22.2 / Android 15**
|
||||
daily driver — do not experiment/flash) and **LAB** (flash/reflash freely).
|
||||
- Exact GOLDEN build fingerprint/patch is **measured** here (`getprop`). GOLDEN
|
||||
is AXP 22.2/A15 — **not** the last GrapheneOS sunfish release (that was
|
||||
**A13**, historical reference only).
|
||||
- Broader offline AXP *sunfish* archive (website, selected git, images) is
|
||||
documented in `docs/axp-sunfish-preservation.md` for execution on `rom-dev01`
|
||||
— not a full Disroot org clone; does not replace live GOLDEN `adb`.
|
||||
- Capture **essential** versions/config up front; GOLDEN remains available for
|
||||
later live `adb` re-queries — do not require an exhaustive one-shot dump of
|
||||
everything before `003`.
|
||||
- **NeoBackup / wipe / migrate GOLDEN are not project requirements.**
|
||||
- Do **not** invent package versions/UIDs in the constitution; this feature
|
||||
records what GOLDEN actually runs.
|
||||
- Do not commit credentials, tokens, or personal identifiers to Git.
|
||||
- Observe devices; do **not** assume bootloader unlock state until measured
|
||||
(both GOLDEN and LAB).
|
||||
- Product intent vs AXP Pro lives in non-normative `docs/axp-pro-parity.md`.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Device roles + LAB stock rescue (Priority: P1)
|
||||
|
||||
As the developer, GOLDEN and LAB are clearly identified, and LAB has a written
|
||||
Google factory-image emergency rescue so experiments cannot permanently brick
|
||||
the lab phone.
|
||||
|
||||
**Why this priority**: Prevents flashing the wrong phone; keeps LAB recoverable.
|
||||
|
||||
**Independent Test**: Serials/labels documented; factory image procedure for LAB
|
||||
reviewed; GOLDEN marked do-not-flash.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** two sunfish devices, **When** I record serials (or equivalent IDs)
|
||||
and physical/doc labels, **Then** GOLDEN vs LAB cannot be confused.
|
||||
2. **Given** GOLDEN and LAB, **When** I inspect bootloader/fastboot/`getprop`
|
||||
on each, **Then** lock state and build identity are recorded without prior
|
||||
assumptions.
|
||||
3. **Given** official Google sunfish factory images, **When** I document image
|
||||
set, hashes, and flash steps for **LAB**, **Then** LAB emergency stock rescue
|
||||
exists before `003` experiments.
|
||||
4. **Given** project docs, **When** reviewed, **Then** they state GOLDEN must
|
||||
not receive experimental project flashes.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Essential GOLDEN inventory (Priority: P1)
|
||||
|
||||
As the developer, I have enough structured inventory of GOLDEN AXP to start
|
||||
`004`–`006`, knowing I can re-probe GOLDEN later for missing details.
|
||||
|
||||
**Why this priority**: Defines the live oracle without blocking on perfection.
|
||||
|
||||
**Independent Test**: Essential checklist complete or explicitly deferred with
|
||||
“re-query GOLDEN later” notes — no silent unknowns for hard-gates.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** GOLDEN AXP, **When** I collect `getprop` / fingerprints, **Then**
|
||||
exact ROM/build identifiers are stored.
|
||||
2. **Given** microG, **When** inventoried at essential level, **Then** recorded:
|
||||
version, signing cert; Self-Check; Device Registration; Cloud Messaging;
|
||||
relevant permissions.
|
||||
3. **Given** Phonesky / `com.android.vending`, **When** inventoried, **Then**
|
||||
recorded: version; APK path; cert; permissions; spoofing state; useful
|
||||
`dumpsys package` / priv-app XML notes.
|
||||
4. **Given** Insular, **When** inventoried, **Then** recorded: profile IDs;
|
||||
profile owner; `dumpsys device_policy` excerpt; owner vs work UIDs/packages;
|
||||
Yuh/Swissquote locations.
|
||||
5. **Given** Magisk/root, **When** inventoried, **Then** recorded: Magisk
|
||||
version; modules; **DenyList including processes**.
|
||||
6. **Given** GSF Proxy and related packages, **When** inventoried, **Then**
|
||||
versions/paths/signatures are recorded.
|
||||
7. **Given** banking interest, **When** measurable, **Then** record observational
|
||||
Play Integrity (or equivalent) state plus Yuh/Swissquote pass/fail on GOLDEN
|
||||
— comparative baseline only, not a Strong Integrity promise for our ROM.
|
||||
8. **Given** Daily-driver MVP features we will replace natively, **When**
|
||||
capturing modules/settings, **Then** document current call-recording and
|
||||
FLAG_SECURE bypass behaviour/source on GOLDEN (AXP vs module; global/per-app).
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Golden banking flow on GOLDEN (Priority: P1)
|
||||
|
||||
As the developer, the known-good banking install order is written from GOLDEN
|
||||
so `006` can reproduce it on LAB (with KernelSU substituting DenyList later).
|
||||
|
||||
**Why this priority**: Order is load-bearing.
|
||||
|
||||
**Independent Test**: Step list matches GOLDEN procedure.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** GOLDEN, **When** I document the banking app install flow, **Then**
|
||||
it explicitly includes:
|
||||
|
||||
1. Aurora Store → install
|
||||
2. **Do not open**
|
||||
3. Magisk DenyList **before** first process (include processes)
|
||||
4. Clone into Insular
|
||||
5. First launch inside Insular
|
||||
6. Phonesky/Play in Insular
|
||||
7. Play update inside work profile if required
|
||||
8. Verify login/biometrics/push/reboot as applicable
|
||||
|
||||
2. **Given** that flow, **When** stored in the redacted summary, **Then** it
|
||||
omits passwords, OTPs, and personal identifiers.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Safe artifact handling (Priority: P2)
|
||||
|
||||
As the developer, sensitive captures stay off Git; redacted summaries are
|
||||
committed to `sunfish-a16-rom`.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** raw pulls/APKs, **When** stored, **Then** they live under e.g.
|
||||
`/srv/rom/references/axp/` on `rom-dev01`, not in Git.
|
||||
2. **Given** in-repo summary, **When** reviewed, **Then** it has versions/hashes/
|
||||
workflow steps without personal secrets.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- GOLDEN encrypt/PIN: document without storing the PIN.
|
||||
- Missing detail later: re-attach GOLDEN and `adb` — do not invent.
|
||||
- LAB brick: use LAB stock factory rescue; do not wipe GOLDEN to “recover”.
|
||||
- Optional personal NeoBackup of GOLDEN is outside project gates.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Label and record GOLDEN vs LAB identities; measure bootloader/
|
||||
fastboot state on both.
|
||||
- **FR-002**: Document LAB Google factory-image emergency rescue (hashes + steps).
|
||||
- **FR-003**: Capture essential GOLDEN inventory (microG, GSF, Phonesky, Insular,
|
||||
Magisk/DenyList processes, Yuh/Swissquote, call-recording + FLAG_SECURE
|
||||
sources, observational Play Integrity if measurable).
|
||||
- **FR-004**: Document GOLDEN banking flow (Aurora → NO OPEN → DenyList →
|
||||
Insular → Play update).
|
||||
- **FR-005**: Store raw artifacts off-Git; commit only redacted docs.
|
||||
- **FR-006**: Gate: no experimental flash on LAB until LAB rescue docs exist and
|
||||
GOLDEN is explicitly marked do-not-flash; **no** NeoBackup/wipe of GOLDEN
|
||||
required.
|
||||
- **FR-007**: Cross-link useful facts into `docs/axp-pro-parity.md` /
|
||||
`docs/device-roles.md` without inventing unseen features.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **GOLDEN**: live AXP oracle (not wiped for bring-up).
|
||||
- **LAB**: experimental flash target + stock rescue docs.
|
||||
- **Reference bundle**: host-local capture directory.
|
||||
- **Redacted summary**: in-repo documentation.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: GOLDEN vs LAB clearly identified; agents/docs forbid flashing GOLDEN.
|
||||
- **SC-002**: LAB stock factory rescue written and reviewed before `003`.
|
||||
- **SC-003**: Essential GOLDEN inventory + banking flow complete enough for
|
||||
`006` hard-gates; gaps marked “re-query GOLDEN” not invented.
|
||||
- **SC-004**: Yuh/Swissquote verified working on GOLDEN and documented.
|
||||
- **SC-005**: Git has no proprietary APK dumps or personal credential material.
|
||||
- **SC-006**: Bootloader states in docs match measured GOLDEN and LAB reality.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Tasks: AXP.OS GOLDEN reference capture
|
||||
|
||||
**Input**: Design docs from `/specs/002-axp-reference-capture/`
|
||||
|
||||
**Prerequisites**: `001` complete on `rom-dev01`
|
||||
|
||||
## Phase 1: Setup (no phone)
|
||||
|
||||
- [x] T001 Confirm active feature `specs/002-axp-reference-capture` in `.specify/feature.json`
|
||||
- [x] T002 [P] Create `docs/002-lab-stock-rescue.md` stub (LAB only; Google factory source)
|
||||
- [x] T003 [P] Create `docs/002-golden-inventory.md` stub (essential checklist + banking flow placeholders)
|
||||
- [x] T004 [P] Create host dirs `/srv/rom/references/axp/{archive,golden,lab,logs}` as `android-build`
|
||||
|
||||
## Phase 2: Offline AXP archive seed (no phone)
|
||||
|
||||
- [~] T005 Rsync `~/Archives/AXP.OS/` → host archive *(~18G/38G in progress; not a `003` flash gate)*
|
||||
- [x] T006 Record archive size + SNAPSHOT_DATE in `/srv/rom/references/axp/logs/archive-rsync.txt` *(partial; refresh when rsync ends)*
|
||||
|
||||
## Phase 3: LAB stock rescue (P1 — may download without phone)
|
||||
|
||||
- [x] T007 Resolve current official sunfish factory image URL + SHA-256 from Google primary page (or document pruning if only one remains) *(Google CDN 404; hash + IA fallback documented)*
|
||||
- [x] T008 Download factory zip to `/srv/rom/references/axp/lab/`; verify SHA-256 *(VERIFY_OK 2026-09-13)*
|
||||
- [x] T009 Complete `docs/002-lab-stock-rescue.md` with flash-all steps, wipe warning, LAB-only scope
|
||||
- [x] T010 Cross-check FR-002/SC-002 in a short verification note in that doc
|
||||
|
||||
## Phase 4: Device roles measured (P1 — phones required)
|
||||
|
||||
- [x] T011 Connect GOLDEN (AXP A15 main); record serial + `getprop` into golden inventory (raw log on host) — **adb sample only, no modifications** *(serial `11071JEC203839`)*
|
||||
- [x] T012 Connect LAB; record serial/label + build identity *(serial `11231JEC207477`, iodé/LOS 7.8 A16 — see `docs/002-lab-iodes-baseline.md`)*
|
||||
- [x] T013 Measure bootloader/fastboot unlock state on **both**; update `docs/device-roles.md` + inventory (SC-006) *(GOLDEN unlocked/orange; LAB locked/green — via getprop)*
|
||||
- [x] T014 Explicit “do not flash GOLDEN” callout in `docs/device-roles.md` and inventory (SC-001)
|
||||
|
||||
## Phase 5: Essential GOLDEN inventory (P1 — GOLDEN adb)
|
||||
|
||||
- [x] T015 Capture microG essential fields (version, cert, Self-Check notes) *(version + sig short; Self-Check UI = re-query)*
|
||||
- [x] T016 Capture Phonesky / `com.android.vending` essentials *(Phonesky_AXP-OS 50.2.12)*
|
||||
- [x] T017 Capture Insular / work profile essentials (`dumpsys device_policy` excerpt redacted) *(Island 6.4.2, user 10)*
|
||||
- [x] T018 Capture Magisk version, modules, DenyList **including processes** *(Magia UI DenyList packages from screenshots; Magisk 29.0; process expand partial; modules dir not readable without root)*
|
||||
- [x] T019 Capture GSF Proxy / related packages versions/paths/signatures
|
||||
- [x] T020 Record observational Play Integrity + Yuh/Swissquote pass/fail on GOLDEN (SC-004) *(Swissquote PASS; Yuh FAIL HA / certificate invalid; Finsky PI token path still completes; keystore2 TEE errors in log)*
|
||||
- [x] T021 Document call-recording + FLAG_SECURE bypass source on GOLDEN *(deferred — re-query; not blocking `003`)*
|
||||
- [x] T022 Mark any missing rows `re-query GOLDEN` — do not invent
|
||||
|
||||
## Phase 6: Banking flow (P1)
|
||||
|
||||
- [x] T023 Write redacted GOLDEN banking install order / observed layout in `docs/002-golden-inventory.md`
|
||||
- [x] T024 Confirm no passwords/OTPs/PII in Git docs (SC-005)
|
||||
|
||||
## Phase 7: Polish / gate
|
||||
|
||||
- [x] T025 Cross-link known facts into `docs/axp-pro-parity.md` without inventing features (FR-007)
|
||||
- [x] T026 FR/SC checklist pass for gate: LAB rescue ready; GOLDEN do-not-flash; inventory+flow sufficient for `006` *(see `docs/002-gate-handoff.md`)*
|
||||
- [x] T027 Handoff note: **`002` complete → `003` on LAB only**
|
||||
- [x] T028 Verify Git trees contain no proprietary APK dumps or credential files
|
||||
|
||||
## Parallel opportunities
|
||||
|
||||
- T002–T004 parallel; T005 archive rsync while drafting T007–T009
|
||||
- T011–T014 require physical devices; block inventory until done
|
||||
@@ -0,0 +1,3 @@
|
||||
# Contracts: N/A for 003
|
||||
|
||||
No HTTP/API contracts. Build/flash/smoke documentation only.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Data model: 003-lineage-23-vanilla-build
|
||||
|
||||
## VanillaBuild
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| manifest_url / branch | From `repo init` |
|
||||
| resolved_manifest | `repo manifest -r` artifact |
|
||||
| lunch_target | e.g. `lineage_sunfish-userdebug` (confirm at build) |
|
||||
| build_id / date | Host timestamp |
|
||||
| artifact_paths | img/zip under `/srv/rom/artifacts/003-…` |
|
||||
| sha256 | Per artifact |
|
||||
| build_log | Compressed under `/srv/rom/logs` |
|
||||
|
||||
## LabFlashSession
|
||||
|
||||
| Field | Notes |
|
||||
|-------|-------|
|
||||
| serial | Must be LAB `11231JEC207477` |
|
||||
| bootloader_state_before/after | Measured |
|
||||
| flash_steps | Documented |
|
||||
| boot_ok | bool |
|
||||
| getprop_fingerprint | Post-boot |
|
||||
|
||||
## SmokeChecklist
|
||||
|
||||
P1 + extended rows from spec; each `pass` / `fail` / `skip` + evidence.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Implementation Plan: LineageOS 23.2 vanilla build for sunfish
|
||||
|
||||
**Branch**: `003-lineage-23-vanilla-build` | **Date**: 2026-09-13 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/003-lineage-23-vanilla-build/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
On `rom-dev01`, sync official LineageOS **23.2** for `sunfish`, build
|
||||
`userdebug` (test-keys), publish hashed artifacts under `/srv/rom/artifacts`,
|
||||
`rsync` to the laptop, flash **LAB only** (`11231JEC207477`), and run P1 +
|
||||
extended hardware smoke. No microG, KernelSU, Magisk, or hardening patches.
|
||||
On flash failure, use `docs/002-lab-stock-rescue.md` — never touch GOLDEN.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Bash + Lineage `repo` / Soong / ninja (AOSP Android 16)
|
||||
|
||||
**Primary Dependencies**: LineageOS 23.2 manifest; device/kernel trees for
|
||||
sunfish; `ccache`; OpenSSH; laptop `adb`/`fastboot`
|
||||
|
||||
**Storage**: `/srv/rom/src` (tree), `/srv/rom/ccache`, `/srv/rom/artifacts`,
|
||||
`/srv/rom/logs` on `rom-dev01`
|
||||
|
||||
**Testing**: Observational boot + hardware checklists (documented results)
|
||||
|
||||
**Target Platform**: `rom-dev01` Ubuntu 24.04 build; LAB Pixel 4a flash
|
||||
|
||||
**Project Type**: ROM bring-up / reproducible baseline artifact
|
||||
|
||||
**Performance Goals**: Complete sync+build with conservative `-j`; survive
|
||||
OOM via documented recovery
|
||||
|
||||
**Constraints**: LAB only; no project patches beyond LOS device needs; no
|
||||
Magisk/KSU “just to test”; GOLDEN forbidden
|
||||
|
||||
**Scale/Scope**: One developer; one known-good vanilla baseline for regression
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- Independence from SSYSTEMS: yes
|
||||
- GOLDEN do-not-flash: enforced (FR-007)
|
||||
- Functionality-first vanilla base before hardening: yes
|
||||
- Secrets/APKs off Git: artifacts stay on host/laptop paths; Git = docs/metadata
|
||||
- Prefer primary sources: Lineage wiki + official manifest
|
||||
|
||||
**Post-design**: Pass — plan does not invent device trees or flash GOLDEN.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/003-lineage-23-vanilla-build/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source / artifact layout
|
||||
|
||||
```text
|
||||
# rom-dev01
|
||||
/srv/rom/src/lineage/ # repo workspace (or documented path)
|
||||
/srv/rom/artifacts/003-*/ # images, zip, SHA-256, repo manifest -r
|
||||
/srv/rom/logs/003-*/ # compressed build logs
|
||||
|
||||
# laptop
|
||||
~/…/artifacts/003-*/ # rsync target for flash
|
||||
docs/003-*.md # flash + smoke results (redacted)
|
||||
```
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
None — single vanilla bring-up path.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Quickstart: 003 vanilla LOS 23.2
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `001` host ready (`rom-dev01`, `android-build`, ccache, repo)
|
||||
- `002` gate: LAB rescue zip OK; GOLDEN do-not-flash
|
||||
- USB to **LAB** only for flash
|
||||
|
||||
## Build (host)
|
||||
|
||||
```bash
|
||||
ssh rom-dev01 # as android-build
|
||||
# repo init/sync lineage-23.2 sunfish — exact commands in tasks / build notes
|
||||
# breakfast/lunch sunfish userdebug
|
||||
# mka bacon or documented target; log + hash artifacts into /srv/rom/artifacts
|
||||
```
|
||||
|
||||
## Flash (laptop → LAB)
|
||||
|
||||
1. `adb devices` / `fastboot devices` — confirm LAB serial
|
||||
2. Unlock LAB if needed (wipes device)
|
||||
3. Flash per LOS wiki / project `docs/003-flash-lab.md` (to be written)
|
||||
4. If brick/bootloop: `docs/002-lab-stock-rescue.md`
|
||||
|
||||
## Smoke
|
||||
|
||||
Fill `docs/003-smoke-lab.md` P1 + extended; keep as known-good baseline before `004`.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Research: 003-lineage-23-vanilla-build
|
||||
|
||||
## R1 — Manifest / branch
|
||||
|
||||
**Decision**: Use official LineageOS `lineage-23.2` (or the wiki-documented
|
||||
sunfish 23.2 branch name measured at implement time). Record exact
|
||||
`repo init` URL/branch and `repo manifest -r` for the known-good build.
|
||||
|
||||
**Rationale**: Constitution base = LOS 23.2 / A16; no AXP/GOS base.
|
||||
|
||||
## R2 — Build user / path
|
||||
|
||||
**Decision**: Build as `android-build` on `rom-dev01`; tree under
|
||||
`/srv/rom/src/` (exact subdir documented at init); `CCACHE_DIR=/srv/rom/ccache`.
|
||||
|
||||
## R3 — Variant
|
||||
|
||||
**Decision**: `userdebug` + LOS default/test-keys for this stage (FR-002).
|
||||
Release keys / AVB = later (`011`).
|
||||
|
||||
## R4 — Flash target
|
||||
|
||||
**Decision**: **LAB only** (`11231JEC207477`). Owner approved unlock/wipe for
|
||||
first custom flash. GOLDEN never flashed. Factory zip on disk =
|
||||
**emergency rescue only** — owner does not want stock as a planned LAB OS;
|
||||
skip “Yuh on stock” experiment.
|
||||
|
||||
## R4b — Banking / root / Phonesky (owner 2026-09-13)
|
||||
|
||||
- Hard-gate focus: **Yuh** (+ Swissquote as tracked); Revolut not a hard-gate.
|
||||
- Root: **KernelSU-Next + SusFS**; ReSukiSU only if KSU-Next fails on LAB.
|
||||
- Play: **AXP-style patched Phonesky/GPlay** priv-app (not XDA FakeStore-first).
|
||||
|
||||
## R5 — Parallelism / OOM
|
||||
|
||||
**Decision**: Start conservative `-j` (e.g. half of vCPUs); document failure
|
||||
recovery (`out/` cleanup) in build notes. Measure host: ~8 vCPU / 62 GiB RAM.
|
||||
|
||||
## R6 — What “vanilla” excludes
|
||||
|
||||
**Decision**: No microG, Phonesky, signature-spoof patches, KernelSU/SUSFS,
|
||||
Magisk, call-recording/FLAG_SECURE ports, Graphene/Divest hardening — even if
|
||||
present on LAB’s current iodé image (that baseline will be wiped by flash).
|
||||
|
||||
## R8 — Proprietary blobs
|
||||
|
||||
**Decision (owner 2026-09-13):** Factory/Lineage-equivalent blob base, then
|
||||
selective **AXP sunfish** diffs and **GrapheneOS** diffs (historical sunfish A13
|
||||
+ transferable bits from a currently supported Pixel). No exotic blob hunting
|
||||
for GPS; do not overthink for `003` vanilla (factory-equivalent only).
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# Feature Specification: LineageOS 23.2 vanilla build for sunfish
|
||||
|
||||
**Feature Branch**: `003-lineage-23-vanilla-build`
|
||||
|
||||
**Created**: 2026-08-09
|
||||
|
||||
**Status**: Active — implementation next (vanilla sync/build on `rom-dev01`)
|
||||
|
||||
**Input**: Produce the first vanilla LineageOS 23.2 / Android 16 build for
|
||||
`sunfish`, copy images to the laptop, flash, and verify boot plus basic
|
||||
hardware — with no microG, KernelSU, or hardening yet.
|
||||
|
||||
## Context / non-goals
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- `001-development-environment` sufficiently complete to sync/build;
|
||||
- `002-axp-reference-capture` P1 complete (GOLDEN labeled; LAB stock rescue
|
||||
documented). Flash **LAB only** — never GOLDEN (`docs/device-roles.md`).
|
||||
|
||||
**Out of scope for this feature:**
|
||||
|
||||
- microG / Phonesky / signature spoofing;
|
||||
- KernelSU / SUSFS / Magisk parity;
|
||||
- call recording, FLAG_SECURE toggles, privacy extras;
|
||||
- project signing / AVB / OTA implementation;
|
||||
- Graphene/AXP/Divest patch ports.
|
||||
|
||||
Build target: **`userdebug`** with development/test-keys.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Reproducible vanilla sync & build (Priority: P1)
|
||||
|
||||
As the developer, I can sync LineageOS 23.2 for sunfish on `rom-dev01` and
|
||||
complete a build that emits flashable images, with manifest/revisions recorded.
|
||||
|
||||
**Why this priority**: Establishes the real base ROM.
|
||||
|
||||
**Independent Test**: Build finishes; artifact paths listed; manifest revision
|
||||
document stored under `/srv/rom` with hashes.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `android-build` on `rom-dev01`, **When** I sync the LOS 23.2
|
||||
sunfish source via `repo`, **Then** the tree matches a documented manifest
|
||||
revision.
|
||||
2. **Given** the synced tree, **When** I build `userdebug` for sunfish with
|
||||
conservative parallelism, **Then** the build completes without requiring
|
||||
project patches beyond LOS-needed device/kernel trees.
|
||||
3. **Given** a successful build, **When** I collect outputs, **Then** images/
|
||||
zip needed to flash sunfish are in `/srv/rom/artifacts` (or documented path)
|
||||
with SHA-256 hashes and a compressed build log.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Flash from laptop (Priority: P1)
|
||||
|
||||
As the developer, I `rsync` artifacts to the laptop and flash the Pixel 4a over
|
||||
USB using fastboot/adb, following the recovery notes from `002` if something
|
||||
fails.
|
||||
|
||||
**Why this priority**: Closes the loop on the thin-client workflow.
|
||||
|
||||
**Independent Test**: Device boots the new build; `getprop` shows LineageOS /
|
||||
expected fingerprints (not AXP).
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** artifacts on the laptop, **When** I flash per documented steps,
|
||||
**Then** the device boots into the vanilla LOS build.
|
||||
2. **Given** a failed flash/boot on **LAB**, **When** I follow `002` LAB stock
|
||||
factory rescue docs, **Then** LAB returns to usable stock. GOLDEN is not
|
||||
touched.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Basic hardware smoke test (Priority: P1)
|
||||
|
||||
As the developer, after first boot I verify essential radios and peripherals
|
||||
well enough to trust this build as the clean base for later features — and I
|
||||
know what was already broken on **vanilla** LOS before we add patches.
|
||||
|
||||
**Why this priority**: A boot-only “success” that breaks telephony/Wi-Fi is not
|
||||
a usable base. Later regressions must be attributable.
|
||||
|
||||
**Independent Test**: Checklist results stored for P1 and extended items on the
|
||||
vanilla build.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** first boot completed, **When** I run the **P1 smoke** set, **Then**
|
||||
each item either works or is logged as a blocking defect with evidence:
|
||||
|
||||
- encryption / PIN
|
||||
- SELinux mode (`Enforcing` expected)
|
||||
- Android security patch level
|
||||
- vendor security patch level / build baseline
|
||||
- SIM detection
|
||||
- mobile data
|
||||
- phone calls
|
||||
- SMS (send/receive as applicable)
|
||||
- Wi-Fi
|
||||
- Bluetooth
|
||||
- GPS
|
||||
- camera(s)
|
||||
- audio (speaker/mic)
|
||||
- NFC
|
||||
- sensors (basic)
|
||||
- fingerprint
|
||||
- USB data / ADB
|
||||
- charging
|
||||
|
||||
2. **Given** P1 smoke done, **When** I run the **extended baseline** set,
|
||||
**Then** each is recorded (need not all be P1 blockers, but must not be
|
||||
skipped silently):
|
||||
|
||||
- airplane mode
|
||||
- flashlight
|
||||
- vibration
|
||||
- screen rotation
|
||||
- USB OTG (if hardware/cable available)
|
||||
- headphone jack
|
||||
- WebView implementation / basic page load
|
||||
- app sideload install smoke (non-Google)
|
||||
- Widevine / DRM security level
|
||||
- eSIM capability/state, if available
|
||||
- WireGuard kernel capability/baseline
|
||||
- bootloader version
|
||||
- baseband / modem version
|
||||
|
||||
3. **Given** smoke results, **When** deciding to proceed to `004`, **Then** no
|
||||
unresolved P1 hardware blockers remain (or they are explicitly accepted with
|
||||
rationale).
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Build disk/oom with 52 GB + swap: document job `-j` and failure recovery
|
||||
(`out/` cleanup).
|
||||
- Partial artifact set: do not flash until required partitions/images are
|
||||
present and hashed.
|
||||
- Do not install Magisk/KernelSU “just to test” in this feature.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Initialize from the documented official LineageOS 23.2
|
||||
manifest/branch (`repo init` → sync) and capture a revision-locked resolved
|
||||
manifest (e.g. `repo manifest -r`) for every known-good build.
|
||||
- **FR-002**: Build `userdebug` images with test-keys / default LOS signing for
|
||||
this stage.
|
||||
- **FR-003**: Record manifest, revisions, build variant, config, hashes, and
|
||||
compressed log for the successful build.
|
||||
- **FR-004**: Publish artifacts to `/srv/rom/artifacts` and document `rsync` +
|
||||
flash procedure.
|
||||
- **FR-005**: Boot sunfish on the vanilla build and run the P1 + extended
|
||||
hardware/baseline checklist (record results even for non-blockers).
|
||||
- **FR-006**: Keep tree free of microG/Phonesky/KernelSU/hardening patches
|
||||
intended for later features.
|
||||
- **FR-007**: On LAB flash failure, follow `002` LAB stock factory rescue; never
|
||||
flash or wipe GOLDEN as part of recovery.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Vanilla LOS build**: clean base artifact set.
|
||||
- **Build metadata**: manifest + hashes + log bundle.
|
||||
- **Smoke checklist**: hardware/regression minimum for this stage.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: One successful sunfish `userdebug` build exists with recorded
|
||||
metadata and hashes.
|
||||
- **SC-002**: Device boots that build after laptop-side flash.
|
||||
- **SC-003**: P1 and extended hardware/baseline checklists are completed and
|
||||
stored (extended items may be non-blocking but must be recorded).
|
||||
- **SC-004**: No dependency on LSPosed/Magisk modules for this stage’s success.
|
||||
- **SC-005**: This build is tagged/kept as a known-good flashable baseline for
|
||||
regression when later features break the device.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Tasks: LineageOS 23.2 vanilla build for sunfish
|
||||
|
||||
**Input**: Design docs from `/specs/003-lineage-23-vanilla-build/`
|
||||
**Prerequisites**: `001` done; `002` P1 gate (`docs/002-gate-handoff.md`)
|
||||
|
||||
## Phase 1: Prep
|
||||
|
||||
- [x] T001 Confirm active feature `specs/003-lineage-23-vanilla-build`
|
||||
- [x] T002 [P] Create `docs/003-build-notes.md` stub (manifest URL/branch TBD at init)
|
||||
- [x] T003 [P] Create `docs/003-flash-lab.md` stub (LAB serial check; link rescue)
|
||||
- [x] T004 [P] Create `docs/003-smoke-lab.md` checklist from spec P1 + extended
|
||||
- [x] T005 Verify LAB serial still `11231JEC207477`; confirm GOLDEN not attached before any flash *(LAB serial documented; flash later)*
|
||||
- [x] T006 Confirm host dirs `/srv/rom/{src,artifacts,logs,ccache}` writable by `android-build`
|
||||
|
||||
## Phase 2: Sync
|
||||
|
||||
- [x] T007 `repo init` official LineageOS 23.2 (wiki-verified URL/branch) under `/srv/rom/src/…` *(`/srv/rom/src/lineage`, `lineage-23.2`)*
|
||||
- [x] T008 `repo sync` sunfish device/kernel dependencies; record wall time / failures *(finished 2026-09-13T21:27:26Z exit=0; tree ~180G)*
|
||||
- [x] T009 Save `repo manifest -r` to `/srv/rom/artifacts/003-…/manifest-rev.xml`
|
||||
|
||||
## Phase 3: Build
|
||||
|
||||
- [x] T010 Configure ccache env; choose parallelism (**`-j8`** = match vCPU)
|
||||
- [x] T011 `lunch`/`breakfast` sunfish `userdebug`; start build; capture log
|
||||
- [x] T012 On OOM/disk failure: document recovery; retry (no silent `-j` guessing) *(N/A — no OOM; mid-run bump -j4→-j8)*
|
||||
- [x] T013 Collect flashable images/zip into `/srv/rom/artifacts/003-…`; SHA-256 all
|
||||
- [x] T014 Compress build log beside artifacts; write build metadata (variant, date, host)
|
||||
|
||||
## Phase 4: Flash LAB
|
||||
|
||||
- [x] T015 `rsync` artifacts to laptop *(`${WORKSPACE}/.local-artifacts/003-vanilla/20260914-lineage-23.2-sunfish/`)*
|
||||
- [x] T016 Unlock LAB bootloader if still locked (owner-approved wipe) — **LAB only**
|
||||
- [x] T017 Flash per `docs/003-flash-lab.md`; verify serial before every `fastboot` command
|
||||
- [x] T018 Confirm first boot; `getprop` shows LOS vanilla (not AXP / not prior iodé id)
|
||||
- [ ] T019 If fail: factory rescue from `002`; do not touch GOLDEN *(N/A so far)*
|
||||
|
||||
## Phase 5: Smoke
|
||||
|
||||
- [x] T020 Complete P1 smoke checklist in `docs/003-smoke-lab.md`
|
||||
- [x] T021 Complete extended baseline checklist (record skips with reason)
|
||||
- [x] T022 Decide gate to `004`: no unresolved P1 blockers (or explicit accept)
|
||||
|
||||
## Phase 6: Polish
|
||||
|
||||
- [x] T023 Tag/keep known-good baseline note (paths + hashes) for regression
|
||||
(`docs/003-gate-handoff.md` + artifacts dir)
|
||||
- [x] T024 Confirm tree has no microG/KSU/hardening patches (FR-006)
|
||||
(vanilla identity props; no microG packages on LAB pre-004)
|
||||
- [x] T025 Handoff: **`003` complete → `004`** (microG path) on LAB only
|
||||
|
||||
## Parallel opportunities
|
||||
|
||||
- T002–T004 while T006 host checks run
|
||||
- T015 rsync can start as soon as T013 hashes exist
|
||||
@@ -0,0 +1,35 @@
|
||||
# Specification Quality Checklist: microG + Phonesky
|
||||
|
||||
**Purpose**: Validate specification completeness before planning
|
||||
**Created**: 2026-09-14
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Spoofing deferred to `005` by design; Self-Check may be partially blocked until then.
|
||||
- Phonesky signing strategy is FR-010 (document during plan/implement; keys host-only).
|
||||
@@ -0,0 +1,35 @@
|
||||
# Contract: system packages (004)
|
||||
|
||||
## Packages that MUST be present on LAB after flash
|
||||
|
||||
| Package | Type | Notes |
|
||||
|---------|------|-------|
|
||||
| `com.google.android.gms` | system/priv | microG |
|
||||
| `com.google.android.gsf` | system/priv | GsfProxy |
|
||||
| `com.android.vending` | **priv-app** | Patched Phonesky |
|
||||
|
||||
## Packages that MUST NOT be present
|
||||
|
||||
| Package | Notes |
|
||||
|---------|-------|
|
||||
| FakeStore (typical `com.android.vending` stub from partner_gms) | Conflicts with Phonesky |
|
||||
| Magisk / KernelSU manager (as ROM-preinstalled) | Out of scope until `007` |
|
||||
|
||||
## Host path contract (rom-dev01)
|
||||
|
||||
| Path | Contents | In Git? |
|
||||
|------|----------|---------|
|
||||
| `/srv/rom/prebuilts/microg/` | GmsCore + GsfProxy APKs + `VERSIONS.txt` | No |
|
||||
| `/srv/rom/prebuilts/phonesky/` | Phonesky APK + permission XMLs + `VERSIONS.txt` | No |
|
||||
| `/srv/rom/secrets/phonesky-signing/` | Optional project keys | No |
|
||||
| Meta-repo `docs/004-*.md` | Runbook + self-check | Yes |
|
||||
| Product/vendor mk under LOS tree | References prebuilts by path | Tree on host; mirror patches in meta if small |
|
||||
|
||||
## Verification commands (LAB)
|
||||
|
||||
```bash
|
||||
adb -s 11231JEC207477 shell pm path com.google.android.gms
|
||||
adb -s 11231JEC207477 shell pm path com.google.android.gsf
|
||||
adb -s 11231JEC207477 shell pm path com.android.vending
|
||||
adb -s 11231JEC207477 shell pm list packages | grep -i fakestore || true
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
# Data model: 004 packages
|
||||
|
||||
## Entities
|
||||
|
||||
### MicroGGmsCore
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| package | `com.google.android.gms` |
|
||||
| role | microG Services Core |
|
||||
| install | privileged / system (product or system_ext per chosen mk) |
|
||||
| source | Official microG release APK on host prebuilts |
|
||||
| golden_ref | `0.3.15.250932` (AXP inventory) |
|
||||
|
||||
### GsfProxy
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| package | `com.google.android.gsf` |
|
||||
| role | Legacy GSF / C2DM proxy |
|
||||
| install | system app or priv-app |
|
||||
| source | microG GsfProxy release (or rebuilt for targetSdk if needed) |
|
||||
| golden_ref | `GsfProxy_GH` v0.1.0 on GOLDEN |
|
||||
|
||||
### PhoneskyPatched
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| package | `com.android.vending` |
|
||||
| role | Patched Play Store |
|
||||
| install | **priv-app** + privapp-permissions + default-permissions XML |
|
||||
| source | AXP archive APK (not Git) |
|
||||
| golden_ref | Phonesky_AXP-OS **50.2.12-24** |
|
||||
| first_candidate | archive **50.3.27-24** or **51.4.19-24** |
|
||||
|
||||
### PermissionConfig
|
||||
|
||||
| Artifact | Purpose |
|
||||
|----------|---------|
|
||||
| `privapp-permissions-com.android.vending.xml` | Privileged permissions allowlist |
|
||||
| `com.android.vending.xml` | Feature/permission declarations as needed |
|
||||
| `phonesky-permissions.xml` (default-permissions) | Default grants |
|
||||
|
||||
### ForbiddenCompanion
|
||||
|
||||
| package | rule |
|
||||
|---------|------|
|
||||
| FakeStore / conflicting Companion | MUST NOT ship alongside Phonesky |
|
||||
|
||||
## Relationships
|
||||
|
||||
- Phonesky **replaces** FakeStore in the compatibility stack.
|
||||
- microG Self-Check may require spoofing of GmsCore (and later Phonesky) —
|
||||
spoofing policy owned by `005`.
|
||||
- All binaries → host prebuilts → product makefile → image; evidence →
|
||||
`/srv/rom/artifacts/004-…`.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Implementation Plan: microG + GSF Proxy + patched Phonesky
|
||||
|
||||
**Branch**: `004-microg-phonesky-integration` | **Date**: 2026-09-14 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/004-microg-phonesky-integration/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Add the Google compatibility stack to the sunfish LOS 23.2 / Android 16 tree on
|
||||
**LAB only**: microG GmsCore, GSF Proxy, and **patched Phonesky** as priv-app
|
||||
(AXP-style), without FakeStore, Magisk, or KernelSU. Signature spoofing beyond
|
||||
what LOS already provides stays in `005`. Proprietary APKs live only under
|
||||
`/srv/rom/` (never Git).
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Android.mk / Soong (`Android.bp` where needed); bash
|
||||
runbooks on `rom-dev01`
|
||||
**Primary Dependencies**: LineageOS 23.2 tree (`/srv/rom/src/lineage`); microG
|
||||
release APKs; AXP `packages_apps_phonesky` permission XMLs + signed APK from
|
||||
project AXP archive; LOS restricted signature spoofing (baseline)
|
||||
**Storage**: Host paths `/srv/rom/prebuilts/{microg,phonesky}/`, secrets under
|
||||
`/srv/rom/secrets/`
|
||||
**Testing**: LAB flash + `pm`/`dumpsys` + microG Self-Check screenshots; no
|
||||
unit-test harness required
|
||||
**Target Platform**: Pixel 4a (`sunfish`) LAB `11231JEC207477`; Android 16
|
||||
**Project Type**: Android ROM packaging / device product overlay
|
||||
**Performance Goals**: N/A (functional compatibility)
|
||||
**Constraints**: No proprietary APKs in Git; no GOLDEN flash; no Magisk/KSU in
|
||||
`004`; Phonesky signing keys host-only
|
||||
**Scale/Scope**: Three system packages + permission XMLs + product makefile +
|
||||
runbook; one rebuild + LAB flash
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| LAB only; never GOLDEN | pass |
|
||||
| No proprietary Google APKs in Git | pass (host `/srv/rom/prebuilts`) |
|
||||
| Phonesky = patched priv-app, not FakeStore primary | pass |
|
||||
| No Magisk/KSU in Compatibility path before `006`/`007` | pass (`004` rootless) |
|
||||
| Spoofing restricted / auditable → full policy in `005` | pass (use LOS baseline only here) |
|
||||
| Prefer AXP reference for packaging | pass (archive Phonesky + XMLs) |
|
||||
| Prefer small attributable changes | pass (vendor/product overlay, not megapatch) |
|
||||
|
||||
**Post-design**: unchanged — design stays packaging + docs.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/004-microg-phonesky-integration/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
│ └── packages.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Host + tree (not all in Git)
|
||||
|
||||
```text
|
||||
# Meta repo (this workspace)
|
||||
docs/004-phonesky-runbook.md
|
||||
docs/004-lab-selfcheck.md
|
||||
vendor packaging stubs / product mk (synced to rom-dev01 tree)
|
||||
|
||||
# rom-dev01 (canonical build)
|
||||
/srv/rom/src/lineage/ # LOS tree
|
||||
/srv/rom/prebuilts/microg/ # GmsCore + GsfProxy APKs (gitignored host)
|
||||
/srv/rom/prebuilts/phonesky/ # Phonesky APK + permission XMLs
|
||||
/srv/rom/secrets/phonesky-signing/ # keys if we re-sign (optional first pass)
|
||||
/srv/rom/artifacts/004-…/ # build zip + self-check evidence
|
||||
```
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why needed | Simpler alternative rejected because |
|
||||
|-----------|------------|--------------------------------------|
|
||||
| None | — | — |
|
||||
|
||||
## Phase 0 / Phase 1
|
||||
|
||||
See `research.md`, `data-model.md`, `contracts/packages.md`, `quickstart.md`.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Quickstart: validate 004 on LAB
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `003` vanilla known-good on LAB (or re-flash `004` build cleanly)
|
||||
- Serial **only** `11231JEC207477`
|
||||
- Host prebuilts populated per `docs/004-phonesky-runbook.md`
|
||||
|
||||
## Build (rom-dev01)
|
||||
|
||||
```bash
|
||||
ssh a16-build # or android-build via a16-build alias
|
||||
# ensure prebuilts exist
|
||||
cat /srv/rom/prebuilts/microg/VERSIONS.txt
|
||||
cat /srv/rom/prebuilts/phonesky/VERSIONS.txt
|
||||
cd /srv/rom/src/lineage
|
||||
source build/envsetup.sh
|
||||
breakfast sunfish userdebug
|
||||
mka bacon -j8
|
||||
```
|
||||
|
||||
Copy zip to `/srv/rom/artifacts/004-…/` + SHA-256; rsync to laptop.
|
||||
|
||||
## Flash LAB
|
||||
|
||||
Same flow as `docs/003-flash-lab.md` (dtbo → boot recovery → format if needed →
|
||||
sideload). **No** GApps add-ons beyond what is already in the ROM image.
|
||||
|
||||
## Validate
|
||||
|
||||
1. `adb devices` shows LAB only.
|
||||
2. Package contract (`contracts/packages.md`).
|
||||
3. Open **microG Settings → Self-Check**; screenshot to
|
||||
`/srv/rom/artifacts/004-…/selfcheck/` (or laptop `.local-artifacts`).
|
||||
4. Open Play Store; note whether login/install works or is blocked pending
|
||||
`005`.
|
||||
5. Confirm no Magisk/KSU: `pm list packages | grep -iE 'magisk|kernelsu'`.
|
||||
|
||||
## Pass criteria
|
||||
|
||||
- SC-001…SC-005 from `spec.md`
|
||||
- Spoofing-only Self-Check failures explicitly listed as `005` follow-ups
|
||||
@@ -0,0 +1,95 @@
|
||||
# Research: 004 microG + Phonesky
|
||||
|
||||
## Decision: Packaging layout — follow AXP GOLDEN scheme (owner 2026-09-15)
|
||||
|
||||
**Decision**: Mirror AXP GOLDEN partition roles. Do not invent a `product`-centric
|
||||
layout. Measured on GOLDEN (`002`):
|
||||
|
||||
| Package | AXP GOLDEN path | Our packaging |
|
||||
|---------|-----------------|---------------|
|
||||
| Phonesky | `/system/priv-app/Phonesky_AXP-OS` | **system** + privileged |
|
||||
| GmsCore | `/system_ext/app/MicrogGmsCore_GH_presigned` | **system_ext** app (not priv-app) |
|
||||
| GsfProxy | `/system_ext/app/GsfProxy_GH` | **system_ext** app |
|
||||
|
||||
Ship via a small `vendor/sunfish-a16` include (partner_gms *pattern*) but
|
||||
**replace FakeStore** with patched Phonesky. Permission XMLs follow the same
|
||||
partitions (`system` for Phonesky, `system_ext` for microG).
|
||||
|
||||
**Rationale**: Owner — AXP methods exist for a reason; goal is modernize (LOS
|
||||
23.2 / A16) and later replace Magisk with KSU-Next+SusFS (`007`), not redesign
|
||||
the compatibility stack. Ad-hoc `LOCAL_PRODUCT_MODULE` + ABI-strip/re-sign of
|
||||
GmsCore risks different update/SELinux/behaviour vs GOLDEN.
|
||||
|
||||
**Alternatives rejected**:
|
||||
- All on `PRODUCT` — layout drift; hit partition checks awkwardly
|
||||
- ABI-strip + project re-sign of GmsCore — breaks official microG F-Droid signer
|
||||
- Stock lineageos4microg + FakeStore — wrong Store model
|
||||
- Magisk module installers — not for `004` (root is `007`, non-Magisk)
|
||||
|
||||
**Partition headroom**: AXP release Phonesky APKs stay **fat** (all ABIs); CI
|
||||
does not strip x86. If LOS 23.2 sunfish `BOARD_SUPER_PARTITION_ERROR_LIMIT` is
|
||||
too tight for this package set, raise the error limit modestly (still under
|
||||
`BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE`) rather than breaking microG’s signer.
|
||||
|
||||
## Decision: Phonesky binary — patch latest, AXP procedure, project sign
|
||||
|
||||
**Decision**: Latest official Play (apkmd) → AXP `patch-playstore` → project JKS
|
||||
under `/srv/rom/secrets/phonesky-signing/`. XMLs from AXP `etc/`. Do **not** ship
|
||||
`Phonesky_AXP-OS-signed.apk` as product (wrong trust domain). Keep fat APK unless
|
||||
a later measured need forces arch filtering (document then).
|
||||
|
||||
## Decision: microG — latest official PRESIGNED + F-Droid
|
||||
|
||||
**Decision**: Latest official GmsCore **default** APK (`com.google.android.gms-*.apk`
|
||||
without `-hw`) + GsfProxy, `PRESIGNED`, system_ext like AXP `*_GH_presigned`.
|
||||
Never re-sign. F-Droid microG repo is the update path. No FakeStore/Companion APK
|
||||
from microG releases.
|
||||
|
||||
**Do not ship `*-hw.apk`**: that Huawei flavor omits
|
||||
`NetworkLocationService` / `NetworkLocationProviderService` from the manifest, so
|
||||
microG Location hides Wi‑Fi/cell NLP toggles. GOLDEN ships the default flavor
|
||||
(`versionName` without `-hw`, e.g. `0.3.15.250932`); LAB previously had
|
||||
`0.3.16.252432-hw` and only Timeline — corrected 2026-09-16 to
|
||||
`0.3.16.252432` default for GOLDEN Location UI parity.
|
||||
|
||||
## Decision: Signature spoofing in `004`
|
||||
|
||||
**Decision**: Use LOS 23.2 restricted spoofing only; gaps → `005`.
|
||||
|
||||
## Decision: AXP scheme vs Android 16 / LOS 23.2 (owner 2026-09-15)
|
||||
|
||||
**Decision**: Prefer the AXP **A15 / GOLDEN** packaging and behaviour scheme when
|
||||
LOS 23.2 / Android 16 still supports it. If A16 makes an equivalent path
|
||||
*easier* (cleaner APIs, existing LOS hooks), use that — still targeting the
|
||||
same end state (priv Play, updatable official-signer microG, banking path).
|
||||
If A16 makes the AXP path *harder* or impossible, do **not** silently invent a
|
||||
divergent stack: document the blocker and redesign the route to the **same**
|
||||
goals (layout roles, update model, no Magisk-shaped packaging).
|
||||
|
||||
**Rationale**: AXP’s choices were intentional; A16 is a port/modernization, not
|
||||
a license to ignore the oracle. Divergence only when measured necessity.
|
||||
|
||||
**Oracle scope (owner 2026-09-16)**: GOLDEN and abu are **Android 15** reference
|
||||
images — use them for packaging/layout/behaviour (e.g. which GmsCore *flavor*
|
||||
exposes Location NLP), not as a pin to their older package versions. On LOS 23.2
|
||||
/ A16 we ship the **newest** fitting official microG (and peers) that preserve
|
||||
that scheme (default/non-hw GmsCore, not `*-hw`).
|
||||
|
||||
**Measured A16 blocker (2026-09-14)**: Putting Phonesky on `system/priv-app`
|
||||
fails `artifact_path_requirements` (`generic_system.mk`) under LOS 23.2.
|
||||
**Route to same end state**: keep AXP paths and add them to
|
||||
`PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST` (same mechanism sunfish already
|
||||
uses for a few system libs) — do not move Phonesky to `product` just to silence
|
||||
the check. GmsCore/Gsf on `system_ext` already passed.
|
||||
|
||||
**Align-first (owner 2026-09-15)**: Do not invent `privapp-permissions` for
|
||||
GmsCore while GOLDEN ships it as non-privileged `system_ext` app. Ship only
|
||||
AXP Phonesky XMLs; repair from Self-Check / build errors if A16 truly requires
|
||||
more.
|
||||
|
||||
## Decision: Signing strategy (FR-010) — locked
|
||||
|
||||
| Package | Signer | Update path |
|
||||
|---------|--------|-------------|
|
||||
| GmsCore / GsfProxy | Official microG (`PRESIGNED`) | F-Droid microG repo |
|
||||
| Phonesky | Project JKS `/srv/rom/secrets/phonesky-signing/` | Same-signer patched APKs |
|
||||
@@ -0,0 +1,178 @@
|
||||
# Feature Specification: microG + GSF Proxy + patched Phonesky
|
||||
|
||||
**Feature Branch**: `004-microg-phonesky-integration`
|
||||
**Created**: 2026-09-14
|
||||
**Status**: Draft
|
||||
**Input**: Continue after `003` gate — integrate Google compatibility stack on LAB
|
||||
vanilla LOS 23.2 / Android 16 (sunfish), without Magisk/KernelSU yet.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - microG Self-Check green on LAB (Priority: P1)
|
||||
|
||||
As the developer, after flashing a build that includes microG + GSF Proxy, I can
|
||||
open microG Settings Self-Check and see the checks required for basic Google
|
||||
compatibility pass (or document exact remaining gaps owned by `005`).
|
||||
|
||||
**Why this priority**: Without a working microG core, Play and banking paths
|
||||
cannot start.
|
||||
|
||||
**Independent Test**: Flash LAB-only build; open microG Self-Check; capture
|
||||
screenshots/log; no Magisk/KSU installed.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** LAB on `003` vanilla baseline, **When** a `004` build is flashed,
|
||||
**Then** `com.google.android.gms` and `com.google.android.gsf` are present as
|
||||
system packages and microG Settings opens.
|
||||
2. **Given** microG is configured (device registration as required), **When**
|
||||
Self-Check runs, **Then** either all P1 checks pass, or each failure is
|
||||
explicitly attributed to signature spoofing (`005`) vs packaging error.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Patched Phonesky as priv-app (Priority: P1)
|
||||
|
||||
As the developer, patched Play Store (`com.android.vending`) is installed as a
|
||||
privileged system app with required permission XMLs, obtained/patched/signed via
|
||||
a documented host-side procedure (APK never committed to Git).
|
||||
|
||||
**Why this priority**: Constitution requires AXP-style patched Phonesky, not
|
||||
FakeStore→Play as primary.
|
||||
|
||||
**Independent Test**: Package present as priv-app; permission XMLs deployed;
|
||||
Play UI launches; update path documented even if spoofing still incomplete.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Phonesky artifacts under a restricted host path, **When** the ROM
|
||||
is built, **Then** `com.android.vending` is a privileged system app with the
|
||||
required default-permission / privapp-permissions configuration.
|
||||
2. **Given** the build is flashed to LAB, **When** Play Store is opened,
|
||||
**Then** it starts (login/install may still depend on `005` spoofing — mark
|
||||
clearly if so).
|
||||
3. **Given** Git history, **When** inspected, **Then** no Google proprietary
|
||||
Phonesky APK bytes are committed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - No FakeStore conflict (Priority: P2)
|
||||
|
||||
As the developer, FakeStore / microG Companion are not installed when they would
|
||||
conflict with real patched `com.android.vending`.
|
||||
|
||||
**Why this priority**: Prevents the wrong Play stub from masking Phonesky.
|
||||
|
||||
**Independent Test**: `pm list packages` shows no conflicting FakeStore when
|
||||
Phonesky is present.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Phonesky is included, **When** packages are listed, **Then**
|
||||
FakeStore is absent (or explicitly disabled with documented reason).
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Reproducible obtain → patch → sign pipeline (Priority: P2)
|
||||
|
||||
As the developer, I can re-run a documented procedure on `rom-dev01` to produce
|
||||
signed Phonesky + microG packaging inputs without tribal knowledge.
|
||||
|
||||
**Why this priority**: Required before any updatable Play Store distribution.
|
||||
|
||||
**Independent Test**: Second operator (or clean host path) follows the runbook
|
||||
and produces matching package names/permissions (signature may differ if keys
|
||||
differ — keys stay host-only).
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the `004` runbook, **When** followed on `rom-dev01`, **Then**
|
||||
inputs land under `/srv/rom/…` (restricted) and the build consumes them
|
||||
without manual one-off hacks.
|
||||
2. **Given** signing keys, **When** stored, **Then** they live only under
|
||||
host secrets (e.g. `/srv/rom/secrets/`), never in Git.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- LOS 23.2 already ships partial microG spoofing → use it; do not invent a full
|
||||
spoofing stack in `004` (that is `005`).
|
||||
- Self-Check fails only on signature-related items → record as `005` dependency,
|
||||
not a `004` packaging failure.
|
||||
- Play login/install fails while Self-Check packaging is OK → same split.
|
||||
- Flash/upgrade wipes user data → LAB only; never GOLDEN.
|
||||
- Wrong device serial → abort flash.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Integrate **latest** official microG Services Core as
|
||||
`com.google.android.gms` on the LOS 23.2 sunfish LAB build (do not pin to
|
||||
GOLDEN’s older version).
|
||||
- **FR-002**: Integrate GSF Proxy as `com.google.android.gsf` (latest upstream).
|
||||
- **FR-003**: Integrate patched Phonesky as privileged `com.android.vending`
|
||||
with required privapp-permissions / default-permissions XML, produced by
|
||||
patching the **latest** official Play Store APK (not an AXP archive binary).
|
||||
- **FR-004**: Document and implement a reproducible obtain → patch → sign →
|
||||
priv-app pipeline for Phonesky on `rom-dev01` using AXP `patch-playstore` /
|
||||
apktool; proprietary APKs MUST NOT be committed to Git.
|
||||
- **FR-005**: Do not install FakeStore (or conflicting Companion) alongside
|
||||
patched Phonesky.
|
||||
- **FR-006**: Record microG Self-Check results on LAB (pass/fail per item) after
|
||||
flash; attribute spoofing-related failures to `005`.
|
||||
- **FR-007**: Keep Magisk and KernelSU out of `004` builds (root arrives in
|
||||
`007`; banking baseline rootless in `006`).
|
||||
- **FR-008**: Flash and validate on LAB serial `11231JEC207477` only; never
|
||||
GOLDEN `11071JEC203839`.
|
||||
- **FR-009**: Prefer AXP golden packaging behaviour as reference (inventory from
|
||||
`002`); do not blind-copy Magisk modules or ship AXP-signed Play as product.
|
||||
- **FR-010**: Phonesky is signed with a **project-owned** stable keystore under
|
||||
`/srv/rom/secrets/phonesky-signing/` so later patched Builds can update Play.
|
||||
- **FR-011**: microG GmsCore/GsfProxy MUST remain **PRESIGNED** with the
|
||||
official microG signer so they stay updatable from the microG F-Droid
|
||||
repository; document repo setup for LAB Self-Check.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **microG Services Core** — `com.google.android.gms`
|
||||
- **GSF Proxy** — `com.google.android.gsf`
|
||||
- **Patched Phonesky** — `com.android.vending` (external proprietary input)
|
||||
- **LAB** — Pixel 4a `11231JEC207477` (Android 16 / LOS 23.2 target)
|
||||
- **GOLDEN** — AXP Pro Android 15 reference (read-only)
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: LAB build includes microG + GSF + patched Phonesky packages with
|
||||
correct package names.
|
||||
- **SC-002**: microG Self-Check evidence captured; packaging failures = 0; any
|
||||
remaining failures mapped to `005` or explicitly accepted.
|
||||
- **SC-003**: Phonesky opens on LAB; Git contains no proprietary Play APK.
|
||||
- **SC-004**: Runbook exists such that a clean `rom-dev01` path can rebuild the
|
||||
same packaging layout.
|
||||
- **SC-005**: No Magisk/KSU in the `004` validation build.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- `003` vanilla baseline remains the parent tree; `004` adds packaging/patches
|
||||
on top without unrelated hardening.
|
||||
- LineageOS 23.2 microG-oriented spoofing hooks may already exist; full
|
||||
restricted spoofing policy is `005`.
|
||||
- `002` / GOLDEN inventory supplies reference behaviour and permission
|
||||
patterns only — not version pins for microG or Play.
|
||||
- Phonesky binary is obtained outside Git via latest Play APK + AXP
|
||||
`patch-playstore` (apktool) + project signing keys on `rom-dev01`.
|
||||
- Official microG release APKs share the signer used by the microG F-Droid
|
||||
repo, enabling same-package updates without re-signing.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Signature spoofing implementation beyond using what LOS already provides
|
||||
(`005`)
|
||||
- Insular / banking hard-gates (`006`)
|
||||
- KernelSU (`007`)
|
||||
- Release signing / AVB relock (`011`)
|
||||
- Flashing or modifying GOLDEN
|
||||
@@ -0,0 +1,94 @@
|
||||
# Tasks: microG + GSF Proxy + patched Phonesky
|
||||
|
||||
**Input**: Design docs from `/specs/004-microg-phonesky-integration/`
|
||||
**Prerequisites**: `003` gate (`docs/003-gate-handoff.md`)
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
- [x] T001 Create host dirs `/srv/rom/prebuilts/{microg,phonesky}/` and
|
||||
`/srv/rom/artifacts/004-microg/` on `rom-dev01` (android-build writable)
|
||||
- [x] T002 [P] Add `docs/004-phonesky-runbook.md` (obtain → place APKs → versions
|
||||
file → no Git) in meta repo
|
||||
- [x] T003 [P] Add `docs/004-lab-selfcheck.md` stub (Self-Check table + `005`
|
||||
attribution) in meta repo
|
||||
|
||||
## Phase 2: Foundational
|
||||
|
||||
- [x] T004 Stage **latest** microG GmsCore + GsfProxy APKs into
|
||||
`/srv/rom/prebuilts/microg/` + `VERSIONS.txt` (URLs/hashes;
|
||||
`PRESIGNED` for F-Droid updates) — currently `v0.3.16.252432` /
|
||||
GsfProxy `v0.1.0` (GitHub latest as of 2026-09-14)
|
||||
- [x] T005 Obtain **latest** official Play Store (apkmd), patch with AXP
|
||||
`patch-playstore` + apktool, sign with project JKS under
|
||||
`/srv/rom/secrets/phonesky-signing/`; stage APK + AXP permission XMLs
|
||||
into `/srv/rom/prebuilts/phonesky/` + `VERSIONS.txt`
|
||||
*(Play **52.9.22-24**, not AXP archive)*
|
||||
- [x] T006 Add LOS product/vendor makefile include that packages the three APKs
|
||||
as system/priv-app **without FakeStore** (`vendor/sunfish-a16/` on host tree)
|
||||
- [x] T007 Wire include into `lineage_sunfish` product so `mka bacon` picks it up
|
||||
|
||||
## Phase 3: User Story 1 — microG Self-Check (P1)
|
||||
|
||||
**Goal**: GmsCore + GsfProxy on LAB; Self-Check evidence
|
||||
**Independent test**: packages present; Self-Check screenshots
|
||||
|
||||
- [x] T008 [US1] Build `004` image (`mka bacon -j8`); log under
|
||||
`/srv/rom/logs/004-build/` — **superseded by `005` T020 bacon**
|
||||
(`bacon-20260915T103756Z.log`)
|
||||
- [x] T009 [US1] Flash LAB only (`11231JEC207477`) per quickstart —
|
||||
**superseded by `005` T022**
|
||||
- [x] T010 [US1] Verify `pm path` for `com.google.android.gms` and
|
||||
`com.google.android.gsf`; fill `docs/004-lab-selfcheck.md` —
|
||||
**done via `005` US6** (2026-09-15)
|
||||
|
||||
## Phase 4: User Story 2 — Patched Phonesky (P1)
|
||||
|
||||
**Goal**: priv-app Phonesky with XMLs; Play launches
|
||||
**Independent test**: `pm path com.android.vending`; app opens
|
||||
|
||||
- [x] T011 [US2] Confirm privapp-permissions XMLs installed on device
|
||||
(`/etc/permissions` or equivalent) — **covered by `005` packaging**
|
||||
- [x] T012 [US2] Launch Play Store on LAB; record result — **pass after
|
||||
`005` spoof + exact-alarm** (was blocked → `005`, now closed)
|
||||
- [x] T013 [US2] Confirm Git/meta repo contains **no** Phonesky APK bytes
|
||||
|
||||
## Phase 5: User Story 3 — No FakeStore (P2)
|
||||
|
||||
- [x] T014 [US3] `pm list packages` shows no FakeStore; document in self-check
|
||||
— **`docs/004-lab-selfcheck.md` 2026-09-15**
|
||||
|
||||
## Phase 6: User Story 4 — Reproducible pipeline (P2)
|
||||
|
||||
- [x] T015 [US4] Finalize runbook with exact copy commands from AXP archive +
|
||||
microG download pins — **`docs/004-phonesky-runbook.md` + `005` runbook**
|
||||
- [x] T016 [US4] Document FR-010 signing strategy (project JKS under
|
||||
`/srv/rom/secrets/phonesky-signing/`; GmsCore stays PRESIGNED)
|
||||
|
||||
## Phase 7: Polish
|
||||
|
||||
- [x] T017 Collect artifacts: zip SHA-256, `VERSIONS.txt` copies, Self-Check
|
||||
evidence → **`005` artifacts `20260915-bacon` + `20260915-us6-validation`**
|
||||
- [x] T018 Update `docs/axp-pro-parity.md` rows microG/Phonesky status —
|
||||
**done in `005` T027**
|
||||
- [x] T019 Handoff note: spoofing done in `005`; next `006` banking rootless;
|
||||
no Magisk/KSU in this build
|
||||
|
||||
## Dependencies
|
||||
|
||||
- T001–T003 before staging
|
||||
- T004–T007 before build
|
||||
- T008–T010 (US1) before claiming microG done
|
||||
- T011–T013 (US2) can overlap validation with US1 after same flash
|
||||
- T014 after flash
|
||||
- T015–T016 can refine docs in parallel with builds
|
||||
- T017–T019 after validation
|
||||
|
||||
## MVP
|
||||
|
||||
T001–T012: packages on LAB + Self-Check notes + Play launch attempt.
|
||||
|
||||
## Parallel opportunities
|
||||
|
||||
- T002/T003 with T001
|
||||
- T004/T005 in parallel
|
||||
- Doc polish T015/T016 while T008 builds
|
||||
@@ -0,0 +1,39 @@
|
||||
# Specification Quality Checklist: Restricted native signature spoofing
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-09-15
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Oracle path and package names appear as acceptance identifiers (required for
|
||||
LAB/GOLDEN verification); patch file paths belong in `/speckit-plan`, not here.
|
||||
- Checklist validated 2026-09-15 after initial draft — ready for `/speckit-plan`.
|
||||
- Spec updated same day with **First working stack** (US6, FR-010/011, SC-007/008):
|
||||
folds `004` packaging leftovers + BeaconDB location into this phase; keeps
|
||||
`006`/`007` out. Re-validated for plan. Plan artifacts generated 2026-09-15.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Contract: Spoofing surface (LAB / user-visible)
|
||||
|
||||
## Settings
|
||||
|
||||
| Interface | Contract |
|
||||
|-----------|----------|
|
||||
| Secure setting | `allow_signature_fake` ∈ {`null`/`0`, `1`} |
|
||||
| Readback | `adb shell settings get secure allow_signature_fake` |
|
||||
| UI | Developer Options exposes enable/disable; OFF disables effect of grants |
|
||||
|
||||
## Permission
|
||||
|
||||
| Interface | Contract |
|
||||
|-----------|----------|
|
||||
| Permission name | `android.permission.FAKE_PACKAGE_SIGNATURE` |
|
||||
| `pm list permissions` | Permission is listed (not “Unknown permission”) |
|
||||
| Grant | Visible in `dumpsys package <pkg>` for authorized packages when user granted |
|
||||
|
||||
## PackageManager behaviour
|
||||
|
||||
When **toggle ON** and package **has grant** and **has** `meta-data fake-signature`
|
||||
(or microG’s equivalent spoof path):
|
||||
|
||||
- Callers using legacy signature APIs and signing-certificate APIs MUST observe
|
||||
the faked Google identity for that package (sufficient for microG Self-Check
|
||||
“correct signature” and Play OAuth registration checks).
|
||||
|
||||
When **toggle OFF**:
|
||||
|
||||
- Effective spoofing MUST NOT occur (silent deny).
|
||||
|
||||
## Allow-list
|
||||
|
||||
| Package | Required |
|
||||
|---------|----------|
|
||||
| `com.google.android.gms` | yes |
|
||||
| `com.android.vending` | yes |
|
||||
| Other packages | denied unless explicitly added later under project policy |
|
||||
|
||||
## First-stack package registration
|
||||
|
||||
| Package | `pm path` expectation |
|
||||
|---------|----------------------|
|
||||
| `com.google.android.gms` | system_ext app path |
|
||||
| `com.google.android.gsf` | system_ext app path |
|
||||
| `com.android.vending` | system priv-app Phonesky path |
|
||||
|
||||
PRESIGNED APKs in the shipped image MUST verify with APK Signature Scheme v2/v3
|
||||
(no post-sign strip).
|
||||
|
||||
## Location (documentation contract)
|
||||
|
||||
Quickstart MUST specify:
|
||||
|
||||
1. Open microG → Location
|
||||
2. Enable network/Wi-Fi location as required by UI
|
||||
3. Set service URL to BeaconDB (or documented successor), not MLS
|
||||
|
||||
No requirement to install UnifiedNlp backend packages.
|
||||
@@ -0,0 +1,70 @@
|
||||
# Data model: 005 spoofing + first-stack entities
|
||||
|
||||
## GlobalSpoofingToggle
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| Setting key | `settings secure allow_signature_fake` (AXP/GOLDEN) |
|
||||
| Values | `0` / unset = OFF; `1` = ON |
|
||||
| Default | OFF |
|
||||
| UI | Developer Options → Signature spoofing support → Allow signature spoofing |
|
||||
| Effect when OFF | Prior per-app grants ignored (silent deny) |
|
||||
|
||||
## SpoofingPermission
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| Name | `android.permission.FAKE_PACKAGE_SIGNATURE` |
|
||||
| Protection | dangerous (user-grantable), as on GOLDEN |
|
||||
| Grant state | Per package / per user; GOLDEN uses `USER_SET` for gms + vending |
|
||||
| Revoke UI | App permissions → Spoof package signature (AXP strings) |
|
||||
|
||||
## AuthorizedPackage
|
||||
|
||||
| Package | Signer identity | Notes |
|
||||
|---------|-----------------|-------|
|
||||
| `com.google.android.gms` | Official microG PRESIGNED | System_ext app; F-Droid updates |
|
||||
| `com.android.vending` | Project Phonesky JKS | System priv-app; `fake-signature` meta-data |
|
||||
|
||||
Extension of this set requires constitution-aligned review (not open allow-all).
|
||||
|
||||
## FakeSignatureMetadata
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| APK meta-data name | `fake-signature` |
|
||||
| Value | Hex-encoded Google platform certificate (injected by AXP `patch-playstore`) |
|
||||
| Consumer | PackageManager spoofing path when permission granted + toggle ON |
|
||||
|
||||
## PackagingArtifacts (first-stack ship)
|
||||
|
||||
| Artifact | Rule |
|
||||
|----------|------|
|
||||
| GmsCore / Gsf / Phonesky APKs | PRESIGNED install without zip-realign strip (`REPLACE_PREBUILT`) |
|
||||
| Phonesky privapp XML | Includes FAKE_PACKAGE + A16 FGS / exact-alarm / Play 52 extras; digest = **our** cert |
|
||||
| Default-permissions / sysconfig | Align with GOLDEN `er_*` intent (power-save, app-link) as needed |
|
||||
|
||||
## LocationConfig (validation, not a package)
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| Provider | microG built-in network location (0.3.x) |
|
||||
| Endpoint | Ichnaea-compatible URL (BeaconDB: `https://api.beacondb.net`) |
|
||||
| Non-goals | UnifiedNlp backend APKs; Mozilla MLS |
|
||||
|
||||
## State transitions
|
||||
|
||||
```text
|
||||
[Toggle OFF] --enable in Dev Options--> [Toggle ON]
|
||||
| |
|
||||
v v
|
||||
spoof denied prompts/grants for
|
||||
for all apps authorized packages
|
||||
|
|
||||
v
|
||||
[Permission granted]
|
||||
|
|
||||
v
|
||||
PackageInfo signatures + signingInfo
|
||||
present Google identity to callers
|
||||
```
|
||||
@@ -0,0 +1,98 @@
|
||||
# Implementation Plan: Restricted native signature spoofing
|
||||
|
||||
**Branch**: `005-restricted-signature-spoofing` | **Date**: 2026-09-15 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/005-restricted-signature-spoofing/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver the **first working Google-compat stack on LAB**: finish `004` packaging
|
||||
gates (PRESIGNED replace + Play FGS privapp), add **AXP/EXTENDROM-style
|
||||
restricted signature spoofing** (Developer Options `allow_signature_fake` +
|
||||
`FAKE_PACKAGE_SIGNATURE` + allow-list for microG + Phonesky), validate Play auth
|
||||
/ Self-Check, and document **modern** microG location (BeaconDB). Do **not**
|
||||
pull `006` banking or `007` root into this phase.
|
||||
|
||||
Primary technical approach: attribute patches from
|
||||
[EXTENDROM_SIGNATURE_SPOOFING](https://github.com/sfX-android/android_vendor_extendrom/wiki/EXTENDROM_SIGNATURE_SPOOFING)
|
||||
(A15 proven on GOLDEN) and port to **Android 16 / LOS 23.2**, ensuring both
|
||||
legacy `PackageInfo.signatures` and modern `signingInfo` are spoofed.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Android frameworks Java/Kotlin patches; Settings overlays;
|
||||
`Android.mk` / product makefiles; bash runbooks on `rom-dev01`
|
||||
**Primary Dependencies**: LOS 23.2 tree; EXTENDROM/AXP sigspoof patches (A15 →
|
||||
A16 port); microG 0.3.x; project-signed Phonesky; GOLDEN 2026-09-15 capture
|
||||
**Storage**: Host `/srv/rom/` prebuilts + secrets; meta-repo `vendor/sunfish-a16/`
|
||||
**Testing**: LAB flash only; `settings`/`pm`/`dumpsys`; microG Self-Check;
|
||||
Play login logcat; optional BeaconDB location smoke
|
||||
**Target Platform**: Pixel 4a LAB `11231JEC207477`; Android 16 / LOS 23.2
|
||||
**Project Type**: Android ROM frameworks + Settings + packaging overlay
|
||||
**Performance Goals**: N/A (correctness / compatibility)
|
||||
**Constraints**: LAB only; no GOLDEN modify; no Magisk/KSU; restricted allow-list;
|
||||
attributable patches; no proprietary APKs in Git
|
||||
**Scale/Scope**: frameworks/base (+ services) spoofing; Settings Developer
|
||||
Options; privapp/default/sysconfig XML updates; one bacon + LAB flash; docs
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| LAB only; never GOLDEN | pass |
|
||||
| Spoofing native, restricted, auditable; no LSPosed | pass (FR-003/006) |
|
||||
| Prefer package/signer allow-list over open fake-signature | pass |
|
||||
| Works without optional root | pass (FR-006, US5) |
|
||||
| Prefer AXP/EXTENDROM behaviour; A16 port if needed | pass |
|
||||
| No proprietary APKs in Git | pass |
|
||||
| Small attributable changes | pass (patch series from EXTENDROM/AXP) |
|
||||
| Do not invent `006`/`007` into this feature | pass (spec Out of Scope) |
|
||||
|
||||
**Post-design**: unchanged — design stays spoofing + first-stack ship gates.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/005-restricted-signature-spoofing/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
│ └── spoofing-surface.md
|
||||
└── tasks.md # via /speckit-tasks (not this command)
|
||||
```
|
||||
|
||||
### Host + tree
|
||||
|
||||
```text
|
||||
# Meta repo
|
||||
vendor/sunfish-a16/ # packaging (REPLACE, privapp XML, gms.mk)
|
||||
docs/a15-a16-delta.md
|
||||
docs/004-*.md # packaging/selfcheck (update for BeaconDB)
|
||||
.local-artifacts/002-golden/20260915-spoofing-phonesky/ # oracle
|
||||
|
||||
# rom-dev01
|
||||
/srv/rom/src/lineage/frameworks/base/ # spoofing patches
|
||||
/srv/rom/src/lineage/packages/apps/Settings/ # Developer Options toggle
|
||||
/srv/rom/references/… or vendor/extendrom/ # patch source (checkout as needed)
|
||||
/srv/rom/artifacts/005-…/ # validation zip + evidence
|
||||
```
|
||||
|
||||
**Structure Decision**: Continue `vendor/sunfish-a16` packaging overlay; apply
|
||||
spoofing as attributable patch series under the LOS tree on `rom-dev01` (not a
|
||||
megapatch in Git). Meta-repo holds vendor stubs, docs, and specs only.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why needed | Simpler alternative rejected because |
|
||||
|-----------|------------|--------------------------------------|
|
||||
| Frameworks patches | LOS 23.2 has no FAKE_PACKAGE | Magisk/LSPosed forbidden by constitution |
|
||||
|
||||
## Phase 0 / Phase 1
|
||||
|
||||
See `research.md`, `data-model.md`, `contracts/spoofing-surface.md`, `quickstart.md`.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Quickstart: 005 first working stack (LAB only)
|
||||
|
||||
**Device**: LAB `11231JEC207477` — never GOLDEN `11071JEC203839`
|
||||
|
||||
## Goal
|
||||
|
||||
One flash proves: microG + patched Play + restricted spoofing + modern location
|
||||
docs. Not banking (`006`), not root (`007`).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Artifact zip from `005` bacon (includes `REPLACE_PREBUILT` + updated privapp)
|
||||
- Laptop `adb`/`fastboot`; hashes verified
|
||||
- Oracle notes (optional): `.local-artifacts/002-golden/20260915-spoofing-phonesky/README.md`
|
||||
|
||||
## Flash
|
||||
|
||||
Follow `docs/003-flash-lab.md` pattern with the **005** zip (dtbo → boot/recovery
|
||||
→ format if needed → sideload). Say **No** to additional packages.
|
||||
|
||||
## After first boot
|
||||
|
||||
```bash
|
||||
SERIAL=11231JEC207477
|
||||
adb -s "$SERIAL" shell getprop ro.lineage.version
|
||||
adb -s "$SERIAL" shell pm path com.google.android.gms
|
||||
adb -s "$SERIAL" shell pm path com.google.android.gsf
|
||||
adb -s "$SERIAL" shell pm path com.android.vending
|
||||
# expect all three present — no remount push
|
||||
```
|
||||
|
||||
## Spoofing
|
||||
|
||||
1. Enable **Developer options**
|
||||
2. Enable **Allow signature spoofing** (`settings get secure allow_signature_fake` → `1`)
|
||||
3. Open **microG Settings → Self-Check**
|
||||
4. Grant spoofing for GmsCore and Play when prompted (or App info → permissions)
|
||||
5. Confirm Self-Check **correct signature** for GmsCore and Play/Companion
|
||||
|
||||
```bash
|
||||
adb -s "$SERIAL" shell settings get secure allow_signature_fake
|
||||
adb -s "$SERIAL" shell dumpsys package com.google.android.gms | grep FAKE_PACKAGE_SIGNATURE
|
||||
adb -s "$SERIAL" shell dumpsys package com.android.vending | grep FAKE_PACKAGE_SIGNATURE
|
||||
```
|
||||
|
||||
## Play auth
|
||||
|
||||
1. Open Play Store; sign in
|
||||
2. Confirm UI stays up (no FGS crash loop)
|
||||
3. Optional logcat gate: **no** `UNREGISTERED_ON_API_CONSOLE` for Phonesky
|
||||
|
||||
In-app Play self-update may still fail (AXP-like) — acceptable.
|
||||
|
||||
## Modern location
|
||||
|
||||
1. microG Settings → Location
|
||||
2. Enable network location as shown
|
||||
3. Configure service URL: `https://api.beacondb.net` (BeaconDB; MLS is dead)
|
||||
4. Do **not** install Déjà Vu / Nominatim NLP backend APKs
|
||||
|
||||
## Pass criteria (SC)
|
||||
|
||||
- [x] Toggle + `allow_signature_fake=1` *(LAB 2026-09-15)*
|
||||
- [x] Self-Check correct signature for gms + vending
|
||||
- [x] Play sign-in without API-console fingerprint error
|
||||
- [x] All three packages from zip without remount *(gms/gsf system; vending upgraded in-place for exact-alarm — next bacon restores system path)*
|
||||
- [x] BeaconDB steps recorded; no UnifiedNlp backends required
|
||||
- [x] No Magisk/KSU on the build
|
||||
|
||||
## Failure
|
||||
|
||||
Capture logcat (`vending`, `GmsAuthenticator`, `SelfCheck`, `PackageManager`).
|
||||
Do not flash GOLDEN. Packaging-only regressions → fix under vendor overlay;
|
||||
spoofing regressions → frameworks/Settings patches.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Research: 005 restricted signature spoofing
|
||||
|
||||
## Decision: First working stack = `004` leftovers + spoofing + modern location
|
||||
|
||||
**Decision**: Ship one LAB validation build that includes (1) unfinished `004`
|
||||
packaging fixes, (2) restricted spoofing, (3) BeaconDB location docs — and
|
||||
**exclude** `006` banking and `007` root.
|
||||
|
||||
**Rationale**: Owner: first phase that must work is microG + patched Play +
|
||||
spoofing. Banking/root are later regressions.
|
||||
|
||||
**Alternatives considered**: Separate tiny `004b` rebuild only — rejected;
|
||||
wastes a flash cycle before spoofing lands. Pulling `006` early — rejected;
|
||||
blocks focus.
|
||||
|
||||
## Decision: Spoofing implementation source = EXTENDROM / AXP (port to A16)
|
||||
|
||||
**Decision**: Use [EXTENDROM_SIGNATURE_SPOOFING](https://github.com/sfX-android/android_vendor_extendrom/wiki/EXTENDROM_SIGNATURE_SPOOFING)
|
||||
as the attributable primary source (matches GOLDEN behaviour:
|
||||
`allow_signature_fake`, Developer Options, per-app `FAKE_PACKAGE_SIGNATURE`).
|
||||
Port patches from the closest supported Android line (**A15** is STABLE/tested;
|
||||
GOLDEN is A15) onto **A16 / LOS 23.2**.
|
||||
|
||||
**Rationale**: Stock LOS 23.2 tree on `rom-dev01` has **no**
|
||||
`FAKE_PACKAGE_SIGNATURE` / `allow_signature_fake` (inventory 2026-09-15). AXP
|
||||
GOLDEN proves the UX and setting key. Old `android_signature_spoofing` repo is
|
||||
obsolete per upstream.
|
||||
|
||||
**Alternatives considered**:
|
||||
|
||||
| Option | Why not |
|
||||
|--------|---------|
|
||||
| lineageos4microg unrestricted spoof | Constitution forbids open spoofing |
|
||||
| Magisk / LSPosed FakeGApps | Forbidden; rootless Compatibility MVP |
|
||||
| Wait for LOS to grow A16 EXTENDROM dir | Blocks first stack; we port ourselves |
|
||||
|
||||
**A16 note**: EXTENDROM wiki table lists A15, not A16. Expect conflict resolution
|
||||
(`repo diff` / split patches) per EXTENDROM porting guide. Record deltas in
|
||||
`docs/a15-a16-delta.md`.
|
||||
|
||||
## Decision: Must spoof `signingInfo`, not only `signatures[]`
|
||||
|
||||
**Decision**: Implementation MUST spoof both legacy `PackageInfo.signatures` and
|
||||
modern `PackageInfo.signingInfo` (GET_SIGNING_CERTIFICATES).
|
||||
|
||||
**Rationale**: microG #2680 / EXTENDROM #48 — Google/Play check `signingInfo` on
|
||||
modern Android; Self-Check “correct signature” fails if only legacy arrays are
|
||||
faked. LOS Gerrit has A13–A15 fixes; ensure A16 port includes equivalent.
|
||||
|
||||
## Decision: Allow-list = microG GmsCore + project Phonesky
|
||||
|
||||
**Decision**: Effective spoofing limited to:
|
||||
|
||||
- `com.google.android.gms` — official microG signer (`73aaa390…` short on GOLDEN)
|
||||
- `com.android.vending` — project Phonesky JKS
|
||||
SHA-256 digest
|
||||
`31:31:86:CB:7D:F2:D4:01:33:72:12:07:B7:29:73:E8:52:F6:1C:87:67:C3:21:E5:C7:50:39:01:1B:83:BD:56`
|
||||
|
||||
Privapp/default XMLs that bind by cert digest MUST use **our** digest (not
|
||||
AXP’s `00:5C:98:05:…`).
|
||||
|
||||
**Rationale**: Constitution + GOLDEN grants; AXP `er_*` XMLs bind Phonesky by
|
||||
digest.
|
||||
|
||||
## Decision: Global toggle default OFF
|
||||
|
||||
**Decision**: `allow_signature_fake` defaults to disabled; user enables in
|
||||
Developer Options (AXP setup guide).
|
||||
|
||||
**Rationale**: Matches oracle docs and reduces surprise attack surface.
|
||||
|
||||
## Decision: `004` packaging leftovers are a `005` ship gate
|
||||
|
||||
**Decision**: Before declaring `005` done, the flashable zip MUST include:
|
||||
|
||||
1. `LOCAL_REPLACE_PREBUILT_APK_INSTALLED` for GmsCore/Gsf/Phonesky (already in
|
||||
working-tree `vendor/sunfish-a16/Android.mk`)
|
||||
2. Phonesky privapp extras for Play 52 / A16 FGS:
|
||||
`FOREGROUND_SERVICE_SYSTEM_EXEMPTED`, `SCHEDULE_EXACT_ALARM` /
|
||||
`USE_EXACT_ALARM`, plus prior grammatical/status-bar entries
|
||||
|
||||
**Rationale**: Measured LAB failures — PRESIGNED strip → no `pm path`; missing
|
||||
FGS allowlist → VpaService/DownloadService crash. Remount pushes are not the
|
||||
shipped artifact.
|
||||
|
||||
## Decision: Modern location = BeaconDB (not UnifiedNlp backends)
|
||||
|
||||
**Decision**: Document configuring microG Location to use an Ichnaea-compatible
|
||||
URL (`https://api.beacondb.net` or documented successor). Do **not** package
|
||||
Déjà Vu / Nominatim NLP / MLS apps.
|
||||
|
||||
**Rationale**: microG 0.3.x dropped UnifiedNlp backends; MLS retired (2025);
|
||||
GOLDEN also has no NLP backend packages. Owner wants modern stack.
|
||||
|
||||
**Alternatives considered**: Ship UnifiedNlp backends — rejected (obsolete for
|
||||
0.3.x primary path).
|
||||
|
||||
## Decision: Out of scope remains `006`/`007`
|
||||
|
||||
**Decision**: No Insular/banking hard-gates; no KSU/SusFS in this feature’s
|
||||
acceptance.
|
||||
|
||||
**Rationale**: Owner confirmation 2026-09-15 — first phase is microG + Play +
|
||||
spoofing only.
|
||||
@@ -0,0 +1,277 @@
|
||||
# Feature Specification: Restricted native signature spoofing
|
||||
|
||||
**Feature Branch**: `005-restricted-signature-spoofing`
|
||||
**Created**: 2026-09-15
|
||||
**Status**: Draft
|
||||
**Input**: Advance spoofing after `004` packaging: LAB Play/microG Self-Check and
|
||||
Google auth fail without AXP-style restricted signature spoofing. GOLDEN capture
|
||||
2026-09-15 is the behavioural oracle. Prefer modern LOS 23.2 / A16 path to the
|
||||
**same end state** as AXP (not Magisk modules).
|
||||
|
||||
## First working stack (this phase — before `006`/`007`)
|
||||
|
||||
This feature closes the **first usable Google-compat stack on LAB**:
|
||||
|
||||
| Must work in this phase | Owner |
|
||||
|-------------------------|--------|
|
||||
| Official microG + GSF (PRESIGNED, F-Droid-updatable) | `004` packaging + `005` ship |
|
||||
| Patched Phonesky priv-app (project-signed, disable/enable OK) | `004` + `005` ship |
|
||||
| Restricted spoofing (Developer Options + grants) | **`005` core** |
|
||||
| Self-Check correct signature + Play auth (no API-console mismatch) | **`005`** |
|
||||
| Modern network location (BeaconDB / Ichnaea-compatible URL; not Déjà Vu NLP) | `005` validation / docs |
|
||||
| `004` packaging leftovers that block a clean flashable zip | **`005` ship gate** (`REPLACE_PREBUILT`, Play FGS privapp) |
|
||||
|
||||
**Explicitly later (do not pull forward):**
|
||||
|
||||
- `006` — Insular / Yuh / Swissquote banking hard-gates
|
||||
- `007` — KernelSU-Next / SusFS / root hide
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Developer Options master switch (Priority: P1)
|
||||
|
||||
As the developer (and later daily-driver user), I can enable **Allow signature
|
||||
spoofing** under Developer Options. When off, spoofing has no effect even if
|
||||
per-app grants remain. When on, authorized apps may use spoofing after grant.
|
||||
|
||||
**Why this priority**: Matches GOLDEN/AXP (`settings secure allow_signature_fake`)
|
||||
and constitution (not unrestricted platform fake-signature).
|
||||
|
||||
**Independent Test**: On LAB build with `005`, toggle the setting; read
|
||||
`settings get secure allow_signature_fake` (0/1); confirm UI strings exist.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a `005` build on LAB, **When** Developer Options is opened,
|
||||
**Then** a **Signature spoofing support** category exposes **Allow signature
|
||||
spoofing** (AXP-equivalent UX).
|
||||
2. **Given** the toggle is OFF, **When** an app holds a prior spoofing grant,
|
||||
**Then** spoofing has **no effect** (same as AXP documented behaviour).
|
||||
3. **Given** the toggle is ON, **When** `settings get secure allow_signature_fake`
|
||||
is read, **Then** the value is `1`.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - microG + Phonesky Self-Check signatures (Priority: P1)
|
||||
|
||||
As the developer, with global spoofing ON and spoofing permission granted to
|
||||
microG GmsCore and patched Phonesky, microG Self-Check marks **correct
|
||||
signature** for both `com.google.android.gms` and `com.android.vending`
|
||||
(Companion/Play Store line), not only “installed”.
|
||||
|
||||
**Why this priority**: Unblocks the `004` gap that packaging alone cannot fix;
|
||||
required before Play OAuth works.
|
||||
|
||||
**Independent Test**: LAB only; no GOLDEN modification; screenshots/log of
|
||||
Self-Check before/after grants.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `004` packages present and global spoofing ON, **When**
|
||||
`FAKE_PACKAGE_SIGNATURE` is granted to GmsCore and Phonesky, **Then**
|
||||
Self-Check shows positive **correct signature** for both.
|
||||
2. **Given** Self-Check, **When** the user taps the resolution for correct
|
||||
signature on Play/microG, **Then** a grant path exists (system permission UI
|
||||
or equivalent) — not a missing activity / unknown permission.
|
||||
3. **Given** global spoofing OFF, **When** Self-Check runs, **Then** correct
|
||||
signature checks fail even if packages are installed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Play login / auth without API-console mismatch (Priority: P1)
|
||||
|
||||
As the developer, after spoofing is enabled and granted for Phonesky, Google
|
||||
account sign-in in Play no longer fails with
|
||||
`UNREGISTERED_ON_API_CONSOLE` / “SHA-1 certificate fingerprint” mismatch caused
|
||||
by presenting the project signing key as the Play identity.
|
||||
|
||||
**Why this priority**: Owner-observed LAB failure; AXP GOLDEN works with spoofing.
|
||||
|
||||
**Independent Test**: LAB logcat during Play sign-in; compare to pre-`005`
|
||||
failure mode.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** spoofing ON + Phonesky granted, **When** signing into Play,
|
||||
**Then** auth token acquisition does not fail with `UNREGISTERED_ON_API_CONSOLE`
|
||||
due to project cert fingerprint.
|
||||
2. **Given** Play update prompts that AXP intentionally blocks, **When** the
|
||||
user tries in-app self-update, **Then** failure remains acceptable (out of
|
||||
scope to enable stock Play self-update).
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Restricted allow-list only (Priority: P1)
|
||||
|
||||
As the project owner, spoofing is **not** a general capability for arbitrary
|
||||
apps. Only explicitly authorized packages/signers may obtain effective spoofing
|
||||
(at minimum official microG GmsCore and project-signed patched Phonesky).
|
||||
|
||||
**Why this priority**: Constitution: native, restricted, auditable; no LSPosed.
|
||||
|
||||
**Independent Test**: Attempt spoofing from a third-party test APK that requests
|
||||
`FAKE_PACKAGE_SIGNATURE` without being allow-listed → denied.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** global spoofing ON, **When** a non-authorized app requests
|
||||
spoofing, **Then** it cannot effectively impersonate Google/platform
|
||||
signatures.
|
||||
2. **Given** documentation, **When** reviewed, **Then** the authorized set and
|
||||
how to extend it are written (for future packages if needed).
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - Survives without root (Priority: P2)
|
||||
|
||||
As the developer, microG and Phonesky spoofing keep working when optional root /
|
||||
Zygisk-style functionality is unavailable (Compatibility MVP is rootless).
|
||||
|
||||
**Why this priority**: Constitution Compatibility MVP ends at `006` rootless.
|
||||
|
||||
**Independent Test**: LAB build without Magisk/KSU; spoofing + Self-Check still
|
||||
pass.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** no Magisk/KSU on the `005` validation build, **When** spoofing is
|
||||
configured, **Then** Self-Check signature lines and basic Play auth path
|
||||
still succeed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 6 - First working stack ship gate (Priority: P1)
|
||||
|
||||
As the developer, one LAB flash of the `005` validation build includes a
|
||||
**complete** first stack: packaging fixes from `004` that never landed in a
|
||||
clean zip, spoofing, and documented modern location setup — without waiting for
|
||||
banking (`006`) or root (`007`).
|
||||
|
||||
**Why this priority**: Owner: this phase must work before later features.
|
||||
|
||||
**Independent Test**: Single zip flash on LAB; follow quickstart; no Magisk/KSU.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the `005` artifact zip, **When** flashed to LAB, **Then** Phonesky
|
||||
registers (`pm path`) without remount hacks; APK signatures verify (no
|
||||
PRESIGNED strip).
|
||||
2. **Given** that build, **When** spoofing is configured per quickstart,
|
||||
**Then** Self-Check signature lines and Play auth meet SC-003/SC-004.
|
||||
3. **Given** microG Location settings, **When** configured for a modern
|
||||
Ichnaea-compatible endpoint (BeaconDB), **Then** the procedure is documented
|
||||
and does not depend on legacy UnifiedNlp backend APKs.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Stock LOS 23.2 tree on `rom-dev01` has **no** `FAKE_PACKAGE_SIGNATURE` /
|
||||
`allow_signature_fake` (inventory 2026-09-15) → must port/adapt from
|
||||
AXP/EXTENDROM patterns, not “enable a hidden LOS flag”.
|
||||
- Phonesky privapp XML on AXP binds permissions to **cert SHA-256 digest**; our
|
||||
project digest differs from AXP’s — XML must use **our** digest.
|
||||
- Play 52.x FGS / privapp extras (`FOREGROUND_SERVICE_SYSTEM_EXEMPTED`, etc.)
|
||||
remain packaging/`004` follow-ups; `005` must not regress them.
|
||||
- Disabling Play via App info remains supported (owner: useful on AXP).
|
||||
- Island/work profile: spoofing grants may need to exist per user — verify at
|
||||
least owner user 0 for P1; note multi-user as follow-up if broken.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: ROM MUST provide a Developer Options control equivalent to AXP
|
||||
**Allow signature spoofing**, persisted as a global setting (GOLDEN:
|
||||
`settings secure allow_signature_fake`).
|
||||
- **FR-002**: ROM MUST define and enforce `android.permission.FAKE_PACKAGE_SIGNATURE`
|
||||
(or AOSP-equivalent restricted spoofing permission) so PackageManager can
|
||||
honour `meta-data fake-signature` for authorized packages when the global
|
||||
toggle is ON and the permission is granted.
|
||||
- **FR-003**: Spoofing MUST be restricted to an explicit allow-list of packages
|
||||
and/or signers; at minimum `com.google.android.gms` (official microG signer)
|
||||
and `com.android.vending` (project Phonesky signer). Unrestricted spoofing is
|
||||
forbidden.
|
||||
- **FR-004**: With toggle ON and grants present, microG Self-Check MUST report
|
||||
positive **correct signature** for GmsCore and Phonesky/Play.
|
||||
- **FR-005**: With toggle ON and Phonesky granted, Play account auth MUST NOT
|
||||
fail with `UNREGISTERED_ON_API_CONSOLE` caused by exposing the project signing
|
||||
certificate as Play’s identity.
|
||||
- **FR-006**: Spoofing MUST NOT depend on Magisk, Zygisk, LSPosed, or other
|
||||
root modules.
|
||||
- **FR-007**: Behaviour and UX SHOULD match GOLDEN/AXP where compatible with
|
||||
Android 16 / LOS 23.2; if the AXP patch set does not apply cleanly, redesign
|
||||
the path to the **same end state** and record deltas in `docs/a15-a16-delta.md`.
|
||||
- **FR-008**: Validation MUST be LAB-only (`11231JEC207477`); GOLDEN remains
|
||||
sample-only.
|
||||
- **FR-009**: Implementation MUST be attributable (source-linked patches /
|
||||
EXTENDROM/AXP/LOS references); no opaque megapatch.
|
||||
|
||||
- **FR-010**: The `005` validation build MUST incorporate outstanding `004`
|
||||
packaging fixes required for a clean flashable image: PRESIGNED APKs installed
|
||||
via replace-prebuilt (no v2/v3 strip), and Phonesky privapp entries needed for
|
||||
Android 16 / Play 52 FGS (e.g. system-exempted foreground service + exact
|
||||
alarm) so Play does not crash on setup/download services.
|
||||
- **FR-011**: First-stack validation MUST document modern microG network
|
||||
location configuration (Ichnaea-compatible service URL such as BeaconDB); MUST
|
||||
NOT require shipping legacy UnifiedNlp backend packages (Déjà Vu, Nominatim
|
||||
NLP apps).
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Global spoofing toggle**: User-facing Developer Options switch; gates all
|
||||
spoofing effect.
|
||||
- **Spoofing permission**: Per-app dangerous/runtime-style permission the user
|
||||
(or approved default path) grants to authorized packages.
|
||||
- **Authorized package set**: microG GmsCore + patched Phonesky (extensible
|
||||
later under constitution rules).
|
||||
- **Oracle capture**: `.local-artifacts/002-golden/20260915-spoofing-phonesky/`
|
||||
(settings, `er_*` XMLs, framework strings, dumpsys grants).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: On LAB, Developer Options exposes the spoofing master switch;
|
||||
`allow_signature_fake` reads `1` when enabled.
|
||||
- **SC-002**: `pm` / permission APIs show `FAKE_PACKAGE_SIGNATURE` defined;
|
||||
grants visible for GmsCore and Phonesky when configured.
|
||||
- **SC-003**: microG Self-Check shows **correct signature** checked for GmsCore
|
||||
and Play/Companion within one configuration session after flash.
|
||||
- **SC-004**: Play sign-in logcat no longer shows `UNREGISTERED_ON_API_CONSOLE`
|
||||
fingerprint mismatch for Phonesky under the spoofed identity.
|
||||
- **SC-005**: A non-allow-listed test app cannot obtain effective Google
|
||||
signature spoofing with the global toggle ON.
|
||||
- **SC-007**: One LAB flash of the `005` zip boots without remount overlays for
|
||||
Phonesky; `apksigner verify` equivalent on-device package is registered; Play
|
||||
does not crash-loop on VpaService/DownloadService for missing FGS privapp
|
||||
allowlist entries.
|
||||
- **SC-008**: Quickstart includes BeaconDB (or successor) location steps;
|
||||
Self-Check / location UI does not depend on empty UnifiedNlp backend lists.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- `004` packaging (PRESIGNED `LOCAL_REPLACE_PREBUILT_APK_INSTALLED`, Phonesky
|
||||
patch with `fake-signature`, privapp XMLs) remains the base; `005` does not
|
||||
replace FakeStore for Play. Unmerged `004` leftovers ship in the same `005`
|
||||
validation build (single first-stack artifact).
|
||||
- Default for the global toggle is **OFF** until the user enables it (AXP
|
||||
“explicitly enable” model), unless plan proves a safer first-boot prompt.
|
||||
- Official microG continues to update via F-Droid same-signer; Phonesky via
|
||||
project JKS.
|
||||
- Primary patch reference: AXP/EXTENDROM signature spoofing + GOLDEN 2026-09-15
|
||||
capture; inventory shows stock LOS 23.2 lacks these hooks. Spoofing MUST also
|
||||
cover modern `PackageInfo.signingInfo` (not only legacy `signatures[]`).
|
||||
- Play self-update remaining broken/blocked is acceptable (AXP parity).
|
||||
- Multi-user/Island spoofing parity is best-effort for P1 (user 0 first).
|
||||
- MLS (Mozilla Location Service) is retired; BeaconDB (or documented successor)
|
||||
is the modern network-location endpoint for microG 0.3.x.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- KernelSU / Magisk / DenyList (`007`)
|
||||
- Banking Insular hard-gates / Yuh / Swissquote (`006`)
|
||||
- Call recording / FLAG_SECURE (`008`/`009`)
|
||||
- Changing Phonesky to Google’s proprietary signer
|
||||
- Unrestricted signature spoofing for all apps
|
||||
- Reintroducing UnifiedNlp backend APKs as the primary location design
|
||||
@@ -0,0 +1,264 @@
|
||||
# Tasks: Restricted native signature spoofing (first working stack)
|
||||
|
||||
**Input**: Design docs from `/specs/005-restricted-signature-spoofing/`
|
||||
**Prerequisites**: `004` packaging on LAB (Phonesky present); GOLDEN oracle
|
||||
`.local-artifacts/002-golden/20260915-spoofing-phonesky/`; constitution spoofing rules
|
||||
|
||||
**Organization**: First working stack = packaging leftovers + spoofing + BeaconDB.
|
||||
**Out of scope**: `006` banking, `007` KSU/root.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete deps)
|
||||
- **[Story]**: US1…US6 from `spec.md`
|
||||
|
||||
## Path conventions
|
||||
|
||||
- Meta repo: `vendor/sunfish-a16/`, `docs/`, `specs/005-…/`
|
||||
- Build host: `/srv/rom/src/lineage/` (frameworks, Settings), `/srv/rom/artifacts/005-…/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
**Purpose**: Patch sources, dirs, delta notes
|
||||
|
||||
- [x] T001 Checkout / mirror EXTENDROM sigspoof sources on `rom-dev01` under
|
||||
`/srv/rom/references/extendrom/` (or sparse clone
|
||||
`sfX-android/android_vendor_extendrom`); record commit in
|
||||
`docs/a15-a16-delta.md`
|
||||
*(2026-09-15: `f129253c…`; also found stock LuK1337 spoof in LOS tree)*
|
||||
- [x] T002 [P] Create `/srv/rom/artifacts/005-spoofing/` and
|
||||
`/srv/rom/logs/005-build/` (android-build writable)
|
||||
- [x] T003 [P] Add `docs/005-spoofing-runbook.md` stub (EXTENDROM port steps,
|
||||
allow-list, LAB-only) in meta repo
|
||||
- [x] T004 [P] Confirm working-tree packaging leftovers present:
|
||||
`vendor/sunfish-a16/Android.mk` has `LOCAL_REPLACE_PREBUILT_APK_INSTALLED`;
|
||||
`vendor/sunfish-a16/permissions/privapp-permissions-com.android.vending.xml`
|
||||
has FGS/exact-alarm + Play 52 entries — sync both to
|
||||
`/srv/rom/src/lineage/vendor/sunfish-a16/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (blocks all stories)
|
||||
|
||||
**Purpose**: A16-portable spoofing patch set + product wiring; no bacon yet
|
||||
|
||||
**⚠️ CRITICAL**: No US validation flash until this phase completes
|
||||
|
||||
- [x] T005 Inventory EXTENDROM A15 patch list vs LOS 23.2 paths; write mapping
|
||||
table in `docs/a15-a16-delta.md` (frameworks/base, services, Settings,
|
||||
overlays)
|
||||
- [x] T006 Apply / port EXTENDROM signature-spoofing patches to
|
||||
`/srv/rom/src/lineage/frameworks/base/` so
|
||||
`android.permission.FAKE_PACKAGE_SIGNATURE` exists and
|
||||
`meta-data fake-signature` is honoured for **both**
|
||||
`PackageInfo.signatures` and `PackageInfo.signingInfo`
|
||||
*(extended LuK1337 path via `apply_005_sigspoof.py`)*
|
||||
- [x] T007 Wire global gate `settings secure allow_signature_fake` in
|
||||
PackageManager path under
|
||||
`/srv/rom/src/lineage/frameworks/base/services/` (silent deny when off)
|
||||
- [x] T008 Restrict effective spoofing to allow-list packages/signers
|
||||
(`com.google.android.gms` official microG; `com.android.vending` project
|
||||
Phonesky digest
|
||||
`31:31:86:CB:7D:F2:D4:01:33:72:12:07:B7:29:73:E8:52:F6:1C:87:67:C3:21:E5:C7:50:39:01:1B:83:BD:56`)
|
||||
— document mechanism in `docs/005-spoofing-runbook.md`
|
||||
- [x] T009 [P] Update Phonesky privapp/default XMLs in
|
||||
`vendor/sunfish-a16/permissions/` to include `FAKE_PACKAGE_SIGNATURE` and
|
||||
bind Phonesky entries to **our** cert SHA-256 digest (not AXP
|
||||
`00:5C:98:…`); sync to host tree
|
||||
*(FAKE_PACKAGE already in privapp; digest enforced in ComputerEngine)*
|
||||
- [ ] T010 [P] Align GmsCore-related default-permissions / sysconfig intent from
|
||||
GOLDEN `er_*` files into `vendor/sunfish-a16/` (power-save / app-link as
|
||||
needed) without inventing GmsCore priv-app
|
||||
|
||||
**Checkpoint**: Foundation ready — bacon is next (US6)
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Developer Options master switch (P1) 🎯 MVP slice
|
||||
|
||||
**Goal**: Toggle **Allow signature spoofing** in Developer Options
|
||||
**Independent test**: UI present; `settings get secure allow_signature_fake` is
|
||||
`1` when ON; OFF disables effect
|
||||
|
||||
- [x] T011 [US1] Port EXTENDROM/AXP Settings Developer Options strings +
|
||||
preference for `allow_signature_fake` into
|
||||
`/srv/rom/src/lineage/packages/apps/Settings/` (or overlay under
|
||||
`vendor/sunfish-a16/`) matching GOLDEN UX
|
||||
(`signature_spoof_category` / Allow signature spoofing)
|
||||
- [ ] T012 [US1] Verify default is OFF; toggling ON/OFF persists across reboot
|
||||
(device proof after US6 flash)
|
||||
|
||||
**Checkpoint**: US1 code landed in tree (validated on device in US6 flash)
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 4 — Restricted allow-list only (P1)
|
||||
|
||||
**Goal**: Non-authorized apps cannot effectively spoof
|
||||
**Independent test**: Third-party test APK requesting FAKE_PACKAGE denied
|
||||
|
||||
- [ ] T013 [US4] Add allow-list enforcement tests/notes in
|
||||
`docs/005-spoofing-runbook.md` (manual LAB procedure + expected deny)
|
||||
- [ ] T014 [US4] Confirm implementation from T008 rejects non-listed packages
|
||||
even with toggle ON (code review + LAB check after flash)
|
||||
|
||||
**Checkpoint**: Policy documented; enforcement in PMS path
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 2 — Self-Check correct signatures (P1)
|
||||
|
||||
**Goal**: microG Self-Check marks correct signature for GmsCore + Phonesky
|
||||
**Independent test**: Self-Check screenshots after grants
|
||||
|
||||
- [ ] T015 [US2] Ensure grant path works (permission UI / Self-Check tap) —
|
||||
no missing `GrantFakeSignaturePermissionActivity` / unknown permission
|
||||
- [ ] T016 [US2] Update `docs/004-lab-selfcheck.md` with spoofing steps and
|
||||
expected green signature rows (post-`005`)
|
||||
|
||||
**Checkpoint**: Self-Check contract ready; device proof in US6
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 3 — Play auth without API-console mismatch (P1)
|
||||
|
||||
**Goal**: Play sign-in without `UNREGISTERED_ON_API_CONSOLE`
|
||||
**Independent test**: logcat during login
|
||||
|
||||
- [ ] T017 [US3] Document auth verification commands in
|
||||
`specs/005-restricted-signature-spoofing/quickstart.md` (already drafted —
|
||||
tighten failure signatures)
|
||||
- [ ] T018 [US3] After flash (US6), capture logcat proving absence of
|
||||
`UNREGISTERED_ON_API_CONSOLE` for Phonesky; store under
|
||||
`/srv/rom/artifacts/005-spoofing/`
|
||||
|
||||
**Checkpoint**: Auth acceptance tied to US6 validation build
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: User Story 5 — Survives without root (P2)
|
||||
|
||||
**Goal**: Spoofing works with no Magisk/KSU
|
||||
**Independent test**: build props / `pm` show no Magisk
|
||||
|
||||
- [ ] T019 [US5] Confirm `005` product makefiles do not pull Magisk/KSU; note in
|
||||
`docs/005-spoofing-runbook.md` and gate handoff
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: User Story 6 — First working stack ship gate (P1)
|
||||
|
||||
**Goal**: One zip = REPLACE packaging + FGS privapp + spoofing; BeaconDB docs
|
||||
**Independent test**: `quickstart.md` end-to-end on LAB
|
||||
|
||||
- [x] T020 [US6] `mka bacon -j8` on `rom-dev01`; log
|
||||
`/srv/rom/logs/005-build/bacon.log`; verify intermediate Phonesky APK
|
||||
`apksigner verify` (v2/v3) under `out/target/product/sunfish/`
|
||||
*(SUCCESS 2026-09-15T14:27Z, 03:49:11; log
|
||||
`bacon-20260915T103756Z.log`; zip SHA256
|
||||
`1f08e00433e073e0b6525eb2539fe9011a291f34604a6917bf1836aecf03e383`;
|
||||
Phonesky v2+v3 OK)*
|
||||
- [x] T021 [US6] Stage zip + imgs + SHA256 + VERSIONS + spoofing notes to
|
||||
`/srv/rom/artifacts/005-spoofing/<date>/` and rsync to
|
||||
`.local-artifacts/005-spoofing/`
|
||||
*(host `…/20260915-bacon/`; laptop got SHA+triage+packaging-check;
|
||||
full zip remains on host)*
|
||||
- [x] T022 [US6] Flash LAB only (`11231JEC207477`); confirm
|
||||
`pm path` for gms/gsf/vending without remount
|
||||
*(gms/gsf `/system_ext/…`; vending from zip then exact-alarm
|
||||
`adb install -r` → `/data/app/…` until next bacon)*
|
||||
- [x] T023 [US6] Enable spoofing toggle; grant FAKE_PACKAGE to gms + vending;
|
||||
Self-Check correct signature green
|
||||
*(`allow_signature_fake=1`; user 0+10 grants; operator Self-Check pass)*
|
||||
- [x] T024 [US6] Play sign-in smoke; confirm no FGS VpaService crash loop; record
|
||||
update-still-blocked as acceptable
|
||||
*(installs OK both profiles after exact-alarm; UNREGISTERED count=0)*
|
||||
- [x] T025 [P] [US6] Document BeaconDB location steps in
|
||||
`docs/004-lab-selfcheck.md` + `quickstart.md` (URL
|
||||
`https://api.beacondb.net`; no UnifiedNlp backends)
|
||||
- [x] T026 [US6] Run full `specs/005-restricted-signature-spoofing/quickstart.md`
|
||||
checklist; tick SC-001…SC-008
|
||||
*(evidence `/srv/rom/artifacts/005-spoofing/20260915-us6-validation/`)*
|
||||
|
||||
**Checkpoint**: First working stack accepted on LAB
|
||||
|
||||
---
|
||||
|
||||
## Phase 9: Polish
|
||||
|
||||
- [x] T027 [P] Update `docs/axp-pro-parity.md` spoofing + microG/Phonesky rows
|
||||
- [x] T028 [P] Finalize `docs/a15-a16-delta.md` with A15→A16 spoofing port notes
|
||||
- [x] T029 Handoff: first stack done; next `006` banking rootless — **no** KSU
|
||||
until after `006`
|
||||
- [x] T030 Mark remaining `004` tasks superseded/closed where `005` US6 covered
|
||||
them (`specs/004-microg-phonesky-integration/tasks.md` notes)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase dependencies
|
||||
|
||||
- Phase 1 → Phase 2 (foundational patches) → US1/US4 code → US2/US3/US5 docs →
|
||||
**US6 build/flash validates everything**
|
||||
- US6 is the integration gate; US1–US5 implementation lands before bacon when
|
||||
possible, device proof in US6
|
||||
|
||||
### User story dependencies
|
||||
|
||||
| Story | Depends on |
|
||||
|-------|------------|
|
||||
| US1 toggle | T005–T007 (+ T011 Settings) |
|
||||
| US4 allow-list | T008 |
|
||||
| US2 Self-Check | T006–T009, US1 toggle |
|
||||
| US3 Play auth | US2 grants working |
|
||||
| US5 no root | Product wiring (Phase 2) |
|
||||
| US6 ship | All above + T004 packaging |
|
||||
|
||||
### Parallel opportunities
|
||||
|
||||
- T002, T003, T004 after T001 started
|
||||
- T009, T010 while T006–T008 in progress (XML vs frameworks)
|
||||
- T025 docs parallel with T020 build
|
||||
- T027, T028 polish parallel
|
||||
|
||||
---
|
||||
|
||||
## Parallel example: Foundational
|
||||
|
||||
```text
|
||||
T009 Update Phonesky privapp digest + FAKE_PACKAGE in vendor/sunfish-a16/permissions/
|
||||
T010 Align GmsCore sysconfig/default-permissions stubs in vendor/sunfish-a16/
|
||||
T006 Port frameworks FAKE_PACKAGE + signingInfo spoof in frameworks/base/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation strategy
|
||||
|
||||
### MVP
|
||||
|
||||
1. Phase 1–2 (patches + XML)
|
||||
2. US1 Settings toggle
|
||||
3. US6 bacon + LAB flash proving toggle + Self-Check + Play auth
|
||||
|
||||
### Incremental
|
||||
|
||||
After MVP flash: tighten allow-list evidence (US4), BeaconDB doc polish (T025),
|
||||
parity docs (T027–T029).
|
||||
|
||||
### Suggested first implement slice
|
||||
|
||||
**T001 → T004 → T005–T011 → T020–T026** (skip polish until green Self-Check).
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Never flash GOLDEN; LAB serial only
|
||||
- No Magisk/KSU in this feature
|
||||
- Do not reintroduce UnifiedNlp backend APKs
|
||||
- Prefer EXTENDROM attributable patches; record conflicts in delta doc
|
||||
- User owns git commit/MR; agents only working tree / host build dirs
|
||||
@@ -0,0 +1,41 @@
|
||||
# Specification Quality Checklist: KernelSU-Next on sunfish (LAB)
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before planning
|
||||
**Created**: 2026-09-15
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Product names required by constitution (KernelSU-Next, SusFS, Magisk-as-non-default,
|
||||
TrickyStore-class *experiment*) appear as **capability choices**, not code design.
|
||||
- Checklist item “non-technical stakeholders”: banking PASS/FAIL and LAB-only
|
||||
constraints are written for the owner; kernel revision pinning is an audit need.
|
||||
- SC-002 “≥95% checklist rows” assumes a concrete verification checklist in
|
||||
`/speckit-plan` / tasks — acceptable at specify stage.
|
||||
- Ready for `/speckit-plan`. **Yuh PASS is a hard-gate** (owner 2026-09-15):
|
||||
without it, root is not justified vs NeoBackup + native call-rec / FLAG_SECURE.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Contract: Yuh hard-gate (banking)
|
||||
|
||||
**Feature**: `007-kernelsu-sunfish`
|
||||
**Device**: LAB `11231JEC207477` only
|
||||
|
||||
## Hard-gate
|
||||
|
||||
| App | Profile | Required outcome to accept `007` |
|
||||
|-----|---------|----------------------------------|
|
||||
| Yuh (`com.yuh`) | Island (work user) | **PASS** — usable authenticated session |
|
||||
| Swissquote | Island | **PASS** — usable authenticated session; does not waive Yuh |
|
||||
| N26 / Revolut | any | Non-blocking |
|
||||
|
||||
## Preconditions for a valid Yuh PASS attempt
|
||||
|
||||
1. Build includes KernelSU-Next pin under test.
|
||||
2. Yuh UID(s) have **root deny** + **verified** mount hide (`ksu-hide-surface.md`).
|
||||
3. Install path prefers Aurora → do not open → Island clone → first launch in
|
||||
Island (AXP-like); document deviations.
|
||||
4. Attestation/SusFS experiments in use are listed with revisions.
|
||||
|
||||
## FAIL handling
|
||||
|
||||
- Capture `keystore2` / KeyMint / RKP / Yuh UI error (compare `002`).
|
||||
- Iterate SusFS/attestation pins; do not mark feature done.
|
||||
- Exhausted options → `007` **incomplete or cancelled**; prefer stock phone for
|
||||
banks rather than shipping root without Yuh.
|
||||
|
||||
## PASS evidence package
|
||||
|
||||
- Build id + date
|
||||
- Profile user id
|
||||
- Stack pins (KSU, SusFS, modules)
|
||||
- Short log excerpt showing absence of prior `HARDWARE_TYPE_UNAVAILABLE` class
|
||||
*or* explicit note if a different success path applies
|
||||
- Stored under `/srv/rom/artifacts/007-kernelsu/…`
|
||||
|
||||
US5 exclusively owns acceptance. Both banks must pass on the same build/stack;
|
||||
failure of either keeps the feature incomplete or triggers withdrawal of root.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Contract: KernelSU hide / umount surface
|
||||
|
||||
**Feature**: `007-kernelsu-sunfish`
|
||||
**Consumers**: LAB validation (`quickstart.md`), future `011` signed builds
|
||||
|
||||
## Root grant
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| Default | No app has root until explicitly allowed |
|
||||
| Banking | `com.yuh`, `com.swissquote.android` → **deny** on all tested `userId`s |
|
||||
| Proof | Manager UI alone insufficient; show failed `su`/root API from those UIDs |
|
||||
|
||||
## Mount hide
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| Mechanism | KernelSU umount / profile hide (and SusFS when enabled) |
|
||||
| Proof | From banking (or probe) UID, sensitive module/overlay paths that appear
|
||||
to a normal rooted UID are **absent** or inaccessible |
|
||||
| `path_umount` | Must work on this 4.14 integration or be explicitly filed as blocker |
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Magisk DenyList semantics as the production contract
|
||||
- LSPosed/Zygisk hide
|
||||
- Claiming “legitimate system” without Yuh PASS (see `banking-yuh-gate.md`)
|
||||
|
||||
## Mandatory evidence checklist
|
||||
|
||||
For each banking package × tested user ID, record PASS/FAIL, method and artifact:
|
||||
- root grant denied;
|
||||
- denied root access demonstrated;
|
||||
- module mount visibility before/after recorded;
|
||||
- configured unmount mechanism actually removes the test mount.
|
||||
|
||||
All rows must PASS. A probe must reproduce the target policy and namespace;
|
||||
a different UID with unrelated settings is not evidence for the banking UID.
|
||||
Unavailable evidence is unverified, not PASS. Optional SUSFS checks apply only
|
||||
when enabled and must identify their tested paths.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Data model: 007 KernelSU / banking gate
|
||||
|
||||
Conceptual entities for validation and artifact tracking (not a database schema).
|
||||
|
||||
## KernelSU pin
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `project` | KernelSU-Next (or documented ReSukiSU fallback) |
|
||||
| `revision` | Exact git tag or commit |
|
||||
| `kernel_base` | LOS 23.2 sunfish-compatible 4.14 tree identity |
|
||||
| `boot_build_id` | `ro.lineage.version` / display id of accepting image |
|
||||
| `status` | `poc` → `pinned` → `withdrawn` |
|
||||
|
||||
## SusFS pin (optional until enabled)
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `enabled` | boolean on accepting build |
|
||||
| `revision` | tag/commit if separate |
|
||||
| `soak_hours` | observed soak before claim |
|
||||
| `status` | `off` / `trial` / `claimed` / `reverted` |
|
||||
|
||||
## App profile (per package × userId)
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `package` | e.g. `com.yuh` |
|
||||
| `user_id` | 0 owner, 10 Island, … |
|
||||
| `root_grant` | MUST be `deny` for banking targets |
|
||||
| `umount_or_hide` | `verified` / `unverified` / `failed` |
|
||||
| `evidence_path` | artifact log/screenshot |
|
||||
|
||||
## Banking session result
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `app` | Yuh \| Swissquote |
|
||||
| `profile` | Island / owner |
|
||||
| `build_id` | ROM build under test |
|
||||
| `stack` | KSU ± SusFS ± attestation modules (names + pins) |
|
||||
| `outcome` | `PASS` \| `FAIL` |
|
||||
| `fail_class` | e.g. KeyMint/`HARDWARE_TYPE_UNAVAILABLE`, UI, network |
|
||||
| `log_refs` | paths under `/srv/rom/artifacts/007-…` |
|
||||
| `date` | ISO date |
|
||||
|
||||
**Rule**: Feature acceptance requires one **Yuh** and one **Swissquote** row on the same build/stack with
|
||||
`outcome=PASS` on LAB Island under root-denied + hide-verified stack.
|
||||
|
||||
## Attestation experiment run
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `modules_or_toggles` | TrickyStore-class + microG HA notes |
|
||||
| `baseline_ref` | `002` Yuh log pack |
|
||||
| `result_ref` | new log pack |
|
||||
| `delta` | same error class / improved / resolved |
|
||||
|
||||
## State transitions (feature)
|
||||
|
||||
```text
|
||||
ksu_poc → profiles_verified → susfs_optional → attestation_trial
|
||||
→ both_banks_pass (GATE) → 007_accepted
|
||||
↘ either_bank_fail_exhausted → 007_incomplete_or_cancelled
|
||||
```
|
||||
@@ -0,0 +1,110 @@
|
||||
# Implementation Plan: KernelSU-Next on sunfish (LAB)
|
||||
|
||||
**Branch**: `007-kernelsu-sunfish` | **Date**: 2026-09-15 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/007-kernelsu-sunfish/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Bring **KernelSU-Next** into the LineageOS 23.2 sunfish **4.14** kernel on LAB,
|
||||
verify per-app / per-user **root denial + mount hide** for banking UIDs, then
|
||||
layer **SusFS** and a **TrickyStore-class** attestation experiment so that
|
||||
**Yuh PASS** (Island) becomes achievable. **Yuh PASS is a hard-gate**: without
|
||||
it, `007` is incomplete/cancelled — root is not justified vs NeoBackup + native
|
||||
`008`/`009` and a stock banking phone.
|
||||
|
||||
`006` rootless-Yuh-pass is **deferred** and does not block start. Swissquote PASS is also mandatory; Revolut/N26 non-blocking. GOLDEN never flashed.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Linux 4.14 kernel (C); KernelSU-Next / SusFS integration;
|
||||
Android userspace manager APK; bash runbooks on `rom-dev01`
|
||||
**Primary Dependencies**: LOS 23.2 sunfish kernel tree; KernelSU-Next (non-GKI
|
||||
4.14-capable pin); SusFS; TrickyStore-class (or documented equivalent); `005`
|
||||
userspace stack; Island; `002` Yuh/KeyMint logs
|
||||
**Storage**: Host `/srv/rom/` kernel outs, module ZIPs, secrets; artifacts under
|
||||
`/srv/rom/artifacts/007-…`
|
||||
**Testing**: LAB flash only; KSU manager grants; mount/root probes per UID;
|
||||
Yuh/Swissquote Island sessions; `keystore2`/KeyMint logcat vs `002`
|
||||
**Target Platform**: Pixel 4a LAB `11231JEC207477`; Android 16 / LOS 23.2
|
||||
**Project Type**: Android ROM kernel + root stack + LAB validation
|
||||
**Performance Goals**: Boot + daily stability; SusFS soak ≥24h if claimed
|
||||
**Constraints**: LAB only; no Magisk production; no Zygisk/LSPosed default;
|
||||
banking never gets root; attributable kernel commits; Yuh PASS mandatory
|
||||
**Scale/Scope**: One kernel integration POC → pin revision → SusFS →
|
||||
attestation experiment → banking hard-gate on LAB
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| LAB only; never GOLDEN | pass |
|
||||
| KernelSU-Next is project root (not Magisk production) | pass |
|
||||
| Banking apps never receive root; profiles + verified umount | pass |
|
||||
| SusFS only after KSU + profiles work | pass (phased US1→US3) |
|
||||
| No Zygisk/LSPosed as initial architecture | pass |
|
||||
| Small attributable, reversible changes | pass (pinned commits) |
|
||||
| `006` before `007` in written order | **amended explicitly in constitution 0.2.0** — rootless Yuh gate deferred; owner-approved sequencing; current-ROM snapshot required (T039) |
|
||||
| Hardening Graphene/AXP full ports | out of scope → `013` |
|
||||
|
||||
**Post-design**: Same. Yuh hard-gate is an owner product gate layered on top of
|
||||
constitution Compatibility MVP (Yuh in Insular) — aligned, stricter on `007`
|
||||
acceptance.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/007-kernelsu-sunfish/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
│ ├── ksu-hide-surface.md
|
||||
│ └── banking-yuh-gate.md
|
||||
└── tasks.md # via /speckit-tasks (not this command)
|
||||
```
|
||||
|
||||
### Host + tree
|
||||
|
||||
```text
|
||||
# rom-dev01
|
||||
/srv/rom/src/lineage/kernel/… # LOS 23.2 sunfish-compatible kernel
|
||||
/srv/rom/src/lineage/… # product builds including boot.img
|
||||
/srv/rom/artifacts/007-kernelsu/ # bacon outs, pins, Yuh log packs
|
||||
/srv/rom/references/… # optional mirrors of KSU/SusFS/TrickyStore docs
|
||||
|
||||
# Meta repo
|
||||
docs/002-*-*.md # Yuh/KeyMint baselines (read-only input)
|
||||
docs/reference-sources.md §8–10 # community inspiration, not base
|
||||
docs/a15-a16-delta.md # attestation notes as measured
|
||||
```
|
||||
|
||||
**Structure Decision**: Kernel work lives on `rom-dev01` LOS tree; meta-repo
|
||||
keeps specs, contracts, runbooks, and pin records. No Magisk tree. No megapatch
|
||||
dumps in Git — pin URLs/commits + small project patches only.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation / stretch | Why needed | Simpler alternative rejected because |
|
||||
|---------------------|------------|--------------------------------------|
|
||||
| Start `007` without closing `006` rootless Yuh | `002` shows Yuh fails with and without Magisk (KeyMint/RKP) | Waiting on rootless Yuh green has no known path |
|
||||
| SusFS + TrickyStore-class in same feature as KSU | Owner: Yuh PASS mandatory; hide alone insufficient on GOLDEN | KSU-only “done” without Yuh → root not worth keeping |
|
||||
| Yuh PASS hard-gate on EOL sunfish | Product rationale: else stock phone + `008`/`009` | Soft FAIL documentation wastes a root maintenance burden |
|
||||
|
||||
## Phase 0 / Phase 1
|
||||
|
||||
See `research.md`, `data-model.md`, `contracts/*`, `quickstart.md`.
|
||||
|
||||
## Remediation alignment — 2026-09-15
|
||||
|
||||
Constitution 0.2.0 explicitly defers `006`; T039 records our current rootless
|
||||
LAB state before kernel changes, without requiring PASS. US5 alone owns banking
|
||||
acceptance: both Yuh and Swissquote must pass on the same stack. US4 owns
|
||||
attestation investigation/evidence, not a duplicate acceptance gate. Older
|
||||
iodé/GOLDEN KeyMint logs are correlations, not proof of our ROM's failure cause.
|
||||
T040 explicitly verifies the no-Zygisk/LSPosed constraint.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Quickstart: 007 KernelSU + Yuh gate (LAB only)
|
||||
|
||||
**Device**: LAB `11231JEC207477` — never GOLDEN `11071JEC203839`
|
||||
|
||||
## Goal
|
||||
|
||||
Prove selective root + verified hide, then **Yuh and Swissquote PASS** in Island. Without both banks
|
||||
passing, do not declare `007` done.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Working `005` userspace stack on LAB (microG + Phonesky + spoofing)
|
||||
- `007` boot image with pinned KernelSU-Next
|
||||
- Island installed; Aurora available
|
||||
- Baseline reading: `docs/002-golden-inventory.md`, `docs/002-lab-iodes-baseline.md`
|
||||
|
||||
## 1. Flash LAB
|
||||
|
||||
Use `docs/003-flash-lab.md` with the `007` artifact. Confirm:
|
||||
|
||||
```bash
|
||||
SERIAL=11231JEC207477
|
||||
adb -s "$SERIAL" shell getprop ro.lineage.version
|
||||
# KernelSU manager present; grant root to one debug app only
|
||||
```
|
||||
|
||||
## 2. Hide surface
|
||||
|
||||
1. Deny root for `com.yuh` and `com.swissquote.android` (all relevant users).
|
||||
2. Enable umount/hide for those UIDs.
|
||||
3. **Verify mounts** from a probe — see `contracts/ksu-hide-surface.md`.
|
||||
|
||||
## 3. SusFS (after step 2 green)
|
||||
|
||||
Enable SusFS per pin; confirm boot; re-check hide. Soak before claiming.
|
||||
|
||||
## 4. Attestation experiment
|
||||
|
||||
Apply TrickyStore-class (or equivalent) + any microG HA toggles under test.
|
||||
Capture logcat around Yuh open (`keystore2`, KeyMint, RKP).
|
||||
|
||||
## 5. Banking (Island)
|
||||
|
||||
1. Aurora install Yuh/Swissquote → do not open on owner if following AXP order.
|
||||
2. Clone into Island; first launch in Island.
|
||||
3. Swissquote: must PASS a usable authenticated session.
|
||||
4. Yuh: **must PASS** for feature acceptance (`contracts/banking-yuh-gate.md`).
|
||||
|
||||
## Pass criteria
|
||||
|
||||
- [ ] KSU selective root works
|
||||
- [ ] Banking UIDs: root deny + verified hide
|
||||
- [ ] SusFS claimed only if stable
|
||||
- [ ] **Yuh PASS** in Island with evidence under `/srv/rom/artifacts/007-…`
|
||||
- [ ] Swissquote PASS on the same stack
|
||||
- [ ] No Magisk production image
|
||||
|
||||
## Failure
|
||||
|
||||
If either bank remains unusable after reasonable SusFS/attestation
|
||||
iterations: stop, keep artifacts, mark `007` blocked — consider stock phone for
|
||||
banks; do not ship “root without Yuh” as success.
|
||||
|
||||
Before any rooted flash, complete T039. Before acceptance complete T040.
|
||||
@@ -0,0 +1,106 @@
|
||||
# Research: 007 KernelSU-Next on sunfish
|
||||
|
||||
## Decision: Defer `006` rootless-Yuh gate; start `007` now
|
||||
|
||||
**Decision**: Do not block on a separate `006` “Yuh green without root”. Absorb
|
||||
banking regression into `007`. A rootless snapshot on the current `005` LAB image is required before root;
|
||||
its PASS/FAIL outcome is informational and does not block experiments.
|
||||
|
||||
**Rationale**: GOLDEN (Magisk) and LAB iodé (no Magisk, locked BL) both show Yuh
|
||||
KeyMint/`HARDWARE_TYPE_UNAVAILABLE`. Rootless is not a known fix.
|
||||
|
||||
**Alternatives**: Force `006` first — rejected. Cancel banking on ROM entirely
|
||||
before trying KSU stack — premature; try `007` experiment first.
|
||||
|
||||
## Decision: Yuh PASS is mandatory to accept `007`
|
||||
|
||||
**Decision**: Feature closes only when both Yuh and Swissquote work in Island on LAB under
|
||||
root-denied + verified hide (+ SusFS/attestation stack as needed). Honest
|
||||
residual FAIL ⇒ `007` incomplete or cancelled — not “KSU done, Yuh later”.
|
||||
|
||||
**Rationale**: Owner (2026-09-15): without Yuh, root adds little vs NeoBackup +
|
||||
native call recording / FLAG_SECURE; denylist-style legitimacy alone is not
|
||||
enough reason to carry KSU. Stock handset remains interim fallback, not
|
||||
acceptance.
|
||||
|
||||
**Alternatives**: Soft gate / document FAIL — rejected by owner.
|
||||
|
||||
## Decision: Prefer ReSukiSU + TEESimulator for hard-bank PoC (2026-09-15)
|
||||
|
||||
**Decision**: Align LAB banking experiments with torukk/abu field results:
|
||||
ReSukiSU over KernelSU-Next when Revolut-class detection matters; **TEESimulator-RS**
|
||||
instead of TrickyStore; document Zygisk Next + PIF inject as possible LAB-only
|
||||
exception if required for the Yuh/Swissquote gate.
|
||||
|
||||
**Rationale**: Owner overlap with that project; XDA 2026-08-22; constitution
|
||||
already names ReSukiSU as evaluable fork.
|
||||
|
||||
**Alternatives**: KernelSU-Next-only in-tree first — still useful as build
|
||||
practice, weaker evidence for hard banks.
|
||||
|
||||
## Decision: Profiles + verified umount before SusFS
|
||||
|
||||
**Decision**: Order: (1) KSU boots + selective root, (2) banking UIDs denied +
|
||||
**mount evidence** of hide/`path_umount`, (3) SusFS, (4) attestation modules.
|
||||
|
||||
**Rationale**: Constitution: SusFS only after KernelSU and application profiles
|
||||
work. GUI toggle alone is insufficient.
|
||||
|
||||
## Decision: TrickyStore-class → prefer TEESimulator-RS
|
||||
|
||||
**Decision**: Attestation experiment track prefers **TEESimulator-RS** (TrickyStore
|
||||
compatible drop-in) per owner + torukk; select banking packages only.
|
||||
|
||||
**Rationale**: Community recommendation over original TrickyStore; same slot in
|
||||
the stack.
|
||||
|
||||
## Decision: Island remains managed-profile vehicle
|
||||
|
||||
**Decision**: Keep Island (already on LAB/GOLDEN) for Yuh/Swissquote unless
|
||||
planning discovers a blocking incompatibility; then document substitute.
|
||||
|
||||
**Rationale**: Matches AXP oracle workflow and existing LAB user 10.
|
||||
|
||||
## Decision: No Zygisk/LSPosed in initial `007`
|
||||
|
||||
**Decision**: Out of default scope. Prefer native ROM features for call-rec /
|
||||
FLAG_SECURE later (`008`/`009`).
|
||||
|
||||
**Rationale**: Constitution.
|
||||
|
||||
## Decision: Full Graphene/AXP kernel hardening stays `013`
|
||||
|
||||
**Decision**: `007` only patches kernel as required for KSU / SusFS / umount.
|
||||
Do not import broad hardening series here.
|
||||
|
||||
**Rationale**: Constitution progress order; reduces blast radius while chasing Yuh.
|
||||
|
||||
## Remediation alignment — 2026-09-15
|
||||
|
||||
Constitution 0.2.0 explicitly defers `006`; T039 records our current rootless
|
||||
LAB state before kernel changes, without requiring PASS. US5 alone owns banking
|
||||
acceptance: both Yuh and Swissquote must pass on the same stack. US4 owns
|
||||
attestation investigation/evidence, not a duplicate acceptance gate. Older
|
||||
iodé/GOLDEN KeyMint logs are correlations, not proof of our ROM's failure cause.
|
||||
T040 explicitly verifies the no-Zygisk/LSPosed constraint.
|
||||
|
||||
## Concrete attestation candidates (not yet selected or validated)
|
||||
|
||||
- TrickyStore: https://github.com/5ec1cff/TrickyStore — certificate-chain
|
||||
intervention; current releases closed-source. Record auditability limitations.
|
||||
- TEESimulator: https://github.com/JingMatrix/TEESimulator — open-source
|
||||
software KeyMint/key-attestation simulation; candidate alternative, not
|
||||
authentic hardware repair. Requires external signing material not bundled.
|
||||
- TEESimulator-RS: https://github.com/Enginex0/TEESimulator-RS — related
|
||||
alternative; independently verify implementation, dependencies and A16 support.
|
||||
- BootloaderSpoofer: https://modules.lsposed.org/module/es.chiteroman.bootloaderspoofer/
|
||||
— LSPosed/Xposed approach, outside FR-009 default; not an approved candidate
|
||||
without a separate explicit scope decision.
|
||||
|
||||
T022 selects one concrete candidate before deployment: upstream URL, immutable
|
||||
commit or release with binary hash, license/source availability, dependencies,
|
||||
key-material provenance/availability and rollback. Do not collect keys from
|
||||
unknown sources or commit signing secrets. Evaluate candidates separately, not
|
||||
as a combined stack. No candidate is verified for Yuh on our sunfish yet.
|
||||
KernelSU/SUSFS and Play Integrity modules are not interchangeable substitutes
|
||||
for Key Attestation. A simulator does not itself create a trusted signing chain.
|
||||
@@ -0,0 +1,269 @@
|
||||
# Feature Specification: KernelSU-Next on sunfish (LAB)
|
||||
|
||||
**Feature Branch**: `007-kernelsu-sunfish`
|
||||
**Created**: 2026-09-15
|
||||
**Status**: In progress (LAB)
|
||||
**Session handoff**: `docs/session-20260916-handoff.md` (2026-09-16)
|
||||
**Input**: After `005` first Google-compat stack works on LAB, skip forcing a
|
||||
rootless Yuh green gate. Prioritize **ReSukiSU** (not Magisk; KSU-Next only as
|
||||
history) on the LineageOS 23.2 sunfish kernel, verified hide for banking UIDs,
|
||||
then SusFS / TEESimulator-class LAB experiments aimed at Yuh KeyMint/RKP
|
||||
failures already logged in `002`. LAB only; never GOLDEN. Personal stock
|
||||
handset for banks remains an optional operator fallback outside this feature.
|
||||
|
||||
**Spine reminder:** product path is **our** LOS 23.2 (`003`→`004`/`005` bacon)
|
||||
then `007`. Community abu/torukk ROMs and Downloads boots are reference only.
|
||||
|
||||
## Context / sequencing vs `006`
|
||||
|
||||
Constitution originally ordered a **rootless** banking baseline (`006`) before
|
||||
root (`007`). Evidence already shows:
|
||||
|
||||
| Device | Stack | Swissquote | Yuh |
|
||||
|--------|-------|------------|-----|
|
||||
| GOLDEN | AXP + Magisk DenyList | PASS (owner) | FAIL — HA / “certificate invalid”; KeyMint/`HARDWARE_TYPE_UNAVAILABLE` |
|
||||
| LAB (iodé A16) | No Magisk; BL locked | — | FAIL — same KeyMint/RKP class |
|
||||
|
||||
So a “rootless Yuh must pass” gate is **not** a credible start condition.
|
||||
This feature **absorbs** the banking regression that `006` would have owned:
|
||||
measure owner + Island UIDs on **our** ROM with root hidden. A separate `006`
|
||||
spec may stay deferred or become a thin historical note — it must not block
|
||||
`007` work.
|
||||
|
||||
**Explicitly later (do not pull into this feature):** call recording (`008`),
|
||||
`FLAG_SECURE` (`009`), AXP UX leftovers (`010`), project signing/AVB (`011`),
|
||||
incremental Graphene/AXP/Divest **hardening** ports (`012`–`013`).
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Bootable rooted LAB image (Priority: P1)
|
||||
|
||||
As the developer, I can flash a LAB build whose kernel includes KernelSU-Next
|
||||
compatible with non-GKI Linux 4.14 / sunfish, boot to the lock screen, and
|
||||
confirm root is available only through the KernelSU manager to apps I approve.
|
||||
|
||||
**Why this priority**: Without a working integrated root path, hide/SusFS/banking
|
||||
experiments cannot run on *our* ROM.
|
||||
|
||||
**Independent Test**: Flash LAB only; manager shows installed; `su` works for one
|
||||
approved test app and fails for an unapproved app.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a `007` LAB flash, **When** the device boots, **Then** telephony,
|
||||
Wi‑Fi, and basic UI work at least as well as the last `005` image.
|
||||
2. **Given** KernelSU manager, **When** root is granted to a single debug app,
|
||||
**Then** that app can obtain root and an unapproved app cannot.
|
||||
3. **Given** documentation, **When** reviewed, **Then** the exact KernelSU-Next
|
||||
revision (tag/commit) used for the accepted POC is recorded for reproducibility.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Banking apps never get root; mounts hidden (Priority: P1)
|
||||
|
||||
As the developer, Yuh and Swissquote (owner and Island/work profile UIDs) are
|
||||
configured so they **never** receive root, and module/overlay mounts that would
|
||||
expose root or custom ROM fingerprints to those UIDs are removed or hidden —
|
||||
verified by a real check, not only a UI toggle.
|
||||
|
||||
**Why this priority**: Constitution root architecture; Magisk DenyList on GOLDEN
|
||||
is oracle-only, not our production model.
|
||||
|
||||
**Independent Test**: Per-UID checks (process view of mounts / root binaries)
|
||||
for banking packages on user 0 and work profile; screenshots/logs stored under
|
||||
artifacts.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Yuh and Swissquote installed (Aurora → Island workflow preferred),
|
||||
**When** root grant lists are reviewed, **Then** those packages are denied
|
||||
root on every relevant user ID.
|
||||
2. **Given** a module or overlay that would be visible to a normal app,
|
||||
**When** the banking UID is inspected, **Then** that mount is absent or
|
||||
otherwise hidden per the verified umount/profile mechanism.
|
||||
3. **Given** only a manager “hide” toggle without mount evidence, **When**
|
||||
validation runs, **Then** the story is **not** marked pass.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - SusFS after profiles work (Priority: P2)
|
||||
|
||||
As the developer, once KernelSU profiles and verified hide work, I can enable a
|
||||
SusFS-capable kernel/config on LAB and confirm the device still boots and that
|
||||
selected path-hiding behaviours are measurable for banking UIDs.
|
||||
|
||||
**Why this priority**: Needed for hard banks on community sunfish reports; must
|
||||
not destabilize before basic KSU works. Constitution: SusFS only after KernelSU
|
||||
and application profiles work.
|
||||
|
||||
**Independent Test**: LAB boot + documented SusFS enablement + before/after
|
||||
visibility check for at least one sensitive path from a banking or probe UID.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** US1–US2 green, **When** SusFS is enabled on LAB, **Then** the
|
||||
device boots and KernelSU manager still functions.
|
||||
2. **Given** SusFS on, **When** a probe from a denied banking UID runs,
|
||||
**Then** at least one previously visible root/custom indicator is hidden
|
||||
(evidence logged).
|
||||
3. **Given** SusFS causes repeated spontaneous reboot or severe thermal
|
||||
instability, **When** triage completes, **Then** SusFS is reverted or pinned
|
||||
to a known-good revision before continuing banking claims.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Attestation / KeyMint experiment track (Priority: P1)
|
||||
|
||||
As the developer, I can run a **LAB-only** attestation-compatibility experiment
|
||||
(TrickyStore-class or equivalent, plus any required microG hardware-attestation
|
||||
toggles) aimed at the Yuh failure mode already captured in `002` (KeyMint /
|
||||
`HARDWARE_TYPE_UNAVAILABLE` / “certificate invalid”), without modifying GOLDEN.
|
||||
|
||||
**Why this priority**: Root hide alone did not fix Yuh on GOLDEN or iodé LAB;
|
||||
attestation is the open hypothesis. **Yuh PASS is mandatory** for feature
|
||||
acceptance — otherwise root is not worth carrying vs NeoBackup + native
|
||||
`008`/`009` and a stock banking phone.
|
||||
|
||||
**Independent Test**: Reproduce Yuh launch with logcat focused on `keystore2` /
|
||||
KeyMint / RKP; compare to `002` baselines; diagnostic results required with artifact paths; US5 owns PASS.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `002` Yuh failure signatures, **When** the experiment stack is
|
||||
applied on LAB, **Then** a new log capture exists that either shows the same
|
||||
class of error or a clear change.
|
||||
2. **Given** a candidate experiment, **When** the same attestation probe and
|
||||
bank attempt are repeated, **Then** record the before/after result, limitations
|
||||
and rollback outcome. US4 owns diagnostic evidence, not banking acceptance.
|
||||
3. **Given** persistent KeyMint/RKP messages, **When** results are interpreted,
|
||||
**Then** do not infer causality or failure from those messages alone. US5
|
||||
exclusively owns the end-to-end banking acceptance decision.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - Banking regression on our ROM (Priority: P1)
|
||||
|
||||
As the project owner, after hide (and any accepted SusFS/attestation experiments)
|
||||
I have a written regression for **Swissquote** and **Yuh** inside Island on the
|
||||
`007` LAB image: install path, profile UIDs, biometrics if used, and outcome.
|
||||
Revolut/N26 remain non-blocking.
|
||||
|
||||
**Why this priority**: Compatibility hard-gates; replaces the deferred `006`
|
||||
oracle for “does banking work on our stack”.
|
||||
|
||||
**Independent Test**: End-to-end on LAB only; evidence under
|
||||
`/srv/rom/artifacts/007-…` (and optional laptop rsync). No GOLDEN flash/wipe.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Island (or documented equivalent), **When** Swissquote is used in
|
||||
the work profile with root denied + hide verified, **Then** Swissquote MUST PASS with a usable authenticated session, date and build id.
|
||||
2. **Given** the same setup for Yuh, **When** login/attestation is attempted,
|
||||
**Then** the session MUST **PASS**; an unusable session means
|
||||
`007` is not accepted.
|
||||
3. **Given** Magisk, **When** proposed as production root, **Then** it is
|
||||
rejected; Magisk A/B diagnostic builds are allowed only as temporary
|
||||
reference per constitution.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- KernelSU-Next revision incompatible with 4.14 → evaluate alternate pin /
|
||||
ReSukiSU only as documented POC fork, not silent default change.
|
||||
- Work-profile UIDs differ from owner → hide/root denial must be tested on both.
|
||||
- `path_umount` missing/broken on 4.14 → story 2 fails until backport/verify.
|
||||
- Attestation modules break Play/microg → revert experiment; keep iterating
|
||||
until both banks PASS or declare `007` blocked/cancelled.
|
||||
- Operator chooses a separate stock phone for banks → interim fallback only;
|
||||
does **not** satisfy the Yuh hard-gate on LAB.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Project MUST integrate KernelSU-Next into the LineageOS
|
||||
23.2–compatible sunfish kernel built with the ROM (not Magisk as production
|
||||
root).
|
||||
- **FR-002**: Root MUST be grantable only to explicitly approved apps; banking
|
||||
packages (at least Yuh and Swissquote) MUST never receive root on owner or
|
||||
work-profile user IDs used in the regression.
|
||||
- **FR-003**: Module/overlay mounts MUST be removable or hidden from selected
|
||||
app processes, with verification beyond manager UI toggles; `path_umount` (or
|
||||
equivalent) support on this kernel MUST be confirmed or explicitly failed.
|
||||
- **FR-004**: The accepted KernelSU-Next revision MUST be pinned and recorded
|
||||
(tag/commit) for reproducible builds.
|
||||
- **FR-005**: SusFS MUST only be enabled after FR-001–FR-003 work on LAB; if
|
||||
enabled, boot stability and at least one measurable hide effect MUST be
|
||||
evidenced.
|
||||
- **FR-006**: Evaluate an attestation candidate with exact source URL, immutable
|
||||
revision or release plus binary hash, dependencies, auditability, baseline,
|
||||
before/after evidence and rollback. KeyMint/RKP causality remains a hypothesis.
|
||||
Banking acceptance is owned solely by FR-007 / US5.
|
||||
- **FR-007**: Both Yuh and Swissquote MUST PASS usable authenticated sessions in
|
||||
the LAB managed profile on the same accepted stack with root denied and hide
|
||||
verified. Failure of either bank leaves `007` incomplete or cancelled.
|
||||
N26/Revolut are non-blocking.
|
||||
- **FR-008**: All flashing, kernel experiments, and attestation modules MUST
|
||||
target LAB (`11231JEC207477`) only; GOLDEN MUST remain read-only oracle.
|
||||
- **FR-009**: Zygisk/LSPosed MUST NOT be introduced as the initial architecture
|
||||
unless a later feature proves no native alternative (out of default `007`
|
||||
scope).
|
||||
- **FR-010**: Feature docs MUST state that deferred `006` rootless-Yuh-pass is
|
||||
not a prerequisite, and must link `002` Yuh/Swissquote evidence paths.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **LAB device**: Experimental sunfish; only flash target for `007`.
|
||||
- **KernelSU profile**: Per-app (and per-user) root grant / umount policy.
|
||||
- **Banking target apps**: Yuh (`com.yuh`), Swissquote (`com.swissquote.android`).
|
||||
- **Managed profile**: Island (or equivalent) work user hosting banking apps.
|
||||
- **Attestation experiment stack**: Optional LAB modules/toggles aimed at
|
||||
hardware attestation / KeyMint behaviour.
|
||||
- **Pinned root revision**: Exact KernelSU-Next (and SusFS, if used) identifiers.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: LAB boots a `007` image with working selective root within one
|
||||
flash cycle after the accepted kernel build.
|
||||
- **SC-002**: For Yuh and Swissquote on every tested user ID, root grant is
|
||||
denied and mount-hide is evidenced (not toggle-only) for every applicable contract checklist row, for both packages and every tested user ID; no failed or unverified mandatory row is allowed.
|
||||
- **SC-003**: **Yuh PASS** on LAB Island under the `007` stack (root denied +
|
||||
verified hide + accepted SusFS/attestation experiments), with build id and
|
||||
evidence — required to close the feature.
|
||||
- **SC-004**: Swissquote MUST PASS a usable authenticated session on the same
|
||||
image/stack as SC-003, with dated evidence; both are required for acceptance.
|
||||
- **SC-005**: If SusFS is claimed in the release notes for this phase, LAB
|
||||
completes ≥24h soak without SusFS-driven reboot loops, or SusFS is withdrawn
|
||||
from the claim.
|
||||
- **SC-006**: Artifact package contains before/after attestation probe results
|
||||
and correlated banking logs, including unresolved messages and limitations.
|
||||
Absence of a log string alone is not proof of successful attestation.
|
||||
- **SC-007**: No Magisk-based production image is published as the project
|
||||
default root path.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- `005` stack (microG + patched Phonesky + restricted spoofing) remains the
|
||||
userspace base on LAB before/while bringing up `007`.
|
||||
- Island (already used on LAB/GOLDEN) remains the managed-profile vehicle unless
|
||||
a documented substitute is chosen during implementation planning.
|
||||
- If EOL sunfish cannot satisfy Yuh even with SusFS/TrickyStore-class stacks,
|
||||
**`007` stays incomplete** (or is explicitly cancelled) — not “done with Yuh
|
||||
documented FAIL”. Rationale: without Yuh, root adds little over NeoBackup +
|
||||
native `008`/`009`; a stock handset becomes the banking plan instead.
|
||||
- Operator may still use a separate stock phone as interim fallback; that does
|
||||
not count as `007` acceptance.
|
||||
- Full GrapheneOS/AXP/Divest kernel hardening ports remain `013`, not this
|
||||
feature — `007` only changes the kernel as needed for KSU/SusFS/umount.
|
||||
- Community sunfish LOS+KSU+SusFS reports are inspiration, not a drop-in base.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Flashing or modifying GOLDEN.
|
||||
- Magisk/Magia as default project root.
|
||||
- Making Revolut/N26 hard-gates.
|
||||
- Call recording, FLAG_SECURE, WebView provider work, project AVB lock.
|
||||
- Purchasing or provisioning a second physical phone (operator choice).
|
||||
@@ -0,0 +1,252 @@
|
||||
# Tasks: KernelSU-Next on sunfish (LAB) + Yuh/Swissquote gate
|
||||
|
||||
**Input**: Design docs from `/specs/007-kernelsu-sunfish/`
|
||||
**Prerequisites**: `005` stack on LAB; `002` Yuh/KeyMint baselines; constitution
|
||||
KernelSU-Next (not Magisk production)
|
||||
|
||||
**Organization**: Priority = **Swissquote + Yuh** on LAB. KSU/SusFS/TrickyStore
|
||||
exist to serve that gate. If the gate cannot be met after the experiment track,
|
||||
**cancel root** and pivot to native `008`/`009` (+ optional stock phone) — do
|
||||
not ship “root without Yuh” as success.
|
||||
|
||||
**Out of scope**: GOLDEN flash; Magisk production; Revolut/N26 hard-gates;
|
||||
full Graphene/AXP kernel hardening (`013`).
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete deps)
|
||||
- **[Story]**: US1…US5 from `spec.md`
|
||||
|
||||
## Path conventions
|
||||
|
||||
- Meta: `docs/`, `specs/007-kernelsu-sunfish/`
|
||||
- Host: `/srv/rom/src/lineage/` (kernel + boot), `/srv/rom/artifacts/007-kernelsu/`,
|
||||
`/srv/rom/logs/007-build/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
**Purpose**: Artifact dirs, baseline index, pin stubs
|
||||
|
||||
- [x] T001 Create `/srv/rom/artifacts/007-kernelsu/` and
|
||||
`/srv/rom/logs/007-build/` on `rom-dev01` (android-build writable)
|
||||
- [x] T002 [P] Add `docs/007-kernelsu-runbook.md` stub (LAB-only; pin table;
|
||||
Yuh hard-gate; cancel-root criteria) in meta repo
|
||||
- [x] T003 [P] Index `002` Yuh evidence paths in
|
||||
`docs/007-kernelsu-runbook.md` (GOLDEN + LAB iodé KeyMint refs from
|
||||
`docs/002-golden-inventory.md` / `docs/002-lab-iodes-baseline.md`)
|
||||
- [x] T004 [P] Confirm LAB still on `005` userspace
|
||||
(`pm path` gms/gsf/vending; spoof toggle) — note build id in
|
||||
`/srv/rom/artifacts/007-kernelsu/preflight.txt`
|
||||
|
||||
- [x] T039 Before T009/T011, capture a rootless snapshot of the current LAB ROM:
|
||||
both bank versions/outcomes, build type, microG/Phonesky versions and
|
||||
attestation probe/logs under `pre-root/`. FAIL is allowed; record actual
|
||||
results rather than inferring them from iodé/GOLDEN. Document Island as
|
||||
the current managed-profile vehicle in `docs/007-kernelsu-runbook.md`.
|
||||
*(2026-09-15: banks not installed → N/A; see pre-root/OUTCOMES.txt)*
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (blocks all stories)
|
||||
|
||||
**Purpose**: Choose 4.14-capable KernelSU-Next revision; locate LOS kernel tree;
|
||||
no banking claims yet
|
||||
|
||||
**⚠️ CRITICAL**: No SusFS/attestation/Yuh PASS claims until KSU boots on LAB
|
||||
|
||||
- [x] T005 Inventory LOS 23.2 sunfish kernel path on
|
||||
`/srv/rom/src/lineage/` (defconfig, branch); record in
|
||||
`docs/007-kernelsu-runbook.md`
|
||||
*(`kernel/google/msm-4.14` @ `28f9290ae067…`; sunfish_defconfig)*
|
||||
- [x] T006 Select KernelSU-Next revision compatible with non-GKI 4.14; document
|
||||
candidates + choice in `docs/007-kernelsu-runbook.md` (ReSukiSU only as
|
||||
explicit fallback)
|
||||
*(`legacy` branch; manual hooks preferred over kprobes)*
|
||||
- [x] T007 Mirror/checkout chosen KernelSU-Next sources under
|
||||
`/srv/rom/references/kernelsu-next/` (or documented path); record commit
|
||||
*(@ `a54e4fa46c6c…`)*
|
||||
- [x] T008 Draft integration notes (what files touch kernel vs boot.img) in
|
||||
`docs/007-kernelsu-runbook.md` — attributable commits only, no megapatch
|
||||
|
||||
**Checkpoint**: Ready to integrate and build boot (US1)
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Bootable rooted LAB image (P1) 🎯 MVP slice
|
||||
|
||||
**Goal**: LAB boots with KernelSU-Next; selective root works
|
||||
**Independent test**: Manager present; one approved app gets root; unapproved
|
||||
does not; telephony/Wi‑Fi OK
|
||||
|
||||
- [ ] T009 [US1] Integrate KernelSU-Next into sunfish kernel tree under
|
||||
`/srv/rom/src/lineage/`; build boot/kernel; log
|
||||
`/srv/rom/logs/007-build/ksu-poc.log`
|
||||
- [ ] T010 [US1] Stage boot/images + SHA256 to
|
||||
`/srv/rom/artifacts/007-kernelsu/<date>-ksu-poc/`
|
||||
- [ ] T011 [US1] Flash LAB only (`11231JEC207477`); confirm boot +
|
||||
`ro.lineage.version`; install/open KSU manager
|
||||
- [ ] T012 [US1] Grant root to one debug app; deny a second; capture evidence
|
||||
under `/srv/rom/artifacts/007-kernelsu/<date>-ksu-poc/root-grant/`
|
||||
- [ ] T013 [US1] Pin exact KernelSU-Next revision in
|
||||
`docs/007-kernelsu-runbook.md` + artifact `PIN.txt`
|
||||
|
||||
**Checkpoint**: US1 green before profiles/SusFS
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Banking never root; mounts hidden (P1)
|
||||
|
||||
**Goal**: Yuh/Swissquote UIDs denied + **verified** umount/hide
|
||||
**Independent test**: `contracts/ksu-hide-surface.md` — not toggle-only
|
||||
|
||||
- [ ] T014 [US2] Configure KSU profiles: deny root for `com.yuh` and
|
||||
`com.swissquote.android` on user 0 and Island user; document steps in
|
||||
`docs/007-kernelsu-runbook.md`
|
||||
- [ ] T015 [US2] Enable umount/hide for those UIDs; verify `path_umount` (or
|
||||
equivalent) works on this 4.14 build — note pass/fail in
|
||||
`/srv/rom/artifacts/007-kernelsu/<date>-hide/umount.txt`
|
||||
- [ ] T016 [US2] From banking or probe UID, capture mount/root visibility
|
||||
before/after hide →
|
||||
`/srv/rom/artifacts/007-kernelsu/<date>-hide/mounts/`
|
||||
- [ ] T017 [US2] Mark `contracts/ksu-hide-surface.md` checklist rows against
|
||||
real evidence (update runbook if contract gaps)
|
||||
|
||||
**Checkpoint**: Hide verified before SusFS
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — SusFS after profiles (P2)
|
||||
|
||||
**Goal**: SusFS on LAB; measurable hide; no reboot loop
|
||||
**Independent test**: Boot + one path hidden; soak before claim
|
||||
|
||||
**Note (2026-09-16):** T018 **build** completed early (API bridge) *before* US2
|
||||
hide verification — process exception. Boot artifact
|
||||
`boot-resukisu-susfs-20260916T004038Z.img` is **trial only**. Prefer LAB on
|
||||
`boot-resukisu-our-20260915T183729Z` until US2 green; then re-attempt T019.
|
||||
abu/torukk boots are reference-only — see `docs/session-20260916-handoff.md`.
|
||||
|
||||
- [x] T018 [US3] Integrate SusFS into the pinned kernel path; build; log
|
||||
(host detach SusFS boot 20260916T004038Z; sha `455a77a6…`)
|
||||
- [ ] T019 [US3] Flash LAB; confirm boot + KSU still works; record SusFS pin in
|
||||
`docs/007-kernelsu-runbook.md`
|
||||
- [ ] T020 [US3] Re-verify banking UID hide with SusFS on → artifact
|
||||
`/srv/rom/artifacts/007-kernelsu/<date>-susfs/`
|
||||
- [ ] T021 [US3] Soak ≥24h or document revert if unstable (SC-005); update
|
||||
SusFS status `trial`/`claimed`/`reverted` in runbook
|
||||
|
||||
**Checkpoint**: SusFS stable or withdrawn before attestation claims that depend
|
||||
on it
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 4 — Attestation / KeyMint experiment (P1)
|
||||
|
||||
**Goal**: TrickyStore-class (or equiv.) vs `002` Yuh KeyMint failure
|
||||
**Independent test**: New log pack; progress toward Yuh PASS
|
||||
|
||||
- [ ] T022 [US4] Choose attestation experiment stack (TrickyStore-class or
|
||||
documented equivalent + microG HA toggles); record source URL, immutable commit or release and binary SHA256, dependencies, key-material requirements, auditability and rollback in
|
||||
`docs/007-kernelsu-runbook.md` **before T023**
|
||||
- [ ] T023 [US4] Apply stack on LAB; capture `keystore2`/KeyMint/RKP logcat on
|
||||
Yuh open → `/srv/rom/artifacts/007-kernelsu/<date>-attest/`
|
||||
- [ ] T024 [US4] Diff against `002` failure class; write short delta note in
|
||||
artifact `DELTA.md` (same / improved / resolved)
|
||||
- [ ] T025 [US4] Iterate one candidate at a time based on measured probe/banking outcomes; do not use a log string alone as the failure criterion; keep each attempt under dated artifact dirs — do
|
||||
not mark feature done on FAIL
|
||||
|
||||
**Checkpoint**: Diagnostic evidence ready for US5; persistent log messages
|
||||
alone do not determine acceptance. Exhausted unsuccessful bank attempts lead
|
||||
to Phase 9 or an incomplete feature.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: User Story 5 — Banking regression / hard-gate (P1)
|
||||
|
||||
**Goal**: **Yuh and Swissquote PASS** in Island
|
||||
**Independent test**: `contracts/banking-yuh-gate.md` + `quickstart.md`
|
||||
|
||||
- [ ] T026 [US5] Install path: Aurora → (prefer no owner open) → Island clone
|
||||
for Yuh + Swissquote; note UIDs in
|
||||
`/srv/rom/artifacts/007-kernelsu/<date>-banking/layout.txt`
|
||||
- [ ] T027 [US5] Swissquote Island session → **PASS required** + evidence under
|
||||
`…/<date>-banking/swissquote/`
|
||||
- [ ] T028 [US5] Yuh Island session → **PASS required**; evidence under
|
||||
`…/<date>-banking/yuh/` (build id, stack pins, log excerpt)
|
||||
- [ ] T040 Before T029 acceptance, verify FR-009: installed packages, root
|
||||
module inventory, relevant processes/mounts and build configuration show
|
||||
no Zygisk/LSPosed integration. Store evidence; a package-name check alone
|
||||
is insufficient. Any proposed exception requires a spec decision first.
|
||||
|
||||
- [ ] T029 [US5] If both banks PASS: fill `data-model.md` banking row + tick
|
||||
`specs/007-kernelsu-sunfish/quickstart.md` pass criteria
|
||||
- [ ] T030 [US5] If either bank FAILS after T022–T025 exhausted: do **not** accept
|
||||
`007`; proceed to Phase 9 cancel-root tasks
|
||||
|
||||
**Checkpoint**: Feature accepted only with both banks PASS
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: Polish (only if both banks PASS)
|
||||
|
||||
- [ ] T031 [P] Update `docs/axp-pro-parity.md` root / DenyList / Yuh / Swissquote
|
||||
rows to reflect KSU-Next + LAB results
|
||||
- [ ] T032 [P] Update `docs/a15-a16-delta.md` attestation/`007` measured notes
|
||||
- [ ] T033 Handoff note in `docs/007-kernelsu-runbook.md`: next may be `008`
|
||||
call recording / `009` FLAG_SECURE; full hardening still `012`–`013`
|
||||
- [ ] T034 Mark deferred `006` as superseded-by-`007` (or thin stub) in
|
||||
`specs/` / roadmap note — no fake rootless Yuh success
|
||||
|
||||
---
|
||||
|
||||
## Phase 9: Cancel-root pivot (only if either banking hard-gate fails)
|
||||
|
||||
**Purpose**: Owner priority — without Yuh/Swissquote success, discard project
|
||||
root and keep native requirements instead
|
||||
|
||||
- [ ] T035 Write `/srv/rom/artifacts/007-kernelsu/CANCEL-ROOT.md` (attempts,
|
||||
last pins, KeyMint residual, recommendation: stock phone for banks)
|
||||
- [ ] T036 Update `docs/007-kernelsu-runbook.md` + `docs/axp-pro-parity.md`:
|
||||
root path **withdrawn**; Magisk/KSU not production
|
||||
- [ ] T037 [P] Stub or specify next focus: `008` call recording + `009`
|
||||
FLAG_SECURE (native, no LSPosed) — Spec Kit when owner starts them
|
||||
- [ ] T038 Leave LAB on last known-good **non-root** (`005`) image or document
|
||||
re-flash steps in runbook
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
```text
|
||||
Setup T001–T004 + T039
|
||||
→ Foundational T005–T008
|
||||
→ US1 T009–T013 (KSU boot)
|
||||
→ US2 T014–T017 (hide)
|
||||
→ US3 T018–T021 (SusFS)
|
||||
→ US4 T022–T025 (attest)
|
||||
→ US5 T026–T030 + T040 (both-bank gate)
|
||||
↘ PASS → Polish T031–T034
|
||||
↘ FAIL → Cancel-root T035–T038
|
||||
```
|
||||
|
||||
- US3 may be skipped only if US4/US5 PASS without SusFS (document why)
|
||||
- US4/US5 are the product priority; US1–US2 are enablers
|
||||
|
||||
## Parallel opportunities
|
||||
|
||||
- T002, T003, T004 after T001
|
||||
- T031, T032 after both banks PASS
|
||||
- T037 anytime during cancel-root phase
|
||||
|
||||
## MVP
|
||||
|
||||
**Minimum useful slice**: T001–T013 (KSU boots on LAB).
|
||||
**Product MVP**: T027 Swissquote PASS and T028 Yuh PASS on the same stack.
|
||||
Either unresolved failure → Phase 9 or remain incomplete, never “007 done”.
|
||||
|
||||
## Suggested next command after tasks
|
||||
|
||||
`/speckit-analyze` (optional) → `/speckit-implement` starting at T001 on
|
||||
`rom-dev01` (kernel work is host-side; LAB flash when boot ready).
|
||||
@@ -0,0 +1,27 @@
|
||||
# Specification Quality Checklist: Call recording + FLAG_SECURE
|
||||
|
||||
**Purpose**: Validate specification completeness before planning
|
||||
**Created**: 2026-09-16
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation-only jargon in Success Criteria
|
||||
- [x] Requirements are testable
|
||||
- [x] Scope (global toggles only) is explicit
|
||||
- [x] Non-goals documented
|
||||
- [x] LAB-only constraint present
|
||||
|
||||
## Completeness
|
||||
|
||||
- [x] User stories cover call-rec and FLAG_SECURE
|
||||
- [x] Secure setting names proposed
|
||||
- [x] Default OFF behaviour stated
|
||||
- [x] EXTENDROM / AXP GOLDEN call-rec references noted in design doc
|
||||
- [x] FLAG_SECURE scope is global only (per-app not planned)
|
||||
|
||||
## Notes
|
||||
|
||||
Ready for `/speckit-plan` when owner starts implementation on `rom-dev01`.
|
||||
Investigate Dialer gate on LOS 23.2 before coding call-rec (A15 EXTENDROM
|
||||
overlay dirs were empty; A11 is reference only).
|
||||
@@ -0,0 +1,32 @@
|
||||
# Contract: Call recording surface
|
||||
|
||||
**Feature**: `008-call-rec-flag-secure`
|
||||
**Consumers**: LAB validation (`quickstart.md`)
|
||||
|
||||
## Secure setting
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| Key | `Settings.Secure.extendrom_call_recording` |
|
||||
| Values | `null`/`0` = stock country rules; `1` = ignore country deny |
|
||||
| Readback | `adb shell settings get secure extendrom_call_recording` |
|
||||
| Write | Developer Options switch or `settings put secure … 0\|1` |
|
||||
|
||||
## Dialer behaviour
|
||||
|
||||
| Condition | Expected |
|
||||
|-----------|----------|
|
||||
| Feature off / setting `0` | `CallRecorder.canRecordInCurrentCountry()` uses `call_record_states.xml` |
|
||||
| Setting `1` and recording enabled | `canRecordInCurrentCountry()` true → record control available |
|
||||
| `call_recording_enabled` false | Still disabled (override does not invent recording capability) |
|
||||
|
||||
## UI
|
||||
|
||||
- Developer Options entry with legal responsibility summary (EXTENDROM-style).
|
||||
- Reset to `0` when Developer Options master is disabled.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Setting readback 0/1.
|
||||
- In-call record start with setting `1` produces a file; note path under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/call-rec/`.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Contract: FLAG_SECURE / screenshot surface
|
||||
|
||||
**Feature**: `008-call-rec-flag-secure`
|
||||
**Consumers**: LAB validation (`quickstart.md`)
|
||||
|
||||
## Secure setting
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| Key | `Settings.Secure.disable_secure_windows` (AOSP `DISABLE_SECURE_WINDOWS`) |
|
||||
| Values | `null`/`0` = stock `FLAG_SECURE`; `1` = global capture override |
|
||||
| Readback | `adb shell settings get secure disable_secure_windows` |
|
||||
| UI preference key | `allow_flag_secure_override` (writes the Secure key above) |
|
||||
| Scope | **Global** (all apps); per-app lists not planned |
|
||||
| Note | WMS only applies this on **debuggable** builds (`ro.debuggable`) |
|
||||
|
||||
## Capture behaviour
|
||||
|
||||
| Condition | Expected |
|
||||
|-----------|----------|
|
||||
| Setting `0`, secure window | System screenshot / screen record blocked as stock |
|
||||
| Setting `1`, same window | System screenshot / screen record succeeds |
|
||||
| Setting `1`, DRM/HW buffer edge cases | May still fail — document if observed |
|
||||
|
||||
## UI
|
||||
|
||||
- Developer Options switch; short summary that this weakens app privacy.
|
||||
- Reset to `0` when Developer Options master is disabled.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Setting readback 0/1.
|
||||
- Before/after screenshots (or failure toast) stored under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/flag-secure/`.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Data model: `008-call-rec-flag-secure`
|
||||
|
||||
## Entities
|
||||
|
||||
### SecureSettingCallRec
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| key | string | `extendrom_call_recording` |
|
||||
| value | int | `0` (default) or `1` |
|
||||
| namespace | Secure | `Settings.Secure` |
|
||||
|
||||
**Transitions**: DO switch ON → `1`; OFF → `0`; Developer Options master
|
||||
disabled → force `0`.
|
||||
|
||||
### SecureSettingFlagSecure
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| key | string | `disable_secure_windows` (DO pref `allow_flag_secure_override`) |
|
||||
| value | int | `0` (default) or `1` |
|
||||
| namespace | Secure | `Settings.Secure` |
|
||||
|
||||
**Transitions**: same as call-rec.
|
||||
|
||||
### DialerCountryPolicy
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| iso | string | ISO country from `GeoUtil.getCurrentCountryIso` |
|
||||
| allowed | bool | from `call_record_states.xml` unless override ON |
|
||||
|
||||
**Effective allow** =
|
||||
`CallRecorderService.isEnabled(context)` AND
|
||||
(`extendrom_call_recording == 1` OR country map allows iso).
|
||||
|
||||
### CapturePolicy
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| windowSecure | bool | app set `FLAG_SECURE` |
|
||||
| override | bool | `disable_secure_windows == 1` |
|
||||
|
||||
**Effective block screenshot** = `windowSecure && !override` (for covered
|
||||
system capture paths).
|
||||
|
||||
## Relationships
|
||||
|
||||
- Both Secure settings are owned by Settings Developer Options controllers.
|
||||
- Dialer reads call-rec setting only in `canRecordInCurrentCountry()` (and any
|
||||
equivalent callers).
|
||||
- Framework/SystemUI reads FLAG_SECURE override on capture / secure checks.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Implementation Plan: Call recording unlock + FLAG_SECURE override
|
||||
|
||||
**Branch**: `008-call-rec-flag-secure` | **Date**: 2026-09-16 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/008-call-rec-flag-secure/spec.md`
|
||||
(roadmap `008` + `009`, global Developer Options toggles only).
|
||||
|
||||
## Summary
|
||||
|
||||
Ship two native Developer Options switches (same pattern as `005`
|
||||
`allow_signature_fake`):
|
||||
|
||||
1. **Disable call recording restrictions** →
|
||||
`Settings.Secure.extendrom_call_recording` (GOLDEN / EXTENDROM
|
||||
`ER_ALLOW_ANY_CALL_REC`) — when ON, Dialer
|
||||
`CallRecorder.canRecordInCurrentCountry()` allows recording regardless of
|
||||
`call_record_states.xml` country flags.
|
||||
2. **Allow screenshots of secure windows** →
|
||||
`Settings.Secure.allow_flag_secure_override` — when ON, system capture
|
||||
paths ignore `FLAG_SECURE` globally.
|
||||
|
||||
References: AXP GOLDEN Secure dump (`extendrom_call_recording=1`) +
|
||||
EXTENDROM `er.sh` F_CALLREC / `overlays/call-rec` / `config/call-rec`.
|
||||
FLAG_SECURE is project-native (not AXP catalog). Re-validate on LOS 23.2 /
|
||||
A16. No Magisk / LSPosed / Zygisk at runtime. LAB only.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Java (Dialer, Settings, frameworks/base); Secure settings;
|
||||
optional Kotlin if Settings already uses it for DO controllers
|
||||
**Primary Dependencies**: LOS 23.2 Dialer (`CallRecorder`,
|
||||
`call_record_states.xml`); Settings Developer Options; SystemUI / WM capture
|
||||
surfaces; EXTENDROM call-rec reference on
|
||||
`/srv/rom/references/extendrom`
|
||||
**Storage**: `Settings.Secure` keys; meta-repo patches under
|
||||
`vendor/sunfish-a16/patches/008-…`
|
||||
**Testing**: LAB flash/`adb`; `settings get/put`; call-record file evidence;
|
||||
screenshot of secure window; Magisk-free image
|
||||
**Target Platform**: Pixel 4a LAB `11231JEC207477`; Android 16 / LOS 23.2
|
||||
**Project Type**: Android ROM (Dialer + Settings + frameworks)
|
||||
**Performance Goals**: N/A (correctness)
|
||||
**Constraints**: LAB only; default OFF; global only (no per-app); attributable
|
||||
patches; no root modules; legal warning on call-rec UI
|
||||
**Scale/Scope**: Two DO preferences; one Dialer gate; one (or few) capture /
|
||||
`FLAG_SECURE` enforcement sites; docs + LAB evidence
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| LAB only; never GOLDEN | pass |
|
||||
| Native call recording; re-validate A16 (no blind AXP XML) | pass (Dialer gate located on LOS 23.2) |
|
||||
| FLAG_SECURE: default stock; user global override; no LSPosed | pass (global only) |
|
||||
| No Magisk as production stage | pass |
|
||||
| Small attributable reversible patches | pass (EXTENDROM F_CALLREC / native FLAG_SECURE) |
|
||||
| Do not pull banking / incomplete `007` into this feature | pass |
|
||||
|
||||
**Post-design**: unchanged — FLAG_SECURE is global-only (not planned per-app);
|
||||
capture paths that stay DRM-blocked must be documented if found on LAB.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/008-call-rec-flag-secure/
|
||||
├── plan.md # this file
|
||||
├── research.md # Phase 0
|
||||
├── data-model.md # Phase 1
|
||||
├── quickstart.md # Phase 1
|
||||
├── contracts/
|
||||
│ ├── call-recording-surface.md
|
||||
│ └── flag-secure-surface.md
|
||||
└── tasks.md # /speckit-tasks (not this command)
|
||||
```
|
||||
|
||||
### Host + tree
|
||||
|
||||
```text
|
||||
# Meta-repo
|
||||
vendor/sunfish-a16/patches/008-call-rec-flag-secure/ # apply scripts (to add)
|
||||
docs/008-009-design.md
|
||||
|
||||
# rom-dev01
|
||||
/srv/rom/src/lineage/packages/apps/Dialer/
|
||||
java/com/android/incallui/call/CallRecorder.java # canRecordInCurrentCountry()
|
||||
java/com/android/dialer/callrecord/res/xml/call_record_states.xml
|
||||
/srv/rom/src/lineage/packages/apps/Settings/ # DO controllers + strings
|
||||
/srv/rom/src/lineage/frameworks/base/ # Secure settings + FLAG_SECURE
|
||||
/srv/rom/references/extendrom/overlays/call-rec/
|
||||
/srv/rom/references/extendrom/config/call-rec/
|
||||
/srv/rom/artifacts/008-call-rec-flag-secure/ # LAB evidence
|
||||
```
|
||||
|
||||
**Structure Decision**: Same as `005` — attributable patches applied on the
|
||||
LOS tree via `vendor/sunfish-a16` scripts; meta-repo holds specs/docs/scripts,
|
||||
not megapatches of Dialer/frameworks.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why needed | Simpler alternative rejected because |
|
||||
|-----------|------------|--------------------------------------|
|
||||
| Frameworks / SystemUI patches for FLAG_SECURE | Constitution requires native override | Magisk module forbidden in production |
|
||||
| Dialer patch (not overlay-only) | Country gate is Java `canRecordInCurrentCountry()` | Blind A11 overlay alone does not wire the Secure setting |
|
||||
|
||||
## Phase 0 / Phase 1
|
||||
|
||||
See `research.md`, `data-model.md`, `contracts/*`, `quickstart.md`.
|
||||
@@ -0,0 +1,69 @@
|
||||
# Quickstart: `008` call-rec + FLAG_SECURE (LAB)
|
||||
|
||||
**Device**: LAB only `11231JEC207477`
|
||||
**Build**: bacon/image with `008-call-rec-flag-secure` applied
|
||||
**Evidence root**: `/srv/rom/artifacts/008-call-rec-flag-secure/`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Magisk **not** required (must work without it).
|
||||
- Developer Options enabled.
|
||||
- Contracts: [call-recording-surface.md](./contracts/call-recording-surface.md),
|
||||
[flag-secure-surface.md](./contracts/flag-secure-surface.md).
|
||||
|
||||
## 1. Defaults
|
||||
|
||||
```bash
|
||||
adb -s 11231JEC207477 shell settings get secure extendrom_call_recording
|
||||
adb -s 11231JEC207477 shell settings get secure disable_secure_windows
|
||||
# expect 0 or null
|
||||
```
|
||||
|
||||
## 2. Call recording (region unlock)
|
||||
|
||||
1. Open **Developer Options** → enable **Disable call recording restrictions**.
|
||||
2. Confirm:
|
||||
|
||||
```bash
|
||||
adb shell settings get secure extendrom_call_recording
|
||||
# expect 1
|
||||
```
|
||||
|
||||
3. Place or receive a call with Dialer → start recording → stop → confirm file
|
||||
(Downloads / Dialer recordings — note path).
|
||||
4. Disable the switch (or turn off Developer Options) → confirm setting `0`
|
||||
and that a restricted country would hide/deny record (or document LAB
|
||||
country ISO + XML flag).
|
||||
|
||||
Store notes + path under `…/call-rec/`.
|
||||
|
||||
## 3. FLAG_SECURE override
|
||||
|
||||
1. Enable **Allow screenshots of secure windows** in Developer Options.
|
||||
2. Confirm:
|
||||
|
||||
```bash
|
||||
adb shell settings get secure disable_secure_windows
|
||||
# expect 1
|
||||
```
|
||||
|
||||
3. Open an app/window that sets `FLAG_SECURE` (e.g. password manager, banking
|
||||
login, or a tiny test APK).
|
||||
4. With toggle **OFF**: system screenshot should fail / blank.
|
||||
5. With toggle **ON**: screenshot or screen record should succeed.
|
||||
6. Toggle OFF again → secure behaviour restored.
|
||||
|
||||
Store images/notes under `…/flag-secure/`.
|
||||
|
||||
## 4. Pass criteria
|
||||
|
||||
- [ ] Both settings default OFF after fresh boot / DO off
|
||||
- [ ] Call-rec ON → recording works; OFF → stock policy
|
||||
- [ ] FLAG_SECURE ON → capture works; OFF → blocked
|
||||
- [ ] No Magisk installed for the successful run
|
||||
|
||||
## Notes
|
||||
|
||||
- User is responsible for call-recording legality.
|
||||
- DRM-protected surfaces may still resist capture; note exceptions.
|
||||
- `user` build retest before release claims (`011`).
|
||||
@@ -0,0 +1,61 @@
|
||||
# Research: `008-call-rec-flag-secure`
|
||||
|
||||
## Decision: Call-rec = AXP GOLDEN / EXTENDROM native model
|
||||
|
||||
**Decision**: Port EXTENDROM `F_CALLREC` (same behaviour as AXP GOLDEN), not
|
||||
Magisk Dialer RRO.
|
||||
|
||||
**GOLDEN evidence**: LAB dump already has
|
||||
`extendrom_call_recording=1` in
|
||||
`.local-artifacts/002-golden/20260915-spoofing-phonesky/settings/secure-*.txt`.
|
||||
|
||||
**Mechanism** (`/srv/rom/references/extendrom/er.sh`):
|
||||
|
||||
1. Overlay Dialer `config.xml`: `call_recording_enabled=true`,
|
||||
`call_recording_audio_source=4`.
|
||||
2. Settings DO: category + legal info + switch
|
||||
`extendrom_call_recording`.
|
||||
3. Controllers: `ER_CallRecPreferenceController` /
|
||||
`ER_CallRecInfo` → `Settings.Secure.ER_ALLOW_ANY_CALL_REC`.
|
||||
4. `Settings.java`:
|
||||
`ER_ALLOW_ANY_CALL_REC = "extendrom_call_recording"`.
|
||||
5. Dialer `CallRecorder.canRecordInCurrentCountry()`: if Secure int == 1,
|
||||
return `true` before country XML map.
|
||||
|
||||
**Secure key (product)**: `extendrom_call_recording` (GOLDEN-compatible).
|
||||
Do **not** invent `allow_call_recording_any_region` for call-rec.
|
||||
|
||||
**Alternatives rejected**:
|
||||
|
||||
- Magisk static RRO of `call_record_states.xml` — always-on, not native ROM,
|
||||
no DO parity with GOLDEN.
|
||||
- Blind A11 overlay-only without Dialer Java gate — may no-op on A16.
|
||||
|
||||
## Decision: FLAG_SECURE = AOSP `disable_secure_windows` + DO
|
||||
|
||||
**Decision**: Do **not** invent a second frameworks hook. LOS 23.2 / A16 already
|
||||
has `Settings.Secure.DISABLE_SECURE_WINDOWS` wired through
|
||||
`WindowManagerService` → `WindowState.isSecureLocked()`. Ship a Developer
|
||||
Options switch (preference key `allow_flag_secure_override`) that writes
|
||||
`disable_secure_windows`.
|
||||
|
||||
**Constraint**: WMS applies the setting only on debuggable builds
|
||||
(`ro.debuggable`). LAB `userdebug` is in scope; `user` retest before release.
|
||||
|
||||
**Alternatives rejected**: Magisk `services.jar` dex patchers as shipping
|
||||
mechanism.
|
||||
|
||||
## Decision: Packaging = `vendor/sunfish-a16` apply like `005`
|
||||
|
||||
Idempotent script under `patches/008-call-rec-flag-secure/`, EXTENDROM/`er.sh`
|
||||
attribution for call-rec.
|
||||
|
||||
## Decision: Combined feature directory
|
||||
|
||||
One Spec Kit feature absorbs roadmap `008` + `009`.
|
||||
|
||||
## Decision: No Magisk artifacts in the repo
|
||||
|
||||
Owner-supplied Magisk zips were temporary agent aids only; removed from the
|
||||
working tree. Implementation references EXTENDROM + GOLDEN dumps + A16 source
|
||||
inventory.
|
||||
@@ -0,0 +1,170 @@
|
||||
# Feature Specification: Call recording unlock + FLAG_SECURE override
|
||||
|
||||
**Feature Branch**: `008-call-rec-flag-secure`
|
||||
**Created**: 2026-09-16
|
||||
**Status**: Draft
|
||||
**Input**: Deliver constitution items `008` and `009` together as native ROM
|
||||
features with two Developer Options toggles (global only). Call recording =
|
||||
disable region/country restrictions via **AXP GOLDEN / EXTENDROM native**
|
||||
`extendrom_call_recording` DO gate. FLAG_SECURE = optional global allow
|
||||
screenshots/capture of secure windows (native frameworks + DO). Pattern
|
||||
matches `005` DO style. No LSPosed/Zygisk/Magisk runtime. LAB only.
|
||||
|
||||
**Design**: [`docs/008-009-design.md`](../../docs/008-009-design.md)
|
||||
|
||||
## Absorbs roadmap
|
||||
|
||||
| # | Theme | In this feature |
|
||||
|---|--------|-----------------|
|
||||
| 008 | Unrestricted call recording (region) | Yes |
|
||||
| 009 | FLAG_SECURE override | Yes — **global only** |
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Call recording region unlock toggle (Priority: P1)
|
||||
|
||||
As a LAB/daily-driver user, I can enable **Disable call recording
|
||||
restrictions** under Developer Options. When ON, the Dialer no longer blocks
|
||||
recording solely because of country/region rules. When OFF, stock LOS
|
||||
restrictions apply.
|
||||
|
||||
**Why this priority**: Core `008` value; small surface; matches EXTENDROM/AXP
|
||||
intent without porting full AXP recording UX.
|
||||
|
||||
**Independent Test**: Toggle setting; `settings get secure
|
||||
extendrom_call_recording`; attempt call recording on LAB Dialer with
|
||||
toggle on vs off.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a build with this feature on LAB, **When** Developer Options is
|
||||
opened, **Then** a switch for disabling call-recording region restrictions
|
||||
is visible (with a short legal responsibility summary).
|
||||
2. **Given** the switch is OFF (default), **When** Dialer evaluates recording
|
||||
eligibility, **Then** stock country/region rules apply.
|
||||
3. **Given** the switch is ON, **When** the user records a call with the
|
||||
system Dialer, **Then** recording is not refused solely due to region /
|
||||
country policy, and a recording artifact is produced.
|
||||
4. **Given** Developer Options is disabled globally, **When** that happens,
|
||||
**Then** `extendrom_call_recording` returns to `0`.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Global FLAG_SECURE / screenshot override (Priority: P1)
|
||||
|
||||
As a LAB/daily-driver user, I can enable **Allow screenshots of secure
|
||||
windows** under Developer Options. When ON, screenshots and screen capture
|
||||
work even if apps set `FLAG_SECURE`. When OFF, Android’s normal secure-window
|
||||
behaviour applies. The override is **global** (all apps).
|
||||
|
||||
**Why this priority**: Constitution `009` project requirement; same DO pattern
|
||||
as spoofing.
|
||||
|
||||
**Independent Test**: App or screen that sets `FLAG_SECURE`; capture with
|
||||
toggle OFF (expect fail) and ON (expect success);
|
||||
`settings get secure disable_secure_windows`.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a build with this feature on LAB, **When** Developer Options is
|
||||
opened, **Then** a switch for secure-window screenshot override is visible.
|
||||
2. **Given** the switch is OFF (default), **When** the user tries to screenshot
|
||||
a `FLAG_SECURE` window, **Then** capture is blocked as on stock.
|
||||
3. **Given** the switch is ON, **When** the user screenshots or screen-records
|
||||
that same window, **Then** capture succeeds.
|
||||
4. **Given** Developer Options is disabled globally, **When** that happens,
|
||||
**Then** `disable_secure_windows` returns to `0`.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Native, attributable packaging (Priority: P2)
|
||||
|
||||
As a maintainer, both behaviours ship in the bacon/ROM tree via
|
||||
`vendor/sunfish-a16` patches (idempotent apply), sourced from EXTENDROM /
|
||||
AXP GOLDEN call-rec (and native FLAG_SECURE work), without Magisk modules.
|
||||
|
||||
**Why this priority**: Constitution: native ROM, attributable, reversible.
|
||||
|
||||
**Independent Test**: Patch script dry-run; tree markers; no Magisk zip in
|
||||
artifacts required for the feature to work after flash.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a clean LOS tree after `repo sync`, **When** the apply script
|
||||
runs, **Then** it is idempotent and records source attribution.
|
||||
2. **Given** a flashed LAB image, **When** Magisk is not installed, **Then**
|
||||
both toggles still function.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Dialer path renamed on A16 → re-locate gate; do not assume A11 overlay paths.
|
||||
- Call recording legal in some jurisdictions only → UI must warn; feature does
|
||||
not claim legality.
|
||||
- Some capture paths (DRM / hardware buffers) may still block — document if a
|
||||
specific path remains blocked after toggle ON.
|
||||
- `user` builds: follow same policy as `005` for whether DO toggles are
|
||||
available (document decision in plan if it differs from `userdebug` LAB).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST expose Developer Options switch **Disable call
|
||||
recording restrictions** backed by
|
||||
`Settings.Secure.extendrom_call_recording` ∈ {`0`,`1`}, default `0`.
|
||||
- **FR-002**: When that setting is `1`, Dialer MUST NOT deny call recording
|
||||
solely due to country/region restriction logic.
|
||||
- **FR-003**: When that setting is `0`, Dialer MUST use stock restriction
|
||||
behaviour.
|
||||
- **FR-004**: System MUST expose Developer Options switch **Allow screenshots
|
||||
of secure windows** backed by
|
||||
`Settings.Secure.disable_secure_windows` (DO: `allow_flag_secure_override`) ∈ {`0`,`1`}, default `0`.
|
||||
- **FR-005**: When that setting is `1`, system screenshot and screen-capture
|
||||
paths MUST allow capture of windows that set `FLAG_SECURE` (global).
|
||||
- **FR-006**: When that setting is `0`, `FLAG_SECURE` MUST behave as stock.
|
||||
- **FR-007**: Both settings MUST reset to `0` when Developer Options is turned
|
||||
off (same pattern as EXTENDROM / `005`).
|
||||
- **FR-008**: Implementation MUST NOT require Magisk, LSPosed, or Zygisk at
|
||||
runtime.
|
||||
- **FR-009**: Patches MUST be attributable (EXTENDROM/`er.sh` F_CALLREC for
|
||||
call-rec; native frameworks for FLAG_SECURE) and apply via
|
||||
`vendor/sunfish-a16/patches/…`.
|
||||
- **FR-010**: Validation MUST be LAB-only (`11231JEC207477`).
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **SecureSetting**: `extendrom_call_recording`,
|
||||
`disable_secure_windows`.
|
||||
- **DeveloperOptionsController**: preference controllers writing those
|
||||
settings.
|
||||
- **DialerRecordingPolicy**: country/region gate gated by call-rec setting.
|
||||
- **SecureCapturePolicy**: framework capture/`FLAG_SECURE` enforcement gated
|
||||
by screenshot setting.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
- **SC-001**: On LAB, both settings read `0` after fresh boot / DO off.
|
||||
- **SC-002**: With call-rec toggle ON, operator completes a recorded call and
|
||||
stores evidence under `/srv/rom/artifacts/008-…/call-rec/`.
|
||||
- **SC-003**: With screenshot toggle ON, operator captures a previously secure
|
||||
window; evidence under `/srv/rom/artifacts/008-…/flag-secure/`.
|
||||
- **SC-004**: Toggles OFF restore stock deny behaviour for the same tests.
|
||||
- **SC-005**: Feature works on a Magisk-free LAB image.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- LOS 23.2 Dialer still has an identifiable country/region recording gate (or
|
||||
equivalent CarrierConfig path) that can be overridden.
|
||||
- “Screenshot” includes the system screenshot gesture and common screen-record
|
||||
entry points; exotic DRM paths may remain blocked (document).
|
||||
- FLAG_SECURE is **global only** (not planned: per-app lists).
|
||||
- `007` remains incomplete; this feature does not depend on KernelSU.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- AXP full call-recording automation UI.
|
||||
- Per-app FLAG_SECURE lists.
|
||||
- Relocked AVB / signed release (`011`).
|
||||
- Banking PASS (`007`).
|
||||
@@ -0,0 +1,226 @@
|
||||
# Tasks: Call recording unlock + FLAG_SECURE override (`008`/`009`)
|
||||
|
||||
**Input**: Design docs from `/specs/008-call-rec-flag-secure/`
|
||||
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`,
|
||||
`contracts/`, `quickstart.md`; constitution native-ROM rules; **AXP GOLDEN /
|
||||
EXTENDROM call-rec model** (not Magisk modules)
|
||||
|
||||
**Primary oracle (call-rec)**: AXP/EXTENDROM native stack — same Secure key
|
||||
already observed on GOLDEN LAB dump
|
||||
(`.local-artifacts/002-golden/…/settings/secure-*.txt` →
|
||||
`extendrom_call_recording=1`):
|
||||
|
||||
| Piece | Host reference |
|
||||
|-------|----------------|
|
||||
| Apply logic | `/srv/rom/references/extendrom/er.sh` (`F_CALLREC` / unrestricted call recording) |
|
||||
| DO controllers | `/srv/rom/references/extendrom/config/call-rec/…/CallRecPreferenceController.java` (+ Info) |
|
||||
| Strings / Dialer config overlay | `/srv/rom/references/extendrom/overlays/call-rec/` |
|
||||
| Docs | `/srv/rom/references/axp/archive/…/knowledge/callrec/` |
|
||||
|
||||
**FLAG_SECURE**: project-specific native DO (not AXP Pro catalog). Magisk
|
||||
modules are **agent-only mental aids** if ever consulted — **never** ship,
|
||||
install, or task-move zips into the tree.
|
||||
|
||||
**Organization**: US1 call-rec (GOLDEN model) → US2 FLAG_SECURE → US3 packaging.
|
||||
|
||||
**Out of scope**: Magisk/Zygisk runtime; static Dialer RRO product; per-app
|
||||
FLAG_SECURE lists (not planned); full AXP auto-record policy UI; `007`; GOLDEN
|
||||
flash; commit/MR.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete deps)
|
||||
- **[Story]**: US1…US3 from `spec.md`
|
||||
|
||||
## Path conventions
|
||||
|
||||
- Meta repo: `vendor/sunfish-a16/`, `docs/`, `specs/008-call-rec-flag-secure/`
|
||||
- Build host: `/srv/rom/src/lineage/`, `/srv/rom/references/extendrom/`,
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/`
|
||||
- GOLDEN settings sample (read-only): `.local-artifacts/002-golden/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Artifact dirs + patch scaffolding; **no Magisk zip handling**
|
||||
|
||||
- [x] T001 [P] Create host dirs `/srv/rom/artifacts/008-call-rec-flag-secure/`
|
||||
(`call-rec/`, `flag-secure/`) and `/srv/rom/logs/008-build/`
|
||||
(android-build writable)
|
||||
- [x] T002 [P] Add stub `docs/008-call-rec-flag-secure-runbook.md` (GOLDEN/
|
||||
EXTENDROM call-rec map, Secure keys, LAB serial, apply order)
|
||||
- [x] T003 [P] Create `vendor/sunfish-a16/patches/008-call-rec-flag-secure/README.md`
|
||||
(idempotent apply like `005-sigspoof`; attribute EXTENDROM/`er.sh` F_CALLREC;
|
||||
FLAG_SECURE as native project patch)
|
||||
|
||||
**Checkpoint**: Dirs + stubs exist
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Port map from GOLDEN/EXTENDROM onto LOS 23.2 paths; Secure key
|
||||
plumbing; **no bacon yet**
|
||||
|
||||
**⚠️ CRITICAL**: Blocks all user stories
|
||||
|
||||
- [x] T004 Extract F_CALLREC steps from
|
||||
`/srv/rom/references/extendrom/er.sh` into a checklist in
|
||||
`docs/008-call-rec-flag-secure-runbook.md` (Settings controllers, Secure
|
||||
`ER_ALLOW_ANY_CALL_REC` = `"extendrom_call_recording"`, DO XML, Dialer
|
||||
`CallRecorder.canRecordInCurrentCountry` early-return, Dialer
|
||||
`config.xml` overlay)
|
||||
- [x] T005 [P] Confirm LOS 23.2 Dialer still uses
|
||||
`/srv/rom/src/lineage/packages/apps/Dialer/java/com/android/incallui/call/CallRecorder.java`
|
||||
and that stock `call_recording_enabled` / audio source match or need
|
||||
EXTENDROM overlay (`call_recording_enabled=true`,
|
||||
`call_recording_audio_source=4`)
|
||||
- [x] T006 [P] Inventory A16 `FLAG_SECURE` / screenshot / screen-record sites
|
||||
under `/srv/rom/src/lineage/frameworks/base/` (+ SystemUI); list candidates
|
||||
in the runbook (native source patches only)
|
||||
- [x] T007 [P] Locate Settings development dashboard +
|
||||
`development_settings.xml` paths on LOS 23.2 (same family as `005`)
|
||||
- [x] T008 Scaffold idempotent
|
||||
`vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py`
|
||||
(dry-run + markers; body filled by story tasks)
|
||||
|
||||
**Checkpoint**: Foundation ready — US1/US2 can proceed in parallel
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — Call recording (GOLDEN / EXTENDROM model) (P1) 🎯 MVP
|
||||
|
||||
**Goal**: Native DO **Disable call recording restrictions** writing Secure
|
||||
`extendrom_call_recording` (GOLDEN-compatible); Dialer allows any country when
|
||||
`1`
|
||||
|
||||
**Independent Test**: `adb shell settings get secure extendrom_call_recording`;
|
||||
toggle; record call per `quickstart.md` and
|
||||
`contracts/call-recording-surface.md`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [x] T009 [P] [US1] Port EXTENDROM strings + DO category/switch/info into
|
||||
`/srv/rom/src/lineage/packages/apps/Settings/` (keys
|
||||
`extendrom_call_recording*`, legal details text from EXTENDROM overlay)
|
||||
- [x] T010 [P] [US1] Add `ER_CallRecPreferenceController` + `ER_CallRecInfo`
|
||||
(or equivalent names) under Settings development; wire into
|
||||
`DevelopmentSettingsDashboardFragment`; reset Secure to `0` when DO
|
||||
master disabled
|
||||
- [x] T011 [US1] Add
|
||||
`Settings.Secure.ER_ALLOW_ANY_CALL_REC = "extendrom_call_recording"` in
|
||||
`/srv/rom/src/lineage/frameworks/base/core/java/android/provider/Settings.java`
|
||||
- [x] T012 [US1] Patch
|
||||
`CallRecorder.canRecordInCurrentCountry()` to early-return `true` when
|
||||
`Settings.Secure.getInt(…, "extendrom_call_recording", 0) == 1` (same
|
||||
injection as `er.sh` F_CALLREC)
|
||||
- [x] T013 [P] [US1] Ensure Dialer call-rec config enabled for sunfish
|
||||
(EXTENDROM overlay values) under Dialer
|
||||
`callrecord/res/values/config.xml` or product overlay
|
||||
- [x] T014 [US1] Encode US1 changes into
|
||||
`vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py`
|
||||
with EXTENDROM/`er.sh` attribution
|
||||
- [ ] T015 [US1] LAB validate *(blocked: wait 008-bacon + Magisk-free flash)* on `11231JEC207477`; evidence under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/call-rec/`
|
||||
|
||||
**Checkpoint**: US1 independently testable (MVP)
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Global FLAG_SECURE override (P1)
|
||||
|
||||
**Goal**: DO **Allow screenshots of secure windows** → Secure
|
||||
`allow_flag_secure_override`; native capture paths honour it globally
|
||||
|
||||
**Independent Test**: Secure window OFF fail / ON success;
|
||||
`settings get secure allow_flag_secure_override`; `quickstart.md` §FLAG_SECURE
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [x] T016 [P] [US2] Settings strings + switch for FLAG_SECURE override under
|
||||
`/srv/rom/src/lineage/packages/apps/Settings/`
|
||||
- [x] T017 [P] [US2] Preference controller for
|
||||
`Settings.Secure.allow_flag_secure_override` with DO-master reset to `0`
|
||||
- [x] T018 [US2] Implement override in inventoried frameworks/SystemUI paths
|
||||
(T006) — **source only**, no jar binary patchers
|
||||
- [x] T019 [US2] Encode US2 into
|
||||
`vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py`
|
||||
- [ ] T020 [US2] LAB validate *(blocked: wait 008-bacon + Magisk-free flash)*; evidence under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/flag-secure/`; note any
|
||||
remaining DRM blocks in the runbook
|
||||
|
||||
**Checkpoint**: US1 + US2 both work
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Native attributable packaging (P2)
|
||||
|
||||
**Goal**: Idempotent `vendor/sunfish-a16` apply; Magisk-free image
|
||||
|
||||
**Independent Test**: Apply dry-run twice; feature works without Magisk
|
||||
(SC-005)
|
||||
|
||||
- [x] T021 [US3] Finish apply script (idempotent, backups, clear missing-path
|
||||
errors); README lists every touched path
|
||||
- [ ] T022 [US3] Apply on `rom-dev01`, bacon detached *(apply done; bacon session `008-bacon` running)* via
|
||||
`/srv/rom/artifacts/bin/rom-detach`, flash LAB **without** Magisk modules
|
||||
for this feature
|
||||
- [ ] T023 [US3] Record Magisk-free PASS *(blocked: post-flash)* under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/` + runbook
|
||||
|
||||
**Checkpoint**: Packaging complete
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting
|
||||
|
||||
- [x] T024 [P] Sync `docs/008-009-design.md`, `research.md`, contracts, and
|
||||
GOLDEN inventory note (`extendrom_call_recording` on GOLDEN) with final
|
||||
A16 paths
|
||||
- [x] T025 [P] Verify DO master-off resets **both** Secure keys to `0`
|
||||
- [ ] T026 Run full `quickstart.md` *(blocked: post-flash)* checklist; evidence index README under
|
||||
`/srv/rom/artifacts/008-call-rec-flag-secure/`
|
||||
- [x] T027 [P] Document `user` vs `userdebug` DO availability (same caution as
|
||||
`005`)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
- **Setup → Foundational → US1 ∥ US2 → US3 → Polish**
|
||||
- **US1** after Phase 2; no dep on US2
|
||||
- **US2** after Phase 2; no dep on US1 (coordinate Settings XML)
|
||||
- **US3** after US1+US2 encoded in apply script
|
||||
|
||||
### Parallel opportunities
|
||||
|
||||
- T001 ∥ T002 ∥ T003
|
||||
- T004 then T005 ∥ T006 ∥ T007
|
||||
- After Phase 2: US1 track (T009–T013) ∥ US2 track (T016–T018)
|
||||
- T024 ∥ T025 ∥ T027
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP
|
||||
|
||||
1. Setup + Foundational (esp. T004/T005 from `er.sh`)
|
||||
2. US1 GOLDEN call-rec → LAB evidence
|
||||
3. Then US2 FLAG_SECURE
|
||||
4. US3 packaging + Magisk-free proof
|
||||
|
||||
### Suggested MVP scope
|
||||
|
||||
**US1 only** (native EXTENDROM/GOLDEN call-rec). US2 still required before
|
||||
calling roadmap `008`+`009` done.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Product is **native ROM** patches. Magisk zips are not part of the feature.
|
||||
- Prefer Secure-setting Dialer gate (GOLDEN) over always-on country XML RRO.
|
||||
- Prefer frameworks source patches over `services.jar` binary patching.
|
||||
- LAB only: `11231JEC207477`. Owner handles commit/MR.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Specification Quality Checklist: AXP LOS22 feature port to LOS23
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-09-16
|
||||
**Updated**: 2026-09-16 (owner clarifications applied)
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Clarifications resolved: Magisk like GOLDEN (newest; AXP preinstall state);
|
||||
full AXP resurrection including hardening/signing/AVB; WebView = LOS23
|
||||
default with chooser unlocked (Aosmium EOL); Phonesky = project recent
|
||||
patched artifact (reconsider if GOLDEN-class fixes missing); microG newest
|
||||
+ integrated; spoofing and call recording selectable; KernelSU out of ship
|
||||
for now with optional recycle of existing `007` functional kernels (FR-016).
|
||||
- Named product components (microG, Phonesky, Magisk, Island) appear because
|
||||
they are the resurrection surface, not implementation design.
|
||||
- Ready for `/speckit-plan` (optional `/speckit-clarify` only if new gaps).
|
||||
@@ -0,0 +1,53 @@
|
||||
# Contract: LAB acceptance gates (`009`)
|
||||
|
||||
**Device**: LAB `11231JEC207477` only — never GOLDEN
|
||||
**Evidence**: `/srv/rom/artifacts/009-axp-los23-port/<build-id>/`
|
||||
|
||||
## Gate A — Boot / hardware
|
||||
|
||||
- [ ] Clean flash boots to home
|
||||
- [ ] Call + Wi‑Fi + unlock smoke (vanilla class)
|
||||
|
||||
## Gate B — Google stack
|
||||
|
||||
- [ ] microG Self-Check required items pass with spoofing ON as needed
|
||||
- [ ] Project Phonesky opens; ordinary app install/update works
|
||||
- [ ] No FakeStore primary
|
||||
- [ ] Version pins: microG/GSF newest stable; Phonesky = project artifact
|
||||
- [ ] If Play lacks GOLDEN-class fix → **FAIL closed** (reconsider Phonesky)
|
||||
|
||||
## Gate C — Toggles
|
||||
|
||||
- [ ] Spoofing OFF/ON behaviour per `toggles-surface.md`
|
||||
- [ ] Call-rec OFF/ON behaviour per `toggles-surface.md`
|
||||
|
||||
## Gate D — Magisk
|
||||
|
||||
- [ ] Preinstall state matches measured GOLDEN/AXP class
|
||||
- [ ] Activation documented and completed on LAB
|
||||
- [ ] DenyList-class hides root from a test/banking package
|
||||
|
||||
## Gate E — Banking
|
||||
|
||||
- [ ] Island present; Swissquote PASS in managed profile workflow
|
||||
- [ ] Yuh recorded; not worse than GOLDEN for packaging/spoofing reasons
|
||||
- [ ] Banks do not receive root
|
||||
|
||||
## Gate F — Usability / WebView
|
||||
|
||||
- [ ] Bundled AXP categories present or documented impossible
|
||||
- [ ] Versions newest workable (except Phonesky rule)
|
||||
- [ ] WebView default LOS; chooser unlocked
|
||||
|
||||
## Gate G — Hardening / signing class
|
||||
|
||||
- [ ] GOLDEN-class hardening/signing/AVB posture present **or** each gap
|
||||
documented as impossible on this stack (no silent omit)
|
||||
- [ ] Staged known-good images retained for bisect
|
||||
|
||||
## Non-gates
|
||||
|
||||
- KernelSU presence or SusFS
|
||||
- FLAG_SECURE override (optional)
|
||||
- Custom AXP backup ROM feature
|
||||
- Yuh PASS if GOLDEN attestation path still FAILs equivalently
|
||||
@@ -0,0 +1,38 @@
|
||||
# Contract: Magisk preinstall (AXP / GOLDEN class)
|
||||
|
||||
**Ship root**: Magisk (newest stable that works on this stack)
|
||||
**Not ship**: KernelSU / SusFS (`007` optional recycle only)
|
||||
|
||||
## Behavioural contract
|
||||
|
||||
1. After a clean `009` flash, Magisk is **present** in an AXP-like
|
||||
**preinstalled but not fully activated** state (exact files/UI measured
|
||||
from GOLDEN — document in LAB runbook).
|
||||
2. Owner can complete activation on LAB using documented steps.
|
||||
3. DenyList-class configuration can hide root from banking packages before
|
||||
first process start (GOLDEN workflow).
|
||||
4. Magisk version in the version-pin record is newest workable stable, not an
|
||||
accidental stale host copy.
|
||||
|
||||
## Banking interaction
|
||||
|
||||
Aurora install → do not open → DenyList (incl. processes) → Island clone →
|
||||
first launch in Island. Banks MUST NOT receive root.
|
||||
|
||||
## Out of contract
|
||||
|
||||
- Shipping Magia branding specifically ( Magisk upstream UI OK if behaviour
|
||||
matches).
|
||||
- Requiring KernelSU coexistence on the same ship image.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
# After flash (pre-activation): document paths/props matching GOLDEN notes
|
||||
adb shell ls -l /system_ext/bin/magisk 2>/dev/null || true
|
||||
adb shell pm list packages | grep -iE 'magisk|magia'
|
||||
|
||||
# After activation: Magisk app reports version; DenyList configurable
|
||||
```
|
||||
|
||||
Evidence under `/srv/rom/artifacts/009-axp-los23-port/magisk/`.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Contract: system packages (AXP resurrection)
|
||||
|
||||
**Device**: LAB only
|
||||
**Build**: `009` product with Google stack + bundled AXP usability set
|
||||
|
||||
## Required packages (minimum)
|
||||
|
||||
| Role | Package | Notes |
|
||||
|------|---------|--------|
|
||||
| microG | `com.google.android.gms` | Newest stable verified; system |
|
||||
| GSF Proxy | `com.google.android.gsf` | Newest stable verified |
|
||||
| Phonesky | `com.android.vending` | Project patched priv-app; host artifact |
|
||||
| Island | `com.oasisfeng.island…` | GOLDEN tool; newest workable |
|
||||
| Magisk UI / stubs | as measured on GOLDEN | Preinstall layout; not fully activated until setup |
|
||||
|
||||
FakeStore / conflicting Companion MUST NOT be the primary Play path.
|
||||
|
||||
## Bundled usability set
|
||||
|
||||
Ship GOLDEN/AXP categories at newest workable stables (Aurora, F-Droid/repos as
|
||||
on GOLDEN, launcher/gallery-class, DNS/hosts helpers if in inventory). Exact
|
||||
package list = version-pin record derived from `002` + acceptance notes.
|
||||
|
||||
## WebView
|
||||
|
||||
- Default provider = LOS23 WebView package.
|
||||
- Aosmium MUST NOT be required.
|
||||
- `cmd webviewupdate` / Developer options chooser MUST remain usable.
|
||||
|
||||
## Verification snippets
|
||||
|
||||
```bash
|
||||
adb shell pm path com.google.android.gms
|
||||
adb shell pm path com.google.android.gsf
|
||||
adb shell pm path com.android.vending
|
||||
adb shell cmd package list packages | grep -E 'island|aurora|fdroid|magisk|magia'
|
||||
adb shell cmd webviewupdate current
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
# Contract: selectable toggles (spoofing + call recording)
|
||||
|
||||
**Surface**: Developer Options (AXP-like)
|
||||
**Defaults**: OFF (`0`) unless a documented project default says otherwise
|
||||
|
||||
## Signature spoofing
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| Secure key | `allow_signature_fake` (GOLDEN/AXP class from `005`) |
|
||||
| OFF | Spoofing has no effect even if prior grants exist |
|
||||
| ON | Authorized packages (microG, Phonesky) may use restricted spoofing |
|
||||
| Forbidden | Unrestricted platform spoofing for arbitrary apps |
|
||||
|
||||
```bash
|
||||
adb shell settings get secure allow_signature_fake
|
||||
# expect 0/null default; 1 when enabled
|
||||
```
|
||||
|
||||
## Call recording unlock
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| Secure key | `extendrom_call_recording` |
|
||||
| OFF | Stock LOS country/carrier-style Dialer policy |
|
||||
| ON | Dialer `canRecordInCurrentCountry()` allows recording |
|
||||
|
||||
```bash
|
||||
adb shell settings get secure extendrom_call_recording
|
||||
# expect 0/null default; 1 when enabled
|
||||
```
|
||||
|
||||
## Optional (not AXP hard gate)
|
||||
|
||||
`disable_secure_windows` / FLAG_SECURE override may ship if already wired
|
||||
(`008`); absence does not fail AXP resurrection acceptance.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Contract: WebView policy
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| Default | LineageOS 23 WebView |
|
||||
| Aosmium | Not shipped / not required (EOL) |
|
||||
| Chooser | Developer options → WebView implementation remains available |
|
||||
| Future | User may install an alternate WebView and select it |
|
||||
|
||||
```bash
|
||||
adb shell cmd webviewupdate current
|
||||
# default should be LOS provider, not org.axpos.aosmium
|
||||
|
||||
adb shell cmd webviewupdate
|
||||
# provider list / update path must not be locked to a single forced package
|
||||
```
|
||||
@@ -0,0 +1,106 @@
|
||||
# Data model: `009-axp-los23-port`
|
||||
|
||||
## Entities
|
||||
|
||||
### VanillaBaseline
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| source | string | `003` LOS 23.2 sunfish (or documented equivalent) |
|
||||
| manifest_rev | string | recorded repo manifest revision |
|
||||
| lab_smoke | enum | `pass` required before AXP integrate stages |
|
||||
|
||||
### AxpCapabilitySet
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| category | string | e.g. google-stack, magisk, banking, call-rec, bundled-apps, hardening |
|
||||
| golden_ref | string | pointer into `002` / AXP Pro row |
|
||||
| status | enum | `required` \| `exception` \| `impossible` |
|
||||
| notes | string | WebView=exception; others default required |
|
||||
|
||||
### VersionPinRecord
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| component | string | microG, GSF, Magisk, Island, Aurora, … |
|
||||
| version_name | string | human version |
|
||||
| version_code | int/string | as applicable |
|
||||
| upstream_ref | string | tag/commit/URL |
|
||||
| policy | enum | `newest_stable` \| `project_phonesky` \| `los_default` |
|
||||
| verified_on | date | LAB verification date |
|
||||
|
||||
**Phonesky row**: `policy=project_phonesky` — must match host artifact id, not
|
||||
“newest Play on internet”.
|
||||
|
||||
### PhoneskyHostArtifact
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| path | string | under `/srv/rom/prebuilts/phonesky/` (not Git) |
|
||||
| package | string | `com.android.vending` |
|
||||
| signature | string | project/patch pipeline identity |
|
||||
| privapp | bool | must be true |
|
||||
| golden_fix_gap | bool | if true → halt acceptance / reconsider |
|
||||
|
||||
### MagiskPreinstallState
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| magisk_version | string | newest stable verified |
|
||||
| layout | string | measured GOLDEN/AXP preinstalled-not-fully-activated |
|
||||
| activated_on_lab | bool | true after owner completes setup |
|
||||
| denylist | set | banking packages hidden from root |
|
||||
|
||||
**Transitions**: `flashed_preinstall` → `activated` → `denylist_configured`
|
||||
→ `banking_ready`.
|
||||
|
||||
### SecureToggle
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| key | string | `allow_signature_fake` or `extendrom_call_recording` |
|
||||
| value | int | `0` default / `1` on |
|
||||
| surface | string | Developer Options |
|
||||
|
||||
### ManagedProfileBanking
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| tool | string | Island (`com.oasisfeng.island…`) |
|
||||
| swissquote | enum | `pass` required |
|
||||
| yuh | enum | `pass` \| `fail_attestation_like_golden` \| `fail_regression` |
|
||||
| root_to_banks | bool | must be false |
|
||||
|
||||
### WebViewPolicy
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| default_provider | string | LOS23 WebView |
|
||||
| aosmium | bool | must be false (not required/shipped) |
|
||||
| chooser_unlocked | bool | must be true |
|
||||
|
||||
### LabAcceptanceBuild
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| artifact_dir | string | `/srv/rom/artifacts/009-axp-los23-port/…` |
|
||||
| hashes | map | SHA-256 of flashables |
|
||||
| version_pins | ref | VersionPinRecord set |
|
||||
| gates | ref | contracts/acceptance-gates.md checklist |
|
||||
|
||||
### OptionalKsuRecycleAsset
|
||||
|
||||
| Field | Type | Rules |
|
||||
|-------|------|--------|
|
||||
| path | string | existing `007` kernel/artifact |
|
||||
| used_for | string | optional debug/reference |
|
||||
| ship | bool | always false unless future spec says otherwise |
|
||||
|
||||
## Relationships
|
||||
|
||||
- `LabAcceptanceBuild` includes one `VersionPinRecord` set + Magisk state +
|
||||
toggle defaults + banking results + WebViewPolicy.
|
||||
- `PhoneskyHostArtifact` feeds product packaging; never stored in Git.
|
||||
- `AxpCapabilitySet` drives which bundled packages appear in pins.
|
||||
- `OptionalKsuRecycleAsset` must not appear as required on acceptance gates.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Implementation Plan: AXP LOS22 feature port to LOS23 (resurrection)
|
||||
|
||||
**Branch**: `009-axp-los23-port` | **Date**: 2026-09-16 | **Spec**: [spec.md](./spec.md)
|
||||
|
||||
**Input**: Feature specification from `/specs/009-axp-los23-port/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Resurrect **AXP.OS Pro on LOS22 / GOLDEN** as a single shippable LineageOS
|
||||
23.2 / Android 16 `sunfish` ROM on **LAB**: vanilla `003` base + full AXP
|
||||
capability set (Google stack, selectable spoofing, Island banking workflow,
|
||||
selectable call-recording unlock, Magisk like GOLDEN, bundled usability apps,
|
||||
GOLDEN-class hardening/signing/AVB posture).
|
||||
|
||||
**Explicit exceptions:** LOS23 WebView default (Aosmium EOL) with unlocked
|
||||
provider chooser; Phonesky = project's recent patched artifact (reconsider if
|
||||
GOLDEN-class fixes missing); KernelSU (`007`) out of ship for now with optional
|
||||
recycle of existing functional kernels (FR-016).
|
||||
|
||||
**Approach:** reuse proven `004`/`005`/`008` runbooks and `vendor/sunfish-a16`
|
||||
packaging where they already match; replace the KernelSU ship path with
|
||||
AXP-style Magisk preinstall (newest Magisk); pin newest stable microG and
|
||||
bundled apps; keep Phonesky on the existing host pipeline; measure Magisk
|
||||
“preinstalled but not fully activated” behaviour on GOLDEN before freezing LAB
|
||||
setup docs.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Android product makefiles / Soong; Java/Kotlin Settings +
|
||||
Dialer + frameworks patches; bash runbooks on `rom-dev01`
|
||||
**Primary Dependencies**: LOS 23.2 sunfish tree; microG + GSF releases; project
|
||||
patched Phonesky host artifacts; Magisk (newest stable that works on this
|
||||
stack); Island; AXP/GOLDEN inventory (`002`); EXTENDROM call-rec reference;
|
||||
existing `vendor/sunfish-a16` overlays/patches from `004`/`005`/`008`
|
||||
**Storage**: Host `/srv/rom/prebuilts/`, `/srv/rom/secrets/`,
|
||||
`/srv/rom/artifacts/009-axp-los23-port/`; meta-repo docs + `vendor/sunfish-a16`
|
||||
scripts (no proprietary APKs in Git)
|
||||
**Testing**: LAB flash/`adb`; microG Self-Check; Play install; Island +
|
||||
Swissquote/Yuh; Magisk DenyList-class; DO toggles; version-pin record
|
||||
**Target Platform**: Pixel 4a LAB `11231JEC207477`; Android 16 / LOS 23.2
|
||||
**Project Type**: Android custom ROM (product overlay + attributable patches)
|
||||
**Performance Goals**: N/A (daily-driver correctness / parity)
|
||||
**Constraints**: LAB only; no GOLDEN flash; no Phonesky bytes in Git; Magisk
|
||||
ship root (not KernelSU); newest stables except Phonesky artifact rule;
|
||||
attributable reversible changes; long builds detached on `rom-dev01`
|
||||
**Scale/Scope**: Full AXP resurrection surface in one feature (Google stack,
|
||||
toggles, Magisk, bundled apps, hardening/signing class); **parallel track**
|
||||
to the standby KernelSU / split roadmap (`004`–`008`/`007`), reusing their
|
||||
artifacts without deleting that track
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| LAB only; never GOLDEN | pass |
|
||||
| Spec-as-source for active feature requirements | pass (`009` normative for ship) |
|
||||
| Functionality first; AXP compatibility oracle | pass (resurrection goal) |
|
||||
| No proprietary Google APKs / secrets in Git | pass (host paths) |
|
||||
| Phonesky priv-app; no FakeStore primary | pass |
|
||||
| Restricted selectable spoofing (not open platform) | pass (reuse `005` class) |
|
||||
| Native call-rec unlock; re-validate A16 | pass (reuse `008` / EXTENDROM) |
|
||||
| Prefer native over LSPosed/Zygisk modules for ROM features | pass |
|
||||
| Small attributable reversible changes | pass (staged integrate; known-good images) |
|
||||
| Base = LOS 23.2 sunfish stack (no unrelated prebuilt kernel) | pass |
|
||||
| Constitution default root = KernelSU; no Magisk production stage | **variance** — see Complexity Tracking (owner ship decision in `009`) |
|
||||
| Signing/AVB historically `011` | **variance** — GOLDEN-class signing/AVB posture pulled into `009` acceptance (may stage inside feature) |
|
||||
|
||||
**Post-design**: Magisk ship + signing/AVB-in-`009` remain justified variances;
|
||||
KernelSU recycle stays optional (FR-016). Recommend a later constitution
|
||||
amendment to align Root architecture text with Magisk resurrection — not
|
||||
blocking this plan.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/009-axp-los23-port/
|
||||
├── plan.md # this file
|
||||
├── research.md # Phase 0
|
||||
├── data-model.md # Phase 1
|
||||
├── quickstart.md # Phase 1
|
||||
├── contracts/
|
||||
│ ├── packages.md
|
||||
│ ├── toggles-surface.md
|
||||
│ ├── magisk-preinstall.md
|
||||
│ ├── webview-surface.md
|
||||
│ └── acceptance-gates.md
|
||||
└── tasks.md # /speckit-tasks (not this command)
|
||||
```
|
||||
|
||||
### Host + tree
|
||||
|
||||
```text
|
||||
# Meta-repo
|
||||
vendor/sunfish-a16/ # product mk, permissions, patch apply
|
||||
docs/002-golden-inventory.md
|
||||
docs/004-phonesky-runbook.md
|
||||
docs/005-spoofing-runbook.md
|
||||
docs/008-call-rec-flag-secure-runbook.md
|
||||
docs/axp-pro-parity.md # non-normative; remap rows → 009 after tasks
|
||||
|
||||
# rom-dev01
|
||||
/srv/rom/src/lineage/ # LOS 23.2 sunfish tree
|
||||
/srv/rom/prebuilts/microg/ # newest microG + GSF
|
||||
/srv/rom/prebuilts/phonesky/ # project patched Phonesky (+ XMLs)
|
||||
/srv/rom/prebuilts/magisk/ # Magisk artifacts for AXP-like preinstall
|
||||
/srv/rom/prebuilts/axp-apps/ # bundled usability apps (newest stables)
|
||||
/srv/rom/secrets/ # Phonesky / later release keys (never Git)
|
||||
/srv/rom/artifacts/009-axp-los23-port/ # images, hashes, version pins, LAB evidence
|
||||
/srv/rom/artifacts/007-…/ # optional KSU kernels (recycle only)
|
||||
```
|
||||
|
||||
**Structure Decision**: Same meta-repo pattern as `004`/`005`/`008` —
|
||||
attributable packaging and patches via `vendor/sunfish-a16`; heavy tree and
|
||||
proprietary blobs only on `rom-dev01`. No megapatch dumps in Git.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|--------------------------------------|
|
||||
| Magisk as ship root (constitution prefers KernelSU; forbids Magisk production stage) | Owner chose **AXP resurrection** = Magisk like GOLDEN (`009` FR-010); KSU out of ship for now | Keeping KernelSU abandons “todo igual que AXP”; Magisk A/B-only diagnostic does not meet ship parity |
|
||||
| GOLDEN-class hardening/signing/AVB inside `009` (was split `011`–`013`) | Owner Q2 = full resurrection, not apps-only | Deferring signing/hardening recreates the decide-scatter `009` was meant to end |
|
||||
| Single Magisk-resurrection feature owns large surface | Simplifies current ship without deleting standby KSU track | Re-merging both tracks into one ambiguous roadmap recreates decide-scatter |
|
||||
|
||||
## Phase 0 / Phase 1
|
||||
|
||||
See `research.md`, `data-model.md`, `contracts/*`, `quickstart.md`.
|
||||
@@ -0,0 +1,81 @@
|
||||
# Quickstart: `009` AXP resurrection (LAB validation)
|
||||
|
||||
**Device**: LAB only `11231JEC207477`
|
||||
**Never**: flash / wipe / Magisk-change GOLDEN
|
||||
**Evidence**: `/srv/rom/artifacts/009-axp-los23-port/<build-id>/`
|
||||
**Contracts**: [packages](./contracts/packages.md),
|
||||
[toggles](./contracts/toggles-surface.md),
|
||||
[magisk](./contracts/magisk-preinstall.md),
|
||||
[webview](./contracts/webview-surface.md),
|
||||
[gates](./contracts/acceptance-gates.md)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `003` vanilla (or documented equivalent) known-good on LAB at least once
|
||||
- Host artifacts: newest microG/GSF, project Phonesky, Magisk prebuilts,
|
||||
bundled app set — under `/srv/rom/prebuilts/` (not Git)
|
||||
- GOLDEN Magisk preinstall notes measured (`adb` only) and copied into the
|
||||
build’s magisk runbook snippet
|
||||
- Prefer **clean flash** for acceptance (dirty upgrade from KSU LAB images is
|
||||
best-effort only)
|
||||
|
||||
## 1. Flash + Gate A
|
||||
|
||||
1. Flash `009` images from artifact dir; record SHA-256.
|
||||
2. Boot → unlock → place call → Wi‑Fi.
|
||||
3. Save `getprop` + brief notes under `…/gate-a/`.
|
||||
|
||||
## 2. Google stack + toggles (Gates B/C)
|
||||
|
||||
1. Enable Developer Options.
|
||||
2. Turn **Allow signature spoofing** ON; grant microG + Phonesky as required
|
||||
(`005` runbook class).
|
||||
3. microG Self-Check → screenshot.
|
||||
4. Open Phonesky → install/update one ordinary app.
|
||||
5. Confirm Secure keys:
|
||||
|
||||
```bash
|
||||
adb -s 11231JEC207477 shell settings get secure allow_signature_fake
|
||||
adb -s 11231JEC207477 shell settings get secure extendrom_call_recording
|
||||
```
|
||||
|
||||
6. Call-rec: ON → record a call → OFF → note stock policy.
|
||||
7. Record version pins (microG, GSF, Phonesky artifact id).
|
||||
|
||||
## 3. Magisk (Gate D)
|
||||
|
||||
1. Document pre-activation state vs GOLDEN notes.
|
||||
2. Complete Magisk activation per runbook.
|
||||
3. Configure DenyList-class hide for a banking package **before** first open.
|
||||
4. Save Magisk version + screenshots under `…/magisk/`.
|
||||
|
||||
## 4. Banking (Gate E)
|
||||
|
||||
1. Aurora → install Swissquote → **do not open**.
|
||||
2. DenyList → Island clone → first launch in Island → login.
|
||||
3. Repeat attempt for Yuh; classify PASS / attestation-like-GOLDEN /
|
||||
packaging regression.
|
||||
4. Confirm banks lack root.
|
||||
|
||||
## 5. Usability + WebView (Gate F)
|
||||
|
||||
1. Confirm bundled categories vs pin record.
|
||||
2. `adb shell cmd webviewupdate current` → LOS default; chooser still listed.
|
||||
|
||||
## 6. Hardening / signing class (Gate G)
|
||||
|
||||
1. Run the hardening/signing checklist defined for this build stage.
|
||||
2. Any missing GOLDEN-class item → written impossible/gap note (no silent
|
||||
skip).
|
||||
|
||||
## Pass criteria
|
||||
|
||||
All boxes in [acceptance-gates.md](./contracts/acceptance-gates.md) for the
|
||||
claimed stage. Full resurrection acceptance = Gates A–G.
|
||||
|
||||
## Notes
|
||||
|
||||
- Optional `007` kernels: may flash for debug only; do not claim ship.
|
||||
- Call-recording legality is the user’s responsibility.
|
||||
- If project Phonesky misbehaves vs GOLDEN needs → stop and reconsider; do
|
||||
not accept Gate B.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Research: `009-axp-los23-port`
|
||||
|
||||
## Decision: Product = AXP resurrection on LOS 23.2 (parallel track)
|
||||
|
||||
**Decision**: Treat `009` as the normative ship feature **for the Magisk AXP
|
||||
resurrection track** that ports the AXP.OS / GOLDEN LOS22 capability set onto
|
||||
LineageOS 23.2 vanilla (`003`), with only the explicit exceptions in the spec
|
||||
(WebView, Phonesky artifact, optional KSU recycle). Keep the prior KernelSU /
|
||||
split roadmap (`004`–`008`/`007` + deferred items) on a **standby git branch**
|
||||
without deleting or rewriting those specs.
|
||||
|
||||
**Rationale**: Owner wants Magisk “todo igual” to AXP now, without throwing
|
||||
away the earlier KSU investment; either track may resume later.
|
||||
|
||||
**Alternatives considered**: Hard-supersede/delete the split roadmap —
|
||||
rejected (owner wants standby). Continue only KSU track — rejected for
|
||||
current ship preference.
|
||||
|
||||
## Decision: Magisk ship root (constitution variance)
|
||||
|
||||
**Decision**: Ship **Magisk** like GOLDEN — newest Magisk stable that works on
|
||||
sunfish / LOS 23.2 — in an AXP-like **preinstalled but not fully activated**
|
||||
layout. Measure the exact first-boot/setup UX on GOLDEN (`adb` only) before
|
||||
freezing LAB instructions. DenyList-class hiding for banks.
|
||||
|
||||
**Rationale**: FR-010 / owner clarification; true AXP resurrection requires
|
||||
Magisk/Magia-class root, not KernelSU.
|
||||
|
||||
**Alternatives considered**:
|
||||
|
||||
- KernelSU-Next (`007`) as ship — rejected for this feature (out of ship for
|
||||
now).
|
||||
- Rootless ship — rejected (banking DenyList workflow is part of GOLDEN).
|
||||
- Magisk only as temporary A/B diagnostic — insufficient for resurrection
|
||||
acceptance.
|
||||
|
||||
**Follow-up (non-blocking)**: Amend constitution Root architecture section in
|
||||
a later docs pass so it no longer contradicts Magisk-as-ship.
|
||||
|
||||
## Decision: Optional recycle of `007` kernels (FR-016)
|
||||
|
||||
**Decision**: Keep the two functional KernelSU kernels/artifacts. Reuse only
|
||||
if helpful (boot reference, differential debug, later optional path). Never
|
||||
gate Magisk acceptance on KSU work.
|
||||
|
||||
**Alternatives considered**: Delete `007` artifacts — rejected (sunk cost;
|
||||
optional value). Force dual-boot Magisk+KSU ship — rejected (complexity).
|
||||
|
||||
## Decision: Reuse `004`/`005` Google stack; bump microG; keep project Phonesky
|
||||
|
||||
**Decision**:
|
||||
|
||||
- microG GmsCore + GSF = **newest stable** (or newest tagged pre-release
|
||||
upstream ships) verified on this stack; integrate with Phonesky as in AXP.
|
||||
- Phonesky = **project patched artifact** from the recent host pipeline
|
||||
(`docs/004-phonesky-runbook.md` / `/srv/rom/prebuilts/phonesky/`), not a
|
||||
blind newest Play download.
|
||||
- If LAB shows missing GOLDEN-class Play fixes with that artifact → **halt**
|
||||
and reconsider Phonesky (spec edge case), do not silently ship FakeStore.
|
||||
- Signature spoofing = selectable DO toggle (`allow_signature_fake` class from
|
||||
`005`); restricted grants for microG + Phonesky only.
|
||||
|
||||
**Alternatives considered**: Newest Play APK every week without project patch
|
||||
pipeline — rejected (breaks reproducible priv-app signing). FakeStore —
|
||||
forbidden. Re-implement spoofing from scratch — reuse `005` unless A16 gaps.
|
||||
|
||||
## Decision: Selectable call recording = EXTENDROM / `008` model
|
||||
|
||||
**Decision**: Ship selectable call-recording unlock using GOLDEN-compatible
|
||||
`Settings.Secure.extendrom_call_recording` + Dialer gate (EXTENDROM
|
||||
`F_CALLREC` / `008` research). Default OFF.
|
||||
|
||||
**Alternatives considered**: Magisk Dialer RRO — rejected (not selectable /
|
||||
not native). Blind old XML overlays — rejected for A16.
|
||||
|
||||
**Note**: Project `FLAG_SECURE` override remains optional vs AXP acceptance;
|
||||
may ship if `008` work is cheap to include.
|
||||
|
||||
## Decision: WebView = LOS23 default, chooser unlocked
|
||||
|
||||
**Decision**: Do not ship Aosmium (EOL). Default = LineageOS 23 WebView.
|
||||
Preserve Android multi-provider selection (Developer options → WebView
|
||||
implementation).
|
||||
|
||||
**Alternatives considered**: Bundle Vanadium/AOSmium fork — rejected (EOL /
|
||||
out of scope). Lock single provider — rejected (FR-015).
|
||||
|
||||
## Decision: Bundled apps = GOLDEN/AXP categories @ newest stable
|
||||
|
||||
**Decision**: Enumerate categories from `002` + AXP Pro catalog (Island,
|
||||
Aurora, F-Droid/repos as on GOLDEN, launcher/gallery-class, DNS/hosts privacy
|
||||
helpers if present). Install newest workable stables; pin versions in the
|
||||
acceptance record. Island remains the managed-profile tool (measured on
|
||||
GOLDEN).
|
||||
|
||||
**Alternatives considered**: LOS defaults only — fails resurrection. Exact
|
||||
GOLDEN version freeze — rejected (owner wants newest stables except
|
||||
Phonesky).
|
||||
|
||||
## Decision: Hardening / signing / AVB inside `009` (staged)
|
||||
|
||||
**Decision**: Acceptance includes GOLDEN-class hardening and signing/AVB
|
||||
posture **as applicable** on LOS 23.2 / sunfish. Implement in **stages inside
|
||||
`009`** (functional Magisk+Google+apps first, then hardening/signing gates),
|
||||
but do not open a separate competing feature number for ship ownership.
|
||||
Document impossible-on-sunfish gaps rather than silent omit.
|
||||
|
||||
**Rationale**: Owner Q2 = full resurrection; still obey constitution
|
||||
“small attributable reversible changes” via staged known-good LAB images.
|
||||
|
||||
**Alternatives considered**: Defer all of `011`–`013` — rejected by owner.
|
||||
One mega-commit everything — rejected (attribution / bisect).
|
||||
|
||||
## Decision: Banking workflow = GOLDEN Magisk DenyList + Island
|
||||
|
||||
**Decision**: Restore constitution banking steps with **Magisk DenyList**
|
||||
(not KSU profiles) + Island: Aurora install → do not open → DenyList → clone
|
||||
to Island → first launch in Island. Swissquote PASS hard gate; Yuh honest vs
|
||||
GOLDEN attestation FAIL.
|
||||
|
||||
**Alternatives considered**: Rootless-only banking gate — incomplete vs AXP.
|
||||
Insular rename — GOLDEN runs Island.
|
||||
|
||||
## Decision: Version freshness policy
|
||||
|
||||
**Decision**: Before long builds: `git fetch --tags` / refresh upstreams for
|
||||
microG, Magisk, bundled apps; record tag/commit + version codes; never ship
|
||||
from shallow or stale laptop caches (AGENTS.md lesson from `007`).
|
||||
|
||||
**Alternatives considered**: Trust whatever is already on the host — rejected.
|
||||
@@ -0,0 +1,426 @@
|
||||
# Feature Specification: AXP LOS22 feature port to LOS23
|
||||
|
||||
**Feature Branch**: `009-axp-los23-port`
|
||||
|
||||
**Created**: 2026-09-16
|
||||
|
||||
**Status**: Clarified — ready for `/speckit-plan`
|
||||
|
||||
**Input**: User description: "009-axp based LOS22 feature port to LOS23 —
|
||||
take vanilla LineageOS 23 for sunfish and integrate the full AXP.OS (LOS22 /
|
||||
Android 15 GOLDEN) feature set into LOS23 without product exceptions; only
|
||||
versions change (newest stable for each system / bundled app that still fits
|
||||
sunfish / Android 16); use the project's already updated patched Phonesky
|
||||
(Google Play)."
|
||||
|
||||
**Owner clarifications (2026-09-16):** Magisk like GOLDEN (newest Magisk;
|
||||
AXP-style preinstalled-but-not-fully-activated layout — measure on GOLDEN);
|
||||
hardening / signing / AVB like GOLDEN (full **AXP resurrection** on LOS23);
|
||||
WebView exception = keep LOS23 WebView (Aosmium EOL) but leave provider
|
||||
selection unlocked; Phonesky = project patched build from recent work unless
|
||||
it lacks GOLDEN-class fixes (then reconsider); microG newest stable integrated
|
||||
with that Phonesky; signature spoofing and call recording **selectable**
|
||||
(toggles); KernelSU (`007`) out of ship for now, with optional recycle of
|
||||
existing functional kernels if useful; otherwise everything equal to
|
||||
AXP/GOLDEN.
|
||||
|
||||
## Context / non-goals
|
||||
|
||||
**Product intent (this feature is normative for the AXP resurrection ship):**
|
||||
|
||||
- This feature is an **AXP.OS resurrection** on LineageOS 23.2 / Android 16
|
||||
`sunfish`: same capability set as AXP on LOS22 / GOLDEN, moved to LOS23.
|
||||
- Base ROM = LineageOS 23.2 / Android 16 `sunfish` vanilla from `003` (or the
|
||||
best known-good vanilla-equivalent flashable baseline already proven on LAB).
|
||||
- Feature source of truth for *what* to ship = what AXP.OS Pro / GOLDEN
|
||||
provides on LOS22 (inventory in `002`, product catalog in
|
||||
`docs/axp-pro-parity.md`), **without omitting AXP capabilities as “decide
|
||||
later” rows**, including Magisk-class root and AXP-class hardening /
|
||||
signing / AVB posture that GOLDEN represents.
|
||||
- Versions = **newest stable** (or newest tagged pre-release the upstream
|
||||
project currently ships) for each system/bundled component, constrained to
|
||||
what still works on sunfish / non-GKI 4.14 / LOS 23.2 — not stale laptop
|
||||
caches or shallow-clone version lies.
|
||||
- **Phonesky exception:** ship the project's **already patched / fixed
|
||||
Phonesky** from the recent host pipeline (not “whatever newest Play APK
|
||||
is today”). If that build is missing fixes that GOLDEN's Phonesky path
|
||||
still needs for daily-driver parity, stop and reconsider the Phonesky
|
||||
plan before accepting the feature.
|
||||
- **WebView exception:** do **not** ship Aosmium (EOL). Default WebView =
|
||||
LineageOS 23's WebView. The ROM MUST keep Android's multi-provider path so
|
||||
the owner can install another WebView later and select it (Developer
|
||||
options → WebView implementation) — not locked to a single provider.
|
||||
- Flash / experiment **LAB only**; GOLDEN remains the read-only oracle
|
||||
(`docs/device-roles.md`).
|
||||
|
||||
**Relationship to earlier features:**
|
||||
|
||||
- `001`–`003` remain shared foundation (host, GOLDEN capture, vanilla build).
|
||||
- **Two parallel product tracks** (neither deletes the other):
|
||||
- **Standby / prior track:** `004`–`008` + `007` KernelSU (+ deferred
|
||||
`006`/`010`–`013` as previously planned). Kept intact for later resume;
|
||||
live on its own git branch once pushed (see plan notes).
|
||||
- **Active Magisk-resurrection track (this feature):** AXP→LOS23 ship with
|
||||
Magisk like GOLDEN. Does **not** rewrite or remove `004`–`008`/`007`
|
||||
specs; it is a new Speckit directory that may **reuse** proven LAB
|
||||
runbooks/results from those features when helpful.
|
||||
- KernelSU / SusFS from `007` stays **out of this track’s ship** for now.
|
||||
Recycle of the two functional `007` kernels is optional (FR-016) — never an
|
||||
acceptance gate for Magisk.
|
||||
- Project-only `FLAG_SECURE` global override may still ship if already
|
||||
specified under `008` (not AXP catalog); it is optional relative to AXP
|
||||
resurrection acceptance. AXP call-recording unlock **is** required and must
|
||||
be selectable.
|
||||
|
||||
**Out of scope for this feature (explicit):**
|
||||
|
||||
- Flashing or modifying GOLDEN.
|
||||
- Committing proprietary Google Phonesky APK bytes, private keys, or personal
|
||||
identifiers to Git.
|
||||
- Replacing the LOS 23.2 sunfish kernel/device stack with an unrelated prebuilt
|
||||
(Graphene A13, stock A13, etc.).
|
||||
- Shipping Aosmium / AOSmium as the default or only WebView (EOL).
|
||||
- Building a custom AXP-style backup/restore ROM feature (personal backup
|
||||
remains an external user tool if needed).
|
||||
- Claiming Yuh hardware-attestation PASS if GOLDEN itself currently FAILs that
|
||||
path — reproduce GOLDEN's *workflow* and document attestation parity honestly.
|
||||
- Deleting or rewriting the standby KernelSU / split-roadmap specs
|
||||
(`004`–`008`/`007`) — they remain valid on the standby branch/track.
|
||||
- Shipping KernelSU-Next as this track’s root (out of ship here; Magisk is
|
||||
the resurrection root). Optional later reuse of `007` kernels is allowed
|
||||
under FR-016 but MUST NOT delay Magisk acceptance.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - AXP resurrection daily-driver on LAB (Priority: P1)
|
||||
|
||||
As the owner, after flashing one LAB build produced under this feature, the
|
||||
phone boots and presents the same class of daily-driver capabilities I rely on
|
||||
with AXP on GOLDEN (Google compatibility stack, Play, managed banking profile
|
||||
workflow, selectable call recording unlock, Magisk root/hide workflow like
|
||||
GOLDEN, AXP hardening/signing posture, and AXP bundled usability apps —
|
||||
except WebView as defined here), without a checklist of deferred AXP features.
|
||||
|
||||
**Why this priority**: This is the whole reason for the resurrection.
|
||||
|
||||
**Independent Test**: Flash one `009` build to LAB; walk the GOLDEN daily
|
||||
checklist (microG Self-Check, Play open/install, Island profile, call-record
|
||||
toggle off/on, spoofing toggle off/on, Magisk present in AXP-like install
|
||||
state, bundled apps present, hardening/signing checks that GOLDEN implies);
|
||||
compare against `002` inventory categories.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** LAB on a vanilla `003` baseline (or documented equivalent),
|
||||
**When** the `009` image is flashed, **Then** the device boots to home and
|
||||
cellular/Wi‑Fi/basic hardware still work as in the vanilla smoke.
|
||||
2. **Given** that build, **When** I compare shipped capability categories to
|
||||
GOLDEN/AXP Pro (Google stack, Play, selectable spoofing, managed profile
|
||||
tool, selectable call recording unlock, Magisk/DenyList-class path,
|
||||
DNS/hosts privacy helpers if present on GOLDEN, F‑Droid/Aurora/launcher/
|
||||
gallery-class bundled apps, hardening/signing/AVB class), **Then** no
|
||||
category is left as “decide / later” without an explicit obsolescence note
|
||||
tied to Android 16 / sunfish impossibility (WebView exception allowed per
|
||||
FR-015).
|
||||
3. **Given** Git and host artifact policy, **When** inspected, **Then** no
|
||||
proprietary Phonesky APK bytes or secrets were committed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Google stack: newest microG + project Phonesky (Priority: P1)
|
||||
|
||||
As the owner, newest-stable microG + GSF Proxy integrate with the project's
|
||||
recent patched Phonesky so I can open Play, sign in as needed, and
|
||||
install/update apps the same way I do on AXP; signature spoofing is
|
||||
selectable (off = stock-safe default behaviour; on = needed Play/microG
|
||||
path).
|
||||
|
||||
**Why this priority**: Without Play/microG parity, the ROM is not a daily
|
||||
driver.
|
||||
|
||||
**Independent Test**: microG Self-Check; Phonesky launches; install or update
|
||||
at least one ordinary app; toggle spoofing off/on and confirm expected
|
||||
behaviour; push notifications smoke for a known test app.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the `009` build on LAB, **When** microG Settings Self-Check runs
|
||||
with spoofing enabled as required, **Then** checks required for basic
|
||||
Google compatibility pass (or each remaining failure is documented as
|
||||
attestation/hardware outside packaging).
|
||||
2. **Given** the project's current patched Phonesky host artifacts, **When**
|
||||
the ROM is built and flashed, **Then** `com.android.vending` is present as
|
||||
privileged Play and opens on LAB.
|
||||
3. **Given** selectable signature spoofing, **When** the owner turns it on,
|
||||
**Then** Play install/update works with microG without FakeStore; **When**
|
||||
turned off, **Then** the device does not expose unrestricted spoofing to
|
||||
arbitrary apps.
|
||||
4. **Given** version policy, **When** microG / GSF versions are recorded,
|
||||
**Then** each is the newest stable (or tagged pre-release upstream
|
||||
currently ships) verified on this stack; Phonesky version matches the
|
||||
project patched artifact (not a blind “newest Play from the internet”).
|
||||
5. **Given** Play behaviour on LAB, **When** compared to GOLDEN needs, **Then**
|
||||
if the project Phonesky lacks a GOLDEN-class fix required for daily use,
|
||||
acceptance stops and the Phonesky plan is reconsidered.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Banking profile workflow parity (Priority: P1)
|
||||
|
||||
As the owner, I can recreate the GOLDEN banking layout on LAB: install via the
|
||||
same store path I use on AXP, place banks in Island, and keep banking apps
|
||||
free of root via Magisk DenyList-class hiding like GOLDEN.
|
||||
|
||||
**Why this priority**: Compatibility hard gates; daily-driver without banks
|
||||
fails the resurrection.
|
||||
|
||||
**Independent Test**: Install Swissquote (hard gate) and attempt Yuh; run
|
||||
inside Island; Magisk DenyList (or AXP-equivalent) applied; record PASS/FAIL
|
||||
honestly vs GOLDEN.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Island on LAB, **When** I follow the documented GOLDEN banking
|
||||
install order, **Then** Swissquote reaches a usable logged-in state in the
|
||||
managed profile.
|
||||
2. **Given** Yuh on the same workflow, **When** tested, **Then** either it
|
||||
PASSes or the failure matches the known GOLDEN attestation-class failure
|
||||
and is documented — not a silent packaging regression.
|
||||
3. **Given** Magisk is present on the build, **When** banking apps run with
|
||||
DenyList-class configuration, **Then** they do not receive root.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Magisk like GOLDEN + selectable call recording (Priority: P1)
|
||||
|
||||
As the owner, Magisk is present the way AXP/GOLDEN presents it (newest Magisk;
|
||||
preinstalled but not fully activated until I finish setup — exact UX measured
|
||||
from GOLDEN), with DenyList-class hiding; call recording unlock is selectable
|
||||
like other Developer Options toggles.
|
||||
|
||||
**Why this priority**: Root and call recording are core AXP daily behaviours.
|
||||
|
||||
**Independent Test**: Confirm Magisk package/binary layout vs GOLDEN notes;
|
||||
complete activation on LAB if required; DenyList a test app; toggle call
|
||||
recording unlock off (restricted) and on (record allowed).
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a fresh `009` flash, **When** inspected, **Then** Magisk is
|
||||
present in an AXP-like preinstalled / not-fully-activated state consistent
|
||||
with GOLDEN measurement, using the newest Magisk stable that works on this
|
||||
stack.
|
||||
2. **Given** Magisk setup completed on LAB, **When** DenyList-class hiding is
|
||||
configured for a banking package, **Then** that package does not receive
|
||||
root.
|
||||
3. **Given** selectable call recording unlock, **When** OFF, **Then** stock
|
||||
LOS country/carrier style restrictions apply; **When** ON, **Then** Dialer
|
||||
can record on LAB without that block.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - AXP usability, privacy, hardening (Priority: P2)
|
||||
|
||||
As the owner, the ROM ships the rest of the AXP usability/privacy surface and
|
||||
GOLDEN-class hardening/signing/AVB posture at newest workable stables, with
|
||||
LOS23 WebView default and an unlocked provider chooser.
|
||||
|
||||
**Why this priority**: Completes resurrection beyond Google/banking/root core.
|
||||
|
||||
**Independent Test**: Package list vs `002`; open bundled apps; confirm
|
||||
default WebView is LOS and another WebView can be selected if installed;
|
||||
hardening/signing checks agreed for GOLDEN-class parity.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the `009` build, **When** I list bundled system/user apps in the
|
||||
AXP usability set, **Then** each GOLDEN/AXP category is present or
|
||||
explicitly marked impossible on Android 16/sunfish with rationale
|
||||
(Aosmium absence is the allowed WebView exception).
|
||||
2. **Given** Developer options, **When** I open WebView implementation,
|
||||
**Then** LOS23 WebView is available/default and the chooser is not locked
|
||||
against future alternate providers.
|
||||
3. **Given** version policy, **When** bundled apps (except Phonesky per
|
||||
FR-004) are recorded, **Then** each is newest stable that still runs on
|
||||
the ROM.
|
||||
4. **Given** GOLDEN/AXP hardening and signing expectations, **When** the
|
||||
accepted build is evaluated, **Then** equivalent class of protections /
|
||||
signing posture is present or each gap is documented as impossible on
|
||||
this stack — not silently dropped.
|
||||
|
||||
---
|
||||
|
||||
### User Story 6 - Parallel tracks stay honest (Priority: P2)
|
||||
|
||||
As the owner, docs make clear that **this** Speckit is the Magisk AXP
|
||||
resurrection track on LOS23, while the prior KernelSU / split roadmap remains
|
||||
on standby (other branch / same `004`–`008`/`007` specs untouched).
|
||||
|
||||
**Why this priority**: Lets either track resume without rewriting history.
|
||||
|
||||
**Independent Test**: `specs/004`–`008`/`007` still exist unchanged in intent;
|
||||
`009` describes Magisk resurrection; git branches separate standby vs active
|
||||
work when published.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the repo, **When** inspected, **Then** `001`–`008`/`007` spec
|
||||
directories remain present (not deleted by `009`).
|
||||
2. **Given** `009`, **When** read as ship intent for Magisk resurrection,
|
||||
**Then** it does not claim to permanently retire the standby track — only
|
||||
that KernelSU is out of *this* track’s ship for now.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Newer “stable” of a bundled app breaks Android 16 / sunfish: pin last known
|
||||
good, document the regression, and retry when a fixed release exists.
|
||||
- Project Phonesky missing a GOLDEN-class fix: halt acceptance; reconsider
|
||||
Phonesky patch/version plan before claiming Play parity.
|
||||
- Magisk “preinstalled but not fully installed” UX differs across Magisk
|
||||
versions: match GOLDEN's *class* of first-boot/setup behaviour; document
|
||||
exact measured steps from GOLDEN before freezing LAB instructions.
|
||||
- GOLDEN Yuh FAIL vs LAB FAIL: distinguish attestation/hardware class from
|
||||
packaging/spoofing regressions.
|
||||
- Vanilla LOS already provides an AXP capability (e.g. WireGuard, encryption):
|
||||
keep LOS behaviour; do not duplicate.
|
||||
- Dirty upgrade from older LAB experimental (incl. KernelSU) images: prefer
|
||||
clean flash for acceptance.
|
||||
- Phonesky host artifacts missing or wrong signature: fail closed — never
|
||||
silently fall back to FakeStore.
|
||||
- Alternate WebView installed by user later: selection must remain possible;
|
||||
default remains LOS23 WebView until the user changes it.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The project MUST produce a flashable LineageOS 23.2 / Android 16
|
||||
`sunfish` build that resurrects the AXP.OS on LOS22 / GOLDEN capability set
|
||||
(including Magisk-class root and GOLDEN-class hardening / signing / AVB
|
||||
posture), without leaving AXP capabilities as open “decide” omissions
|
||||
except the WebView exception in FR-015.
|
||||
- **FR-002**: Version selection for system and bundled components (except
|
||||
Phonesky per FR-004) MUST prefer the newest stable (or newest tagged
|
||||
pre-release upstream currently ships) that still works on sunfish /
|
||||
LOS 23.2; GOLDEN versions are a floor reference, not a freeze.
|
||||
- **FR-003**: The ROM MUST ship newest-stable microG Services Core and GSF
|
||||
Proxy integrated with the project Phonesky (no FakeStore as primary Play).
|
||||
- **FR-004**: The ROM MUST ship the project's recent patched Phonesky as
|
||||
privileged `com.android.vending`, with a documented host-side obtain /
|
||||
patch / sign / deploy path that never commits APK bytes to Git. If that
|
||||
artifact lacks GOLDEN-class fixes required for daily-driver Play behaviour,
|
||||
the Phonesky plan MUST be reconsidered before acceptance.
|
||||
- **FR-005**: The ROM MUST provide **selectable** signature spoofing for the
|
||||
microG + Phonesky path (owner-controlled toggle; default safe/off or
|
||||
project-documented default). Spoofing MUST remain restricted/controlled —
|
||||
not unrestricted platform spoofing for all apps.
|
||||
- **FR-006**: The ROM MUST support the GOLDEN managed-profile banking workflow
|
||||
(Island as measured on GOLDEN) including Swissquote PASS as a hard gate.
|
||||
- **FR-007**: Banking applications MUST run without being granted root
|
||||
(Magisk DenyList-class hiding).
|
||||
- **FR-008**: The ROM MUST include **selectable** AXP-equivalent call
|
||||
recording unlock (toggle; OFF = stock LOS restrictions, ON = unlock).
|
||||
- **FR-009**: The ROM MUST include the AXP usability/privacy bundled surface
|
||||
present on GOLDEN / AXP Pro (stores, launcher/gallery-class apps, DNS/hosts
|
||||
or equivalent blockers when part of that surface) at newest workable
|
||||
stables, subject to FR-015 for WebView.
|
||||
- **FR-010**: The ROM MUST ship **Magisk** like GOLDEN: newest Magisk stable
|
||||
that works on this stack, in an AXP-like preinstalled but not fully
|
||||
activated layout (exact first-boot/setup behaviour measured from GOLDEN),
|
||||
with DenyList-class hiding sufficient for FR-007. KernelSU is **out of
|
||||
ship for now** (not the resurrection root path).
|
||||
- **FR-011**: The feature acceptance gate MUST include GOLDEN/AXP-class
|
||||
hardening and signing / AVB posture (as applicable on LOS 23.2 / sunfish),
|
||||
not only apps and Google compatibility. Gaps MUST be documented as
|
||||
impossible on this stack rather than silently omitted.
|
||||
- **FR-012**: Acceptance flashing MUST use LAB only; GOLDEN MUST remain
|
||||
unmodified by this feature's work.
|
||||
- **FR-013**: Each shipped capability MUST be attributable (what upstream or
|
||||
AXP behaviour it reproduces) and reversible (known-good prior LAB image
|
||||
retained).
|
||||
- **FR-014**: This feature MUST live as a **new Speckit** (`009`) in parallel
|
||||
with the standby KernelSU / split roadmap (`004`–`008`/`007`). Those older
|
||||
specs MUST NOT be deleted or rewritten to match Magisk resurrection.
|
||||
Reusable runbooks/results from them MAY be referenced. For *this* track’s
|
||||
ship only, Magisk (not KernelSU) is the root path.
|
||||
- **FR-015**: Default WebView MUST be LineageOS 23's WebView. Aosmium MUST NOT
|
||||
be required. The ROM MUST keep WebView provider selection available so a
|
||||
future alternate WebView can be installed and chosen.
|
||||
- **FR-016**: Existing functional KernelSU / related kernels and artifacts
|
||||
from `007` SHOULD be retained and MAY be recycled when useful (reference
|
||||
boot images, differential debugging, or a later optional non-ship path).
|
||||
Such reuse is **optional** (“si se puede, ok”), MUST NOT become an
|
||||
acceptance requirement for Magisk resurrection, and MUST NOT imply KernelSU
|
||||
is back in the ship path unless a future spec explicitly says so.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Vanilla baseline**: The LOS 23.2 sunfish build from `003` (or documented
|
||||
equivalent) before AXP feature integration.
|
||||
- **AXP capability set**: Inventory of features/packages/behaviours from
|
||||
GOLDEN (`002`) plus AXP Pro catalog rows promoted by this spec
|
||||
(resurrection target).
|
||||
- **Version pin record**: Documented package/component versions chosen for the
|
||||
accepted `009` build (newest workable stable each; Phonesky = project
|
||||
artifact id/version).
|
||||
- **Phonesky host artifact**: Project patched/signed Play APK and permission
|
||||
metadata kept outside Git on the build host.
|
||||
- **Magisk preinstall state**: Measured GOLDEN/AXP layout for Magisk present
|
||||
but not fully activated, plus LAB setup steps.
|
||||
- **LAB acceptance build**: Flashable image set + hashes + smoke/banking /
|
||||
Magisk / hardening results for this feature.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: One LAB flash of a `009` build boots and completes the vanilla
|
||||
hardware smoke within the same session as flash (owner can place a call,
|
||||
use Wi‑Fi, and unlock the device).
|
||||
- **SC-002**: 100% of AXP resurrection capability categories from the agreed
|
||||
inventory are either demonstrated on LAB or explicitly documented as
|
||||
impossible on Android 16/sunfish — zero silent omissions (WebView exception
|
||||
allowed only as FR-015).
|
||||
- **SC-003**: With spoofing enabled as required, microG Self-Check required
|
||||
items and project Phonesky open/install succeed on LAB for ordinary apps on
|
||||
the first accepted build candidate (or within one documented fix iteration).
|
||||
- **SC-004**: Swissquote managed-profile + Magisk DenyList-class workflow
|
||||
PASSes on LAB; Yuh result is recorded and is not worse than GOLDEN for
|
||||
packaging/spoofing reasons.
|
||||
- **SC-005**: Every bundled/system app version in the acceptance record
|
||||
(except Phonesky) is newer than or equal to GOLDEN's measured version,
|
||||
unless a newer release was tried and failed with a written regression note;
|
||||
Phonesky matches the recorded project patched artifact.
|
||||
- **SC-006**: Owner can turn signature spoofing and call recording unlock off
|
||||
and on and observe the documented behaviour each time.
|
||||
- **SC-007**: Magisk is present post-flash in the AXP-like preinstall state and
|
||||
can be fully activated on LAB using documented steps measured from GOLDEN.
|
||||
- **SC-008**: Default WebView is LOS23's; provider selection remains available.
|
||||
- **SC-009**: Owner can perform the GOLDEN-equivalent daily checklist on LAB
|
||||
without consulting a scatter of conflicting feature specs for what “ships”.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- `003` vanilla LOS 23.2 sunfish is (or becomes) available as the integration
|
||||
base; LAB stock rescue from `002` remains valid.
|
||||
- GOLDEN inventory (`002`) plus AXP Pro docs are sufficient to enumerate the
|
||||
capability set; live `adb` re-query of GOLDEN is allowed (especially Magisk
|
||||
preinstall/activation details).
|
||||
- “AXP resurrection” means Magisk + GOLDEN-class hardening/signing/AVB + full
|
||||
AXP user surface on LOS23, with only the stated WebView and Phonesky-artifact
|
||||
exceptions.
|
||||
- Island remains the managed-profile tool because that is what GOLDEN
|
||||
actually runs (AXP docs saying “Insular” are historical naming).
|
||||
- FakeStore is never the primary Play path.
|
||||
- Selectable spoofing and selectable call recording follow the same class of
|
||||
Developer Options UX already explored in `005`/`008` runbooks where useful.
|
||||
- Project `FLAG_SECURE` override is nice-to-have, not an AXP resurrection
|
||||
hard gate.
|
||||
- Personal app/data backup is not a ROM feature gate.
|
||||
- Builds and long compiles run on `rom-dev01`; laptop holds docs/specs and
|
||||
flash tools only.
|
||||
- Prior KernelSU LAB experiments (including the two functional kernels already
|
||||
built) are **out of ship for now** but kept as recyclable assets: reuse if
|
||||
helpful, never required for Magisk acceptance.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Feature Specifications
|
||||
|
||||
Numbered feature specs for `sunfish-a16-rom`.
|
||||
|
||||
## Structure
|
||||
|
||||
```text
|
||||
specs/
|
||||
└── NNN-short-name/
|
||||
├── spec.md # Only human-maintained requirements source
|
||||
├── plan.md # Derived — regenerate after spec changes
|
||||
├── tasks.md # Derived — regenerate after spec changes
|
||||
└── …
|
||||
```
|
||||
|
||||
## Numbering
|
||||
|
||||
- Three-digit, sequential: `001-…`, `002-…`
|
||||
- Short name: lowercase, hyphen-separated
|
||||
- Create a feature directory only when ready to specify/implement it
|
||||
|
||||
## Spec-as-source
|
||||
|
||||
1. Edit requirements only in `spec.md`.
|
||||
2. Run `/speckit-plan` and `/speckit-tasks` to regenerate derived artifacts.
|
||||
3. Implementation follows the active feature; do not invent decisions missing
|
||||
from the constitution or the active `spec.md`.
|
||||
|
||||
## Active / next features
|
||||
|
||||
| Dir | Intent |
|
||||
|-----|--------|
|
||||
| `001-development-environment` | ROM build host env on existing `rom-dev01` (not VM creation) |
|
||||
| `002-axp-reference-capture` | Document GOLDEN AXP oracle + LAB stock rescue; no NeoBackup/wipe of GOLDEN |
|
||||
| `003-lineage-23-vanilla-build` | First vanilla LOS 23.2 on **LAB only** → flash → boot → P1 (**done** 2026-09-14) |
|
||||
| `004-microg-phonesky-integration` | microG + GSF Proxy + patched Phonesky on LAB (packaging done; Self-Check/auth → `005`) |
|
||||
| `005-restricted-signature-spoofing` | Restricted spoofing + bacon zip — **done enough for LAB**; Location UI follow-up open |
|
||||
| `007-kernelsu-sunfish` | ReSukiSU + SusFS bring-up — **incomplete** (banks FAIL; see `docs/007-lab-results-20260916.md`) |
|
||||
| `008-call-rec-flag-secure` | Native DO toggles: call-rec region unlock + global FLAG_SECURE override — **next** |
|
||||
|
||||
Handoff snapshot: `docs/session-20260916-handoff.md`.
|
||||
Design: `docs/008-009-design.md`.
|
||||
|
||||
## Roadmap (non-binding)
|
||||
|
||||
Later features are created only when prior work supplies enough information.
|
||||
Numbers may shift; this list is guidance, not stubs:
|
||||
|
||||
| # | Theme |
|
||||
|---|--------|
|
||||
| 004 | microG + GSF Proxy + patched Phonesky |
|
||||
| 005 | Restricted native signature spoofing (bacon shipped; **Location UI gap** follow-up) |
|
||||
| 006 | **Rootless** banking baseline — **deferred** (absorbed into `007` gate) |
|
||||
| 007 | ReSukiSU + SusFS — **incomplete** (banking hard-gate FAIL) |
|
||||
| 008+009 | Delivered together as `008-call-rec-flag-secure` (global DO toggles only) |
|
||||
| 010 | Remaining AXP Pro usability/privacy features (matrix spans 004–013; NeoBackup is external) |
|
||||
| 011 | Signing / AVB / OTA + banking regression on signed/relocked ROM |
|
||||
| 012 | Userspace hardening (promote from `docs/hardening-backlog.md`) |
|
||||
| 013 | Kernel hardening + EOL firmware limits documentation |
|
||||
|
||||
## New feature
|
||||
|
||||
```text
|
||||
/speckit-specify
|
||||
```
|
||||
Reference in new issue
Block a user