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.

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

Metadata

Metadata

Assignees

No one assigned

    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 seatpm:queuepriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions