Deprecate now() in favour of execution.timestamp (#104) - #455
Merged
jeremymanning merged 1 commit intoAug 3, 2026
Conversation
`now()` reads the clock afresh at every use, so two steps of one run get
different answers. `execution.timestamp` is computed once per run. Six
catalogue examples stamped their reports with `now()`, which is exactly the
case where one answer is wanted:
"timestamp": "{{ now() }}" -> "{{ execution.timestamp }}"
*Report generated on: {{ now() }}*
A warning, not an error. `now()` keeps working -- pipelines outside this
repository use it, and refusing them to make a style point would be a
gratuitous break -- but validation now names the replacement:
'now()' is deprecated: it is read afresh at every use, so two steps of
one run disagree. Use 'execution.timestamp', which is the same for
every step.
The pipeline still validates (exit 0) and still runs.
`GlobalSpec` carries `deprecated_for`, so the message, the generated
documentation and the catalogue guard all come from one declaration rather
than three restatements. `find_global_misuse` reports it only for a call
that would otherwise work: a wrong-arity `now(1, 2)` gets the arity error
alone, one problem at a time.
`TemplateValidationError` already carried a severity; the validator now
routes on it, so a warning goes to `warnings` and lets the run proceed while
an error still refuses it.
Measured: blocking suite 696 -> 700 passed, 0 failed. Catalogue unchanged at
30/117 -- the six migrated files fail for unrelated reasons, so this moves
correctness rather than the count.
Three mutations, all killed:
- drop `deprecated_for` from `now` -> 2 tests
- make the deprecation an error -> 4 tests
- report it for a call that cannot work anyway -> 1 test
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Reopens #453. Like #452, it merged into a stacked base that
mainhad already taken, so it reported "merged" while its code never reachedmain—mainstill hasdeprecated_fornowhere andnow()in six examples. Same commit, correct base.Stacked on #454, which reopens the RuntimeContext work against
main. Review that first; this retargets tomainwhen it merges.What changed
now()reads the clock afresh at every use;execution.timestampis computed once per run. Six catalogue examples usednow()to stamp reports — precisely the case that wants one answer:A warning, not an error
now()keeps working. Pipelines outside this repo use it, and refusing them to make a style point would be a gratuitous break. Validation says so and names the replacement:Exit 0, and it still runs. Verified through the CLI, not just the unit.
Chose a validation warning over a Python
DeprecationWarning: pipeline authors write YAML, not Python, andDeprecationWarningisignored in this project's pytest config — it would have been invisible to exactly the people who need it. The action-alias precedent uses the Python warning, so this is a deliberate divergence.One declaration, three consumers
GlobalSpec.deprecated_fordrives the message, the generated docs, and the catalogue guard rather than three restatements.find_global_misusereports it only for a call that would otherwise work —now(1, 2)gets the arity error alone. One problem at a time.Measured
now()The count is flat because the six migrated files fail for unrelated reasons — this moves correctness, not the metric, which is the distinction worth keeping visible.
Mutations — three, all killed
deprecated_forfromnowOne flaw caught in my own guard: with no deprecated globals the regex became an empty alternation matching nearly every call, so the test would have reported the whole catalogue as offending. Guarded.
🤖 Generated with Claude Code