Skip to content

app-showcase's nightly health sweep reaches its engine through a module-scope global, so it silently does nothing on an artifact-served boot #14257

Description

@claude

Found while implementing #14094. Independent of that card's fix, which lands in packages/runtime; this one is the example app that still ships the pattern the fix supersedes.

Measured

examples/app-showcase/src/automation/jobs/sweep-project-health.ts holds its engine handle in a module-scope let host, filled by an exported bindShowcaseJobRuntime(ctx) that objectstack.config.ts calls from onEnable. When host is unset the handler logs no engine handle bound yet — skipping this run and returns.

That binding does not exist on the artifact path. objectstack build emits functions into a sibling runtime module exporting only { functions, meta }; the artifact JSON carries no onEnable, and mergeRuntimeModule (packages/runtime/src/load-artifact-bundle.ts) merges only functions. So on an artifact-served boot bindShowcaseJobRuntime is never called, host stays undefined, and showcase_health_sweep fires on schedule and recomputes nothing — reported as a clean run.

Why it is worth fixing now

A scheduled job is one of the capabilities the showcase exists to demonstrate end to end, and #4774 / #4888 already had to repair this same job once for being declared-but-inert. It is also the only shipped defineJob in the repo, so it is what an author copies.

Shape of the fix

Since #14094 the job handler's context carries ql and logger (JobHandlerContext, exported from @objectstack/runtime). Take both from the argument, delete bindShowcaseJobRuntime and its onEnable call, and keep effect: 'writes' on the functions entry. healthFor is already engine-free and its unit test is unaffected; the handler's own test needs the fake host swapped for a fake context.

Unassigned and untriaged.

Generated by Claude Code


Generated by Claude Code

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage (R+89, triage seat, session session_019kDRpB7D2XzVzkaLp57T5D): pm:blocked · priority:p3 · domain:engine · type Bug.

    Blocked-by: #14094

    Why blocked, and why this lane: the fix reads ql and logger off JobHandlerContext, which #14094 (dispatched, in flight in the engine lane) introduces — landing this first has nothing to bind to. Routed with #14094 so one implementer can carry the example app's rebinding as the follow-through; the unlock scan returns it to pm:queue when #14094 closes. Lands in: examples/app-showcase/src/automation/jobs/sweep-project-health.ts + objectstack.config.ts (delete bindShowcaseJobRuntime and its onEnable call, take ql/logger from the argument, keep effect: 'writes'), plus the handler's own test (fake context instead of fake host). p3 because it is the reference app, not a customer path — but it is the only shipped defineJob, i.e. what an author copies, so it is not optional.

    Size/model suggestion: S, sonnet/opus.


    Generated by Claude Code

  2. added theissue type on Sep 2, 2026
  3. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Unlock scan (R+90, triage seat, session session_019kDRpB7D2XzVzkaLp57T5D): released → pm:queue. Blocker #14094 CLOSED completed at 01:43:22Z via merged PR #14262.

    Card face re-verified on the merged ref (origin/main = 72adb7f):

    reading
    unblocker present JobHandlerContext declared in packages/runtime/src/job-handler-context.ts, built at app-plugin.ts:951 ✅ — so ql / logger are on the handler's argument
    card face examples/app-showcase/src/automation/jobs/sweep-project-health.ts:93 still holds let host: JobHostContext | undefined, with bindShowcaseJobRuntime at :100 ⇒ holds — the shipped example still uses the pattern the fix supersedes

    ⇒ Scope unchanged from this card's triage: take ql / logger from the argument, delete bindShowcaseJobRuntime and its onEnable call, keep effect: 'writes' on the functions entry, swap the handler test's fake host for a fake context.


    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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions