Commit 3a6d92f
Fixes #21279
Clause-②: no
## What changes
`RecordActivityProps`, the `ComponentPropsMap['record:activity']` row,
gains a `guidance` table that names `items` and `loading`. It uses the
shape `RecordHistoryProps` already uses for `entries` / `loading`. Both
keys stay undeclared, so the accept set does not change. Only the
unrecognized-key refusal changes: it now names them as the host's feed
slot and gives the remedy, which is to omit them. No new vocabulary.
- `packages/spec/src/ui/component.zod.ts`: the two `guidance` entries,
plus a docblock that records the renderer read points and the
`record:chatter` `feed` mount.
- `packages/spec/src/ui/component-record-blocks.test.ts`: pins through
the row (below).
- `.changeset/21279-record-activity-host-feed-guidance.md`: an
`@objectstack/spec` `patch`, message text only.
## Premise check (base `4b20c84748`)
1. **Before.** `RecordActivityProps` was `strictObject({ surface,
history, guidanceSets }, …)` with no `guidance` map. Measured through
the row: `{ items: [ … ] }` gave one `unrecognized_keys` issue at path
`[]` with keys `["items"]`, and the message was only the generic line:
"Unrecognized key(s) on this `record:activity`: `items`. Until this
shape was closed, …". `loading` got the same, and so did `feed.items` on
`record:chatter`.
2. **The renderer reads both keys.** objectui at the `.objectui-sha` pin
`89cad75d5570`,
`packages/plugin-detail/src/renderers/record-activity.tsx`:
- `:161-166` reads `items` as an array, off the node or out of the
`properties` bag, and `loading` as `schema.loading ?? bag.loading`.
- `:265-266` the host `loading` wins over the discussion context's flag
and over the self-fetch state.
3. **Generated reference page.** `check:docs` (inside `check:generated`)
is green with nothing regenerated. The reference page does not lift
`guidance` text, so no generated file is in this diff.
## After
Through `ComponentPropsMap['record:activity']`, the same single
`unrecognized_keys` issue (keys `["items"]`) now carries:
```text
Unrecognized key(s) on this `record:activity`: `items`.
• `items` is not authorable surface. On a standalone `record:activity` it is the HOST's data channel: a host composing that block in code passes the feed it already owns, and the renderer presents it in place of its own sources; hand-authored items would ship a static snapshot of the feed that never updates. On a `record:chatter` / `record:discussion` `feed` nothing reads it. Omit it: the block presents the record page's discussion feed, and a standalone `record:activity` with no discussion context self-fetches the record's own `sys_activity` rows. Until this shape was closed, …
```
`loading`: "`loading` is not authorable surface. On a standalone
`record:activity` it is the host's fetch state for its `items` feed and
wins over the block's other loading sources, so authored `true` pins the
loading state on forever. On a `record:chatter` / `record:discussion`
`feed` nothing reads it. Omit it with `items`: each block takes its
loading state from its own source."
(Round 2, head `ab58157585`: both bullets now state who reads the key on
each mount, because the table is one flat map shared by the standalone
row and the `record:chatter` / `record:discussion` `feed`. See *Review
round 1*.)
Control: the `record:history` `entries` / `loading` messages are
byte-identical before and after. I captured both probe outputs and the
diff of the history section exits 0.
## Pins (`component-record-blocks.test.ts`, through the row)
- `items` (a feed and `[]`) and `loading` (`true` and `false`) are each
refused with exactly one issue: `code` `unrecognized_keys`, `path` `[]`,
`keys` the one key. The refusal is about the key, not a value domain.
- The `items` message carries the named first sentence, the omit remedy
and `sys_activity`. The `loading` message carries its named first
sentence and "Omit it with `items`".
- CONTROL: an unrelated unknown key on the row keeps the generic
refusal, with no host-channel line.
- The `record:chatter` and `record:discussion` `feed`, which is the same
object, still refuses both keys at path `["feed"]`, and (round 2) the
message carries the mount-true clause "On a `record:chatter` /
`record:discussion` `feed` nothing reads it." with "Omit it".
- The existing `record:history` pins are the unchanged control.
## Reverse verification (ablation)
The ablation ran from the committed fix, with `node
scripts/ablation-replace.mjs` wrapping the run. It changed the literal
anchor `guidance: {` + `items: '`items` is the HOST` to
`guidanceAblated: {` …, which disables the whole table.
- Mutation landed: anchor 1 to 0, blob `a301b1717b3a` to `a2e40a0d5943`.
- `vitest run src/ui/component-record-blocks.test.ts`: **2 failed / 30
passed**. The two named-message pins went red. The other three pins
(refusal, control, chatter `feed`) stayed green, as they should: the
ablation removes the message and leaves the accept set alone.
- Restored: blob equals HEAD (`a301b1717b3a`), `git diff HEAD` is empty,
and `git status` is clean.
- Direction observed: red, the ordinary direction.
## Verification (head `b6224772eb`)
- `pnpm --filter @objectstack/spec exec vitest run --project local
--maxWorkers=2`: **600 files, 17611 passed, 1 todo**, exit 0. Before the
merge, on `29f3682ea5`: 599 files, 17578 passed.
- `pnpm --filter @objectstack/spec typecheck`: exit 0. That covers `tsc
--noEmit`, `check:scripts-typecheck` and `check:test-typecheck`. The
edited test file is in `tsconfig.test.json`'s program
(`--listFilesOnly`: 1 hit) and has no debt-ledger entry.
- `pnpm --filter @objectstack/spec build && … check:generated`: all 15
generated artifacts up to date. Nothing was regenerated.
- `node scripts/pm/check-widening-tells.mjs --declaration no --diff`:
exit 0. `component.zod.ts` was judged against a declared surface and no
widening tell fired. The changeset and the test file are NOT MEASURED by
construction. `Clause-②: no` holds.
- Gate union from `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` (85 commands), each run on this
head with its exit code captured before any pipe. `--ran`
reconciliation: **83 exit 0, 1 NOT MEASURED, 1 unrun.**
- NOT MEASURED: `check:dual-build-cjs-loads`. It exited 3, PREREQUISITE
NOT MET: it needs a whole-workspace build, and 63 of 77 build tasks are
turbo cache misses here.
- Unrun on this head: `check:type-check-debt`. Its `--re-measure` builds
the whole workspace closure and then type-checks every package. On
`29f3682ea5` it passed its self-test and coverage leg, then hit my 300 s
per-command cap during the closure build. That run left partial `dist/`
trees in this worktree, which I removed before the rerun. It does not
fit the foreground cap on this shared box, so it is declared to CI.
- The diff adds no file and edits no `tsconfig`.
- Lint, narrowed and proven: `eslint --no-inline-config --format json`
on the two edited TS files gives **2 files, 0 errors, 0 warnings**.
- Population: both are in eslint's own population
(`ESLint.isPathIgnored` is false for both).
- Invariance: `eslint.config.mjs` never enables type-aware linting (0
`projectService`, no `parserOptions.project`; its own comment at
`:327-328` says so). So this diff cannot move the verdict on any
untouched file. Repo-wide `pnpm lint` is CI's.
## Acceptance notes
- **The `record:chatter` / `record:discussion` `feed` mount**
(superseded in round 2). Round 1 left the host-channel sentence
describing the standalone block only, and declined chatter-mount wording
as splitting one shape. The at-tier record `5954789199` (FAIL) overruled
that: the guidance table is one flat map that cannot be scoped per
mount, so the fix is wording true on both. Round 2 (`ab58157585`) states
each mount.
- **`PROPS_HISTORY`'s shared tail** ("…was not read there…") is
pre-existing-false for host-channel keys the renderer does read, on
`record:history` and here. Not owed by this PR (record `5954789199` ③);
the seat carries it.
- **`main` merged once.** Merged `fa7b565212` (merge `b6224772eb`). No
conflict, none of this diff's files, no `os-regen` deferral. After the
merge I ran a frozen install, a spec rebuild and `check:generated`, then
the full spec suite and the gate union on the merge head. `main` has
moved since, to `41a3c8df15`: a comment-only edit in `view.zod.ts` with
no overlap, so I did not merge again.
## Review round 1
- At-tier contract review **FAIL** on `b6224772eb` (`5954789199`), on
one point: the new bullets were false on the `record:chatter` /
`record:discussion` `feed` mount. Everything else (accept set unchanged,
`record:history` byte-identical, `patch` / `Clause-②: no`) was judged
right.
- Patch round 2 (`ab58157585`, +47 / -29 in the same 3 files): the
bullets are reworded for both mounts, the chatter pin asserts the
mount-true clause, and the changeset sentence is corrected. Two
ablations each turn the expected pins red, and the restore is proven
(dev report `5955605217`).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3bddd4a commit 3a6d92f
3 files changed
Lines changed: 118 additions & 0 deletions
File tree
- .changeset
- packages/spec/src/ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
280 | 280 | | |
281 | 281 | | |
282 | 282 | | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
283 | 355 | | |
284 | 356 | | |
285 | 357 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1610 | 1610 | | |
1611 | 1611 | | |
1612 | 1612 | | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
| 1645 | + | |
| 1646 | + | |
1613 | 1647 | | |
1614 | 1648 | | |
1615 | 1649 | | |
| |||
0 commit comments