Product Backlog Items
| Document version | Date | Summary |
|---|---|---|
| v1 | 2026-07-17 | Create the V0 backlog |
| v2 | 2026-07-20 | Add and refine the v0.2.0 backlog |
| v3 | 2026-07-24 | Archive v0.2.0 and open the next backlog |
| v4 | 2026-07-27 | Add v0.3.0 and complete E17 planning |
| v5 | 2026-07-27 | Record completed v0.3.0 PBIs through E20 |
| v6 | 2026-07-27 | Clarify the T-Display family and selected S3 variant contract |
| v7 | 2026-08-01 | Archive the completed v0.3.0 backlog and open the next release backlog |
| v8 | 2026-08-02 | Add the v0.4.0 local persistence foundation backlog |
| v9 | 2026-08-03 | Bring the wall-clock stamp and bounded absence into v0.4.0 scope |
| v10 | 2026-08-04 | Archive the completed v0.4.0 backlog and await the next release backlog |
| v11 | 2026-08-05 | Add the v0.5.0 board runtime and embedded asset pipeline backlog |
1. Purpose
This document defines the Product Backlog Items for V0. It decomposes the epics in epics into independently verifiable increments.
The backlog is ordered by dependency and risk. A PBI may be refined before implementation, but its outcome and acceptance criteria must remain aligned with the specification, milestones, the general architecture, and the active version architecture document.
2. PBI structure
Each PBI contains:
- an epic reference
- an intended outcome
- the work included in the PBI
- acceptance criteria
- dependencies
Implementation details may change when evidence supports a better solution. Acceptance criteria describe required behaviour and evidence rather than a preferred internal implementation.
3. Shared Definition of Done
Every completed PBI must satisfy all applicable acceptance criteria and the following shared rules.
3.1 Required strict quality gate
The strict quality gate must run after every PBI that changes code, build configuration, tests, or developer tooling. It includes:
- formatting verification with
clang-format - a clean GCC build using ISO C99 without compiler extensions
- the complete unit test suite built and run with GCC
- a clean Clang build using ISO C99 without compiler extensions
- the complete unit test suite built and run with Clang
- the agreed GCC and Clang warnings treated as errors for project code
- Cppcheck analysis of project code
- parallel Clang-Tidy analysis of project code
- an AddressSanitizer build and test run
- an UndefinedBehaviourSanitizer build and test run
- a Pet Core symbol scan against the allowlist for the toolchain that built the archive
- a self-containment compilation of every public header, alone, for GCC and Clang
A documentation-only PBI does not require compiler checks unless it changes a technical contract that can be verified immediately.
If a required check cannot run, the PBI is not complete unless the maintainer explicitly accepts and records the exception.
The canonical strict gate runs on Linux. A Windows developer runs the native Windows gate before handover. The PBI remains incomplete until the canonical Linux strict gate also passes. This keeps the completion rule consistent without requiring Linux-only tools on Windows.
The native Windows gate includes formatting verification, MSVC warnings, an MSVC build, CTest, and Cppcheck. An optional Windows Clang and Ninja gate adds parallel Clang-Tidy, ASan, and UBSan where the selected toolchain supports them. Valgrind is not a Windows requirement.
3.2 Audit quality gate
The audit quality gate includes the strict gate plus:
- branch coverage generation
- Valgrind memory analysis
- runtime allocation verification of Pet Core, requiring zero heap usage
- clean rebuilds from empty build directories
- release support matrix verification
The audit gate runs:
- before a version release
- before closing a milestone
- after material ownership, storage layout, capacity, or lifetime changes
- when requested by the assigned PBI
Coverage and Valgrind do not need to run after every ordinary PBI.
3.3 Scope and documentation
Before a PBI is complete:
- its acceptance criteria must be checked
- relevant tests must be added or updated
- affected component knowledge files must be updated when required by agent rules
- progress and last development must be updated according to agent rules
- newly discovered deferred work must be recorded in the appropriate backlog or limitation file
- unrelated behaviour must not be added to the PBI
3.4 Portability status
Linux GCC and Linux Clang are the verified host toolchains for v0.1.0.
Windows compatibility is a design requirement from the first PBI. Project code, public headers, paths, CMake logic, tests, and developer workflows must avoid unnecessary POSIX assumptions. Windows must not be described as build tested until the project has been built and tested using an actual Windows developer environment or Windows CI runner.
Embedded portability is also a design requirement. It does not mean that v0.1.0 supports an embedded deployment. Pet Core must remain independent from operating system windows, filesystems, sockets, threads, sensors, and platform clocks.
MSVC is the native Windows compatibility compiler. Windows uses C17 mode to compile the C99 Core because MSVC does not provide a C99 language mode. GCC and Clang remain the strict C99 conformance toolchains. An optional Windows Clang and Ninja configuration owns compilation database analysis and sanitiser checks.
4. Quality tooling policy
4.1 Tool names
Project configuration and commands use unversioned executable names:
gcc
clang
clang-format
clang-tidy
run-clang-tidy
cppcheck
gcovr
valgrind
cmake
ninja
nm
python3Local environments may select a specific installed version outside project files when required.
4.2 Formatting baseline
The initial .clang-format configuration is:
Language: C
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
ColumnLimit: 100
PointerAlignment: Right
BreakBeforeBraces: Attach
SpaceBeforeParens: ControlStatements
SpaceAfterCStyleCast: false
IndentCaseLabels: true
BreakBeforeBinaryOperators: None
SortIncludes: Never
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: true
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false4.3 Clang-Tidy baseline
The initial .clang-tidy configuration is based on:
Checks: >
clang-analyzer-*,
bugprone-*,
cert-*,
misc-*,
performance-*,
portability-*,
readability-*,
-readability-magic-numbers,
-readability-identifier-length,
-readability-function-cognitive-complexity,
-readability-braces-around-statements,
-misc-include-cleaner,
-bugprone-easily-swappable-parameters,
-performance-enum-size
WarningsAsErrors: '*'
HeaderFilterRegex: '.*/(src|include|frontends|tests)/.*'
ExcludeHeaderFilterRegex: '.*/(build|_deps|third_party)/.*'
SystemHeaders: false
FormatStyle: fileClang-Tidy must analyse only project translation units and project headers. Dependencies may still be parsed when required to understand project code, but diagnostics from system headers, generated files, fetched dependencies, and third-party code must not be treated as project findings.
The check list may be refined when a check is demonstrably unsuitable for C99 or conflicts with an explicit project rule. Disabling a check requires a short recorded reason.
5. Archived releases
Completed v0.1.0 PBIs are archived in release v0.1.0. That archive holds
PBI-001 through PBI-034 with their outcomes, included work, acceptance criteria, and dependencies,
grouped by epic E01 through E07.
Completed v0.2.0 PBIs are archived in release v0.2.0. That archive holds
PBI-035 through PBI-063 with their outcomes, included work, acceptance criteria, and dependencies,
grouped by epic E08 through E16.
Completed v0.3.0 PBIs are archived in release v0.3.0. That archive holds
PBI-064 through PBI-085 with their outcomes, included work, acceptance criteria, and dependencies,
grouped by epic E17 through E23.
Completed v0.4.0 PBIs are archived in release v0.4.0. That archive holds
PBI-086 through PBI-102 with their outcomes, included work, acceptance criteria, and dependencies,
grouped by epic E24 through E29.
PBI identifiers continue after PBI-102. They are permanent and are not reused, so a future release
never restarts the sequence. PBI-102 was opened after PBI-101 and belongs to E24, so the highest
identifier does not sit in the last epic of its release.
6. Release v0.5.0 PBIs
The release goal and expected capabilities are recorded in
milestones, the epic map in epics,
and the concrete architecture in architecture for v0.5.0. PBI identifiers
continue from PBI-103. ADR-015 was written during planning, so the ADRs this release’s epics write
continue from ADR-016.
A new PBI is added under its epic heading and follows the structure in section 2, the shared Definition of Done in section 3, and the quality tooling policy in section 4.
Device work has an evidence rule of its own. A PBI whose acceptance depends on hardware is complete only when a maintainer has run it on the classic board and the observation is recorded. No agent, no gate, and no build output may stand in for that observation.
E30 v0.5.0 architecture and release scope
PBI-103 Accept the v0.5.0 version architecture [+]
Epic: E30 v0.5.0 architecture and release scope
Outcome: The v0.5.0 release has an accepted architecture document that defines the run loop, the
frontend split, the pack and board profile ownership, the verification composition, and the support
claim limits before implementation begins.
Included work:
- review
docs/arch/arch-v0.5.0.mdagainst the milestone entry and the epic map - keep the required arc42 top level structure
- confirm that no ESP-IDF, board, panel, or GPIO dependency reaches the Core or a hosted composition
- confirm that asset facts and board facts have no overlapping owner
- confirm that the support matrix separates hosted evidence, cross-build evidence, and device observation
- name the decisions that require an ADR and the epic that writes each one
- mark the document accepted and link it from the milestone entry
Acceptance criteria:
- every required architecture section exists
- the run loop, the time source, and the delta bound policy are recorded with their reasons
- the frontend split names which sources are hosted-buildable and which are backend-only
- the pack carries no board offset, no rotation, and no panel colour order in the recorded format
- the architecture records which claims come from a gate and which come from a maintainer
- the milestone entry links the accepted document and the release status reflects it
Dependencies: None
PBI-104 Record the device evidence model and the serial diagnostic contract [+]
Epic: E30 v0.5.0 architecture and release scope
Outcome: What counts as device evidence, and what a serial transcript may be used to prove, are written down before any device work produces output that a release will quote.
Included work:
- record the diagnostic line format, its prefix, and its key-value shape
- record the event vocabulary and which events are contractual
- record which fields an event carries and how an unknown field is treated
- record what a transcript proves and what it cannot prove
- record the maintainer observation policy, including what must be observed for the panel, the buttons, and a continuous run
- record the soak duration and the readings it must capture
Acceptance criteria:
- the line format and the event vocabulary are recorded in the version architecture
- a free-form status line is explicitly excluded as release evidence
- the transcript boundary states that physical panel output is not proven by a transcript
- the observation policy names the panel, the button, and the soak observations separately
- the soak duration and its heap readings are stated rather than left to judgement
Dependencies: PBI-103
PBI-105 Record the hosted firmware and TFT verification composition decision [+]
Epic: E30 v0.5.0 architecture and release scope
Outcome: The mechanism that makes the firmware and TFT sources reachable by the hosted gate is decided and recorded, so the epics that depend on it implement a decision rather than reopen it.
Included work:
- record the registry composition as the accepted mechanism and the rejected alternative with its reason
- record the app and frontend entries, their targets, and the derived composition name
- record why the composition name carries no suffix and where its claim boundary is stated instead
- record which tooling the new composition affects, including the gate helper that assumes no hosted firmware composition
- write the ADR for the decision and its alternatives
Acceptance criteria:
- the accepted mechanism and the rejected alternative are both recorded with reasons
- the composition name is explained as derived rather than chosen
- the claim boundary states that the composition is build and test evidence and not a device claim
- the affected tooling is named so the implementing PBI cannot discover it late
- the ADR records the alternatives and the consequences
Dependencies: PBI-103
E31 Board execution and panel bring-up
PBI-106 Add flash and monitor to the project command entrypoint [+]
Epic: E31 Board execution and panel bring-up
Outcome: A maintainer can flash the firmware and read its serial output through the project command entrypoint instead of remembering an SDK invocation.
Included work:
- add
flashandmonitorcommands following the existing command-first grammar - accept a port argument and a dry-run option consistent with the existing commands
- delegate to the ESP-IDF tooling without duplicating its behaviour
- report a missing environment or a missing port as a clear failure rather than a traceback
- extend
tools/tests/test_pet.pyto cover the new surface, including invalid arguments - document the commands in the development workflow
Acceptance criteria:
./pet.py flashand./pet.py monitorexist and follow the existing grammar- a dry run prints the planned command without executing it
- an absent ESP-IDF environment produces a named failure rather than an unhandled error
- the project command suite covers the new commands and their argument errors
- the development workflow documents both commands and the raw SDK equivalents
Dependencies: PBI-103
PBI-107 Bring up the ST7789 panel on the classic board [+]
Epic: E31 Board execution and panel bring-up
Outcome: The classic T-Display panel is lit from the project firmware and shows a deliberate pattern, which is the first physical output the project has ever produced.
Included work:
- initialise the SPI bus, the panel handle, the reset sequence, and the backlight through
esp_lcd - apply the orientation, gap, colour order, and inversion settings the board needs
- draw a diagnostic pattern that makes geometry and colour errors visible, such as edge markers and primary colour fields
- transfer the pattern through a full-frame draw
- report panel readiness and panel failure through the diagnostic events
- keep every ESP-IDF call inside the backend that owns it
Acceptance criteria:
- the panel lights and shows the diagnostic pattern on the physical classic board
- the pattern reaches all four edges of the visible area
- a panel initialisation failure is reported as a fault event rather than a reset loop
- no ESP-IDF call appears outside the backend
- the ESP-IDF build continues to configure, compile, and link, and the hosted gate is unaffected
Dependencies: PBI-106
PBI-108 Measure and record the classic panel profile [+]
Epic: E31 Board execution and panel bring-up
Outcome: The board profile carries measured panel facts, and a reader can tell which values were measured and which remain vendor-documented.
Included work:
- measure the visible area, the panel offsets, the native orientation, and the transfer orientation
- measure the colour order and whether the colour path is inverted
- record the values in the classic variant header with their provenance
- replace the blanket unverified comment with per-value provenance
- record the pixel encoding the measured colour path consumes, which the pack format later fixes
- update the board documentation to match
Acceptance criteria:
- the measured values are recorded in the classic variant header
- each recorded value states whether it is measured or vendor-documented
- the recorded pixel encoding is the one the panel consumed in the observed pattern
- a colour or geometry error in the diagnostic pattern would have been visible with these values
- no measured value is asserted for a variant this release did not run
Dependencies: PBI-107
PBI-109 Implement the serial diagnostic line format [+]
Epic: E31 Board execution and panel bring-up
Outcome: The firmware emits diagnostics in the contractual format, so a transcript can be quoted as release evidence rather than read as free text.
Included work:
- implement the diagnostic emitter in the firmware application
- emit the boot and display readiness events with their recorded fields
- emit a fault event with a named reason
- keep the event vocabulary in one place rather than spread across call sites
- add host tests over the formatting of each event
- replace the existing ad hoc firmware output
Acceptance criteria:
- every emitted line follows the recorded prefix, event, and key-value shape
- the event names match the recorded vocabulary
- host tests assert the formatted output of each event
- no free-form status line remains in the firmware
- the emitter performs no dynamic allocation
Dependencies: PBI-104, PBI-107
E32 Continuous embedded runtime
PBI-110 Add the monotonic time source and the bounded delta policy [+]
Epic: E32 Continuous embedded runtime
Outcome: The firmware derives its elapsed time from a monotonic platform clock through a seam a host test can replace, and it never hands the Core more time than the bound allows.
Included work:
- define the time seam the application reads and the platform implements
- implement the ESP-IDF monotonic source behind that seam
- convert the platform value to milliseconds and derive the delta from the previous reading
- clamp the delta to the recorded bound and account for what was clamped
- emit the clamp through a diagnostic rather than dropping it silently
- write the ADR for the run loop and time source policy, including the rejected alternatives
Acceptance criteria:
- the application reads time through a seam rather than through an SDK call
- the delta delivered to the Core is monotonic and never exceeds the recorded bound
- a clamped delta produces a diagnostic naming the clamp
- host tests drive the derivation with supplied values, including a clamp and a stalled clock
- the ADR records the policy, the bound, and the alternatives
- the bound sits inside the single-update bound the Core already enforces
Dependencies: PBI-103
PBI-111 Convert the firmware application into a continuous run loop [+]
Epic: E32 Continuous embedded runtime
Outcome: The firmware application runs forever in normal operation, and the same lifecycle can be driven a fixed number of iterations by a host test.
Included work:
- restructure the application around one iteration function and one non-returning driver
- keep the world alive across iterations rather than initialising and resetting per run
- pace the loop so it yields rather than busy spins
- emit the runtime readiness event once the loop is established
- add host tests that drive a fixed number of iterations with supplied time values
- keep the application free of dynamic allocation
Acceptance criteria:
- the application does not return in normal operation
- one iteration function is shared by the device driver and the host tests
- the loop yields between iterations and does not busy spin
- host tests drive iterations deterministically and assert the resulting world and snapshot
- the firmware performs no dynamic allocation of its own
- the runtime readiness event is emitted once rather than per iteration
Dependencies: PBI-110
PBI-112 Observe a continuous device run [+]
Epic: E32 Continuous embedded runtime
Outcome: The board is observed running continuously for the recorded soak duration, which is the first evidence that the runtime survives more than a boot.
Included work:
- flash the firmware and run the board for the recorded soak duration
- capture the serial transcript for the whole run
- record the minimum free heap at the start and at the end
- record the observed iteration pace and the presentation progress, which is the progress the
transcript evidences until
PBI-116puts the pet on the glass - record any reset, watchdog abort, stall, or repeated fault
- file a bug for any defect found rather than fixing it inside this PBI
Acceptance criteria:
- the run reaches the recorded soak duration on the physical classic board
- the transcript shows no unexpected reset and no watchdog abort
- the minimum free heap does not fall continuously across the run
- the presentation continues to progress at the end of the run
- the observation is recorded with its date, duration, and readings
Dependencies: PBI-111
E33 TFT presentation frontend
PBI-113 Register the firmware and TFT composition [+]
Epic: E33 TFT presentation frontend
Outcome: The firmware application and the TFT frontend are a selectable composition, so the hosted gate builds and tests them the same way it builds every other composition.
Included work:
- add the
firmwareapp and thetftfrontend entries toconfig/compositions.json - confirm the composition resolves and its directories and targets exist
- extend the composition, gate, and project command suites for the new composition
- reconcile the gate helper that adds firmware and board includes because no hosted firmware composition existed
- confirm that the new composition passes the strict gate before any frontend source is added
- run the firmware host tests that
PBI-109registered but no composition could reach
Acceptance criteria:
firmware-tftresolves through the registry and appears in the composition listing- the composition configures, builds, and tests through the existing commands
- the composition, gate, and project command suites cover it
- the reconciled gate helper reflects what is now true rather than what was true before
pet_firmware_testsis configured, run, and reported by the gate rather than compiled by hand- the headless and desktop compositions are unaffected
Dependencies: PBI-105
PBI-114 Create the TFT frontend contract and the frame buffer surface [+]
Epic: E33 TFT presentation frontend
Outcome: The TFT frontend has a public contract and a caller-owned frame buffer surface with pixel operations that a host test can assert.
Included work:
- define
pet_frontend_tftwith its status values, configuration, and lifecycle - define the surface over a caller-owned frame buffer with its dimensions and pixel encoding
- implement pixel, rectangle, and clipping operations that never write outside the buffer
- keep every operation free of allocation and free of platform headers
- add host tests over the surface, including clipping at every edge and a zero-sized region
- write the ADR for the full frame buffer strategy and its rejected alternatives
Acceptance criteria:
- the contract compiles in the hosted composition with no ESP-IDF header present
- a write outside the surface is clipped rather than performed
- the surface holds no static mutable state and allocates nothing
- host tests cover clipping at each edge, a zero-sized region, and a full-surface fill
- the ADR records the frame buffer strategy, its memory cost, and the streaming alternative
Dependencies: PBI-113
PBI-115 Compose the pet from a snapshot [+]
Epic: E33 TFT presentation frontend
Outcome: A snapshot becomes a composed frame through role selection, scaling, and placement, and an unchanged selection composes nothing.
Included work:
- map a snapshot to a presentation role through the existing presentation component
- place and scale the presentation area through the existing layout component
- compose the background and the pet into the frame buffer
- implement the procedural fallback appearance that needs no asset
- skip composition when the selection equals the one already presented
- add host tests over selection, placement, scaling, the fallback, and the skip rule
Acceptance criteria:
- the frontend receives a snapshot and never a mutable world pointer
- the composed output is a deterministic function of the snapshot. animation time is not an input
while the appearance is procedural, and it enters with the pack at
PBI-121 - an unchanged selection composes nothing and reports that nothing changed
- the fallback composes with no asset source present
- scaling and placement come from the layout component rather than from frontend arithmetic
- host tests assert the composed buffer contents rather than only the call sequence
Dependencies: PBI-114
PBI-116 Add the ESP-IDF display backend and present on the panel [+]
Epic: E33 TFT presentation frontend
Outcome: The composed frame reaches the physical panel through a thin backend, and the pet is visible on the board through the fallback path.
Included work:
- move the panel bring-up from the diagnostic path into the frontend display backend
- transfer the composed buffer with one full-frame draw per changed frame
- translate panel errors into frontend status values
- select the backend by build option so it is absent from every hosted composition
- emit the display readiness event with the measured geometry
- observe the pet on the physical board
- confirm on the panel that the presentation keeps progressing across a long run, which
PBI-112could only evidence from the transcript because nothing but the bring-up pattern was on the glass
Acceptance criteria:
- the backend is absent from the hosted composition and present in the embedded build
- a changed frame produces exactly one full-frame transfer
- an unchanged frame produces no transfer
- a panel error becomes a frontend status and a fault event rather than an abort
- the pet is visible on the physical classic board through the fallback appearance
- the embedded boundary check holds over the backend sources
Dependencies: PBI-115, PBI-108
E34 Embedded asset pack and converter [+]
PBI-117 Decide and record the embedded asset pack format [+]
Epic: E34 Embedded asset pack and converter
Outcome: The pack format is decided, versioned, and recorded before any code writes or reads one.
Included work:
- decide the header, the magic value, the format version, and the field widths
- decide how the compiled presentation structure is carried and how image indices replace paths
- decide the entry table, the pixel encoding, the byte order, and the transparency representation
- decide the compatibility promise and record that it is narrower than the save format promise
- record the rejected alternatives, including pre-composition and a chroma key
- write the ADR for the format and the converter contract
Acceptance criteria:
- the format table is recorded field by field with widths and order
- the compiled presentation structure carries every record the canonical manifest declares
- the format carries no board offset, no rotation, and no panel colour order
- the declared pixel encoding matches the measured panel path
- the compatibility promise is stated rather than implied
- the ADR records the rejected alternatives with their reasons
Dependencies: PBI-108
PBI-118 Implement the deterministic converter [+]
Epic: E34 Embedded asset pack and converter
Outcome: A project-owned converter compiles the canonical manifest and its images into one pack, deterministically and with no dependency beyond the standard library.
Included work:
- parse the canonical manifest and resolve its images, animations, roles, and fallback chain in a
module of its own, importable and testable without the pack encoder, following
ADR-015 - decode the accepted PNG subset and reject everything outside it with a named reason
- convert pixels to the declared encoding and build the transparency representation
- write the pack with its header, presentation structure, entry table, and payloads
- fail without writing a partial pack
- add
tools/tests/test_pack.pycovering determinism, a known expected output, and each rejection - open the limitation for the manifest grammar now having two readers, naming
ADR-015as the accepted resolution and the first grammar change as the signal that it is due
Acceptance criteria:
- equal inputs produce byte-identical packs across repeated runs
- the canonical asset set converts to the recorded expected pack
- an unsupported colour type, bit depth, or interlace is rejected with a named reason
- a failure leaves no output file behind
- the converter imports nothing outside the standard library
- the converter suite runs as a gate step beside the existing tool suites
- the grammar module is exercised by tests that construct no pack, so it can move to its later home without carrying the encoder with it
- the grammar reader rejects everything
components/manifestrejects, over the same cases, so the two readers are known to agree at the moment the second one is introduced - the limitation is recorded with its trigger rather than left in a comment
Dependencies: PBI-117
PBI-119 Generate the pack from the build [+]
Epic: E34 Embedded asset pack and converter
Outcome: The pack is a build output produced from the canonical sources, so no device can ever run a pack that somebody forgot to regenerate.
Included work:
- add the pack generation step to the build with the canonical sources as its inputs
- place the output in the build directory and keep it out of the source tree
- make the builds that need a pack depend on the generation step
- confirm that a changed sprite or manifest regenerates the pack
- keep the hosted builds able to generate a pack for their tests
Acceptance criteria:
- the pack is generated into the build directory and no pack is committed
- a changed canonical source regenerates the pack on the next build
- a build that needs a pack cannot run before the pack exists
- the hosted compositions can generate a pack for their tests
- a clean tree build produces the pack without a manual step
Dependencies: PBI-118
E35 Embedded asset-backed presentation
PBI-120 Implement the embedded pack reader [+]
Epic: E35 Embedded asset-backed presentation
Outcome: The pack reader accepts a valid pack and rejects every malformed one before any lookup can reach a byte it should not.
Included work:
- add the reader to
components/assetsbehind its own build selection, which a cross build and a test build both take because the hosted gate is where the format is verified - validate the magic value, the format version, the declared sizes, and every entry offset
- answer a lookup with a pointer into the pack and a length, copying no pixel
- report a rejection reason the caller can present or log, drawn from a named set that covers the
acceptance rules and supplies the
pack-rejectedreason vocabulary - add host tests over a valid pack, a truncated one, a corrupted one, an unknown version, and an entry whose offset falls outside the payload, building the malformed variants from a minimal valid pack the test constructs and reading the generated canonical pack for the accepted case
Acceptance criteria:
- validation completes before any lookup is answered
- a rejected pack yields no pointer and a named reason
- the reason set covers every acceptance rule the contract lists and holds no unreachable value
- an accepted lookup returns a pointer into the pack rather than a copy
- the reader allocates nothing and holds no state beyond the borrowed pack bytes, whose lifetime belongs to the caller
- the desktop build is unaffected and keeps its manifest and image path
- the reader compiles in the embedded build with the boundary check holding
Dependencies: PBI-119
PBI-121 Materialise the presentation structure from a pack [+]
Epic: E35 Embedded asset-backed presentation
Outcome: A pack yields the same presentation structure the canonical manifest parses into, so the device runs the existing selection code rather than a second one.
Included work:
- materialise the compiled records into a caller-owned manifest with image indices in place of paths
- keep the materialisation bounded by the existing manifest capacities
- record the storage cost of the materialised structure
- take the composition canvas extents from the pack and remove the frontend default that
PBI-115left inpet_frontend_tft/frontend.h - give the presentation its animation time, which
PBI-115left out because a procedural appearance has no frames to time, carrying it from the application clock through the frontend contract - add host tests that parse the canonical manifest, materialise the pack, and compare the resolution of every role at several animation times, over the generated canonical pack
Composing a pack frame is PBI-122, so the appearance this PBI leaves on the surface is still the
procedural one. What changes here is where its extents and its timing come from.
Acceptance criteria:
- both structures resolve the same role, animation, frame, and duration for every canonical role
- the fallback chain resolves identically from both structures
- the materialisation allocates nothing and fits the recorded capacities
- a pack that declares more records than the capacities allow is rejected rather than truncated
- the canvas extents a frame is composed on come from the pack, and no frontend source states a canvas size of its own
- the storage cost is recorded where the release evidence can quote it
Dependencies: PBI-120
PBI-122 Present canonical frames on the board [+]
Epic: E35 Embedded asset-backed presentation
Outcome: The firmware image carries the pack and the canonical pet appears on the physical panel, which is the evidence that closes the embedded asset gap.
Included work:
- embed the generated pack into the firmware image as read-only bytes and reach them through a platform seam, so the application stays hosted-testable
- pass the embedded bytes to the reader at startup
- draw one pack frame into the surface through its colour payload and its one-bit mask, which is the first consumer the mask has had
- walk the resolution chain that architecture section 6.4 draws, so a missing entry or a geometry the surface cannot take reaches the fallback rather than a partial frame
- compose pack frames instead of the fallback when a pack is accepted
- emit the pack readiness and pack rejection events with their fields
- observe the canonical pet on the physical board
- confirm that a deliberately damaged pack falls back without ending the application
Acceptance criteria:
- the firmware image carries the pack and reports its size and entry count
- the canonical pet is visible on the physical classic board
- the presented frames come from the pack rather than from the fallback
- a damaged pack selects the fallback, reports a reason, and leaves the application running
- no pixel is copied out of the pack to present it
- the image size and the pack size are recorded for the release evidence
Dependencies: PBI-121, PBI-116
E36 Board input and semantic actions
PBI-123 Implement the pure button filter
Epic: E36 Board input and semantic actions
Outcome: Raw button levels become stable edges through a rule that a host test can drive completely, without a board and without a clock.
Included work:
- define the filter state, its inputs, and its outputs beside the frontend that consumes it
- implement the debounce interval and the edge derivation as a pure transition
- keep the rule free of allocation, static state, and platform headers
- add host tests over a clean press, a bouncing press, a held press, a release, and a rapid sequence
- record the chosen debounce interval with its reason
Acceptance criteria:
- one press produces exactly one press edge rather than one per sample
- a bouncing sequence within the interval produces no additional edge
- a held button produces no repeated press edge
- the rule is a function of its inputs and holds no hidden state
- host tests supply both levels and timestamps and assert every edge
- the debounce interval is recorded rather than left as a literal without a reason
Dependencies: PBI-113
PBI-124 Add the ESP-IDF input backend
Epic: E36 Board input and semantic actions
Outcome: Both board pins are configured and sampled on hardware, and the behaviour of the strapping pin is recorded rather than discovered later.
Included work:
- configure both button pins with the pull configuration the board needs
- sample both levels each iteration and supply the monotonic timestamp the filter needs
- keep all filter state outside the backend
- observe the behaviour of
GPIO 0at reset and during a run - record the observed pin behaviour in the board profile
- keep the backend absent from hosted compositions
Acceptance criteria:
- both pins are configured and sampled on the physical classic board
- the backend holds no filter state and makes no input decision
- the reset and runtime behaviour of
GPIO 0is recorded with what was observed - the backend is absent from the hosted composition and present in the embedded build
- sampling adds no measurable stall to the loop pace recorded earlier
Dependencies: PBI-123, PBI-111
PBI-125 Map a filtered edge to a semantic action
Epic: E36 Board input and semantic actions
Outcome: A button press becomes an existing semantic product action delivered through the public Core API, and nothing about the pin reaches the Core.
Included work:
- add the input mapping to the firmware application beside its other host responsibilities
- map one button to an existing action and decide the second button according to the recorded strapping behaviour
- deliver the action through the public Core API within the loop iteration
- emit the input diagnostic naming the button and the action
- add host tests over a mapped edge, an unmapped edge, and a rejected action result
Acceptance criteria:
- a filtered press produces exactly one semantic action
- an unmapped edge produces no action and no misleading diagnostic
- no GPIO number, pin, or button index appears in a Core call
- a rejected action result is reported rather than ignored
- the input diagnostic names the button and the action it produced
- host tests cover the mapping without a board
Dependencies: PBI-124
E37 Release verification and hardening
PBI-126 Run the release gates and record the build evidence
Epic: E37 Release verification and hardening
Outcome: The hosted and cross-build evidence for the release is produced from a clean tree and recorded where the release can quote it.
Included work:
- run the audit gate from a clean tree over headless, desktop-sdl, and firmware-tft
- run the ESP-IDF build and record the framework version, the toolchain, the image size, and the pack size
- run the support matrix step
- record the coverage, allocation, boundary, and tool suite results
- fix or record every failure rather than rerunning until it passes
Acceptance criteria:
- the audit gate passes from a clean tree over all three compositions
- the ESP-IDF build is recorded with its versions and sizes
- every gate result is recorded with the command that produced it
- an unavailable check is recorded as not run rather than as passing
- no evidence is recorded for a tree that later changed without rerunning the gate
Dependencies: PBI-112, PBI-122, PBI-125
PBI-127 Record the end-to-end device observation
Epic: E37 Release verification and hardening
Outcome: A maintainer observes the complete product path on the physical board, from a button press to a visible pet response drawn from the pack, and the observation is recorded as evidence.
Included work:
- flash the release firmware onto the classic board
- observe the canonical pet presented from the pack
- observe a button press producing a visible response
- capture the serial transcript covering boot, pack readiness, runtime readiness, and the input event
- record what was observed, by whom, and when
- keep the observation separate from every automated result
Acceptance criteria:
- the observation covers the panel, the pack-backed presentation, and the button response
- the transcript follows the recorded format and matches what was observed
- the record names the observer, the date, the board, and the firmware version
- the evidence file presents the observation as maintainer observation rather than as a check
- a fallback-only presentation would have failed this observation rather than passing it
Dependencies: PBI-126
PBI-128 Reconcile the limitations and the support claims
Epic: E37 Release verification and hardening
Outcome: Every limitation this release touched is closed, narrowed, or carried deliberately, and no support claim is broader than the evidence behind it.
Included work:
- close
LIM-012for the classic variant onesp32only - close
LIM-013on the strength of the canonical frame evidence - keep
LIM-015open and correct its tracking column - open
LIM-018for the absent hardware-in-the-loop gate, separating hosted assertions from physical observation - review
LIM-011and leave it unchanged - update the support matrix and the architecture support claims
Acceptance criteria:
- the closed limitations name the evidence that closed them
- no closed limitation implies a claim for another variant, board, or target
LIM-015no longer names this release as its ownerLIM-018separates what a hosted test asserts from what only a person observed- the support matrix records no device claim as automated evidence
- every limitation the release did not touch is left open by decision rather than by omission
Dependencies: PBI-127
PBI-129 Complete the release documentation and archive
Epic: E37 Release verification and hardening
Outcome: The release is closed with its evidence, its archive, and its documents consistent with what was actually built.
Included work:
- write the release evidence file following the structure of the previous release
- tick the milestone exit criteria or record why one is carried
- update the version architecture to reflect the implemented system
- set the project version and prepare the archive under
docs/releases/v0.5.0/ - follow the release process for the archive, the rollover, and the tag
- update the roadmap so it no longer describes scope this release now owns
Acceptance criteria:
- the evidence file records every claim with the check or observation behind it
- every milestone exit criterion is ticked or carried with a stated reason
- the version architecture matches the implemented system
- the archive holds the epics, PBIs, limitations, bugs, progress, and evidence for the release
- the roadmap no longer describes the delivered direction
- the release process steps that remain for the maintainer are named explicitly
Dependencies: PBI-128
7. Deferred backlog areas
The following areas remain outside the active PBI set:
- digital adapters such as Git activity
- physical sensor adapters
- networking and local device discovery
- multiple pets and household relationships
- long-term traits, marks, memories, and maturity
- a non-volatile storage implementation of the storage contract and its flash layout
- wireless facilities, over-the-air updates, and power management on the board
- board variants and embedded targets other than the classic T-Display on
esp32 - partial or dirty-region display updates
- an automated hardware-in-the-loop verification gate
- automatic saving, automatic loading, and a save location policy for a packaged product
- a Core allocator or arena without evidence from a later version requirement
- Windows build verification without a Windows environment or runner
These areas must be introduced through a version architecture document and its PBIs rather than being added opportunistically to the current release.
A visual frontend was deferred throughout v0.1.0 and is the subject of v0.2.0, so it is no longer
listed here. The list as it stood at the close of v0.1.0 is preserved in
release v0.1.0.
The list as it stood at the close of v0.2.0 is preserved in
release v0.2.0, the list at the close of v0.3.0 in
release v0.3.0, and the list at the close of v0.4.0 in
release v0.4.0.
Durable saves were deferred throughout v0.1.0 to v0.3.0 and are the subject of v0.4.0, so they
are no longer listed here. What that release deliberately left undone is listed above instead, and
LIM-015 and LIM-017 carry the two entries that a later release owns.
The embedded display runtime and the embedded asset path were deferred through v0.4.0 and are the
subject of v0.5.0, so they are no longer listed here either. What that release deliberately leaves
undone is listed above, and LIM-015 and the new hardware-in-the-loop entry carry the parts a later
release owns.