Skip to content

Pin retirement is keyed by literal while revival authorization is keyed by site #1006

Description

@The01Geek

Problem

load_retired_wording_literal_keys in lib/test/pin-corpus-lint.py keys retirement by literal, while RevivalAuthorization is keyed by site. The two do not line up.

The retired rows are assert_pin_red_on_removal meta-assertions ("…pin is removal-proof/removal-sensitive") that issue #810 retired as redundant_retire — redundant with the assert_pin_unique pins they were written about. Those subject pins survive and are boundary in the live ledger, and 6 of the 7 distinct literals additionally carry an explicit RETAIN_BOUNDARY row in the frozen residual-prose manifest.

Because retirement collapses to a literal key, a redundant_retired twin now poisons the retained pin that shares its literal.

Evidence

Surfaced by PR #1005 (issue #1002), where 8 of 43 gate findings landed in this class. Confirmed end to end rather than by code reading: in a throwaway worktree the retained pin at lib/test/run.sh:2653 was given the full authorization — a valid # structural-pin-ok: declaration, an exact retired-pin-revivals.tsv row, and a same-branch boundary ledger change recorded in a new bundle — committed, and the gate still reported it:

MUTATION-ROUTING	lib/test/run.sh:2653	assert_pin_unique	A reception pass that pushes uses an explicit destination ref	literal resolves into prose at .prflow/prompt-extensions/receiving-code-review.md:135; the assert_pin_unique helper does not change the verdict

The message carries no remediation clause — there is no further step available. That is deliberate and tested: test_a_retired_literal_keeps_the_pre_948_revival_contract asserts precisely that a fully-authorized revival of a prose-target retired literal is still reported.

The same frozen manifest records 'prefer mutation evidence…' as RETAIN_BOUNDARY at one home and RETIRE_PROSE at another — direct evidence that the manifests record site dispositions that the retirement set collapses to literal keys.

Why this matters beyond that PR

This is latent for any branch that touches those lines, rename or not. A contributor who edits one of those assert_pin_unique sites for an ordinary reason inherits an unsatisfiable gate finding with no documented exit.

Desired behaviour

Decide whether load_retired_wording_literal_keys should key on site identity (source_file + helper + literal — which the manifests already record) rather than on the literal alone, and either implement that or record why the literal-level collapse is correct and what the exit is for a retained subject pin that shares a retired twin's literal.

Not in scope

Re-adjudicating any individual pin. This is about the keying, not about the verdicts.


Decision (2026-07-31): key retirement on SITE identity

The issue asks the maintainer to decide between site-keying and recording why the literal-level collapse is correct. Measurement settles it in favour of site-keying, so this is now decided rather than open.

The evidence

  • The two keying schemes are structurally asymmetric in the code, not merely in effect. RevivalAuthorization is a NamedTuple carrying full site identity — source_path, family, helper, literal_key, target_path, plus the structural category and rationale. load_retired_wording_literal_keys returns a bare set() of literals. The site information exists on one side and is discarded on the other.
  • The manifests already record conflicting dispositions for the same literal at different homes. An executed scan over the frozen manifests finds 2 literals carrying both RETAIN_BOUNDARY and RETIRE_PROSE. Literal-keying is therefore not a simplification of equivalent data — it is lossy, and it discards exactly the distinction the manifests were written to record.
  • The failure it produces has no exit. The reported finding carries no remediation clause, and test_a_retired_literal_keeps_the_pre_948_revival_contract asserts that a fully authorized revival — valid # structural-pin-ok: declaration, exact retired-pin-revivals.tsv row, same-branch boundary ledger change in a new bundle — is still reported. A contributor who edits one of those assert_pin_unique sites for an ordinary reason inherits an unsatisfiable gate.

An unsatisfiable gate with no documented exit is strictly worse than either alternative, and the data needed to fix it is already recorded. Hence the decision.

What must NOT change

This is a keying fix, not a loosening. Re-adjudicating any individual pin stays out of scope (as the issue already states), and the fix must not become a way to revive a genuinely retired literal:

  • A literal retired at a given site stays retired at that site. Site-keying narrows which sites a retirement covers; it must never turn a retirement into a no-op.
  • The existing authorization requirements are unchanged — a revival still needs its declaration, its ledger row, and its bundle. This changes what the gate matches, not what it demands.
  • test_a_retired_literal_keyed_...'s intent is preserved for the case it was written about: a retired literal at its own site still reports, fully authorized or not.

Acceptance Criteria

  • load_retired_wording_literal_keys (or its replacement) keys retirement on site identity — source_file + helper + literal — drawn from the same manifest fields RevivalAuthorization already carries, rather than on the literal alone.
  • A retained boundary pin that merely shares a literal with a redundant_retired twin at a different site is no longer reported, driven end-to-end (the PR PRFlow rename Tier 1: atomic directory/vendored-path/config-key/workflow-body migration + /prflow:init #1005 reproduction: the retained pin at the assert_pin_unique site with a full authorization) rather than asserted by code reading.
  • A retired literal at its own site is still reported, with a negative control proving the gate did not simply go quiet. This is the assertion that distinguishes a fix from a hole.
  • The two literals that carry both RETAIN_BOUNDARY and RETIRE_PROSE are each resolved to the disposition recorded for their site, and both are covered by a test.
  • The frozen manifests are read, not rewritten — they are byte-frozen historical records and a migration must not restate them.
  • Any test whose expectation genuinely changes is updated with its rationale recorded, not deleted; a test that still describes real intended behavior stays.
  • lib/test/run.sh reports zero failures and zero skips.

Not in scope

Re-adjudicating individual pins (unchanged from above). #1007 sits behind this and is not addressed here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions