Repository navigation
workflow DSL: decide the eight open design questions, and fix what verifying them exposed - #610
Merged
Merged
Conversation
…rifying them exposed Reads #468, #472, #479, #480, #481, #488, #577 and #578 side by side against src/ at 5.5.0 -- each was filed separately, from a different corpus, against 5.0.4 -- and records a decision for every one. Three of them stop being independent when read together. docs/design/workflow-dsl/00-cluster-decisions.md carries the decisions, the sequence, and what was rejected. Not version-pinned, because the cluster is not: most of it is additive across 5.x minors and exactly one member joins the 6.0.0 cohort. The verification pass turned up three things the issues do not record. The static type vocabulary is unsound, and three of the eight want to build on it. parse_type_name is `self.eat("ID").val` and type_system falls back to ANY, so `fn b(name: strng)` checks clean and silently disables checking on that parameter; `map` is unnameable and looks nameable; `record` is in TYPE_NAMES but is a keyword, so it is a dead entry. Reported (open): #609. Nothing typed should be added to the DSL until it is fixed -- a `returns: "recrod"` meaning "any type at all" would be a new instance of the declared-but-not-enforced shape the last three releases were spent removing. An `after` edge carries the dependency's value, and nothing said so. Inside a step body each name declared with `after` is bound to that step's return value, with correct scoping -- an undeclared read is `Undefined variable`. Documented in neither docs/guide/, llms.txt nor llms-full.txt, so a reader concludes all data must route through `state`. New guide section 3.1, with the case that follows from it: a `skipped` producer binds `nil`, indistinguishable from a step that returned `nil`, and only r["statuses"] tells them apart. llms-full.txt's workflow example had never parsed. `step validate after []` is `Expected identifier, got '['`. It survived because the gate's document list had two AI-discoverability files in it and covered one -- llms.txt was scanned, llms-full.txt was not, so the file 5.5.0 shipped inside the wheel for agents to read was the one nothing checked. Fixed, and llms-full.txt is now in the list; its other three blocks were already clean. Two symbol suppressions come with it, both prose rather than claims: `std:module` is the placeholder spelling of the import form, and `std:string` is named deliberately to say that it fails. Gates: static 135/135, runtime 251/251 (was 245 -- six new blocks, all executed), contracts 6/6, opcodes 26/26, shapes 0 new, versions 15/15, ruff and mypy clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ng5gg1i8SSCgpHbkNt6zZa
This was referenced Aug 26, 2026
Closed
Closed
Closed
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.
Summary
A decision session over the eight open workflow-DSL design questions — #468,
#472, #479, #480, #481, #488, #577, #578. Each was filed separately, from a
different corpus, against v5.0.4. Read side by side at 5.5.0 they constrain each
other, and three stop being independent.
docs/design/workflow-dsl/00-cluster-decisions.mdcarries a decision for each,the sequence, and what was rejected. This PR does not implement any of them.
The decisions, in one line each
mapis added;recordis made spellable or removed. Warn in 5.x, error at 6.0.0tool.registerschema-from-signature ships first and forces D1; a step'sreturns:waits for it. Two vocabularies with a derivation between them, deliberately not unifiedworkflow_waitargument 2 type-dispatches — string iscorrelation_keyas today, map is an options map carryingschema. There is no free positional slotrun_workflow(flow, args_map)— notrun_workflow(build("lite")). Arguments become part of run identity and ride #470's mechanismskipped, non-list →upstream_failed, re-expansion to a different length → refused as topology driftTaskNodealready carriesmax_retries/timeout_ms/cacheper node, so a mapped node gives "retry only the two that failed" for free — no eighth status, no envelope, no second definition of "done" for@exactly_onceto disagree withcompensate_with, not a workflow exit hook — the hook needs run-status visibility inside a step body, which is a larger change than the feature. A compensated run is terminalmerge:validation). The barrier itself is deferred — it duplicatesafter, more narrowlybudget { ..., limits: { <meter>: <n> } }. Nested, so the outer vocabulary stays closed and parse-checkable while the open part is explicitly host-resolved. A declared meter with no accountant is an errorWhat verifying them exposed
Every claim in all eight issues was re-executed against
src/at 5.5.0 beforeany decision was made. Three findings the issues do not record:
1. The static type vocabulary is unsound — and three of the eight want to build
on it.
parse_type_nameisself.eat("ID").val;type_systemfalls back toANY. So one transposed letter silently disables checking:One error, for
a. Also:mapis unnameable and looks nameable — and it is whatrun_workflowand most step bodies return. Andrecordis inTYPE_NAMESbut isa keyword, so it is a dead entry. This is the declared-but-not-enforced shape
(#467, #473, #478, #492) at the annotation surface. Reported (open): #609.
2. An
afteredge carries the dependency's value, and nothing said so. Insidea step body each name declared with
afteris bound to that step's return value,with correct scoping — an undeclared read is
Undefined variable. Documented inneither the guide,
llms.txtnorllms-full.txt, so a reader concludes all datamust route through
state. New §3.1, with the consequence: a skipped producerbinds
nil, indistinguishable from a step that returnednil, and onlyr["statuses"]tells them apart —r["steps"]omits it entirely.3.
llms-full.txt's workflow example had never parsed.step validate after []is
Expected identifier, got '['. It survived because the gate's document list hadtwo AI-discoverability files in it and covered one —
llms.txtwas scanned,llms-full.txtwas not. So the file 5.5.0 shipped inside the wheel for agents toread was the one nothing checked. Fixed, and
llms-full.txtis now in the list;its other three blocks were already clean.
Two symbol suppressions come with it, both prose rather than claims:
std:moduleis the placeholder spelling of the import form, and
std:stringis nameddeliberately in order to say that it fails.
Testing
--static--runtime--contracts--opcodes--shapes--versionsruff/mypyEvery guide and
llms-full.txtexample in this PR was run against dev source andits output pasted verbatim.
Noticed, not done
docs/guide/workflows-and-tasks.mdhas two### 4.2headings, both under## 5. Failure and recovery(lines 508 and 582), alongside a### 4.1and a### 4.0.Pre-existing; renumbering would move anchors other documents may link to, so it is
left for a pass that can check inbound links.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ng5gg1i8SSCgpHbkNt6zZa