# Spike: Clarify HPT export retention-range messaging

Status: complete
Result: complete; recommendation promoted to implementation ticket
Disposition: planned
Type: spike
Updated: 2026-07-23
Next Action: implement work/tickets/ticket-hpt-export-domain-failure-reasons.md
Campaign: 003-complete-bounded-hpt-slow-export-firmware-ticket
Parent: work/wp/active/wp-triple-mirrored-circular-hpt-log-store.md
Produces: work/tickets/ticket-hpt-export-domain-failure-reasons.md

## Question

How should customer log export distinguish a requested interval that predates
the records still retained on circular HPT media from actual HPT corruption,
an HPT read failure, and a USB publication failure?

The immediate Controller A observation was:

- a ten-minute visible export completed successfully;
- a thirty-minute request displayed `Error / Copying log data`;
- live read-only diagnostics showed export state `HPT_EXPORT_FAILED`,
  `HptStatus = HPT_STATUS_CORRUPT`, USB status zero, one record scanned, zero
  selected, and 40 requested-range gaps;
- HPT media remained ready with no SSP or first-sector error while minute
  logging continued; and
- the accelerated wrap fixture retained only 16 records, so the requested
  thirty-minute interval necessarily began before the retained history.

The request was valid under the normal 90-day date-entry policy, but unavailable
under the deliberately tiny qualification geometry. That is an availability
condition, not evidence that the card or retained records are corrupt.

## Timebox

Two engineering hours for source tracing, a failure-reason/UI contract, and
acceptance-test definition. Do not change firmware or disturb the live
Controller A/USB evidence as part of this spike.

## Findings

- The date-entry validator checks only the product's 90-day policy, future
  timestamps, ordering, and minimum duration. It cannot know the media's
  current oldest retained timestamp.
- `S_HptExportStatus` exposes HPT and USB statuses plus gap counters, but no
  explicit export failure reason or oldest available timestamp.
- The raw export iterator treats a sequence gap that may overlap the requested
  interval as either `HPT_STATUS_IO_ERROR` or `HPT_STATUS_CORRUPT`. The
  out-of-retention case therefore reaches the same status as damaged or
  internally inconsistent retained data.
- The progress screen reduces those terminal states to numeric values
  (`900`, `901`, and `902`). The visible export maps `900` to the generic
  `Copying log data` error text, so the operator cannot choose a corrective
  action.
- After accelerated wrap, the live store snapshot reported a first sequence
  older than the actual retained set. The iterator safely skipped missing
  sequences and failed closed, but deriving availability indirectly from gaps
  obscures whether the request is simply too old or retained data was lost.
- The USB writer did not start for this failure. USB status remained zero and
  no partial raw export was handed off, which is the correct complete-or-fail
  behavior.
- Subsequent host inspection confirmed that the successful ten-minute CSV was
  complete and that the rejected thirty-minute request left neither a
  finalized file nor a temporary/partial artifact.

### Failure-reason contract

| Reason | Meaning | Customer message | Required behavior |
| --- | --- | --- | --- |
| `RANGE_NOT_RETAINED` | Request begins before the oldest available record | Requested log range is no longer available. Choose a shorter or more recent range. | Reject before publication; do not label media corrupt |
| `RETAINED_DATA_GAP` | A record expected inside the advertised retained interval is missing or ambiguous | Log data validation failed. The requested file was not created. | Fail closed and preserve diagnostic sequence/gap detail |
| `HPT_MEDIA_IO` | Raw media read/open operation failed | Log media read error. Try again or service the SD card. | Fail closed; preserve HPT/SSP/sector diagnostics |
| `USB_IO` | Temporary-file write, flush, close, verify, or rename failed | USB write error. Check or replace the USB drive. | Leave no finalized partial CSV |
| `INVALID_REQUEST` | Dates are invalid or outside the product policy | Existing date-specific correction | Reject before scanning |
| `EXPORT_CAPACITY` | A valid request exceeds the bounded staging/export capacity | Requested range is too large to export. Choose a shorter range. | Fail closed without calling it corruption |

## Recommendation

Implement an export-domain failure enum rather than inferring customer meaning
from `HptStatus`, `UsbStatus`, or the generic progress number. Add the reason and
the oldest/newest available timestamp (and sequence where useful) to the public
export status.

At snapshot creation, establish the true current retained bounds. If the
requested start precedes the oldest available customer record, fail immediately
with `RANGE_NOT_RETAINED`. Keep the existing fail-closed gap check, but reserve
`RETAINED_DATA_GAP`/`HPT_STATUS_CORRUPT` for a hole or ambiguity inside the
advertised retained interval. Correct the circular store's live oldest-sequence
tracking if inspection confirms it can remain stale after reclamation.

Have the HMI terminal screen consult the export failure reason and display the
actionable message from the matrix. The generic progress value may continue to
drive the widget, but it must not be the semantic source of truth.

The recommendation was promoted on 2026-07-24 to
`work/tickets/ticket-hpt-export-domain-failure-reasons.md`. This spike remains
the discovery record.

Do not weaken the 90-day customer promise because this accelerated fixture
retains only 16 minutes. Production geometry must still retain and export at
least the newest 90 days; this reason exists for qualification fixtures,
degraded/replaced media, or requests beyond the actually available history.

## Follow-Up

- [x] Inspect the current USB stick on the host and preserve the successful
  ten-minute CSV plus the absence of a finalized thirty-minute partial file.
- Historical planning item: Create a bounded implementation ticket covering the explicit reason enum,
  retained-bound discovery/tracking, and HMI mapping.
- Historical planning item: Add host/source tests for every row in the failure-reason contract.
- Historical planning item: On Controller A, verify ten minutes succeeds and thirty minutes on the
  16-record fixture reports `RANGE_NOT_RETAINED` without creating a file.
- Historical planning item: Inject an actual retained-range gap and confirm it still reports data
  validation failure rather than range unavailability.
- Historical planning item: Inject HPT read and USB write failures and confirm their messages and
  diagnostics remain distinct.
- Historical planning item: Repeat a normal production-geometry request within the newest 90 days to
  prove the customer retention contract is unchanged.
