Skip to content

Commit 25a711b

Browse files
authored
Merge pull request #332 from LeXwDeX/dev
release: dev -> main — MEMORY write-path repair + DAG gate hardening batch
2 parents e62a875 + f1c2c8c commit 25a711b

15 files changed

Lines changed: 1237 additions & 154 deletions

packages/core/src/plugin/command/workflow-routing.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ Top level is `title`/`mode`/`admission` (optional) and `config` (required);
108108
`kind` (required), `depends_on`, `instruction`, `worker_type`, `required`,
109109
`report_to_parent` — never `worker`, `prompt`, or `agent`.
110110

111+
A `report_to_parent` node with dependents is a reporting checkpoint: gate each
112+
dependent on its output via `condition`, keep it a reporting leaf, or drop
113+
`report_to_parent`.
114+
111115
Validate that `spec_path` before start. Fix every diagnostic in the same file
112116
and revalidate; validation creates no workflow. A successful start returns the
113117
exact workflow ID. The parent owns the graph, controls, and final report;

packages/opencode/src/dag/CONTEXT.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Workflow Orchestration turns one user objective into one durable DAG. Its model-
1313
| Orchestration Router | The product-owned parent guidance that qualifies an objective and selects one Workflow Route without external Skill discovery. |
1414
| Block Composer | The Orchestration Router decision that selects the smallest Block graph justified by current evidence. |
1515
| Decision Checkpoint | One parent-owned confirmation for unresolved user choices that materially change behavior, scope, acceptance, or an irreversible boundary. |
16+
| Reporting Checkpoint | A `report_to_parent: true` node with dependents; its dependents must gate on its output via `condition`, or it must be a reporting leaf. |
1617
| Workflow Brief | The recommended route, scope, acceptance evidence, assumptions, risks, and material alternatives presented at a Decision Checkpoint. |
1718
| Block | A reusable high-level orchestration capability such as explore, plan, debug, coding, verify, or review. Blocks compile into Nodes. |
1819
| Node | A low-level durable unit of child-agent work with dependencies, prompt input, policy, and output contract. |
@@ -31,6 +32,7 @@ Workflow Orchestration turns one user objective into one durable DAG. Its model-
3132
- Model-facing graph actions expose only `spec_path`; graph fields live in YAML so provider tool-call serialization cannot turn a nested graph into a string.
3233
- Legacy YAML may be adapted at the file boundary without making legacy fields valid inline input.
3334
- Runtime Admission and Workflow Authoring Check have separate names, state, and responsibilities.
35+
- Dependents of a reporting checkpoint must be gated on its output; authoring rejects ungated shapes at start/validate (enforcement point: authoring boundary only, runtime create deliberately unchanged).
3436

3537
## Boundaries
3638

@@ -43,3 +45,5 @@ Workflow Orchestration turns one user objective into one durable DAG. Its model-
4345
## Decisions
4446

4547
- [ADR-0001: One Workflow Authoring Check authority](docs/adr/0001-workflow-authoring-check.md)
48+
- [ADR-0002: Parallel workspace writers with an implementation aggregator](docs/adr/0002-parallel-writers-aggregator.md)
49+
- [ADR-0003: Reporting checkpoint gating at the authoring boundary](docs/adr/0003-reporting-checkpoint-gating.md)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# ADR-0003: Reporting checkpoint gating at the authoring boundary
2+
3+
- Status: Accepted
4+
- Date: 2026-08-17
5+
6+
## Context
7+
8+
On 2026-08-17 a hand-authored 15-node workflow (issue #320) ran 75 minutes to
9+
`completed` although every one of its five decision checkpoints returned
10+
`verdict: replan`. The checkpoint nodes carried `report_to_parent: true` but
11+
their stage dependents declared only `depends_on`, no `condition`. The engine
12+
spawns a dependent the moment all of its dependencies complete, so each next
13+
stage started milliseconds (≈12ms) after its checkpoint settled; the wake to
14+
the parent was terminal-only advisory signal, never a gate. The authoring
15+
model ignored warning-level feedback, which is how the ungated shape shipped.
16+
17+
Block-compiled graphs already gate dependents on checkpoint verdicts (the
18+
issue #294 REJECT-checkpoint shape); hand-built node graphs had no equivalent
19+
check.
20+
21+
## Decision
22+
23+
A `report_to_parent: true` node with dependents is a **reporting checkpoint**.
24+
Each dependent must gate on the checkpoint's output via `condition`
25+
(`input_mapping` does not count — it feeds data, it does not gate), or the
26+
checkpoint must be a reporting leaf, or the node must drop `report_to_parent`.
27+
`node_defaults.report_to_parent` is honored: a node inheriting the default
28+
reports the same way.
29+
30+
Enforcement lives in `checkpointGateDiagnostics`, wired only into
31+
`validatePostCompile`'s structural branch — the authoring start/validate path.
32+
Every ungated dependent emits one error-severity `dag.invalid` diagnostic in
33+
both `portable` and `environment` profiles, so `start` and `validate` reject
34+
the shape before any durable graph exists.
35+
36+
Enforcement is authoring-only by design. `Dag.create` and the replan/extend
37+
fragment paths stay untouched: the verdict vocabulary is open, the ACCEPT path
38+
must not wait for the parent, and runtime enforcement would change the
39+
semantics of every existing graph, including issue #294's wake-chain and
40+
reopen-extend behavior.
41+
42+
## Consequences
43+
44+
- Ungated reporting checkpoints fail fast at start/validate with a diagnostic
45+
naming the checkpoint, the dependent, and the three legal fixes.
46+
- Runtime create, wake chains, and reopen-extend semantics are unchanged;
47+
trusted internal callers retain full runtime flexibility.
48+
- Saved and curated workflows were audited: 14 curated block workflows are
49+
unaffected; only `ultra-flow-route.yaml` and `release-route.yaml` trip the
50+
new check and are tracked in opencode-dag-config#14.
51+
52+
## Alternatives Considered
53+
54+
- Runtime enforcement at `Dag.create`: rejected — the verdict vocabulary is
55+
open-ended, the ACCEPT path must not block waiting for the parent, and it
56+
would change the behavior of every existing graph.
57+
- Warning-severity diagnostic: rejected — the authoring model ignores
58+
warnings; that is precisely how the incident happened.
59+
- A new explicit `gate` field on dependents: rejected — `condition` already
60+
expresses output gating and the block compiler already emits it; a second
61+
mechanism would split the gating vocabulary.
62+
63+
## Deferred
64+
65+
- Replan/extend fragments are not checkpoint-gate-checked (coverage gap; no
66+
date). Runtime flexibility was prioritized; fragment authoring remains
67+
advisory.
68+
- Deprecation of advisory wake chains (no date): `report_to_parent` without
69+
gated dependents stays legal but is a smell worth revisiting once fragment
70+
coverage exists.

0 commit comments

Comments
 (0)