Asteria Fleet Data Quality Hub — Reconciliation & Certification Audit
This skill solves the recurring task family: "audit collection X as of cutoff Y against the Asteria Fleet Data Quality Hub and return one certified JSON answer." Every task in the family has the same shape — only the collection, cutoff, focus IDs, thresholds, and output contract change. The procedure below is parameterized by those inputs; it does not depend on any specific answer. Never copy values from another task's answer — re-derive everything for the current task's data.
Inputs (always present in the task directory)
prompt.txt — narrative of what to audit and report.
payloads/case_scope.json — the parameters: collection_id, cutoff timestamp, focus/decision IDs, ranking limits and ordering rules, certification thresholds, status→action map, control-case anchors.
payloads/answer_template.json — the output contract: a JSON Schema (or field contract) with required keys, enums, patterns, minItems/maxItems, ordering rules, and numeric precision. Emit EXACTLY this shape.
environment_access.md — the only source of network access: base URL, bearer token, and the allow-list of endpoints.
Golden rules (read first)
- One JSON object, exactly the template. No extra keys, no missing keys, no commentary, no Markdown fences. Templates use
additionalProperties: false — every key you emit must be in the schema.
- Discover, don't assume. Fetch
/api/catalog/schema and /api/source-snapshots at runtime to learn field names and snapshot statuses. Do not hardcode today's field names or row counts.
- The CERTIFIED snapshot wins. Overlapping records across snapshots are reconciled by retaining the occurrence from the authoritative (CERTIFIED) snapshot.
- Quarantined records are excluded from normalized totals; valid mismatches are INCLUDED. This is the most common accounting error.
- Control codes are inferred per-ID from evidence, never hardcoded. The allowed code values come from the template; which code applies to which ID is derived from that ID's audit outcome.
- Respect ordering and precision exactly. Lexicographic ascending, by-ID ascending, rank ascending; round money/quantity to the decimals declared in the template; counts are exact integers.
- Paginate everything. Collections are explicitly larger than one page.
Procedure
1. Connect
Read environment_access.md. Set BASE_URL and Authorization: Bearer <token>. Use ONLY the endpoints listed there. All reads are GET; the only write-shaped call is POST /api/query, which is a read-only query interface that still requires the bearer credential. See references/endpoints.md.
2. Load parameters and contract
Parse case_scope.json (parameters) and answer_template.json (contract). Note every required key, enum, pattern, minItems/maxItems, ordering rule, and precision declaration. Plan the output object against the contract BEFORE computing.
3. Resolve the source of truth
GET /api/catalog/collections → find the collection whose stable ID equals case_scope.collection_id.
GET /api/source-snapshots → list that collection's snapshots. The authoritative snapshot has status CERTIFIED (fall back to the newest non-STALE snapshot if none is CERTIFIED). authoritative_snapshot_id = its stable ID; authoritative_row_count = its row count.
scoped_raw_row_count = in-scope raw rows (all snapshots within the cutoff; see the per-task contract for the exact denominator).
4. Fetch and scope the raw records
Fetch the relevant record endpoint (/api/transactions/fuel, /api/transactions/freight, /api/maintenance/events, or /api/contacts) and page through every page. Use POST /api/query to filter by collection and cutoff when the raw endpoint is large. Keep only rows whose business timestamp is <= case_scope.cutoff_at (maintenance: within business_period.start..end). raw_row_count = total in-scope raw rows across snapshots.
5. Deduplicate and pick survivors
Group raw rows by their stable logical key (logical transaction / charge / event / contact-cluster ID). Rows sharing a logical key across snapshots are one logical entity. For each group:
retained occurrence = the one from the authoritative snapshot; others are duplicates.
duplicate_raw_count = raw_row_count − logical_count.
Emit duplicate groups per the contract (charge_id/logical_event_id, snapshot_ids sorted + unique, retained_snapshot_id).
6. Normalize measures
- Units: apply
/api/reference/conversions to bring every measure to the canonical unit declared in case_scope (volume→L, weight→KG, distance→KM).
- Currency: apply
/api/reference/fx to convert each amount to the base currency (USD) at the rate valid on the record's business date.
Keep full precision through the pipeline; round only at emission.
7. Resolve canonical category / class
Map each record's raw description/alias/merchant to a canonical category via /api/reference/aliases. Outcomes per record:
- exactly one recognized → recognized class.
- zero recognized → unrecognized.
- more than one recognized → ambiguous.
Unrecognized and ambiguous both mean "cannot be assigned to exactly one recognized category."
8. Classify each logical record
- Quarantine if ANY of: unresolved class (unrecognized OR ambiguous), nonpositive/invalid quantity, nonpositive/invalid weight, nonpositive/invalid distance, or (contacts) no usable contact channel. Track per-reason sub-counts when the contract asks.
- Mismatch (valid) if recognized class ≠ expected class (expected class comes from the record's own declared/expected field). Mismatches are VALID.
- Valid otherwise.
invalid_quantity_count, unrecognized_count, ambiguous_count are reported separately when the contract includes them.
9. Exception accounting
An exception = a logical record that is a valid mismatch OR a quarantine. exception_count = mismatch_count + quarantine_count over distinct logical records (no overlap — mismatches are valid, quarantines are not). This drives the rankings.
10. Normalized totals
Sum over valid records only (exclude quarantined; include valid mismatches):
- volume / weight / distance in canonical units, spend in base currency.
- Group by canonical category (fuel_type / service_class) → one row per category, sorted by category ascending.
total_* = sum of the group totals.
Round each emitted number to the decimals declared in the template (typically 2). valid_transaction_count/valid_charge_count = count of valid logical records. See references/pipeline.md for the accounting identities that must hold.
11. Rankings
Apply the ranking policy from case_scope exactly — the limit AND every tie-break:
- Merchants (fuel):
exception_count DESC, then merchant_id ASC, limit merchant_ranking_limit.
- Carriers (freight):
mismatch_spend_usd DESC (exposure = normalized USD on valid class mismatches only; quarantined charges excluded), then carrier_id ASC, limit carrier_ranking_limit.
- Assets (maintenance): sort keys from case_scope (e.g.,
rejected_event_count DESC, then regression_event_count DESC, then asset_id ASC), limit from case_scope.
Assign rank 1..N ascending. Reversing a tie-break changes the answer.
12. Control / decision code panels
For every public ID listed in a case_scope decision panel (reference alias IDs, transaction/charge IDs, event IDs, focus-cluster IDs, control-case IDs, focus-people anchors), infer the applicable internal code:
- The allowed code values and code field names come from
answer_template.json. The human-readable expansions are intentionally NOT supplied — infer from evidence.
- Look up each ID's evidence via
POST /api/query and the reference/contacts data, then map its audit outcome (which snapshot/source system it came from, validity, mismatch vs. quarantine reason, channel readiness, consent, record status, field provenance) onto the code enum for that panel.
- Code families you will meet (exact allowed values are in the template): reference-policy
RB-*, source-basis/retention SB-*, ledger-disposition/routing LD-*, maintenance-source MS-*, history-route HR-*, identity IC-*, outreach OR-*, field-provenance FP-*.
- Emit one row per scoped ID, sorted by that ID ascending. See
references/codes_and_status.md.
13. Certification / close status
Apply the certification rules declared in case_scope:
- Threshold + action-map style (e.g., partner onboarding): compute the gate metric (e.g.,
quarantine_rate = quarantined_rows / canonical_entities, rounded to the declared decimals), classify PASS / PASS_WITH_EXCEPTIONS / HOLD against status_thresholds, map status → action via status_action_map.
- Gate style (e.g., maintenance odometer regression): a
certification_gate declares a condition and its status/action; a triggered gate ⇒ that status/action directly (e.g., any regression ⇒ HOLD / BLOCK_AND_REMEDIATE).
- Default (no explicit rules): infer conservatively — any quarantine / invalid / regression ⇒
HOLD / BLOCK_AND_REMEDIATE; a fully clean audit ⇒ PASS / RELEASE.
The status/action pair must be one of the template's allowed enum pairs.
14. Emit and validate
- Build ONE JSON object matching
answer_template.json exactly: all required keys, no extras, correct enums/patterns, correct minItems/maxItems, declared ordering, declared precision.
- Run
python3 skill/scripts/validate_answer.py <answer.json> <answer_template.json> as a pre-flight sanity check.
- Output only the JSON. No prose, no fences. See
references/output_contract.md.
Per-task focus areas
The contract varies; let it drive what you compute. Recurring panels:
- Source/audit summary — counts (raw, logical, duplicate, valid, mismatch, quarantine) + the authoritative snapshot ID.
- Mismatch / quarantine ID lists — complete, deduplicated, lexicographically ascending.
- Normalized totals — per category + grand totals, valid records only.
- Focus rollups — one row per focus asset/person/cluster with survivor + canonical fields + source-system provenance.
- Rankings — top-N with the declared sort and tie-breaks.
- Decision/code panels — one coded row per scoped public ID.
- Status — status + action from the certification rules.
Common pitfalls
- Undercounting because you didn't paginate.
- Including quarantined records in normalized totals (or excluding valid mismatches).
- Retaining the wrong snapshot's occurrence (must be the CERTIFIED/authoritative one).
- Rounding too early, or to the wrong number of decimals.
- Reversed tie-break order in rankings.
- Hardcoding a control code instead of re-deriving it for the scoped ID.
- Emitting extra keys, missing keys, or any text outside the JSON.
Reference files
references/endpoints.md — endpoint catalog and runtime discovery checklist.
references/pipeline.md — detailed phases 3–11 with the accounting identities.
references/codes_and_status.md — control-code inference and certification status.
references/output_contract.md — ordering, precision, and JSON emission rules.
scripts/validate_answer.py — pre-flight output sanity check.
1---2name: asteria-fleet-dq-audit-33description: Reconcile and certify a data collection in the Asteria Fleet Data Quality Hub. Deduplicate overlapping source snapshots (CERTIFIED wins), normalize measures with reference aliases/conversions/fx, classify mismatches vs. unrecognized/ambiguous vs. quarantined, compute normalized totals and rankings, infer internal control codes per scoped public ID, and emit ONE answer JSON conforming exactly to the task's answer_template.json. Use whenever a task points at <TASK_ENV_BASE_URL> / the Asteria Fleet Data Quality Hub and asks for a reconciled audit plus a certification/close decision returned as a single JSON object.4---56# Asteria Fleet Data Quality Hub — Reconciliation & Certification Audit78This skill solves the recurring task family: *"audit collection X as of cutoff Y against the Asteria Fleet Data Quality Hub and return one certified JSON answer."* Every task in the family has the same shape — only the collection, cutoff, focus IDs, thresholds, and output contract change. The procedure below is parameterized by those inputs; it does **not** depend on any specific answer. Never copy values from another task's answer — re-derive everything for the current task's data.910## Inputs (always present in the task directory)1112- `prompt.txt` — narrative of what to audit and report.13- `payloads/case_scope.json` — the **parameters**: `collection_id`, cutoff timestamp, focus/decision IDs, ranking limits and ordering rules, certification thresholds, status→action map, control-case anchors.14- `payloads/answer_template.json` — the **output contract**: a JSON Schema (or field contract) with required keys, `enum`s, `pattern`s, `minItems`/`maxItems`, ordering rules, and numeric precision. Emit EXACTLY this shape.15- `environment_access.md` — the **only** source of network access: base URL, bearer token, and the allow-list of endpoints.1617## Golden rules (read first)18191. **One JSON object, exactly the template.** No extra keys, no missing keys, no commentary, no Markdown fences. Templates use `additionalProperties: false` — every key you emit must be in the schema.202. **Discover, don't assume.** Fetch `/api/catalog/schema` and `/api/source-snapshots` at runtime to learn field names and snapshot statuses. Do not hardcode today's field names or row counts.213. **The CERTIFIED snapshot wins.** Overlapping records across snapshots are reconciled by retaining the occurrence from the authoritative (CERTIFIED) snapshot.224. **Quarantined records are excluded from normalized totals; valid mismatches are INCLUDED.** This is the most common accounting error.235. **Control codes are inferred per-ID from evidence, never hardcoded.** The allowed code values come from the template; which code applies to which ID is derived from that ID's audit outcome.246. **Respect ordering and precision exactly.** Lexicographic ascending, by-ID ascending, rank ascending; round money/quantity to the decimals declared in the template; counts are exact integers.257. **Paginate everything.** Collections are explicitly larger than one page.2627## Procedure2829### 1. Connect30Read `environment_access.md`. Set `BASE_URL` and `Authorization: Bearer <token>`. Use ONLY the endpoints listed there. All reads are GET; the only write-shaped call is `POST /api/query`, which is a read-only query interface that still requires the bearer credential. See `references/endpoints.md`.3132### 2. Load parameters and contract33Parse `case_scope.json` (parameters) and `answer_template.json` (contract). Note every required key, enum, pattern, `minItems`/`maxItems`, ordering rule, and precision declaration. Plan the output object against the contract BEFORE computing.3435### 3. Resolve the source of truth36- `GET /api/catalog/collections` → find the collection whose stable ID equals `case_scope.collection_id`.37- `GET /api/source-snapshots` → list that collection's snapshots. The **authoritative** snapshot has status `CERTIFIED` (fall back to the newest non-STALE snapshot if none is CERTIFIED). `authoritative_snapshot_id` = its stable ID; `authoritative_row_count` = its row count.38- `scoped_raw_row_count` = in-scope raw rows (all snapshots within the cutoff; see the per-task contract for the exact denominator).3940### 4. Fetch and scope the raw records41Fetch the relevant record endpoint (`/api/transactions/fuel`, `/api/transactions/freight`, `/api/maintenance/events`, or `/api/contacts`) **and page through every page**. Use `POST /api/query` to filter by collection and cutoff when the raw endpoint is large. Keep only rows whose business timestamp is `<= case_scope.cutoff_at` (maintenance: within `business_period.start..end`). `raw_row_count` = total in-scope raw rows across snapshots.4243### 5. Deduplicate and pick survivors44Group raw rows by their stable logical key (logical transaction / charge / event / contact-cluster ID). Rows sharing a logical key across snapshots are one logical entity. For each group:45- `retained` occurrence = the one from the authoritative snapshot; others are duplicates.46- `duplicate_raw_count = raw_row_count − logical_count`.47Emit duplicate groups per the contract (`charge_id`/`logical_event_id`, `snapshot_ids` sorted + unique, `retained_snapshot_id`).4849### 6. Normalize measures50- Units: apply `/api/reference/conversions` to bring every measure to the canonical unit declared in case_scope (volume→L, weight→KG, distance→KM).51- Currency: apply `/api/reference/fx` to convert each amount to the base currency (USD) at the rate valid on the record's business date.52Keep full precision through the pipeline; round only at emission.5354### 7. Resolve canonical category / class55Map each record's raw description/alias/merchant to a canonical category via `/api/reference/aliases`. Outcomes per record:56- **exactly one** recognized → recognized class.57- **zero** recognized → *unrecognized*.58- **more than one** recognized → *ambiguous*.59Unrecognized and ambiguous both mean "cannot be assigned to exactly one recognized category."6061### 8. Classify each logical record62- **Quarantine** if ANY of: unresolved class (unrecognized OR ambiguous), nonpositive/invalid quantity, nonpositive/invalid weight, nonpositive/invalid distance, or (contacts) no usable contact channel. Track per-reason sub-counts when the contract asks.63- **Mismatch (valid)** if recognized class ≠ expected class (expected class comes from the record's own declared/expected field). Mismatches are VALID.64- **Valid** otherwise.65`invalid_quantity_count`, `unrecognized_count`, `ambiguous_count` are reported separately when the contract includes them.6667### 9. Exception accounting68An **exception** = a logical record that is a valid mismatch OR a quarantine. `exception_count = mismatch_count + quarantine_count` over distinct logical records (no overlap — mismatches are valid, quarantines are not). This drives the rankings.6970### 10. Normalized totals71Sum over **valid** records only (exclude quarantined; **include** valid mismatches):72- volume / weight / distance in canonical units, spend in base currency.73- Group by canonical category (fuel_type / service_class) → one row per category, sorted by category ascending.74- `total_*` = sum of the group totals.75Round each emitted number to the decimals declared in the template (typically 2). `valid_transaction_count`/`valid_charge_count` = count of valid logical records. See `references/pipeline.md` for the accounting identities that must hold.7677### 11. Rankings78Apply the ranking policy from `case_scope` exactly — the limit AND every tie-break:79- **Merchants (fuel):** `exception_count DESC`, then `merchant_id ASC`, limit `merchant_ranking_limit`.80- **Carriers (freight):** `mismatch_spend_usd DESC` (exposure = normalized USD on **valid** class mismatches only; quarantined charges excluded), then `carrier_id ASC`, limit `carrier_ranking_limit`.81- **Assets (maintenance):** sort keys from case_scope (e.g., `rejected_event_count DESC`, then `regression_event_count DESC`, then `asset_id ASC`), limit from case_scope.82Assign `rank` 1..N ascending. Reversing a tie-break changes the answer.8384### 12. Control / decision code panels85For every public ID listed in a `case_scope` decision panel (reference alias IDs, transaction/charge IDs, event IDs, focus-cluster IDs, control-case IDs, focus-people anchors), infer the applicable internal code:86- The **allowed code values** and code field names come from `answer_template.json`. The human-readable expansions are intentionally NOT supplied — infer from evidence.87- Look up each ID's evidence via `POST /api/query` and the reference/contacts data, then map its audit outcome (which snapshot/source system it came from, validity, mismatch vs. quarantine reason, channel readiness, consent, record status, field provenance) onto the code enum for that panel.88- Code families you will meet (exact allowed values are in the template): reference-policy `RB-*`, source-basis/retention `SB-*`, ledger-disposition/routing `LD-*`, maintenance-source `MS-*`, history-route `HR-*`, identity `IC-*`, outreach `OR-*`, field-provenance `FP-*`.89- Emit one row per scoped ID, sorted by that ID ascending. See `references/codes_and_status.md`.9091### 13. Certification / close status92Apply the certification rules declared in `case_scope`:93- **Threshold + action-map style** (e.g., partner onboarding): compute the gate metric (e.g., `quarantine_rate = quarantined_rows / canonical_entities`, rounded to the declared decimals), classify `PASS` / `PASS_WITH_EXCEPTIONS` / `HOLD` against `status_thresholds`, map status → action via `status_action_map`.94- **Gate style** (e.g., maintenance odometer regression): a `certification_gate` declares a condition and its status/action; a triggered gate ⇒ that status/action directly (e.g., any regression ⇒ HOLD / BLOCK_AND_REMEDIATE).95- **Default** (no explicit rules): infer conservatively — any quarantine / invalid / regression ⇒ `HOLD` / `BLOCK_AND_REMEDIATE`; a fully clean audit ⇒ `PASS` / `RELEASE`.96The status/action pair must be one of the template's allowed enum pairs.9798### 14. Emit and validate99- Build ONE JSON object matching `answer_template.json` exactly: all required keys, no extras, correct enums/patterns, correct `minItems`/`maxItems`, declared ordering, declared precision.100- Run `python3 skill/scripts/validate_answer.py <answer.json> <answer_template.json>` as a pre-flight sanity check.101- Output only the JSON. No prose, no fences. See `references/output_contract.md`.102103## Per-task focus areas104The contract varies; let it drive what you compute. Recurring panels:105- **Source/audit summary** — counts (raw, logical, duplicate, valid, mismatch, quarantine) + the authoritative snapshot ID.106- **Mismatch / quarantine ID lists** — complete, deduplicated, lexicographically ascending.107- **Normalized totals** — per category + grand totals, valid records only.108- **Focus rollups** — one row per focus asset/person/cluster with survivor + canonical fields + source-system provenance.109- **Rankings** — top-N with the declared sort and tie-breaks.110- **Decision/code panels** — one coded row per scoped public ID.111- **Status** — status + action from the certification rules.112113## Common pitfalls114- Undercounting because you didn't paginate.115- Including quarantined records in normalized totals (or excluding valid mismatches).116- Retaining the wrong snapshot's occurrence (must be the CERTIFIED/authoritative one).117- Rounding too early, or to the wrong number of decimals.118- Reversed tie-break order in rankings.119- Hardcoding a control code instead of re-deriving it for the scoped ID.120- Emitting extra keys, missing keys, or any text outside the JSON.121122## Reference files123- `references/endpoints.md` — endpoint catalog and runtime discovery checklist.124- `references/pipeline.md` — detailed phases 3–11 with the accounting identities.125- `references/codes_and_status.md` — control-code inference and certification status.126- `references/output_contract.md` — ordering, precision, and JSON emission rules.127- `scripts/validate_answer.py` — pre-flight output sanity check.