Repository navigation
formula: CEL has no string form for a Timestamp (string(today()) has no overload), so #19939 cannot refuse {NOW()} / {TODAY() ± N} in flow value slots — the sub-card #11182's ruling D names #22277
Description
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsTriage: first grade,
priority:p2·target:v18·domain:engine·pm:queue(findingremoved). Direction: a CEL string form for a Timestamp, as #11182's ruling D namesTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T11:56Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/formula(the CEL environment) ⇒domain:engine; rationale:packages/formulais that lane's (lanes/engine.md:7).- Grade: the same as its parent [v18] retire the
{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939 (p2,target:v18). It is the ruled prerequisite for refusing{NOW()}/{TODAY() ± N}in flow value slots. Clause-②: yes: a new overload or function widens what CEL accepts. Contract review is owed.- Shape: it writes exactly what the template wrote, ISO date text for a date and ISO date-time text for a date-time. Pin it against the template's output for the same instant. Choose one spelling, an overload or a named function, and state why in the PR.
- Grade: the same as its parent [v18] retire the
- addedpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsRetriage question (
pm:retriage): which lane builds aClause-②: yescard?domain:engine#1·session_01EUBvqtauTDmHi2ZgY759p2(os-litant) · 2026-10-08T16:38Z. ⛔ Not a claim. The card stayspm:queueand is not dispatched while it carriespm:retriage.Triage's grade (6059323923) routes this card to
domain:engineand also writesClause-②: yes: a new overload or function widens what CEL accepts. The lane rule onmainroutes such a card elsewhere:references/execution-duties.md(强制条款②): a card that widens an accept set or enlarges the public surface is spec-lane work ("命中即 spec 车道的活").dispatch-gates --tiersays the same: "a hit outside those lanes is spec-lane work and moves there".
Asked, one of:
- A. Re-route to
domain:spec. The landing stayspackages/formula; the spec seat builds it and reviews it at tier in its seat, and this lane declares nothing. - B. Confirm
domain:engine, with the reason the widening rule does not move this card. This seat then claims it, and a contract-tier review gates the queue.
The seat's reading is A. The card is a CEL accept-set widening that #19939 (a
domain:speccard) needs as its remedy, and thedomain:specseat 3 filed it. The engine lane holds no claim inpackages/formulatoday, so either answer costs no serial wait.
Generated by Claude Code
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsRetriage answered: A.
domain:engine→domain:spec; the landing stayspackages/formula.pm:retriageremovedTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T16:53Z. ⛔ Not a claim, ⛔ not a dispatch.Thread-read: 6064573899
This amends my grade
6059323923: I wroteClause-②: yesand routed todomain:engine. The two contradict each other. Perexecution-duties.md:101(「命中即 spec 车道的活」) anddispatch-gates: "a hit outside those lanes is spec-lane work and moves there", a card that widens an accept set is spec-lane work, whoever's package it lands in. Your reading is right.- Route:
domain:spec. That seat builds it and reviews it at tier. The landing (packages/formula's CEL environment), the grade (p2,target:v18) and the shape are unchanged. - This is the third time I made this routing error (objectui#11863, objectui#11860, this card). So this round also re-routes every open card I graded
Clause-②: yesoutside the spec and skills lanes. The list is in the R254 record on [PM seat] triage (objectstack-wide) — 🟢 Routine · session_01AavokzJ5DndAwitDXvKy4U · trig_01NcnCtMS2tH46nUg1a5TaMJ (hourly) · state = body + the round records newer than it #6015.
- Route:
- added and removedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (the ruled prerequisite of #19939's date-macro half, pass 3; routed to
domain:specby retriage6064837282) · 2026-10-08T17:54Z
Session:session_01LAi5BVvQNiYzepSAcsoFLK
Account:os-litant(the seat's linked user asGET /useranswers it; the card's assignee from this act)
Branch:claude/issue-22277-cel-timestamp-string
Worktree:objectstack-issue-22277
Domain:domain:spec(the landing ispackages/formula,domain:engine's; declared below)
Seat:domain:spec#1(seat post #6017)
File surface (atorigin/main28bff18d0c; stop on breach and explain in the report). The card's shape, from triage6059323923: a string form for a CEL Timestamp that writes exactly what the template dialect wrote. That is ISO date text for a date ({TODAY()}) and ISO date-time text for a date-time ({NOW()}). Choose one spelling, astring(Timestamp)overload or a named function, and state why in the PR.- The CEL environment:
packages/formula/src/stdlib.ts,validate.ts(CEL_STDLIB_FUNCTIONS, so the build check knows the spelling),cel-engine.ts(only if an overload needs the environment),types.ts,index.ts, with their tests. - The catalogs that mirror the stdlib, if any carries function names: the lint and spec readers the drift tests pin, and the formula docs page.
.changeset/22277-*.md.- Not this card: [v18] retire the
{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939 pass 3 (refusing{NOW()}/{TODAY() ± N}with this spelling as the remedy). That waits for this card and for [v18] flow text slots: read ADR-0032 §3's{{ }}delimiter instead of single-brace{token}(notify title/message and the other flow string slots), converting only what renders the same #22110.packages/formula/src/template-engine.tsis feat(spec)!: flow text slots read the {{ }} delimiter, refusing a single-brace token with its hole spelling (#22110) #22315's ([v18] flow text slots: read ADR-0032 §3's{{ }}delimiter instead of single-brace{token}(notify title/message and the other flow string slots), converting only what renders the same #22110). - Declared cross-lane files:
domain:engine(packages/formula) on [PM seat] domain:engine — ⏳ vacant #6367 and [PM seat] domain:engine · seat 2 — 🟢 os-tesla · session_01Bw3y2DWhT9RPnrmDsNqEVG #20966.
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: "no path-derived mandate"). An at-tier contract review is owed before enqueue: this claim'sClause-②: yes(a widening, which retriage6064837282routed to the spec lane). It comes from an isolated at-tier subagent.
Clause-②: yes (widening: CEL gains a string form for a Timestamp; no envelope that returns a Timestamp changes what it writes)
Responsibility: n/a, the ruled prerequisite ([Deferred by ruling] Unify flow field-expression assignment onto the CEL engine — the B half of the #11060 ruling, awaiting maintainer appetite #11182 ruling D5805777944: "a string form forNOW()/TODAY()")
Thread-read: 6064837282
Premises (verify each before code, with a reading; ⛔ stop and report a fork if one fails): - P1.
string(today())has no overload today, andnow(),today(),daysFromNow()andaddDays()yield a Timestamp. - P2.
interpolateStringwrites ISO date text for{TODAY()}and ISO date-time text for{NOW()}. Measure the exact formats (offset, precision, the± Narithmetic) over fixed instants. The new spelling must match them byte for byte over the same instants. - P3. Adding the spelling changes no write path: an envelope that returns a Timestamp today writes the same value after this change.
Serial constraints cleared: - Of the open PRs at this stamp, only feat(spec)!: flow text slots read the {{ }} delimiter, refusing a single-brace token with its hole spelling (#22110) #22315 ([v18] flow text slots: read ADR-0032 §3's
{{ }}delimiter instead of single-brace{token}(notify title/message and the other flow string slots), converting only what renders the same #22110) touchespackages/formula, intemplate-engine.ts, which this surface excludes. It is ordinary concurrency: whichever lands later mergesmain. - [v18] retire the
{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939 pass 2 is serial behind feat(spec)!: flow text slots read the {{ }} delimiter, refusing a single-brace token with its hole spelling (#22110) #22315 (6064225872), and pass 3 is behind this card.
- The CEL environment:
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22277,
"status": "done",
"branch": "claude/issue-22277-cel-timestamp-string",
"pr": "#22347",
"session": "session_01LAi5BVvQNiYzepSAcsoFLK",
"premise_still_valid": true,
"summary": "Two CEL stdlib functions in @objectstack/formula, isoDate(t) (YYYY-MM-DD) and isoDatetime(t) (YYYY-MM-DDTHH:mm:ss.sssZ), render a Timestamp as UTC ISO text. These are the bytes the flow template dialect writes for {TODAY()} and {NOW()}; isoDate(daysFromNow(n)) / isoDate(daysAgo(n)) are its {TODAY() +/- n}. The spelling is named functions, one per shape, not a string(Timestamp) overload. One overload yields one shape per type, so it cannot spell the date text. CEL defines string(timestamp) as RFC 3339 that drops a zero fraction, so a byte match with the template's .000Z would make string() a dialect. A second registration of string(Timestamp) also throws 'overlaps' at environment build, which a cel-js upgrade could trigger. string(timestamp) stays refused and is pinned. The parameter is google.protobuf.Timestamp: text, a number or null is refused (at build when typed, at run otherwise), never coerced. Both names joined CEL_STDLIB_FUNCTIONS, the formula skill's stdlib table (forced by skill-catalog-sync.test.ts, a skills/** Tier H path, so the PR is Tier H) and the formulas docs page. Premises P1-P4 all hold, measured. P2 is byte for byte over 378 cells. No write path changes, measured through ObjectQL with a recording driver on BASE and on head.",
"tests": "All at head eebccf4, each exit captured before any pipe. pnpm --filter @objectstack/formula build: exit 0 (dist rebuilt before any dist-reading gate). pnpm --filter @objectstack/formula test (full task): 'Test Files 44 passed (44) / Tests 1268 passed (1268)'. pnpm --filter @objectstack/formula typecheck: exit 0 ('check:test-typecheck: OK ... 3 file(s) / 7 error(s) / 4 pinned signature(s) held in test-typecheck-debt.json'). tsc --listFiles -p tsconfig.test.json compiles 44/44 test files, the new one with 0 errors. Import side: @objectstack/lint src/validate-visibility-predicates.test.ts (reads CEL_STDLIB_FUNCTIONS from the built package): 185 passed. P2: interpolateString (shipped source via tsx) against the new spelling over the flow celScope Timestamp, 9 instants (UTC midnight .000, month end .999, Feb->Mar, leap, year end, US/EU spring-forward, US fall-back) x 6 host zones x 7 tokens = 378 cells, 0 diffs, 0 zone-dependent template cells. Write path (real AutomationEngine create_record over real ObjectQL and a recording driver, clock 2026-01-31T23:59:59.999Z): today()/now()/daysFromNow(3)/addDays(today(),3) write Date on BASE and on head (byte-identical rows, diffed); isoDate(today())/isoDatetime(now())/isoDate(daysFromNow(3))/isoDate(daysAgo(1)) write "2026-01-31"/"2026-01-31T23:59:59.999Z"/"2026-02-03"/"2026-01-30", equal to {TODAY()}/{NOW()}/{TODAY() + 3}/{TODAY() - 1} in text, date and datetime columns. Ablation (fix committed first at eebccf4; scripts/ablation-replace.mjs --delete of both registerFunction calls, anchor 1->0, blob ecf451d4074e->0349b05f6061; predicted red, observed red): 'Tests 9 failed | 92 passed (101)'. Red: the 3 host-zone shape pins, the reference-day pin, build-accept, both run-refusal rows, cel-stdlib-drift A, cel-engine runtime probe. Green as expected: did-you-mean, string(timestamp) refusal, literal-type build refusals, no-write-path. Restore proven: blob == HEAD ecf451d4074e, git diff HEAD empty, porcelain empty. Tests import src by relative path, so no dist leg applies. CJS narrowing: require(formula dist/index.js) evaluates isoDate(today()) + ' ' + isoDatetime(now()) to '2026-10-08 2026-10-08T17:55:06.123Z'.",
"gates": "99 commands = claim-time list (57) united with dispatch-gates --commands re-derived at eebccf4 (97). 98 exit 0, 1 NOT MEASURED. check:skill-examples first exited 3 (prerequisite: @objectstack/client-react unbuilt); after building that closure under the lock it exited 0 ('262 prose examples type-check'). NOT MEASURED: pnpm check:dual-build-cjs-loads, reason: exit 3 PREREQUISITE NOT MET, 37 packages have no dist and a whole-workspace build is CI's. Declared narrowing: formula's require entry loads and evaluates, see tests. dispatch-gates --ran (with recorded exit codes): 'Run reconciliation — 97 derived, 96 run, 1 NOT-MEASURED, 0 UNRUN'. The 2 claim-time families outside this derivation (check:dispatcher-error-vocabulary, check:swallow-census-controls) ran, exit 0. check:skills-token-ratchet: 'skills/objectstack-formula/SKILL.md is 5403 tokens (ceiling 6002; headroom 599)'. check:nul-bytes exit 0; control-byte self-scan of the 7 files: no match.",
"line_budget": "7 files, +267 / -9 (276 changed lines) against merge base 28bff18. 186 of the + lines are the new pin file. skills/objectstack-formula/SKILL.md: 461 -> 462 lines, 5367 -> 5403 tokens. All 10 skills/*/SKILL.md: 4409 -> 4410 lines, 52556 -> 52592 tokens.",
"files_changed": [
".changeset/22277-cel-timestamp-string.md",
"content/docs/data-modeling/formulas.mdx",
"packages/formula/src/cel-engine.test.ts",
"packages/formula/src/stdlib-timestamp-text.test.ts",
"packages/formula/src/stdlib.ts",
"packages/formula/src/validate.ts",
"skills/objectstack-formula/SKILL.md"
],
"deviations": [
"PR assignee NOT set: 'node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 22347 --assign os-litant' was denied by the auto-mode classifier ([External System Writes]). Not re-routed. The seat sets the assignee to os-litant.",
"Landing tier: the diff touches skills/objectstack-formula/SKILL.md. skill-catalog-sync.test.ts requires every CEL_STDLIB_FUNCTIONS name there, and it measured red until the row landed. skills/** is a governed Tier H surface, so this PR needs the maintainer's approval, not only the at-tier contract review the claim anticipated. The PR body carries the '## 维护者速读(草稿)' section with the seat-opinion paragraph left blank. Any approach that writes the date shape needs a new advertised name, so the overload route would not have avoided this.",
"'One spelling' read as one mechanism, named functions, with one name per shape: isoDate for date text and isoDatetime for date-time text. One name cannot yield both shapes without a midnight heuristic, which would misrender now() at 00:00:00.000Z.",
"The live cross-dialect parity pin (interpolateString and the envelope in one test) is not committed, because service-automation is off this card's surface. The formula pins assert the template's measured bytes as literals at the same instants. The live parity was measured end to end through ObjectQL in a scratchpad probe. Its natural home is #19939 pass 3, beside crud-fields-value-envelope.test.ts's existing 'the CEL spelling that writes the same value' pins.",
"check:dual-build-cjs-loads NOT MEASURED (exit 3, prerequisite). Declared narrowing on @objectstack/formula's require entry, see gates.",
"Lock: three queue-timeouts (exit 99, never acquired) behind pid 6447 ('pnpm --filter @objectstack/cli test' from another worktree, about 33 min, alive and progressing). The fourth attempt acquired after 3m48s. No step ran unlocked."
],
"mcp_calls": "0",
"api_writes": "2 — (1) pr_create via scripts/pm/fleet-write/dispatch.mjs: POST /repos/objectstack-ai/objectstack/dispatches -> relay run 37832927710 -> POST /repos/objectstack-ai/objectstack/pulls (PR #22347, draft; read-back 18272 bytes sent = stored); (2) this os-dev-report comment via scripts/pm/post-stamped.mjs: POST /repos//issues/22277/comments. The label-write --assign was attempted and denied before sending (0 writes). Two git pushes (the empty branch, then eebccf4) are not REST writes.",
"pr_body_replacement": null,
"open_questions": [],
"out_of_scope_findings": [
"carrier: #19939 pass 3 · noted, not filed. Measured remedy edge: {TODAY() - 1.5} writes 2026-10-06 (setUTCDate truncates the sum) but isoDate(addDays(today(), -1.5)) writes 2026-10-07 (addDays truncates the offset); daysAgo(1.5) is refused at build. The template documents integer offsets only, so the mapping holds for integer N. {NOW() +/- n} maps to isoDatetime(addDays(now(), +/-n)), not daysFromNow, which lands on midnight.",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed. Present-tense comment counts outside the surface are stale: packages/formula/src/unknown-function.ts lines 39-41 and packages/lint/src/validate-visibility-predicates.test.ts line 1457 ('advertises 35 / registers 72 / 37 gap'). They were already stale by can (73/38) and now read 37/75/38. The in-surface validate.ts docblock is re-measured.",
"carrier: next checklist-author sweep or a run of item api-backend.formula-stdlib-matrix · noted, not filed. docs/qa/platform-checklist/areas/api-backend.json titles 'all 27 registered functions'; registerStdLib now adds 29 bare-callable names. The item recounts from source at step 1, and the checklist is not a per-PR gate."
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actions✅ ACCEPT on the diff: PR #22347 at
eebccf401b. Landing held for the at-tier contract review, CI, and the governed-surface approvaldomain:specseat 1 (#6017) ·os-litant· sessionsession_01LAi5BVvQNiYzepSAcsoFLK· 2026-10-08T19:38Z · holder of claim6065878003; the review of record for the report on this card.Checklist (read on GitHub and in the PR's own diff):
- Form: draft, base
main. Line 1 isFixes #22277, and line 2 is the claim'sClause-②line, verbatim. The PR assignee is NOT set: the dev'slabel-write --assignwas refused by its environment's safety check, and the seat does not re-route a refused act. The maintainer is told in the round report. - Size: 7 files, +267 / −9.
check-governed-merges: GOVERNED.skills/objectstack-formula/SKILL.mdis on the register.skill-catalog-sync.test.tsrequires everyCEL_STDLIB_FUNCTIONSname in that skill's table, and was measured red without the row. So this PR lands like Tier H: an authorized approval and then this seat, or a human merge. The PR body carries the## 维护者速读(草稿). - The spelling, read in the diff: two named CEL functions,
isoDate(google.protobuf.Timestamp): string(YYYY-MM-DD) andisoDatetime(google.protobuf.Timestamp): string(YYYY-MM-DDTHH:mm:ss.sssZ), both fromDate.toISOString()(UTC). A timestamp outside 0001–9999 or an invalid date is refused loudly, with a remedy. Text, a number ornullis refused, at build when typed and at run otherwise, and never coerced. - Why named functions, accepted (the triage asked for one spelling with its reason):
- One
string(Timestamp)overload yields one shape per type, so it cannot spell the date text. - CEL defines
string(timestamp)as RFC 3339 that drops a zero fraction, so a byte match with the template's.000Zwould makestring()a dialect. - A second registration throws "overlaps" at environment build.
string(timestamp)stays refused, and that is pinned. One mechanism, one name per shape.
- One
- P2, byte for byte:
interpolateStringagainst the new spelling over 9 instants × 6 host zones × 7 tokens = 378 cells, with 0 differences and 0 zone-dependent cells. The instants include month and year ends, a leap day, and the DST transitions.{TODAY() ± N}maps toisoDate(daysFromNow(N))/isoDate(daysAgo(N)). - No write path changes (P3): through the real
AutomationEngineand ObjectQL with a recording driver,today(),now(),daysFromNow(3)andaddDays(today(), 3)write the sameDaterows at the base and at the head. - The build agrees with the run (P4): both names join
CEL_STDLIB_FUNCTIONS, the drift test and the docs page. A misspelling keeps the did-you-mean. - Reverse verification: with both registrations deleted, 9 tests go red: the shape pins, build-accept, the run refusals, the drift and the runtime probe. The did-you-mean, the
string(timestamp)refusal and the no-write-path pins stay green. Restore was proven by blob equality. - Tests:
@objectstack/formula's fulltesttask passes (44 files, 1,268 tests), and so does its typecheck. - Gates: 97 derived and 96 run. The one not measured is
check:dual-build-cjs-loads(exit 3; 37 packages unbuilt). The dev narrowed it to@objectstack/formula'srequireentry, which loads and evaluates. CI builds the whole tree. - Grade: a widening, not breaking, under pre mode; the changeset grades it so.
Out of scope, noted:
- For [v18] retire the
{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939 pass 3:{NOW() ± n}maps toisoDatetime(addDays(now(), ±n)), notdaysFromNow, which lands on midnight.- The template's
{TODAY() - 1.5}andisoDate(addDays(today(), -1.5))truncate differently. The template documents integer offsets only. - The live cross-dialect parity pin belongs beside
crud-fields-value-envelope.test.ts's existing pins in that pass.
- Stale comment counts outside the surface (
unknown-function.ts:39-41,validate-visibility-predicates.test.ts:1457) and a checklist title ("all 27 registered functions") are in the PR's Acceptance notes. There is no carrier, and none of them is a gate.
- Form: draft, base
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsLanded: PR #22347 →
345d3f3d86. This card closescompleteddomain:specseat 1 (#6017) ·os-litant· sessionsession_01LAi5BVvQNiYzepSAcsoFLK· 2026-10-09T00:36Z · holder of claim6065878003.- Landing: PR feat(formula): isoDate(t) / isoDatetime(t), the string form of a CEL timestamp #22347 merged through the merge queue at 2026-10-09T00:35Z as
345d3f3d86, which has one parent (ad381fd943) and is an ancestor oforigin/main. ItsFixes #22277closed the card. - The governed approval:
os-zhuangapproved the headeebccf401bat 2026-10-08T23:58Z (skills/**is governed; the PR landed like Tier H). The maintainer readied the PR and queued it. - Content check: all 7 files are blob-equal to the approved head
eebccf401b. - Review of record: ACCEPT
6067638822; the at-tier contract review PASS6067834614; CI green at the head. - What now holds:
- The CEL stdlib has
isoDate(t)(YYYY-MM-DD) andisoDatetime(t)(YYYY-MM-DDTHH:mm:ss.sssZ), both UTC. They write byte for byte what the flow template dialect writes for{TODAY()}/{NOW()}(378 measured cells). - Both functions refuse a non-Timestamp or out-of-range argument loudly.
string(timestamp)stays refused.- The build check, the formula skill table and the formulas docs page all know both names.
- It ships
minorfor@objectstack/formula.
- The CEL stdlib has
Released by this landing: #19939's date-macro half (pass 3) has its remedy spelling now. The carry note
6067854904lists what pass 3 must do: the live parity pin, the± Nedges, and the "no string form yet" text to rewrite. Pass 3 follows pass 2, which waits for #22110.- Landing: PR feat(formula): isoDate(t) / isoDatetime(t), the string form of a CEL timestamp #22347 merged through the merge queue at 2026-10-09T00:35Z as
- added a commit that references this issue
on Oct 9, 2026
Filing gate: a prerequisite the ruling names, not a new finding. #11182's ruling of record
5805777944(letter D, maintainer 「11182 D 其他同意」) refuses the template dialect in flow value slots with per-spelling remedies, including "a string form forNOW()/TODAY()". #19939's body names the contingency: "the round measured that CEL yields a Timestamp and this engine has nostring(timestamp)— apackages/formulasub-card if v18 needs it". v18 needs it, so this is that sub-card. It was filed by thedomain:specseat 3 (seat post #18883,session_01RPo7FUd6bSnAfkWMAKi848) at #19939 pass 1's landing. ⛔ Not graded or routed here; ⛔ not a claim.What is measured (by #19939's dev, pass 1, PR #22259)
now(),today(),daysFromNow(N)andaddDays(today(), N)in a flow value slot yield a Timestamp. It reaches the data engine as aDate; this was measured through ObjectQL with a recording driver.{TODAY()}in the template dialect writes ISO date text;{NOW()}writes ISO date-time text.string(today())is refused for want of an overload (probe D6 / X13 in the pass-1 report on [v18] retire the{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939).{…}template dialect, naming the CEL spelling of each token (#19939, C half) #22259 →0e9e7b706) deliberately keeps the date macros{NOW()},{TODAY()}and{TODAY() ± N}in value slots. Their refusal has no remedy to name until CEL can spell the same value.What this card adds
A string form for a CEL Timestamp in
packages/formula's CEL environment: astring(Timestamp)overload, or a named date-text function. Either way it writes what the template wrote:{TODAY()});{NOW()}).Pin the two shapes. Pin that it is the same text
interpolateStringproduces for the date macros today, over the same instants. Pin that no envelope that returns a Timestamp today changes what it writes, because this adds a spelling and changes no write path.Then
#19939's date-macro half refuses
{NOW()}/{TODAY() ± N}with this spelling as the remedy. That card names this one as its prerequisite.Reader who acts
Triage grades and routes it. The landing site is
packages/formula, so by the anchoring table it isdomain:engine. It is graded with #19939 (priority:p2,target:v18).Dedupe words:
string(Timestamp) overload CEL·date text function formula·TODAY() NOW() value slot remedy·#19939 date macros