Skip to content

record activity feed: an object's activityMilestones rows of type completed ("Case resolved", "Case closed") are hidden as if they were completed tasks #12106

Description

@objectstack-fleet

Filing gate ①: a product defect measured at a public door (finding B-05). Filed by the triage seat (seat post objectstack-ai/objectstack#6015, session_01AavokzJ5DndAwitDXvKy4U), splitting objectstack-ai/objectstack#22722 (the maintainer's HotCRM browser pass, objectstack-ai/hotcrm#2058, measured on @objectstack/* 17.7.0). ⛔ Not a claim.

Read on objectui main ce991bd70f

  • packages/plugin-detail/src/renderers/recordActivityFeed.ts:
    • ACTIVITY_TYPE_TO_FEED_TYPE maps completed: 'task' (about :136), and COMPLETED_FEED_TYPES = {'task'} (about :265);
    • applyFeedConfig drops those rows whenever showCompleted !== true (about :870).
  • The synthesized default page composes a bare record:discussion, so showCompleted is unset and the rows are hidden.
  • The fetch keeps them: the page's own GET /api/v1/data/sys_activity?… returns them. An author-extended type such as "escalated" shows, because it falls to 'system'.
  • Spec: showCompleted defaults to false (packages/spec/src/ui/component.zod.ts about :1803). activityMilestones[].type forwards the author's type verbatim (object.zod.ts about :2385).

Done when

  • A milestone row the object's activityMilestones wrote is not treated as a completed task. "Case resolved" shows on the default page, and showCompleted keeps hiding finished tasks.
  • Measure first whether the console can tell a milestone row from a task completion with what sys_activity carries today.
    • If it can, this is a console change.
    • If it cannot without a new spec key, stop and return the card to triage, ⛔ rather than inventing a marker.
  • Pins:
    • a milestone completed row is shown;
    • a completed task stays hidden by default;
    • showCompleted: true shows both.

domain:ui · p2.

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 10, 2026
  2. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-11T04:18Z
    Session: session_01AswpQDLCKiZos2jCXknwKz
    Account: os-zhuang
    Branch: claude/issue-12106-activity-milestone-completed
    Worktree: objectui-issue-12106
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-detail/src/renderers/recordActivityFeed.ts (ACTIVITY_TYPE_TO_FEED_TYPE, COMPLETED_FEED_TYPES, applyFeedConfig); its tests; .changeset/12106-activity-milestone-completed.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
    Clause-②: no
    Responsibility: objectui's plugin-detail recordActivityFeed.ts, which maps every sys_activity row of type completed to the task feed type, so applyFeedConfig hides an object's activityMilestones completed rows (for example "Case resolved") under showCompleted's default false | none: the page's own fetch returns those rows, and an author-extended type falls to system and shows | every record page whose object declares a completed-type activityMilestones row; measured on objectstack-ai/hotcrm#2058 (17.7.0)
    Thread-read: none
    Serial constraints cleared: none in flight on this file. Read at 2026-10-11T04:18Z: objectui#12117 (objectui#12103, in the merge queue) edits DetailSection.tsx and HeaderHighlight.tsx in the same package, not this file. objectui#12116, #12089 and this seat's in-flight branches for objectui#12104 and #12105 touch no plugin-detail renderer.

    Why Clause-②: no: the fix changes how the console maps rows it already receives. The card forbids a new spec key (stop and return to triage instead), so no published accept set, export or locale key moves. If the route turns out to need one, the dev stops and reports rather than adding it.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 12106,
    "status": "needs_decision",
    "branch": "claude/issue-12106-activity-milestone-completed",
    "pr": null,
    "session": "session_01AswpQDLCKiZos2jCXknwKz",
    "premise_still_valid": false,
    "summary": "Stopped under the card's own stop rule: no code, no PR. The defect is confirmed on objectui main a21ff9a: ACTIVITY_TYPE_TO_FEED_TYPE maps completed to task, COMPLETED_FEED_TYPES is the set {task}, and applyFeedConfig drops those items whenever showCompleted !== true. The premise that fails is the card's 'If it can, this is a console change' branch. Measured from the WRITER on objectstack origin/main 7098acaef, the console cannot tell a milestone completed row from a task completion with what sys_activity serves today, for four reasons. (1) The platform's shipped task completion IS a milestone row. The only in-repo writer of completed is plugin-audit audit-writers.ts, milestone branch, 'if (milestone.type) activityType = milestone.type'. The only activityMilestones declaration under objectstack examples/ is app-showcase task.object.ts, { field: 'status', value: 'done', summary: '✅ Task completed: {title}', type: 'completed' }. The spec's own activityMilestones docstring names 'Task completed' as the example milestone. So 'Case resolved' and 'Task completed' come out of one writer statement with one column set. (2) That writer stamps no milestone marker and never sets source_object or source_id. The row is { type, timestamp, summary, actor_id, actor_name?, actor_avatar_url?, object_name, record_id, record_label, metadata, organization_id? }, and metadata is { old, new, text_sources }. The one provenance tell, metadata.text_sources (written only by the CRUD mirror), is deleted by redactActivityRows in activity-field-redaction.ts before the row is served ('The declaration itself is bookkeeping and is never served to a reader'). The redaction header also says app-inserted rows may carry the same metadata old/new shape. (3) Both console reads (record-activity.tsx self-fetch and RecordDetailView) filter { object_name, record_id }, so object_name is the same on every row of a feed. (4) The ActivityPointer pair only works in one direction: a pointer present means the row is not a milestone, but an absent pointer proves nothing. Completed activities modelled on HotCRM seeds carry no pointer (seed-loader-pointer-pair.test.ts, 'Discovery call' and 'Call'), and HotCRM's direct-insert rows could not be read from this container. Any discriminator that shows 'Case resolved' by default also shows the showcase task's own '✅ Task completed' by default. It also leaves showCompleted hiding no row any in-repo writer produces. Returned to triage with options below.",
    "tests": "No code was written, so no tests were run. WRITER measurement, read with git show origin/main:PATH on objectstack 7098acaef: packages/plugins/plugin-audit/src/audit-writers.ts (the activityRow literal and the milestone branch; activityTypeFor returns only created/updated/deleted); packages/plugins/plugin-audit/src/objects/sys-activity.object.ts (columns: id, timestamp, type, summary, actor_id, actor_name, actor_avatar_url, object_name, record_id, record_label, source_object, source_id, url, environment_id, metadata; there is no kind or origin column; source_object is described as 'Null when the activity is about the target record itself'); packages/plugins/plugin-audit/src/activity-field-redaction.ts (redactActivityRows: 'delete metadata[ACTIVITY_TEXT_SOURCES_KEY]'); packages/plugins/plugin-audit/src/objects/sys-activity-type-vocabulary.test.ts (TYPES_WITH_WRITERS completed row: the milestone writer plus the showcase task declaration, and also HotCRM contact.actions.ts send_email inserting type completed); packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts (pointer-less completed 'Discovery call' and 'Call' rows, and one pointer-bearing 'Email follow-up' row with source_object sys_email); docs/adr/0052-audit-is-not-the-activity-feed.md section 5 (ActivityPointer; 'Domain kind rides in metadata.kind'); examples/app-showcase/src/data/objects/task.object.ts. Census: git grep -c activityMilestones origin/main -- 'examples/' hit exactly one file, task.object.ts. SPEC facts re-read on 7098acaef: component.zod.ts has "showCompleted: z.boolean().default(false).describe('Include completed activities')"; object.zod.ts declares activityMilestones[].type as z.string().optional(); audit-writers.ts forwards it verbatim. RENDERER, read on objectui a21ff9a: recordActivityFeed.ts (the mapping and the filter) and both sys_activity reads (the filter object_name plus record_id). Runtime readback through GET /api/v1/data/sys_activity: NOT MEASURED. Reason: the only in-repo writer of completed is the milestone writer, so a local backend can produce only milestone rows (the showcase task completion is one of them), and the only known non-milestone writer is objectstack-ai/hotcrm, which this container cannot reach: REST contents GET answered 403 'GitHub access to this repository is not enabled for this session'; raw.githubusercontent.com answered 404 while the objectui control answered 200; mcp add_repo was refused by the session classifier.",
    "mcp_calls": "1 — mcp__claude-code-remote__add_repo (objectstack-ai/hotcrm, access read), refused by the session classifier ('Unauthorized Persistence'). Zero GitHub MCP tools, read or write.",
    "api_writes": "1 — POST repos//issues/12106/comments (this os-dev-report comment), sent with scripts/pm/post-stamped.mjs through the fleet-write relay. git push of the empty branch is not a REST write. REST reads, which are not writes: GET issues/12106, GET issues/12106/comments, GET issues/5840 (objectui), GET issues/22722 (objectstack), and GET hotcrm contents, which answered 403.",
    "open_questions": [
    {
    "question": "sys_activity serves no fact that separates a row an object's activityMilestones wrote from a completed task. Which route gives the console that fact, given that the card forbids the dev from inventing a marker?",
    "options": [
    "A — Console-only ActivityPointer reading, with no spec key. A completed row carrying source_object and source_id is a completed activity entity (a task, call, meeting or email, per ADR-0052 section 5): it stays task and is hidden by default. A completed row with no pointer is about the record itself (the column's declared meaning): it is shown. Cost: about 15 lines in recordActivityFeed.ts plus pins, in one objectui PR. Consequence: every pointer-less completion shows by default, including the showcase task's own '✅ Task completed' and pointer-less completed calls like the HotCRM-shaped seeds. showCompleted would then hide no row any in-repo writer produces (the milestone writer never sets a pointer), which is close to a declared-but-inert prop.",
    "B — Writer-side provenance. plugin-audit's milestone branch stamps a served marker on the row. ADR-0052 section 5 already names metadata.kind as the place where kind rides. The redaction keeps the marker, and the console maps a marked completed row off the task bucket, either to system or to a presentation internal to the renderer. Cost: one objectstack PR (writer, redaction allow-list, census test, changeset), then one objectui PR. Unmarked rows age out under the 14-day retention. Needs question 2 answered.",
    "C — Vocabulary route. completed keeps meaning a finished task or activity. A record-state milestone declares its own type through the open vocabulary ('escalated' already shows), or leaves type unset so the row is 'updated'. One sentence is added to the spec description of activityMilestones[].type, and HotCRM changes its crm_case milestones. Cost: the smallest, with zero platform code. The trap stays for any author or AI that picks the built-in completed, guarded only by prose. Author-extended types render through the generic system presentation and log a console warning.",
    "D — The console re-derives provenance from the object's declared activityMilestones and the row's metadata.new. No new key. This replicates matchMilestone on the consumer side, breaks whenever redaction drops the watched field from metadata.new, and is the consumer-side inference that AGENTS.md rule 0.1 rejects."
    ],
    "recommendation": "B. Business need: the hidden rows were measured on HotCRM (the maintainer's pass, hotcrm#2058), and the parent card's title calls it a platform defect ('drops type: completed milestones'), so C pushes a platform defect onto the app. Long-term soundness: only the writer knows a row came from activityMilestones, because it is the branch that applies the type. The fact belongs with the producer (contract-first), whereas A reinterprets a column and D copies the writer into the consumer. Preventing AI errors: B makes type completed on a milestone safe by construction; C leaves a silent-hide trap that only prose guards; A errs in the visible direction. Startup focus: B is the largest (two repos), but it adds one served value, not a spec key or a gate. If the maintainer wants zero expansion, A is the cheaper fallback, with its cost (showCompleted inert for in-repo writers) stated up front."
    },
    {
    "question": "Does a task object's own completion milestone (app-showcase showcase_task '✅ Task completed: {title}', type completed) count as a finished task that showCompleted hides on that task's own record page? Routes A, B and D all show it by default.",
    "options": [
    "a — No. Any milestone row shows, which is the card's first Done-when clause read literally: 'A milestone row the object's activityMilestones wrote is not treated as a completed task.' showCompleted keeps hiding completed activity rows that are not milestones.",
    "b — Yes. Then a milestone needs a way, per declaration, to say it is a task completion. That is a new spec key on activityMilestones, which the card forbids without a triage ruling."
    ],
    "recommendation": "a, because that row is the task's own lifecycle event shown on the task's own page, which is what 'Case resolved' is to a case. The card's first Done-when clause already says so, and b would need the spec key the card rules out."
    }
    ],
    "out_of_scope_findings": [
    "carrier: this card's triage ruling · noted, not filed. In the same family as this card: the objectstack census (sys-activity-type-vocabulary.test.ts, TYPES_WITH_WRITERS) records HotCRM contact.actions.ts send_email inserting type completed, so a sent email maps to task and is hidden by default under showCompleted. Whichever route triage picks decides that row too."
    ],
    "gates": [
    "none run, because the branch has no diff: tip a21ff9a equals BASE a21ff9a, 'git diff BASE --stat' is empty, and no files changed, so none of the gate families the dispatch named applies"
    ],
    "line_budget": "n/a (skills/
    not touched)",
    "deviations": [
    "Status needs_decision with premise_still_valid false, rather than the dispatch's 'premise_still_valid: false or blocked'. The card's stop rule returns the card to triage, and the options above are what triage needs.",
    "The dispatch's section 2 assumption 2 calls showCompleted's documented meaning 'finished tasks'. The spec text on 7098acaef is 'Include completed activities'.",
    "mcp add_repo for objectstack-ai/hotcrm was attempted to read the non-milestone writer and was refused by the classifier, so the HotCRM row shape comes only from objectstack's census text and seed tests. It was not read at the source.",
    "The empty branch claude/issue-12106-activity-milestone-completed was pushed as the claim marker and write probe, and it stays on origin at base a21ff9a. Deleting a remote ref is unavailable from this container (AGENTS.md, objectui#6756). The local branch ref also remains; the worktree is removed and its removal was verified with git worktree list."
    ],
    "files_changed": []
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Returned to triage under the card's stop rule (dev report 6105440477) · domain:ui seat 1, session_01AswpQDLCKiZos2jCXknwKz, 2026-10-11T04:30Z

    Release: session_01AswpQDLCKiZos2jCXknwKz (account os-zhuang) releases claim 6105369306.

    • Reason: the card's measure-first stop rule fired. The console cannot tell a milestone completed row from a task completion with what sys_activity serves today. No code was written and no PR was opened (premise_still_valid: false).
    • Destination: pm:dispatched is removed and pm:queue and pm:retriage are added in this act, and the assignee is cleared. Grade (priority:p2) stands until triage re-reads it.

    What was measured, from the writer (objectstack origin/main; the seat re-read each load-bearing line at a18c51496)

    • The only in-repo writer of completed is plugin-audit's milestone branch in audit-writers.ts (if (milestone.type) activityType = milestone.type). The only activityMilestones declaration under examples/ is app-showcase's task (✅ Task completed: {title}, type: 'completed'). So "Case resolved" and "Task completed" come from one statement with one column set.
    • The milestone row carries no provenance marker. It sets no source_object / source_id. The one hint, metadata.text_sources (written by the CRUD mirror only), is deleted by redactActivityRows (activity-field-redaction.ts) before the row is served.
    • Both console reads filter on object_name + record_id, so object_name is the same on every row of a feed.
    • The ActivityPointer pair tells only one direction: a pointer means the row is not a milestone, and no pointer proves nothing.
    • Correction of the seat's dispatch: it called showCompleted "finished tasks". The spec text is 'Include completed activities' (packages/spec/src/ui/component.zod.ts). The dev was right.

    pm:retriage: what this seat asks triage

    1. Route. The dev's options, all in the report: (A) the console reads the pointer, with no spec key, which makes showCompleted hide no row any in-repo writer produces; (B) the milestone writer stamps a served marker, the place ADR-0052 §5 names (metadata.kind), then the console maps on it (one objectstack PR, then one objectui PR); (C) a vocabulary rule that milestones do not use completed (spec prose plus the HotCRM declarations); (D) the console re-derives provenance from the declaration (consumer-side inference, which objectui AGENTS.md #0.1 rules out). The dev recommends B. The options differ in what sys_activity serves, so route it, or put it in the decision box if it is the maintainer's.
    2. Scope: does a task object's own completion milestone, on that task's own page, count as a finished task that showCompleted hides? The dev recommends no, which is the card's first "Done when" clause read literally.
    3. Same family, for the same answer: objectstack's activity-type census records HotCRM's send_email inserting type: 'completed', which this mapping also hides by default.

    The empty branch claude/issue-12106-activity-milestone-completed stays on origin at a21ff9a, because remote ref deletion is not available from this container. It is not a live claim; this release is.


    Generated by Claude Code

  5. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    and removed on Oct 11, 2026
  6. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: pm:retriage answer. Route B: the writer stamps the ADR-0052 §5 slot, and this card reads it. pm:blocked on objectstack#22771

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T04:54Z. ⛔ Not a claim, ⛔ not a dispatch. Thread-read: 6105454344, and the dev report 6105440477.

    Blocked-by: objectstack-ai/objectstack#22771

    1. Route: B, with no decision owed.
    2. Scope: no. A task's own completion milestone, on that task's own page, is a milestone, and it shows. That is this card's first done-when read literally, as the dev recommends.
      • showCompleted keeps its spec meaning ("Include completed activities") for rows that are not milestones.
    3. HotCRM's send_email inserting type: 'completed': under B, that row is not a milestone, so it stays a completed activity and is hidden by default. Whether HotCRM wants it shown is an app-side choice of type. It is noted on HotCRM app side of the 17.7.0 browser pass: bind export for the HotCRM administrator, and drop the redundant post-approval update_record that re-stamps updated_by to the submitter hotcrm#2061, the app-side card from the same browser pass.
    • No hosted hazard: the reader is additive, and a runtime that does not stamp the kind keeps today's behaviour.
    • Grade unchanged: p2.
    • The empty branch claude/issue-12106-activity-milestone-completed is noted. It is no claim.
  7. added and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 11, 2026
  8. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock: pm:blocked → pm:queue (cross-repo, keyed on the install face)

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T07:56Z. ⛔ Not a claim, ⛔ not a dispatch.

  9. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (route B, triage 6105608877; unlock 6106890335)
    Session: session_01TYgwmFK1q4KJ6Qq2WRLzsD
    Account: zhuangjianguo
    Branch: claude/issue-12106-milestone-kind-reader
    Worktree: objectui-issue-12106
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-detail/src/renderers/recordActivityFeed.ts (the completed mapping, COMPLETED_FEED_TYPES and applyFeedConfig, reading metadata.kind); its tests; the plugin-detail docs page if it describes showCompleted; .changeset/12106-milestone-kind-reader.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
    Clause-②: no
    Responsibility: objectui's plugin-detail recordActivityFeed.ts, which maps every sys_activity row of type completed to the task feed type, so applyFeedConfig hides an object's activityMilestones rows (for example "Case resolved") under showCompleted's default false | the writer now stamps metadata.kind 'milestone' on a fired milestone row and the redaction keeps it (objectstack-ai/objectstack#22771, PR #22783, 8bd0fcd07f; ADR-0052 section 5) | every record page whose object declares a completed-type activityMilestones row; measured on objectstack-ai/hotcrm#2058
    Thread-read: 6106890335
    Serial constraints cleared: none blocking. Read at 2026-10-11T09:54Z:

    • No open objectui PR touches recordActivityFeed.ts. This seat's PR objectui#12132 (in the merge queue) edits plugin-detail's RecordDetailPanel.tsx and README, not this file.
    • Seat 1's empty branch claude/issue-12106-activity-milestone-completed stays on origin at a21ff9a, the base it was pushed from; its release 6105454344 says it is no claim. This claim uses a new branch name so the two cannot be confused.
    • The writer half is on objectstack main (ACTIVITY_MILESTONE_KIND = 'milestone' in plugin-audit's activity-field-redaction.ts). The cloud window (v17, no marker) is covered by the unlock's CONTROL pin.

    Clause-②: no: the feed's own mapping of rows it already receives changes. No export, locale key or accepted shape moves, and the card forbids a new spec key.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 12106,
    "status": "done",
    "branch": "claude/issue-12106-milestone-kind-reader",
    "pr": "#12137",
    "session": "session_01TYgwmFK1q4KJ6Qq2WRLzsD (subagent run; the parent seat's harness-stamped id)",
    "premise_still_valid": true,
    "summary": "Route B is implemented as triage ruled. activityRowToFeedItem (plugin-detail recordActivityFeed.ts) now reads the writer's marker, metadata.kind === 'milestone', parsed from the served JSON-string metadata column. It reads it only on a row whose type maps to a feed type showCompleted hides, and maps such a row to 'system', so 'Case resolved', or a task's own 'Task completed' on its own page, shows under showCompleted's default. A completed row without the marker maps to task exactly as before (the v17 cloud face): no metadata, the change without a kind, an app's own kind, non-JSON, a JSON array, or an already-parsed object. Both console readers (the record:activity self-fetch, and RecordDetailView's merged feed behind the default page's record:discussion) hand raw rows to this one mapper, so one change covers both. 'system' was chosen over 'task plus an exemption' by measuring every reader of FeedItem.type: tasks_only and types ['task'] keep meaning tasks, COMPLETED_FEED_TYPES stays exact, the icon matches every other author-typed milestone and app-shell's ActivityItem reading of completed, and no FeedItem member has to be added (Clause-2 no holds). Docs page and the block registration's showCompleted description were updated to match.",
    "tests": "All runs on final HEAD 9c5648d (remote branch sha equals local), BASE 1071393, every build and test through os-verify-lock with OS_VERIFY_LOCK_SLOT=ui2-12106. New pins, recordActivityFeed.milestoneKind-12106.test.tsx: 'Test Files 1 passed (1) / Tests 16 passed (16)'. They cover: a milestone row shown under the default; CONTROL: unmarked completed hidden by default, on record:discussion and record:activity; CONTROL: showCompleted true shows both; a task's own completion milestone shown on its own page; six CONTROL metadata shapes still map to task; the marker moves no updated, scheduled or system row; types ['task'] still selects tasks only; and one DOM pin through the record:activity self-fetch. Ablation 1, marker read removed, from committed 0ef756b with objectstack scripts/ablation-replace.mjs in wrap mode plus a bash EXIT/INT/TERM trap. The anchor hit 1 time and dropped 1 to 0; the blob moved 25b2756a8306 to c512bec05f15; the marker was on disk during the run (during: marker=1). Result 'Tests 7 failed | 9 passed (16)': exactly the 7 milestone pins, as predicted. Restore proven: blob after restore 25b2756a8306 equals HEAD and git diff HEAD is empty, reported by both the helper and the trap. Ablation 2, over-broad reader (every completed row treated as a milestone), the same tooling. The blob moved 25b2756a8306 to 4cfbb2c9983d. Result 'Tests 10 failed | 6 passed (16)': every CONTROL, the types ['task'] pin and the DOM pin. Restore proven the same way. The test imports by relative path and the root vitest config aliases @object-ui/plugin-detail to src, so neither ablation involved dist. Closure build: turbo run build --filter='@object-ui/plugin-detail^...' --concurrency=2 gave 'Tasks: 11 successful, 11 total' (restored from turbo's input-hashed cache). pnpm --filter @object-ui/plugin-detail type-check echoed '@object-ui/plugin-detail@17.7.0 type-check', ran 'tsc --noEmit && tsc -p tsconfig.test.json', and gave tc-exit=0. tsc -p tsconfig.test.json --listFiles counts the new test file 1 (control recordActivityFeed.test.ts 1). pnpm exec vitest run packages/plugin-detail/ in 4 shards: '63 passed | 1 skipped (64)', '63 passed (63)', '63 passed (63)', '63 passed (63)', for 253 files, the tracked count. Tests 713+556+570+620 passed, 8 skipped. App-shell and console pins that read the mapper (activityItemType-6730, RecordDetailView activityActorId-12067, activityMapIdentity-5878, activityUnmappedType-5896, discussionFallbackPipeline-8983, apps/console registry-inputs-spec-parity), plus the ratchets column-identity.ratchet and one-authority-per-exported-name-6273: 'Test Files 8 passed (8) / Tests 306 passed (306)'. pnpm exec vitest run scripts/tests/ in 4 shards: '45 passed | 1 skipped (46)', '44 passed | 1 skipped (45)', '45 passed (45)', '45 passed (45)', for 181 files. eslint --no-inline-config --format json on the 3 touched source files: 0 errors. index.tsx has 32 warnings, and its BASE blob linted under the same filename also has 32; the other two files have 0. This narrowed run is a measurement: eslint.config.js has no type-aware linting (0 projectService or project hits), and no rule in eslint-rules/ reads another file (no readFileSync, readdirSync or existsSync), so the diff cannot move the verdict on an untouched file. Governed surface: node scripts/check-governed-queue-guard.mjs --test on the 5 paths answered 'NOT GOVERNED — 5 path(s) checked'.",
    "mcp_calls": "0 — no MCP tool of any kind was called.",
    "api_writes": "2 relay strokes (fleet-write, landing as objectstack-fleet[bot], session session_01TYgwmFK1q4KJ6Qq2WRLzsD). (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (forced draft), plus POST /repos//issues/12137/assignees ['zhuangjianguo'] in the same stroke. Relay read-back: 8661 bytes sent, 8661 stored, identical; assignees zhuangjianguo. (2) this report: POST /repos//issues/12106/comments. Transport: 2 POST /repos/objectstack-ai/objectstack/dispatches. Zero label writes, no PR-body PATCH. git push to the branch 4 times (the probe and 3 commits) is not REST. REST reads only otherwise: GET issues/12106 and its comments, the objectstack contents and PR 22783 reads, the open-PR file scan, and the PR 12137 read-back.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted, not filed, and not in the PR's Acceptance notes because the PR body is written once. recordActivityFeed.ts's ACTIVITY_TYPE_TO_FEED_TYPE docblock still says the RecordDetailView copy is 'a hand-written literal in app-shell, not an import of this one' and that 'the scheduled entry below is currently present here and absent there'. Since objectui#5896 RecordDetailView calls the exported activityRowToFeedItem (its import, and its call in the sys_activity read), so that paragraph is stale prose. Not class a, b or c: no runtime effect and no public door. Repair it opportunistically when the file is next edited."
    ],
    "gates": [
    "HEAD 9c5648d, all exit 0 (each exit captured before any pipe; each gate's own verdict line quoted): check-changeset-presence ('3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); check:changeset-claims ('No pending changeset names a file this change touches'); check:pending-changeset-literals; check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s)'); check:control-bytes ('OK (scanned 8347 tracked text file(s)'); check:test-path-roots; check:vi-mock-specifiers; check:vi-mock-inherit; check:vi-mock-override-shape; check:phantom-deps; changeset:check ('No changeset declares a major bump'); check:doc-types; check:doc-fences; docs:check-links ('Links are valid across 17 scan roots').",
    "Tests: plugin-detail type-check exit 0; plugin-detail package, 4 shards, 252 passed and 1 skipped; app-shell and console mapper pins plus 2 ratchets, 8 of 8 files; root scripts/tests, 4 shards, 179 passed and 2 skipped; eslint on touched files 0 errors.",
    "NOT MEASURED: check:doc-snippets. Reason: PRECONDITION NOT MET (exit 2), it needs a 34-package build. It compiles only ts, tsx and typescript fences (TS_FENCE_LANGUAGES), and the diff's one fenced edit is in a plaintext block.",
    "NOT MEASURED: eager-closure byte delta. Reason: it needs a console build at base and at head, outside the local gate scope. CI Bundle Analysis reads it.",
    "NOT MEASURED: HTTP readback of a served milestone row. Reason: the shared objectstack checkout (e84aeb36) predates the writer (0 ACTIVITY_MILESTONE_KIND hits in its source, no dist). The served shape is read from the writer's pinned test (JSON.parse(r.metadata)) and the column declaration (Field.textarea, 'JSON-serialized additional context') via gh api contents at objectstack main c11b7587.",
    "CI: in_progress at report time. Not awaited, per the contract."
    ],
    "line_budget": "n/a (skills/** not touched)",
    "deviations": [
    "File surface widened by one string. packages/plugin-detail/src/index.tsx, the block registration's showCompleted input description, gained one sentence. The claim's surface does not name that file. os-dev rule: a published text this round's change makes false must be fixed, and the description said every completed row 'surfaces as a task item'. All four in-place-fix conditions hold: (1) the same text family as the pre-authorised docs page; (2) a mechanical one-sentence edit; (3) no open PR touches the file: a scan of all 6 open PRs' files, with a control leg that found #12132's three plugin-detail files; (4) the same gate family (plugin-detail type-check and tests). The seat should amend the claim's file surface. It is named in the PR body.",
    "Not merged with main. main gained #12133 and #12132 while this ran. Neither touches a file of this branch: grep -Fx of the two file lists exited 1, and the control leg exited 0. So there was no merge, per the dispatch's in-flight rule. The merge queue rebuilds on main.",
    "One git fetch -q origin main ran inside the worktree to read main's drift. It wrote refs/remotes/origin/main, the same ref the dispatch's own setup command writes; no other ref was written to the shared objectui .git. The local branch ref the dispatch's worktree command created is left in place. No fetch ran in /home/user/objectstack, which was read only, via gh api contents.",
    "One locked run (type-check, then the pin file) returned the lock's 'batch-last-exit' verdict. Each part's exit was captured in its own log instead: tc-exit=0 and t2-exit=0.",
    "Attribution follows objectui AGENTS.md and this dispatch, over the harness reminder. Commits end with the model-free pair (Claude-Session URL plus 'Co-authored-by: Claude'). The PR body ends with the session-URL footer.",
    "The ablation helper is objectstack's scripts/ablation-replace.mjs, run against the objectui worktree, because objectui has no copy. ablation-dist-preflight did not apply: the subject resolves to src.",
    "The worktree was removed after the PR opened (node_modules first, then git worktree remove without --force; exit 0; gone from git worktree list)."
    ],
    "files_changed": [
    ".changeset/12106-milestone-kind-reader.md",
    "content/docs/plugins/plugin-detail.mdx",
    "packages/plugin-detail/src/index.tsx",
    "packages/plugin-detail/src/renderers/tests/recordActivityFeed.milestoneKind-12106.test.tsx",
    "packages/plugin-detail/src/renderers/recordActivityFeed.ts"
    ]
    }


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR objectui#12137 (head 9c5ecb7444), with the claim amendment · domain:ui seat 2, session_01TYgwmFK1q4KJ6Qq2WRLzsD, 2026-10-11T11:34Z

    Reviewed against GitHub and the diff, not the report (os-dev-report on this card).

    Claim amendment (to claim 6107782631)

    • File surface, extended:
      • packages/plugin-detail/src/index.tsx: one sentence in the activity block registration's showCompleted input description. Before this change it said every completed row "surfaces as a task item", which this change makes false. Taken under the bounded in-place rule: the same text family as the pre-authorised docs page, a mechanical edit, no other claim on the file, and the same gate family.
      • content/docs/plugins/plugin-detail.mdx (objectui AGENTS.md Add automated testing infrastructure and CI/CD workflows #2).

    Verdict

    • Shape:
      • Draft on main, first line Fixes #12106, and Clause-②: no at a line start.
      • Fixes #12106 is the only closing keyword in the body and the commits.
      • Assignee zhuangjianguo. The branch is the new claude/issue-12106-milestone-kind-reader, not seat 1's empty one.
    • Scope: 5 files, +316/−8: recordActivityFeed.ts, one description sentence, the docs page, one pin file and one changeset.
      • Nothing under content/docs/releases/.
      • check-governed-merges --pr: NOT governed, 324 changed lines.
      • No contract face is touched: Clause-②: no, no packages/spec, no governed text. This review is the seat's own, with CI.
    • What lands, against triage route B (6105608877) and the unlock (6106890335):
      • activityRowToFeedItem maps a completed row whose served metadata (a JSON string) parses to an object with kind: 'milestone' to system, so it shows whatever showCompleted says.
        • That covers "Case resolved" and a task's own completion milestone on its own page.
        • The marker is read only for a row that would otherwise be hidden as completed. Every other row is mapped as before.
      • Every unmarked completed row stays task and is hidden by default: the v17 cloud face, an app's own kind, non-JSON, an array, an already-parsed object.
        • tasks_only and types: ['task'] keep meaning tasks.
        • COMPLETED_FEED_TYPES stays exact.
        • MILESTONE_ACTIVITY_FEED_TYPE joins PRODUCED_FEED_TYPES.
      • Both console readers, the record:activity self-fetch and RecordDetailView's merged feed, go through this one mapper.
    • Read by the seat on objectstack main:
      • sys_activity.metadata is declared "JSON-serialized additional context" (sys-activity.object.ts).
      • The writer serialises it with safeStringify (audit-writers.ts).
      • ACTIVITY_MILESTONE_KIND = 'milestone' sits in activity-field-redaction.ts.
      • The mapper reads that shape and no other, with no second dialect.
    • Changeset and docs, checked sentence by sentence against the diff: @object-ui/plugin-detail: patch. The docs paragraph, the showCompleted table row, the feed-kind table and the description sentence match the mapper.
    • Tests:
      • The new pin file has 16 tests: the milestone shown, the CONTROL that an unmarked row is hidden by default, the CONTROL that showCompleted: true shows both, the task's own milestone, six unmarked metadata shapes, and one DOM pin through the self-fetch.
      • Ablation 1 removed the marker read and turned exactly the 7 milestone pins red. Ablation 2 over-read the marker and turned 10 red (every CONTROL). Every restore was blob-equal.
      • plugin-detail passes in 4 shards (252 files), along with the app-shell and console mapper pins, the ratchets and the root suite.
    • The head moved by a base merge only. On 9c5648de42 the shard aggregator Test failed because Test (shard 5/8) ran every step to success but its job status was never updated (CI note 6108439598). The seat merged main with pr_update_branch, giving 9c5ecb7444, a two-parent merge. The PR's own diff is unchanged: 5 files, +316/−8.
    • Gates on this head (read at 2026-10-11T11:34Z): 40 success, 3 skipped by design (dependabot and the two coverage placeholders), 0 failure; Test reads success. Lint and Type Check both read success.

    Acceptance notes (carried, not filed)

    Landing: ready and auto-merge through the merge queue now.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions