Repository navigation
test(qa): the ADR-0058 D7 expression ledger discovers the cron and template dialects - #15526
Merged
os-litant merged 3 commits intoSep 4, 2026
Merged
Conversation
ADR-0058 D7's conformance ratchet re-discovers expression surfaces by SCHEMA NAME, and `EXPRESSION_INPUT_SCHEMAS` listed only `ExpressionInputSchema` and `SettingsVisibilityInputSchema`. `DECLARES_EXPRESSION` requires a listed name to start immediately after the colon, so the 12 positions typed `CronExpressionInputSchema` / `TemplateExpressionInputSchema` could never match: the ledger reported a complete classification while carrying zero `cron` and zero `template` rows. Structurally blind, not merely un-updated. Widen the roster and classify what it finds, on one commit — adding the names alone turns the ratchet red with no rows to point at. Discovery: 26 surfaces -> 36 (+10). The delta is 10 and not 12 because a ratchet key is `file:field`: `api/export.zod.ts:cronExpression` (`:576`, `:706`) and `system/disaster-recovery.zod.ts:schedule` (`:57`, `:238`) each collapse two positions onto one key. Recorded in the `discoverSurfaces` docblock, with the 8 pre-existing collapses that are not all the same surface (filed as #15500). Five new rows, each naming the reader actually found by walking out from the declaration — and saying so when none was found: - `cron-job-schedule` (enforced/throw) — the one cron slot with an evaluator: `toBoundaryJobSchedule` lowers the envelope and refuses by name, croner runs it, AppPlugin contains the throw as an ERROR log plus a counter. - `cron-knowledge-refresh` (experimental) — surfaced, deliberately unscheduled. - `cron-declared-unwired` (experimental) — five slots on subsystems that were declared and never built; no evaluator found for any of them. - `template-prompt` (experimental) — `PromptTemplateSchema` has no consumer. - `template-title-format` (experimental) — the KEY has a build-time reader that never evaluates the template; the interpolation site is in objectui and was not measured from this checkout, so it is not written in as if it had been. `@objectstack/formula` cronEngine has zero consumers outside its own package, so no cron slot is syntax-checked anywhere; the rows say that rather than implying it. Per #15028 the envelope arm accepts any dialect, so the parse does not pin these to `cron`/`template` either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
…pression-ledger-cron-template
`check:doc-authoring` flagged 6 (file,id) pairs the new rows introduced: the `enforcement` and `note` fields are runtime strings that reach authors, operators and generated surfaces, and none of those readers can resolve a bare tracker id. The ids move to adjacent `//` comments, where the reader who CAN resolve them is already looking, and the strings say the same thing self-containedly. No baseline entry added — that file is maintainer-only and shrink-only, and adding one to get green is the path its own failure text refuses. The pinned population is unchanged at 831 sites. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 4, 2026
os-litant
marked this pull request as ready for review
September 4, 2026 20:10
os-litant
enabled auto-merge
September 4, 2026 20:11
os-litant
deleted the
claude/issue-15027-expression-ledger-cron-template
branch
September 4, 2026 20:42
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 #15027
ADR-0058 D7's conformance ratchet re-discovers expression surfaces by SCHEMA NAME.
EXPRESSION_INPUT_SCHEMASlisted two names, andDECLARES_EXPRESSIONrequires a listed name to start immediately after the colon — so every slot typedCronExpressionInputSchemaorTemplateExpressionInputSchemacould never match. The ledger reported a complete classification while carrying 14 rows, alldialect: 'cel'. Structurally blind, not merely un-updated.The roster widening and the rows that classify what it finds land on one commit, deliberately: the names alone turn the ratchet red with nothing to point at.
The delta is +10, not +12 — and that is a finding, not a reconciliation
The card counted 8 cron positions, the dispatch counted 12 (cron 9 + template 3). Both position counts are correct. The ratchet moved by 10:
A ratchet key is
file:field, notfile:line, so two declarations of one key name in one file are one key. Two of the new pairs collapse:api/export.zod.ts:cronExpression(:576,:706) andsystem/disaster-recovery.zod.ts:schedule(:57,:238). Both are genuinely the same surface twice, so one row is honest for each.⭐ Eight keys already collapsed that way before this change, and at least three of them join surfaces that are not the same —
data/field.zod.ts:requiredWhencovers both the server-enforcedFieldSchemagate and theInlineGridColumnSchemacell whose own describe says "nothing on the write path reads it". That is a separate defect in the instrument, filed as #15500 and deliberately not touched here: changing the key shape re-points everycoversentry in the ledger. The arithmetic and the hazard are recorded in thediscoverSurfacesdocblock so the next author does not read a green ratchet as "every declaration is classified".The five new rows, and what was actually measured
Every
enforcementnames what a reader hunt found by walking out from the declaration. Where the hunt found nothing, the row says so instead of borrowing a neighbour's.cron-job-scheduleenforced/throwsystem/job.zod.ts:expressiontoBoundaryJobSchedule→CronJobAdapter→ cronercron-knowledge-refreshexperimentalai/knowledge-source.zod.ts:croncron-declared-unwiredexperimentaltemplate-promptexperimentalai/model-registry.zod.ts:system,:usertemplate-title-formatexperimentaldata/object.zod.ts:titleFormatThree measurements worth pulling out, because each one changed a row:
toBoundaryJobSchedulelowers the envelope and refuses by name; AppPlugin contains the throw as an ERROR log plus ajobScheduleFailuresTotalcounter and the job does not run. Cron syntax is never judged on that path.@objectstack/formulacronEngine has zero consumers outside its own package. So no cron slot anywhere is syntax-checked. The rows say that rather than implying a validator exists.template-title-formatsplits two questions on purpose.packages/spec/liveness/object.jsonclassifies the keylive("objectui{{record.field}}interpolation") — that ledger asks whether anything READS the key. This one asks what EVALUATES the expression. The only interpolation site named is in the sibling repo objectui, which is not in this checkout, so it is not written intoenforcementas if it had been measured. The build-time reader that does exist (validateRecordTitle, reportingtitle-format-retired) reads that the key is present and never looks at the template text; the server-side title resolver deliberately never reads it at all.Reverse verification — both halves are load-bearing
Two legs, run against the committed tree (the ledger is imported by relative path inside the package, so no
dist/is involved and no rebuild applies):UNCLASSIFIED, 0STALEUNCLASSIFIED, 10 keysSTALELeg A proves discovery genuinely finds the 10 keys; leg B proves the roster widening is what makes them visible at all. Each mutation was confirmed on disk before the run (occurrence counts of the removed and injected text), each restore was proved by an empty
git diff HEAD, and both files were finally hash-compared against their HEAD blobs.One bounded in-place correction, named here because it is a correction
cel-flow's comment read "Connector-attached sync (ConnectorSchema.syncConfig) declares no expression surface; nothing to re-point at." Widening the roster falsifies its first clause:syncConfig.scheduleis a declared expression surface — a cron one, invisible to discovery when that sentence was written. The comment now says it declares no CEL surface to re-point that cover at, and points atcron-declared-unwired. Same file, same defect class, no new verification surface.Verification
Gate union derived on the merged tree with
dispatch-gates --commands --repo objectstack-ai/objectstackfrom the paths actually changed, then run atab90950f0c0— the final commit: 42/42 green.check:doc-authoringwas genuinely RED first, and the fix is a second commit: the newenforcement/notefields are runtime strings, and I had put six tracker ids inside them. The ids moved to adjacent//comments. No baseline entry was added — that file is maintainer-only and shrink-only, and its pinned population is unchanged at 831 sites.Also on
ab90950f0c0:@objectstack/dogfoodtypecheckclean, andtsc --listFilesconfirms both edited files are in the program, so that green covers this diff rather than skipping it.vitest run test/expression-conformance.test.ts— 3/3 pass. Dependency closure built first.No changeset: this diff is tests-only inside
@objectstack/dogfood, which is"private": trueand releases nothing, so the Check Changeset step's route 2 applies and theskip-changesetlabel is the PREFERRED exemption. Labelled accordingly.Left alone, on purpose
#15028 is open and remains open:
CronExpressionInputSchemapins the dialect only on its bare-string arm, so a cron-typed slot green-parses acelenvelope. That weakens the parse-level enforcement these rows describe, and the rows name it rather than papering over it. Out of scope here.The five
cron-declared-unwiredslots and the two prompt keys are ADR-0049 enforce-or-remove candidates. Each wants its own look; classifying them honestly is what this card asked for, and a sweep is not.🤖 Generated with Claude Code
Generated by Claude Code
Generated by Claude Code