Summary
A relation permalink is from/type/to with the type authored by the user, so a relation can be made to occupy any path — including one an observation already owns. The two rows then collide on search_index's permalink uniqueness.
This is pre-existing on main, not introduced by any branch in flight. Raised during review of #1426 and reproduced there against origin/main with no temporal qualifier, no duplicate observation, and no ordinal involved.
Reproduction
A note containing:
- [decision] redis
- observations [[decision/redis]]
produces a colliding pair.
- Postgres:
IntegrityError — Key (2, observation, 1) is not present in table "search_index"
- SQLite: both rows silently coexist under one permalink
The SQLite behavior is the more dangerous of the two, since nothing surfaces.
Why a better segment does not fix it
The obvious mitigation — reserving a path segment that relations cannot occupy — does not work. The relation type is authored, so any reserved segment can be spelled by a user and collide again. There is no naming scheme that closes it.
Direction
Put the row kind into the address or into the uniqueness scheme, so an observation and a relation cannot occupy the same key regardless of what either is named.
That is a migration on search_index's unique index, and it affects every row kind on both backends — entity, observation and relation. It wants to be scoped and tested on its own rather than carried along by a feature branch.
Note
Raised on #1426 (3918032660) and declined there on scope, with the reproduction above run on origin/main as the evidence that it is not that branch's defect.
Summary
A relation permalink is
from/type/towith the type authored by the user, so a relation can be made to occupy any path — including one an observation already owns. The two rows then collide onsearch_index's permalink uniqueness.This is pre-existing on
main, not introduced by any branch in flight. Raised during review of #1426 and reproduced there againstorigin/mainwith no temporal qualifier, no duplicate observation, and no ordinal involved.Reproduction
A note containing:
produces a colliding pair.
IntegrityError—Key (2, observation, 1) is not present in table "search_index"The SQLite behavior is the more dangerous of the two, since nothing surfaces.
Why a better segment does not fix it
The obvious mitigation — reserving a path segment that relations cannot occupy — does not work. The relation type is authored, so any reserved segment can be spelled by a user and collide again. There is no naming scheme that closes it.
Direction
Put the row kind into the address or into the uniqueness scheme, so an observation and a relation cannot occupy the same key regardless of what either is named.
That is a migration on
search_index's unique index, and it affects every row kind on both backends — entity, observation and relation. It wants to be scoped and tested on its own rather than carried along by a feature branch.Note
Raised on #1426 (
3918032660) and declined there on scope, with the reproduction above run onorigin/mainas the evidence that it is not that branch's defect.