Skip to content

docs(qa): RUNNER.md reads the connector self-URL from /meta/connector and states the scheduled-work switch - #24156

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24119-runner-facts
Oct 17, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24119-runner-facts

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24119
Clause-②: no

Docs only: docs/qa/platform-checklist/RUNNER.md, the two runner facts the card names, both inside "Environment facts the runner should not re-derive". Nothing else in the file moved. The "The record title" section is untouched, because #24127 may change it. No area file, no product code, no changeset: the diff ships nothing from any package, and the seat applies skip-changeset at review.

Authored by the os-dev dispatched for this card by the domain:devx seat 2, session session_016PVjjuVPte5XEJvaQx1E4t, branch claude/issue-24119-runner-facts.

How both facts were re-measured

Both were measured on main at 2889760a5, the branch point, by reading the code and by two os dev boots of examples/app-showcase. The boots ran after a full pnpm build, on the RUNNER's canonical boot line (objectstack dev --ui --seed-admin -p PORT -d file:...):

  • Boot A: -p 47311, environment untouched.
  • Boot B: OS_PORT=47312 OS_AUTOMATION_SCHEDULED_WORK_ENABLED=1, -p 47312.

Both boots served the same examples/app-showcase/dist/objectstack.json. The build compiled it with no OS_PORT, so its two self-pinging connectors hold providerConfig.baseUrl: http://127.0.0.1:3000. Nothing listened on 3000.

Passage 1: the connector self-URL check

Old (the bullet's Check: sentence; the rest of the bullet is unchanged):

**Check:** before scoring any connector clause, `GET /api/v1/automation/connectors` and read the
instance `baseUrl` — if it says `` and your server does not listen there, the
fixture is misconfigured, not blocked.

New:

**Check:** before scoring any connector clause, read the instance's own metadata —
`GET /api/v1/meta/connector/showcase_status_api`, field `item.providerConfig.baseUrl`,
which is the value `resolveShowcaseSelfUrl()` produced
(`examples/app-showcase/src/system/connectors/index.ts`). ⛔ Not
`GET /api/v1/automation/connectors`: that route lists registry descriptors — `name`,
`label`, `type`, `description`, `icon`, `origin`, `state`, `degradedReason`, `actions`
(`getConnectorDescriptors()`, `packages/services/service-automation/src/engine.ts`) —
and carries no `baseUrl` at all. On `os dev` the value follows the serving process's
environment, not the compiled artifact. Measured on `main` at `2889760a`: `-p 47311`
alone answered `http://127.0.0.1:3000`, and `showcase_declarative_connector_ping`
(fired by a `showcase_task` create) failed `fetch failed`; `OS_PORT=47312` with
`-p 47312` answered `http://127.0.0.1:47312` and the same flow completed, while
`dist/objectstack.json` still held `http://127.0.0.1:3000`. Only an artifact-only boot
(`os start --artifact`) freezes the value at build time (the `self-url.ts` header). If
it names a port your server does not listen on, the fixture is misconfigured, not
blocked.

Sources and measurements:

  • GET /api/v1/automation/connectors is served by the parts[0] === 'connectors' branch of packages/runtime/src/domains/automation.ts. That branch answers getConnectorDescriptors() from packages/services/service-automation/src/engine.ts, whose projection is name, label, type, description, icon, origin, state, degradedReason, actions. It has no baseUrl and no providerConfig. Measured on both boots: every row's keys were exactly actions, description, icon, label, name, origin, state, type, and the string baseUrl does not occur in the body.
  • GET /api/v1/meta/connector/showcase_status_api answers the declared item. Its item.providerConfig.baseUrl is the value resolveShowcaseSelfUrl() produced (examples/app-showcase/src/system/connectors/index.ts). Boot A answered http://127.0.0.1:3000. Boot B answered http://127.0.0.1:47312, while the artifact on disk still said 3000.
  • The materialized connector dials that value. On boot A, creating a showcase_task fired showcase_declarative_connector_ping, which failed with Node 'ping' failed: connector_action(showcase_status_api.request) failed: fetch failed. On boot B the same create produced a completed run whose ping.body carried status: 'ok'.
  • The value is read at boot, not at build, for this reason. The showcase config is a host config: its plugins: array holds instances (isHostConfig, packages/cli/src/utils/plugin-detection.ts). So the serve child loads objectstack.config.ts itself and wraps it in new AppPlugin(config) (packages/cli/src/commands/serve.ts), and resolveShowcaseSelfUrl() reads the serving process's environment. os dev hands -p to that child as --port and never exports OS_PORT (its localEnv, packages/cli/src/commands/dev.ts). So the bullet's existing claim that -p alone is not enough still holds, and that part was left as written.

Disproved half of the card's reading. The card recorded that "GET /api/v1/meta/connector shows the build-time http://127.0.0.1:3000". On an os dev boot that value is not build-time. It follows the serving process's environment: boot B answered 47312 over an artifact holding 3000. 3000 is what any boot without OS_PORT or SHOWCASE_SELF_URL answers. The new text says this, so the next runner does not reason from the artifact.

Passage 2: scheduled work

Premise correction. RUNNER.md had no scheduled-work passage, so there was nothing stale to rewrite:

  • git show c91af8ed6:docs/qa/platform-checklist/RUNNER.md | grep -ci schedul prints 0 (exit 1).
  • The file is byte-identical between c91af8ed6, the card's measurement commit, and 2889760a5: git diff --stat prints nothing.
  • git merge-base --is-ancestor c91af8ed6 2889760a5 exits 0. A positive answer proves itself, even on this shallow checkout.

The fact was missing, not stale. The card's Done-when ("RUNNER.md states both facts as the runtime answers them") is met by adding it as one new environment-fact bullet, right after the connector bullet. Old text: none.

New:

- **Package-authored scheduled work is OFF on a stock boot — no `schedule` or
  `time_relative` flow binds and no packaged `defineJob` is scheduled unless you export
  `OS_AUTOMATION_SCHEDULED_WORK_ENABLED=1`.** The switch is an environment read,
  `resolveScheduledWorkEnabled()` / `resolveScheduledWorkPolicy()` in
  `packages/types/src/env.ts`: unset, empty, or anything other than `true` / `1` / `on` /
  `yes` (case-insensitive) is off, in every tenancy posture, and `os dev` sets nothing for
  you. Every binder reads that one answer — the automation engine's trigger bind and its
  `/_status` row (`packages/services/service-automation/src/engine.ts`), the schedule
  trigger (`packages/triggers/trigger-schedule/src/schedule-trigger.ts`), and AppPlugin's
  declarative-job loop, which logs `declarative jobs NOT scheduled — …` at info level
  (`packages/runtime/src/app-artifact-handlers.ts`). It does not gate platform-internal
  jobs (approvals escalation, the lifecycle Reaper, the messaging dispatch loop).
  **Check:** the boot banner. Measured on `main` at `2889760a` with the canonical boot
  below: a default boot printed `32 flow(s) 19 bound` and `1 flow declares a 'schedule'
  trigger but is NOT bound — disabled by deployment policy …: showcase_scheduled_digest`
  (the same line for `time_relative`: `showcase_task_due_reminder`), and
  `GET /api/v1/automation/_status` answered `bound: false` with that reason for both; the
  same boot with the switch exported printed `21 bound`, `_status` answered
  `bound: true` for both, and `showcase_scheduled_digest` completed its first run
  (`trigger.type: 'schedule'`) within a minute. **Fix:** export the switch before the boot,
  beside `OS_PORT`. ⛔ Do not score a clock-driven clause on a default boot, and do not
  file the unbound flow: it is the deployment policy working, not a trigger defect.

Sources and measurements:

  • The reader is resolveScheduledWorkEnabled() in packages/types/src/env.ts. It reads OS_AUTOMATION_SCHEDULED_WORK_ENABLED and is truthy only for 1, true, on or yes. Its docblock reads "Default OFF, in every posture and every kernel". resolveScheduledWorkPolicy() and scheduledWorkDisabledReason() in the same file are what the engine's bind, the /_status row and the schedule trigger read. AppPlugin's job loop logs declarative jobs NOT scheduled — … at info level (packages/runtime/src/app-artifact-handlers.ts, the !resolveScheduledWorkEnabled() branch).
  • os dev does not set it. Neither packages/cli/src/commands/dev.ts nor serve.ts names the variable, and dev's localEnv does not carry it.
  • Boot A's banner printed Flows: 32 flow(s) 19 bound … and the two NOT bound — disabled by deployment policy lines, for showcase_task_due_reminder and showcase_scheduled_digest. _status answered bound: false for both, with the policy reason.
  • On boot B the banner printed 21 bound, and _status answered bound: true for both. showcase_scheduled_digest completed its first run at 2026-10-17T05:51:55Z with trigger.type: 'schedule', less than a minute after boot.

Gates

All gates below were run on the final head 4094dd433, which is d76548150 (the edit) plus a merge of main at 6dede7a51. The merged commit touches none of the paths cited above. Each exit code was captured before any pipe.

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 13 commands from a 1-path change set. Every one exited 0: check-ci-filter-parity, check-closing-keyword-parity and its --self-test, check-comment-mask-corpus, @objectstack/lint check:doc-formula-expressions, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:platform-checklist, check:refd-timer-probe and check:watch-hint-literal.
  • check:platform-checklist printed: check-platform-checklist: OK — 16 areas, 327 items (322 active, 1 planned).
  • --ran reconciliation: 13 derived famil(ies) accounted for — 13 run, 0 NOT-MEASURED (a DERIVED zero — all 13 recorded an exit code and none of them is 3).
  • node scripts/pm/check-governed-merges.mjs --branch claude/issue-24119-runner-facts: 0 of 1 path(s) hit the register and NOT governed, 42 changed lines.
  • CI check-runs had not concluded when this PR was opened.

Acceptance notes

  • The area files already name the switch per item (automation.json, integration-system.json, platform-core.json, approvals.json). The new bullet states it once, for every item and every runner.
  • Not measured: serve.ts says that on an os dev boot of a host config, the dev artifact door's copy of the stack replaces the config wrap's copy on the first artifact reload. After a watch rebuild, /meta/connector would therefore follow the recompiled artifact. Whether that recompile sees an exported OS_PORT was not measured. Both boots above were cold boots with no rebuild. No carrier.

Generated by Claude Code

…facts as the runtime answers them

The connector self-URL check pointed runners at GET /api/v1/automation/connectors
for a baseUrl that route never carries; it now reads the instance's own metadata
(GET /api/v1/meta/connector/showcase_status_api, item.providerConfig.baseUrl) and
records what a dev boot answered with and without OS_PORT.

Package-authored scheduled work being off by default
(OS_AUTOMATION_SCHEDULED_WORK_ENABLED) had no environment fact at all; it gets one,
with its reader, the binders that consume it, and a measured default/on boot pair.

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

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · PR #24156 (draft, head 4094dd433, Fixes #24119) · domain:devx seat 2 · session_016PVjjuVPte5XEJvaQx1E4t · 2026-10-17T06:25Z

Checked on GitHub and against the sources, not on the report's say-so.

  • Shape:
    • 1 file, docs/qa/platform-checklist/RUNNER.md, +39 / −3, inside the claim's surface. The "The record title" section is untouched.
    • Not governed: check-governed-merges --pr 24156 reads 0 of 1 path.
    • The body opens Fixes #24119, then Clause-②: no.
    • It is docs only, so the seat applied skip-changeset in this act.
  • Fact 1, connector self URL: corrected.
    • The Check now reads GET /api/v1/meta/connector/showcase_status_api → item.providerConfig.baseUrl, the value resolveShowcaseSelfUrl() sets (examples/app-showcase/src/system/connectors/index.ts:64).
    • It names GET /api/v1/automation/connectors as the wrong place. This seat read getConnectorDescriptors() in service-automation/src/engine.ts: it maps name, label, origin, state, degradedReason and actions, with no baseUrl.
    • The card's "build-time 3000" reading is disproved for os dev by a measured boot pair (47311 → 3000; OS_PORT=47312 → 47312 while the artifact held 3000).
  • Fact 2, scheduled work: added, since it was missing rather than stale.
    • RUNNER.md had no scheduled-work passage (grep -ci schedul = 0). A new environment-fact bullet now states the switch.
    • This seat read resolveScheduledWorkEnabled() in packages/types/src/env.ts:237: unset is off, and on means 1, true, on or yes.
    • The bullet also names the binders that read it and the measured default/on boot pair (19 → 21 bound, /_status bound:false → true, showcase_scheduled_digest ran).
    • This stays inside the dispatched file, so it is not a surface breach.
  • Gates: local, 13 derived, 13 exit 0, check:platform-checklist included. CI on this head: 31 success, 7 skipped, and 1 failure, Check Changeset, which the label answers.
  • No qa-run record, per ruling C on [Decision] checklist-test files one open qa-run issue per re-run: 40 of 42 open qa-run issues are re-runs that verified ledger edits. Keep, one record per batch, or file only on a problem? #24127. The one carrier: none note stays in the PR's Acceptance notes.
  • Landing: once every check on this head reads green, the seat readies the PR, arms auto-merge, and confirms the merge on origin/main.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 17, 2026 06:27
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 17, 2026 06:27
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 17, 2026
Merged via the queue into main with commit c40506a Oct 17, 2026
43 of 44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24119-runner-facts branch October 17, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants