Skip to content

Commit a337d0c

Browse files
committed
docs(references): regenerate the sortability reference from the amended spec text
Claude-Session: https://claude.ai/code/session_01EUBvqtauTDmHi2ZgY759p2 Co-authored-by: Claude <noreply@anthropic.com>
1 parent d0528df commit a337d0c

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

‎content/docs/references/api/protocol.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,7 +1360,7 @@ Enable package response
13601360

13611361
| Property | Type | Required | Description |
13621362
| :--- | :--- | :--- | :--- |
1363-
| **fields** | `Record<string, { sortable: boolean; reason?: 'virtual-type'; caveat?: 'unprovisioned-anchor' }>` | ✅ | Verdict per sortable-addressable column, keyed by field name. The domain is the served field map plus the always-provisioned `id`; a name absent from this map (an unknown field, a dotted path, an unprovisioned audit column) has no platform sort behind it and must get no sort affordance. |
1363+
| **fields** | `Record<string, { sortable: boolean; reason?: 'virtual-type'; caveat?: 'unprovisioned-anchor' }>` | ✅ | Verdict per sortable-addressable column, keyed by field name. The domain is the served field map plus the always-provisioned `id`, less any field the caller's own field permission withholds: a caller exempt from the object-schema mask (ADR-0106 D4) is served such fields in `item` and gets no entry for them; for every other caller the served map already excludes them. A name absent from this map (an unknown field, a dotted path, an unprovisioned audit column, a field the caller may not read) has no platform sort behind it and must get no sort affordance. |
13641364

13651365

13661366
---

‎content/docs/references/api/sortability.mdx‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@ records as deliberately rejected).
3636
`assertSortFieldsExist` (`@objectstack/metadata-protocol`, #6994) and
3737
`assertOrderByIsMaterializable` (`@objectstack/objectql`, #7095) — actually
3838
do with an `orderBy` over the name. Three verdicts are REFUSALS, and one
39-
measured degradation is not refused; the projection covers all four:
39+
measured degradation is not refused; the projection covers all four, and
40+
one more absence that is a fact about the CALLER, not the column (5.):
4041

4142
1. **Unknown name** — not a field of the object. Refused (`400
4243
INVALID_SORT`). Encoded as ABSENCE: the projection's domain is exactly
43-
the served field map plus the always-provisioned `id`, so a name with no
44-
entry has no platform sort behind it and gets no affordance.
44+
the served field map plus the always-provisioned `id`, less any field
45+
the caller's own field permission withholds (5. — which removes nothing
46+
for every caller but a D4-exempt one), so a name with no entry has no
47+
platform sort behind it and gets no affordance.
4548
2. **Dotted path** (`account.name`) — crosses into a related record no
4649
driver joins for. Refused. Encoded as absence too: entries are keyed by
4750
whole-column field names, and a dotted name can never appear as one.
@@ -62,6 +65,15 @@ measured degradation is not refused; the projection covers all four:
6265
so the entry stays `sortable: true` — the enforcement fact — and carries
6366
`caveat: 'unprovisioned-anchor'` so a consumer can choose a conservative
6467
affordance without re-deriving federation from the document.
68+
5. **Withheld by the caller's field permission** (ADR-0106 D1/D4, #22250) —
69+
a field the caller's own field-level security marks unreadable. Refused
70+
for that caller by the data route's field guard (`403`: filtering or
71+
sorting on a hidden field would leak its values). Encoded as absence: no
72+
entry, whatever the caller's class — including a caller exempt from the
73+
object-schema mask (ADR-0106 D4: `manage_metadata`, `studio.access`,
74+
`setup.access`), who IS served the field in `item.fields` because
75+
authoring needs the whole definition. For every other caller the mask
76+
has already removed the field from `item`, so this is case 1's absence.
6577

6678
## Considered and deliberately NOT members
6779

@@ -132,7 +144,7 @@ const result = FieldSortabilitySchema.parse(data);
132144

133145
| Property | Type | Required | Description |
134146
| :--- | :--- | :--- | :--- |
135-
| **fields** | `Record<string, { sortable: boolean; reason?: 'virtual-type'; caveat?: 'unprovisioned-anchor' }>` | ✅ | Verdict per sortable-addressable column, keyed by field name. The domain is the served field map plus the always-provisioned `id`; a name absent from this map (an unknown field, a dotted path, an unprovisioned audit column) has no platform sort behind it and must get no sort affordance. |
147+
| **fields** | `Record<string, { sortable: boolean; reason?: 'virtual-type'; caveat?: 'unprovisioned-anchor' }>` | ✅ | Verdict per sortable-addressable column, keyed by field name. The domain is the served field map plus the always-provisioned `id`, less any field the caller's own field permission withholds: a caller exempt from the object-schema mask (ADR-0106 D4) is served such fields in `item` and gets no entry for them; for every other caller the served map already excludes them. A name absent from this map (an unknown field, a dotted path, an unprovisioned audit column, a field the caller may not read) has no platform sort behind it and must get no sort affordance. |
136148

137149
### Nested Shape: `ObjectSortability.fields[string]`
138150

0 commit comments

Comments
 (0)