5.7 KiB
Structured Finance Output Contract
Purpose and compatibility
Each invocation has two JSON contracts with different consumers:
- In legacy
daily-monthlymode,result.jsonandstructured-result.jsonuse version1.0. - In database-ingestion
dailymode, both contracts use version2.0, requireprocessing_mode: "daily", and require the monthly output/artifact to be null.
Do not add database fields to result.json or derive database rows by reopening generated workbooks. The processor creates every requested workbook and every structured record from the same in-memory classified records. The structured file intentionally does not hash itself; it hashes result.json and the other requested artifacts, avoiding an impossible self-hash recursion.
Batch contract
The payload records:
business_date,processor_version,rule_set_sha256, andresult_schema_version;- the four database counters and a five-outcome reconciliation;
- deterministic channel/worksheet counts;
- absolute local artifact paths, SHA-256 values, sizes, MIME types, and database-compatible file kinds;
- every XML source reservation in original order;
- structured errors on failed runs.
rule_set_sha256 is a deterministic manifest digest of the processor, independent validator, Skill contracts, fixed price table, and both workbook templates. processor_version changes when processor behavior or its payload contract changes.
activation_eligible: true means only that the file pipeline and independent validations passed. It is not proof that a database transaction committed, and it never switches finance.current_daily_versions by itself.
Per-source-record contract
Every /G_RESERVATION produces exactly one record with a continuous one-based source_sequence and source_location = reservation[N].
Direct Opera XML has no source Excel coordinate:
source_worksheet = nullsource_row_no = null
The deterministic channel destination is channel_key, even when daily mode does not create a monthly workbook. source_worksheet/source_row_no are reserved for an explicitly approved workbook-backfill adapter and must not be fabricated for direct XML.
The only outcomes are:
retainedexcluded_rate_codeduplicatevalidation_failedprice_unmatched
Duplicate records point to the earlier retained candidate through duplicate_of_source_sequence. decision_codes preserve deterministic reasons such as whitelist exclusion, duplicate selection, exact price matching, the zero-price exception, or a validation error.
Derived keys are:
normalized_rate_code = upper(trim(rate_code))
group_code_key = upper(trim(res_comment))
company_key = deterministic company keyword normalization
An empty trimmed RES_COMMENT produces JSON null for group_code_key. Never substitute BLOCK_CODE, confirmation number, or another value. Non-empty Group Codes start with booking_source_match_status = not_checked; empty values use missing_group_code.
The database adapter performs the only approved booking-source lookup:
structured record group_code_key
= booking.booking_source_rows.group_code_key
booking_type_of_room_raw
= booking.booking_source_rows.hotel_raw
This is an exact normalized lookup, not fuzzy matching. room_category_label remains the Opera/XML actual room category and must never be overwritten with hotel_raw.
Price and worksheet mapping
- XML/daily
EFFECTIVE_RATE_AMOUNTbecomes structuredeffective_rate_amountand monthlyRATE_AMOUNT. REAL PRICEbecomesreal_price.TOTAL PRICEbecomestotal_priceand always equalsreal_price * no_of_rooms * nightsfor retained rows.nightsmay be zero when arrival and departure are the same date; the correspondingtotal_priceis numeric zero. Negative nights are invalid.KB(100/晚/间)becomeskb_amount; it is present only forDY-AI-Easy-KBand equalsno_of_rooms * 100.- The actual monthly worksheet becomes
channel_key; direct XML still keepssource_worksheet = null. pricing_methodisprice_reference_exactorzero_price_exceptionfor retained rows.
Failure and version-switch boundary
Success requires XML parsing, filtering, deduplication, pricing, deterministic channel assignment, every requested workbook write, independent output validation, and structured completeness validation. Daily v2 validates only the daily workbook and requires no monthly artifact; legacy v1 additionally requires and validates the monthly workbook. A successful payload has no validation_failed or price_unmatched rows and satisfies:
source_rows = removed_by_rate_code + removed_as_duplicates + output_rows
On failure, activation_eligible is false, output_rows is zero, daily/monthly artifacts are null, and the exception/result artifacts remain available. Valid candidates that never reached a fully validated formal result are marked validation_failed with BATCH_NOT_VALIDATED; already excluded, duplicate, or price-unmatched conclusions remain explicit.
The future database adapter must:
- confirm
current_database() = 'booking_test'before any write; - re-hash every file and validate this payload;
- allocate a new immutable version for every accepted same-day rerun;
- write file objects, the daily version, all records, channel metrics, and exact Group Code lookup results in one transaction;
- activate the new daily version and supersede the prior one only at the end of that successful transaction;
- roll back fully on any error, leaving the previous current version unchanged.
This Skill does not execute database DDL or DML. Its Finance payload targets the current booking_test contract after migrations 002-004, while the file processor itself remains runnable without a live database connection.