Pet architecture for v0.3.0

Document versionDateSummary
v12026-07-25Initial architecture for the embedded firmware foundation and project UX release
v22026-07-27Accept the release architecture, assign open decisions, and clarify embedded asset and support evidence boundaries
v32026-07-27Record the implemented project command and its workflow and configuration boundaries
v42026-07-27Record project-owned local dependency source overrides
v52026-07-27Select the T-Display family, S3 variant, and ESP-IDF esp32s3 build boundary
v62026-07-27Record the implemented family selection and executed S3 cross-compile evidence
v72026-07-27Clarify the stable family API and variant metadata contract
v82026-07-28Select every shared component for embedded build evidence, isolate the desktop asset reader, and record the shared build interface reuse in ADR-010
v92026-07-28Record the component, embedded, and allocation probe coverage boundaries and the unavailable check rule
v102026-07-28Record the greet presentation rule and its action dwell ordering invariant

Status: Accepted

Product version: v0.3.0

Milestone: V0 software companion foundation

Release: Embedded firmware foundation and project UX

General architecture: Pet architecture

Template: arc42

Versioning: Semantic Versioning 2.0.0

1. Introduction and goals

1.1 Purpose

Version v0.3.0 introduces the embedded firmware foundation and simplifies the daily development workflow.

The release proves that Pet Core and selected frontend-neutral components can be built and linked in an ESP-IDF firmware foundation for a LILYGO T-Display S3 board. It must do that without making ESP-IDF, board pins, display controllers, filesystems, generated assets, or network facilities part of Pet Core.

This is not the first complete hardware runtime. The release creates a firmware foundation that later display and input work can grow from, rather than a disposable probe application that exists only to make one toolchain pass.

flowchart LR
    C[Pet Core]
    P[Presentation and layout components]
    A[firmware app foundation]
    B[T-Display family and S3 variant]
    E[ESP-IDF platform glue]
    F[future TFT frontend]

    E --> A
    E --> B
    A --> C
    A -. later .-> P
    A -. later .-> F

1.2 Architecture goals

The release must prove that:

  • the Core stays independent of ESP-IDF, board support packages, display drivers, SDL, filesystems, wireless stacks, and hardware SDK headers
  • the project has a non-disposable embedded firmware host boundary for later hardware runtime work
  • ESP-IDF can build and link the firmware foundation on the selected development host
  • board-specific facts live in a selected family variant rather than in the Core, firmware app, or generic frontend contracts
  • the small TFT display direction is separated from T-Display S3 board pins and firmware lifecycle
  • embedded runtime assets are planned as generated artefacts derived from canonical PNG and manifest sources
  • desktop and headless workflows continue to work while embedded verification is added
  • common developer commands become simple without removing direct CMake and gate usage
  • carried limitations are actively closed, narrowed, or given explicit follow-up ownership

1.3 Included capabilities

  • apps/firmware embedded firmware app foundation
  • ESP-IDF platform and build integration under platforms/esp_idf
  • T-Display family selection under boards/t_display, with S3 under variants/s3
  • small TFT frontend direction under frontends/tft, with ST7789 as the first controller family
  • ESP-IDF build and link evidence for the firmware foundation
  • embedded boundary evaluation for selected frontend-neutral components
  • project command entrypoint for common build, test, run, verify, and clean workflows
  • dependency and local override policy for fetched dependencies
  • documented embedded asset direction from canonical source assets to generated runtime artefacts
  • continued headless and desktop SDL verification
  • targeted resolution work for embedded support, dependency overrides, allocation-probe coverage, and the presentation priority issue

1.4 Excluded capabilities

  • complete T-Display S3 pet runtime
  • required ST7789 rendering implementation
  • board button input dispatched into Core actions
  • runtime PNG decoding on embedded firmware
  • runtime text manifest parsing on embedded firmware
  • complete asset converter implementation
  • local persistence and save compatibility
  • identity, traits, memories, maturity, or formative events
  • physical sensor adapters
  • digital activity adapters
  • Wi-Fi, Bluetooth, networking, synchronisation, peer discovery, and pet transfer
  • production power management
  • final production hardware selection or custom hardware design
  • generic host support library
  • generic frontend support library
  • Windows build verification unless a real Windows environment or runner is available during the release

Excluded capabilities must not leave placeholder dependencies inside the Core.

1.5 Stakeholders

Developer

Needs a simpler daily workflow and a clear way to verify the new embedded build without remembering all CMake, CTest, gate, and ESP-IDF details.

Future firmware developer

Depends on the firmware foundation becoming the first real embedded host boundary rather than a temporary probe.

Future frontend developer

Depends on small TFT display work being separated from board configuration, controller-specific code, and firmware app lifecycle.

Product reviewer

Uses this release as evidence that the product can move toward a physical device without claiming a complete hardware experience too early.

2. Architecture constraints

2.1 Product constraints

  • the release belongs to the V0 milestone
  • one world contains one active pet
  • the release must preserve the non-punitive companion principles in the specification
  • the firmware foundation must not simulate unsupported product features in app code
  • embedded support claims must not be broader than executed evidence
  • final production hardware selection remains out of scope

2.2 Technical constraints

  • Pet Core remains portable ISO C99
  • Pet Core does not include ESP-IDF, FreeRTOS, board, display, SDL, filesystem, Wi-Fi, Bluetooth, or network headers
  • ESP-IDF integration is outside the Core and belongs to the firmware app and platform glue
  • board pins and display geometry are configuration data, not Core data
  • frontends/tft must not own T-Display S3 pin choices
  • runtime embedded assets must not require a desktop filesystem
  • desktop SDL and headless builds must remain supported compositions
  • third-party headers, generated dependency files, and SDK files are not project code for diagnostics

2.3 Documentation and language constraints

  • code and developer documentation use British English
  • C domain identifiers use the pet prefix
  • version architecture documents follow the policy in arch README
  • meaningful decisions with alternatives receive ADRs when they become durable implementation commitments
  • roadmap documents and idea documents remain non-authoritative until content moves into milestones, version architecture, epics, PBIs, or ADRs

2.4 Verification constraints

  • Linux desktop GCC and Clang verification continues to be required
  • ESP-IDF build evidence is required before release completion
  • hardware runtime evidence is not required for v0.3.0
  • if no hardware runtime is executed, the support matrix must say so explicitly
  • allocation and boundary checks must distinguish Core claims from SDK and frontend behaviour

3. System scope and context

3.1 Product context

The release does not add a new user-facing pet experience. A user can still try the product through the v0.2.0 desktop app. The embedded work prepares the future physical device path.

flowchart TD
    U[User]
    D[Desktop app]
    FW[Firmware foundation]
    C[Pet Core]
    HW[LILYGO T-Display S3 board]

    U --> D
    D --> C
    FW --> C
    FW --> HW

3.2 Technical context

The firmware app is an embedded host boundary. It owns Core lifecycle calls and selected component linkage. The ESP-IDF platform adapter owns app_main, SDK integration, and any SDK diagnostic used by the build-proof executable.

The T-Display family configuration owns variant selection and maps the selected variant to its SDK target. The S3 variant owns its screen geometry, display controller family, parallel display bus, relevant GPIO pins, button pins, and power facts. Neither layer owns product behaviour.

The TFT frontend direction names the small raster display boundary that later rendering work should use. ST7789 is the first controller family for that frontend, but the frontend group should be able to add related SPI TFT controllers without changing the firmware app or Core. v0.3.0 may add only the source ownership and contract skeleton required by architecture and build proof. A complete renderer is deferred.

The ESP-IDF platform glue owns SDK build integration. It must not become the owner of Core rules or frontend-neutral component contracts.

3.3 External interfaces

The release interfaces are:

  • project command entrypoint for daily workflows
  • existing CMake presets and gate commands for maintainer workflows
  • ESP-IDF build commands used by the release gate or documented verification
  • firmware app entry as required by ESP-IDF
  • board configuration records for the selected T-Display S3
  • public Core API consumed by the firmware foundation
  • public frontend-neutral component APIs consumed by the firmware foundation where selected

No network, cloud, persistence, sensor, or runtime display user interface is present.

4. Solution strategy

4.1 Functional core and embedded shell

The firmware app is an embedded imperative shell. It composes the Core with platform glue and board configuration. The Core still receives explicit values and exposes derived snapshots.

flowchart LR
    E[ESP-IDF entry]
    A[firmware app]
    B[board config]
    C[Pet Core]
    S[PetSnapshot]
    P[frontend-neutral presentation components]

    E --> A
    A --> B
    A --> C
    C --> S
    A --> P

4.2 Main strategies

  1. keep product behaviour in the Core
  2. keep ESP-IDF and board effects in the firmware app, board configuration, and platform glue
  3. create a reusable firmware foundation rather than a disposable probe
  4. keep TFT controller logic separate from board pin configuration
  5. prove embedded build and link before claiming embedded runtime behaviour
  6. evaluate frontend-neutral components under the embedded boundary one by one
  7. use generated embedded asset artefacts later instead of requiring runtime PNG decoding or text manifest parsing
  8. simplify daily workflow through a small command wrapper over existing build and gate operations
  9. keep direct CMake, CTest, gate, and ESP-IDF commands available for maintainers
  10. close or narrow carried limitations when release evidence makes the old statement too broad

4.3 Technology strategy

ESP-IDF is the embedded framework selected for this release. It is a firmware and platform dependency only. The Core must not include or link against ESP-IDF.

The selected build variant is s3, the non-touch LILYGO T-Display S3 sold by Robotistan as product 23746. It uses an ESP32-S3R8, an ST7789 170 by 320 panel, 16 MB flash, and 8 MB OPI PSRAM. Variant metadata selects the ESP-IDF esp32s3 target. The project records build evidence separately from hardware runtime evidence.

frontends/tft is named for the small TFT display class rather than for the board vendor. ST7789 is the first controller-specific implementation direction inside that frontend group. boards/t_display owns the stable family contract and selection; its variants/s3 area owns the pin and geometry facts that make a TFT frontend usable on the selected board.

5. Building block view

5.1 Level 1 building blocks

flowchart TD
    subgraph Firmware["apps/firmware"]
        FW[firmware app foundation]
    end

    subgraph Platform["platforms/esp_idf"]
        IDF[ESP-IDF build glue]
    end

    subgraph Board["boards/t_display"]
        BS[T-Display variant selector]
        BD[variants/s3 facts]
        BS --> BD
    end

    subgraph FutureFrontend["frontends/tft"]
        ST[TFT frontend direction]
    end

    subgraph Shared["components"]
        PR[presentation]
        LY[layout]
        MF[manifest]
        AS[assets]
    end

    C[Pet Core]
    W[project command entrypoint]
    G[gate and CMake]
    D[direct idf.py]

    FW --> C
    FW --> PR
    FW --> LY
    IDF --> FW
    IDF --> BS
    FW -. later .-> ST
    AS --> MF
    W --> G
    D --> IDF

5.2 Pet Core

The Core remains the platform independent authority for world state and product transitions.

The Core must not:

  • include ESP-IDF or FreeRTOS headers
  • include board configuration headers
  • include TFT controller or display driver headers
  • include SDL headers
  • read files or generated asset storage directly
  • read platform clocks, buttons, GPIO, Wi-Fi, Bluetooth, or network APIs
  • know the selected board or firmware stack

Core changes in this release are justified only when they are needed to preserve an existing Core claim, fix a carried limitation, or keep public operations covered by verification.

5.3 Firmware app foundation

apps/firmware owns the embedded firmware host foundation. It is a real app boundary intended to grow into later hardware runtime work.

Responsibilities:

  • initialise one PetWorld through public Core APIs
  • run the minimum Core lifecycle needed for build and link evidence
  • request a snapshot where useful for evidence or future display integration
  • remain independent of board configuration and SDK facilities
  • return a bounded success or failure result to the platform entry point

The firmware app must not own display drawing rules, board pin definitions, product progression, storage semantics, asset conversion, or Core internal headers.

The firmware app is generic in the sense that it owns the product lifecycle pattern, not the physical details of one board. It decides when the world is initialised, updated, snapshotted, and later presented. It does not decide which GPIO pin is the backlight, how an ST7789 panel is initialised, or how ESP-IDF transfers bytes over SPI.

The intended division is:

AreaOwnsDoes not own
apps/firmwareCore lifecycle, app loop policy, semantic dispatch points, later save and presentation orchestrationGPIO pins, panel init sequences, SPI implementation, generated asset format, product rules
boards/t_displaystable family contract, variant selection, SDK target mappingCore lifecycle, rendering algorithms, ESP-IDF project shape
boards/t_display/variants/s3S3 pins, display geometry, bus and power facts, button pinsfamily selection, Core lifecycle, rendering algorithms
frontends/tftsmall TFT presentation, panel-family code such as ST7789 setup, drawing generated framesboard pin values, firmware loop, Core mutation
platforms/esp_idfESP-IDF app entry integration, SDK build glue, platform primitives such as delay and bus accessproduct rules, board-independent rendering policy

For v0.3.0, the firmware foundation may stop after a minimal lifecycle:

platform entry -> firmware app -> pet_world_init -> pet_world_update -> pet_world_snapshot
               -> firmware result -> platform diagnostic

That path is deliberately useful later. A later display runtime extends the same app boundary with input collection, presentation selection, TFT drawing, and delay policy instead of replacing the foundation with a differently named product app.

5.4 ESP-IDF platform glue

platforms/esp_idf owns project integration with ESP-IDF.

Responsibilities:

  • provide the ESP-IDF project or component build shape
  • select the target chip and toolchain for release evidence
  • adapt Pet project libraries into ESP-IDF build units without copying source ownership
  • keep SDK diagnostics outside project diagnostic scope where practical
  • document the exact build command used for release evidence

The platform glue must not become a second composition registry or a second source of dependency policy.

5.5 T-Display family and S3 variant configuration

boards/t_display exposes the stable pet_board_t_display/board.h contract and pet::board_t_display target. PET_T_DISPLAY_VARIANT selects one declared variant; undeclared values fail configuration. The only implemented selection is s3, whose metadata maps to ESP-IDF esp32s3.

boards/t_display/variants/s3 owns the selected non-touch LILYGO T-Display S3 facts. The vendor record confirms the values below. They remain unverified on project hardware until a later runtime PBI executes them.

FactVendor-documented value
System on chipESP32-S3R8
Display controllerST7789
Native panel size170 by 320
Display bus8-bit parallel
Data 0 to 7GPIO 39, 40, 41, 42, 45, 46, 47, 48
CS, DC, WR, RDGPIO 6, 7, 8, 9
ResetGPIO 5
BacklightGPIO 38
Peripheral powerGPIO 15, active high
Button 1GPIO 0
Button 2GPIO 14

The S3 variant may later include rotation, colour order, detailed backlight policy, reset policy, and input polarity. A future classic variant requires its own header, target metadata, build, and evidence before it is selectable. No variant value enters the Core.

5.6 TFT frontend direction

frontends/tft is the intended owner for small raster TFT presentation work. Its name is not LILYGO-specific and is not tied to one controller. ST7789 is the first controller family considered inside this frontend group.

Potential later responsibilities:

  • initialise TFT panel resources through platform-owned bus handles
  • accept presentation roles, layout results, and generated image artefacts
  • draw fallback and asset-backed frames to a small TFT target
  • keep controller-specific code, such as ST7789 initialisation and pixel-transfer details, isolated from the generic TFT presentation path
  • avoid owning board pin configuration
  • avoid owning firmware lifecycle

v0.3.0 does not require a complete TFT renderer. It records the ownership boundary so that the later hardware runtime does not grow display code inside the firmware app. Later e-ink, OLED, or other display classes may reuse the same app, board, platform, and frontend-group pattern without being forced into frontends/tft.

5.7 Shared components

The release selects all four frontend-neutral components for embedded build evidence. The selection was decided by reading what each component actually depends on rather than by what its name suggests, and no component is deferred.

Componentv0.3.0 embedded statusReason
components/presentationSelectedIt maps a snapshot to a role and selects deterministically over accepted manifest records, and it reaches for stddef.h, string.h, and the Core public types only
components/layoutSelectedIt is pure geometry over stddef.h and is the component a small display needs most
components/manifestSelectedThe parser is bounded, caller fed, and allocation free, so it compiles for the target as a build-time validation and desktop runtime component
components/assetsSelected without the desktop readerThe loading policy is reader neutral, so the component enters the embedded build while pet_assets_stdio_reader stays a desktop selection

Embedded build evidence means that the cross toolchain compiles the component sources under the project warning contract and archives them beside the firmware app. It does not mean that the firmware calls a component, that a component was executed on a device, or that a component may assume storage.

Two records are large enough to be a deliberate embedded decision rather than an incidental one. On the esp32s3 toolchain PetManifest occupies 13844 bytes and PetAssetSet occupies 14116 bytes, and a caller that parses a manifest also supplies a text buffer of up to PET_MANIFEST_SIZE_MAX, which is 16384 bytes. A device that chose to parse the canonical manifest at runtime would therefore budget roughly 30 KB of RAM for one asset set. Neither record is allocated or held on a stack by the components themselves, because the world, the manifest, the asset set, and the manifest text buffer are all caller owned. The firmware does not pay that cost in this release, because section 8.3 keeps runtime text manifest parsing off the embedded path.

If a later component cannot enter the ESP-IDF build without inappropriate desktop or filesystem assumptions, the release records the reason and either narrows the component boundary or defers the component with a PBI.

5.8 Project command entrypoint

The root pet.py entrypoint is a small standard-library wrapper over existing CMake, CTest, gate, and run workflows. It supports:

./pet.py build
./pet.py build app=desktop front=sdl
./pet.py build all
./pet.py test
./pet.py run desktop
./pet.py verify
./pet.py clean

Build, test, and verify accept compact app=APP, optional front=FRONTEND, or bare all selection. They resolve through config/compositions.json. Verify always delegates to the strict gate. Dry-run prints the planned argument arrays without executing them.

The wrapper does not duplicate the composition registry or hide failures by running a different set of checks from the documented gate. Fast and audit level selection remains direct gate.py usage. The complete daily and maintainer contract is in the development workflow.

5.9 Proposed source layout

apps/
    firmware/
        CMakeLists.txt
        README.md
        include/
            pet_app_firmware/
                app.h
        src/
            app.c
 
boards/
    t_display/
        CMakeLists.txt
        README.md
        cmake/
            select_variant.cmake
        include/
            pet_board_t_display/
                board.h
        variants/
            s3/
                README.md
                variant.cmake
                include/
                    pet_board_t_display/
                        variants/
                            s3.h
 
frontends/
    tft/
        README.md
        include/
            pet_frontend_tft/
                frontend.h
        src/
            panel_st7789.c
 
platforms/
    esp_idf/
        README.md
        CMakeLists.txt
        sdkconfig.defaults
        main/
            CMakeLists.txt
            app_main.c
        cmake/
            pet_core.cmake
 
config/
    compositions.json
    verification.json
 
DEVELOPMENT.md
pet.py

Files are added by implementation PBIs only when they have real responsibility. The layout records ownership, not a requirement to create empty placeholders.

5.10 Composition model

The v0.2.0 app and frontend composition model remains valid for desktop and headless builds.

v0.3.0 must not create a fake composition only to satisfy the existing model. If the firmware foundation becomes a selectable composition, it must represent a real app boundary. If the ESP-IDF build remains outside the normal composition registry during this release, the version architecture and gate must say so explicitly.

Toolchain selection and app/frontend selection remain different concepts. ESP-IDF is a platform and toolchain environment, not a frontend.

5.11 Dependency rules

flowchart TD
    AF[apps/firmware]
    PI[platforms/esp_idf]
    BT[boards/t_display selected variant]
    FS[frontends/tft]
    CP[components/presentation]
    CL[components/layout]
    CM[components/manifest]
    CA[components/assets]
    API[Public Pet API]
    CORE[Pet Core]
    IDF[ESP-IDF SDK]

    AF --> API
    AF --> BT
    AF --> PI
    AF --> CP
    AF --> CL
    AF -. later .-> FS
    PI --> IDF
    FS --> BT
    FS --> PI
    FS --> CP
    FS --> CL
    CA --> CM
    API --> CORE
  1. the Core depends on no app, frontend, board, platform, SDK, SDL, filesystem, or generated asset target
  2. the firmware app depends on the public Core API and selected boundary components
  3. board configuration depends on no Core internal header and owns no product rule
  4. ESP-IDF platform glue depends on the SDK, not the other way around
  5. TFT frontend code, when implemented, depends on platform display facilities and board configuration but not on mutable Core world state
  6. controller-specific TFT code is selected or configured at a narrow boundary and does not spread board #ifdef branches through rendering code
  7. desktop SDL dependency remains isolated to the SDL frontend
  8. fetched third-party dependency overrides are policy controlled and not ad hoc source edits

6. Runtime view

sequenceDiagram
    participant Dev as Developer
    participant IDF as ESP-IDF build
    participant App as firmware app
    participant Core as Pet Core

    Dev->>IDF: run idf.py build
    IDF->>App: compile app entry
    App->>Core: link public Core operations
    IDF-->>Dev: build result

The required result is configure, compile, and link evidence. Hardware execution is not required for this release unless a PBI explicitly adds it.

6.2 Firmware lifecycle skeleton

The firmware app lifecycle for v0.3.0 is intentionally small:

sequenceDiagram
    participant IDF as ESP-IDF
    participant App as firmware app
    participant Core as Pet Core

    IDF->>App: app entry
    App->>Core: pet_world_init
    Core-->>App: status
    App->>Core: pet_world_update
    Core-->>App: status
    App->>Core: pet_world_snapshot
    Core-->>App: snapshot

The skeleton proves linkability and app ownership. It does not claim visible output, button input, persistence, sensor input, or networking.

The lifecycle skeleton is not a second product model. It is the smallest executable shape of the same firmware app boundary that a later release extends with board input, TFT output, generated assets, persistence, and real timing policy.

6.3 Future display runtime

Display runtime is a later flow:

sequenceDiagram
    participant App as firmware app
    participant Core as Pet Core
    participant Present as presentation components
    participant FE as TFT frontend
    participant Board as T-Display S3 board

    App->>Core: update and snapshot
    Core-->>App: snapshot
    App->>Present: role and layout selection
    Present-->>App: presentation selection
    App->>FE: draw generated frame
    FE->>Board: display bus operations

This release records the boundary so later work has a destination. It does not require the flow to execute.

7. Deployment view

7.1 Logical outputs

The release produces or preserves:

Pet Core library
Headless diagnostic executable
SDL frontend library
Desktop application executable
Firmware app foundation source
ESP-IDF build integration
Board configuration record
Project command entrypoint
Test executable or executables
Development runtime asset directory

There is no production firmware image support claim unless the ESP-IDF evidence actually builds one. There is no installer or hardware product package.

7.2 Platform verification matrix

EnvironmentEvidence targetRequired for release
Linux x86-64 desktop, GCCBuild tested and runtime testedYes
Linux x86-64 desktop, ClangBuild tested and runtime testedYes
Linux dummy or headless video driverAdditional hosted runtime evidence onlyNo
T-Display s3 variant, ESP-IDF v6.0.2 for esp32s3Cross-compile tested through configure, compile, and linkYes
Selected T-Display S3 hardwareRuntime unverified unless execution evidence is recordedNo
MSVC on WindowsPortable by design, unverifiedNo
Clang and Ninja on WindowsPortable by design, unverifiedNo
Classic ESP32 T-Display variant and other ESP32-class boardsNot implemented, unverifiedNo
Raspberry Pi Pico SDKArchitecture preserved, unverifiedNo
Arduino hostArchitecture preserved, unverifiedNo

The selected ESP-IDF row is supported by the E20 cross-compile recorded in section 10.5. The successful configure, compile, and link without hardware execution is cross-compile evidence, not hardware runtime evidence. Hosted build evidence, embedded cross-compile evidence, and named-target runtime evidence remain separate claims.

7.3 Build and gate interface

The release keeps the CMake and Python tooling boundary from earlier releases. CMake owns targets, include paths, compile options, link options, generated headers, selected directories, and CTest registrations. Python owns workflow orchestration, composition selection, quality gates, registry validation, and report coordination.

The project command entrypoint calls those tools. It does not replace their authority. Daily examples are:

./pet.py build
./pet.py test app=desktop front=sdl
./pet.py test
./pet.py run desktop
./pet.py verify
./pet.py verify all
./pet.py clean

Maintainer examples remain available:

./gate.py strict
./gate.py strict --all-compositions
cmake --preset linux-gcc-debug -DPET_APP=headless -DPET_FRONTEND=none
cmake --preset linux-gcc-debug -DPET_APP=desktop -DPET_FRONTEND=sdl

Project-owned composition and verification policies live under config/. Conventional .clang-format, .clang-tidy, and CMakePresets.json files stay at the repository root because their tools discover them there.

The ESP-IDF build is run from platforms/esp_idf after activating the selected SDK:

. "$HOME/.local/opt/espressif/export.sh"
idf.py set-target esp32s3
idf.py build

7.4 Deployment constraints

  • no daemon is installed
  • no network port is opened
  • no account is required
  • no persistent application data is written
  • no hardware runtime is claimed unless executed
  • generated embedded assets, if any are produced, are derived artefacts and are not canonical source
  • production packaging is deferred

8. Crosscutting concepts

8.1 Time

The Core continues to receive explicit elapsed deltas. The firmware app must not make the Core read ESP-IDF clocks directly.

v0.3.0 does not need to settle the final embedded elapsed-time policy. If the firmware foundation uses a fixed value only to prove linkage, that is evidence for build shape, not evidence for runtime clock policy.

8.2 Randomness

The Core random source remains caller-owned and explicit. The firmware foundation must not read platform entropy inside the Core.

A later hardware runtime may seed a PetRandom from a platform source, but that seed production is a host concern and is outside this release unless a PBI explicitly includes it.

8.3 Embedded assets

Canonical pet presentation assets remain:

assets/pet/manifest.petasset
assets/pet/sprites/*.png

Embedded runtime assets should be generated artefacts derived from those canonical sources. The expected direction is:

canonical PNG and manifest
    -> build-time converter or packer
    -> generated C arrays, packed binary, or display-native frames
    -> embedded runtime consumption

The embedded runtime should not be required to parse the text manifest, decode PNG, follow desktop paths, or use a filesystem to present the pet. Runtime text manifest parsing and PNG decoding may remain available to desktop builds and build-time tools, but they are not embedded runtime requirements.

This release records the direction. A separate ADR is required when the project commits to a specific generated format, converter contract, or compatibility promise. Converter implementation and generated format selection are deferred beyond v0.3.0 to a later display runtime PBI or release.

8.4 Component embedded suitability

Frontend-neutral components are evaluated by their actual dependencies, not by their directory name.

  • pure deterministic components should build in the embedded environment
  • desktop reader or filesystem implementations are selected out of embedded builds
  • a component that depends on standard hosted C file I/O must either isolate that dependency or be excluded with a recorded reason
  • tests should keep memory-reader or fixture-based paths available so embedded suitability does not depend on a desktop checkout

A hosted implementation is isolated by its own directory and build option rather than by a preprocessor branch, so the separation is visible in the source tree. components/assets holds the one such implementation in src/desktop/reader_stdio.c, selected by PET_ASSETS_STDIO_READER, which defaults off for a cross build.

A platform reaches a component by including cmake/pet_build_interfaces.cmake and adding the component directory, as recorded in ADR-010. It does not restate what a component owns, so the hosted and embedded builds cannot drift into different sources, standards, or warning contracts.

8.5 Dependency and local override policy

Fetched dependencies must have a project-owned local override policy where practical. This release is expected to address the carried dependency limitation for cmocka and SDL, and to avoid creating the same problem for ESP-IDF integration.

PET_CMOCKA_SOURCE_DIR and PET_SDL_SOURCE_DIR are the supported local source override variables, as recorded in ADR-008. An unset variable keeps the pinned FetchContent default. A set variable names a prepared source checkout and maps to CMake’s dependency-specific source override before the dependency is made available.

The variables may be provided directly to CMake or stored in the Git-ignored CMakeUserPresets.json. cmocka remains test-only and SDL remains SDL-frontend-only. Both retain their existing third-party diagnostic isolation.

ESP-IDF is local SDK and toolchain setup rather than a FetchContent dependency. Its supported environment and build model must be used without adding another project-specific checkout path.

The implemented policy:

  • keep pinned defaults for reproducible clean builds
  • allow local dependency locations without source edits
  • keep third-party diagnostics out of project diagnostics
  • document what is supported by the project and what remains local environment setup
  • does not claim package-manager support or guaranteed offline-first configuration

8.6 Host and frontend support libraries

No generic host support library is implemented by default in this release.

The firmware app is the second platform-host direction after desktop, so it provides evidence for the host support layer idea. The expected outcome remains a host conformance checklist and small pure helper functions before any optional pet_host_support library.

No generic frontend support library is implemented by default. frontends/tft is the next frontend direction, but a real support library still needs duplication evidence from implemented frontends.

8.7 Testing and verification

Unit tests remain owned by the component that owns the behaviour.

Additional release evidence should cover:

  • project command entrypoint dispatches to the documented underlying tools
  • dependency overrides work or are explicitly recorded as unsupported
  • ESP-IDF build configures, compiles, and links the firmware foundation
  • Core compile lines do not include forbidden embedded SDK or frontend dependencies
  • selected frontend-neutral components either build under ESP-IDF or are excluded with a reason
  • allocation probe coverage cannot silently omit a newly added public Core operation
  • the presentation priority issue is fixed or explicitly deferred with a narrower follow-up

The boundary checks read declared policy rather than restating rules in each script. Include boundaries read source text, the Core symbol scan reads compiled output and hosted compile lines, tools/verify/embedded.py reads the embedded compile database, and tools/verify/probe.py compares the public operations of the Core archive against the operations the allocation probe object calls.

A check whose evidence is absent is reported as unavailable and is not counted as passing. The embedded boundary is the one such check, because the ESP-IDF build is external to the hosted gate, and --require turns its absence into a failure on a path that must not accept missing evidence.

8.8 Compatibility and support claims

E20 improves embedded support from architecture-preserved to cross-compile tested for the selected ESP-IDF esp32s3 target. It does not imply that every ESP32-class board, every T-Display revision, classic ESP32, Arduino, PlatformIO, Raspberry Pi Pico, or a physical hardware runtime is supported.

The version architecture records the exact claim at release completion.

8.9 Language and documentation

Developer documentation uses British English. Board names, vendor names, SDK names, and product links keep their official spelling.

8.10 Process diagnostics and exit status

The desktop app process diagnostic contract remains unchanged.

The firmware foundation may report build-time or link-time evidence through the gate rather than through a process exit status. A runtime diagnostic contract for embedded hardware is deferred until hardware execution is in scope.

8.11 Greet presentation rule

A greet sets the happy expression and the attentive activity in one call, and the presentation mapping answers a known expression ahead of the activity it covers. The product rule of a greet is therefore a short happy reaction followed by the visible remainder of the attentive dwell, and then a settled idle pet.

The rule is held by one ordering invariant. An expression dwell that an action starts must be shorter than an activity dwell the same action starts, because the covering expression would otherwise outlast the covered activity and that activity role could never reach a screen. PET_HAPPY_FOR_MS is 10000 and PET_ATTENTIVE_FOR_MS is 30000, and a Core test asserts the ordering rather than the values, as recorded in ADR-011.

The role priority itself is unchanged, so an expression still answers ahead of an activity and a renderer still receives roles rather than Core enumerations.

9. Architecture decisions

9.1 Accepted decisions

  • v0.3.0 is the embedded firmware foundation and project UX release
  • ESP-IDF is the selected embedded framework for this release
  • T-Display boards use the boards/t_display family selector, with s3 as the only implemented variant and ESP-IDF esp32s3 as its mapped target, as recorded in ADR-009
  • the embedded firmware app foundation belongs under apps/firmware
  • the stable T-Display contract and selection belong under boards/t_display
  • T-Display S3 facts belong under boards/t_display/variants/s3
  • small TFT display presentation direction belongs under frontends/tft
  • ST7789 is the first controller family considered inside frontends/tft
  • ESP-IDF build and platform glue belongs under platforms/esp_idf
  • the firmware foundation must be reusable by later hardware runtime work, not a disposable probe
  • embedded runtime assets should be generated artefacts derived from canonical PNG and manifest sources
  • runtime embedded firmware is not required to parse the text manifest or decode PNG
  • the simple project command entrypoint wraps existing workflows instead of replacing their authority
  • the command surface is root pet.py with build, test, run desktop, strict verify, clean, dry-run, compact composition selection, and direct maintainer workflow documentation
  • all four frontend-neutral components are selected for embedded build evidence, and the desktop asset reader is a build selection rather than a component requirement
  • a platform reuses component build files through shared build interfaces rather than restating them, as recorded in ADR-010
  • a greet presents a short happy reaction and then the attentive activity, held by an action dwell ordering invariant rather than by a change to role priority, as recorded in ADR-011
  • cmocka and SDL use the project-owned local source override policy in ADR-008
  • ESP-IDF remains externally installed SDK and toolchain setup rather than a fetched dependency
  • the firmware foundation remains outside the hosted composition registry; direct idf.py is its build authority
  • board selection remains a separate future target dimension rather than another frontend
  • generic host and frontend support libraries remain deferred unless implementation evidence justifies them

9.2 Open decisions

The remaining decisions have explicit implementation or later-release ownership.

DecisionOwner
First embedded asset converter and generated formatLater display runtime PBI or release, followed by an ADR before any compatibility promise
TFT controller selection and compile-time configuration boundaryLater display runtime PBI or release
ST7789 bus, colour, rotation, and framebuffer strategyLater display runtime PBI or release
Hardware runtime diagnostic contractLater hardware runtime PBI or release

Resolved choices with meaningful alternatives receive ADRs when they become durable commitments.

9.3 Architecture deviations

No deviation from the general architecture is accepted for this release.

Any later deviation must be recorded here with its reason, impact, and tracking PBI.

10. Quality requirements

10.1 Requirement mapping

Requirementv0.3.0 tacticEvidence
SPEC-PR-007TFT direction stays outside Core and board config stays outside frontend-neutral presentationdependency and boundary checks
SPEC-FR-025firmware foundation consumes public snapshots and selected presentation componentsbuild and link evidence
SPEC-FR-026TFT frontend direction is separate from SDL, e-ink, OLED, board pins, and controller-specific detailsarchitecture review
SPEC-FR-028headless composition remains verifiedstrict gate
SPEC-FR-029generated embedded assets remain derived from canonical sources and Core knows no asset formatboundary checks and documentation
SPEC-NFR-001ESP-IDF build proof while keeping SDK out of CoreESP-IDF build and Core dependency scan
SPEC-NFR-002allocation probe coverage tightened and embedded component suitability evaluatedallocation and build checks
SPEC-NFR-003workflow wrapper dispatches to existing test and gate toolstool tests
SPEC-NFR-006app, board, frontend, platform, and tool boundaries are explicitreview and boundary checks
SPEC-NFR-007support claims distinguish build evidence from runtime evidencerelease evidence

10.2 Required test areas

  • project command entrypoint parsing and command planning
  • wrapper calls or dry-runs that map to existing build, test, run, verify, and clean workflows
  • pinned and local dependency source configuration for cmocka and SDL
  • ESP-IDF configure, compile, and link evidence for the firmware foundation
  • Core boundary checks against ESP-IDF, board, display, SDL, filesystem, and network dependencies
  • embedded build selection for selected frontend-neutral components
  • stdio reader exclusion or isolation for embedded builds
  • allocation-probe public API coverage
  • presentation role priority around attentive and happy behaviour
  • continued headless and desktop SDL gate coverage

10.3 Required development checks

The strict gate continues to apply to implementation PBIs. This release adds embedded verification steps for the selected ESP-IDF target.

The release gate must cover:

  • the existing strict gate for supported hosted compositions
  • ESP-IDF build proof for the firmware foundation
  • dependency and include boundary checks relevant to the embedded split
  • allocation-probe coverage enforcement
  • documentation updates for every carried limitation touched by the release

10.4 Release compliance

The release complies with this architecture when:

  • all v0.3.0 exit criteria are satisfied
  • all v0.3.0 PBIs are complete
  • support claims match executed evidence
  • no excluded runtime capability is claimed
  • carried limitations are closed, narrowed, or linked to follow-up PBIs
  • this document reflects the implemented system

10.5 Release evidence

E20 records the following embedded evidence before the final release review:

  • . "$HOME/.local/opt/espressif/export.sh"; idf.py set-target esp32s3; idf.py build completed from platforms/esp_idf
  • ESP-IDF v6.0.2 selected esp32s3 and used bundled Xtensa GCC 15.2.0
  • the minimal project configured, compiled, linked pet_firmware.elf, and produced pet_firmware.bin at 0x23cb0 bytes
  • Core and apps/firmware compile commands contained no ESP-IDF include path or ESP_PLATFORM definition and ended in -std=c99
  • no device was flashed or run

The remainder of this section is completed at release review.

Expected evidence includes:

  • hosted strict or audit gate result for headless and desktop SDL compositions
  • ESP-IDF build command, target, toolchain version, and result
  • pinned-default and local dependency source configuration results
  • dependency boundary scan result for Core
  • selected component embedded build status
  • project command entrypoint verification
  • limitation closure or narrowing notes

11. Risks and technical debt

RiskImpactMitigation
firmware foundation becomes a disposable probelater runtime work has to be restarted under a different appname and structure it as apps/firmware, and document the path to display and input work
board pins leak into frontend or Core codeanother board requires invasive changeskeep stable selection under boards/t_display and S3 facts under variants/s3
ESP-IDF leaks into Pet CoreCore portability claim becomes falseenforce include and dependency boundary checks
TFT work grows into a board-specific frontendcontroller reuse is lostkeep TFT code under frontends/tft, controller-specific code narrow, and board data in the selected T-Display variant
generated embedded asset direction becomes a hidden compatibility promise too earlyconverter and format freeze before runtime needs are knownrecord direction now, require ADR for a committed generated format
runtime support is overstatedrelease claims become misleadinglabel build, cross-compile, and hardware runtime evidence separately
project command wrapper duplicates build truthworkflows diverge and hide failuresmake the wrapper call existing CMake, CTest, gate, and run commands
dependency override policy becomes ad hocclean and offline builds stay fragiledocument supported override variables and gate what is practical
targeted limitation work expands into unrelated platform workrelease becomes too broadkeep LIM-012, LIM-005, LIM-003, and LIM-010 owned by their related epics unless a PBI adds another item

12. Glossary

12.1 Terms

Firmware app foundation

The embedded host app under apps/firmware. It is intended to grow into later hardware runtime work.

ESP-IDF

Espressif’s official development framework used for this release’s embedded build evidence.

T-Display S3

The selected non-touch LILYGO ESP32-S3R8 display board with a 170 by 320 ST7789 panel.

Board configuration

The source area that owns board-specific facts such as pins, display geometry, backlight policy, and button pins.

TFT frontend

The frontend group for small raster TFT presentation. ST7789 is the first controller family under this group, but the group is not tied to one board vendor or one controller.

Generated embedded asset artefact

A target-specific runtime asset derived from canonical PNG and manifest sources. It is not canonical source.

Build tested

Compiled and linked with a named hosted or SDK toolchain. It does not imply hardware execution.

Runtime tested

Executed and verified on a named target.

12.2 References