# Structured Result Contract

## Purpose

`structured-result.json` version `4.0` is the daily fact/review payload consumed by the trusted ARR adapter. It contains every XML source reservation, including filtered, duplicate, invalid, candidate and unmatched rows. Historical v3 artifacts remain ARR read-compatible only; they do not gain manual-review behavior.

`result.json` is the ARR/front-end run result. Do not add database records to it. Do not reconstruct database rows from the XLSX.

## Transport boundary

- Object storage materialization and its credentials belong to the ARR runtime, not this Skill.
- The runtime passes one already-fetched local XML path into the processor.
- ARR already knows the job/source-file identity from the upload context and binds that identity to this payload after comparing the XML hash.
- Structured artifact objects contain no local absolute path, OSS key, signed URL, AccessKey, or database credential.
- Runtime-local paths are ephemeral orchestration data and must not be persisted as business facts.

## Batch fields

The payload includes:

- `business_date`
- `processor_version`
- `rule_set_sha256`
- `result_schema_version`
- `source_rows`
- `removed_by_rate_code`
- `removed_as_duplicates`
- `output_rows`, `candidate_rows`, `review_required_rows`, and `review_issue_count`
- six-outcome reconciliation
- grouped, privacy-minimized `review_issues` with fixed-table candidate-price comparisons
- `review_case_id`, `manual_override_sha256`, and `manually_priced_rows` on final manual replay only
- channel counts
- path-free XML/daily/result/exception artifact metadata
- every XML source record in original order
- structured errors

`rule_set_sha256` hashes only resources that determine daily processing: Skill instructions, processor, independent validator, daily contracts/Schemas, price table, and daily template.

The structured file does not hash itself, avoiding self-hash recursion.

## Outcomes and lineage

Allowed outcomes:

- `retained`
- `candidate`
- `excluded_rate_code`
- `duplicate`
- `validation_failed`
- `price_unmatched`

Duplicates point to an earlier `source_sequence`. `decision_codes` explain deterministic choices. A final replay changes only approved missing-key rows to `retained` with `pricing_method: manual_review` and `MANUAL_PRICE_APPLIED`; candidate rows never enter Finance facts.

For direct XML:

- `source_sequence` is continuous and one-based;
- `source_location = reservation[N]`;
- `source_worksheet = null`;
- `source_row_no = null`.

## Finance/booking semantics

- `effective_rate_amount` comes from XML/daily `EFFECTIVE_RATE_AMOUNT`.
- `real_price` comes from the approved price rule.
- `total_price = real_price * no_of_rooms * nights`.
- `nights` may be zero; it may not be negative for retained rows.
- `kb_amount = no_of_rooms * 100` only when `channel_key = DY-AI-Easy-KB`.
- `room_category_label` remains the Opera actual room category.
- `group_code_key` comes only from normalized `RES_COMMENT`.
- Non-empty Group Codes begin with `booking_source_match_status = not_checked`; empty values use `missing_group_code`.

ARR performs the later exact booking lookup:

```text
structured group_code_key
= booking.booking_source_rows.group_code_key
```

It may then expose `booking.booking_source_rows.hotel_raw` as the original booking `type_of_room` text. It must not overwrite `room_category_label`.

## Activation boundary

`activation_eligible: true` means only that the deterministic final file pipeline passed. It does not mean database commit succeeded. `review_required` is false and has no daily/report artifact.

ARR must revalidate Schema, hashes and the independent replay before it writes file/version/record/channel/lookup rows in one transaction and switches the current daily version last. Review receipt writes only a case/items/events audit record. A frozen manual replay creates the first Finance version and one commit event only after that final validation succeeds.
