Files
pad/cmd
xarmian cd85651c47 feat(relations): render relation values for humans, and prove the store half (PLAN-2857 U6)
TTY render, per the lead's call that `pad item show` is the dogfooding
path and the data is already in the response. One renderer
(cli.RenderRelationValue), no new lookup: it formats what
`relation_targets` already carries, and falls back to the raw value for a
field that is not a relation or was not hydrated.

    resolved  ->  "COLO-3 · Red"
    id-only   ->  "<id> (unavailable)"

ONE DEVIATION FROM THE INSTRUCTION, and it is deliberate. The brief said
id-only renders "(deleted)". It renders "(unavailable)" instead, because
an id-only entry has TWO causes this layer cannot tell apart: the target
is gone, or the requester may not see it. "(deleted)" asserts
non-existence for both, which is false for half of them — and it is the
same defect codex round 12 found in the copy dialog, where the UI read
`not_found` as "does not exist" when the server also emits it for a
target the caller merely cannot see. The server works to make those two
indistinguishable; the renderer must not undo that in the last inch. A
test asserts the render contains none of deleted/removed/missing/does not
exist, so the claim cannot creep back in. Reversible in one line if the
lead wants "(deleted)" anyway.

STORE-LEVEL PROVING TESTS, the design row's, with CONVE-34 controls:

  - three spellings (uuid, ref, exact title) store an identical id — this
    is also the control that a uniformly-refusing resolver would fail;
  - a title unique WORKSPACE-wide but outside the declared collection
    refuses (R11), carries MatchedID, and an in-collection title resolves
    in the SAME run so the leg cannot pass by refusing everything;
  - two same-titled items in the target collection give `ambiguous`, not
    `not_found`, and the reason is enumerable via RelationIssueReasons();
  - the ref rung beats an item literally TITLED like a ref, pinning the
    shadowing edge the doc comment names;
  - a soft-deleted title is not a handle, with the live-again control;
  - hydration returns the triple, leaves a dangling value id-ONLY and
    PRESENT, and refuses to hydrate a foreign-workspace id.

MUTATION MATRIX — every one run, and the two inconclusive results chased
rather than counted as passes:

  M1  hydration query loses `workspace_id = ?`        KILLED
  M2  RelationTargetAmbiguous constant retyped        SURVIVED — UNFAITHFUL:
      mutating the constant moves both sides of the test's comparison.
      Redone at the call site:
  M2b ambiguous BRANCH emits not_found                KILLED
  M3  first attempt                                   sed did not match;
      the "survival" was a mutation that never applied. Re-run with a
      before/after count guard:
  M3  MatchedID dropped from the wrong_collection issue  KILLED
  M4  title rung removed from the ladder              KILLED

Gates: go test ./... 0, gofmt clean, lint 0 issues.

Claude-Session: https://claude.ai/code/session_01PRcuviXka4Un1FGrBrX8jc
2026-09-11 00:25:26 +00:00
..