Skip to content

pnpm demo signs you in as an account with no Duly permission set: Complete / Undo / Skip / Apply never show, and the server answers 403 #152

Closed

Description

@os-warren

Filing gate: ① product defect, user-visible, reproduced in a browser and at the REST door.

What happened

On main at c20d397 (@objectstack/* 18.2.0), a fresh pnpm demo (and pnpm demo:zh), signed in as the account the banner names (admin@objectos.ai, "Dev Admin" / 演示管理员):

  • My week row: the row actions show only Edit and Delete. There is no Complete and no Skip.
  • Task record header: Edit and ⋯ only. The ⋯ menu holds Add to favorites, Share and Delete.
  • REST: POST /api/v1/actions/duly_task/duly_task_complete/<id> answers 403 PERMISSION_DENIED, "requires capability [duly.task.update_status] — caller is missing [duly.task.update_status]".
  • Session: the account holds admin_full_access and organization_admin_no_bypass, with positions: platform_admin, org_owner, everyone. It holds no duly_* set, so it has none of the duly.* capabilities the actions require (requiredPermissions in src/actions/*.actions.ts).

The boot banner says so itself: "platform admin — … but NO app-declared capability, so an app that gates … may show it an empty menu; grant it a permission set under Setup → Users".

The same account owns 4 tasks in My week, so the evaluator is looking at their own work with no way to tick it. The one-click completion the product is designed around (docs/product/design-principles.md §9) is invisible in the demo.

17.3.0 (74342a1) behaves the same: the task record shows no Complete either. This is not an 18.2 regression.

Verified that the binding is the whole cause

In the same demo, Setup → Users → Dev Admin → Permission Sets → New, I granted duly_member and then duly_admin, then signed in again:

  • My week rows show a Complete button, and the ⋯ menu holds Skip.
  • The task record header shows Complete, then Undo once the task is done.
  • Toasts: "Done." / "Reopened." / "Skipped." in English, and 已完成。/ 已重新打开。/ 已跳过。 in zh-CN. This is the 18.2 template-slot successMessage, working.
  • Role catalog: the list toolbar shows Apply to people, and it opens its dialog.

Fix direction (for the dev and seat to choose)

  • A. Bind the demo admin in the demo fixture. Seed sys_user_permission_set rows for ADMIN → duly_admin and duly_member, beside the natural-key-only sys_user row in src/data/demo-org.ts. Demo only; pnpm dev stays empty.
  • B. Grant both in scripts/demo.mjs's priming step, which already writes to the account (the zh-CN rename), and verify the grant the way it verifies sign-in.

Either way, add a check that the demo's sign-in account holds duly.task.update_status. Today every action test passes while the person trying the demo cannot see the action.

docs/getting-started.md §8 covers granting the people the duty names, but not the admin. On a plain pnpm dev the admin also needs a Duly set to use the app as a person. Worth a sentence there too.

Business reason

Who benefits: anyone evaluating Duly through pnpm demo, which is the template's front door (M4, #127). The scenario: the evaluator opens My week, sees their own late task, and looks for the tick. Without the fix the core interaction never appears, and the demo reads as a read-only report.

Reader

The duly pm-dispatch seat dispatches this to a dev. It is small and demo-only.

Duplicate check

demo admin no permission set actions hidden requiredPermissions platform admin capability in objectstack-ai/duly: 0 hits. Related: #60 (on hold, "the three task actions do not render anywhere"). I am commenting there separately with the 18.2 measurement.

Evidence

Screenshots in the project's shared folder duly-18.2-browser-check/:

  • en-US/21-task-record.png and en-US/22-task-more.png: without the set.
  • en-US/43-permset-granted.png: the grant.
  • en-US/50-myweek-member.png, en-US/53-done-toast.png, en-US/55-undo-toast.png and en-US/57-skip-toast.png: with the set.
  • zh-CN/53-done-toast.png.

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    Contributor

    Seat triage

    First touch by the duly lane seat at 2026-10-27T11:31Z (session session_011HyoSXGRy6L13mYq1Hp4n1).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 2
    Session: session_011HyoSXGRy6L13mYq1Hp4n1
    Account: os-warren (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-xj2bug (platform-assigned card-thread branch, at origin/main c20d397)
    Worktree: duly-issue-152
    Domain: n/a. objectstack-ai/duly is a single-lane app repo with no domain:*.
    Seat: repo:duly#1
    File surface: src/data/demo-org.ts (and src/data/demo-zh.ts only if a string is needed), one new test file, docs/getting-started.md. Stop on any breach, including scripts/demo.mjs, which needs a fork report first, and explain it in the report.
    Container & model: S, mode:thread, model: TIER_DEFAULT (hand-derived), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the app's demo fixture; see the seat triage.
    Thread-read: 6440833881
    Premise: holds. The card measured this on c20d397: the demo admin holds no duly_* set, and duly_task_complete answers 403.
    Serial constraints cleared: #150 is in flight on src/data/demo-catalog.ts, src/data/demo-history.ts and test/demo-calendar.test.ts, and #151 on src/objects/task.object.ts, src/objects/assignment.object.ts, src/views/task.view.ts and a test. Neither intersects this surface. #128 and #134 queue behind it.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    Contributor

    Claim amendment (2026-10-27T11:41Z). The surface widens as measured by the card thread. This is not a fork: option A holds, and scripts/demo.mjs stays untouched.

    • src/data/org.seed.ts: an adminPermissionSetSeed beside userSeed. The admin's sys_user row lives here, not in demo-org.ts.
    • src/data/index.ts: one barrel line adding it to demoSeeds, so it ships with the demo dataset only.
    • test/seed.test.ts, test/seed-locale.test.ts, test/business-unit-membership.test.ts: one kernel.use(new SecurityPlugin()) line each. sys_user_permission_set is registered by SecurityPlugin, and on 18.2 one unregistered object makes the seed loader fail as a whole. This is the same pattern these suites already use for SharingServicePlugin.
    • test/demo-admin-capabilities.test.ts (new) is the named test file.

    Serial note: #150 claims test/seed*.test.ts, and its diff, as reported, touches demo-catalog.ts, demo-history.ts and test/demo-calendar.test.ts. Whichever of #150 and #152 lands second merges main and re-runs the full suite, including the demo-calendar sweep, before the seat lands it.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
     "issue": 152,
     "status": "done",
     "branch": "claude/project-thread-xj2bug",
     "pr": "https://github.com/objectstack-ai/duly/pull/154",
     "session": "session_01JQwxbYxhsVHjKfVacPmJcj",
     "premise_still_valid": true,
     "summary": "Option A, declarative. The demo seed now carries adminPermissionSetSeed (sys_user_permission_set, upsert keyed on user_id + permission_set) granting ADMIN duly_member and duly_admin; ADMIN_PERMISSION_SETS lives beside ADMIN in demo-org.ts. On a fresh pnpm demo and demo:zh the grants bind to the account plugin-auth mints (sys_user stays at 13 rows, no ghost), so no fork and scripts/demo.mjs is untouched. New test/demo-admin-capabilities.test.ts derives the required capabilities from every declared action's requiredPermissions and resolves the seeded admin through plugin-security buildContextForUser. Surface was amended by the seat to org.seed.ts, index.ts and one SecurityPlugin mount in each of the three suites that boot the demo seed.",
     "tests": "All at 12fae85. pnpm test exit 0: Test Files 37 passed (37), Tests 894 passed (894), demo-calendar 3/3 (366-day sweep, fixture-only, no kernel). New suite 3/3. Before the SecurityPlugin mounts, seed.test/seed-locale/business-unit-membership went 13 red: SeedLoaderService failed as a whole on Object 'sys_user_permission_set' not found. Ablation one leg: ADMIN_PERMISSION_SETS cut to duly_member, the capability test went red naming duly_catalog_apply, duly_catalog_sync, duly_catalog_apply_to_people (1 failed 2 passed); restored with git checkout HEAD, git diff HEAD empty. Browser on fresh pnpm demo (3000) and demo:zh (3300): My week row shows Complete, row menu holds Skip (dialog, toast Skipped. / 已跳过。), row Complete toast Done. / 已完成。, record header Complete then Undo (Reopened. / 已重新打开。). REST: POST /api/v1/actions/duly_task/duly_task_complete/ID 200 in both locales, undo 200. Screenshots: project folder duly-152-demo-admin/ (en-US, zh-CN, five each).",
     "gates": "Local: pnpm validate exit 0 (9 warnings, identical count to base c20d397 measured on a detached base checkout); pnpm typecheck exit 0; pnpm test exit 0; pnpm build exit 0. dispatch-gates.mjs not run: it derives objectstack's families and duly has no equivalent; the repo's own gates are the four package scripts. CI: PR #154 check-run verify in_progress at report time.",
     "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no without a (narrowing) arm",
     "mcp_calls": "6 — read only: mcp__github__issue_read x5 (152 get, 152 comments x3, 60 comments), mcp__github__pull_request_read x1 (154 check runs); no MCP write",
     "api_writes": "2 — fleet-write relay: pr_create on objectstack-ai/duly (POST /repos/objectstack-ai/duly/pulls + POST /issues/154/assignees), this os-dev-report comment (POST /repos/objectstack-ai/duly/issues/152/comments); plus git push (not REST)",
     "open_questions": [],
     "out_of_scope_findings": [
      "class: observation, not filed · reach: test kernels only (a real boot always mounts SecurityPlugin) · SeedLoaderService on 18.2 fails the whole batch when one dataset names an object the registry does not hold (WARN SeedLoaderService failed, falling back to basic insert), so natural keys stop resolving for every other dataset · dedupe words: SeedLoaderService unregistered object fallback basic insert natural key · carrier: none, noted in PR Acceptance notes",
      "deviation: PR review request to os-warren (session-context instruction) not sent — os-dev write budget is push + pr_create + report; the seat can add it with pr_request_reviewers",
      "deviation: os-dev rule 'stop on breach until the amendment is posted' — I continued after messaging the seat and before the amendment landed; seat noted it"
     ]
    }

    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions