Skip to content

os explain flow's example teaches $currentUser as an assignment value, a spelling nothing resolves #14782

Closed

Description

@os-litant

Found while working on #14139 (the same literal on the filter surface); out of scope
there, filed unassigned for triage. Suggested domain: domain:cli. That card's triage
comment already anticipated this one: "packages/cli/src/commands/explain.ts's
$currentUser is a default-value sample on a different surface and is out of this card's
scope; if it is also wrong it is a domain:cli card."

The sample

packages/cli/src/commands/explain.ts:128, inside the flow entry's example string —
the text os explain flow prints to an author:

example: `{
  name: 'assign_on_create',
  type: 'autolaunched',
  label: 'Auto-Assign on Create',
  trigger: { object: 'project_task', event: 'afterInsert' },
  steps: [
    { type: 'assignment', field: 'assigned_to', value: '$currentUser' },
  ],
}`,

Note this is a flow step of type: 'assignment' (Set Variable,
packages/spec/src/automation/flow.zod.ts:30) — not a field defaultValue, and not a
query filter. The surface is its own; that is exactly why #14139 left it alone.

What was measured

On origin/main:

  • The literal appears exactly once in non-test, non-CHANGELOG source in the whole
    repository — this sample.
    (git grep -n -F '$currentUser' returns 4 hits: this line,
    two in skills/objectstack-ui/rules/list-views.md which skills/objectstack-ui teaches $currentUser as a filter value, contradicting its own "only two tokens resolve in a filter" contract #14139 is fixing, and
    docs/adr/0017-object-has-many-view.md:216 which is SQL-shaped prose.)
  • The flow template vocabulary is brace-based, not $-prefixed. Flow templates are
    written {record.field} and validated by flow-template-unknown-field
    (packages/lint/src/validate-flow-template-paths.ts:92), whose diagnostics say an
    unresolvable path "resolves to an empty string at runtime (silently)".
  • The $-prefixed sentinels that do exist are enumerated and different: $root
    (approval organization), $trigger, $record, $source. There is no $currentUser
    among them, and no alias table maps it.
  • The acting-user token on the value-producing surface next door is spelled bare:
    DEFAULT_VALUE_TOKEN_CURRENT_USER = 'current_user'
    (packages/spec/src/data/default-value-tokens.ts:67), matched EXACTLY by
    isCurrentUserDefaultToken (:114-116), whose own comment names currentUser as an
    authoring error rather than an accepted spelling. packages/spec/src/data/default-value-shape.ts:225
    carries currentuser only as a near-miss suggestion, and
    default-value-shape.test.ts:54 pins currentUser (camelCase) is a literal.
  • Nothing in packages/services/service-automation strips or resolves a leading $ in an
    assignment value.

What was NOT measured — please settle this in triage

I did not execute an assignment node with this value against a running engine. So the
claim I am confident in is "no declared vocabulary contains this spelling and nothing was
found that resolves it"; the claim I have not proved is "an assignment step therefore
stores the literal string $currentUser into assigned_to". If it does, that is the
lookup('sys_user') column taking a bogus literal — the same failure class as the DDL
incident catalogued in the default-value-tokens.ts module note.

Why it matters

os explain is an authoring aid whose whole audience is authors — increasingly AI authors
— writing their first flow. It is the one place a reader is told what an assignment value
looks like. If the spelling resolves nowhere, the sample teaches a value that either fails
validation or is silently stored as text, and the reader has no other reference to correct
it against.

Likely fix

Decide the correct spelling for "the acting user" on the flow-assignment surface, then make
the sample use it. If no such token exists on this surface, the sample should assign
something that does resolve rather than inventing a sentinel — and the gap itself is worth a
separate decision, since "assign to the current user on create" is the textbook
auto-assignment flow.

Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    on Sep 3, 2026
  2. huangyiirene commented on Sep 3, 2026

    @huangyiirene
    Collaborator

    Triage — graded. bug · documentation · priority:p3 · pm:queue · domain:cli. The card asked triage to settle the half it did not measure. Partly settled below — and a second defect turned up on the way.

    Verified at origin/main

    ✅ git grep -F '$currentUser' returns exactly the four hits described: explain.ts:128, skills/objectstack-ui/rules/list-views.md:95 and :103 (#14139's), and docs/adr/0017-…:216 (SQL-shaped prose). So the sample really is the only non-test source occurrence outside what #14139 is already fixing.
    ✅ DEFAULT_VALUE_TOKEN_CURRENT_USER = 'current_user' at default-value-tokens.ts:67, matched exactly at :115.

    ⭐ The unmeasured half, advanced but not closed

    packages/services/service-automation/src/builtin/logic-nodes.ts:135:

    variables.set(key, interpolate(value, variables, context));

    and :92 states the intent outright — the assignment node shares the CRUD/screen resolution "so value: '{record.amount}' resolves". ⇒ The resolver on this surface is brace-based, confirming the card's vocabulary finding at the execution layer rather than only the declaration layer. A $-prefixed token carries no braces, so there is nothing for it to match.

    ⚠️ What that does not establish, and I am not asserting: that assigned_to ends up holding the literal '$currentUser'. variables.set sets a flow variable, not a record field; reaching a lookup('sys_user') column takes a later record-writing node. The card's feared failure class stays plausible and unproven. ⛔ Do not write it up as measured.

    ⭐ Second defect the card did not find — the sample's node SHAPE

    logic-nodes.ts:85-88 warns:

    mismatch here silently sets a variable literally named assignments
    • Studio visual builder → { assignments: { <var>: <value> } }
    • bundled example flows → { assignments: [{ variable, value }] }

    The sample writes neither. It writes { type: 'assignment', field: 'assigned_to', value: '$currentUser' } — a field/value pair with no assignments key at all.

    ⚠️ I am not concluding the sample is shape-invalid, because these may be two layers: the flow spec step shape (packages/spec/src/automation/flow.zod.ts:30, which the card cites) versus the runtime node config these builtins consume. Settling that is the claimer's first step, and it is cheap: if the spec step shape is field/value and something adapts it, the sample's only defect is the token; if the surfaces are the same, the sample teaches a node that silently sets a variable named assignments and the card is understated.

    ⇒ ⛔ Do not fix the token before answering that. Correcting $currentUser in a sample whose shape is also wrong ships a second wrong sample that now looks authoritative.

    Scope — terminal

    The fix lands in packages/cli/src/commands/explain.ts — one lane, one file.

    • If a resolving spelling for "the acting user" exists on the flow-assignment surface ⇒ use it, and keep the sample's shape whatever step 1 established as correct.
    • If no such token exists on this surface ⇒ ⛔ do not invent one and ⛔ do not borrow current_user from the default-value surface on the assumption it carries over. Change the sample to assign something that demonstrably resolves (a brace template such as {record.…}), and say in the report that "assign to the current user on create" has no expressible spelling here.

    ⛔ That gap is out of scope: the card is right that it deserves its own decision, and it is one — a missing token on a published authoring surface is a contract question, not a sample fix. ⛔ Do not open an ADR or add a token; name it in the report and it gets carded separately.

    ⚠️ ⛔ Do not touch skills/objectstack-ui/rules/list-views.md:95/:103 — those two hits belong to #14139, on the filter surface, and editing them here collides with that card.


    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

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentationdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions