fix(spec): replace the croner-refused cron example in the DisasterRecoveryPlan docblock - #16415
Open
huangyiirene wants to merge 2 commits into
Open
fix(spec): replace the croner-refused cron example in the DisasterRecoveryPlan docblock#16415huangyiirene wants to merge 2 commits into
huangyiirene wants to merge 2 commits into
Conversation
…overyPlan docblock
The `DisasterRecoveryPlanSchema` `@example` spelled its six-hourly backup
schedule `'0 0/6 * * *'`. `0/6` is Quartz-style stepping, and `croner` — the
only cron parser the platform runs, reached via `CronJobAdapter` -> `new Cron()`
— refuses it:
TypeError: CronPattern: Syntax error, stepping with numeric prefix ('0/6')
is not allowed. Use wildcard (*/step) or range (min-max/step) instead.
Measured against the croner 10.0.1 copy installed for
`@objectstack/service-job`, with the sibling example `'0 2 * * *'` as the
positive control (accepted). The replacement `'0 */6 * * *'` is accepted and
fires at the same instants; it is the spelling this schema's own tests already
use.
Comment-only: no schema, no export, no accept-set movement. The docblock does
publish into the shipped `dist/system/index.d.ts`, so the change is
user-visible and carries a changeset.
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
Co-authored-by: Claude <noreply@anthropic.com>
… closes the docblock The wildcard-step form croner's own error message suggests cannot be written inside a `/** ... */` block comment: the step separator is the comment terminator, so the file stops parsing. Measured — esbuild refused disaster-recovery.zod.ts at the example's own line, column 26, during `pnpm --filter @objectstack/spec build`. The enumerated equivalent carries no such sequence, is accepted by the same croner 10.0.1 copy, and was measured to fire at the identical instants (00:00, 06:00, 12:00, 18:00). Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 130 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
huangyiirene
marked this pull request as ready for review
September 6, 2026 21:24
huangyiirene
enabled auto-merge
September 6, 2026 21:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #15945
One character-level edit to a TSDoc
@example, plus its changeset. The interesting part is the measurement, and one thing the card got wrong.The measurement the card asked for
Triage was explicit that it had not run
croner, so the card's central claim was inherited, not measured. Measured here against thecroner10.0.1 copy installed for@objectstack/service-job— the same libraryCronJobAdapterhands every scheduled expression to (packages/services/service-job/src/cron-job-adapter.ts:130,new Cron():'0 0/6 * * *''0 0,6,12,18 * * *''0 */6 * * *''0 2 * * *':19/:58The refusal, quoted:
The control matters: without an ACCEPTED result in the same run, a REFUSED reading is indistinguishable from a probe that cannot construct any job at all. Both spellings of six-hourly were measured to fire at identical instants —
2026-09-06T06:00Z, 12:00Z, 18:00Z, 2026-09-07T00:00Z— so this is an equivalent, not an approximation.The trap: the spelling croner itself recommends is not writable here
croner's error message suggests
*/step, and that is the spellingdisaster-recovery.test.ts:168andintegration/connector.test.ts:238use. It cannot be written at this site: the example lives inside a/** ... */block comment, and the wildcard-step separator is the comment terminator. Writing it closed the docblock mid-example and the file stopped parsing — measured, not reasoned:That is why this PR ships the enumerated form
'0 0,6,12,18 * * *'— the card's own second option — rather than the wildcard-step form. It is croner-accepted, fires identically, and carries no comment-terminating sequence. The failure is loud (the build refuses it), so this is an authoring hazard rather than a latent defect, but it is worth knowing before anyone "tidies" this example toward the more idiomatic spelling.Anchors: every one re-read on current
main, and they had driftedBase
fd75728bc6.disaster-recovery.zod.ts:187— the defect:204disaster-recovery.zod.ts:19— sibling example'0 2 * * *':19disaster-recovery.zod.ts:57— the.describe():58disaster-recovery.zod.ts:238— the DR-drill schedule:255disaster-recovery.test.ts:168— the wildcard-step spelling:168expression.zod.ts:25— "No cron syntax is judged at parse time":25One card claim measured FALSE
The card and the triage comment both state the docblock "lands in customer-facing generated docs (
content/docs/references/system/disaster-recovery.mdx)". It does not. The string0 0/6occurs exactly once in the whole tracked repository — at the source line itself. The generated page carries only the.describe()strings, which already spelled the good example (cron+0 2 * * *) at rows 33 and 140.The premise survives anyway, because the docblock publishes somewhere else — the shipped type declarations:
That is the text an editor shows on hover for every consumer of
@objectstack/spec, which is why this change is user-visible and carries a changeset.packages/spec/scripts/build-docs.tsnever reads TSDoc@exampleat all — it synthesises its import examples from the real export surface, deliberately — so the mdx omission is by design and is not filed as a finding.The
N/Msweep, re-taken with its control litRe-taken rather than inherited, and widened from triage's
packages/spec/srcto the wholepackages/specpackage (1587 files), then topackages · examples · content · skills · apps · scripts:N/M-shaped string literals: 35 inpackages/spec, 248 repo-wide. These are true-positive non-cron hits — a date'7/28/2026', CIDRs'192.168.1.0/24'and'10.0.0.0/8', prose like'404/405/501', test names like'SEAM 2/3'. The matcher demonstrably returns hits.packages/spec('0 2 * * *','*/15 * * * *','0 0 * * 0', …), so the "exactly 1" in stage B is a reading and not a broken classifier.Triage's finding is confirmed and now holds over a wider corpus: there is no sweep owed, and nothing else in the repo is a sibling of this defect.
Clause ②: no
A docblock example. No schema, no export, no accept-set movement, no cron parsing added anywhere;
CronExpressionInputSchemais untouched. Measured rather than asserted: rebuilding@objectstack/specand diffing all 64 emitted.d.tsfiles against the pre-edit build gives 1 file changed, 1 line changed, and that line is the comment. No dependent package can observe a type-level difference.Deliberately out of scope, per the dispatch: the wider
formulacronEnginevscronergrammar divergence (5 of 32 patterns) is reported on #15035 and is the spec lane's to rule on. It is not addressed here.Verification
Repository
objectstack-ai/objectstack, head0e1867d18a, basefd75728bc6.pnpm --filter @objectstack/spec build— exit 0 (check-dts-emitted: 34/34 declaration file(s) present)pnpm --filter @objectstack/spec typecheck— exit 0 (check:test-typecheck: OK)pnpm --filter @objectstack/spec test— exit 0, 482 files / 13102 tests passedpnpm --filter @objectstack/spec check:generated— exit 0,All 15 generated artifacts are up to datepnpm lint(eslint . --no-inline-config) — exit 0, whole repository, not narrowed, 64sscripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackagainst the real change set: 67 commands, 66 exit 0 and 1 declared to CI. Two came back exit 3PREREQUISITE NOT MET— a code that measures nothing and is not a finding.check:doc-formula-expressionswas re-run green (exit 0) after building the two prerequisites it named;check:dual-build-cjs-loadsneeds all 86 packages built and is declared to CI, which builds fresh.pnpm check:nul-bytesexit 0, plus a direct control-character scan of both edited files — clean, with its positive control lit (the same expression finds planted BEL and ESC bytes).Test Core (5/6)is being killed at its 30-minute wall on a large fraction of runs right now (#16173). If it is red, read that shard's duration first.Not for merging
Draft, by instruction. No governed surface in the diff (
packages/spec/src/**and.changeset/**only), but the merge call is the PM's regardless.Generated by Claude Code