Skip to content

docs(automation): add scheduled jobs and email templates guides - #10273

Merged
os-elon merged 1 commit into
mainfrom
claude/issue-10211-jobs-email-templates
Aug 21, 2026
Merged

docs(automation): add scheduled jobs and email templates guides#10273
os-elon merged 1 commit into
mainfrom
claude/issue-10211-jobs-email-templates

Conversation

@os-elon

@os-elonos-elon commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes#10211
Part of #10206

job and email_template are both first-class authorable metadata with a generated
reference page and no how-to. This adds the two guides and puts them in the Automation
sidebar.

Premise check

All three of the PM's claims verified against origin/main before writing:

ClaimVerdict
references/system/job.mdx 182 lines, references/system/email-template.mdx 95 linesconfirmed, exactly
automation/index.mdx mentions jobs in one bullet, no Card, no pageconfirmed
emailTemplates returns zero hits across the hand-written docsconfirmed — zero hits across all of content/docs/, generated pages included
canonical schema is EmailTemplateDefinitionSchema, not the removed EmailTemplateSchemaconfirmed — the legacy name survives only in comments and retirement pins

What the measurement changed

The card proposed leading jobs.mdx with "job versus a schedule-type flow". That
framing is right, but the obvious axis for it is wrong, so the page says so explicitly.

A schedule-type flow does not own a timer. ScheduleTrigger registers each
schedule-triggered flow as a job named flow-schedule: plus the flow name, and hands it
to the same IJobService (packages/triggers/trigger-schedule/src/schedule-trigger.ts).
So the two share their schedule forms, their adapter, and their cluster leader election —
including the per-job lock.acquire('job:' + name) in
packages/services/service-job/src/cron-job-adapter.ts. Cluster behaviour therefore
cannot be the deciding axis, and kernel/cluster.mdx §1's "a schedule-triggered Flow
fires once on every node" is a motivating bug class the document exists to close, not a
current-state claim. §5.1 is the current one, it still holds, and it is what the page
cross-links.

What actually decides is what runs, who may change it after deploy (job is
allowRuntimeCreate: false / allowOrgOverride: false — a code artifact by
construction, since handler names a key in the compiled bundle's function table), the
identity the run's writes carry, and where run history lands.

Deliberately not documented

Per the card's "an undocumented gap is smaller than a documented fiction":

  • clusterScope / leaderStrategy auto-wiring — schema accepts the annotations, no
    runtime consumes them (cluster.mdx §5.1 marks it Phase 4). The page documents the lock
    that does work and says nothing about declaring scope.
  • A jobs admin HTTP API — none exists. The only jobs routes on the client are data
    import jobs, unrelated. Observability is documented as sys_job / sys_job_run
    records plus IJobService.getExecutions.
  • variables[].type coercion — declared, and the renderer does not coerce by it. It
    is documented as an authoring hint; only required is described as enforced, because
    only required is (MISSING_VARIABLES).

Verification

Every TypeScript sample carries an os:check marker, so check:skill-examples
type-checks all three against the built @objectstack/spec — this is the acceptance
criterion "every code sample validates against the real schema", made machine-checkable
rather than asserted. Confirmed the blocks are actually extracted, not skipped:

• content/docs/automation/email-templates.mdx:20 → docs__automation_email-templates__1.ts
• content/docs/automation/email-templates.mdx:108 → docs__automation_email-templates__2.ts
• content/docs/automation/jobs.mdx:14 → docs__automation_jobs__1.ts
✅ 212 prose examples type-check against @objectstack/spec

Reverse-verified that green is not vacuous. Replacing schedule: with the legacy
cron: alias in the defineJob sample turned it red in the predicted direction:

error TS2353: Object literal may only specify known properties,
and 'cron' does not exist in type '{ name: string; schedule: ... }'

then restored, byte-identical, back to green. Both legs proved on disk by anchor count
before reading any result — the first mutation attempt was a perl -0pino-op (zero
match, exit 0, file untouched) and would have read as a passing ablation had the count
not been checked.

Gate union re-derived against the actual diff with node scripts/pm/dispatch-gates.mjs
and re-run at 98b5b91f3all green. Re-derivation added four families the
dispatch list did not name (check:doc-authoring, check:doc-formula-expressions,
check:pm-governed-merges, check:skill-frame-sync), pulled in by the .claude/ file
below.

The one file outside content/docs/automation/

.claude/workflows/docs-accuracy-audit.js — two added lines, generated by
node scripts/docs-audit/check-audit-scope.mjs --write. check:docs-audit-scope is on
this card's own gate list and fails for any new hand-written page until that
derived list is regenerated; the workflow runs in a node:vm with no filesystem, so it
cannot enumerate content/docs/** itself. Mechanical and required, but naming it here
since the card scoped the surface to content/docs/automation/.

No changeset: this PR publishes nothing (docs content plus one derived workflow list), so
it carries skip-changeset.

Out of scope, filed separately


Generated by Claude Code

Both kinds are first-class authorable metadata with a generated reference and
no how-to page: `job` had one bullet in automation/index.mdx and no page, and
`emailTemplates` returned zero hits across the hand-written docs.
- `jobs.mdx` leads with the job vs `schedule`-type flow decision. The two share
their timing: a schedule flow is registered against the same IJobService as
`flow-schedule:<name>`, so cluster leader election and the schedule forms are
identical for both. What differs is what runs, who may change it after deploy
(`job` is allowRuntimeCreate:false / allowOrgOverride:false), the identity its
writes carry, and where its run history lands.
- `email-templates.mdx` documents authoring against the canonical
EmailTemplateDefinitionSchema, the three-rung locale ladder (exact, en-US,
then deterministic for no-locale calls only), the notify-node path, and the
seed-not-clobber materialization into sys_email_template.
Every TypeScript sample carries an `os:check` marker, so check:skill-examples
type-checks all three against the built @objectstack/spec.
`.claude/workflows/docs-accuracy-audit.js` is regenerated by
`scripts/docs-audit/check-audit-scope.mjs --write` — mechanical, and required
by check:docs-audit-scope for any new hand-written page.
Part of #10206
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GawRwpD44VwBDVy3hs77AX
@os-elonClaude

Copy link
Copy Markdown
CollaboratorAuthor

Landed by the PM under the maintainer's explicit instruction — audit record.

This is a governed PR (.claude/workflows/docs-accuracy-audit.js, the #9866 collision), so under the standing regime the merge is the maintainer's own act and their click is the review record. It is being landed by an agent instead, on instruction. This comment exists so the entry is legible in check-governed-merges rather than reading as an unexplained agent merge.

Provenance — who, what, where. The repository owner, in the PM session driving epic #10206, 2026-08-20. Authorization verbatim: 「你帮我处理合并吧」. Their per-PR verdict on this one, verbatim: 「可合」 — 「证据规格最高的一张:premise 三核 + 反向验证还自纠了一次 no-op 突变」.

PM position, recorded rather than dropped. I stated before acting that an agent-executed governed merge removes the human click the fence treats as the review record, and that the audit would flag it. The maintainer instructed anyway. The decision is theirs; this is the record of it, not a silent reinterpretation of the rule.

Landing route. A direct merge is refused by repository rules (405 Changes must be made through the merge queue), so this PR was flipped ready and entered the merge queue via auto-merge — the only sanctioned path, and the same one every other PR in this repo takes. It lands only if the full-suite queue build passes; the queue has been dequeuing on an unrelated @objectstack/example-showcase failure tonight (see #10253), so a dequeue here would not be this PR's defect.


Generated by Claude Code

Merged via the queue into main with commit a774465Aug 21, 2026
30 checks passed
@os-elon
os-elon deleted the claude/issue-10211-jobs-email-templates branch August 21, 2026 01:39
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(automation): job and email_template are authorable, referenced, and have no how-to page

2 participants

@os-elon@claude