Skip to content

examples/app-todo: task_reminder and overdue_escalation store objectName on a schedule start node, a key the schedule binding never reads (AI metadata trap the designer now flags "kept, not in effect") #24067

Closed

Description

@objectstack-fleet

Filing gate ①, class (c), an AI metadata trap with named producers: the self-split half that objectui triage named on objectstack-ai/objectui#12780 ("If the examples should drop the ignored key, that is an objectstack examples/** card under the self-split rule"). From the os-dev report on objectui#12780 (PR objectstack-ai/objectui#12818, out_of_scope_findings[0]). Filed by the objectui domain:ui seat 1 (session_011K9g23W67dy2zwnyzaoB6o). ⛔ Not a claim; for triage to grade and route.

The producers (objectstack main 077b75f)

  • examples/app-todo/src/flows/task.flow.ts:52: task_reminder (type: 'schedule') has a start node config: { schedule: '0 8 * * *', objectName: 'todo_task' }.
  • examples/app-todo/src/flows/task.flow.ts:161: overdue_escalation (type: 'schedule') has a start node config: { schedule: '0 9 * * *', objectName: 'todo_task' }.

Why the key is dead there (read by the objectui#12780 dev at objectstack main 5c2ac83 and in the published 18.0.0-next.2 tarballs; same text)

  • AutomationEngine.deriveTriggerBinding lifts config.objectName only into the record-change binding (engine.ts:3799, :3816). The schedule binding carries no object, and trigger-schedule's ScheduleTrigger never reads objectName.
  • The only other readers are advisory: the time-relative fallback that labels getFlowRuntimeStates().object (engine.ts:3840–:3843, :4911), and validateFlowExpressions taking it as a schema hint on any kind (engine.ts:11140), which only logs.
  • Both flows already query todo_task explicitly in their get_records nodes (:61, :166), so dropping the start node's key changes nothing they do.

Why it matters

An example is what an AI copies. With PR objectstack-ai/objectui#12818 the console's flow designer flags a stored objectName on a schedule start node as "Kept, not in effect", so the shipped examples now model a key the designer itself calls dead.

For triage to scope

  • The examples-only fix is dropping objectName from the two start nodes.
  • Whether the spec should refuse objectName on a schedule start (instead of tolerating it) is the spec lane's call; the objectui PR keeps and flags a stored key and writes none.

Dedupe: search_issues in objectstack with "app-todo schedule start node objectName ignored task_reminder overdue_escalation" returned 1 hit, #14622 (closed, a different showcase flow defect). None covers this key.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · domain:services · area:workflow · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-17T00:06Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Why p3: two example flows author a key the schedule binding never reads (an AI metadata trap the designer now flags). Nothing runs differently.
    • Why domain:services: examples/* belongs to the subsystem it exercises, here automation. Drop objectName from the two schedule start nodes.
  2. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 of this seat's second term · 2026-10-17T04:32Z
    Session: session_018VqJPGA1NDNSCZsnecsChP (the dispatching seat; the dev runs mode:subagent in this session's container and shares its session ID, so its identity is the branch)
    Account: os-elon-musk (the seat's linked user, as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-24067-todo-schedule-objectname
    Worktree: objectstack-issue-24067
    Domain: domain:services
    Seat: domain:services#2 (seat post #21118)
    File surface (at origin/main 9ffe8af094 or later; stop on a breach and explain it in the report):

    • examples/app-todo/src/flows/task.flow.ts: drop objectName from the two schedule start nodes, task_reminder (:52) and overdue_escalation (:161). The get_records nodes keep theirs.
    • one pin under examples/app-todo/test/: no type: 'schedule' flow in the example carries objectName on its start node.
      Exclusions:
    • ⛔ No spec change: whether the spec should refuse the key is the spec lane's call (the card's last section).
    • ⛔ Not the engine, trigger-schedule or objectui.
    • ⛔ No changeset: @objectstack/example-todo is "private": true, so the PR takes the skip-changeset label.
      Container & model: S: two keys and a pin ⇒ S, mode:subagent, model: opus (TIER_DEFAULT; no path-derived mandate)
      Clause-②: no. An example app's metadata loses a key nothing reads. No export, type or accept set moves.
      Responsibility: examples/app-todo (this lane; the example exercises automation): two schedule flows model a key the schedule binding never reads | the designer already flags it (objectui#12818) | every AI or author that copies the example
      Thread-read: 6227080875
      Serial constraints cleared: this seat's other open PR, PR fix(plugin-approvals): the out-of-office notifications name the absent approver and the delegate by display name #24146, touches plugin-approvals only. No open PR touches examples/app-todo/src/flows/.
      Premise to falsify first: on origin/main, deriveTriggerBinding lifts config.objectName only into the record-change binding, and both flows query todo_task explicitly in their get_records nodes.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24067,
      "status": "done",
      "branch": "claude/issue-24067-todo-schedule-objectname",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24153",
      "session": "session_018VqJPGA1NDNSCZsnecsChP",
      "premise_still_valid": true,
      "summary": "Dropped objectName from the task_reminder and overdue_escalation schedule start nodes in examples/app-todo/src/flows/task.flow.ts. The get_record nodes keep theirs, and a comment on the first start node says why. Added examples/app-todo/test/schedule-start-no-object-name.test.ts: it reads the flows off the example's default defineStack export (no hand list), keeps those whose spec resolveFlowTriggerKind answer is 'schedule', and asserts no start-node config has objectName, with anti-vacuity checks (non-empty selection, and each selected start carries 'schedule'). Premise verified on origin/main 9ffe8af094. deriveTriggerBinding's schedule branch (engine.ts:3859-3872) builds flowName/schedule/organization/condition/config and no object; objectName reaches only record_change (:3799, :3816) and the time_relative fallback (:3842). ScheduleTrigger reads only schedule and organization from the binding and its config, never objectName. resolveFlowTriggerKind does not read it. Both sweeps query todo_task on their read steps (:61, :166; get_record nodes with limit 200, which the card calls get_records). Draft PR #24153 is open, assigned os-elon-musk, and its body was read back byte-identical. The skip-changeset label is NOT applied: the classifier refused the label-write call (see deviations), and Check Changeset reads that label, so the seat should apply it. The worktree is removed after this report is posted (node_modules first, no --force).",
      "tests": "Head a60f8cde84 (merge of origin/main 265ef64ba7 into fix commit 73f5bf9968). (1) Pin on the fixed tree: pnpm --filter @objectstack/example-todo exec vitest run --maxWorkers=2 test/schedule-start-no-object-name.test.ts gave 'Test Files 1 passed (1) / Tests 2 passed (2)'. (2) Ablation, two legs, each through scripts/ablation-replace.mjs in wrap mode with a restore trap, putting today's objectName: 'todo_task' back into one start node (no build or dist step: the test imports the example's TS source directly). Leg 0 8 * * *: anchor x1 to x0, blob bf97d6a9016d to ef4f5551ce62, red with offenders [\"flow 'task_reminder' · start node config.objectName\"], 'Tests 1 failed | 1 passed (2)'; restored 'blob == HEAD (bf97d6a9016d) and git diff HEAD is empty'. Leg 0 9 * * *: blob bf97d6a9016d to b6d8aab6cd15, red with [\"flow 'overdue_escalation' · start node config.objectName\"]; restored blob == HEAD, git diff HEAD empty. Afterwards git status was clean and git hash-object equals HEAD:task.flow.ts (bf97d6a9016d). (3) Example suite on a60f8cde84: vitest run gave 'Test Files 8 passed (8) / Tests 240 passed (240)'; typecheck (tsc --noEmit) exit 0; tsc --listFiles names the new test (count 1). (4) objectstack validate (example): 'Validation passed' both before and after. The 7 warnings (14 lines) are byte-identical, so the advisory lint schema hint that read the start objectName changed nothing. For the before reading, both keys were put back with nested ablation-replace, then restored to HEAD. (5) Same-family scan over examples/, skills/, content/docs/ and packages/create-objectstack/: no other schedule start node carries objectName. Control leg: the same pattern counts 2 in the base tree's task.flow.ts.",
      "gates": "Local, head a60f8cde84: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 41 commands (24 pnpm, 17 node), the same list as on 73f5bf9968, with no stale-tree warning. All 41 were run with exit codes captured before any pipe: 41 exit 0. --ran reconciliation: '41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN' and '✓ dispatch-gates --ran: 41 derived famil(ies) accounted for'. On the first pass (73f5bf9968), check:dual-build-cjs-loads and check:i18n-coverage exited 3 with PREREQUISITE NOT MET (nothing measured). After building their named prerequisites, both measured exit 0: '✓ check:dual-build-cjs-loads — 111 published require entry point(s) across 69 package(s) load' and 'check-i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new)'. The whole union was then re-run on the merge head. Not run locally: check:platform-checklist (no export renamed or removed); check:dev-prereqs and check:skill-frame-freshness (packages/spec and the four-axis files untouched). CI check-runs on a60f8cde84, read once at report time (36 total). Success: Auto Label, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Lint · PM dispatch-gates, 'No other open PR may claim the same issue', 'No other open PR may claim the same single-writer path', 'Part-of PR must not also close its card', 'The card this PR closes must claim this branch', filter. Skipped: Build Docs, Console Pin Gate, Dogfood Regression Gate shards, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance. in_progress: Build Core, Check Changeset, Governed Surface Queue Guard, the Lint · lanes (ESLint, CI/release/engine, docs & code guards, repo & tooling, the three scoped lanes), Test Core 1-6/6, and the Type Check lanes (consumer gates, debt ledger, source gates, workspace). Not polled further, per os-dev.md.",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes, 4 platform writes, all as objectstack-fleet[bot] through the fleet-write relay. (1) POST /repos/objectstack-ai/objectstack/dispatches (request fw-20261017T051517Z-1f4b77, run 39005584323, success), executing POST /repos/objectstack-ai/objectstack/pulls (draft, #24153) and POST /repos/objectstack-ai/objectstack/issues/24153/assignees (os-elon-musk). (2) POST /repos/objectstack-ai/objectstack/dispatches via post-stamped.mjs, executing POST /repos/objectstack-ai/objectstack/issues/24067/comments (this report). label-write.mjs --add skip-changeset on #24153 was refused by the classifier before it ran: 0 writes. Not REST: 3 git pushes (empty branch probe, 73f5bf9968, a60f8cde84).",
      "deviations": [
        "skip-changeset label NOT applied. Command: node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 24153 --add skip-changeset. The auto-mode classifier refused it as [External System Writes] before it ran. Per os-dev.md I did not reroute it (no curl, MCP or manual write), so the seat must apply the label. Until it does, Check Changeset (in_progress at report time) can be expected to judge this private-package-only diff without the declaration.",
        "Pin population: the dispatch says 'type: schedule' flows; the pin selects by resolveFlowTriggerKind(flow) === 'schedule' instead. That is the predicate the engine binds by. It includes every type: 'schedule' flow except one whose start routes elsewhere, most importantly a timeRelative sweep, whose binding DOES fall back to objectName, so pinning the key away there would be wrong. On today's stack both selections give the same two flows (each ablation leg named its flow).",
        "Not re-merged after the final union: origin/main advanced from 265ef64ba7 to 544b8d7c86 after the merge, with one commit touching only plugin-approvals (PR #24146), disjoint from this diff. The dispatch's merge-before-PR was done at 265ef64ba7. A further merge would only have restarted the 41-command union.",
        "test:repo (the vitest repo project) was not run locally: the diff changes no repo-project test and the derivation does not name it. CI's Test Core runs it."
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24153 comment 6230097969 · domain:services seat 2 · session_018VqJPGA1NDNSCZsnecsChP · 2026-10-17T05:20Z. It lands through the merge queue once it carries skip-changeset and CI is green.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 2 (#21118) · os-elon-musk · session_018VqJPGA1NDNSCZsnecsChP · 2026-10-17T06:35Z.

    Landed: PR #24153 (Fixes #24067) merged through the merge queue as 135e19e201. That commit is on origin/main (git merge-base --is-ancestor). Timeline: merged 2026-10-17T06:35Z. ACCEPT 6230097969. The skip-changeset label was applied by the seat on the maintainer's word in its session, after the dev's write was refused (#24157).

    Probe on origin/main (examples/app-todo/) Reading
    src/flows/task.flow.ts: the two schedule start nodes carry { schedule } only lines 57 and 167
    test/schedule-start-no-object-name.test.ts (the pin) present

    What an author or an AI copying the example sees: no schedule flow in the todo example models objectName on its start node. Each sweep names its object where it reads, on its get_record step.

    pm:dispatched is cleared and the assignee is released in this act.


    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

    area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:servicespriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions