mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 08:21:14 +00:00
[AZ-307] c6 FreshnessGate: active-conflict reject + stable-rear downgrade
Replaces the AZ-305 pass-through _evaluate_freshness hook with the production FreshnessGate. Loads tile_freshness_rules + sector classifications once at construction, builds an rtree index, and on every evaluate() either returns metadata unchanged (FRESH), stamps freshness_label=DOWNGRADED (stable_rear + stale), or raises FreshnessRejectionError carrying tile_id / age_seconds / classification / rule diagnostics (active_conflict + stale). Constructed inside PostgresFilesystemStore.from_config; the public storage_factory signature is preserved so AZ-305 unit tests still build the store with freshness_gate=None for the pass-through path. FDR schema bumped to v1.2.0: adds c6.freshness.rejected and c6.freshness.downgraded kinds (non-breaking; v1.1 readers route them opaquely). Operator CLI `python -m c6_tile_cache.freshness_gate explain` dry-runs the decision for a (lat, lon, capture_ts). Adjacent hygiene: c6_tile_cache.tools._dump_tile now passes os.environ to load_config (AZ-305 regression — load_config requires the env mapping). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
**Component**: shared_fdr_client (cross-cutting concern owned by E-CC-FDR-CLIENT / AZ-247)
|
||||
**Producer task**: AZ-272 — `_docs/02_tasks/todo/AZ-272_fdr_record_schema.md`
|
||||
**Consumer tasks**: every onboard component that emits FDR records (C1–C13), the C13 writer (AZ-248 / E-C13), post-flight tooling (E-C12 operator side), the FdrClient ring buffer (AZ-XX / E-CC-FDR-CLIENT next task), and `FakeFdrSink` (AZ-XX / E-CC-FDR-CLIENT fourth task)
|
||||
**Version**: 1.1.0
|
||||
**Version**: 1.2.0
|
||||
**Status**: draft
|
||||
**Last Updated**: 2026-05-12
|
||||
|
||||
@@ -55,6 +55,8 @@ class FdrRecord:
|
||||
| `flight_footer` | C13 (writer) | `{flight_id, flight_ended_at_iso, flight_ended_at_monotonic_ns, records_written, records_dropped_overrun, bytes_written, rollover_count, clean_shutdown}` | Single record at flight close (envelope `producer_id="shared.fdr_client"`) |
|
||||
| `c6.write` | C6 (`PostgresFilesystemStore`) | `{tile_id, source, disk_bytes, content_sha256}` | v1.1.0 (AZ-305). Emitted on every successful `write_tile`. `tile_id` is the canonical UUIDv5 derived from `(zoom, x, y, source, flight_id)`; `source` is the `TileSource` enum value; `disk_bytes` is the JPEG payload length; `content_sha256` is the lowercase hex digest of the body. Envelope `producer_id="c6_tile_cache.store"`. |
|
||||
| `c6.write_failed` | C6 (`PostgresFilesystemStore`) | `{tile_id, source, reason, error_class, message}` | v1.1.0 (AZ-305). Emitted on every failed `write_tile` path. `reason` ∈ `{content_hash_mismatch, freshness_reject, metadata_error, fs_error}`; `error_class` is the exception class name; `message` is the rewrapped exception's `str` (truncated to 512 chars to keep the record inline). Envelope `producer_id="c6_tile_cache.store"`. |
|
||||
| `c6.freshness.rejected` | C6 (`FreshnessGate`) | `{tile_id, age_seconds, classification, rule_action, rule_max_age_seconds}` | v1.2.0 (AZ-307). Emitted on every active-conflict-stale reject. `tile_id` is the canonical UUIDv5; `age_seconds` is the integer-rounded `(now - capture_timestamp).total_seconds()` at decision time; `classification` is the `SectorClassification` enum value (always `"active_conflict"` for this kind in practice); `rule_action` is always `"reject"`; `rule_max_age_seconds` is the rule's threshold (e.g. `15552000` for the 6-month default). Envelope `producer_id="c6_tile_cache.freshness"`. |
|
||||
| `c6.freshness.downgraded` | C6 (`FreshnessGate`) | `{tile_id, age_seconds, classification, rule_action, rule_max_age_seconds}` | v1.2.0 (AZ-307). Emitted on every stable-rear-stale downgrade (including the implicit-default path for tiles outside every loaded sector). Same payload shape as `c6.freshness.rejected` so reject/downgrade FDR traces are line-for-line comparable; `rule_action` is always `"downgrade"` and `classification` is always `"stable_rear"` for this kind. Envelope `producer_id="c6_tile_cache.freshness"`. |
|
||||
|
||||
### Wire bytes
|
||||
|
||||
@@ -108,3 +110,4 @@ class FdrRecord:
|
||||
|---------|------|--------|--------|
|
||||
| 1.0.0 | 2026-05-10 | Initial contract derived from E-CC-FDR-CLIENT epic (AZ-247) | autodev decompose Step 2 |
|
||||
| 1.1.0 | 2026-05-12 | Add `c6.write` and `c6.write_failed` kinds emitted by C6 `PostgresFilesystemStore` (AZ-305). Non-breaking; v1.0 parsers see the records as unknown kinds and route them through the forward-compat opaque path. | AZ-305 implement |
|
||||
| 1.2.0 | 2026-05-12 | Add `c6.freshness.rejected` and `c6.freshness.downgraded` kinds emitted by the C6 `FreshnessGate` (AZ-307). Non-breaking; v1.1 parsers see the records as unknown kinds and route them through the forward-compat opaque path. | AZ-307 implement |
|
||||
|
||||
Reference in New Issue
Block a user