opencode-gbuild 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,100 +1,146 @@
1
1
  ---
2
- description: Executes a gbuild graph — dispatches every ready-and-independent node in the current wave concurrently, reviews each node's output with gbuild-reviewer before checkpointing it complete, and resumes only the remaining frontier on re-invocation. Use after /gbuild:plan has written graph.json.
2
+ description: Executes a gbuild graph — dispatches every ready-and-independent node in the current wave concurrently, reviews each node's output with gbuild-reviewer before recording it complete, and resumes only the remaining frontier on re-invocation. Use after /gbuild:plan has charted the graph.
3
3
  ---
4
4
 
5
- Run `.gbuild/$ARGUMENTS/db/graph.json` (the feature slug is `$ARGUMENTS`).
5
+ Run the graph in `.gbuild/$ARGUMENTS/db` (the feature slug is `$ARGUMENTS`; `DB` below).
6
6
 
7
7
  **CRITICAL: this skill must run in the main context, not inside a forked agent.** It dispatches its own
8
- subagents per node; a subagent cannot itself fan out further subagents reliably.
8
+ subagents per node; a subagent cannot itself fan out further subagents reliably. It is also the store's
9
+ **only writer**: subagents never run `cypherlite` — they get what they need in their prompt and report
10
+ back in their final message, and this skill records it.
9
11
 
10
- ## Step 0: Load and query
12
+ ## Store rules
11
13
 
12
- Load `.gbuild/<feature>/db/graph.json` (a CypherLite GraphData file — nodes keyed by integer `id`, with a
13
- `slug` property; dependencies are `DEPENDS_ON` relationships, feature-level acceptance is `Acceptance`
14
- nodes linked by `HAS_ACCEPTANCE`/`SATISFIES`; checkpoints live in the sibling `.gbuild/<feature>/nodes/`).
15
- **Confirm it's well-formed first:**
14
+ - `cypherlite --version` first. If it's missing, stop: gbuild needs it
15
+ (`curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash`).
16
+ - One `cypherlite` command at a time against `DB` — never parallel tool calls on it, never from a subagent.
17
+ - Always `--mode jsonl`: one JSON object per row, no output = no rows. Every `--param` value is JSON,
18
+ single-quoted for the shell (`--param 'slugs=["a","b"]'`).
19
+ - `storage locked` → another process holds the store: wait a few seconds, retry up to 3 times, then stop.
20
+ Exit code 1 = failure; read stderr. Anything beyond the scripts below: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
21
+ - Never re-read what you already hold. The claimed wave's definitions stay valid for its retries.
16
22
 
17
- ```
18
- python3 ${CLAUDE_PLUGIN_ROOT}/scripts/validate_format.py .gbuild/<feature>/db/graph.json
19
- ```
20
-
21
- If it prints `invalid: ...`, stop and report — do not attempt to run a graph `plan` didn't finish
22
- correctly. Then take the frontier:
23
+ ## Step 0: Check and recover
23
24
 
24
25
  ```
25
- python3 ${CLAUDE_PLUGIN_ROOT}/scripts/graph.py .gbuild/<feature>/db/graph.json --status
26
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
27
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
26
28
  ```
27
29
 
28
- Take the `frontier` list (node **slugs**) from the status report. This is the set of nodes ready
29
- right now — not a judgement call, the query already excludes anything blocked, in-flight, or done.
30
+ - `validate` printing anything → stop and report the rows; do not run a graph `plan` didn't finish
31
+ correctly.
32
+ - `attention` rows with reason `in_progress` are left over from an interrupted run (this skill is the
33
+ only writer and records every node before finishing). Check `git log` for commits their agents already
34
+ made, then reset them all in one call so they re-dispatch, and mention it in the report:
30
35
 
31
- If `frontier` is empty and `completed` + `cancelled` covers every node, the graph is done — report that
32
- and stop. If `frontier` is empty but nodes remain incomplete, there's a stuck cluster (likely an
33
- `escalate`d or `stop`ped node) — report what's blocking per the last checkpoint and stop.
36
+ ```
37
+ cypherlite DB --mode jsonl --param 'slugs=["<slug>", ...]' --param 'status="pending"' \
38
+ < ${CLAUDE_PLUGIN_ROOT}/cypher/set-status.cypher
39
+ ```
34
40
 
35
41
  ## Step 1: Establish VCS facts
36
42
 
37
- Default to `git`. `git check-ignore -q .gbuild/` tells you whether to stage anything under it at all.
43
+ Default to `git`. `git check-ignore -q .gbuild/` tells you whether to commit the store at all.
38
44
 
39
45
  ## Step 2: Pick a backend
40
46
 
41
47
  **Workflow tool**, if this session has opted into multi-agent orchestration (ultracode, or the user
42
- asked for a workflow explicitly) — translate `frontier` into a `pipeline()`/`parallel()` script: each
43
- node is an `agent()` implement call, immediately followed by a `gbuild-reviewer` `agent()` review call
44
- scoped to that node's `contract.output` + `acceptance`, using `schema` for the pass/fail verdict. Code
45
- nodes touching files that could conflict with a concurrent sibling get `isolation: 'worktree'`.
46
- Controlled-cycle clusters become a bounded `while` loop per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md`'s round cap. Route
47
- `model_tier: strong` nodes via `opts.model` where the harness supports an override.
48
+ asked for a workflow explicitly) — translate each claimed wave into a `pipeline()`/`parallel()` script:
49
+ each node is an `agent()` implement call, immediately followed by a `gbuild-reviewer` `agent()` review
50
+ call scoped to that node's outputs + `acceptance`, using `schema` for the pass/fail verdict. Code nodes
51
+ touching files that could conflict with a concurrent sibling get `isolation: 'worktree'`.
52
+ Controlled-cycle clusters become a bounded `while` loop per `${CLAUDE_PLUGIN_ROOT}/reference/shapes.md`'s
53
+ round cap. Route `model_tier: strong` nodes via `opts.model` where the harness supports an override. The
54
+ script never touches the store: collect the results and record them from the main context (step 3.4).
48
55
 
49
56
  **Fallback** (default — no opt-in required, and always what step 3 below assumes): fire one `Agent`
50
- tool call per node in the current `frontier`, **all in a single message** — this is what makes the fan-
51
- out real rather than claimed. Do not dispatch them one at a time across separate messages; that's
52
- exactly the serial behavior this plugin replaces.
53
-
54
- ## Step 3: Per-node dispatch (fallback backend)
55
-
56
- For every node in the current wave's `frontier`, in one message, spawn one `Agent` call per node:
57
-
58
- 1. **IMPLEMENT.** Give the agent the node's `slug`, `title`, `type`, `contract.input` (resolved: for
59
- each `DEPENDS_ON` target, read the actual `output` values from its checkpoint
60
- `.gbuild/<feature>/nodes/<dep-slug>.json`), and `acceptance`. Tell it to produce `contract.output`'s
61
- declared shape and, for `code`/`test`/`chore` nodes, to actually make the change in the working tree
62
- (not describe it) and commit it — message `<feature>/<slug>: <what changed>`.
63
- 2. **REVIEW.** Once IMPLEMENT returns, spawn a `gbuild-reviewer` agent (agents/gbuild-reviewer.md — this
64
- plugin's own copy, gbuild does not depend on hone-ai being installed) against the actual diff and
65
- output. Never let the implementing agent review its own work.
66
- 3. **PASS or FAIL:**
67
- - **Pass** (`VERDICT: pass`): write `.gbuild/<feature>/nodes/<slug>.json` with `status: completed`,
68
- the `output`, the review verdict, and timestamps.
69
- - **Fail**: apply the node's `failure_policy` (`${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`) — `retry`/`repair`
70
- re-dispatch (bounded, 2 attempts) with the reviewer's per-criterion failures fed back in;
71
- `fallback` dispatches the named alternate approach; `skip` checkpoints `cancelled`; `escalate`
72
- checkpoints `failed` and stops that node's downstream only; `stop` halts the entire run.
73
-
74
- Each node's checkpoint write is independent — nodes in the same wave never touch each other's files, so
75
- true concurrent dispatch is safe by construction.
57
+ tool call per claimed node, **all in a single message** — this is what makes the fan-out real rather
58
+ than claimed. Do not dispatch them one at a time across separate messages; that's exactly the serial
59
+ behavior this plugin replaces.
60
+
61
+ ## Step 3: One wave
62
+
63
+ 1. **CLAIM.**
64
+
65
+ ```
66
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/dispatch.cypher
67
+ ```
68
+
69
+ It moves the whole frontier to `in_progress` and prints one row per claimed node with everything its
70
+ agent needs: `slug`, `title`, `type`, `acceptance`, `failure_policy`, `model_tier`, `verify`,
71
+ `inputs` (an input with a `value` came from an upstream node; one without is external — its `shape`
72
+ says where to find it), and `outputs`. **No rows** → nothing is ready: go to step 5.
73
+
74
+ 2. **IMPLEMENT.** In one message, spawn one `Agent` per claimed node with its row. Tell it to:
75
+ - actually do the work — for `code`/`test`/`chore` nodes make the change in the working tree (not
76
+ describe it) and commit it, message `<feature>/<slug>: <what changed>`;
77
+ - produce a value for every output field: a scalar or a list of scalars, JSON-encoding anything
78
+ nested into a string;
79
+ - record its own UTC start and finish (`date -u +%Y-%m-%dT%H:%M:%SZ`) and end its final message with
80
+ `{"started_at": "...", "completed_at": "...", "outputs": {...}}`;
81
+ - **not** run `cypherlite` or touch `.gbuild/`.
82
+
83
+ 3. **REVIEW.** Once IMPLEMENT returns, spawn a `gbuild-reviewer` per node, again all in one message
84
+ (`agents/gbuild-reviewer.md` — this plugin's own copy, gbuild does not depend on hone-ai being
85
+ installed). Give it the node's row, the agent's reported outputs, and where the diff is. Never let
86
+ the implementing agent review its own work.
87
+
88
+ 4. **RECORD** the whole wave in one call — one result per node, `verdict` from the reviewer's
89
+ `VERDICT:` line, `failed_criteria` from its `[fail]` lines:
90
+
91
+ ```
92
+ cypherlite DB --mode jsonl --param 'results=[
93
+ {"slug": "<slug>", "verdict": "pass", "failed_criteria": [], "outputs": {...},
94
+ "started_at": "<iso>", "completed_at": "<iso>"},
95
+ {"slug": "<slug>", "verdict": "fail", "failed_criteria": ["<criterion>"]}
96
+ ]' < ${CLAUDE_PLUGIN_ROOT}/cypher/record.cypher
97
+ ```
98
+
99
+ Each returned row says whether that node `completed`. A slug missing from the output was not
100
+ recorded (it wasn't `in_progress`) — find out why before moving on. `InvalidPropertyType` means an
101
+ output value was a map; the whole batch was rejected — JSON-encode it and send the batch again.
102
+
103
+ 5. **FAILURES.** For each row with `completed: false` (a failed review, or a pass `record` downgraded
104
+ because `missing_outputs` is non-empty), apply the node's `failure_policy`
105
+ (`${CLAUDE_PLUGIN_ROOT}/reference/failure-policies.md`), using its `attempt` as the count:
106
+ - `retry` / `repair` → re-dispatch implement → review with the failed criteria fed back in, reusing
107
+ the row you already hold, then record just those nodes. Bounded: 2 attempts.
108
+ - `fallback` → dispatch the named alternate approach the same way.
109
+ - `skip` → `cancelled`; `escalate` (or an exhausted retry/repair) → `failed`, its dependents stay
110
+ blocked while siblings elsewhere keep going; `stop` → `failed` and halt the entire run. One
111
+ `set-status.cypher` call per status, with every slug that gets it.
112
+ - A completed router (`decision` choosing a branch) → cancel the unselected branches with
113
+ `set-status.cypher` before the next claim.
114
+
115
+ Nodes in the same wave never read each other's outputs, so true concurrent dispatch is safe by
116
+ construction — only the store calls are serialized.
76
117
 
77
118
  ## Step 4: Next wave
78
119
 
79
- Re-run `graph.py --status`. If the wave that just finished unblocked new frontier nodes, repeat step 3
80
- for them. Keep going until `frontier` is empty (done, or stuck — see step 0's exit conditions).
120
+ If `.gbuild/` isn't ignored, commit the store: `git add .gbuild/<feature>/db` and
121
+ `git commit -m "<feature>: record wave <n>"`. Then claim again (step 3). Keep going until a claim
122
+ returns no rows.
81
123
 
82
124
  ## Step 5: Report and stop
83
125
 
84
- Report: which nodes ran this invocation, which passed review outright vs. needed a repair pass, what's
85
- newly in the frontier or still blocked, and any `failed`/`escalate`d nodes needing a decision.
126
+ ```
127
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
128
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/attention.cypher
129
+ ```
130
+
131
+ Every `progress` row with `open: []` → the graph is done. Otherwise `attention` names what's stuck
132
+ (`failed` nodes with their last failed criteria, and what they block).
86
133
 
87
- Close with the next step:
134
+ Report: which nodes ran this invocation, which passed review outright vs. needed a repair pass, and any
135
+ `failed` nodes needing a decision. Close with the next step:
88
136
 
89
- - **Graph fully done** (every node `completed` or `cancelled`) → say so plainly, then
90
- `next: /gbuild:review <feature>` — the per-node reviews graded each node against its own contract;
91
- nothing has yet looked at what the accumulated diff did to the codebase.
92
- - **Work remains** (frontier non-empty, or nodes `failed`/`escalate`d awaiting a decision) →
93
- `next: /gbuild:status <feature>`.
137
+ - **Graph fully done** → say so plainly, then `next: /gbuild:review <feature>` — the per-node reviews
138
+ graded each node against its own contract; nothing has yet looked at what the accumulated diff did to
139
+ the codebase.
140
+ - **Work remains** (nodes `failed` awaiting a decision) → `next: /gbuild:status <feature>`.
94
141
 
95
142
  ## Resuming
96
143
 
97
- Re-invoking `/gbuild:run <feature>` after an interruption re-runs step 0 fresh: anything with a
98
- `completed` or `cancelled` checkpoint is excluded from `frontier` automatically, so only the genuinely
99
- remaining work re-dispatches. Nothing needs to be told what already finished — the checkpoint files are
100
- the memory.
144
+ Re-invoking `/gbuild:run <feature>` after an interruption re-runs step 0 fresh: nodes an interrupted
145
+ wave left `in_progress` are reset, and the next claim picks up exactly the remaining frontier. Nothing
146
+ needs to be told what already finished — the store is the memory.
@@ -2,7 +2,16 @@
2
2
  description: Reports a gbuild feature's graph — frontier, blocked, in-flight, completed, each node's review verdict, and the cluster shapes with evidence of what actually ran concurrently. Use to check progress or diagnose a stuck run.
3
3
  ---
4
4
 
5
- Report status for `$ARGUMENTS`.
5
+ Report status for `$ARGUMENTS`. This skill only reads the store; `DB` below is `.gbuild/<feature>/db`.
6
+
7
+ ## Store rules
8
+
9
+ - `cypherlite --version` first. If it's missing, stop: gbuild needs it
10
+ (`curl -sSfL https://neo4j-labs.github.io/cypherlite/install.sh | bash`).
11
+ - One `cypherlite` command at a time — never parallel tool calls on the same store.
12
+ - Always `--mode jsonl`: one JSON object per row, no output = no rows.
13
+ - `storage locked` → another process (likely a running `/gbuild:run`) holds the store: wait a few
14
+ seconds, retry up to 3 times, then say so. Anything else: `${CLAUDE_PLUGIN_ROOT}/reference/cypher.md`.
6
15
 
7
16
  ## Mode
8
17
 
@@ -13,73 +22,66 @@ Report status for `$ARGUMENTS`.
13
22
 
14
23
  ## Single feature
15
24
 
16
- ### 1. Load
25
+ This is the human-facing report, so it's the one place that reads every node.
17
26
 
18
- `.gbuild/<feature>/db/graph.json` (a CypherLite GraphData file — GbuildNodes have a `slug` property and
19
- are linked by `DEPENDS_ON` relationships; feature-level acceptance is `Acceptance` nodes linked by
20
- `HAS_ACCEPTANCE`/`SATISFIES`) and every `.gbuild/<feature>/nodes/*.json` checkpoint (keyed by slug; the
21
- `nodes/` dir is a sibling of the `db/` graph folder). This is a small, bounded read — status doesn't
22
- scale with graph size the way loading full node prose would.
23
-
24
- ### 2. Compute
27
+ ### 1. Load
25
28
 
26
29
  ```
27
- python3 ${CLAUDE_PLUGIN_ROOT}/scripts/graph.py .gbuild/<feature>/db/graph.json --status
30
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/status.cypher
31
+ cypherlite DB --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/validate.cypher
28
32
  ```
29
33
 
30
- Gives `frontier` / `blocked` / `in_flight` / `completed` / `cancelled` / `failed` / `waves` (all as slug
31
- lists) directly — don't re-derive these by hand.
34
+ One call after the other. `status.cypher` gives one row per node with its derived `state`
35
+ (`frontier` / `blocked` / `in_progress` / `completed` / `cancelled` / `failed`), `wave`, `waiting_on`,
36
+ review summary and timestamps — don't re-derive any of these by hand.
32
37
 
33
- ### 3. Render the graph
38
+ ### 2. Render the graph
34
39
 
35
- Draw the DAG with a marker per node status:
40
+ Draw the DAG with a marker per node state:
36
41
 
37
42
  ```
38
- ✓ completed ◐ in_progress ○ pending (frontier) ● pending (blocked) ✗ failed
43
+ ✓ completed ◐ in_progress ○ frontier ● blocked ✗ failed – cancelled
39
44
  ```
40
45
 
41
- Annotate blocked nodes with what they're waiting on: `● d-join-and-sum ← b-consume-doubled, c-consume-squared`.
46
+ Annotate blocked nodes with what they're waiting on (`waiting_on`):
47
+ `● d-join-and-sum ← b-consume-doubled, c-consume-squared`.
42
48
 
43
- Group by wave (from `--waves`) so fan-out is visible in the layout, not just in the dependency list.
49
+ Group by `wave` so fan-out is visible in the layout, not just in the dependency list.
44
50
 
45
- ### 4. Review verdicts
51
+ ### 3. Review verdicts
46
52
 
47
- For every `completed` node, one line: pass outright, or passed after N repair attempts, from its
48
- checkpoint's `review` field. For `failed` nodes, the last review's failed acceptance bullets verbatim —
49
- this is what a human needs to make the `escalate`/`stop` call.
53
+ For every `completed` node, one line: passed outright (`review_attempts: 1`), or passed after N repair
54
+ attempts. For `failed` nodes, `last_failed_criteria` verbatim — this is what a human needs to make the
55
+ `escalate`/`stop` call.
50
56
 
51
- ### 5. Concurrency evidence
57
+ ### 4. Concurrency evidence
52
58
 
53
- For each wave with more than one node, compare `started_at` timestamps across that wave's checkpoints.
54
- Report whether they actually overlapped (real concurrent dispatch) or ran sequentially despite being in
55
- the same wave (a sign the fallback backend was invoked one node at a time — a bug in how `run` was
56
- driven, not a graph problem).
59
+ For each wave with more than one completed node, compare the implementing agents' `started_at` /
60
+ `completed_at` intervals. Report whether they actually overlapped (real concurrent dispatch) or ran
61
+ back-to-back despite being in the same wave (a sign the fallback backend was invoked one node at a time —
62
+ a bug in how `run` was driven, not a graph problem).
57
63
 
58
- ### 6. Next action
64
+ ### 5. Next action
59
65
 
60
66
  One priority-ordered list: what `/gbuild:run <feature>` would do next (the current frontier), and
61
- anything needing a human decision first (`failed`/`escalate`d nodes, an empty frontier with incomplete
62
- nodes remaining).
67
+ anything needing a human decision first (`failed` nodes, an empty frontier with incomplete nodes
68
+ remaining, `in_progress` nodes when no run is active — an interrupted wave `run` will reset).
63
69
 
64
- ### 7. Invariant checks
70
+ ### 6. Invariant checks
65
71
 
66
- Numbered, only reporting violations (silence on an item means it passed, not that it was skipped):
72
+ `validate.cypher` is the invariant check — it covers non-empty acceptance, acceptance coverage,
73
+ acyclicity, completed nodes without a passing review or missing an output value, orphan chores, and the
74
+ `FROM` cut test. Report every row it returned, numbered. If it returned nothing, say so in one line —
75
+ don't let silence be ambiguous between "checked, clear" and "not checked."
67
76
 
68
- 1. Every GbuildNode has non-empty `acceptance` (should already be caught by `validate_format.py`'s own
69
- validation — report if a node manages to lack it anyway, since that means the file was hand-edited or
70
- written by something other than `plan`).
71
- 2. Every `Acceptance` node is `SATISFIES`-covered by at least one GbuildNode (enforced by
72
- `validate_format.py` — report if one slips through anyway).
73
- 3. `DEPENDS_ON` is acyclic (validated by `validate_format.py`/`graph.py` already; report if it somehow
74
- wasn't checked).
75
- 4. No `completed` node's checkpoint is missing a `review` field with `verdict: pass` — a node marked
76
- complete without a passing review means `run` skipped the review step.
77
- 5. Every `chore`-type GbuildNode is the target of at least one `DEPENDS_ON` edge.
77
+ ## All-features mode
78
78
 
79
- If all five are clear, say so in one line — don't let silence be ambiguous between "checked, clear" and
80
- "not checked."
79
+ Don't read every node of every feature. For each `.gbuild/<slug>/db` found, one store at a time:
81
80
 
82
- ## All-features mode
81
+ ```
82
+ cypherlite .gbuild/<slug>/db --mode jsonl < ${CLAUDE_PLUGIN_ROOT}/cypher/progress.cypher
83
+ ```
83
84
 
84
- For each `.gbuild/<slug>/db/graph.json` found, one line: slug, node counts by status, and whether the
85
- frontier is empty (done or stuck) or has ready work. Point at `/gbuild:status <slug>` for detail.
85
+ Print one line per feature: slug, node counts by state summed over its waves, and whether it's done
86
+ (every `open` empty), has ready work (`frontier` > 0), or is stuck. Point at `/gbuild:status <slug>` for
87
+ detail.
@@ -0,0 +1,57 @@
1
+ // A worked 4-node diamond: A produces a value, B and C each consume it
2
+ // independently, D joins both. This is exactly the script plan writes for a
3
+ // new feature — one atomic statement, piped into the store:
4
+ // cypherlite .gbuild/<slug>/db < plan.cypher
5
+ // Variables (f, a1, a, a_value, ...) are only scoped to this one statement, so
6
+ // the whole graph is created in a single CREATE chain.
7
+ .begin
8
+ CREATE (f:Feature {
9
+ feature: 'example-diamond',
10
+ destination: 'A tiny worked example: A produces a shared value, B and C each consume it independently, D joins both.',
11
+ context: "Ships with the plugin as the toy graph used in gbuild's own tests. Not a real feature.",
12
+ out_of_scope: ['Anything beyond demonstrating fan-out and join scheduling.']
13
+ })
14
+ CREATE (a1:Acceptance {id: 'a-1', text: 'run dispatches B and C concurrently, not one after the other'})
15
+ CREATE (a2:Acceptance {id: 'a-2', text: 'D does not start until both B and C are recorded completed'})
16
+ CREATE (f)-[:HAS_ACCEPTANCE]->(a1), (f)-[:HAS_ACCEPTANCE]->(a2)
17
+
18
+ CREATE (a:GbuildNode:Chore {
19
+ slug: 'a-produce-shared-value', title: 'Produce the shared value B and C both need', type: 'chore',
20
+ acceptance: ['output.value is a single integer'],
21
+ failure_policy: 'retry', model_tier: 'cheap', status: 'pending'
22
+ })
23
+ CREATE (a)-[:OUTPUT]->(a_value:Field {name: 'value', shape: '<integer>'})
24
+
25
+ CREATE (b:GbuildNode:Code {
26
+ slug: 'b-consume-doubled', title: 'Consume the shared value, produce its double', type: 'code',
27
+ acceptance: ['output.doubled equals input.value multiplied by 2'],
28
+ failure_policy: 'repair', model_tier: 'cheap', status: 'pending'
29
+ })
30
+ CREATE (b)-[:DEPENDS_ON]->(a)
31
+ CREATE (b)-[:INPUT]->(:Field {name: 'value', shape: '<integer>'})-[:FROM]->(a_value)
32
+ CREATE (b)-[:OUTPUT]->(b_doubled:Field {name: 'doubled', shape: '<integer>'})
33
+ CREATE (b)-[:SATISFIES]->(a1)
34
+
35
+ CREATE (c:GbuildNode:Code {
36
+ slug: 'c-consume-squared', title: 'Consume the shared value, produce its square', type: 'code',
37
+ acceptance: ['output.squared equals input.value raised to the power of 2'],
38
+ failure_policy: 'repair', model_tier: 'cheap', status: 'pending'
39
+ })
40
+ CREATE (c)-[:DEPENDS_ON]->(a)
41
+ CREATE (c)-[:INPUT]->(:Field {name: 'value', shape: '<integer>'})-[:FROM]->(a_value)
42
+ CREATE (c)-[:OUTPUT]->(c_squared:Field {name: 'squared', shape: '<integer>'})
43
+ CREATE (c)-[:SATISFIES]->(a1)
44
+
45
+ CREATE (d:GbuildNode:Code {
46
+ slug: 'd-join-and-sum', title: 'Join B and C, produce their sum', type: 'code',
47
+ acceptance: ['output.sum equals input.doubled plus input.squared',
48
+ 'only runs after both b-consume-doubled and c-consume-squared are recorded completed'],
49
+ failure_policy: 'repair', model_tier: 'cheap', status: 'pending'
50
+ })
51
+ CREATE (d)-[:DEPENDS_ON]->(b), (d)-[:DEPENDS_ON]->(c)
52
+ CREATE (d)-[:INPUT]->(:Field {name: 'doubled', shape: '<integer>'})-[:FROM]->(b_doubled)
53
+ CREATE (d)-[:INPUT]->(:Field {name: 'squared', shape: '<integer>'})-[:FROM]->(c_squared)
54
+ CREATE (d)-[:OUTPUT]->(:Field {name: 'sum', shape: '<integer>'})
55
+ CREATE (d)-[:SATISFIES]->(a2);
56
+ .commit
57
+ .checkpoint