Skip to content

Fix post-migration tag counts - #717

Closed
xlcrr wants to merge 53 commits into
masterfrom
bugs/2026/08/plastic-bag-count
Closed

xlcrr wants to merge 53 commits into
masterfrom
bugs/2026/08/plastic-bag-count

Conversation

@xlcrr

@xlcrr xlcrr commented Aug 14, 2026 •

Copy link
Copy Markdown
Member

Some tags were not correctly migrated during the v5 update

Introducing a fix to track problematic tags and upgrade them 1 by 1

xlcrr and others added 9 commits August 3, 2026 17:01
--advance overwrote approver/approved_at on every transition, so the
first rung past MAPPING_APPROVED erased the record of who authorised
the entry. Those two columns are now written once and every later
transition is appended to verification_evidence as
"STATUS by <who> at <when>", keeping the full history to COMPLETE.

Also records the ordering caveat in §4 B (CODE_UPDATED precedes the
apply, inverting the prose order — inert for entry 1, re-check per
entry) and adds the §4 E production-run checklist.

Entry 1 other--plastic_bag advanced MAPPING_APPROVED -> CODE_UPDATED.
DRY_RUN_VERIFIED is deliberately not taken: it is perishable and
belongs immediately before the production apply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@xlcrr xlcrr self-assigned this Aug 14, 2026
@xlcrr xlcrr added the Cleanup label Aug 14, 2026
xlcrr and others added 26 commits August 17, 2026 00:00
…grity check

Tests only — expected to fail until the implementation lands:
- quick-tag repoint drops the approved subtype
- stale-client remount loses the subtype and 422s on object+category moves
- pure category move leaves the source pivot selectable and writable
- olm:verify-tag-integrity --fix exits 0 with unrepairable defects remaining

Adds merged_into_clo_id + merged_into_type_id to category_litter_object so the
retirement record can hold the full approved mapping (object, category, type).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…check on leftovers

The retirement record held only the survivor object. An approved mapping is a
triple (object, category, type) and can differ per category, so it now lives on
the source pivot. resolveActiveClo() follows it directly instead of searching the
original category; the quick-tag repoint and the stale-client remount carry the
recorded type; a pure category move retires the source pivot and the picker
excludes retired pivots. olm:verify-tag-integrity --fix now recounts and fails if
anything unrepairable remains.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
litter_object_types.id is bigint unsigned ($table->id()); the FK column was
declared unsignedInteger, so MySQL rejected the foreign key and the migrate
step failed on CI before any test ran. Caught by CI on PR #717.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
scopeActive() type-hinted Builder without importing it, so PHP resolved the hint
to App\Models\Litter\Tags\Builder and every ->active() call threw a TypeError —
including the picker in GetTagsController. Caught by CI on PR #717 (phpunit step)
and reproduced locally.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
marine/bottle is now a declared pairing (kept on request), so the seeder creates its
pivot and the fixture guard fails. alcohol/butts is still unsanctioned and keeps the
test asserting the same legacy reclassification behaviour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… path

CategoryObject::resolveActiveMapping() walks merged_into_clo_id with a cycle guard and
carries the approved subtype forward from whichever hop introduced it. The photo-tag
remount, the quick-tag sync and the legacy {object, category} path all use it, so a
pairing retired by a pure category move is no longer refilled, a preset saved before a
type split keeps the subtype, and a two-mapping-old CLO lands on the final survivor
with the type introduced on the second hop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The web picker builds its chips from objects[].categories, not category_objects, so
the earlier filter never reached the UI.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…appings as immutable

The command no longer creates the survivor pivot: taxonomy is declared in TagsConfig
and created by the seeder, and a missing pairing aborts the run before any change. A
tombstone left by an earlier, different mapping is skipped so the chain continues
through the survivor it recorded; a tombstone from the same mapping is resumed; one
that disagrees on category or type is a conflicting retry and fails. Category-less
rows now take the type and target category like every other row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ings and on chain cycles

olm:verify-tag-integrity could exit 0 while a mapping was incomplete, because rows on a
tombstoned pairing still have a sanctioned pivot. Document the checks and the
no-invention rule for olm:migrate-tag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ecated CLO pointer

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…still has rows

A --category move could land rows on a survivor pivot that an earlier move had already
retired, and a later object retirement skipped an interrupted mapping's tombstone,
retiring the object with its rows still in place and leaving the earlier mapping
impossible to re-run. Both now abort inside the transaction before any change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pivot existence and state, type approval, mapping immutability and the interrupted-
mapping guard were checked only on the apply path, so a manifest dry run could pass and
the apply then abort. The checks now live in a read-only plan the dry run executes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…w olm:migrate-tag guards

A replayed manifest entry whose object is retired into the requested survivor, with
every source pivot tombstoned as requested and nothing left on it, exits 0 with
"Already applied" even after the survivor itself retired. A replay that names a
different category or type still falls through to the immutability refusal.

The runbook now covers the active-destination check, the interrupted-mapping guard,
dry-run validation and the replay behaviour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ate remounted preset types

olm:verify-tag-integrity --fix nulled litter_object_type_id on rows whose pairing has no
pivot, which the same run reports as needing a taxonomy decision; those rows are now left
alone. --photo-id no longer fails on the global quick-tag and chain-cycle checks. The
quick-tag sync drops a preset type the survivor pairing does not approve, as the photo-tag
remount already did. BrandsConfig and the flat en.json now name the plastic_bag survivor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…seeder step, changelog

The runbook examples, Mobile.md and API.md still described plastic_bag retiring into
plasticBags and a same-category remount; the survivor is plastic_bag and the remount follows
the recorded tombstone across categories and adds the approved subtype. The runbook now says
where the approved list must be committed, which mappings are excluded, that the seeder runs
after migrate, and that the gate stays red until every pairing is decided. Changelog rewritten
under the new rules; the v5-migration skill no longer prescribes the deleted command.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Those files are not loaded by the app, and the branch had moved their plastic-bag label onto
the key being retired. Translations are out of scope for this work.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@xlcrr

xlcrr commented Sep 13, 2026

Copy link
Copy Markdown
Member Author

Prompt hell.

@xlcrr xlcrr closed this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant