# Booking source and company-report retry semantics

## Metadata

- Date: 2026-08-03
- Status: Confirmed in source; live acceptance remains pending the controlled port-8766 restart
- Scope: Repeated identical Booking Excel uploads, company-report reruns and subset-source reruns
- Confidence: Fact for the current source contracts and tests; live runtime is still the stale PID 11176
- Source: `booking_ingestion/excel_review_postgres.py`, `company_reports/repository.py`, `company_reports/core.py`,
  `company_reports/publishing.py` and focused unittest suites
- Last verified: 2026-08-03

## Confirmed behavior

1. A byte-identical `.xlsx` is identified by its file SHA-256. In the real PostgreSQL review repository, if that
   artifact has already been activated, a repeated upload returns `BOOKING_EXCEL_SOURCE_ALREADY_ACTIVATED` and does not
   create another extraction batch. If the workbook has the same Booking rows but different XLSX bytes, it is a new
   upload and must go through review/activation again; row-level semantic deduplication is not used at upload time.
2. A company report can be generated again after a successful publication. The report reservation identity includes the
   month/period cutoff, Finance daily-version pins, Booking parse-version pins and processor/rule/schema identity. An
   unchanged identity reuses the complete archive/result pair; a changed identity creates a new version and retains the
   earlier files. Partial, corrupt or semantically conflicting publication state fails closed.
3. A subset workbook is not a duplicate of its previous superset. After review is complete and the subset is activated,
   `booking.current_source_batch` points to it and a report rerun reads that active Booking snapshot. Finance facts remain
   the report row boundary; Group Codes missing from the subset produce rows with blank Booking Room details rather than
   silently deleting the Finance rows. Upload alone does not switch the active source, and an open review draft blocks
   company-report generation until it is activated or discarded.

## Runtime boundary

The current 8766 listener is still PID `11176`, started on 2026-08-02 before the duplicate-publication fix. The source
contracts above are therefore the intended behavior after a controlled restart; the failed August retry is not valid live
acceptance of the fixed publisher.

## User-visible reuse status

The current publication outcome contains the artifact and result metadata but no `reused`/`publication_disposition`
field. `CompanyRunResult` and the public company-job projection likewise expose success, version number and download URL,
not whether the publisher reused an existing archive/result pair. Consequently, after a successful retry the operator sees
`成功` and a normal download link; the downloaded bytes can be the original archived file, but the page does not identify
which prior file/version was reused.

## Verification

- Focused source-upload/publisher/integration unittest: 14 tests passed, 2 optional ArtifactTool integration tests
  skipped because the local dependency is unavailable.
- No source activation, report rerun, output repair or business-data mutation was performed.
