Files
Oleksandr Bezdieniezhnykh 2d88d3d674 [Batch 44 prep] Add batch 44 implementation plan
Captures the architectural plan agreed in the prior /autodev session:
C12 package rename (c12_operator_tooling -> c12_operator_orchestrator),
C11 internal flight-state gate removal (SRP fix; supersedes AZ-317),
AZ-329 PostLandingUploadOrchestrator rewrite around flight_footer FDR
record, and AZ-330 OperatorReLocService implementation. Execution starts
in the next /autodev invocation; this commit makes the planning artifact
durable so the batch executes against a fixed plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 18:06:02 +03:00

27 KiB
Raw Permalink Blame History

Batch 44 — Implementation Plan

Date drafted: 2026-05-13 Drafted in conversation: /autodev session, prior to batch 44 start Status: PLAN ONLY — do NOT start implementation until next /autodev invocation. Cycle: 1

Why a plan instead of just doing it

Two architectural decisions converged this batch and need to be executed as ONE atomic refactor; splitting them would leave the codebase in a transiently inconsistent state.

  1. C11's internal flight-state gate violates SRP. AZ-317 placed an ON_GROUND check inside HttpTileUploader. "Upload bytes" and "decide when uploading is safe" are different responsibilities; the latter is an orchestrator-level policy decision that belongs in C12.
  2. The C12 package name c12_operator_tooling understates its role. It owns orchestrators (build-cache, post-landing upload, operator-reloc) — "tooling" reads as a grab-bag. Rename: c12_operator_toolingc12_operator_orchestrator.

Decision recap (from the prior conversation)

  • The on-ground signal will be the presence of the flight_footer FDR record (kind already registered in KNOWN_PAYLOAD_KEYS; producer is C13's AZ-292, shipped) with clean_shutdown == True. No new FDR record kind needs to be defined. No 30-second threshold. No dependency on E-C8.
  • C11's HttpTileUploader becomes a dumb pipe: read pending from C6 → POST to ingest → mark uploaded. The flight-state-gating Protocol/Gate/error are deleted from C11.
  • C12's PostLandingUploadOrchestrator (AZ-329) performs the footer check; if the footer for flight_id exists and clean_shutdown == True, it calls tile_uploader.upload_pending_tiles(UploadRequest(flight_id=...)). Otherwise it refuses with FlightStateNotConfirmedError.

Tasks delivered in batch 44

Task Type Complexity Notes
Rename (no ticket, hygiene) refactor ~2pt c12_operator_toolingc12_operator_orchestrator. ~57 files touched.
C11 gate removal (supersedes AZ-317, partial revert of AZ-319) refactor ~3pt Create new tracker ticket AZ-XXX (or reopen AZ-317 marked superseded).
AZ-329 (rewritten) feature 3pt PostLandingUploadOrchestrator against flight_footer.
AZ-330 feature 3pt OperatorReLocService — unchanged from existing spec.
Total ~11pt Within batch cap (4 tasks; 20-point budget).

Phase plan (execute in this order)

Phase A — Component rename (c12_operator_toolingc12_operator_orchestrator)

Goal: one atomic rename with no behavioural change. Done before any code edits so subsequent phases work in the new namespace.

Source moves:

  • src/gps_denied_onboard/components/c12_operator_tooling/src/gps_denied_onboard/components/c12_operator_orchestrator/ (recursive git mv).
  • tests/unit/c12_operator_tooling/tests/unit/c12_operator_orchestrator/ (recursive git mv).

Symbol updates (kept as-is — only the package path changes):

  • Class names: C12Config, C12CompanionConfig, C12BuildCacheConfig, OperatorToolServices — KEEP. The C12 prefix is the component number (12), not the word "tooling". OperatorToolServices stays because the CLI binary itself is unchanged.
  • Logger names: c12_operator_toolingc12_operator_orchestrator (all occurrences in c12_factory.py and module-level logging.getLogger("c12_operator_tooling.*") calls).
  • Config-block slug: register_component_block("c12_operator_tooling", C12Config)register_component_block("c12_operator_orchestrator", C12Config). Note: this is a config-schema-key change; the deployment env will need to update YAML/JSON config files that key on this slug. List of changes goes into Phase F.
  • CMake flag: BUILD_C12_OPERATOR_TOOLINGBUILD_C12_OPERATOR_ORCHESTRATOR in cmake/build_options.cmake.
  • pyproject.toml console script: operator-tool = "gps_denied_onboard.components.c12_operator_tooling.cli:cli"... c12_operator_orchestrator.cli:cli. KEEP the binary name operator-tool for operator UX continuity; this is the only ambiguity — see Open Questions.

Import updates (mechanical replace across the workspace):

from gps_denied_onboard.components.c12_operator_tooling     →
from gps_denied_onboard.components.c12_operator_orchestrator

Applies to: c12 source (~30 files), c12 tests (~12 files), runtime_root/c12_factory.py, runtime_root/__init__.py, tests/unit/test_ac1_scaffold_layout.py, tests/unit/test_ac3_compose_files.py.

Docs / config updates (deferred to Phase F so renaming stays code-only here):

  • _docs/02_document/module-layout.md — section heading, Owns/Imports from/Consumed by paths.
  • _docs/02_document/components/13_c12_operator_tooling/13_c12_operator_orchestrator/ (directory rename).
  • _docs/02_document/contracts/c12_operator_tooling/c12_operator_orchestrator/ (directory rename).
  • _docs/02_document/epics.md: "E-C12 Operator Pre-flight Tooling" → "E-C12 Operator Pre-flight Orchestrator".
  • _docs/02_document/architecture.md, FINAL_report.md, glossary.md, data_model.md, system-flows.md, deployment/*: all references.
  • Task specs: AZ-326, AZ-327, AZ-328, AZ-329, AZ-330, AZ-489 Component: field; same for AZ-401, AZ-403 references.
  • Already-completed batch reports and cumulative reviews — leave as historical record (do NOT rewrite history).

Verification after Phase A:

  • git grep c12_operator_tooling -- ':!_docs/03_implementation/batch_*' ':!_docs/03_implementation/cumulative_review_*' ':!_docs/03_implementation/reviews/*' returns zero hits.
  • pytest tests/unit/c12_operator_orchestrator -q passes (no behavioural change, just the rename).
  • Full unit suite still 1522 passed, 80 skipped (same as batch 43 baseline).

Phase B — Remove C11 internal flight-state gate

Files to delete:

  • src/gps_denied_onboard/components/c11_tile_manager/flight_state_gate.py
  • tests/unit/c11_tile_manager/test_flight_state_gate.py (or test_az317_flight_state_gate.py — locate the actual filename).

Files to modify:

  • src/gps_denied_onboard/components/c11_tile_manager/interface.py:
    • Remove FlightStateSource Protocol class.
    • Update __all__.
    • Update module docstring.
  • src/gps_denied_onboard/components/c11_tile_manager/errors.py:
    • Remove FlightStateNotOnGroundError class + __all__ entry + docstring mention.
  • src/gps_denied_onboard/components/c11_tile_manager/_types.py:
    • Audit FlightStateSignal usage. If only the gate referenced it → delete. If HttpTileUploader still emits it in FDR records or elsewhere → keep as a closed enum for confirm_flight_state() return shape, BUT note that TileUploader.confirm_flight_state() is itself going away (see next bullet).
    • The confirm_flight_state method on TileUploader Protocol exists per interface.py — this method only makes sense if there's a gate. Decision: drop it. Remove from Protocol, from HttpTileUploader, from any test fakes.
  • src/gps_denied_onboard/components/c11_tile_manager/tile_uploader.py:
    • Remove FlightStateGate import.
    • Remove flight_state_gate: FlightStateGate constructor parameter.
    • Remove the confirm_on_ground() call at the top of upload_pending_tiles.
    • Remove the _LOG_KIND_REFUSED / pass-through confirm_flight_state method.
    • Re-test all upload paths now run without the gate.
  • src/gps_denied_onboard/components/c11_tile_manager/__init__.py:
    • Remove FlightStateGate, FlightStateNotOnGroundError, FlightStateSource from imports + __all__.
    • Keep FlightStateSignal only if confirm_flight_state survives; otherwise remove.
  • src/gps_denied_onboard/components/c11_tile_manager/idempotent_retry.py:
    • Audit for FlightStateGate / FlightStateNotOnGroundError references. The retry decorator wraps TileUploader; if it catches the gate error it must stop.
  • src/gps_denied_onboard/runtime_root/c11_factory.py:
    • Remove build_flight_state_gate(*, source: FlightStateSource) -> FlightStateGate.
    • Remove flight_state_gate= from build_tile_uploader(...).
    • Remove FlightStateSource from imports + module docstring.
  • tests/unit/c11_tile_manager/test_tile_uploader.py:
    • Remove all test cases that mock the gate / assert confirm_on_ground was called / assert FlightStateNotOnGroundError semantics.
    • Replace any fixture that injects a fake gate with a no-gate construction.
  • tests/unit/c11_tile_manager/test_idempotent_retry.py:
    • Adjust if any test cared about the gate's error class.
  • tests/unit/c11_tile_manager/test_protocol_conformance.py:
    • Drop FlightStateSource conformance assertions.

Files to LEAVE ALONE (these reference the gate in completed task specs / batch reports — historical record):

  • _docs/02_tasks/done/AZ-317_c11_flight_state_gate.md — leave the spec as-is; mark Status: superseded by batch 44 SRP refactor in a one-line annotation at the top.
  • _docs/02_tasks/done/AZ-319_c11_tile_uploader.md — leave; the relevant gate text is now historical.
  • _docs/03_implementation/batch_*_report.md, cumulative_review_* — historical, untouched.
  • _docs/03_implementation/reviews/batch_38_review.md, batch_39_review.md — historical.

Contract document update (Phase F covers):

  • _docs/02_document/contracts/c11_tilemanager/tile_uploader.md v1.0.0 → v2.0.0. Remove the gate clauses, the confirm_flight_state method row, FlightStateNotOnGroundError.

Verification after Phase B:

  • git grep -E 'FlightStateGate|FlightStateNotOnGroundError|FlightStateSource' src/ tests/ returns zero hits.
  • pytest tests/unit/c11_tile_manager -q passes.
  • Full unit suite passes (count will drop by ~1015 tests; document the new baseline in the batch 44 report).

Phase C — AZ-329 task spec rewrite

Rewrite _docs/02_tasks/todo/AZ-329_c12_post_landing_upload.md from scratch around the new design. Outline:

  • Description: PostLandingUploadOrchestrator reads the C13 FDR for flight_id, locates the flight_footer record (the C13 writer emits exactly one per flight on clean shutdown), and if found with clean_shutdown == True, calls tile_uploader.upload_pending_tiles(UploadRequest(flight_id=..., ...)). Footer absent → flight didn't terminate cleanly → refuse. Footer present but clean_shutdown == False → operator inspects manually → refuse.
  • Dependencies: AZ-326, AZ-319 (post-gate-removal TileUploader), AZ-272 (FdrRecord schema; flight_footer kind already there), AZ-292 (C13 footer producer; already shipped), AZ-263, AZ-269, AZ-266.
  • DTOs (in renamed c12_operator_orchestrator/_types.py):
    • PostLandingUploadRequest(flight_id: UUID, satellite_provider_url: str, batch_size: int = 50).
    • Reuses C11's UploadBatchReport via the AZ-507 consumer-side cut pattern (mirror locally as UploadBatchReportCut).
  • Reader (fdr_footer_reader.py): FdrFooterReader Protocol + LocalFdrFooterReader concrete. Iterates <fdr_root>/<flight_id>/segment_*.fdr newest-to-oldest, returns the first flight_footer record found (or None). Streaming — never loads full segments into memory.
  • Errors (c12_operator_orchestrator/errors.py):
    • FlightStateNotConfirmedError(Exception) with flight_id: str, not_confirmed_reason: Literal["flight_id_not_found", "footer_missing", "unclean_shutdown", "fdr_unreadable"], remediation: str.
  • Acceptance criteria (~8 ACs, all unit-testable via fake FdrFooterReader + fake TileUploader):
    • AC-1: footer present + clean_shutdown=True → upload invoked, returns UploadBatchReport.
    • AC-2: footer absent → FlightStateNotConfirmedError("footer_missing").
    • AC-3: footer present + clean_shutdown=FalseFlightStateNotConfirmedError("unclean_shutdown").
    • AC-4: <fdr_root>/<flight_id>/ does not exist → FlightStateNotConfirmedError("flight_id_not_found").
    • AC-5: FDR parse error mid-stream → FlightStateNotConfirmedError("fdr_unreadable: ...").
    • AC-6: footer search starts from newest segment (don't scan all segments if the latest has the footer).
    • AC-7: Returns C11's UploadBatchReport unchanged on success (passthrough).
    • AC-8: api_key in PostLandingUploadRequest is SecretStr; REDACTED in logs.
    • AC-9: integration test with a real FDR fixture that contains a clean-shutdown footer.
    • AC-10: integration test with a real FDR fixture that contains a clean_shutdown=False footer.
  • Non-Functional Requirements:
    • Footer read completes ≤ 1 s wall-clock even for 64 GB of FDR segments (newest-segment-first short-circuit).
    • Memory peak ≤ 50 MB (streaming reader).
  • Excluded explicitly:
    • Any flight_state.tick / state.tick payload-field reading.
    • The 30-second contiguous-ON_GROUND threshold.
    • A "force-upload" override (intentionally not supported).

Update _docs/02_document/components/13_c12_operator_orchestrator/tests.md C12-IT-03 to match (footer-based test, drop the 30s assertion).

Phase D — AZ-329 implementation

In renamed c12_operator_orchestrator/:

  • New files:
    • post_landing_upload.pyPostLandingUploadOrchestrator class + the AZ-507 consumer-side cut (TileUploaderCut Protocol matching C11's upload_pending_tiles(UploadRequest)).
    • fdr_footer_reader.py — Protocol + concrete LocalFdrFooterReader.
  • Modified files:
    • _types.pyPostLandingUploadRequest, UploadBatchReportCut.
    • errors.pyFlightStateNotConfirmedError.
    • config.py — extend C12Config with post_landing: C12PostLandingConfig(fdr_root: Path).
    • cli.pyupload-pending subcommand (already a placeholder in cli.py per the AZ-326 ship); wire to services.post_landing_upload_orchestrator. Map FlightStateNotConfirmedErrorEXIT_FLIGHT_STATE_NOT_CONFIRMED (already defined).
    • __init__.py — re-export new public symbols.
  • Composition root (runtime_root/c12_factory.py):
    • Add build_post_landing_upload_orchestrator(config, *, tile_uploader: TileUploaderCut) -> PostLandingUploadOrchestrator.
    • Extend OperatorToolServices with post_landing_upload_orchestrator: PostLandingUploadOrchestrator | None = None.
    • Extend build_operator_tool(...) aggregator: when a tile_uploader is provided, build and wire.
  • Tests (tests/unit/c12_operator_orchestrator/):
    • test_post_landing_upload_orchestrator.py — covers AC-1 through AC-8 with fakes.
    • test_fdr_footer_reader.py — covers AC-5 + the streaming NFR.
    • Integration test fixtures for AC-9 + AC-10: scripted FDR segments with / without clean_shutdown=True footer. Live under tests/fixtures/c12_orchestrator/fdr/ or similar.

Phase E — AZ-330 implementation

Implement per existing _docs/02_tasks/todo/AZ-330_c12_operator_reloc_service.md, adjusted only for the renamed package. Re-use LatLonAlt from src/gps_denied_onboard/_types/geo.py (the shared definition exists — AZ-330's risk-mitigation note flagged this; we confirmed it during the prior session).

  • New files (in c12_operator_orchestrator/):
    • operator_reloc_service.pyOperatorReLocService class.
    • operator_command_transport.pyOperatorCommandTransport Protocol.
  • Modified files:
    • _types.pyReLocHint (consume shared LatLonAlt).
    • errors.pyGcsLinkError.
    • cli.py — wire reloc-confirm subcommand.
    • __init__.py — re-exports.
  • Composition root:
    • build_operator_reloc_service(...) factory.
    • Extend OperatorToolServices with operator_reloc_service: OperatorReLocService.
  • Tests: 10 ACs per the existing spec — all unit-testable via fake OperatorCommandTransport.
  • Contract document: _docs/02_document/contracts/c12_operator_orchestrator/operator_command_transport.md (already exists at the old path — gets moved during Phase A).

Phase F — Documentation updates

  • _docs/02_document/module-layout.md:
    • Section heading and all paths: c12_operator_toolingc12_operator_orchestrator.
    • C11 component section: drop FlightStateSource, FlightStateGate from the Public API + Internal lists.
  • _docs/02_document/components/13_c12_operator_orchestrator/description.md:
    • Rewrite the C12 § 2 row for trigger_post_landing_upload around the footer-based design.
    • Remove any reference to a 30-second threshold.
    • Update the component name in the title.
  • _docs/02_document/components/13_c12_operator_orchestrator/tests.md:
    • C12-IT-03 rewritten around flight_footer (no FlightStateSignal, no 30-second window).
  • _docs/02_document/components/12_c11_tilemanager/description.md:
    • Remove the AZ-317 gate description; C11 is now a dumb pipe.
  • _docs/02_document/components/12_c11_tilemanager/tests.md:
    • Remove gate-related tests.
  • _docs/02_document/contracts/c11_tilemanager/tile_uploader.md:
    • v1.0.0 → v2.0.0. Drop gate clauses, confirm_flight_state, FlightStateNotOnGroundError.
    • Add migration note pointing to batch 44.
  • _docs/02_document/contracts/c12_operator_orchestrator/ — directory move (Phase A) + content tweaks.
  • _docs/02_document/architecture.md:
    • Update C12 component name in the system overview.
    • Update C11 component description (no internal gate).
  • _docs/02_document/glossary.md:
    • "operator tooling" → "operator orchestrator" (semantic).
  • _docs/02_document/epics.md:
    • E-C12 epic name updated.
  • _docs/02_document/FINAL_report.md:
    • Component table update.
  • _docs/02_document/deployment/*:
    • containerization.md, environment_strategy.md, ci_cd_pipeline.md, deployment_procedures.md, observability.md — replace package name references.
  • README.md: any references to operator_tooling.
  • pyproject.toml: package path in entry-point + any tool config keys.
  • cmake/build_options.cmake: BUILD_C12_OPERATOR_TOOLINGBUILD_C12_OPERATOR_ORCHESTRATOR.
  • .github/workflows/release.yml: any references.
  • docker-compose.yml, docker-compose.test.yml: service / image references.

Phase G — Tracker (Jira) updates

  • AZ-317 (C11 Flight-State Gate): transition to a "Superseded" or "Won't Do" status with a comment linking to batch 44. Spec stays in _docs/02_tasks/done/ annotated.
  • AZ-319 (C11 TileUploader): add a comment noting batch 44 removed the gate dependency; the AZ-319 ticket itself stays Done.
  • AZ-329: keep ticket; comment with the design pivot; replace spec in _docs/02_tasks/todo/ and resync description in Jira.
  • AZ-330: comment with the package-rename note; nothing else changes.
  • New ticket for the C11 gate revert (suggested name: "C11 SRP correction — remove internal flight-state gate; AC-NEW-7 enforcement moves to C12"). Component: c11_tile_manager. Epic: AZ-251 (E-C11). Complexity: 3pt.
  • New ticket for the C12 rename (suggested name: "Rename c12_operator_tooling → c12_operator_orchestrator"). Component: c12_operator_orchestrator. Epic: AZ-253 (E-C12). Complexity: 2pt.
  • Epic AZ-253 rename: "E-C12 Operator Pre-flight Tooling" → "E-C12 Operator Pre-flight Orchestrator".
  • Update _docs/02_tasks/_dependencies_table.md:
    • Add the two new tracker IDs to the table.
    • The C11 dependency on AZ-317 (if any task depends on the gate) goes away — none should, since AZ-317 was self-contained.
    • Increment task / point counts.

Phase H — Tests, code review, commit

  1. Full repo unit suite: must return to a clean green baseline. Document the new pass count in the batch 44 report (expected slightly lower than 1522 due to deleted gate tests + slightly higher due to new AZ-329 / AZ-330 tests; net ~+15).
  2. Targeted suites at each phase boundary:
    • Phase A end: pytest tests/unit/c12_operator_orchestrator -q
    • Phase B end: pytest tests/unit/c11_tile_manager -q
    • Phase D end: pytest tests/unit/c12_operator_orchestrator/test_post_landing_upload_orchestrator.py -v
    • Phase E end: pytest tests/unit/c12_operator_orchestrator/test_operator_reloc_service.py -v
  3. AC coverage verification for AZ-329 + AZ-330 per the implement skill's Step 8.
  4. Code review (/code-review) on the full batch diff. Architecture findings expected (cross-task consistency: c11 and c12 cuts) — these escalate per the auto-fix matrix, never auto-fix.
  5. Single commit with subject:
    [AZ-329] [AZ-330] [AZ-XXX-C11-revert] [AZ-YYY-c12-rename] C12 orchestrator rename + C11 gate removal + post-landing upload + reloc service (Batch 44)
    
    (Subject is over 72 chars — split into subject + body per .cursor/rules/git-workflow.mdc. Subject: [Batch 44] C12 rename + C11 gate removal + post-landing upload + reloc service. Body lists tracker IDs.)
  6. Batch 44 report: _docs/03_implementation/batch_44_cycle1_report.md per the standard template, with sections for each phase.
  7. NO cumulative review this batch — cumulative review fires at batch 45 (40-42, then 43-45). Batch 44 is mid-window. Per the implement skill Step 14.5 (K=3), the next cumulative review covers 43-45.

File inventory snapshot (as of 2026-05-13)

Files referencing c12_operator_tooling to be touched in Phase A (rename) + Phase F (docs)

  • Source / tests (renamed in Phase A): ~38 files under src/gps_denied_onboard/components/c12_operator_tooling/, src/gps_denied_onboard/runtime_root/c12_factory.py, tests/unit/c12_operator_tooling/, tests/unit/test_ac1_scaffold_layout.py, tests/unit/test_ac3_compose_files.py, pyproject.toml, src/gps_denied_onboard/runtime_root/__init__.py, src/gps_denied_onboard/healthcheck.py.
  • Docs (updated in Phase F): _docs/02_document/module-layout.md, _docs/02_document/components/13_c12_operator_tooling/{description,tests}.md (directory rename), _docs/02_document/contracts/c12_operator_tooling/* (directory rename), _docs/02_document/architecture.md, _docs/02_document/FINAL_report.md, _docs/02_document/epics.md, _docs/02_document/glossary.md, _docs/02_document/data_model.md, _docs/02_document/system-flows.md, _docs/02_document/deployment/*.
  • Task specs (updated in Phase F): _docs/02_tasks/done/AZ-{326,327,328,489}_*.md, _docs/02_tasks/todo/AZ-{329,330,401,403}_*.md, _docs/02_tasks/done/AZ-263_initial_structure.md.
  • Infra: docker-compose.yml, docker-compose.test.yml, cmake/build_options.cmake, .github/workflows/release.yml, README.md.
  • Historical (leave alone): _docs/03_implementation/batch_21_*.md, batch_42_*.md, batch_43_*.md, cumulative_review_batches_40-42_*.md and any earlier batch reports.

Files referencing FlightStateGate / FlightStateNotOnGroundError / FlightStateSource (Phase B)

  • src/gps_denied_onboard/components/c11_tile_manager/{interface.py, errors.py, _types.py, tile_uploader.py, idempotent_retry.py, flight_state_gate.py, __init__.py}
  • src/gps_denied_onboard/runtime_root/c11_factory.py
  • tests/unit/c11_tile_manager/{test_flight_state_gate.py, test_tile_uploader.py, test_idempotent_retry.py, test_protocol_conformance.py}
  • Docs: _docs/02_document/contracts/c11_tilemanager/tile_uploader.md (v1.0.0 → v2.0.0), _docs/02_document/components/12_c11_tilemanager/{description,tests}.md, _docs/02_document/components/13_c12_operator_tooling/{description,tests}.md, _docs/02_document/architecture.md, _docs/02_document/module-layout.md, _docs/02_tasks/done/AZ-317_*.md (annotate as superseded).

Open questions for the next session

These should be resolved BEFORE Phase A starts:

  1. CLI binary name: keep operator-tool or rename to operator-orchestrator? Default proposal: keep operator-tool — operator-facing UX continuity matters more than internal package consistency. The user said "rename C12" — the C12 package — not "rename the CLI". If user wants both, change pyproject.toml script entry too.
  2. Internal class name OperatorToolServices: keep or rename to OperatorOrchestratorServices? Default proposal: rename (it's internal; renaming costs nothing and stays consistent).
  3. AZ-317 spec file disposition: leave annotated in _docs/02_tasks/done/AZ-317_c11_flight_state_gate.md, OR move to a new _docs/02_tasks/superseded/ folder? Default proposal: annotate in place. Don't introduce a new lifecycle folder for one task.
  4. Whether AZ-318's PerFlightKeyManager lifetime hooks depend on flight-state: low-likelihood but verify in Phase B before deleting FlightStateSignal from _types.py.
  5. C8 ↔ C11 relationship: C8 was producing flight-state intended for C11's gate. Now that the gate is gone, does C8 still need to emit flight-state to anywhere? Check AZ-391 outputs; flight-state may still be used by C5 (state estimator) for sensor-fusion gating — independent of C11. Most likely C8's flight-state output stays and only C11 stops consuming it.

Acceptance criteria for batch 44 completion

Batch 44 is complete when ALL of the following hold:

  • git grep c12_operator_tooling -- src/ tests/ cmake/ pyproject.toml docker-compose*.yml .github/ returns zero hits (excluding historical batch reports).
  • git grep -E 'FlightStateGate|FlightStateNotOnGroundError|FlightStateSource' src/ tests/ returns zero hits.
  • c12_operator_orchestrator package exists with all prior c12_operator_tooling contents + AZ-329 + AZ-330 additions.
  • pytest tests/ -q is green (count documented in batch report).
  • AZ-329 + AZ-330 ACs all have direct test coverage (AC coverage verification step).
  • /code-review on the batch diff returns PASS or PASS_WITH_WARNINGS (Architecture findings escalate per the auto-fix matrix).
  • _docs/02_tasks/todo/AZ-329_c12_post_landing_upload.md rewritten and moved to _docs/02_tasks/done/.
  • _docs/02_tasks/todo/AZ-330_c12_operator_reloc_service.md moved to _docs/02_tasks/done/.
  • Jira tickets transitioned: AZ-317 superseded; AZ-329 + AZ-330 + new C11-revert + new C12-rename → In Testing.
  • Single commit on dev branch; user asked whether to push.
  • _docs/03_implementation/batch_44_cycle1_report.md written.
  • _docs/_autodev_state.md updated: last_completed_batch: 44, in_flight_batch: null, in_flight_tasks: null, sub_step.phase: 2, name: detect-progress, detail: "".

Recovery / abort guidance

If Phase A breaks more than expected (e.g., test_ac1_scaffold_layout / test_ac3_compose_files hardcode the package path in surprising ways): pause and ask the user before patching test fixtures. Test scaffolds may encode invariants that the rename invalidates by design.

If Phase B reveals that something outside C11 (a c4/c5/c8 wiring, or a contract conformance test) depends on FlightStateSource for reasons unrelated to upload gating: pause and ask. C11's FlightStateSource was supposed to be a C11-internal Protocol — but the C11 _types.py declares FlightStateSignal as a closed enum that other components may have started consuming.

Pointer for the next /autodev invocation

Re-read this plan first. Execute phases A → B → C → D → E → F → G → H in order, with the verification at each phase boundary. Do not skip Phase A's verification — every subsequent phase assumes c12_operator_tooling is a dead string. If any verification fails, stop and ask the user.