Skip to content

fix(example-todo): drop objectName from the two schedule start nodes - #24153

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24067-todo-schedule-objectname
Oct 17, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24067-todo-schedule-objectname

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24067
Clause-②: no

What

examples/app-todo's two daily sweeps, task_reminder and overdue_escalation, stored objectName: 'todo_task' on a type: 'schedule' start node, a key the schedule binding never reads. This PR drops the key from both start nodes and adds a pin over the example's shipped stack. Clause-② is no: an example app's metadata loses a key nothing reads, and no export, type or accept set moves.

Premise verified first (on origin/main 9ffe8af094)

  • AutomationEngine.deriveTriggerBinding (packages/services/service-automation/src/engine.ts) puts config.objectName into the record-change binding (:3799, :3816) and, as a fallback behind timeRelative.object, into the time-relative binding (:3842). Its schedule branch (:3859 to :3872) builds flowName, schedule, organization, condition and config, and no object.
  • ScheduleTrigger (packages/triggers/trigger-schedule/src/schedule-trigger.ts) reads binding.schedule and binding.organization, and from binding.config only schedule and organization. It never reads objectName, and the run context it builds carries no object.
  • The spec's resolveFlowTriggerKind never reads objectName. Neither start node has a record-* triggerType, so both flows resolve to schedule.
  • Both sweeps name todo_task on their read steps: get_upcoming_tasks (:61) and get_overdue_tasks (:166). These are get_record nodes with limit: 200; the card calls them get_records, but they are the same nodes. They keep their objectName.
  • The only other readers are advisory: the engine's validateFlowExpressions schema hint (it logs and never throws) and @objectstack/lint's validate-expressions hint. Under "Evidence" below, objectstack validate gives the same output before and after.

Changes

  • examples/app-todo/src/flows/task.flow.ts: drop objectName from both schedule start nodes. A comment on the first one says why.
  • examples/app-todo/test/schedule-start-no-object-name.test.ts (new): reads the flows from the example's default defineStack export, not from a hand list, and keeps those whose resolveFlowTriggerKind answer is schedule. It then asserts that none of them has objectName on its start node's config. Anti-vacuity: the selection must be non-empty, and each selected start node must carry schedule.

Selection, as a deviation from the dispatch wording. The claim describes the pin's population as "type: 'schedule' flows". The pin selects by the spec resolver's schedule answer instead, because that is the predicate the engine binds by. Every type: 'schedule' flow is included unless its start node routes it to another trigger. The case that matters is a timeRelative sweep: its binding does fall back to objectName, so pinning the key away there would be wrong.

Evidence

  • Pin, on the fixed tree: pnpm --filter @objectstack/example-todo exec vitest run --maxWorkers=2 test/schedule-start-no-object-name.test.ts gives 2 passed.
  • Ablation through scripts/ablation-replace.mjs (wrap mode, with a restore trap). Each leg puts today's objectName: 'todo_task' back into one start node:
    • Leg 0 8 * * *: anchor count 1 to 0, blob bf97d6a9016d to ef4f5551ce62. Red, offenders flow 'task_reminder' · start node config.objectName. Restored: blob equals HEAD bf97d6a9016d, git diff HEAD empty.
    • Leg 0 9 * * *: blob bf97d6a9016d to b6d8aab6cd15. Red, offenders flow 'overdue_escalation' · start node config.objectName. Restored: blob equals HEAD, git diff HEAD empty.
  • Example suite on head a60f8cde84: vitest run gives 8 files and 240 tests passed. typecheck (tsc --noEmit) exits 0, and tsc --listFiles includes the new test.
  • objectstack validate on the example passes both before and after, and its 7 warnings are byte-identical. For the "before" reading, both keys were put back with nested ablation-replace, then restored to HEAD.
  • Same-family scan over examples/, skills/, content/docs/ and packages/create-objectstack/ found no other schedule start node with objectName (control: the same pattern finds 2 in the base tree's task.flow.ts).

Gates (local, head a60f8cde84)

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 41 commands. All 41 were run, and every exit code was captured before any pipe: 41 exit 0.
  • --ran reconciliation: 41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN.
  • On the first pass (head 73f5bf9968), check:dual-build-cjs-loads and check:i18n-coverage refused with PREREQUISITE NOT MET (exit 3, nothing measured). I built the packages they named, and both then measured exit 0. The whole union was then re-run on the merge head.
  • CI owns the full set of families, the type-check lanes and the jobs scheduled by these paths.

Acceptance notes

  • No changeset: @objectstack/example-todo is "private": true, so this PR carries the skip-changeset label.
  • The card's last section leaves open whether the spec should refuse objectName on a schedule start node. That is the spec lane's call, and this PR does not touch it.
  • The head merged origin/main at 265ef64ba7. Since then, main has advanced by one commit that touches only plugin-approvals, which this diff does not touch.

Generated by Claude Code

task_reminder and overdue_escalation stored objectName on a schedule
start node. The schedule binding carries no object: deriveTriggerBinding
lifts objectName into the record-change binding only, and ScheduleTrigger
never reads it, so the key was stored and never acted on (the flow
designer flags it "kept, not in effect"). Both sweeps already name
todo_task on their get_record steps.

Adds a pin over the shipped stack: no flow whose resolved trigger kind is
schedule carries objectName on its start node.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VqJPGA1NDNSCZsnecsChP
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:services seat 2 · session_018VqJPGA1NDNSCZsnecsChP · 2026-10-17T05:19Z

Reviewed against GitHub at head a60f8cde84, from the diff and the dev's report on #24067. Clause-②: no: an example app's metadata loses a key nothing reads. So this is the seat's own review of record.

Form

  • Draft, base main. The first line is Fixes #24067, then Clause-②: no.
  • 2 files, about +65 / −2. No changeset: @objectstack/example-todo is private.
  • Path face: examples/app-todo/** only, so NOT governed.

The change. objectName is gone from the task_reminder and overdue_escalation schedule start nodes. Both sweeps still name todo_task on their get_record steps.

  • The premise, read by the dev on origin/main: deriveTriggerBinding's schedule branch carries no object, ScheduleTrigger reads only schedule and organization, and objectName reaches only the record-change binding and the time-relative fallback.
  • objectstack validate on the example passes before and after, with byte-identical warnings.

The pin. test/schedule-start-no-object-name.test.ts reads the flows off the example's own defineStack export. It selects by the spec's resolveFlowTriggerKind(flow) === 'schedule', the predicate the engine binds by, so a time-relative sweep (whose binding does fall back to objectName) is rightly left out.

  • Anti-vacuity: the selection is non-empty, and each selected start carries schedule.
  • Ablation: each start node's key put back reds the pin with that flow named. Both restores are proven by blob.

Gates and CI

  • Gates: 41 derived, 41 exit 0, reconciled with --ran.
  • The example passes 8 files and 240 tests. Typecheck exits 0.
  • CI at a60f8cde84: Check Changeset is red because the PR does not yet carry the skip-changeset label, which that check reads. The dev's write of the label was refused by the dev's permission check. The label waits on the maintainer's word in the seat's session. Other lanes were still running at this review.

Out-of-scope findings: none.

ACCEPT. The seat marks the PR ready and enables auto-merge through the fleet relay once the label is on and CI is green on this head.


Generated by Claude Code

@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 17, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 17, 2026 06:18
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 17, 2026 06:18
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 17, 2026
Merged via the queue into main with commit 135e19e Oct 17, 2026
46 of 47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24067-todo-schedule-objectname branch October 17, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants