Repository navigation
fix(plugin-detail): a milestone's completed row is not hidden as a completed task (objectui#12106) - #12137
Merged
objectstack-fleet[bot] merged 4 commits intoOct 11, 2026
Conversation
A sys_activity row of type completed that an object's activityMilestones entry fired carries metadata.kind 'milestone' (plugin-audit, ADR-0052 section 5). The record activity mapper now reads that marker on a row that would land on a feed type showCompleted hides, and maps it to system, so "Case resolved" shows under showCompleted's default. A completed row without the marker maps to task and stays hidden by default, as before. Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD Co-authored-by: Claude <noreply@anthropic.com>
Pins the route-B reading: a marked completed row maps to system and shows under showCompleted's default; CONTROL pins hold the unmarked face (hidden by default) and showCompleted true (both shown); a task's own completion milestone shows on its own page; one DOM pin goes through the record:activity self-fetch. Docs: the plugin-detail page's mapping section, the showCompleted row and the produced-kinds table say what a milestone row does. The block registration's showCompleted description says the same. Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD Co-authored-by: Claude <noreply@anthropic.com>
…ng to any Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD Co-authored-by: Claude <noreply@anthropic.com>
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
|
Contributor
Author
|
CI note —
Generated by Claude Code |
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
|
This was referenced Oct 11, 2026
objectstack-fleet
Bot
deleted the
claude/issue-12106-milestone-kind-reader
branch
October 11, 2026 11:54
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 free
to 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 #12106
Clause-②: no
What changes
A
sys_activityrow of typecompletedthat an object'sactivityMilestonesentry fired ("Case resolved", "Case closed", a task's own "Task completed") is no longer read as a completed task. plugin-audit stamps such a row withmetadata.kind: 'milestone'(objectstack-ai/objectstack#22771, landed by objectstack-ai/objectstack#22783 as8bd0fcd07f).activityRowToFeedItemnow reads that marker on a row that would land on a feed typeshowCompletedhides, and maps it tosystem. A row without the marker maps exactly as before.This is route B from the card's triage ruling (comment
6105608877), under the unlock's landing condition (comment6106890335): an unmarkedcompletedrow behaves as today, hidden undershowCompleted's default.Both readers
One change covers both console reads of
sys_activity, because both hand raw, unprojected rows to this one mapper:record:activityblock's self-fetch (record-activity.tsx, itsdataSource.find('sys_activity', …));RecordDetailView, itssys_activityread), which feeds therecord:discussionblock on the synthesized default page. That reader calling the exported mapper is already pinned byRecordDetailView.activityUnmappedType-5896.test.tsx("IDENTITY — the merge builds its items with the exportedactivityRowToFeedItem").Why
system, and nottaskwith ashowCompletedexemptionMeasured against every reader of
FeedItem.typein the tree:system(this PR)taskplus an exemptionfilterMode: 'tasks_only'(RecordActivityTimeline,filterItems)types: ['task']allow-list (applyFeedConfig)showCompleted(COMPLETED_FEED_TYPES)taskis produced only by completed activitiesFEED_TYPE_ICONS,FEED_TYPE_COLORS)escalatedfalls tosystem), and what app-shell'sActivityItemsurface givescompleted(activityItemType.ts)unifiedTimeline: falseFeedItemmember in@object-ui/types, set by every host feedThe exemption route would also move a published type (
FeedItem), whichClause-②: norules out. The cost ofsystem: on a page withshowCompleted: true, a milestonecompletedrow that used to draw with the task icon now draws with the system icon.The served shape
sys_activity.metadatais atextareacolumn described as "JSON-serialized additional context". The writer stores it withsafeStringify, the redaction re-serialises it, and the writer's own test (activity-milestone-kind.integration.test.ts) reads the served row withJSON.parse(r.metadata). So the reader parses that JSON string and reads nothing else. An already-parsed object is not read as the marker: no served row carries one, and reading both would be a second dialect (AGENTS.md #0.1). A string that is not a JSON object, or akindother than'milestone'(an app may writekind: 'email'), is "no marker".Docs
content/docs/plugins/plugin-detail.mdx: a new paragraph after the mapping paragraph says what a milestone row does, and theshowCompletedinput row and the produced-kinds table say the same. The props listing'sshowCompletedcomment now reads "Include completed activities" (the spec's description) instead of "Show completed tasks". The new paragraph sits outside the anchored mapping paragraph, sodocsActivityMapTranscription-7876.test.tsstill reads exactly the map's transcription.packages/plugin-detail/src/index.tsx: the block registration'sshowCompletedinput description gains one sentence saying a milestone row shows either way. This change made that text false for milestone rows, so it is corrected here. No other open PR touches the file (read while writing this, with a control leg).packages/plugin-detail/README.mdnamesshowCompletedbut does not describe the mapping, so it is unchanged.Pins
New file
recordActivityFeed.milestoneKind-12106.test.tsx, 16 tests:showCompleted's default (record:discussion, the default page's block);completedrow with no marker is hidden by default, as today (the v17 face), onrecord:discussionandrecord:activity;showCompleted: trueshows both;system; six CONTROL shapes still map totask(nometadata, the change without akind, an app's ownkind, non-JSON, a JSON array, an already-parsed object); the marker moves noupdated,scheduledorsystemrow;types: ['task']still selects tasks only;record:activityself-fetch: "Case resolved" renders and the unmarked completion does not.Ablation, both directions (from committed
0ef756b, each restore proven)Driven by objectstack's
scripts/ablation-replace.mjsin wrap mode (the anchor must hit once, the blob must change, the restore is proven by blob equal to HEAD and an emptygit diff HEAD), inside a bash EXIT/INT/TERM trap that repeats the same proof. The test imports the module by relative path, so the run readssrcand nodist/rebuild is involved.isMilestoneActivityRow(row)replaced byfalse): 7 failed, 9 passed. The 7 are the milestone pins, as predicted. Restored: blob25b2756a8306equals HEAD,git diff HEADempty.completedrow treated as a milestone): 10 failed, 6 passed. The 10 are every CONTROL, thetypes: ['task']pin and the DOM pin. Restored the same way.Verification on final HEAD
9c5648dturbo run build --filter='@object-ui/plugin-detail^...' --concurrency=2, 11 of 11 tasks (restored from turbo's input-hashed cache).pnpm --filter @object-ui/plugin-detail type-check(echoedtype-check, rantsc --noEmit && tsc -p tsconfig.test.json): exit 0.--listFilesshows the test program compiles the new file.pnpm exec vitest run packages/plugin-detail/in 4 shards: 252 files passed and 1 skipped (253, the tracked count); 2459 tests passed, 8 skipped.column-identity.ratchet.test.ts,one-authority-per-exported-name-6273.test.ts): 8 files, 306 tests passed.pnpm exec vitest run scripts/__tests__/in 4 shards: 179 files passed, 2 skipped (181).check-changeset-presence,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations,check:control-bytes,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:phantom-deps,changeset:check,check:doc-types,check:doc-fences,docs:check-links.index.tsxhas 32 warnings, the same 32 as its BASE blob; the other two files have 0. This narrowed run is a measurement: the config has no type-aware linting and no custom rule ineslint-rules/reads another file, so this diff cannot move the verdict on an untouched file.Acceptance notes
check:doc-snippets. Reason: PRECONDITION NOT MET (exit 2), it needs a 34-package build. It compiles onlyts,tsxandtypescriptfences, and this diff's one fenced edit is inside aplaintextblock.Seat
domain:ui#2, sessionsession_01TYgwmFK1q4KJ6Qq2WRLzsD.Generated by Claude Code