# Company report source label and live runtime

## Read-only evidence

- `booking.current_source_batch` points to accepted Booking Excel batch 7 with 72 source rows. No reviewing extraction
  draft is open.
- The latest August `01-10` jobs contain `source: null`, and all five company results report
  `COMPANY_REPORT_PUBLISH_FAILED` at stage `publish`. The reports reached publish after building company row counts
  54/18/7/1/15, so the subset was parsed and reached report generation.
- Batch 7 was activated before the failed jobs were created. The company-report repository reads
  `booking.v_current_room_items`, so the active source boundary is the new batch; the missing source field is trace
  metadata, not proof of an old-data report.
- The live Web PID on port 8766 started on 2026-08-02 12:20. The current `arr_web/company_jobs.py` and
  `company_reports/publishing.py` were modified on 2026-08-03, after that process started. Refreshing the page cannot
  load the new Python code; a controlled Web restart is needed for future jobs to persist source metadata and use the
  current duplicate-publication handling.

## Conclusion

The message does not by itself mean the report used the previous Excel. In this case the new subset is active, but the
currently running Web process is stale and saved new job records without the source summary. The same stale process
also rejected the new `01-10` publication attempts at the publish boundary. Existing null metadata should not be
backfilled by guessing; future jobs should be checked after a controlled restart and one authorized rerun.

## Post-restart retry recheck

The operator reported restarting port 8766 and reran `2026-08/01-10`. The newest job `253ce23dc7544d34a6e0fb9405ac4d9a`
was created at `2026-08-03T07:09:33Z` and finished at `07:10:28Z`; it again built the five row sets
`54/18/7/1/15`, then failed all five companies at `publish` with `COMPANY_REPORT_PUBLISH_FAILED`. Earlier job
`c5358fa293184f5f9bad85178afada22` succeeded at `06:25Z` with the same row counts and complete archive/result pairs.

The effective listener is still PID `11176`, started `2026-08-02 12:20:56 +0800`, under detached Screen
`arr2-web-8766`. The current `company_reports/publishing.py` was modified at `2026-08-03 11:19:58 +0800`, after that
process started. The deterministic reservation and complete-pair reuse fix is therefore present in source but not loaded
by the process that handled the retry. A browser refresh only reloads static assets; it cannot reload imported Python
modules or replace the port listener.

The operator-facing publish copy was shortened to an actionable message: `数据已处理，但正式 Excel 保存失败。请重启
报表服务后再生成。`

No service restart, source activation, job backfill or report regeneration was performed by this recheck.

## Latest retry recheck

The operator's next `2026-08/01-10` attempt created job `087dceca79e64bebb719ad06e7813465` at
`2026-08-03T07:28:52Z` and finished at `07:29:49Z`. It again built row counts `54/18/7/1/15`; every company failed only
with `COMPANY_REPORT_PUBLISH_FAILED` at `publish`. The result is therefore the same stale-runtime retry signature, not a
new source-validation, Booking-match or workbook-build failure.

At `2026-08-03 15:37 +0800`, `*:8766` was still owned by PID `11176` under Screen `11172.arr2-web-8766`, both started
`2026-08-02 12:20:56 +0800`. The current publisher and company-job modules were modified after that start time. The
existing launcher `--check` passes, so configuration is ready; the running listener itself has simply not been
replaced.

The earlier successful `c5358fa...` job's five versioned XLSX files match both their result JSON artifact hashes and
their current-download copies. The failed retries contain no artifact descriptors and did not overwrite the successful
files. Current source's six publisher regressions pass. The safe repair is to stop the exact old listener, verify port
8766 is free, start one new Screen session through the launcher, verify its PID/start time and authenticated company
readiness, then run one explicitly authorized retry. No archive deletion, metadata backfill or file repair is needed.

This check remained read-only: no service restart, report generation, artifact mutation, source activation or database
write was performed.

## Controlled restart and live acceptance

After explicit operator confirmation, the exact stale listener PID `11176` was stopped with SIGINT. Port 8766 was
verified free, then one detached `arr2-web-8766` session was started through the existing launcher. The new listener was
PID `54127`, started `2026-08-03 15:46:29 +0800`, after the current publisher and company-job module modifications.
`/healthz` returned 200 and authenticated `/api/health` reported database, processing, monthly, download,
company-report and company-source readiness all true.

Exactly one new `2026-08/01-10` task was submitted: `05cc547d62854df281b0c9cac60e6f6d`. It finished at
`2026-08-03T07:48:37Z` with `succeeded`; all five companies succeeded with row counts `54/18/7/1/15`. The job now
records non-null active Booking batch-7 source metadata, confirming the new Python process loaded the source-traceability
code.

The five version numbers and artifact descriptors exactly match the earlier successful job `c5358fa...`. Every archive
XLSX, current-download XLSX and result JSON hash matches its registered artifact identity; all five authenticated HTTP
download routes returned 200 and matched those hashes. Archive mtimes remained at the original 14:24–14:25 publication
times, proving the retry reused the existing publication pair without overwriting it.

The temporary authenticated session was logged out and its temporary files removed. No Booking source activation,
Finance fact change, artifact deletion or repair occurred. The stale-listener incident is resolved; detached-session
reboot supervision remains a separate deployment gap.
