Repository navigation
v0.18.0
Added
rote runshows a gate's message while the run waits (#304). Every
workflow runtime now renders ahitl_gate'snotify.message_templatewith
the run's real values and reports it on the channelrote runalready
watches (arote_gate_statusevent on DBOS, a query on Temporal, a
rote-gate-parklog line on Cloudflare and Inngest).rote runprints it
on stderr. Display only:channelandtargetare still never sent to.- A node declares the environment variables its code reads (#302).
env: [NAME, ...]on pure_function and external_call nodes. Verification
finds literalos.environ/os.getenvreads and sends an undeclared one
back for repair.rote skill installrecords each declared variable's
value, and a run whose value differs is refused, so a compiled skill no
longer silently drops a variable its module reads (expense-audit's report
directory). Names rote reserves (ROTE_*, vendor keys, proxies,PATH,
PYTHON*and the like) are refused in the IR. - Structure-pass constants are typed, with a unit (#303). A constant is a
number, boolean or string checked against the skill's own words, and a
number carries a unit in the newNode.constant_units(percent,count,
days,currency:USD, ...). 75% is75with unitpercent, never0.75
or the text'75%'. A number the skill writes in words is kept and listed
for review. - A compile's repair can declare a pipeline input field (#297). A module
that reads a caller-supplied field the skeleton never declared can now add
it throughsystem1/input_fields.yaml(or the parallel path's
input_fields), checked against the skill's text and the sample input.
Every applied or refused entry is an Open question in compile-report.md.
Changed
-
Agent-loop tools are pinned to the one grounded server that offers
them (#296). The compile pins a loop tool to its server when exactly one
listed server offers it, and leaves it as an Open question when two do.
System-1 no longer picks the first of two servers. A loop tool no listed
server offers is a review gap (loop_tool_unserved), not an error. -
The static eval sizes a compiled judge's input along the IR's data flow
(#300). A judge that receives a whole external result used to be priced
as its prompt plus a few tokens per field, so compiled cost looked far
too small. It now carries the same size the agent side uses, and each
judge and loop states its input sizes under Assumptions in the scorecard. -
A compile's constants keep the sign the skill writes. The structure
pass compared a number's absolute value to its quote, so5passed for
"below -5%" and a flipped rule shipped as decided. A number now matches its
quote with its sign. A negative value for an unsigned number ("a drop of
15%" as-15) is still accepted, since that is a real reading, but it is
listed for review like a number read from words. A minus that runs into a
word or digit ("5-10 days", "COVID-19") is not read as a sign. -
A compiled skill's gate message reads as it does on the workflow
runtimes. The HUMAN block filled a gate's placeholders with Python's
str(), so a boolean readTrue, a whole float2.0and a missing owner
an empty string, whererote runshowstrue,2andnull, and a bidi
override in a value reached the agent's terminal raw. The renderer is now
one module (rote.adapters._gate_runtime_helper): the Python runtimes embed
its source and a compiled skill ships it asscripts/_rote_gate.pywhen a
gate has a message. -
Behavior change: a node with no
retry:is attempted once on every
runtime. It ran once on dbos, python and temporal, but up to six times on
cloudflare (step.do's default of 5 retries) and four on inngest (the
SDK's function-level default of 3), so a paid judge or a call that is not
idempotent did different things per runtime. Cloudflare now emits
retries: { limit: 0 }and inngestretries: 0when no node declares a
retry. A declaredretry:is unchanged.tests/test_retry_parity*.py
counts the attempts on all six runtimes. -
A failing generated test shows its local values to the repair. The
test run passes--showlocals, so a failed assertion on an overall
outcome now carries the finding that caused it (a $2,500 meals line that
also trips the $75 meals cap). pytest shortens each value when not
verbose, so the output budget holds. -
System-1's test rules name the three mistakes behind most red tests.
GENERATE.md now says to build each case from one clean fixture changing
only the field a rule reads, to compute expected numbers in the test
instead of by hand, and to pass inputs shaped like the sample (JSON
numbers, neverDecimal).
Fixed
-
Compile usage that was not measured reads as unknown (#299, #301).
Missing token counts were reported as zeros, so an unmeasured compile looked
free. Each stage is nowmeasured,partialorunavailable, in the
summary,--json,compile-metrics.jsonand the progress file. Codex usage
comes from the lastturn.completed, with cache reads and writes split out
once. A deliverable that still fails verification now saysverification FAILEDin the header and prints nonext: rote runline. -
A compile checks the boundaries its generated tests cannot see (#291).
A real compile passed 38 generated tests while every MCP call went out with
no arguments, two gate consumers read keys their gates never declared, and
a renderer required an input field the contract left out. Verification now
reads the deliverable for each:- an MCP call whose node holds constants
mcp.argsnever sends is an error
when the tool's schema names its parameters, and an unresolved call
(listed, blocking the run, never guessed) when no schema does; - code that reads a key a gate does not declare is an error;
- code that reads a pipeline-input field the contract does not declare is
an error.
Gates that split one section's items between them are held to what they
collect together, not each to the whole section.
- an MCP call whose node holds constants
-
A compile no longer ships a field read from an MCP result that has no
such field. Verification checks every<node>.output.<field>read of an
MCP-bound node against the result a recorded run returned, else the
outputSchema the server declares. A result that is text or a list, or a
closed object without the field, goes back to the agent as an error,
because the run would fail at that read. With nothing recorded or
declared, it is an Open question in the report. -
rote runon a temporal app names the exception a failed step raised,
not only Temporal's "Activity task failed" wrapper.