# 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.