Files
wyndham-ARR/.project-docs/50-evidence/topics/2026-08-03-company-report-publish-retry.md

4.2 KiB

Evidence Topic: 2026-07 company-report retry publication failure

Metadata

  • Date: 2026-08-03
  • Status: Implemented; live historical rerun pending
  • Scope: 2026-07 company-channel report, C/O 11-20, local Web job 60bcda9c8dae49758fb69dc47e0ff9e7
  • Confidence: Fact for recorded job/build observations; inference for the exact publisher guard
  • Source: job JSON, prior successful job JSON, read-only controlled PostgreSQL snapshot, source-code inspection and temporary-directory double-build probe
  • Last verified: 2026-08-03
  • Stale trigger: changes to the company XLSX builder, artifact identity, reservation-version derivation or publisher idempotency

Question

Why did the Web show 正式表格发布失败 for 2026-07?

Evidence

  • The failed job is for report month 2026-07, period 11-20, and as-of date 2026-07-20. All five companies failed at stage publish with COMPANY_REPORT_PUBLISH_FAILED; there are no record IDs and no source/Booking/business validation errors.
  • The immediately preceding job for the same month and period succeeded for all five companies and created archive versions. The failure is therefore a retry of an already published semantic snapshot, not a first-build data failure.
  • company_reports.repository.PostgresReportRepository.reserve_report() derives the version directory from a deterministic semantic identity containing the company, period, as-of date, processor/rule/schema versions, daily-version pins and Booking-version pins. The retry therefore targets the same archive version path.
  • A read-only double-build probe loaded the current controlled July snapshot and built each of the five valid 11-20 workbooks twice in separate temporary directories. For every company, the two binary SHA-256 values differed while the builder's semantic_sha256 was identical.
  • AtomicReportPublisher._install_once() rejects an existing archive path when its binary SHA-256 differs from the newly built file, raising COMPANY_REPORT_PUBLISH_FAILED. The result JSON also embeds the binary SHA-256, so allowing only the archive copy would still leave the same retry-identity conflict at result validation.
  • No database write, report rerun or output repair was performed during this diagnosis.

Implemented Fix

  • AtomicReportPublisher now checks for an existing archive/result pair before creating legacy/current side effects. A retry is reusable only when both files are regular files, the result JSON matches the deterministic report identity and current semantic SHA, and the archive's actual SHA-256 matches the result JSON's stored artifact SHA.
  • A matching retry returns the existing archive/result metadata and activates the repository without copying the new XLSX bytes. An existing current file is left untouched; a missing current file is repaired from the existing archive.
  • Partial, corrupt, hash-inconsistent or semantically conflicting publication state fails closed with PUBLISH_FAILED. First publication and activation-failure rollback paths remain covered.
  • Regression coverage passed for same-semantic/different-binary retry, semantic mismatch, partial publication and corrupted archive. The real ArtifactTool integration regression is present but was skipped locally because the optional @oai/artifact-tool dependency is unavailable.
  • No live report rerun, output repair or business-data mutation was performed after the code change.

Conclusion

The 2026-07 11-20 failure was caused by a non-byte-deterministic XLSX build colliding with the publisher's deterministic archive/version identity on retry. The workbook contents were semantically the same, but changing XLSX bytes made the immutable archive and result identity appear conflicting. The existing successful 11-20 artifacts remain valid; the failed retry did not replace them. The publisher now handles this case idempotently by reusing that stable identity.

Fix direction

The publisher-side idempotency fix is implemented and is the active remedy: reuse/validate the existing artifact by semantic identity and preserve one stable binary artifact identity. Making the XLSX builder byte-deterministic remains an optional future optimization, not a prerequisite for retry success. The historical job still needs a deliberate live rerun to verify the deployed path.