wao 0.40.0 → 0.40.2

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.
Files changed (37) hide show
  1. package/cjs/ao.js +4 -4
  2. package/cjs/create.js +32 -27
  3. package/cjs/workspace/.claude/agents/builder.md +4 -2
  4. package/cjs/workspace/.claude/skills/build/SKILL.md +34 -12
  5. package/cjs/workspace/.claude/skills/build-aos/SKILL.md +10 -1
  6. package/cjs/workspace/.claude/skills/build-device/SKILL.md +37 -23
  7. package/cjs/workspace/.claude/skills/build-frontend/SKILL.md +17 -14
  8. package/cjs/workspace/.claude/skills/build-module/SKILL.md +10 -1
  9. package/cjs/workspace/.claude/skills/plan/SKILL.md +12 -4
  10. package/cjs/workspace/.claude/skills/readme/SKILL.md +151 -45
  11. package/cjs/workspace/.claude/skills/report/SKILL.md +2 -1
  12. package/cjs/workspace/dashboard/index.html +154 -3
  13. package/cjs/workspace/dashboard/public/favicon.ico +0 -0
  14. package/cjs/workspace/dashboard/public/favicon.png +0 -0
  15. package/cjs/workspace/dashboard/server.js +93 -12
  16. package/cjs/workspace/dashboard/src/App.jsx +2297 -372
  17. package/cjs/workspace/docs/wao-sdk.md +1 -1
  18. package/cjs/workspace/package.json +1 -1
  19. package/esm/ao.js +3 -3
  20. package/esm/create.js +3 -0
  21. package/esm/workspace/.claude/agents/builder.md +4 -2
  22. package/esm/workspace/.claude/skills/build/SKILL.md +34 -12
  23. package/esm/workspace/.claude/skills/build-aos/SKILL.md +10 -1
  24. package/esm/workspace/.claude/skills/build-device/SKILL.md +37 -23
  25. package/esm/workspace/.claude/skills/build-frontend/SKILL.md +17 -14
  26. package/esm/workspace/.claude/skills/build-module/SKILL.md +10 -1
  27. package/esm/workspace/.claude/skills/plan/SKILL.md +12 -4
  28. package/esm/workspace/.claude/skills/readme/SKILL.md +151 -45
  29. package/esm/workspace/.claude/skills/report/SKILL.md +2 -1
  30. package/esm/workspace/dashboard/index.html +154 -3
  31. package/esm/workspace/dashboard/public/favicon.ico +0 -0
  32. package/esm/workspace/dashboard/public/favicon.png +0 -0
  33. package/esm/workspace/dashboard/server.js +93 -12
  34. package/esm/workspace/dashboard/src/App.jsx +2297 -372
  35. package/esm/workspace/docs/wao-sdk.md +1 -1
  36. package/esm/workspace/package.json +1 -1
  37. package/package.json +1 -1
package/cjs/ao.js CHANGED
@@ -1609,11 +1609,11 @@ var AO = /*#__PURE__*/function () {
1609
1609
  value: function () {
1610
1610
  var _ress2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee14(_ref16) {
1611
1611
  var _this4 = this;
1612
- var pid, limit, asc, cursor, err, msgs, next, res, sort, _t34;
1612
+ var pid, limit, asc, from, err, msgs, next, res, sort, _t34;
1613
1613
  return _regenerator().w(function (_context14) {
1614
1614
  while (1) switch (_context14.p = _context14.n) {
1615
1615
  case 0:
1616
- pid = _ref16.pid, limit = _ref16.limit, asc = _ref16.asc, cursor = _ref16.cursor;
1616
+ pid = _ref16.pid, limit = _ref16.limit, asc = _ref16.asc, from = _ref16.from;
1617
1617
  err = null;
1618
1618
  msgs = null;
1619
1619
  next = null;
@@ -1629,7 +1629,7 @@ var AO = /*#__PURE__*/function () {
1629
1629
  process: pid,
1630
1630
  limit: limit,
1631
1631
  sort: sort,
1632
- from: cursor
1632
+ from: from
1633
1633
  });
1634
1634
  case 2:
1635
1635
  res = _context14.v;
@@ -1641,7 +1641,7 @@ var AO = /*#__PURE__*/function () {
1641
1641
  process: pid,
1642
1642
  limit: limit,
1643
1643
  sort: sort,
1644
- from: cursor
1644
+ from: from
1645
1645
  });
1646
1646
  case 4:
1647
1647
  res = _context14.v;
package/cjs/create.js CHANGED
@@ -478,16 +478,21 @@ var main = /*#__PURE__*/function () {
478
478
  t.fail("Failed to install dependencies");
479
479
  return _context5.a(2);
480
480
  case 15:
481
+ t.sub("root dependencies installed");
482
+ _context5.n = 16;
483
+ return exec("cd \"".concat(appdir, "/dashboard\" && npm install"));
484
+ case 16:
485
+ t.sub("dashboard dependencies installed");
481
486
  t.done();
482
487
  hbWarnings = [];
483
488
  if (!(hbMode !== "skip")) {
484
- _context5.n = 26;
489
+ _context5.n = 27;
485
490
  break;
486
491
  }
487
492
  t.step("Detecting HyperBEAM environment");
488
- _context5.n = 16;
493
+ _context5.n = 17;
489
494
  return detectHBEnv();
490
- case 16:
495
+ case 17:
491
496
  _yield$detectHBEnv = _context5.v;
492
497
  deps = _yield$detectHBEnv.deps;
493
498
  missing = _yield$detectHBEnv.missing;
@@ -522,24 +527,24 @@ var main = /*#__PURE__*/function () {
522
527
  t.sub(".env.hyperbeam \u2192 CWD=".concat(hbCwd));
523
528
  t.done();
524
529
  if (!(hbMode === "clone")) {
525
- _context5.n = 23;
530
+ _context5.n = 24;
526
531
  break;
527
532
  }
528
533
  t.step("Cloning HyperBEAM");
529
534
  t.sub("tag: ".concat(HB_TAG));
530
- _context5.n = 17;
535
+ _context5.n = 18;
531
536
  return exec("cd \"".concat(appdir, "\" && git clone --depth 1 --branch ").concat(HB_TAG, " ").concat(HB_REPO, " HyperBEAM"), {
532
537
  maxBuffer: 50 * 1024 * 1024,
533
538
  timeout: 600000
534
539
  });
535
- case 17:
540
+ case 18:
536
541
  t.done();
537
542
  if (!(deps.erl && deps.rebar3 && missing.length === 0)) {
538
- _context5.n = 22;
543
+ _context5.n = 23;
539
544
  break;
540
545
  }
541
546
  t.step("Compiling HyperBEAM (with genesis-wasm)");
542
- _context5.p = 18;
547
+ _context5.p = 19;
543
548
  envParts = [];
544
549
  if (deps.gcc) {
545
550
  envParts.push("CC=gcc-".concat(deps.gcc), "CXX=g++-".concat(deps.gcc));
@@ -548,46 +553,46 @@ var main = /*#__PURE__*/function () {
548
553
  envParts.push("CMAKE_POLICY_VERSION_MINIMUM=3.5");
549
554
  }
550
555
  envPrefix = envParts.join(" ");
551
- _context5.n = 19;
556
+ _context5.n = 20;
552
557
  return exec("cd \"".concat(appdir, "/HyperBEAM\" && ").concat(envPrefix, " rebar3 as genesis_wasm compile"), {
553
558
  maxBuffer: 50 * 1024 * 1024,
554
559
  timeout: 600000
555
560
  });
556
- case 19:
561
+ case 20:
557
562
  t.sub("genesis-wasm device compiled");
558
563
  t.done();
559
- _context5.n = 21;
564
+ _context5.n = 22;
560
565
  break;
561
- case 20:
562
- _context5.p = 20;
566
+ case 21:
567
+ _context5.p = 21;
563
568
  _t4 = _context5.v;
564
569
  t.fail("Compile failed — check .env.hyperbeam and run manually");
565
- case 21:
566
- _context5.n = 23;
567
- break;
568
570
  case 22:
571
+ _context5.n = 24;
572
+ break;
573
+ case 23:
569
574
  if (missing.length > 0) {
570
575
  t.step("Skipping compilation (missing dependencies)");
571
576
  t.sub("Run 'cd HyperBEAM && rebar3 compile' after installing dependencies");
572
577
  t.done();
573
578
  }
574
- case 23:
579
+ case 24:
575
580
  // Generate wallet in HyperBEAM directory
576
581
  hbWalletDir = (0, _path.resolve)(appdir, hbCwd);
577
582
  t.step("Generating HyperBEAM wallet");
578
583
  hbArweave = _arweave["default"].init();
579
- _context5.n = 24;
584
+ _context5.n = 25;
580
585
  return hbArweave.wallets.generate();
581
- case 24:
586
+ case 25:
582
587
  hbJwk = _context5.v;
583
- _context5.n = 25;
588
+ _context5.n = 26;
584
589
  return hbArweave.wallets.jwkToAddress(hbJwk);
585
- case 25:
590
+ case 26:
586
591
  hbAddr = _context5.v;
587
592
  (0, _fs.writeFileSync)((0, _path.resolve)(hbWalletDir, ".wallet.json"), JSON.stringify(hbJwk));
588
593
  t.sub("address: ".concat(hbAddr));
589
594
  t.done();
590
- case 26:
595
+ case 27:
591
596
  if (withFrontend) {
592
597
  t.step("Setting up frontend");
593
598
  t.sub("Vite + React + wao/web");
@@ -634,16 +639,16 @@ var main = /*#__PURE__*/function () {
634
639
  console.log(" ".concat(dim("$"), " yarn deploy src/counter.lua --wallet .wallet.json"));
635
640
  console.log();
636
641
  });
637
- _context5.n = 28;
642
+ _context5.n = 29;
638
643
  break;
639
- case 27:
640
- _context5.p = 27;
644
+ case 28:
645
+ _context5.p = 28;
641
646
  _t5 = _context5.v;
642
647
  t.fail(_t5.message);
643
- case 28:
648
+ case 29:
644
649
  return _context5.a(2);
645
650
  }
646
- }, _callee5, null, [[18, 20], [7, 27]]);
651
+ }, _callee5, null, [[19, 21], [7, 28]]);
647
652
  }));
648
653
  return function main() {
649
654
  return _ref5.apply(this, arguments);
@@ -35,8 +35,10 @@ Read these before building:
35
35
  - **aos**: Write AOS scripts in `src/` with input validation
36
36
  - **aos-test**: Write in-memory tests in `test/`, iterate until `yarn test` passes
37
37
  - **aos-integration**: Write HyperBEAM tests, iterate until they pass
38
- - **device**: Write Erlang module, compile with `rebar3 as genesis_wasm compile`
39
- - **device-test**: Write eunit tests, iterate until `rebar3 eunit` passes
38
+ - **module-lua**: Write standalone Lua module in `custom-lua/`, no AOS framework
39
+ - **module-wasm**: Write Rust WASM64 module in `custom-wasm/`, `#![no_std]`
40
+ - **module-test**: Write HyperBEAM integration tests for custom modules
41
+ - **device**: Write Erlang device + inline eunit tests in same `.erl` file, compile with `rebar3 as genesis_wasm compile`, iterate until `rebar3 eunit` passes
40
42
  - **device-integration**: Write WAO SDK integration tests against running HyperBEAM
41
43
  - **frontend**: Write React components with `wao/web`
42
44
  - **frontend-test**: Write vitest tests, iterate until they pass
@@ -31,7 +31,20 @@ Full build orchestrator. Sequences through plan → build → test → validate
31
31
 
32
32
  ### 1. Check for existing plan (resume support)
33
33
 
34
- Read `plan.md` and `tasks.json` at the project root. If both exist and tasks.json has `"current_step"`, resume from that step — skip to the first task with `"status": "pending"` or `"in_progress"`.
34
+ Read `plan.md` and `tasks.json` at the project root. If both exist and tasks.json has `"current_step"`, resume:
35
+
36
+ 1. Find the first task with `"status": "in_progress"` — resume debugging that task immediately.
37
+ 2. If no `in_progress` task, find the first task with `"status": "pending"` — start it.
38
+ 3. If ALL tasks are `"done"`, **re-verify every test task** by running its tests:
39
+ - `aos-test` → `yarn test <files>`
40
+ - `aos-integration` → `yarn test <files>`
41
+ - `device` → `cd $HB_DIR && rebar3 eunit --module=<module>`
42
+ - `device-integration` → `yarn test <files>`
43
+ - `frontend-test` → `cd frontend && npm run test:unit`
44
+ - `frontend-integration` → `cd frontend && npm run test:e2e`
45
+ - `validate` → run all validation gates
46
+
47
+ If any test task fails, set that task back to `"in_progress"` in tasks.json and resume debugging it. Do NOT skip over failing tests just because the task was previously marked done.
35
48
 
36
49
  If no plan exists, proceed to step 2.
37
50
 
@@ -75,7 +88,7 @@ Before starting the build loop, check which tracks are selected and verify their
75
88
  grep '^CWD=' .env.hyperbeam 2>/dev/null | cut -d= -f2-
76
89
  ```
77
90
 
78
- If the plan includes `device`, `device-test`, `device-integration`, `aos-integration`, `module-lua`, `module-wasm`, or `module-test` tasks, verify:
91
+ If the plan includes `device`, `device-integration`, `aos-integration`, `module-lua`, `module-wasm`, or `module-test` tasks, verify:
79
92
 
80
93
  1. `.env.hyperbeam` exists and has a `CWD` value
81
94
  2. The `CWD` path points to a valid HyperBEAM directory (`$CWD/src` exists)
@@ -108,8 +121,7 @@ b. Read the skill file for this task's type and follow its instructions. The map
108
121
  | `module-lua` | `.claude/skills/build-module/SKILL.md` |
109
122
  | `module-wasm` | `.claude/skills/build-module/SKILL.md` |
110
123
  | `module-test` | `.claude/skills/build-module/SKILL.md` |
111
- | `device` | `.claude/skills/build-device/SKILL.md` |
112
- | `device-test` | `.claude/skills/build-device/SKILL.md` |
124
+ | `device` | `.claude/skills/build-device/SKILL.md` (eunit tests are inline — same file) |
113
125
  | `device-integration` | `.claude/skills/test-device/SKILL.md` |
114
126
  | `frontend` | `.claude/skills/build-frontend/SKILL.md` |
115
127
  | `frontend-test` | `.claude/skills/build-frontend/SKILL.md` |
@@ -125,12 +137,21 @@ d. After completing, verify the task's `done_when` criteria are met:
125
137
 
126
138
  e. If the criteria are met, update the task status to `"done"` in `tasks.json`.
127
139
 
128
- f. If a step fails, retry up to 3 times. On each retry:
129
- - Read the error output
130
- - Fix the code
131
- - Re-run
132
-
133
- g. If still failing after 3 attempts, **stop and ask the user**: retry, skip, or debug manually?
140
+ f. **If tests fail, keep debugging.** Do not stop. On each iteration:
141
+ 1. Read the full error output — stack traces, assertion messages, log lines
142
+ 2. Identify the root cause (wrong logic, missing handler, bad import, timing issue, etc.)
143
+ 3. Fix the code — not the test, unless the test itself has a bug
144
+ 4. Re-run the failing test file specifically (faster feedback than full suite)
145
+ 5. If the same error persists after 3 different fix attempts, step back:
146
+ - Re-read the relevant docs (AOS patterns, HyperBEAM device protocol, etc.)
147
+ - Check if the plan itself has a wrong assumption
148
+ - Try a completely different approach
149
+ 6. Continue iterating until all tests pass — there is no retry limit
150
+
151
+ g. Only escalate to the user if:
152
+ - The failure is environmental (port conflict, missing binary, permissions)
153
+ - The test requires user input (wallet, external service URL)
154
+ - You've tried 10+ iterations with no progress on the same error
134
155
 
135
156
  h. Move to the next task.
136
157
 
@@ -161,7 +182,8 @@ Overall: PASS / FAIL
161
182
 
162
183
  ## Failure handling
163
184
 
164
- - If a skill exits with test failures, read the output, fix the code, and re-run.
185
+ - **Test failures are expected.** The build loop is: write code → run tests → read failures fix → re-run. This is the core loop — never skip it, never give up early.
186
+ - If a skill exits with test failures, read the full output, diagnose the root cause, fix the code (not the test), and re-run. Keep iterating until 100% pass.
165
187
  - If a skill cannot be dispatched (unknown type), skip and warn.
166
188
  - If the user interrupts, save current state to tasks.json so the next session can resume.
167
189
 
@@ -180,7 +202,7 @@ Never force a task to `done` status with failing tests. The TaskCompleted hook w
180
202
 
181
203
  ### Build stalls on a single task
182
204
  - Check if it's a test failure loop — read the last test output
183
- - If the same error repeats 3 times, the issue may be in the plan, not the code
205
+ - If the same error persists after 3 different fix attempts, step back and reconsider the plan may have a wrong assumption
184
206
  - Run `/debug` to diagnose port/process/WASM issues
185
207
 
186
208
  ### Resume doesn't pick up the right task
@@ -117,4 +117,13 @@ For each test-fix cycle:
117
117
  3. Classify: is the bug in source code or test code?
118
118
  4. Fix ONE issue per iteration (don't change multiple things at once)
119
119
  5. Re-run only the failing test first, then full suite
120
- 6. If the same test fails 3 times with the same error, stop and reconsider the approach — the plan may need updating
120
+ 6. If the same error persists after 3 different fix attempts, step back:
121
+ - Re-read the relevant docs (AOS patterns, Lua conventions, etc.)
122
+ - Check if the plan itself has a wrong assumption
123
+ - Try a completely different approach
124
+ 7. Continue iterating until all tests pass — there is no retry limit
125
+
126
+ Only escalate to the user if:
127
+ - The failure is environmental (missing binary, permissions, port conflict)
128
+ - The test requires user input (wallet, external service URL)
129
+ - You've tried 10+ iterations with no progress on the same error
@@ -59,7 +59,7 @@ Do NOT mark the task as done if any prerequisite fails. Set the task status to `
59
59
 
60
60
  3. Read `docs/hyperbeam-dev.md` for the device protocol (arity/3 functions, state management, auth patterns).
61
61
 
62
- 4. **If the task type is `device`**write the Erlang device:
62
+ 4. Write the Erlang device with **inline eunit tests** (HyperBEAM convention device and tests live in the same file):
63
63
 
64
64
  Write `$HB_DIR/src/dev_{name}.erl`:
65
65
 
@@ -67,6 +67,9 @@ Do NOT mark the task as done if any prerequisite fails. Set the task status to `
67
67
  -module(dev_{name}).
68
68
  -export([info/3, init/3, compute/3]).
69
69
  -include("include/hb.hrl").
70
+ -ifdef(TEST).
71
+ -include_lib("eunit/include/eunit.hrl").
72
+ -endif.
70
73
 
71
74
  %% Exports: list available keys
72
75
  info(_Msg1, _Msg2, Opts) ->
@@ -88,35 +91,37 @@ Do NOT mark the task as done if any prerequisite fails. Set the task status to `
88
91
  {ok, Msg1};
89
92
  handle_action(_, Msg1, _Msg2, _Opts) ->
90
93
  {ok, hb_maps:put(<<"Error">>, <<"Unknown action">>, Msg1)}.
91
- ```
92
-
93
- Key patterns:
94
- - Use `hb_maps` for state (not plain maps)
95
- - Use `hb_private` for secrets
96
- - Use `ar_wallet` for auth/signing
97
- - Route actions via `hb_ao:get(<<"Action">>, Msg2, Opts)`
98
- - Return `{ok, UpdatedMsg}` or `{error, Reason}`
99
-
100
- 5. **If the task type is `device-test`** — write eunit tests:
101
-
102
- Write `$HB_DIR/test/dev_{name}_tests.erl`:
103
94
 
104
- ```erlang
105
- -module(dev_{name}_tests).
106
- -include_lib("eunit/include/eunit.hrl").
95
+ %%%===================================================================
96
+ %%% EUnit Tests (inline — HyperBEAM convention)
97
+ %%%===================================================================
98
+ -ifdef(TEST).
107
99
 
108
100
  info_test() ->
109
- {ok, Info} = dev_{name}:info(#{}, #{}, #{}),
101
+ {ok, Info} = info(#{}, #{}, #{}),
110
102
  ?assertMatch(#{<<"exports">> := _}, Info).
111
103
 
112
104
  compute_test() ->
113
- {ok, State} = dev_{name}:init(#{}, #{}, #{}),
105
+ {ok, State} = init(#{}, #{}, #{}),
114
106
  Msg = #{<<"Action">> => <<"MyAction">>},
115
- {ok, Result} = dev_{name}:compute(State, Msg, #{}),
107
+ {ok, Result} = compute(State, Msg, #{}),
116
108
  ?assertMatch(#{}, Result).
109
+
110
+ -endif.
117
111
  ```
118
112
 
119
- 6. Compile (use the `$HB_DIR` path):
113
+ Key patterns:
114
+ - **Device + tests in same file** — use `-ifdef(TEST).` / `-endif.` guards
115
+ - Tests call local functions directly (no `module:function` prefix needed)
116
+ - Use `hb_maps` for state (not plain maps)
117
+ - Use `hb_private` for secrets
118
+ - Use `ar_wallet` for auth/signing
119
+ - Route actions via `hb_ao:get(<<"Action">>, Msg2, Opts)`
120
+ - Return `{ok, UpdatedMsg}` or `{error, Reason}`
121
+
122
+ **Do NOT create separate test files** in `$HB_DIR/test/`. All eunit tests go inline in the device source file.
123
+
124
+ 5. Compile (use the `$HB_DIR` path):
120
125
 
121
126
  ```bash
122
127
  cd $HB_DIR && rebar3 as genesis_wasm compile
@@ -130,10 +135,10 @@ Do NOT mark the task as done if any prerequisite fails. Set the task status to `
130
135
 
131
136
  If the beam file is missing, compilation failed silently. Read the full output and fix.
132
137
 
133
- 7. Run eunit tests:
138
+ 6. Run eunit tests (note: test the device module directly, not a separate test module):
134
139
 
135
140
  ```bash
136
- cd $HB_DIR && rebar3 eunit --module=dev_{name}_tests
141
+ cd $HB_DIR && rebar3 eunit --module=dev_{name}
137
142
  ```
138
143
 
139
144
  8. If compilation errors or test failures:
@@ -175,4 +180,13 @@ For each test-fix cycle:
175
180
  3. Classify: is the bug in source code or test code?
176
181
  4. Fix ONE issue per iteration (don't change multiple things at once)
177
182
  5. Re-run only the failing test first, then full suite
178
- 6. If the same test fails 3 times with the same error, stop and reconsider the approach — the plan may need updating
183
+ 6. If the same error persists after 3 different fix attempts, step back:
184
+ - Re-read the relevant docs (HyperBEAM device protocol, Erlang patterns, etc.)
185
+ - Check if the plan itself has a wrong assumption
186
+ - Try a completely different approach
187
+ 7. Continue iterating until all tests pass — there is no retry limit
188
+
189
+ Only escalate to the user if:
190
+ - The failure is environmental (rebar3 missing, Erlang version, port conflict)
191
+ - The test requires user input (wallet, external service URL)
192
+ - You've tried 10+ iterations with no progress on the same error
@@ -112,20 +112,23 @@ cd frontend && npx playwright --version 2>/dev/null || echo "Playwright not inst
112
112
  cd frontend && npm run test:unit
113
113
  ```
114
114
 
115
- 7. If any tests fail:
116
- - Read the error output
117
- - Fix the component or test code
118
- - Re-run tests
119
- - Repeat until **100% pass**
115
+ 7. **If tests fail, keep debugging.** Do not stop. On each iteration:
116
+ 1. Read the full error output — stack traces, assertion messages, log lines
117
+ 2. Identify the FIRST failing test (fix failures in order)
118
+ 3. Classify: is the bug in component code or test code?
119
+ 4. Fix ONE issue per iteration (don't change multiple things at once)
120
+ 5. Re-run the failing test file specifically (faster feedback than full suite)
121
+ 6. If the same error persists after 3 different fix attempts, step back:
122
+ - Re-read the relevant docs (`wao/web` patterns, React testing library, vitest mocking)
123
+ - Check if the plan itself has a wrong assumption
124
+ - Try a completely different approach
125
+ 7. Continue iterating until all tests pass — there is no retry limit
126
+
127
+ Only escalate to the user if:
128
+ - The failure is environmental (missing dependency, port conflict, permissions)
129
+ - The test requires user input (wallet, external service URL)
130
+ - You've tried 10+ iterations with no progress on the same error
120
131
 
121
132
  8. Update the task status to `"done"` in `tasks.json`.
122
133
 
123
- ## Iteration Protocol
124
-
125
- For each test-fix cycle:
126
- 1. Run tests and capture FULL output
127
- 2. Identify the FIRST failing test (fix failures in order)
128
- 3. Classify: is the bug in source code or test code?
129
- 4. Fix ONE issue per iteration (don't change multiple things at once)
130
- 5. Re-run only the failing test first, then full suite
131
- 6. If the same test fails 3 times with the same error, stop and reconsider the approach — the plan may need updating
134
+ **IMPORTANT**: Only mark done if all tests pass 100%.
@@ -244,7 +244,16 @@ For each test-fix cycle:
244
244
  3. Classify: is the bug in module code or test code?
245
245
  4. Fix ONE issue per iteration (don't change multiple things at once)
246
246
  5. Re-run only the failing test first, then full suite
247
- 6. If the same test fails 3 times with the same error, stop and reconsider the approach — the plan may need updating
247
+ 6. If the same error persists after 3 different fix attempts, step back:
248
+ - Re-read the relevant docs (custom module patterns, WASM64/Lua conventions, etc.)
249
+ - Check if the plan itself has a wrong assumption
250
+ - Try a completely different approach
251
+ 7. Continue iterating until all tests pass — there is no retry limit
252
+
253
+ Only escalate to the user if:
254
+ - The failure is environmental (cargo missing, WASM build tools, port conflict)
255
+ - The test requires user input (wallet, external service URL)
256
+ - You've tried 10+ iterations with no progress on the same error
248
257
 
249
258
  ## Troubleshooting
250
259
 
@@ -119,8 +119,7 @@ Plan a feature before building it. The plan and tasks are written to files so an
119
119
  | `module-lua` | `/build-module` |
120
120
  | `module-wasm` | `/build-module` |
121
121
  | `module-test` | `/build-module` |
122
- | `device` | `/build-device` |
123
- | `device-test` | `/build-device` |
122
+ | `device` | `/build-device` (eunit tests inline — same file) |
124
123
  | `device-integration` | `/test-device` |
125
124
  | `frontend` | `/build-frontend` |
126
125
  | `frontend-test` | `/build-frontend` |
@@ -134,8 +133,8 @@ Plan a feature before building it. The plan and tasks are written to files so an
134
133
  - Tests: `{ "type": "module-test", "skill": "/build-module", "files": ["test/{name}-module.test.js"], "done_when": "yarn test test/{name}-module.test.js — all pass" }`
135
134
 
136
135
  **Device tasks** (if building Erlang devices) — add `"device"` to `tracks` array and add these to `tasks`:
137
- - `{ "type": "device", "skill": "/build-device", "files": ["HyperBEAM/src/dev_{name}.erl"], "done_when": "rebar3 as genesis_wasm compileno errors" }`
138
- - `{ "type": "device-test", "skill": "/build-device", "files": ["HyperBEAM/test/dev_{name}_tests.erl"], "done_when": "rebar3 eunit all pass" }`
136
+ - `{ "type": "device", "skill": "/build-device", "files": ["HyperBEAM/src/dev_{name}.erl"], "done_when": "rebar3 compile + eunitall pass" }`
137
+ - **HyperBEAM convention**: device source and eunit tests live in the same `.erl` file using `-ifdef(TEST).` guards. Do NOT create separate test files in `HyperBEAM/test/`.
139
138
  - `{ "type": "device-integration", "skill": "/test-device", "files": ["test/{name}-device.test.js"], "done_when": "yarn test test/{name}-device.test.js — all pass" }`
140
139
 
141
140
  **Frontend tasks** (if building frontend) — add `"frontend"` to `tracks` array and add these to `tasks`:
@@ -149,6 +148,15 @@ Plan a feature before building it. The plan and tasks are written to files so an
149
148
  **Final validation** — always the last task:
150
149
  - `{ "type": "validate", "skill": "/validate", "done_when": "overall PASS" }`
151
150
 
151
+ ### IMPORTANT: Replace all placeholders with actual names
152
+
153
+ The templates above use `{name}` as a placeholder. When writing `tasks.json`, replace ALL placeholders with the actual file names from the plan. For example:
154
+ - `"files": ["src/{name}.lua"]` → `"files": ["src/token.lua", "src/registry.lua"]`
155
+ - `"files": ["test/{name}.test.js"]` → `"files": ["test/token.test.js", "test/registry.test.js"]`
156
+ - `"done_when": "yarn test test/{name}.test.js — all pass"` → `"done_when": "yarn test test/token.test.js test/registry.test.js — all pass"`
157
+
158
+ The `files` array must list every actual file the task will create. The `done_when` must reference the actual test commands. Never leave `{name}` as a literal string in the output.
159
+
152
160
  ### Task ordering rules
153
161
 
154
162
  The build order matters. Within each component: