Files
ARR-2.0-0918/integrations/ohip/README.md
T

527 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ARR 的 OHIP 应用
2026-09-18最新:已完成[15字段数据入口](DATA_SOURCE.md)及页面→共用处理→复核→日报/月报,
并将本机8875配置为OHIP沙箱OHIPSB02,沿用原登录信息。接口数据不生成中间XML。
启动和登录不查询订单;本轮未实际取数。用户通知同事补权后,06:00:56Z核对`blocks.read`已生效,
所需权限齐全、原密钥有效,本机下载按钮已启用。见[补权记录](PLATFORM_ACCESS_REQUEST.md)及[本机入口配置](../../arr_web/DIRECT_DATA_ENTRY.md)。
当前`application.json`记录实有6组读取权限;`integration.json`记录ARR的8项取数需求加`getRoomClasses`
(仅为保留此前configuration.read,不由ARR调用),本轮未apply。
平台同事另授hotel.read、finance.read,ARR未使用;后续不能直接apply该需求清单覆盖实有权限。
原应用和密钥保留。
本轮7项新检查及相关回归共37项通过,包含独立本机数据库、启动不取数、权限控制及日期传递。
下面关于原生 XML 等价和历史故障的记录保留为历史依据,不是本轮新增数据入口的实现前提。
2026-09-17房号后续:[room_calendar_evidence.py](room_calendar_evidence.py)已实现只读单页证据核对,
保留按预订ID关联的全部房间/换房段并区分缺失与空集合。13新/71项测试通过;原3份响应均仍缺room,
未新增酒店请求或选定ARR房号。[核验记录](../../.project-docs/50-evidence/topics/2026-09-17-arr-room-calendar-evidence.md)。
2026-09-17新增[独立姓名补充](profile-supplement.md):完整v2主体不依赖searchProfiles,
姓名失败只留下补充缺口;后续固定主体/补充摘要,只查询未取得的姓名。已接本地候选准备,旧v3归档协议不改。
这是本地工具,未启用Web、未取得完整实际ARR;下文v3停止行为保留为历史实测。
2026-09-17修复复验:公开目录0.9.0/158项,新getRoomCalendar已发布;6次只读实测/审计完成,
原失败档案仍503,3次房间日历200均无room集合,2笔预订摘要匹配但仍无房号。未开启全日重采/新权限/运行接线。
[最新结果与平台定位编号](platform-recovery-check-20260917.md)。历史404与先前样本成功不代表本次结果。
最新:获准的全日v3实测在23:34–23:36遇到间歇性503。搜索139个候选、已取6笔详情/日价;6个主客档案中5个成功,
第6个连续3次503后停止。23次请求全部有平台审计,原件72个文件完整保留;未形成完整日候选。
[本轮回执](named-day-live-result-20260916.json)与[可给平台的排查说明](profile-summary-platform-check.md)。
此前22:21原3位主客全部200的样本仍成立,但不能代表全日稳定;GET未重测。
平台支持还包括[历史房号来源](arr-platform-next-actions.md),getRoomCalendar上次目录复查仍404。
现已完成v3姓名采集、原件归档、离线重放和批次复用;217项范围测试通过,原3份真实响应离线校验通过。
139笔历史预订对应112个不同主客档案,按档案复用响应但逐预订核对姓名。首次全日v3实测失败;同源报表规则及完整ARR仍待验收。
[本轮证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-named-day-capture.md)。
另已修复冻结结果落盘后、ready标记前中断导致无法恢复的问题:新增预先持久化的清单摘要,恢复时逐项核对原包。
48项相关测试通过,包括真实进程退出、原包不重算及交付不重复;旧无摘要包仍拒绝,已完成旧包兼容。
见[恢复修复证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-freeze-recovery.md)。未启用Web运行接线。
另把归档累计大小限制提前到写入前,并为失败摘要预留空间;含后续预算回归共164项不同用例通过。
[预算证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-acquisition-budget.md);139笔离线重放、851原件与XML不变。
最新:[房号与关联档案核对](../../.project-docs/50-evidence/topics/2026-09-16-arr-room-profile-selection.md)已实现三处房号一致、
指定角色/内部Profile ID/名称两层一致的选择器,10新/133项测试通过。真实139笔中73笔房号一致、24笔Group关联一致;
缺失字段不补空、不回退,不把Group填入公司列。发现Oracle的getRoomCalendar可提供换房历史候选,平台精确目录查询404,
是否需要补充仍待评估。本轮无酒店业务调用,完整ARR和按钮仍未就绪。
最新补充:[字段选择器](source_fields.py)已实现Resv.-GEN全部备注、两层一致人数和到店日原始房数取值。
10项新增/123项相关测试通过;139笔离线核对全部与独立比较器一致,851原件未变。
其中1笔有两条不同GEN备注,顺序会影响现有处理器,尚不认定API顺序等于报告顺序;共享房口径也未验明。
见[本轮证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-note-count-selection.md)。完整ARR及按钮联调仍未就绪。
最新实现:[受限字段选择器](source_fields.py)已支持确认号、日期、严格单日费率代码、绑定的原始有效价及空Trace,
12新/91项相关测试通过;139笔离线字段覆盖已记录。这仍不是完整ARR适配或按钮就绪。
[新证据与姓名补充路径](../../.project-docs/50-evidence/topics/2026-09-16-arr-direct-field-selection.md)记录现成的
searchProfiles摘要候选。用户已批准并完成profiles.read追加;3位主客POST及同一人GET对照均返回平台503/ohip_unavailable,
9新/100相关测试通过。见[实测证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-profile-summary-probe.md)和
[可提供给平台的排查说明](profile-summary-platform-check.md);未取得完整姓名或完整ARR输出。
2026-09-16 已通过 CLI 0.5.0 和用户交付的 Automation Principal 创建应用,并签发一个独立应用 API Key。
本目录保存无秘密的接入清单、应用元数据、接口映射/实测聚合结果、独立只读采集工具和本地 XML 比对工具。
已实现单日 API 候选数据采集及私有原件归档;尚未接入生产调度、源格式适配或 ARR 入库。
- 服务:[OHIP Edge](https://ohip.nianxx.cn)
- 应用:`Wyndham-ARR2.0-Codex`
- 应用 ID:`caller_zloxalzsQ9pYsztt`
- 权限清单:[integration.json](integration.json)
- 应用登记信息:[application.json](application.json)
- 当前权限:`reservations.read`和用户批准新增的`profiles.read`。声明searchHotelReservations、getReservation、
searchRateInfo、searchProfiles;明确确认附带getRateInfo、getProfile、getProfiles。plan/validate/apply及回读
已完成,沿用原应用和唯一密钥。[授权与查询证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-profile-summary-probe.md)。
最初因CLI的manifest要求至少一个操作,以ARR数据读取用途开通搜索和详情;这不代表已经确定
用 JSON 重建源 XML。当前目录仍未找到 `RES_DETAIL` 原报表下载操作。
本轮已完成[接口参数与16个来源字段对应表](arr-api-mapping.md),并准备[五个研究请求示例](arr-api-request-examples.json)。
后续已完成 OHIPSB02 的[一日只读实测](../../.project-docs/50-evidence/topics/2026-09-16-arr-api-live-probe.md):139个预订及详情,
备注GEN编码与官方示例相反,effectiveRate未返回,时间条件会排除缺少ETA的记录。示例不能直接当作生产参数。
2026-09-16用户通知后已核实:平台0.7.0同时发布 `getRateInfo` 和推荐的 `searchRateInfo`,
均在现有 `reservations.read` 组内。ARR现有密钥在OHIPSB02的5笔样本/11次只读调用全部成功,
指定日有效价使用 `detail.totalRateAmount`。见[发布与实测证据](../../.project-docs/50-evidence/topics/2026-09-16-rate-info-publication.md)。
[给平台的具体接口清单](rate-info-platform-request.md)保留补充前的历史需求,不再表示接口缺失。
当前重点是[业务要素与API映射](../../.project-docs/50-evidence/topics/2026-09-16-arr-api-scope-correction.md):
用户的页面操作用于解释数据需求,应研究searchHotelReservations/getReservation的组合及缺口。
XML是样本和既有入口格式,JSON返回是否需要适配须核实后讨论,不能把原生文件接口缺失当成整个API路径阻塞。
[原生文件清单](arr-report-platform-handoff.md)和[XML交付草案](native-xml-delivery-trial.md)保留历史参考,
页面操作/计划报表/SFTP分支已停止推进;不再要求用户提供这条分支的截图或配置。
用户提供的手工XML已完成本地结构与处理检查,同环境数据具备后再作接口逐笔对比。
[样本导出要求](manual-export-sample-request.md)保留历史收样记录;额外页面截图不作为当前API研究的前置条件。
手工 XML 已到并通过现有处理器/独立校验:72源行、61保留行,日期2026-09-15;备注实际为CAS/GENERAL,
用户已确认页面Resv.-GEN,CAS/GENERAL是该XML内部字段;不再要求确认。见 [基准证据](../../.project-docs/50-evidence/topics/2026-09-16-manual-arr-xml-baseline.md)。
## API 候选数据采集
日期由上游系统传入 From Date / To Date,当前业务规则是两者均为T-1;ARR不自行计算T-1。
用户本次指定 From Date = To Date = 有效价查询日期 = `2026-09-15`。v2入口要求三个日期显式传入、有效且相等,
分别映射搜索起止和日价detailDate,批次重试沿用已保存值。缺失不默认昨日,不重新读取时钟。
日期是本次执行输入,不永久写死为该日;延迟执行、重试不会因当天日期变化而改变范围。
### v3:增加主客完整姓名摘要
[collect_arr_named_day.py](collect_arr_named_day.py)增加`searchProfiles`,必须显式给出`max_profiles`,与系统日期、
酒店及批次ID一起固定。按详情中唯一Primary主客的内部Profile ID精确查询,每次一个ID、limit1/offset0;
响应身份/酒店/操作/分页均须符合。重用同一档案的原始响应时,仍逐预订比较姓、名、中间名、title和prefix。
使用上游`formerName.fullName`原文,不拼接、不去空格、不制造缺失的nameType。
- [capture_named_day_job.py](capture_named_day_job.py)是独立v3批次入口,显式日期和凭证参数同v2,额外必填
`--max-profiles`。帮助命令`python -m integrations.ohip.capture_named_day_job --help`不调用酒店接口。
实际执行会读取酒店业务数据;用户已授权的一轮全日实测按139预订/112档案上限执行,遇503后停止。
该次失败原件保留;不得反复自动启动新整批或扩大日期/酒店/人数范围。
- v3使用四个接口和独立协议标记,原v2批次/原件不能原地升级。已完成批次逐项验证后复用,不加载密钥或重发请求;
有姓名缺口的完整候选也稳定复用,重新观察上游需要新批次。失败/中断重试保留旧尝试,从头采集完整新尝试。
- `rate-assessments.json`在v3中增加逐预订`profile`证据,绑定成功请求;姓名原文、ID及组成只留在私有文件。
公开回执保留`unique_profiles/profile_records/valid_name_candidates/profile_issues/all_names_valid`等聚合项。
- 缺失姓名/没有唯一主姓名/组成不符分别记缺口;显式非法结构、错身份、警告、权限失败或重试耗尽使整批失败。
所有响应和最终清单都有大小上限,写入前预留失败摘要空间。40秒客户端期限,短暂故障最多3次尝试,
Retry-After超过30秒停止当前尝试。采集完整及姓名候选有效均不代表原报告显示等价或Finance就绪。
- [audit_arr_named_day.py](audit_arr_named_day.py)接受`--capture-dir`与外部保存的`--manifest-sha256`,不联网、不加载凭证,
核对所有原件、请求顺序、成功响应引用、逐预订判断和汇总。v2核验器明确拒绝v3档案。
- 未改Web接线或运行服务。原3份真实摘要已离线验证;后续实测另外保存失败批次。原139笔/851原件与手工XML均不变。
### v2:保留的搜索、详情和指定日有效价
[collect_arr_day.py](collect_arr_day.py) 增加 `searchRateInfo`,按已经核验的内部Reservation ID与指定日期逐笔取价,
全部结束后复查完整搜索集合。原始响应和请求归档为 `arr-api-capture/v2`;
[audit_arr_day.py](audit_arr_day.py) 使用独立保存的manifest摘要核验所有文件、请求顺序、日期/身份和有效价判定。
旧v1档案和工具继续保留,不能将其两操作档案误认为已经包含日价。
推荐用[本地批次入口](capture_day_job.py),复用既有私有状态/进程锁/整批重试逻辑:
```sh
.venv/bin/python -m integrations.ohip.capture_day_job \
--job-store "$HOME/Downloads/arr-day-jobs" \
--batch-id arr-20260915-001 \
--from-date 2026-09-15 --to-date 2026-09-15 --rate-date 2026-09-15 \
--hotel-id OHIPSB02 \
--credential-file "$HOME/Library/Application Support/ohipctl/credentials/arr2-application-caller_zloxalzsQ9pYsztt.json"
```
- 此命令会实际读取酒店接口。新目录/批次ID用于新的采集意图;同一ID不能更换日期、酒店、分页上限或协议版本。
已完成批次先核验原档再复用,之后不会加载密钥或调用网络。失败/中断从offset0新建整日尝试,不拼接残缺结果。
- 原始报文仍保持0700目录/0600文件、SHA-256清单和外部根摘要。单次直接采集可用
`python -m integrations.ohip.collect_arr_day`,相同日期/酒店/凭证参数,另提供新的 `--output-dir`。
- `candidate_capture_complete=true` 表示三个接口的完整候选取得并通过末尾搜索复查。
`all_rates_valid` 单独表示每笔金额有效且币种与详情费率段一致;缺价、隐藏价、缺失/冲突币种会记录诊断,
保留完整候选,绝不以0或base代替。显式数值0合法。权限/网络最终失败、警告、错身份、分页/末次复查漂移仍使整批失败。
- 完成但带价格诊断的档案也会稳定复用;要重新观察修复后的上游数据,须显式使用新批次ID。
CLI退出码0只代表候选采集完成,调用方必须读取价格和业务标记,不能把它解释为下载处理成功或Finance成功。
- `rate-assessments.json` 是私有逐笔诊断,金额精确保存为十进制文本。接口不回显预订ID/日期,关联依据是经过核验的详情
和实际请求;前后列表一致仍不能证明Oracle原子快照。`finance_ready/report_equivalence_verified/atomic_snapshot`始终false。
- 当前仍是采集层,未生成源XML或接入后台的ARRDownloadExecutor。后台的succeeded要求独立验证后的Finance提交,
不得用采集完成替代。来源适配、同源报告验收和实际交付见[验收清单](arr-api-acceptance-matrix.md)。
```sh
.venv/bin/python -m integrations.ohip.audit_arr_day \
--capture-dir /absolute/path/to/attempt-0001 \
--manifest-sha256 <采集完成时另存的64位摘要>
.venv/bin/python -m unittest tests.test_ohip_day_capture tests.test_ohip_day_jobs
```
### v1:保留的搜索/详情采集
[collect_arr_source.py](collect_arr_source.py) 是可直接运行的 Python 标准库工具,只调用已有的
`searchHotelReservations` 和 `getReservation`。日期必须明确指定;`--hotel-id` 用于核验平台选择的酒店,
不能用它切换平台路由。以下命令会进行真实只读调用,输出目录必须是仓库外尚不存在的新目录:
```sh
.venv/bin/python integrations/ohip/collect_arr_source.py \
--arrival-date 2026-09-15 \
--hotel-id OHIPSB02 \
--credential-file "$HOME/Library/Application Support/ohipctl/credentials/arr2-application-caller_zloxalzsQ9pYsztt.json" \
--output-dir "$HOME/Downloads/arr-api-2026-09-15-run-001"
```
- 只按到店日期取候选集合,使用已测试的 ConfirmationNo 升序分页;尚未认定等价报表筛选或物理行顺序。
不预先排除取消/NoShow、空 ETA、缺费率代码或未分房记录,不筛选备注、Trace 或费率白名单。
- 每页最多100条,最多100页/10,000笔;详情按内部 Reservation ID 读取,8个 fetchInstructions 使用重复查询键。
这些是本工具的保守上限,不是 Oracle 声明的接口上限。
- 核对分页计数、下一 offset、唯一身份、酒店、到店日期、详情状态/修改时间;显式备注/Trace计数须匹配。
详情须恰好一笔且属于目标预订;最后重查全部搜索行,任何内容或顺序变化都会失败。
- 单次网络超时25秒;限流、选定5xx及瞬时传输错误最多3次尝试。遵守 Retry-After;超过30秒的服务端等待要求
会停止本批次而非提前重试。401/403、重定向、警告、超大/非法响应和空日结果均不能得到完整采集标记。
- 应用密钥只在内存构造 X-API-Key;核验凭证归属、状态、服务和文件权限。拒绝重定向,不把密钥写入命令、归档或日志。
工具没有请求额外权限、改订房、写 Finance、上传 OSS、生成 XML/XLSX 或部署能力。
输出目录0700、文件0600,文件只能新建不能覆盖。每次尝试的请求元数据(不含认证头)、原始响应字节和状态分别保存;
`result.json` 列出前面文件的 SHA-256/字节数;程序摘要另外返回 `manifest_sha256`,供单独保存并固定整批清单。
失败也保留已取得证据;中断导致没有最终 `result.json` 时必须视为不完整,
不支持自动续接或复用该目录。归档包含客人及备注资料,应按酒店要求保管;摘要不输出这些明细。
退出码0只表示 `candidate_capture_complete=true`。`finance_ready`、`report_equivalence_verified`、`atomic_snapshot`
始终为false。状态/修改时间和搜索复查无法证明 Oracle 原子快照,也不能排除没有反映在搜索行中的详情变化。
空源不能据此清空某天 Finance;失败批次不能作部分日报提交。
验证:34项采集/本地HTTP测试及18项既有XML比对测试通过;已保存的139笔真实详情、4页搜索响应离线回放通过,
原始477文件在回放前后摘要一致。本轮未重新请求酒店业务数据。可复现测试命令:
```sh
.venv/bin/python -m unittest tests.test_ohip_arr_collection tests.test_ohip_report_comparison
```
[采集工具验证证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-api-collector.md)记录样本、目录刷新和限制。
后续日价封装已接入上文v2采集;同环境报表的筛选、字段与顺序验收仍待完成。
## 指定预订和日期的有效价
[rate_info.py](rate_info.py) 是独立的只读查询模块,优先使用 `searchRateInfo`:
```text
POST /api/v1/reservations/rate-info/searches
{"id":"<内部Reservation ID>","type":"Reservation","summaryInfo":false,"detailDate":"2026-09-15"}
```
调用方传入已核验的酒店、私有Archive和HTTPTransport;密钥仍由已有受保护文件加载,不进入源码或日志。
接口正文不需要 query 包装;本轮最小四字段请求无需追加日期范围或重新报价参数。
GET `/api/v1/reservations/rate-info` 仅保留兼容核对,平台已标为上游弃用。
有效价候选为 `data.detail.totalRateAmount`,币种为 `data.detail.revenue.currencyCode`。
缺价、隐藏、警告、空对象或summary结果不能填0;显式0合法。原始金额按Decimal解析,读接口可有界重试。
[定义摘要](rate-info-contract.json)和[脱敏实测](rate-info-verification.json)已保存;5类样本包括跨日变价、包价、零价、零晚和普通预订。
此模块已接入v2整日采集,尚未接入生产。v1档案仍只有search/detail;早期5笔验证不代表原报表等价通过。
接口返回也不是最终财务 `REAL PRICE`,后续仍走固定定价规则和必要的人工复核。
```sh
.venv/bin/python -m unittest tests.test_ohip_rate_info
```
## 可重试的采集批次
[capture_job.py](capture_job.py) 在原采集器外增加本地任务状态、并发锁和完成档案复用。
它不依赖getRateInfo,可先用于现有两项读取接口。下面命令会在需要新采集时进行真实只读调用:
```sh
.venv/bin/python integrations/ohip/capture_job.py \
--job-store "$HOME/Downloads/arr-api-jobs" \
--batch-id arr-20260915-001 \
--arrival-date 2026-09-15 \
--hotel-id OHIPSB02 \
--credential-file "$HOME/Library/Application Support/ohipctl/credentials/arr2-application-caller_zloxalzsQ9pYsztt.json"
```
`batch-id` 是调用方给“一次采集意图”分配的稳定编号,仅允许小写字母、数字、连字符和下划线,最多64字符。
它不是永久的日期缓存:同一天主动刷新数据要使用新编号;同一编号的重试必须保留原日期、酒店、分页配置和接口契约。
日期仍须显式指定,没有新增定时器或自行决定酒店时区。
| 批次现状 | 再次执行同一命令的行为 |
|---|---|
| 从未执行 | 创建第一轮完整采集 |
| 正在执行 | 返回batch_busy,第二个进程不读取凭证、不调用接口 |
| 已完成 | 校验原清单摘要及全部文件,回放请求/响应完整性后返回同一档案,reused=true;无需重新读取凭证或接口 |
| 上一轮失败 | 保留旧目录,从第一页开始新一轮完整采集;不拼接旧页或旧详情 |
| 上一进程中断 | 获得OS锁后将旧轮次记为interrupted,再重新采集完整一天;不依靠PID或超时猜测进程已死 |
| 抓取完成但完成状态未持久化 | 不擅自采用尚未登记摘要的结果;保留该轮原件并重新采集 |
| 同编号改日期/酒店/参数,或已完成档案变动 | 拒绝执行,不自动覆盖原件或重新下载掩盖差异 |
一次命令最多发起一轮采集;单次HTTP仍沿用原采集器的有限重试。一个批次最多10轮,达到上限后停止。
本工具不自动循环重启失败批次,也未实现跨运行的服务端限流等待调度。失败原因应先解决,再重试。
目录在仓库外、目录0700/文件0600。批次内 `job.json` 固定身份与参数,`state.json` 原子写入轮次状态和完成清单摘要,
`attempt-0001/`等目录保留各轮原始证据。只有持有批次文件锁的进程可推进;进程退出由OS释放锁。
2026-09-17补充:三个采集版本共用的批次身份比较已按规范化JSON摘要执行,整数与浮点数/布尔值不互相冒充,
JSON对象字段顺序不影响重用。身份冲突会在工厂调用、状态写入或新建采集轮次前拒绝。
此实现用于本机POSIX文件系统,不是多台服务器共享锁或生产数据库任务队列。不要修改/删除.lock或手动改state.json绕过保护。
完成回执含capture_dir、manifest_sha256、记录数和轮次,可交给本地档案核验工具。它只表示采集完成,
finance_ready/report_equivalence_verified始终为false。财务端避免重复提交仍需后续服务端任务/事务衔接;
现有人工XML上传保持每次创建新任务的行为,本工具没有调用该入口。
验证:20项批次管理测试覆盖跨进程互斥、真实进程退出、完成前中断、失败整批重采、档案变化拒绝及凭证延迟读取;
结合已有测试共99项通过。139笔已有样本离线运行首次读取143份响应,第二次新增读取0份、返回相同清单摘要。
原档案432文件保持不变,未调用酒店接口。详见[批次验证证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-capture-jobs.md)。
## 处理结果交接与重试(本地原型)
[processing_handoff.py](processing_handoff.py) 补上未来源适配器与既有处理链之间的交接基础,
当前只有可注入依赖的 Python 库,没有 CLI、Web 路由、调度器或运行环境凭证加载。
目前使用合成 XML 验证,尚未把 API 原始数据转换或提交到 Finance。
- `prepare` 接受 XML、采集批次/酒店/日期/清单摘要及适配契约编号,以应用、酒店和批次固定处理任务 ID。
同一任务改 XML、日期、采集摘要、适配契约、原文件名或处理规则均拒绝;主动重新采集使用新的批次编号。
- 先在本地私有文件存储中运行真实固定处理器和独立校验器,成功校验后保存同一组 XML、结果文件、日报及交付内容。
报告日期须匹配批次日期;`PRICE_UNMATCHED` 和业务失败也沿用既有交付契约。
- 发布完整文件组前先持久化独立清单摘要,文件组原子保存后再写ready标记;二者之间中断可凭原摘要和完整校验恢复。
旧版未登记摘要的文件组仍拒绝自动采用。保存完成后的重试核对每个文件和摘要,不重新生成 XLSX,也不替换源文件。
- `deliver` 必须显式传入目标对象存储、仓库和验证服务,使用已固定的文件字节和任务/交付 ID。
上传中断、登记回执丢失或提交结果不明,均可重试相同文件组;不调用每次新建 UUID 的人工上传入口,
也不因客户端异常把可能已经提交的任务改为失败。
- 编排器还应传`expected_binding`及`expected_policy`;Web执行器现在总是传入。交付锁内先比对实际包的
完整采集来源与处理规则,匹配后才允许目标存储/数据库写入。既有只传包摘要的独立调用保持兼容。
身份文件与已固定清单使用严格JSON摘要比对,不再接受整数/浮点数的宽松相等。
- 结果仍经独立校验及现有数据库交付事务;成功版本/事件的权威在数据库。`receipt.json` 只是原交付的确认,
不能代表之后的人工复核进度;复核及当前任务状态仍从现有接口读取。
`CaptureBinding` 只是记录输入来源,**不证明 XML 与接口数据等价**;回执明确保留
`source_mapping_verified=false`。接口字段适配、完整价格、同源验收、生产运行接线和跨主机调度仍待完成。
真实PostgreSQL并发/断连已在隔离临时数据库中验证,见[SQL证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-postgres-download-acceptance.md);
它使用合成来源及本地对象,不是生产验收。不得把本地文件锁当作分布式队列,也不能仅凭准备成功就提交真实接口候选数据。
同一文件组丢失或被修改后应停下核验,不能通过新编号掩盖结果不明。
库测试使用实际处理器/校验器、临时文件存储和内存仓库;另有模拟游标和真实隔离PostgreSQL验收。
没有连接业务数据库。原人工上传入口及人工价格复核保持现有实现。
```sh
.venv/bin/python -m unittest tests.test_ohip_processing_handoff
```
详见[交接验证证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-processing-handoff.md)。
## 本地档案与字段核验
[audit_arr_capture.py](audit_arr_capture.py) 只读已保存的采集目录,不需要凭据,也不联网或改动原件。
先用单独记录的 `result.json` SHA-256固定清单,再检查每个文件、请求顺序、分页和详情响应,回放完整采集检查,
最后输出16字段的候选缺失/多值、姓名组成、日期段、备注和房号碰撞等聚合统计。
```sh
.venv/bin/python integrations/ohip/audit_arr_capture.py \
--capture-dir /Users/chillishark/Downloads/arr-api-collector-replay-20260916-uvwshily/capture \
--manifest-sha256 879d2f0a6254425fcf31ee57c1a79ec66d48f7a88bc5d9af30353b9ef28e428e
```
上例固定的是本机已验证的离线回放档案,不能拿来核对另一批次。新采集应使用当时返回并单独保存的清单摘要;
不能在发现疑似改动后重新计算候选目录的摘要并将其当作原始证据。哈希能检查相对固定清单的完整性,不能证明Oracle真实性。
原始目录必须保持0700/文件0600;拒绝符号链接、目录穿越、未列入或缺失文件、清单声明与协议回放不一致。
本工具另有限制:清单32MiB、总原件1GiB;超过时停止,不截断后给出完整结论。
退出码0表示档案回放和统计成功,**不代表字段有效性或报表口径已通过**。非空候选统计不验证全部数值范围/币种/展示规则;
同房组是全部当前房号候选trim后得到的碰撞,保留前导零,尚未按白名单及候选有效性分类,不是应删除行数。
FULL_NAME完整显示名与姓名组成字段分别计数,不自行拼接;有效价不回退到base/total;公司角色不自动选择优先级。
所有 `finance_ready`、`report_equivalence_verified` 和逐字段映射标记保持false。
协议回放复用采集器逻辑,是本地完整性检查,不能替代未来API→来源映射的独立验收。
v1档案没有保存响应重试头,因此本工具不验证历史等待秒数;实际客户端的Retry-After行为由本地HTTP测试覆盖。
两项API之外的新操作需要同步扩展采集/档案契约,不能把新响应直接塞入v1目录。
[本轮聚合结果](arr-api-capture-audit-20260916.json)来自139笔已有响应;[报表验收清单](arr-api-acceptance-matrix.md)
区分已覆盖场景和仍需同源证明的口径。本轮27项新增核验测试与已有52项测试共79项通过。
```sh
.venv/bin/python -m unittest tests.test_ohip_capture_audit tests.test_ohip_arr_collection tests.test_ohip_report_comparison
```
## API 与原报告字段观察
[compare_arr_sources.py](compare_arr_sources.py) 只读固定摘要的v2/v3完整采集及原ARR XML,酒店/日期不同拒绝逐笔比较。
内部预订ID仅与RESV_NAME_ID唯一配对,重复ID保留为歧义;逐项比较记录集合、顺序、有效价和42项直接值/候选假设。
公司角色、姓名格式和Trace过滤分别观察,不从一次相等自动选择业务规则。
公司另比较`C- `/`T- `/`S- `/`G- `前缀假设,入住总人数与到店日人数分别比较;不删原前缀或在缺值时互相补位。
`native_observations`只描述XML自身的固定分类计数和排序假设,即使不同酒店也可返回;它不是跨酒店逐笔比对。
其中字符串大小写折叠后的升序仅是样本属性,不证明配置的排序或同键先后规则,ROWNUM不用于重排。
```sh
.venv/bin/python -m integrations.ohip.compare_arr_sources \
--capture-dir /absolute/path/to/v2-capture \
--capture-sha256 <另存的采集清单摘要> \
--report /absolute/path/to/same-source-arr.XML \
--report-sha256 <已固定的原报告摘要>
```
输出只含聚合及每项最多20个问题行位置。退出0表示完成观察,2表示不可比,3表示输入无效;三个业务就绪标记始终false。
相同酒店/日期不能证明环境/数据时点一致,数值相等也不替代处理器校验。工具不生成XML或提交Finance。
Oracle已确认原报告排除已解决Trace;无解决标记的API记录仍只是独立候选,不能直接证明报表顺序和范围。
工具累计40项测试与47项相关回归通过;当前OHIPSB02与57106真实输入正确返回不可比,851份档案原件未变。
用户暂时无法访问测试酒店导出同源报告,逐笔验收保持待完成。见[详细证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-source-comparison.md)。
v3输入须在上述命令中增加`--capture-version v3`,并传对应v3目录及摘要;默认v2不自动升级。
v3结果为`arr-api-native-comparison/v2`,增加主客摘要姓名的原文及去除首尾空格两项独立观察。
原文比较使用XML解析后的文字;缺失或组成不符不回退到搜索姓名/拼接姓名。Trace已按用户要求排除在v3待验收项之外。
当前真实v3批次不完整,仍被拒绝比较。见[新版证据](../../.project-docs/50-evidence/topics/2026-09-17-arr-named-field-evidence.md)。
后续显示字段研究见[本轮证据](../../.project-docs/50-evidence/topics/2026-09-16-arr-display-contract.md)。
## 原生 XML 本地比对
用户最新确认准确原文件为`/Users/chillishark/Downloads/res_detail_71054429.XML`,页面选项Resv.-GEN。
它与下方旧文件基准字节及摘要完全相同,故既有72行/61保留处理结果仍适用;CAS/GENERAL是源XML内部元数据,
不是选项矛盾。文件及页面确认已完成,[记录](../../.project-docs/50-evidence/topics/2026-09-16-confirmed-native-arr-notes.md)。
[compare_report_xml.py](compare_report_xml.py) 比较固定手工基准与将来取得的原生 XML,仅做本地只读检查。
运行示例(将 candidate 换成实际待比文件;没有接口文件时不能据此声称下载验收通过):
```sh
.venv/bin/python integrations/ohip/compare_report_xml.py \
--baseline /Users/chillishark/Downloads/arr-manual-baseline-20260916-710p_dt_/input/res_detail_71050118.XML \
--baseline-sha256 5c87ab6f2483b2244e98e47bb792080ef4aca9036568638842116b246ac97438 \
--candidate /path/to/native-download.XML
```
- 必须提供已确认的基准 SHA-256,防止用错或替换基准。不要从待比文件计算这个基准值。
- 输出 JSON 到 stdout:文件摘要、源记录数、酒店/分组日期、字节/内容一致性、报表元数据差异、
记录顺序、缺失/新增/变化的记录数及位置。诊断仅显示有限字段名,不输出客人、备注、房号、金额或预订 ID。
- 逐笔定位按 `RESV_NAME_ID` 及其第几次出现,不合并重复 ID;位置为 XML 物理顺序,从1开始。
多条备注与 Trace、字段顺序、未知字段、原始金额和未筛选费率都参与比较,不按 ROWNUM 重新排序。
- 忽略属性排列、XML 声明/BOM、注释和元素间纯缩进。保留叶子文本中的空格、非空混合文本、元素内处理指令、
子元素顺序;XML 解析本身会规范化换行/字符引用。根节点外处理指令不参与内容比较。缺失元素与空元素不同。
- UTF-8、RES_DETAIL、非空原始行、单一酒店及有效且一致的分组日期是最低结构要求;拒绝 DTD/实体声明、
混合酒店/日期、缺失或重复身份字段、意外记录布局、超过64MiB或128层的文件。空日报不在本工具已接受范围内。
- 退出码:`0 match`、`1 different`、`2 not_comparable`(酒店或分组日期不同)、`3 invalid_input`。
明细各最多50项,总数不截断;`different` 不等于接口错误,可能是两次导出期间业务事实已变化。
本工具没有网络/上传/数据库/凭证能力,也没有接入 Web、worker 或 Finance。相同酒店和日期不足以证明同一环境、
同一数据时点;相同内容不证明页面筛选、内部备注标记或未来文件的业务正确性。它不重算价格,不验证所有 ARR
必填字段,不替代既有处理器和独立校验。正式验收仍须核实同环境/参数/导出时点,再用现有处理链验证候选文件。
验证记录见 [比对工具证据](../../.project-docs/50-evidence/topics/2026-09-16-native-arr-xml-comparison.md)。
## 逐笔字段来源证据(离线,尚非最终报表适配)
[提取器](source_facts.py)将完整v2/v3采集的每笔记录、16目标列候选及上下文保留到私有JSON;
[独立验证器](validate_source_facts.py)重读固定原件,检查完整记录集合、字段值、类型、顺序、JSON路径和成功请求出处。
记录捕获顺序,不选择公司角色、不拼显示姓名、不筛备注/Trace、不生成ARR XML或执行Finance提交。
```sh
.venv/bin/python -m integrations.ohip.source_facts \
--capture-dir /absolute/path/to/v2-capture \
--capture-sha256 <已保存的采集清单摘要> \
--output-dir /absolute/private/new-field-evidence
.venv/bin/python -m integrations.ohip.validate_source_facts \
--capture-dir /absolute/path/to/v2-capture \
--capture-sha256 <已保存的采集清单摘要> \
--facts /absolute/private/new-field-evidence/source-facts.json \
--facts-sha256 <提取后另存的证据摘要>
```
导出目录必须在仓库外且尚不存在,目录0700/文件0600;成功生成`source-facts.json`和`verification.json`。
候选文件包含敏感原始字段,只保存在私有目录;stdout仅聚合结果。独立验证命令只读,需显式传入原先保存的证据摘要。
缺失/null/空集合/明确空串/错误容器/非标量分别记录;多值不合并,Decimal金额不转float。所有字段映射仍为
`unresolved`,退出0及`facts_verified=true`仅证明证据与固定原件一致;三个来源/等价/Finance标记始终false。
工具不实现Web的`adapt()`或`validate()`,不能用作运行时已验收适配器或业务校验器。
16项新测试,连同相关回归共140项通过;139笔现有采集已导出并独立验证,851原件未变。聚合计数是跨层/多段候选数量,
不是有效预订数。见[聚合结果](arr-source-facts-verification-20260916.json)和
[证据与边界](../../.project-docs/50-evidence/topics/2026-09-16-arr-source-field-evidence.md)。
v3输入需在提取和验证两条命令中均增加`--capture-version v3`,并使用对应v3目录和摘要;默认仍为v2。
新版字段证据为`arr-source-field-evidence/v2`:FULL_NAME分别保存搜索候选、摘要原文及逐预订校验候选,
绑定实际成功的档案请求/响应。`source_not_acquired`表示未查询,和已查询后缺值或空值分开。
独立验证器从原始详情推导唯一主客及Profile ID,再匹配成功响应;同名或共享档案不能掩盖错配。
新增19项及相关范围共198项测试通过,原139笔证据字节和契约摘要保持不变。真实失败批次只用于5份姓名的底层核验,
未导出为完整v3字段证据。[本轮离线回执](named-source-facts-offline-20260916.json)及
[新版验证范围](../../.project-docs/50-evidence/topics/2026-09-17-arr-named-field-evidence.md)。
## ARR 处理 XML 输出模块
### 逐笔候选准备与缺口汇总(2026-09-17)
[prepare_arr_source.py](prepare_arr_source.py)把已有严格取值器串联起来,先独立验证字段证据,再为全部记录的16列
生成`candidate`或固定原因的`gap`。它保留全部记录及采集顺序,不执行费率白名单、去重、报表排序或XML生成。
候选表示已满足对应取值条件,不表示原ARR报表已验收;公司显示、Block代码、包价显示、房型标签仍明确待定。
缺少姓名不影响其他字段的离线准备,v2记为未采集;v3逐预订姓名缺口原样保留。有效价使用精确Decimal文本,
不经浮点数、不把大指数展开成巨型字符串。Trace按用户范围明确为空;备注保留原文、重复和数组顺序。
```sh
.venv/bin/python -m integrations.ohip.prepare_arr_source \
--capture-dir /absolute/path/to/complete-capture \
--capture-sha256 <另存的完整采集清单摘要> \
--capture-version v3 \
--output-dir /absolute/private/new-preparation
```
v2归档使用`--capture-version v2`(也是默认值)。只接受完整固定归档;不完整v3在输出目录创建前被拒绝。
私有新目录包含`source-facts.json`、`source-candidates.json`和只含聚合的`preparation-summary.json`,目录0700、文件0600。
候选摘要绑定采集及字段证据SHA256;stdout仅计数/固定原因。退出0表示候选诊断已生成,四个业务/完整ARR标记仍false。
没有`adapt`或`validate`方法,不能把这个工具注入正式执行器。已有139笔真实归档的
[离线结果](source-preparation-offline-20260917.json)保留全部行,923份新旧原归档及原XML不变。
按钮后台执行器另已支持显式`capture_version="v3", max_profiles=N`,必须注入匹配的三Reader工厂和已验收来源组件。
旧版默认为v2;本次未改`arr_web.run`或启用按钮,详见[交接契约](../../arr_web/ARR_DOWNLOAD_HANDOFF.md)。
最新业务范围:用户明确不需要Trace,未来API适配传`SourceRow.traces=()`;输出不含Trace内容。
下面通用序列化器仍能保留调用方显式提供的Trace,历史72行投影测试对应原生样本,不代表当前API必须提供Trace。
本次范围调整不改变人工XML入口、已保存v2归档或旧版采集回放规则。
`arr_xml_contract.SourceDocument`明确包含酒店、业务日和有序`SourceRow`;每行必须显式给出14个文本字段及
`notes/traces`元组。`arr_xml.serialize(document)`生成处理器兼容的XML字节,
`validate_arr_xml.verify(document, payload)`独立解析并核对全部字段和列表顺序。金额以准确文本传递;
不转float、不筛白名单、不去重、不改变公司/姓名/备注格式。空字符串可以保留,None/缺失值不能自动补齐。
输出限25MiB(含XML转义后的字节),与现有冻结交接入口一致;空日仍不在当前处理器接受范围内。
验证只返回`serialization_verified`,不授予来源/报表等价或Finance就绪。此模块没有从API选择最终值,
也不实现`adapter.adapt(archive)`或`mapping_validator.validate(archive,payload)`,不能单独接按钮。
13项新测试及相关回归通过;确认样本72行、58备注、31Trace经本模块输出后,处理结果与原基准逐笔一致
(61保留/11排除)。这是处理字段投影,不复制原生报表的其他元数据,也不证明API已经能输出完整ARR。
见[输出验证](../../.project-docs/50-evidence/topics/2026-09-16-arr-xml-output-boundary.md)及[安全汇总](arr-xml-roundtrip-20260916.json)。
## 本机凭证
授权文件保存在仓库外,目录权限 0700、文件权限 0600:
- CLI 管理身份:`~/Library/Application Support/ohipctl/credentials/automation-auto_219f3af6dc2123dc29ee3138.json`
- ARR 应用 API Key:`~/Library/Application Support/ohipctl/credentials/arr2-application-caller_zloxalzsQ9pYsztt.json`
CLI 管理命令在进程环境中指定:
```sh
export OHIP_EDGE_URL=https://ohip.nianxx.cn
export OHIP_EDGE_AUTOMATION_FILE="$HOME/Library/Application Support/ohipctl/credentials/automation-auto_219f3af6dc2123dc29ee3138.json"
export OHIP_EDGE_TIMEOUT=20s
"$HOME/.local/bin/ohipctl" automation whoami
"$HOME/.local/bin/ohipctl" integration list
```
如另有 `OHIP_EDGE_AUTOMATION_TOKEN`,CLI 会优先使用它;本次操作已确认没有此项覆盖。
未修改 shell 启动文件,也未把凭据注入 ARR Web/worker。
后续消费代码在内存中读取应用凭证文件,核对 `version=ohip.application-credential/v1`、`status=ready`、
`service_url` 和 `application_id`,再将 `value` 放入 `X-API-Key`。不要把整个 JSON 打印到日志或提交仓库。
## 已验证和下一步
已完成身份验证、plan/validate、创建、应用回读、首次密钥签发、密钥列表及审计核对。
本地凭证的应用 ID、服务地址、Key ID 和文件权限均已核对;其后用户继续授权的 OHIPSB02 只读联调已完成,
未提交 Finance 或调用 Oracle 写入接口。
用户已确认 ARR 与预订部项目服务同一家酒店。预订部任务中也已明确:当前使用标准测试环境,先联调,
经 Oracle 审批后再接酒店正式环境,接口契约沿用。`OHIPSB02` 是当前已知测试酒店;无需再次询问其是否为
日常真实酒店。平台管理审计的 `deployment_environment=production` 标签不改变这一 Oracle 测试环境背景。
正式接入时再核对地址、凭据、酒店 ID 和业务代码映射;当前可继续测试阶段的接口研究。
详见 [同酒店背景](../../.project-docs/50-evidence/topics/2026-09-16-shared-hotel-rsvn-context.md)。
字段、分页、完整日快照、备注/Trace 与金额等价性仍按
[接口研究](../../.project-docs/50-evidence/topics/2026-09-16-ohip-interface-review.md)讨论。
应用签发证据见 [操作记录](../../.project-docs/50-evidence/topics/2026-09-16-ohip-application-provisioning.md)。