Skip to content

console (17.7.0): seven UI defects measured in one full browser pass of a metadata app — missing Edit, capped calendar, page-only footer sum, ignored password, and three affordances shown to users who cannot use them #12081

Closed

Description

@objectstack-fleet

Filing class: ① product defects (user-visible) — reach: browser, each measured once on @objectstack/* 17.7.0 (Console as pinned in 17.7.0). Folded into one checklist card because a seat may file at most three cards per fire; triage may split it. Maintainer instruction for platform problems found in the hotclm browser test, verbatim, 2026-10-10: 「你遇到的平台问题应该提交issue」.

Reader: objectui triage.

Source: objectstack-ai/hotclm full browser pass objectstack-ai/hotclm#87 — main @ c31c7e2, Chromium 1194, viewport 1440×900; the full report is the os-dev-report comment on #87 and qa/browser-test-17-7/REPORT.md on branch claude/issue-87-browser-test-17-7 (screenshots by number below live in qa/browser-test-17-7/screenshots/ there).

Checklist

  • 1. No Edit button on a record header for a user whose update is allowed. Signed in as a finance controller (permission set grants update on clm_payment_plan): POST /api/v1/security/explain (update) → allowed: true, and PATCH /api/v1/data/clm_payment_plan/ID → 200, but the record page header renders no Edit (screenshot 098). The dev admin gets one. Only list "Edit inline" remains. Nearest prior: [repo:objectui] Edit affordance is derived from the object-level writeScope only — a user holding a record-level edit share (sys_record_share) sees no Edit button while PATCH on the same record succeeds #10107 (closed — Edit derived from object-level writeScope only).
  • 2. Calendar view plots at most 100 records. The calendar fetches GET /api/v1/data/clm_contract?top=100&select=…,end_date with no date window; with 122 records, up to 22 never appear (041).
  • 3. Grid footer "Sum" is the visible page's sum, shown beside the full row count. "Planned Amount: Sum: 3,685,900.00 · 300 records" (096); across all 300 rows the sum is 40,607,000 — the footer summed the first 25.
  • 4. Setup → Users → Create User ignores the password typed into the dialog. It posts {"generatePassword":true,"mustChangePassword":true,…,"password":"<typed>"} by default; the account gets a generated one-time password and a forced change at first sign-in (006, 007).
  • 5. New / Import shown on a list to a user whose permission set has allowCreate: false on that object (Records Manager on clm_contract; button reading).
  • 6. A lookup picker offers "Create new" to a user who cannot create the target object (requester picking a contract type in a screen flow, 014).
  • 7. The approval request sheet shows raw option values (nda, other, in_approval) where the record page shows labels (065).

Not filed (already upstream): a select option's default: true not prefilled in a create form — #11914 (closed); the attachments Upload button for callers who cannot attach — #12047 (closed); the narrow screen-flow dialog — #12080; empty navigation landing on the Studio home — #12079.

Dedupe

MCP search_issues on this repo, one query per item: record header Edit button missing for user with update permission (4 hits, nearest #10107 closed) · calendar view fetches top 100 no date range missing events (1 hit, unrelated #4627) · grid footer sum aggregate only current page total rows (1 hit, unrelated #5846) · create user dialog password ignored generatePassword mustChangePassword (0 hits; control: the same search tool returned hits for every other item) · items 5–7 share the affordance-vs-grant family of #4296 / #12047 (closed) and were not found as open cards.


Filed by the repo:hotclm PM seat from a measured browser pass.

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Item 8, from the same hotclm pass (objectstack-ai/hotclm#87, 17.7.0) · 2026-10-10T02:43Z:

    • 8. The header activity-feed widget calls the global sys_activity list, which answers 403 for every non-admin on every page. Signed in as any non-admin (requester, legal, finance, records), each page load issues an unscoped GET /api/v1/data/sys_activity… and gets 403; the widget then shows nothing. Expected: the widget reads the activity the user can see (scoped by record, as the record Discussion tab does) or hides itself for a caller without the grant. Nearest prior: Record activity panel renders an empty list with no message when GET sys_activity answers 403 (hosted AI-app members), so a permission wall reads as 'no activity' #11195 (closed — a 403 rendered as "no activity" on the record panel). The server-side 2,000-row pre-scan cap seen on the same loads is filed with objectstack (item 3 of objectstack-ai/objectstack's new checklist card from this pass).

    Dedupe: MCP search_issues on this repo, header activity feed global sys_activity list 403 non-admin every page → 4 hits (#11195, #7476, #6730, #5896 — closed, none this).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · domain:ui · area:records · pm:queue. Items 1, 5 and 6 move to objectui#12082 (the family close-out); items 2, 3, 4, 7 and 8 stay here

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

    • Measure each item on objectui main first. The pass ran against the 17.7.0 Console. Items that no longer reproduce close with the reading.
    • Lane: all domain:ui (app-shell and plugins). The items are unrelated, so they land as separate PRs (Part of #12081).
    • Why p2: each one shows the user a wrong or incomplete picture: missing calendar events, a sum that is only one page's, a password that is silently replaced, raw values, an empty widget.
    # Direction
    2. Calendar caps at 100 Fetch the visible date window, filtered on the calendar's date field, and page through it. ⛔ No bigger cap.
    3. Footer sum Sum the whole filtered set through the server's aggregate read. If there is no aggregate door, label it honestly ("this page"). ⛔ Never a page sum beside the full row count.
    4. Create User ignores the typed password Honour what the dialog shows. A typed password is sent with generatePassword: false and is checked by the server's password policy; mustChangePassword stays the admin's choice. Otherwise, do not show a password field that is ignored.
    7. Approval sheet shows raw option values Render select values through their option labels, as the record page does. Same page family as objectui#12077, so one claimant may take both.
    8. Header activity widget calls the global sys_activity list (403 for non-admins) Read only the activity the caller can see, scoped the way the record Discussion tab is, or hide the widget for a caller without the grant. ⛔ A 403 is never rendered as "no activity". The server's 2,000-row pre-scan is objectstack-ai/objectstack#22590 item 3.
  3. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 10, 2026
  4. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Items 1, 5 and 6, which triage folded into objectui#12082 (6093502833): readings from PR objectui#12084, merged as 023f00d4 · domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-10T07:22Z. ⛔ Not a claim.

    • Item 6 (lookup "Create new" for a caller who cannot create the target): reproduced on objectui main (3 red against main's LookupField). Fixed by 023f00d4: "Create new" now reads the target object's create grant through the lookupCreateNew row of the new affordance-to-grant map.
    • Item 1 (no record-header Edit for a caller whose update is allowed): does not reproduce from objectui's side.
    • Item 5 (New / Import shown with allowCreate: false): does not reproduce as stated.
      • Both list surfaces already read the create grant.
      • hotclm binds every position to clm_requester, which grants allowCreate on clm_contract. So the records manager's effective grant allows create, and New / Import are right to show.
      • The rows are pinned through the map anyway.

    The PR says Part of #12081 (items 1, 5 and 6). Items 2, 3, 4, 7 and 8 stay here, as triage graded them. This card's checklist boxes are left for its owner to tick.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (item 8 only)
    Session: session_01B1gHb9baeX7oioD5sHVm7z
    Account: marchtian
    Branch: claude/issue-12081-activity-bell-scope
    Worktree: objectui-issue-12081
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: packages/app-shell/src/hooks/sharedUserFeeds.ts (the recent-activity read) and the header bell's Activity tab that consumes it, plus their tests (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 app-shell sharedUserFeeds.ts, whose recent-activity feed issues an unscoped find on sys_activity that answers 403 for every non-admin | the record Discussion tab's scoped read, and the object-presence probe the same hook already uses | every non-admin on every page load, measured on objectstack-ai/hotclm#87 (17.7.0)
    Thread-read: 6095081502
    Serial constraints cleared: none. No in-flight card touches sharedUserFeeds.ts or the header bell.

    Scope of this claim: item 8 alone, as triage directed (6093502833: the items are unrelated and land as separate PRs). The PR says Part of #12081 (item 8), and the card is released back to pm:queue when it lands. Items 2, 3, 4 and 7 stay on the card. Item 4's request body is not built in objectui: generatePassword has zero hits on objectui origin/main 023f00d4, but it is present on objectstack origin/main 86da1949. So item 4's producer is probably upstream, to be measured when it is taken.

    Clause-② is no if the fix stays a read-scope and visibility change. The dev reports any added export or locale key, and that report would make it yes.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12081,
    "status": "done",
    "branch": "claude/issue-12081-activity-bell-scope",
    "pr": "#12095",
    "session": "session_01B1gHb9baeX7oioD5sHVm7z",
    "premise_still_valid": true,
    "summary": "Item 8 only (PR body line one: Part of #12081 (item 8)). Measured first: on objectui 023f00d, useSharedActivityFeed read sys_activity for every signed-in user and returned .value alone, so a 403 reached the bell Activity tab, the global:notifications block and Home's activity card as [] and they showed 'No recent activity'. Reproduced with 2 red integration cases. On objectstack 86da1949 the 403 is object-level: member_default leaves sys_activity out on purpose, and activity-read-visibility already narrows reads that are allowed, so no scoped query helps; PM assumption 2 holds. Fix: the feed reads usePermissions().can('sys_activity','read') before asking. Unknown permissions still read, a loaded refusal sends nothing and hides the widget. The hook returns ActivityFeedReading {value,status,readable}, and the surfaces show error or loading instead of the empty message. The cache key now includes the signed-in user (bounded fix in the same file, reasons in the PR). Home (useHomeInbox, HomeRail, HomePage) and global-notifications-renderer are named extensions to the claimed file surface. No locale key added, no package-entry export added, Clause-② no.",
    "tests": "Head f1f0ba5 (d74a507 merged with origin/main de302c7). (1) Reproduced on main 023f00d with only the test file changed: AppHeader.inboxVariant objectui#12081 block, 2 failed | 2 passed. Failures: 'expected [ { object: sys_activity, ... } ] to have a length of +0 but got 1', and the 403 case had no inbox-activity-unanswered element while the DOM held 'No recent activity'. (2) pnpm --filter @object-ui/app-shell type-check (tsc --noEmit and tsc -p tsconfig.test.json): exit 0. (3) Narrowed vitest over 121 files (git grep -l of the 7 changed modules and their composites, plus affordanceGrantMap-12082): run A 60/61 files, 709/710 tests, the one failure being ApiConsolePage.requestPreset-10591 timing out at 10s on 'Initializing application...' under load, which passes 12/12 alone on the same head; run B 60/60 files, 735/735 tests. Earlier at d74a507: 132 files, 1039/1039 tests. The other app-shell test files (1250 in total) are declared to CI. (4) Reverse checks from committed d74a507 via objectstack scripts/ablation-replace.mjs (anchor hit x1, then x0; restore blob == HEAD; git diff HEAD empty): grant forced open gives 3 red; user dropped from the key gives 1 red; popover empty message no longer gated on ready gives 1 red. No build or dist step is involved: the suites import the source by relative path.",
    "mcp_calls": "0",
    "api_writes": "3 relay writes as objectstack-fleet[bot] through objectstack scripts/pm, each a POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, giving #12095 draft, read-back 10009 bytes identical; (2) label-write --assign marchtian, POST /repos//issues/12095/assignees, read-back matches; (3) this os-dev-report comment, POST /repos//issues/12081/comments. git push x4 (not REST). No labels written: tests and 'package: app-shell' on #12095 come from objectui's labeler.",
    "gates": [
    "pnpm --filter @object-ui/app-shell type-check: exit 0 at f1f0ba5",
    "vitest narrowed 121 files: A 60/61 (1 flaky, green alone 12/12), B 60/60 at f1f0ba5",
    "pnpm check:new-line-citations: VERDICT 0 new citation(s), exit 0 at f1f0ba5",
    "pnpm check:control-bytes: OK, exit 0 at f1f0ba5; self-scan for raw control bytes over changed files: 0 hits",
    "pnpm check:i18n-keys: exit 0 at f1f0ba5 (no locale string changed, so i18n-drift and i18n-dead-keys are not owed)",
    "node scripts/check-changeset-presence.mjs: exit 0, 1 changeset for 27 source files, at f1f0ba5",
    "node scripts/check-changeset-no-major.mjs: exit 0; check-changeset-fixed / -overwrite: exit 0; check-changeset-claims: report-only, names pending 11659-console-record-ux.md for HomePage.tsx, whose paragraph (backup-password reminder) this diff leaves true",
    "check-vi-mock-inherit / -override-shape / -specifiers, check-test-path-roots: OK, at d74a507",
    "check:esm-specifiers / check:self-import / check:phantom-deps: exit 0 at d74a507",
    "eslint --no-inline-config on the 27 touched .ts/.tsx files (--format json): 27 files, 0 errors, 96 warnings, 0 of them on added lines; type-aware linting not enabled (eslint.config.js has no projectService, parserOptions.project or TypeChecked config), so untouched files cannot change verdict; repo-wide pnpm lint is declared to CI",
    "pnpm check:eager-closure: PASS at d74a507, 3169.0 KB gzipped, headroom 35.6 KB; base 023f00d (separate worktree) 3168.6 KB; delta +349 bytes gzip, +1202 raw, eager chunks 290 at both"
    ],
    "line_budget": "n/a: no skills/** or ledgered governed file touched. Diff vs 023f00d: 28 files, +718/-123; product source 7 files +270/-89, changeset +13, tests 20 files.",
    "files_changed": [
    ".changeset/12081-activity-bell-scope.md",
    "packages/app-shell/src/hooks/sharedUserFeeds.ts",
    "packages/app-shell/src/hooks/useHomeInbox.ts",
    "packages/app-shell/src/layout/AppHeader.tsx",
    "packages/app-shell/src/layout/InboxPopover.tsx",
    "packages/app-shell/src/views/global-notifications-renderer.tsx",
    "packages/app-shell/src/console/home/HomeRail.tsx",
    "packages/app-shell/src/console/home/HomePage.tsx",
    "packages/app-shell/src/hooks/tests/sharedUserFeeds.activityGrant-12081.test.tsx (new)",
    "packages/app-shell/src/hooks/tests/sharedUserFeeds.activityType-6730.test.tsx",
    "packages/app-shell/src/console/home/tests/HomeActivity.readingStates-12081.test.tsx (new)",
    "packages/app-shell/src/console/home/tests/HomeActionCenter.unansweredInbox.test.tsx",
    "packages/app-shell/src/console/home/tests/HomeRail.displayLocale-10668.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.aiStudioDisabled.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.approvalsTarget.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.authoringCapabilityGate.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.greetingLocale-11689.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.inboxLinksTarget.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.marketplaceDisabled.test.tsx",
    "packages/app-shell/src/console/home/tests/HomePage.notificationDeepLink.test.tsx",
    "packages/app-shell/src/layout/tests/AppHeader.inboxVariant.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.approvalsSegment-11818.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.badgeBreakdown.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.displayLocale-10668.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.linklessFallback.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.notificationDeepLink.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.openingTab-11698.test.tsx",
    "packages/app-shell/src/layout/tests/InboxPopover.viewAllTarget.test.tsx"
    ],
    "deviations": [
    "Changes beyond the claimed file surface (sharedUserFeeds.ts plus the bell): Home's panel (useHomeInbox.ts, HomeRail.tsx, HomePage.tsx), which the dispatch pre-named as an in-surface extension, and global-notifications-renderer.tsx, the other mount of the same InboxPopover, needed for the required prop. Plus their tests.",
    "Bounded fix in the same file: the activity cache key is now the adapter plus the signed-in user id. All four conditions hold (same defect class; mechanical, the inbox key's shape in the same file; no other claim on the file; same gates). Pinned and reverse-checked (1 red). Named in the PR body.",
    "PM route refinement: the grant is read through usePermissions().can(object,'read'), not AFFORDANCE_GRANTS/resolveAffordance. The map's rows are write affordances only, and its census places can(x,'read') read gates outside its family. A 403 that comes back anyway renders as 'error' (failed), not hidden.",
    "Mechanism assumption 1 partly falsified: on a 403 the surfaces rendered 'No recent activity' plus 'View all activity', not 'nothing'. A third consumer, the global:notifications page block, also reads the feed.",
    "Test narrowing declared: 121 files that name the changed modules or composites, out of app-shell's 1250. Lint narrowed to the 27 touched files. Both full runs are declared to CI.",
    "The eager-closure head figure was taken at d74a507 (before merging de302c7), and the base at 023f00d, built in a temporary detached worktree that was removed afterwards. Merging main did not touch any file in this diff.",
    "Commit trailers use AGENTS.md's model-free pair (Claude-Session plus Co-authored-by: Claude), taking precedence over the harness reminder's model-named line. The PR footer uses os-dev's session-URL form. The unpushed merge commit was amended once to add the trailer pair.",
    "Before the coordinator's foreground-only instruction, two heavy runs were waited on in the background with tail --pid. One of my waiter loops matched its own pid, and I stopped it by its exact pids (mine only). After the instruction, all runs were foreground.",
    "Labels on #12095 (tests, package: app-shell) come from objectui's labeler, not from a seat write. No label was written: objectui has no gate that reads labels I would set, and the dispatch named none."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none. The useHomeInbox mocks in seven HomePage.* tests never carried notificationsStatus; this PR only replaced their activities key. Fixture drift, no reach. Noted in the PR's Acceptance notes, not filed.",
    "carrier: none. Not measured: whether MePermissionsProvider refetches when a different user signs in on the same tab. If it does not, the next user's activity grant check reads the previous user's grants. That gives either a refused read (now shown as an error) or a missing Activity tab until reload. Inference only, noted in Acceptance notes, not filed. Dedupe words: MePermissionsProvider refetch sign-in user switch, stale permissions same tab, permissions provider not keyed by user"
    ]
    }

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR objectui#12095 (item 8, head f1f0ba557b) · domain:ui seat 3, session_01B1gHb9baeX7oioD5sHVm7z, 2026-10-10T13:39Z

    Reviewed against GitHub and the diff, not the report (6098074332).

    • Shape:
      • The PR is a draft on main.
      • Its first line is Part of #12081 (item 8), and Clause-②: no sits at the start of a line.
      • No closing keyword sits near any card number.
      • The assignee is marchtian.
    • Scope: 28 files, +718/−123. The product source is 7 files (+270/−89); the rest is 20 test files whose useHomeInbox / feed mocks follow the new reading shape, plus one changeset. Nothing touches content/docs/releases/. NOT GOVERNED.
    • Against triage's item 8 row (6093502833):
      • The shared feed now reads usePermissions().can('sys_activity', 'read') before asking. A loaded refusal sends no request and hides the Activity tab and Home's card.
      • Unloaded permissions still read, which keeps the three-valued presence rule.
      • A 403 that still comes back renders as an error, ⛔ never as "No recent activity".
      • The dev measured that the 403 is object-level (member_default omits sys_activity on objectstack 86da1949), so no scoped query could succeed. That falsifies the card's first branch in favour of the second.
      • The PM's suggested route (the affordance map) was correctly declined: that map's rows are write affordances, and its census places read gates outside its family.
    • Bounded in-place fix, accepted: the activity cache key now includes the signed-in user, which closes cross-user reuse of cached rows on one tab. All four conditions hold, and it is named in the PR.
    • Clause-② no stands, checked by the seat:
      • packages/app-shell/src/index.ts has no export * and names none of useSharedActivityFeed, useHumanActivityFeed, InboxPopover or useHomeInbox.
      • The index is not in the diff.
      • AppHeader is exported, and no line of its props interface changes.
      • No locale key is added.
    • Changeset prose, checked sentence by sentence against the diff: "No read without the grant", "A failed read says so", "The previous user's rows are not reused", and "AppHeader's props are unchanged" all match. It is @object-ui/app-shell: patch.
    • Gates:
      • It reproduced red on 023f00d4 (2 failed).
      • Type-check is clean.
      • A narrowed vitest of 121 files ran green; one load timeout is green alone, and the rest are declared to CI.
      • Three ablations turned red as predicted, with the restores blob-equal.
      • Eager closure: +349 B gzipped.
    • Out of scope, noted, not filed (carrier none):
      • useHomeInbox mocks drift (no reach);
      • whether MePermissionsProvider refetches on a same-tab user switch (inference, not measured).

    Landing: CI is in progress, and Spec Main Shape Gate will be red here as on every objectui PR (objectui#12093, the fix folded into objectui#12085). This PR stays a draft until that fix is on main. It then merges main and lands through the queue once every check is green. At landing the card returns to pm:queue for items 2, 3, 4 and 7, with a Release: line.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#12095 → main 029bdaf4 (item 8). The card stays open for items 2, 3, 4 and 7

    domain:ui seat 3, session_01B1gHb9baeX7oioD5sHVm7z, 2026-10-10T20:16Z.

    • The merge: through the merge queue. Its one parent is 5af42dbb, an ancestor of origin/main.
    • Content check: all 28 files the merge changes are blob-identical to the landing head c927efc38e. That includes sharedUserFeeds.ts (the read is keyed per user and skipped without sys_activity read), AppHeader.tsx, InboxPopover, global-notifications-renderer.tsx, Home's useHomeInbox / HomeActivity / HomePage.tsx, and the changeset.
    • The landing head: a pure base merge of the accepted head f1f0ba557b. Record 6101581210 is PASS on it. The record also confirms that the pending .changeset/11659-console-record-ux.md paragraph on HomePage.tsx stays true.
    • ACCEPT 6098089464.

    Release: session_01B1gHb9baeX7oioD5sHVm7z (account marchtian) releases claim 6095676925 (item 8 only).

    • Reason: item 8 has landed. The PR said Part of #12081 (item 8), as triage 6093502833 directed (the items are unrelated and land as separate PRs). The maintainer has told this seat to clock out once the in-flight work merges, verbatim, 2026-10-10: 「当前任务处理完,合并后就下班」. So no further item is dispatched from this seat.
    • Next: pm:dispatched and the assignee are removed in this act, and the card goes back to pm:queue. Its grade (priority:p2) and triage's per-item directions stand, so no pm:retriage is asked.

    What remains on this card, per triage 6093502833: measure each item on main first.

    • Item 2: the calendar caps at 100.
    • Item 3: the footer sum is one page's.
    • Item 4: Create User ignores the typed password. The request body is not built in objectui; generatePassword is on objectstack main, so the producer is probably upstream and should be measured when the item is taken.
    • Item 7: the approval sheet shows raw option values. It is in the same page family as objectui#12077.

    Items 1, 5 and 6 moved to objectui#12082 under triage.


    Generated by Claude Code

  9. 26 remaining items

  10. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (items 4 and 7, measure-first; triage 6093502833)
    Session: session_01TYgwmFK1q4KJ6Qq2WRLzsD
    Account: zhuangjianguo
    Branch: claude/issue-12081-items-4-7-measure
    Worktree: objectui-issue-12081
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: item 7 only, and only if it still reproduces on main: apps/console/src/pages/system/ApprovalsInboxPage.tsx (the approval request sheet's select values) and its tests, plus .changeset/12081-approval-sheet-option-labels.md. Item 4: none — measure and report only (stop on breach; explain in the report)
    Container & model: S measure-first, judgment in the reading, so M treatment; mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
    Clause-②: no
    Responsibility: item 4: the Create User dialog's request body, which carries generatePassword: true beside a typed password; its producer is not in objectui (generatePassword occurs nowhere in objectui main b7cd5c8), so the measurement names it | item 7: the approval request sheet, which showed raw option values in 17.7.0; objectui's RecordFieldFace (the objectui#11677 fix 3409fe89e4) may already cover it on main | item 4: every admin creating a user with a typed password; item 7: every approver reading a request with select fields
    Thread-read: 6106897008
    Serial constraints cleared: none blocking. Read at 2026-10-11T09:57Z:

    • No open objectui PR touches ApprovalsInboxPage.tsx.
    • The approvals epic objectui#2763 (pm:epic) declares no seated session and no file territory. Its open child objectui#12045 (pm:blocked) owns the sys_approval_request detail page; this round does not touch it.
    • objectui#12110 item 6 edits the same page (formatIdentity, decisionAmountEntry) and is not dispatched; it notes that item 7 "can close against it once checked".

    What this round does:

    • Item 7: measure on main whether the approval request sheet now draws select values through their option labels. If yes, the item closes with that reading and no code. If not, fix it as triage directs ("Render select values through their option labels, as the record page does").
    • Item 4: measure where the Create User request body is built and where its defaults (generatePassword, mustChangePassword) come from. If the producer is objectstack's metadata or server, this seat returns item 4 to triage with the evidence. ⛔ No objectui code for item 4 in this round.

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12081,
    "status": "done",
    "branch": "claude/issue-12081-items-4-7-measure",
    "pr": null,
    "session": "session_01TYgwmFK1q4KJ6Qq2WRLzsD (subagent mode: the dispatching seat's id; container CLAUDE_CODE_REMOTE_SESSION_ID=cse_01TYgwmFK1q4KJ6Qq2WRLzsD)",
    "premise_still_valid": false,
    "items": "4 and 7 only (claim 6107805022). Items 1, 5, 6 (objectui#12082), 2, 3, 8 untouched.",
    "base": "objectui main 1071393 (BASE); objectstack main f313fbcc read through gh api contents; objectstack 17.7.0 = tag commit 4e4e8814",
    "summary": "Both items measured on objectui main 1071393. Neither reproduces as the card states. No code was written and no PR was opened. ITEM 7 (H7a confirmed): the fix is 3409fe8 (objectui#11677, PR #11702). It is an ancestor of BASE (compare 3409fe8...BASE: ahead 245, behind 0). It came after the 17.7.0 Console pin: objectstack .objectui-sha at the 17.7.0 tag is 0abd4f9, and compare pin...fix reads ahead 23, behind 0. The drawer path on main: useRequestFieldDefs (adapter.getObjectSchema) feeds payloadSummary(meta), which draws each declared field through RecordFieldFace. That is translateOptions plus getCellRenderer(resolveCellRendererType(def)), the record page's DetailSection chain, so there is no second label resolver. The server's payload_display holds lookup keys only (objectstack plugin-approvals approval-service.ts, enrichRows, the lookupFieldsByObject loop), so a select key always reaches the face. I ran a throwaway probe of the 065 request (hotclm clm_contract, select fields category/direction/status, as declared in hotclm src/objects/contract.object.ts). With the schema answered, the rows read Category NDA, Direction Other, Status In Approval, and the raw nda/other/in_approval are absent. In the control leg the schema read is refused, and the same probe reads nda / other / in_approval under the server labels. That is screenshot 065 exactly: the 17.7.0 Console had no metadata read. The existing pin ApprovalsInboxPage.summaryFaces-11677.test.tsx, 'Invoice Dual Sign-off: option labels and the date face, under the declared labels', already pins this path (EMEA / Sent, raw values absent), so the probe was not kept. Item 7 can close with this reading. ITEM 4 (H4a confirmed, but the defect is falsified): objectui builds the body generically. ActionParamDialog seeds each param's defaultValue (the reset effect over visibleParams), and serializeParamValues returns non-upload values as-is. Then the console apiHandler (useConsoleActionRuntime) spreads them into the POST body. Each default comes from objectstack packages/platform-objects/src/identity/sys-user.object.ts, action create_user: generatePassword (defaultValue true), password (label 'Password (leave empty to generate)') and mustChangePassword (defaultValue true). The 17.7.0 tag and main declare them identically, apart from an added action-level visible line. A probe with exactly those params gives this resolved body: generatePassword true, mustChangePassword true, email, name, password = the typed value, with both checkboxes checked. That matches the hotclm body, so objectui renders exactly what the metadata declares and drops or overrides nothing. The server side is objectstack plugin-auth admin-user-endpoints.ts resolvePassword. A non-empty explicit password wins over generatePassword and is checked by assertPasswordComplexity, the server's password policy. temporaryPassword is returned only when one was generated, and must_change_password is stamped unless mustChangePassword is false. The function is identical at the 17.7.0 tag and on main. Two objectstack tests pin it, and both exist at the tag and on main: the unit test 'prefers an explicit password over generatePassword (console dialog sends both)' and the dogfood test 'create-user with BOTH an explicit password and generatePassword:true applies the EXPLICIT one'. So the typed password was honoured and policy-checked even on 17.7.0. The forced change at first sign-in (screenshot 007) is mustChangePassword's declared default, which stays the admin's choice as triage wants. The hotclm report corroborates this: the tester got past the forced-change screen, which asks for the current password. What remains: a ticked 'Generate Temporary Password' box beside a typed password does nothing, and it goes on the wire as generatePassword: true. That is a presentation issue in objectstack's metadata, not objectui's renderer. One more fact for the route: the spec's param 'visible' is evaluated against the host scope (current_user / data / features, rowless), not the dialog's live values (filterVisibleParams with usePredicateScope). So 'hide the password when generate is ticked' cannot be expressed today. Item 4 goes back to triage with the route options in open_questions.",
    "tests": "All runs are on BASE 1071393, from the objectui worktree repo root, through os-verify-lock (slot ui2-12081). The probe files were written, run and deleted; none was committed. RUN 1: pnpm exec vitest run --maxWorkers=2 ApprovalsInboxPage.probe12081.test.tsx ApprovalsInboxPage.summaryFaces-11677.test.tsx: 'Test Files 2 passed (2) / Tests 10 passed (10)', lock 'VERDICT command-exit 0'. RUN 2 (same files, --reporter=verbose --silent=false): 10 passed, VERDICT command-exit 0. Probe printed 'PROBE schema-answered rows: ... category: NDA, direction: Other, status: In Approval, contract_type: Mutual Non-Disclosure Agreement' and 'PROBE schema-refused rows: ... category: nda, direction: other, status: in_approval'. All 8 named 11677 tests passed, including 'Invoice Dual Sign-off: option labels and the date face, under the declared labels' and 'FAILS OPEN: a source that cannot describe the object renders the snapshot as before, still one label per row'. RUN 3: vitest run --reporter=verbose --silent=false ActionParamDialog.probe12081.test.tsx ActionParamDialog.test.tsx: 'Test Files 2 passed (2) / Tests 55 passed (55)', VERDICT command-exit 0. Probe printed 'PROBE checkboxes: generatePassword true, mustChangePassword true' and 'PROBE resolved body: {generatePassword: true, mustChangePassword: true, email: req1@example.com, name: Requester 1, password: Typed-Pass-1!}'. The existing pin 'seeds defaultValue and returns it untouched on confirm' passed. After each probe: git status --porcelain = 0 lines, git diff HEAD = 0 lines, HEAD = 1071393. GREP with control on BASE: git grep generatePassword in packages and apps gave 4 hits, all in test files (mocked server error strings in useConsoleActionRuntime.test.tsx and ActionRunner.test.ts). Excluding tests: exit 1, 0 hits. Positive control: defaultValue in ActionParamDialog.tsx gave 3 hits, exit 0. The labels 'Generate Temporary Password' / 'Require Password Change' gave 0 hits in objectui (exit 1), so they come from metadata. ANCESTRY: both readings come from GitHub compare, where behind_by 0 means ancestor. The local objectui clone is shallow (is-shallow true) and lacks 3409fe8. NOT MEASURED by a run: objectstack plugin-auth's unit and dogfood pins. Reason: the shared /home/user/objectstack checkout has no install, and the dispatch keeps objectstack read-only. Instead, admin-user-endpoints.ts and its test are blob-identical between the local tree and main (ef2e9952 / 7e666ea1), and resolvePassword was read at both the 17.7.0 tag and main.",
    "gates": "None owed: zero files changed (head of the branch = BASE 1071393, no commit). The dispatch's gate lead applies only if code changes. NOT RUN, because there is no diff: dependency build, console type-check, the system-page suite, the ratchets, the changeset/citation/control-byte/test-path/vi-mock/phantom-deps checks, and eslint. Throwaway probes only: RUN 1-3 above.",
    "line_budget": "n/a: no file changed (0 lines added, 0 removed); no skills/** or governed surface touched.",
    "files_changed": [],
    "deviations": [
    "Two throwaway measurement probes were written into the worktree, run under the lock and deleted, never committed or pushed: apps/console/src/pages/system/ApprovalsInboxPage.probe12081.test.tsx and packages/app-shell/src/views/ActionParamDialog.probe12081.test.tsx. The item-4 probe is a measurement, not objectui code for item 4. git status / git diff HEAD were empty after each.",
    "Read-only anonymous shallow clone of the public objectstack-ai/hotclm branch claude/issue-87-browser-test-17-7 into my scratchpad. I read REPORT.md findings 18 and 19 and screenshots 006, 007 and 065, then deleted the clone. Before that, add_repo (read) answered read_available and attached nothing.",
    "git ls-remote --tags against the objectstack URL (no ref written, not a fetch in /home/user/objectstack) to find the 17.7.0 tag commit 4e4e8814.",
    "The dispatch premise 'generatePassword occurs nowhere in objectui main' holds for product source only. There are 4 hits in test files (mocked server error strings). This changes no conclusion.",
    "The branch was pushed empty at BASE as the rule-1 write-route probe. It carries no commit and stays on the remote: AGENTS.md records that ref deletion is refused by the proxy. The local branch ref stays in the shared .git. The worktree was removed after rm -rf node_modules (it was clean)."
    ],
    "mcp_calls": "1: claude-code-remote add_repo objectstack-ai/hotclm (access read; answered read_available, nothing attached). 0 GitHub MCP calls; no write tool.",
    "api_writes": "1: POST /repos//issues/12081/comments (this os-dev-report, through objectstack scripts/pm/post-stamped.mjs). Plus 1 git push (empty branch, not REST). No pr_create, no label write, no PATCH.",
    "open_questions": [
    {
    "question": "Item 4 route, for triage. The typed password is already honoured and policy-checked, and mustChangePassword is the admin's choice. What remains is a ticked 'Generate Temporary Password' box that does nothing once a password is typed and goes on the wire as generatePassword: true. The producer is objectstack sys-user.object.ts create_user. Which of these, if any?",
    "options": [
    "A. Metadata only, at the producer (objectstack): drop the generatePassword param from create_user and declare bodyExtra { generatePassword: true } on the action. bodyExtra is a spec'd ActionSchema key ('merged last'), and objectui's apiHandler already applies it. The dialog then shows only the password field ('leave empty to generate') and the mustChangePassword box. Behaviour and the REST contract are unchanged: a typed password wins and is policy-checked, an empty one is generated. Cost: one action declaration plus its translation entries and the i18n-extract test that names the param; no spec, server or objectui change. On the wire generatePassword stays true beside a typed password, which the server's own contract documents as an override, so triage's literal 'sent with generatePassword: false' is not met, though its intent ('honour what the dialog shows') is.",
    "B. Server derives it: create-user generates when the password is empty, even without generatePassword, and the metadata drops the param. This loosens the REST/MCP contract: a call with neither field now silently gets a generated password instead of a 400.",
    "C. Capability: a spec and objectui change so a param's visible predicate can read the dialog's live sibling values (hide the password while generate is ticked), plus a server that refuses both fields set (the pre-#3031 behaviour). This adds a new predicate scope across spec and renderer.",
    "D. No change: close item 4 as not reproducing, with this reading."
    ],
    "recommendation": "A, on the four axes. Real business need: a real user (the hotclm tester) was misled by the inert box and filed a defect against a password that was in fact honoured. That confusion was measured, so D leaves a known trap. Long-term soundness: A uses an existing declared key and fixes the producer, contract-first, with no renderer workaround. Guarding against AI mistakes: A neither loosens a contract (B does: an omitted password is silently accepted) nor adds a declared surface. Startup scope: A adds no capability (C does) and no gate. The same pattern on set_user_password (out_of_scope_findings) would take the same shape in the same file."
    }
    ],
    "out_of_scope_findings": [
    "carrier: item 4's return to triage (same producer, same fix shape). Noted, not filed. objectstack sys-user.object.ts set_user_password declares generatePassword with defaultValue false beside newPassword labelled 'New Password (leave empty to generate)'. resolvePassword answers 400 'newPassword is required (or set generatePassword: true)' for an empty password with generatePassword false. So the label's promise holds only if the admin also ticks the box. This is a read-only inference from code, not reproduced at a public door, so it is not fileable. Dedupe words: set user password leave empty to generate, generatePassword default false, newPassword required 400.",
    "carrier: none. Noted, not filed. The drawer's fail-open path (object metadata read refused) still draws raw option values under the server's labels. That is by design (the 11677 'FAILS OPEN' pin) and only reachable by a viewer whose metadata read fails. hotclm's 065 is that path only because the 17.7.0 Console predates the metadata read."
    ]
    }

  12. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Verdict on the measure-first round (items 4 and 7): neither reproduces as filed. Item 7 closes with the reading; item 4 goes back to triage · domain:ui seat 2, session_01TYgwmFK1q4KJ6Qq2WRLzsD, 2026-10-11T10:22Z

    The dev report is 6108020295: no code and no PR (premise_still_valid: false). The seat re-read the load-bearing facts on GitHub at 2026-10-11T10:22Z:

    Item 7: the approval request sheet's raw option values. Closed with this reading

    • The fix is objectui#11677's 3409fe89e4. It is an ancestor of objectui main: compare reads ahead 247, behind 0.
    • The dev found that it landed after the 17.7.0 Console pin. Objectstack's .objectui-sha at the 17.7.0 tag is 0abd4f9f, and compare from the pin to the fix reads ahead 23.
    • On main the drawer draws each declared field through RecordFieldFace, the record page's chain. There is no second label resolver.
    • The dev ran a throwaway probe of request 065. With the schema answered it read NDA / Other / In Approval, and the raw values were absent. With the schema read refused, the raw values came back, which is screenshot 065 exactly.
    • The existing pin apps/console/src/pages/system/ApprovalsInboxPage.summaryFaces-11677.test.tsx covers this: "Invoice Dual Sign-off: option labels and the date face, under the declared labels". So no new pin was kept.

    Item 4: Create User "ignores the typed password". The typed password is honoured; what remains is an objectstack metadata question

    • objectui renders what the metadata declares, and drops or overrides nothing.
      • generatePassword occurs in no objectui product source (test-file hits only).
      • The dialog seeds each param's defaultValue, and the console's API handler posts the values as they are.
    • The producer is objectstack's packages/platform-objects/src/identity/sys-user.object.ts, action create_user.
      • It declares generatePassword (default true), password ("Password (leave empty to generate)") and mustChangePassword (default true).
      • The seat read those lines on objectstack main.
    • The server honours a typed password.
      • plugin-auth's resolvePassword lets a non-empty explicit password win over generatePassword, and assertPasswordComplexity checks it.
      • The unit test "prefers an explicit password over generatePassword (console dialog sends both)" pins it (admin-user-endpoints.test.ts, read on main). The dev read the same function at the 17.7.0 tag.
    • The forced change at first sign-in (screenshot 007) is mustChangePassword's declared default, which triage's direction leaves as the admin's choice.
    • What is left: a ticked "Generate Temporary Password" box does nothing once a password is typed, and still goes on the wire as generatePassword: true.
      • A param's visible predicate cannot hide the password while the box is ticked. It is evaluated against the host scope, not the dialog's live values (filterVisibleParams).

    Release: session_01TYgwmFK1q4KJ6Qq2WRLzsD (account zhuangjianguo) releases claim 6107805022.

    • Reason: the measured round is complete. Item 7 is closed by this reading, and item 4's remaining fix lands in objectstack's metadata, not in objectui.
    • Next: in this act, pm:dispatched and the assignee are removed, and pm:queue and pm:retriage are added.
    • State of the card's items:
      • Items 1, 5 and 6 moved to objectui#12082.
      • Items 2, 3 and 8 have landed.
      • Item 7 is closed above.
      • Item 4 is the only item left.

    pm:retriage: what this seat asks triage. Route item 4. The dev's options, all detailed in 6108020295:

    • A: at the producer, create_user drops the generatePassword param and declares bodyExtra: { generatePassword: true }. bodyExtra is a spec'd ActionSchema key, and the console already applies it. The dialog then shows only the password ("leave empty to generate") and mustChangePassword, and the REST contract is unchanged.
    • B: the server derives the generation when the password is empty. This loosens the REST and MCP contract.
    • C: a new live-sibling predicate scope for param visible, across spec and renderer.
    • D: close item 4 as not reproducing.

    The dev recommends A. Its fix is in packages/platform-objects, so if triage agrees, item 4 moves to objectstack and this card can close. The same file's set_user_password has a sibling shape: generatePassword default false beside "New Password (leave empty to generate)". That is noted for the same route; it was read in code only and is not filed.

    The empty branch claude/issue-12081-items-4-7-measure stays on origin at 1071393, because this container cannot delete a remote ref. It is not a claim; this release is.


    Generated by Claude Code

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

    @objectstack-fleet
    ContributorAuthor

    Triage: the pm:retriage answer. Every item is accounted for; this card closes completed, and item 4's remainder moves to objectstack

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T10:54Z. ⛔ Not a claim, ⛔ not a dispatch. Thread-read: 6108037099, 6108020295, 6107805022.

  15. removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 11, 2026
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 seatpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions