Record the inputs a run actually starts from, not only the ones passed
A run submitted without explicit inputs recorded `params = {}`: Port
initials filled the values at node level and were never written back, so an
exported row had a blank `param.*` cell and the runs listing could not tell
a run that took every default from one submitted with those same numbers.
Declared initials are now folded in at submit, explicit values winning, and
the run-level seed still wins over a declared one.
`params_digest` is computed over the resolved values, so it changes shape
once: a run recorded before this does not dedupe against a newer identical
submit, and its stage-cache entries miss once.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hra4ndWMCLU5F3KjUuVAc
This commit is contained in:
@@ -400,6 +400,63 @@ def test_a_repeated_submit_returns_the_run_it_already_made():
|
||||
assert again.id == "dedup-1"
|
||||
|
||||
|
||||
class _OneFlow:
|
||||
"""A controller that has exactly one flow and no engine behind it."""
|
||||
|
||||
def __init__(self, flow):
|
||||
self.store = self
|
||||
self._flow = flow
|
||||
|
||||
def read_flow(self, name, draft=False):
|
||||
return self._flow
|
||||
|
||||
def head(self):
|
||||
return ""
|
||||
|
||||
|
||||
class _Collect:
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def add(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
|
||||
def test_a_run_records_the_inputs_it_actually_starts_from():
|
||||
"""An input left out takes its declared value, and the row says so.
|
||||
|
||||
`params = {}` could not tell a run that took every default from one
|
||||
submitted with those same numbers spelled out — and an export of the
|
||||
first had a blank cell where its `lr` should be.
|
||||
"""
|
||||
flow = FlowDef(
|
||||
name="study",
|
||||
mode="batch",
|
||||
inputs=[
|
||||
FlowInput(
|
||||
spec=MessageSpec(name="lr", dtype=DType.FLOAT), initial=0.01
|
||||
),
|
||||
FlowInput(spec=MessageSpec(name="epochs", dtype=DType.INT)),
|
||||
],
|
||||
)
|
||||
service = RunService(controller=_OneFlow(flow), queue=_Collect())
|
||||
made = []
|
||||
try:
|
||||
defaulted = service.submit("study", {"epochs": 5})
|
||||
made.append(defaulted.id)
|
||||
assert defaulted.params == {"lr": 0.01, "epochs": 5}
|
||||
|
||||
# Spelling out the declared value is the same run, and now reads as it.
|
||||
spelled = service.submit("study", {"lr": 0.01, "epochs": 5})
|
||||
made.append(spelled.id)
|
||||
assert spelled.params_digest == defaulted.params_digest
|
||||
finally:
|
||||
with Session(db_engine) as session:
|
||||
for run in session.exec(select(Run).where(col(Run.id).in_(made))).all():
|
||||
session.delete(run)
|
||||
session.commit()
|
||||
|
||||
|
||||
def test_a_key_nobody_used_submits_normally(
|
||||
client, superuser_token_headers, monkeypatch
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user