Skip to content

Restore toast Undo on one-click completion now that row actions can declare a field write (objectstack#14092 closed) #146

Closed

Description

@objectstack-fleet

Found by the 18.1.0 upgrade (PR #144, head fd0e541, report #139 comment 6412788813); not changed there because it changes behaviour.

Background

#4 / #41 shipped one-click completion with undo. The complete row action is a script action, and undoable on it was never fulfilled by any runtime; spec 18 removes the key, so #144 drops it. The one-click reversal stays the duly_task_undo row action (pinned by test/task-actions.test.ts), but the toast Undo the deck shows is gone.

objectstack#14092 (no declarative field write for a ROW action) is closed completed since 2026-09-03. If complete becomes an operation: 'update' row action, the platform's toast Undo may apply to it.

What done looks like

  • Measure on 18.1.0: does a declarative row update action get a toast Undo, and does it still run the task hook that stamps completed_at / completed_late? Quote the platform source or docs.
  • If yes: move complete (and skip if it fits) to the declarative form, keep the stamping and permission gates identical, keep duly_task_undo working, and test both.
  • The headers of src/actions/task.handlers.ts and src/actions/task.actions.ts say no row-level declarative field write exists; correct them either way.

Restart-when: #144 is merged.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Unblocked at 2026-10-27T08:15Z: the restart condition holds. #144 (Upgrade to @objectstack 18.2.0) merged as c20d397, so main now runs 18.2.0. Moved from pm:blocked to pm:ready. Re-measure on 18.2.0 before you build, since this card was written against 18.1.0.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_011HyoSXGRy6L13mYq1Hp4n1
    Account: os-warren (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-fica3z (platform-assigned card-thread branch, at origin/main 25743ed)
    Worktree: duly-issue-146
    Domain: n/a. objectstack-ai/duly is a single-lane app repo with no domain:*.
    Seat: repo:duly#1
    File surface: src/actions/task.actions.ts, src/actions/task.handlers.ts, test/task-actions.test.ts; test/security.test.ts, test/demo-admin-capabilities.test.ts and src/translations/en.ts only if the measurement requires them. src/translations/zh-CN.ts only after telling the seat (#128 holds it). Stop on any breach until the seat posts a Claim amendment.
    Container & model: S-M, mode:thread, model: TIER_DEFAULT (hand-derived), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: to be measured. App work if 18.2 gives a declarative row update action a toast Undo; otherwise a fork report, and the upstream half is filed.
    Thread-read: 6436953483
    Premise: to be measured first: objectstack#14092 is closed completed (2026-09-03), and whether 18.2 renders a toast Undo for it is the measurement.
    Serial constraints cleared: #128 is in flight on src/objects/task.object.ts, src/translations/zh-CN.ts and src/actions/catalog.actions.ts, and #160 on src/flows/assignment.flow.ts and src/email-templates/assignment.email-template.ts. Neither intersects this surface.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim correction (2026-11-02T02:50Z): the Branch line should read "at origin/main f26fc5c", not 25743ed. The seat's claim template carried a stale base. The card thread works from f26fc5c, which includes #158 and #159.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    repo:duly#1 · os-warren · session_01JQwxbWM2DtyF9EXG41gsbt
    os-dev-report

    {
      "issue": 146,
      "status": "done",
      "branch": "claude/project-thread-fica3z",
      "pr": "https://github.com/objectstack-ai/duly/pull/164",
      "session": "session_01JQwxbWM2DtyF9EXG41gsbt",
      "premise_still_valid": true,
      "summary": "Measured on main f26fc5c (@objectstack 18.2.0): all three conditions hold. (1) spec 18.2 admits undoable on operation:'update'; console 18.2 ActionRunner.executeUpdateOperation posts to the action route, builds the undo from the row and handlePostExecution puts Undo on the success toast; the runtime also returns an undo envelope. (2) executeDeclarativeUpdateAction writes via callData('update') under the caller's own context, so task.hook.ts stamps completed_at/completed_late (measured, true on a past-due task). (3) actionPermissionError runs ahead of the declarative branch on the REST /actions door and the MCP door (measured 403 PERMISSION_DENIED). duly_task_complete and duly_task_skip are now operation:'update' + patch + undoable:true; their handlers are removed; duly_task_undo keeps its handler. Stale headers of task.actions.ts and task.handlers.ts rewritten. Behaviour change named and pinned: completing a cancelled task through the API now answers 200 (the handler's 409 is gone; the data plane already accepted the same PATCH); declared rule is #162. Surface amendment by seat ruling: test/catalog-instantiate.test.ts, src/translations/authored-text.ts. zh-CN.ts untouched.",
      "tests": "head c0551f9: pnpm test exit 0, Test Files 38 passed (38), Tests 938 passed (938); test/task-actions.test.ts 44/44 (complete/skip driven through HttpDispatcher.handleActions, toast-undo envelope applied as the console does, undo row action, capability 403 for all three, 404/400 subject refusals, #162 pin). Ablation on committed HEAD: undoable true -> false on complete (marker grep 1), task-actions 3 failed / 41 passed (undoable declaration, route undo envelope, applying it); restored with git checkout HEAD --, git diff HEAD empty, blob hash = HEAD, marker 0. Browser on pnpm demo (en-US, :3000) and pnpm demo:zh (:3300), demo admin, My week first row Complete: toast 'Done. Undo' / '已完成。 撤销'; Undo sends PATCH /api/v1/data/duly_task/ID {status:open}; toast 'Change undone' / '已撤销更改'; row back to Open/待办 with Complete; REST read status open, completed_at null, completed_late null. Screenshots in project files duly-146-declarative/.",
      "gates": "local, head c0551f9, exit codes captured before any pipe: pnpm validate 0 (9 pre-existing warnings, none on actions), pnpm typecheck 0, pnpm test 0, pnpm build 0. duly has no scripts/pm/dispatch-gates.mjs; gate list hand-derived from package.json (verify = validate+typecheck+test) plus build per AGENTS.md. CI: .github/workflows/ci.yml job verify on the PR, in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "7 — issue_read x3 (get, get_comments x2), create_pull_request, issue_write (assignees os-warren), update_pull_request (reviewers; refused: PR author), pull_request_read x1 (body read-back). Write tools are in the list: this session's harness mandates the GitHub MCP for all GitHub writes and the order asked for os-warren as assignee; named here rather than hidden.",
      "api_writes": "1 — this os-dev-report comment via scripts/pm/post-stamped.mjs (POST issues/146/comments); git push x1 (branch claude/project-thread-fica3z)",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: b · reach: POST /api/v1/actions/duly_task/duly_task_complete/ID on a cancelled task answers 200 and stores done (measured in test and route) · the declared transition rule belongs on the object · carrier: #162 (filed by the seat) · noted, not filed",
        "carrier: none · duly_task_undo could also be declarative (patch status in_progress); left as a handler because the card moved only the two actions missing a toast Undo · noted in task.handlers.ts header and PR Acceptance notes"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment (2026-11-02T03:20Z; the ruling was given to the card thread at 2026-11-02T03:00Z, and this record was held by the fleet write throttle). The file surface adds two files, both direct consequences of moving complete / skip to declarative update actions:

    • test/catalog-instantiate.test.ts: the two "handler wiring" loops skip action.operation === 'update', with a comment pointing to test/task-actions.test.ts, which pins that the declarative pair carry no handler.
    • src/translations/authored-text.ts: 'action.operation' becomes a machine(...) verdict, and 'action.patch' goes into OPAQUE, mirroring the view.bulkActionDefs[] rows. No translated string moves.

    Serial note: #160 also claims src/translations/authored-text.ts, for one flow.nodes[].config.assignments entry. The two entries sit in different parts of the table. Whichever of #146 and #160 lands second merges main and re-runs test/i18n-coverage.test.ts before the seat lands 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