Skip to content

Retire the pre-adaptation back-compatibility cluster in one piece — the condition ADR-0015 called uncheckable is settled by decision #52

Description

@TBarregren

This was generated by AI during triage.

Split out of #41, which is closed in favour of this. The decision behind it was taken during that triage: this project carries no backwards compatibility below 1.0.

What this removes

ADR-0015's penultimate Consequences bullet enumerates a back-compatibility cluster and states that it must retire as one piece — removing any part of it ahead of the others would leave a site mid-upgrade with an unrecoverable build. The members it names:

  • Sweeper::reclaimable()'s carve-out for the stranded stall
  • Extraction_Job::is_pre_adaptation_stall()
  • Dispatcher::resume_failed(), the resume path that reads it, and is_resumable() with it
  • Sealed_Writer::seed_index() and its call in Artifact_Builder::advance()
  • Build_Progress::$legacy_names
  • every from_array() branch whose absent key is exclusively a signal that a record predates 0.6.0 — the schema-8 budget keys, the schema-6 segment_names/table_offset/table_cursor triad, the schema-6 attempts/error pair, and the schema-3/4/5 fields older still

ADR-0015 is equally explicit about what is not in the cluster, and that boundary is load-bearing here. A few other tolerant from_array() branches read an absent key as the ordinary not-yet-populated shape of a brand-new current-schema record as much as a legacy one: progress, progressed_at, the schema-8 additions (host_memory_limit and its three siblings), skipped_files, and attempt_log. Those stay.

Why this is possible now

ADR-0015 states the retirement condition — that no un-resumed pre-adaptation stall remains on any site still running this plugin — and then says plainly that nothing the plugin can observe establishes it, "because it ships to sites the author does not operate."

That premise no longer holds. The plugin is installed on exactly one site, operated by the author, and has been distributed to nobody else. The condition is settled by decision rather than by observation, which is the outcome ADR-0015 anticipated but could not reach.

The same bullet warns that an unimplemented recommendation sitting in a Consequences list is the shape that quietly becomes permanent. This ticket is the alternative to that.

Agent Brief

Category: enhancement
Summary: Remove the pre-adaptation back-compatibility cluster in one piece, so a failed extraction record is terminal for every purpose and no record is exempt from the TTL sweep.

Current behavior:
A record written by 0.5.1 or earlier — failed, carrying a diagnosis, and missing the budget keys this release always writes — is treated as a resumable stall. The TTL sweep spares it unconditionally, the Dispatcher may re-drive it into running, the builder reseeds a sealed index from segment names a schema-6 record carried, and record deserialisation tolerates a family of absent keys that only such a record has.

Two consequences follow, and the second is a defect. A failed job is not strictly terminal. And because the sweep's carve-out is wider than the resume it protects, a legacy record stalled where nothing can shrink — a structure-only table, or the sealed index — is spared forever and re-driven by nobody (#41).

Desired behavior:
No record is exempt from the sweep. failed is terminal for every purpose, in both directions: it frees the concurrency slot, and nothing re-enters it into running. The sweep applies its ordinary TTL and absolute-lifetime windows to every failed record alike. Deserialisation understands the current schema and no earlier one.

A record the plugin can no longer parse must degrade quietly — skipped, with the enumeration continuing — never thrown. A stray legacy file left on a live site must not be able to break the listing or the sweep for the jobs around it. This is the one behaviour that must be got right, because it is what makes the removal safe to ship to a site that may still hold such a file.

Key interfaces:

  • Sweeper::reclaimable() — becomes a question about terminality alone; a failed record is reclaimable like any other
  • Dispatcher — loses the resume path and the predicates serving it; the tick and watchdog no longer consider a failed job
  • Extraction_Job::from_array() — parses the current schema; branches that exist only to read a pre-0.6.0 write are gone, and the ones ADR-0015 excludes from the cluster remain
  • Extraction_Job::$budget_keys_present — with no record lacking the keys, judge whether the property still earns its place, and remove it if not. to_array()'s use of it to omit the keys again goes with it
  • Build_Progress — loses its legacy-name tolerance and the segment_names branch that feeds it
  • Sealed_Writer::seed_index() — removed, along with its call site and the branch selecting it

Acceptance criteria:

  • Nothing in the codebase references is_pre_adaptation_stall(), resume_failed(), seed_index(), or $legacy_names; the symbols are gone rather than merely unused
  • The sweep reclaims a failed record on the same TTL and lifetime windows as any unfinished job, with no exemption of any kind
  • A failed job is never re-entered into running by a tick, the watchdog, or any other path
  • Deserialising a record that predates the current schema does not throw; the record is skipped and enumeration of the records around it completes
  • The integration suite's assertions covering the pre-adaptation shape, the resume, and the adapt-after-stall path are removed or rewritten to the new behaviour, and the suite passes — the three files touching this are consume-cancel-ttl-test.php, resume-and-adapt-test.php and opaque-failure-test.php
  • composer gate passes
  • ADR-0015 carries a dated addendum recording that the exemption was retired by decision rather than by the observation it said it could not make, and that the ADR's own re-drive half no longer describes the code. Keep its existing text verbatim with a bolded pointer, per the convention ADR-0013 established
  • CHANGELOG.md's [Unreleased] records the change, including that a failed record is now reclaimed on the ordinary windows
  • CONTEXT.md no longer defines terms that name only the removed path

Out of scope:

  • Any migration, cleanup routine, or one-shot path that hunts down legacy records. There is none, deliberately. The sweep reclaims what it finds on its ordinary windows, which is the whole disposal story.
  • The adaptation machinery itself — budget halving, the attempt counter, the floor, the host-limit raise, the attempt log. Only the pre-adaptation legacy path retires. A stall this release diagnoses still shrinks its chunk and retries.
  • API_VERSION and SCHEMA_VERSION. Nothing here changes the sealed container's byte format or the REST contract; the record shape a current release writes is unchanged.
  • The thrown-failure work from Record what an opaque failure actually was — a failed job's error is null and the poll reports a fallback sentence #25 and ADR-0022. thrown is a current-schema field and stays.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestready-for-agentFully specified, ready for an AFK agent

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions