mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 14:01:12 +00:00
[AZ-619] Phase A: build_pre_constructed seeds c13_fdr + clock
Adds airborne_bootstrap.build_pre_constructed(config) returning a dict with the two foundational keys: a per-binary shared FdrClient under "c13_fdr" (via make_fdr_client with the new AIRBORNE_MAIN_PRODUCER_ID constant) and a fresh WallClock under "clock". Phases B..F (AZ-620..AZ-624) extend this function additively without breaking the AZ-619 contract. The c13_fdr instance is identity-stable across calls (per the make_fdr_client per-producer cache) so callers can call build_pre_constructed twice and get the same FdrClient back - AC-619.2. Replay-mode override is unchanged: compose_root merges replay_components over pre_constructed so the WallClock here is replaced by TlogDerivedClock in replay binaries (existing contract documented in compose_root's docstring). Tests: 5 new unit tests under tests/unit/runtime_root/ test_az619_pre_constructed_phase_a.py, all passing. AZ-591 not regressed (12/12 in the combined run). Spec moved to _docs/02_tasks/done/. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
# AZ-619 — Phase A: build_pre_constructed seeds c13_fdr + clock
|
||||
|
||||
**Task**: AZ-619_pre_constructed_phase_a_c13_fdr_clock
|
||||
**Name**: AZ-618 Phase A: build_pre_constructed seeds c13_fdr + clock
|
||||
**Description**: Foundational subtask of AZ-618. Introduces `airborne_bootstrap.build_pre_constructed(config) -> dict[str, Any]` and seeds the two simplest entries: `c13_fdr` (per-binary single FdrClient via `make_fdr_client("airborne_main", config)`) and `clock` (`WallClock()`). The function is additive — phases B..F (AZ-620..AZ-624) extend it without breaking this contract.
|
||||
**Complexity**: 2 points
|
||||
**Dependencies**: AZ-591 (registry seam), AZ-273 (FdrClient), AZ-398 (WallClock). All in `done/`.
|
||||
**Component**: runtime_root (cross-cutting)
|
||||
**Tracker**: AZ-619
|
||||
**Epic**: AZ-602 (parent: AZ-618 umbrella)
|
||||
|
||||
## Outcome
|
||||
|
||||
- `src/gps_denied_onboard/runtime_root/airborne_bootstrap.py` exports a public `build_pre_constructed(config: Config) -> dict[str, Any]`.
|
||||
- The returned dict contains at least `c13_fdr` (FdrClient) and `clock` (WallClock).
|
||||
- Re-invocation in the same process returns dict where `c13_fdr` is the same FdrClient (per `make_fdr_client` cache); `clock` may be a fresh WallClock each call.
|
||||
- Unit tests under `tests/unit/runtime_root/test_az619_pre_constructed_phase_a.py` cover both ACs.
|
||||
|
||||
## Scope
|
||||
|
||||
### Included
|
||||
|
||||
- New module symbol: `airborne_bootstrap.build_pre_constructed(config)`.
|
||||
- Internal builders: `_build_c13_fdr(config) -> FdrClient` and `_build_clock(config) -> WallClock`. Replay-mode clock override is NOT done here — `compose_root` already merges `replay_components` over `pre_constructed` so `WallClock` gets replaced by `TlogDerivedClock` in replay mode. The contract is "live default; replay overrides".
|
||||
- `__all__` updated to export `build_pre_constructed`.
|
||||
- New unit test file: `tests/unit/runtime_root/test_az619_pre_constructed_phase_a.py` (AC-619.1, AC-619.2).
|
||||
|
||||
### Excluded
|
||||
|
||||
- All other 10 keys in `AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS` — AZ-620..AZ-623.
|
||||
- `runtime_root.main()` integration — AZ-624.
|
||||
- Full AC-1..AC-5 of the AZ-618 umbrella — AZ-624.
|
||||
- Jetson tier-2 verification — AZ-624 (per `_docs/02_document/tests/tier2-jetson-testing.md` Mandatory-Tier-2 Scope, this subtask is in scope but the actual Jetson run is consolidated at AZ-624 to avoid 6 separate Jetson runs for one feature).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
**AC-619.1: `build_pre_constructed(default_config)` returns required minimum keys**
|
||||
Given a default airborne `Config`
|
||||
When `build_pre_constructed(config)` is called
|
||||
Then the returned dict has key `c13_fdr` mapping to an `FdrClient` instance
|
||||
And key `clock` mapping to a `WallClock` instance
|
||||
And no other keys are required at this phase (additional keys are allowed for forward-compat).
|
||||
|
||||
**AC-619.2: c13_fdr is cached across calls**
|
||||
Given `build_pre_constructed(config)` has been called once and returned `dict_a`
|
||||
When `build_pre_constructed(config)` is called a second time, returning `dict_b`
|
||||
Then `dict_a["c13_fdr"] is dict_b["c13_fdr"]` (same instance via `make_fdr_client` cache).
|
||||
|
||||
**AC-619.3: unit tests exist**
|
||||
Given the changes above are landed
|
||||
When `pytest tests/unit/runtime_root/test_az619_pre_constructed_phase_a.py` is invoked
|
||||
Then both AC-619.1 and AC-619.2 are exercised by named tests.
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- The construction is single-threaded and synchronous; no GPU, no I/O beyond what `make_fdr_client` already does (FdrClient logger init).
|
||||
- Builder must complete in <100 ms on Mac dev host for the default config.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- AZ-591 (registry seam): DONE — `airborne_bootstrap.py` already exists with the required keys map.
|
||||
- AZ-273 (FdrClient): DONE — `make_fdr_client` is the public entry-point.
|
||||
- AZ-398 (WallClock): DONE — stateless, no-arg constructor.
|
||||
|
||||
## Constraints
|
||||
|
||||
- MUST NOT modify any per-component factory signature.
|
||||
- MUST NOT introduce new `BUILD_*` env flags.
|
||||
- MUST be additive: the function shape `build_pre_constructed(config) -> dict[str, Any]` survives unchanged through AZ-620..AZ-624.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The producer ID for `make_fdr_client` is "airborne_main" (per the bootstrap convention; consumer-side components call `make_fdr_client(<their_slug>, config)` separately and get their own per-component FdrClient via the per-producer cache). The single FdrClient passed via `pre_constructed["c13_fdr"]` is the one the wrapper factories pass into `build_<...>_strategy(config, fdr_client=...)`. Whether wrappers should use the shared "airborne_main" client or fetch their own per-component client is a design question that does NOT need to be resolved in this subtask — the wrappers already accept whichever client we pass. Defer the design clarification to the AZ-624 integration AC if needed.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Umbrella spec: `_docs/02_tasks/todo/AZ-618_airborne_bootstrap_pre_constructed.md`
|
||||
- Existing bootstrap module: `src/gps_denied_onboard/runtime_root/airborne_bootstrap.py:92` (AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS)
|
||||
- FdrClient factory: `src/gps_denied_onboard/fdr_client/client.py:192` (`make_fdr_client`)
|
||||
- WallClock: `src/gps_denied_onboard/clock/wall_clock.py`
|
||||
Reference in New Issue
Block a user