Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-detail): pin recordActivityFeed's OPEN-vocabulary contract to sys_activity.type - #6112
Merged
yinlianghui merged 1 commit intoAug 24, 2026
Conversation
… a defined fallback `activityRowToFeedItem` returned `null` for any `sys_activity.type` outside `ACTIVITY_TYPE_TO_FEED_TYPE`, so a stored row with an author-extended type was queryable and invisible. Under the 2026-08-24 direction-4 ruling on objectstack#11507 that column is author-extensible, so such a value is legitimate data and dropping it reproduces the objectui#5840 failure by a different route. It now renders through `UNMAPPED_ACTIVITY_FEED_TYPE`, still announced once per distinct type. The pin that replaces the set-equality check objectui#5840 removed is two-directional and says so in its docblock: the map must cover every BUILT-IN type (superset), and an unknown type must reach the feed through the fallback. Set equality is not asserted in either spelling. Part of #5969 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 24, 2026 18:02
Uh oh!
There was an error while loading. Please reload this page.
yinlianghui
deleted the
claude/issue-5969-activity-feed-open-vocabulary-pin
branch
August 24, 2026 18:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#5969
Implements the maintainer ruling of 2026-08-24 on objectstack#11507, direction 4:
sys_activity.typeis author-extensible. All gates below ran on8740317bc, thefinal commit on this branch.
Item 4 answer: this IS a behaviour change, not only a pin
What I found was a drop, not a defined fallback.
activityRowToFeedItemreturnednullfor anysys_activity.typeoutsideACTIVITY_TYPE_TO_FEED_TYPE— the row wasstored, queryable and invisible, with only a console warning. Under the ruling that value
is legitimate author-extended data, so the drop reproduces the #5840 failure by a different
route. It now renders through
UNMAPPED_ACTIVITY_FEED_TYPE(the genericsystemfeedtype), still announced once per distinct type. A real
patchchangeset names it.Kept minimal:
ACTIVITY_TYPE_TO_FEED_TYPEitself is unchanged, so the copyRecordDetailViewreads is untouched. The four deliberate exclusions (commented/mentioned/login/logout→undefined) still returnnull, silently — those aredecisions, not gaps.
The two halves of the pin
Superset, in words:map ⊇ built-ins — every value the platform declares has an
entry here, a feed type or an explicit
undefined. A new built-in with no entry turns thepin red. The converse (built-ins ⊇ map) is not asserted and neither is set equality
in any spelling: under direction 4 an author-extended key legitimately lives outside the
declaration, and the pin
#5840removed is the one that made a closed declaration dropstored rows. A second test asserts the non-containment explicitly, so "restore the equality
check" has to delete a passing test to happen.
Fallback: a positive observable — the row is present, carries its own summary, actor and
timestamp, and its feed type is the declared fallback — with the counter-probe in the same
run:
createdstill rendersfield_changeandscheduledstill rendersevent, so a mappointed wholesale at the bucket cannot read as green.
The docblock names the ruling (objectstack#11507, direction 4, 2026-08-24) in both the map
and the fallback constant, so the next sweep does not "restore" set-equality.
Where the built-in set was read from, and its limit
Source: objectstack
packages/plugins/plugin-audit/src/objects/sys-activity.object.ts,the
type: Field.select([...])declaration, read at objectstack commit91b1342(objectstack#11522) on 2026-08-24. Proved to be the only declaration on the platform by
grepping every spelling of the vocabulary across
packages/andapps/— one non-test hit,that file.
@objectstack/plugin-auditis a serverplugin, and none of
@objectstack/spec/client/formula/lintcarry thedeclaration (
specpublishesFeedItemType, the map's values, never its keys). So thecensus in the test is a documented hand copy, and it had already drifted —
scheduledwasdeclared upstream on 2026-08-24 while the previous census still filed it as "undeclared but
written". Filed as objectstack#11807 (finding, unassigned): publish the built-in set where a
UI package can read it, which is what would let that literal be deleted. The fallback is
what keeps the drift costing an icon rather than a row.
Which assertions survive a revert
Measured, not asserted, by ablation B (reverting the fallback line):
warns once per unknown type— 4 tests.and stated: the superset leg pins a relation between the map and the platform that already
holds today; it is not a test of this behaviour change, and its discriminating power is
measured by ablating the map (ablation A), not by ablating the fix.
Verification
Direction predicted before each run; both predictions held. Each probe asserted anchor
uniqueness, printed its landing site, grepped injected and removed text separately, kept
a control string present in both versions (
export const ACTIVITY_TYPE_TO_FEED_TYPE), andrestored under
trap … EXIT INT TERMwith a cwd-independentgit -C … checkout --.git diff HEAD --statwas empty after each. The edit was committed before ablating. Norebuild step is involved: the tests import
../recordActivityFeedby relative source path,so nothing resolves through
dist/.assigned: 'field_change'from the mapassigned), whole-table control red (predicted side effect), fallback green — 2 failed / 39 passedundefinedpnpm --filter '@object-ui/plugin-detail^...' buildpnpm --filter @object-ui/plugin-detail type-check(tsc --noEmit && tsc -p tsconfig.test.json)FeedItemTypepnpm exec vitest run packages/plugin-detail/src(root form)pnpm exec vitest run …/recordActivityFeed.test.ts --reporter=verbose--filter '...@object-ui/plugin-detail'matches 11 packages (plugin-detail + app-shell, plugin-calendar/gantt/kanban, runner, apps/console, apps/site, 3 examples); the suffix form matches 13 (its dependencies) — the prefix list contains the consumers, which is the direction contract tightenings needpnpm --filter @object-ui/app-shell type-checkpnpm exec vitest run packages/app-shell/src/viewspnpm exec eslintover the merge-base delta, plain confignode scripts/check-changeset-presence.mjsnode scripts/check-control-bytes.mjspnpm check:spec-symbolsgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'on changed filesEnvironmental red, resolved, not a finding: app-shell
type-checkfirst exited 2 withCannot find module '@object-ui/auth' / plugin-chatbot / plugin-view / plugin-list / plugin-form— the unbuilt-closure signature (no@object-ui/plugin-detailamong them). Itwent green after
pnpm --filter '@object-ui/app-shell^...' build.Gate set derivation (standing rule from #5874): enumerated from each CI job's own step
list —
ci.ymlType Check + Test,lint.ymlLint,changeset-presence.yml,control-bytes.yml— not from top-level script names.check:spec-symbolswas picked upthat way. Skipped as not-applicable to a two-file TS diff with no new imports, deps, locale
strings or packages:
check:phantom-deps,check:self-import,check:esm-specifiers,check:i18n-keys,check:i18n-drift,check:icon-record-names,check:action-forward-parity,check:designer-field-key-parity, the coverage meta-checks.Declared narrowing: the downstream test sweep ran
packages/app-shell/src/viewsratherthan all 11 packages' suites, because grep showed app-shell is the only downstream package
referencing the changed module's exports (2 files; the other 9 match zero). CI runs the full
farm regardless.
Deviation:#6088 (
packages/plugin-detail/src/synth/) had not landed onmainat branchtime, so this branches from
b00fcba45instead of a base containing it. Different file, nooverlap.
Generated by Claude Code