Files
pad/internal/store
xarmian 8fedc5487c fix: three codex round-3 findings — oracle, bulk defaults, required (TASK-2878)
Round 3 confirmed round 2's fixes and found three more. Codex still could
not execute anything, so all three were static reads I verified myself.

## `wrong_collection` DISCLOSED EXISTENCE

The store emits `wrong_collection` when a value names a LIVE item outside the
field's declared target, and the server's visibility layer skipped any key
that already carried an issue. So the message — "is not an item in
collection X" — told a caller the value EXISTS, distinguishably from the
`not_found` a nonexistent value gets. An existence oracle for anyone who
cannot see that item, and the exact shape the `not_found` collapse exists to
prevent.

Collapsed to `not_found` when the requester cannot see the target, and KEPT
otherwise: "you linked a task where a person belongs" is the useful half of
this reason, and blanket-collapsing would have passed the security leg while
destroying it. Both legs are in the test for that reason.

Needed one new store export, `ResolveRelationTarget`: deciding what to
disclose about a live item requires the item, and the resolver is the only
thing that maps a value to one under the no-slug rule.

## BULK STATUS / PRIORITY BYPASSED RELATION DEFAULTS

`bulkFieldUpdate` resolves only the keys `changes` names — correctly, since
re-litigating stored values would freeze legacy items — but `ValidateFields`
runs BEFORE it and INJECTS schema defaults. A defaulted relation was
persisted raw: never canonicalised, never checked against its collection.
The same late-arrival the migrate doors hit, reached by a different route,
and the narrow pass built for them covers it unchanged.

`dropped_fields` now rides every bulk op's activity row, not just the move
branch: a status or priority change can discard a relation default too, and
a drop nobody records is the defect BUG-2674 closed.

## A REQUIRED RELATION COULD END UP ABSENT AND REPORTED VALID

The late pass deletes a key AFTER validation passed, so nothing re-checked
required-ness: a required relation whose default did not resolve left the
item with the field absent, and the preflight reported `valid: true`.

Re-running validation is not the fix — it would re-inject the same broken
default. There is no valid value for that field, so the doors refuse:
`missing_required_fields` on move and bulk move, a FieldValidationError on
the copy, and on the preflight a `needs_value` row with `valid: false`. That
split is the one this pair has everywhere else — the preview says what is
wrong, the copy refuses.

## Counterfactuals

Remove the oracle collapse -> the visibility leg DETECTED. Remove the
bulk-update late pass -> DETECTED. Remove the required-relation refusal at
the copy door -> DETECTED. All build-checked first.

Gates: internal/server ok 352.1s · internal/store ok 358.7s · internal/items
ok · internal/mcp ok 21.0s · go vet clean · gofmt clean · make lint 0 issues.
Postgres green on the parent commit (store 596.7s, server 294.7s, private
container port 5481); re-running on this tree.
2026-09-04 17:04:52 +00:00
..