You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Record timeline: the client's audit→activity pairing map restates the spec's new RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES #30408
Filed from the contract review of PR #30405 (card #30343), should-fix 2 (record 6655016200). ⛔ Not a claim. Triage sets the grade.
Business reason. The record page's 动态 badge (server count) and the 动态 stream (client pairing) must fold the same activity types into an audit row, or the badge and the drawn rows drift apart again, which is what #30343 fixed. Today the two lists are spelled twice.
Reader who acts.domain:ui, ui/packages/plugin-detail/src/recordTimelineStream.ts.
The client keeps its own local AUDIT_ACTION_TO_ACTIVITY_TYPE map with the same entries in recordTimelineStream.ts (pairActions), while it already imports RECORD_TIMELINE_UPDATE_ACTIVITY_TYPE from the spec.
What to do
Import the spec constant in recordTimelineStream.ts in place of the local map (no behaviour change), and add a pin that the two cannot diverge (the client pairs exactly the types the spec constant names).
Serial after PR #30405 merges. Dedupe: AUDIT_ACTION_TO_ACTIVITY_TYPE, RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES: no other card. New.
Claim: PM loop round 5 · 2026-11-05T13:16Z
Session: session_01L6bhgUR8Nu4M7tbtgES7q2
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-30408-timeline-folded-types
Worktree: objectstack-issue-30408
Domain: domain:ui
Seat: domain:ui#6
File surface: ui/packages/plugin-detail/src/recordTimelineStream.ts (the local AUDIT_ACTION_TO_ACTIVITY_TYPE map replaced by the spec's RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES from @objectstack/spec/api), one pin beside its tests that the client pairs exactly the types the spec constant names, one root .changeset/ file. ⛔ packages/** (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: default (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: the client's own copy of the pairing map in ui/packages/plugin-detail | none: today's entries match | the record page's 动态 badge and stream, which drift apart if either list changes alone; reached on PR #30405's contract review (record 6655016200)
Thread-read: 6656388796
Premise: holds on origin/maina1d0b1ee9e: the local map (create→created, update→RECORD_TIMELINE_UPDATE_ACTIVITY_TYPE, delete→deleted) restates RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES in packages/spec/src/api/record-page.zod.ts entry for entry; @objectstack/spec is workspace:^ in plugin-detail
Serial constraints cleared: PR #30405 merged; no open PR touches recordTimelineStream.ts (read over the 37 open PRs' file lists at claim time).
{
"issue": 30408,
"status": "done",
"branch": "claude/issue-30408-timeline-folded-types",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30517",
"session": "session_01L6bhgUR8Nu4M7tbtgES7q2",
"premise_still_valid": true,
"summary": "Premise held on origin/main a1d0b1ee9e: the local AUDIT_ACTION_TO_ACTIVITY_TYPE map in ui/packages/plugin-detail/src/recordTimelineStream.ts restated RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES (exported from @objectstack/spec/api via record-page.zod) entry for entry. The map is replaced by foldedActivityTypeOf(), which reads the spec constant through an own-key check (Object.prototype.hasOwnProperty.call; the source tsconfig lib is ES2020, so no Object.hasOwn), so restore, unknown actions and prototype keys never pair. No behaviour change. A new top-level describe in the existing recordTimelineStream-27055.test.tsx pins, driven from the spec constant, that each entry pairs with its activity type and no other folded type, and that six actions outside it pair with nothing. One root changeset, @object-ui/plugin-detail patch, with the claim's Clause-2 no and Metadata-protocol none lines. No packages/** change. Draft PR 30517, no assignee, no reviewer, no labels.",
"tests": "At head 0e467929a3. Stream file: pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-detail/src/__tests__/recordTimelineStream-27055.test.tsx: Test Files 1 passed (1), Tests 42 passed (42), lock VERDICT command-exit 0. Package: pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-detail/: Test Files 371 passed, 1 skipped (372), Tests 3328 passed, 18 skipped (3346), exit 0. pnpm --filter @object-ui/plugin-detail type-check (tsc --noEmit and tsc -p tsconfig.test.json): exit 0, after building the plugin-detail upstream closure with turbo (51 tasks successful). Positive control via scripts/ablation-replace.mjs (ui src is read directly by vitest, no dist leg): anchor ' return RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES[' replaced so delete returns undefined; anchor 1 to 0, marker 0 to 1, blob ca01922c2dbc to 5837636a3f05; run Tests 1 failed, 41 passed (42), the failing case being the audit delete entry pairs with the activity deleted row; restored, blob ca01922c2dbc equals HEAD blob, git diff HEAD empty. A first ablation attempt used an anchor the replacement also contained; the tool refused it before running (anchor count did not drop), so it measured nothing.",
"gates": "dispatch-gates --commands derived 35 families at 0e467929a3; all 35 ran locally with exit 0 captured before any pipe (check:* family, node self-tests, check-sdui-manifest, check-adr-0087-registration, check-changeset-no-major, check-empty-changeset, and pnpm --dir ui exec vitest run scripts/: Test Files 170 passed, 2 skipped; Tests 4985 passed, 2 skipped). dispatch-gates --ran with exit codes: 35 derived families accounted for, 35 run, 0 NOT-MEASURED (a derived zero). PR check-runs: not yet read; in_progress at report time. Repo-wide lint and the full farm belong to CI.",
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: one fleet-write relay repository_dispatch (pr_create, run 42040579684, success, read-back identical) and this os-dev-report comment via post-stamped; plus git push (not a REST write)",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none. Noted in the PR's Acceptance notes, not filed: before this PR no pin covered the delete pair (the ablation reddened only the new pin), and the own-key guard has no red-capable control of its own, since under the old lookup a prototype key resolved to a function that never equals an activity type string."
]
}
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 kept ·
domain:ui· 2026-11-05T11:04Z⛔ Not a claim.
RECORD_TIMELINE_FOLDED_ACTIVITY_TYPESinrecordTimelineStream.tsin place of the local map, and pin that the two cannot diverge. Serial after PR fix(spec,rest): the record page's timeline count counts one create or delete written to both sources once #30405.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:ui#6 · os-sales · session_01L6bhgUR8Nu4M7tbtgES7q2
Claim: PM loop round 5 · 2026-11-05T13:16Z
Session:
session_01L6bhgUR8Nu4M7tbtgES7q2Account:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30408-timeline-folded-typesWorktree:
objectstack-issue-30408Domain:
domain:uiSeat:
domain:ui#6File surface:
ui/packages/plugin-detail/src/recordTimelineStream.ts(the localAUDIT_ACTION_TO_ACTIVITY_TYPEmap replaced by the spec'sRECORD_TIMELINE_FOLDED_ACTIVITY_TYPESfrom@objectstack/spec/api), one pin beside its tests that the client pairs exactly the types the spec constant names, one root.changeset/file. ⛔packages/**(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: the client's own copy of the pairing map in
ui/packages/plugin-detail| none: today's entries match | the record page's 动态 badge and stream, which drift apart if either list changes alone; reached on PR #30405's contract review (record 6655016200)Thread-read: 6656388796
Premise: holds on
origin/maina1d0b1ee9e: the local map (create→created,update→RECORD_TIMELINE_UPDATE_ACTIVITY_TYPE,delete→deleted) restatesRECORD_TIMELINE_FOLDED_ACTIVITY_TYPESinpackages/spec/src/api/record-page.zod.tsentry for entry;@objectstack/specisworkspace:^in plugin-detailSerial constraints cleared: PR #30405 merged; no open PR touches
recordTimelineStream.ts(read over the 37 open PRs' file lists at claim time).objectstack-fleet commentedon Nov 5, 2026
domain:ui#6 · os-sales · session_01L6bhgUR8Nu4M7tbtgES7q2
os-dev-report
{ "issue": 30408, "status": "done", "branch": "claude/issue-30408-timeline-folded-types", "pr": "https://github.com/objectstack-ai/objectstack/pull/30517", "session": "session_01L6bhgUR8Nu4M7tbtgES7q2", "premise_still_valid": true, "summary": "Premise held on origin/main a1d0b1ee9e: the local AUDIT_ACTION_TO_ACTIVITY_TYPE map in ui/packages/plugin-detail/src/recordTimelineStream.ts restated RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES (exported from @objectstack/spec/api via record-page.zod) entry for entry. The map is replaced by foldedActivityTypeOf(), which reads the spec constant through an own-key check (Object.prototype.hasOwnProperty.call; the source tsconfig lib is ES2020, so no Object.hasOwn), so restore, unknown actions and prototype keys never pair. No behaviour change. A new top-level describe in the existing recordTimelineStream-27055.test.tsx pins, driven from the spec constant, that each entry pairs with its activity type and no other folded type, and that six actions outside it pair with nothing. One root changeset, @object-ui/plugin-detail patch, with the claim's Clause-2 no and Metadata-protocol none lines. No packages/** change. Draft PR 30517, no assignee, no reviewer, no labels.", "tests": "At head 0e467929a3. Stream file: pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-detail/src/__tests__/recordTimelineStream-27055.test.tsx: Test Files 1 passed (1), Tests 42 passed (42), lock VERDICT command-exit 0. Package: pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-detail/: Test Files 371 passed, 1 skipped (372), Tests 3328 passed, 18 skipped (3346), exit 0. pnpm --filter @object-ui/plugin-detail type-check (tsc --noEmit and tsc -p tsconfig.test.json): exit 0, after building the plugin-detail upstream closure with turbo (51 tasks successful). Positive control via scripts/ablation-replace.mjs (ui src is read directly by vitest, no dist leg): anchor ' return RECORD_TIMELINE_FOLDED_ACTIVITY_TYPES[' replaced so delete returns undefined; anchor 1 to 0, marker 0 to 1, blob ca01922c2dbc to 5837636a3f05; run Tests 1 failed, 41 passed (42), the failing case being the audit delete entry pairs with the activity deleted row; restored, blob ca01922c2dbc equals HEAD blob, git diff HEAD empty. A first ablation attempt used an anchor the replacement also contained; the tool refused it before running (anchor count did not drop), so it measured nothing.", "gates": "dispatch-gates --commands derived 35 families at 0e467929a3; all 35 ran locally with exit 0 captured before any pipe (check:* family, node self-tests, check-sdui-manifest, check-adr-0087-registration, check-changeset-no-major, check-empty-changeset, and pnpm --dir ui exec vitest run scripts/: Test Files 170 passed, 2 skipped; Tests 4985 passed, 2 skipped). dispatch-gates --ran with exit codes: 35 derived families accounted for, 35 run, 0 NOT-MEASURED (a derived zero). PR check-runs: not yet read; in_progress at report time. Repo-wide lint and the full farm belong to CI.", "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2: one fleet-write relay repository_dispatch (pr_create, run 42040579684, success, read-back identical) and this os-dev-report comment via post-stamped; plus git push (not a REST write)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none. Noted in the PR's Acceptance notes, not filed: before this PR no pin covered the delete pair (the ablation reddened only the new pin), and the own-key guard has no red-capable control of its own, since under the old lookup a prototype key resolved to a function that never equals an activity type string." ] }objectstack-fleet commentedon Nov 5, 2026
domain:ui#6 · os-sales · session_01L6bhgUR8Nu4M7tbtgES7q2
Landing · 2026-11-05T15:43Z · PR #30517 merged as
8a0516c3f(2026-11-05T15:36Z; seat ACCEPT 6660285615 on head0e467929)origin/mainafter the mergeRECORD_TIMELINE_FOLDED_ACTIVITY_TYPESinui/packages/plugin-detail/src/recordTimelineStream.tsrecordTimelineStream-27055.test.tsxState:
Fixes #30408closed the card;pm:dispatchedremoved in the same stroke as this comment.