Skip to content

Flow notify: a record-triggered flow's notification links nowhere unless the author adds the source pair #30121

Closed

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

From a real-user walkthrough of the development flow, filed on the maintainer's word: 「第一组:会卡住人或误导人,立卡」 (2026-11-04). Measured on main 987ff33b88 unless a line says otherwise. Test project scaffolded with create-objectstack@18.3.0.

What a customer sees

A technician is assigned a ticket, gets the notification, clicks it, and lands on the notification list, not the ticket. The author wrote the obvious flow, recipients, title and message, and os validate passed.

Measured

  • Published 18.3.0: sys_inbox_message.action_url is null, and the click opens sys_inbox_message?view=mine. Adding sourceObject and sourceId: { dialect: 'cel', source: 'record.id' } gave actionUrl: /asset_repair_ticket/ID, and the click opened the record.
  • main: packages/services/service-automation/src/builtin/notify-node.ts, near line 976, builds source only from the explicit pair. It reads nothing from the trigger.

The seat itself omitted the pair on the first write, while authoring from the skill.

Expected

In a flow with a record trigger, a notify node with no source and no actionUrl links to the triggering record. An explicit actionUrl or pair still wins. A flow with no trigger record stays as it is.

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server · pm:queue · 2026-11-04T16:20Z

    ⛔ Not a claim.

    • Read fresh. A record-triggered flow's notify builds its link only from an explicit sourceObject / sourceId pair, so the obvious flow sends a notification that links nowhere. Default the source from the trigger record (notify-node.ts). p2.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

    Claim: PM loop round 1
    Session: session_01Utp6CZMkHvuDeVYgTD73qF (seat) · dev card thread session_01Utp6CZ1tD2uZm21w4Bj1xs
    Account: os-bill
    Branch: claude/project-thread-0eqtwo (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-30121
    Domain: domain:server
    Seat: domain:server#4
    File surface: packages/services/service-automation/src/builtin/notify-node.ts and its tests, the run-context seam that exposes the trigger record to the node if the fix needs it (inside service-automation), one changeset; skills/** / content/docs/** only for a one-line default note (else Skills-docs: follow-up owed). ⛔ packages/spec/**, docs/adr/**, .claude/**, AGENTS.md, ui/**, service-automation/src/screen-input-contract.ts (stop on breach; explain in the report)
    Container & model: S–M, mode:thread, model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: high
    Clause-②: no
    Metadata-protocol: semantic
    Responsibility: n/a — not a defect card
    Thread-read: 6635843688
    Premise: holds
    Serial constraints cleared: none — no in-flight claim or open PR names notify-node.ts; this seat's #30178 (screen-input-contract.ts, on hold for a ruling) is a different file in the same package; seat 5's #29919 touches service-messaging / service-queue, not service-automation.

    Dispatch order: /mnt/project-files/server-seat4/dispatch-30121.md (project shared folder). Ruling section: the card's origin 「第一组:会卡住人或误导人,立卡」 (maintainer, 2026-11-04) and triage audit 6635843688 ("Default the source from the trigger record").

    Posted 2026-11-05T02:52Z.

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
    os-dev-report

    Status: done. Draft PR #30252, head 6de9d516, Fixes #30121. Clause-②: no. Metadata-protocol: semantic (changeset minor on @objectstack/service-automation). Skills-docs: follow-up owed (three files named in the PR body); the seat files the card.

    {
      "issue": 30121,
      "status": "done",
      "branch": "claude/project-thread-0eqtwo",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30252",
      "session": "session_01Utp6CZ1tD2uZm21w4Bj1xs",
      "premise_still_valid": true,
      "summary": "notify-node.ts gains defaultClickThroughOf: when a notify node writes none of sourceObject, sourceId and actionUrl, its click-through source is the run's trigger record, read through the existing triggerRecordOf(context) (object + record.id), so the messaging service stores source_object/source_id and synthesizes /OBJECT/ID. That covers record-change runs, a time-relative sweep's row and an action started on a record; a schedule tick, an inbound API post (no object) and a manual start with no record are unchanged. An explicit pair or actionUrl wins, a half-written pair is still dropped, and beforeDelete/afterDelete are not defaulted (the record is gone). The organization fallback skips its second candidate when the source is the defaulted trigger record; the resolved organization is unchanged. Studio form help for the three keys states the default.",
      "tests": "head 6de9d516 (code unchanged since 07615b8f; the merge brought no service-automation or spec file): vitest src/builtin/notify-node.test.ts Test Files 1 passed, Tests 23 passed (17 + 6 new pins in one new top-level describe); pnpm --filter @objectstack/service-automation test under the lock: Test Files 263 passed (263), Tests 3407 passed (3407), VERDICT command-exit 0; service-automation typecheck exit 0 (check:test-typecheck OK, 0 debt). Ablation on committed 5d129999 via scripts/ablation-replace.mjs: the default's `return trigger;` replaced by `return trigger && undefined; // ABLATED_30121` (anchor 1 to 0, blob 94746f6b12e1 to 381704ef410f): 1 failed (pin 1, record-triggered notify links to the trigger record), 22 passed; restore blob equals HEAD, git diff HEAD empty. The suite imports the executor from src, so no build sits between mutation and run. A first attempt used a bare identifier marker that threw ReferenceError (8 unrelated reds); discarded as a malformed mutation, not counted.",
      "gates": "head 6de9d516, dispatch-gates --commands: 59 families. 58 exit 0 (the teardown self-test among them, after the fetch below). pnpm check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET (needs the whole workspace built): NOT MEASURED, left to CI. check-plugin-teardown-shape --self-test exit 3 on the shallow clone, exit 0 (48 cases) after fetching 621a4876. pnpm lint exit 0 (outside the derivation, run on the order's word). --ran: 59 derived families accounted for, 58 run, 1 NOT-MEASURED. PR check-runs: not yet read at report time (in_progress). Records: /mnt/project-files/server-seat4/30121/gates-ran.txt and gates-ran-verdict.txt",
      "dogfood_battery": "n/a: no bang in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "3: git push (not REST), pr_create #30252 (relay, read-back identical 7397 bytes, assignees none), this os-dev-report comment (relay)",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": ["carrier: seat (Skills-docs follow-up) · packages/spec/src/automation/io-node-config.zod.ts sourceObject/sourceId describes, skills/objectstack-automation/SKILL.md notify example line, content/docs/automation/flows.mdx notify sourceId paragraph do not state the trigger-record default · noted, not filed"]
    }

    Deviations: the merge commit 6de9d516 carries no trailer pair (git's default merge message). The session-context assignee and reviewer step on the PR was skipped under os-dev rule 2 and the order's no-MCP-write line; the seat sets them at hand-over. The platform's PR-activity subscription was not taken, per os-dev (the dispatch contract outranks it); a later red returns as a patch round. Two route decisions the order left open, stated in the PR body: a time-relative sweep's row qualifies as a trigger record, and a delete event is not defaulted.

    Report taken 2026-11-05T03:44Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

    Landed · PR #30252

    Reading Value
    PR #30252 MERGED 2026-11-05T04:32Z, merge commit 04f36b63f; Fixes #30121 closed this card
    main source packages/services/service-automation/src/builtin/notify-node.ts:180 defaultClickThroughOf, the trigger-record default

    State change: pm:dispatched removed, assignee cleared. The Skills-docs follow-up #30254 is now unblocked.

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

    domain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions