@codedology/code-forge 0.14.0 → 0.15.0

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 (42) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +136 -438
  3. package/docs/README.md +1 -1
  4. package/docs/reference/blocks.json +420 -1
  5. package/docs/reference/config.md +7 -0
  6. package/package.json +1 -1
  7. package/schema/code-forge.schema.json +22 -0
  8. package/scripts/first-use.mjs +11 -5
  9. package/skill/SKILL.md +2 -0
  10. package/skill/references/autopilot.md +2 -0
  11. package/skill/references/code.md +25 -1
  12. package/skill/references/review.md +10 -2
  13. package/skill/scripts/forge +1 -1
  14. package/src/autopilot/scopes.mjs +2 -1
  15. package/src/cli/block.mjs +235 -44
  16. package/src/cli/gates.mjs +36 -6
  17. package/src/cli/ledger.mjs +21 -2
  18. package/src/cli/report.mjs +14 -0
  19. package/src/cli/review-file.mjs +56 -16
  20. package/src/cli/run.mjs +44 -7
  21. package/src/cli/status.mjs +7 -3
  22. package/src/cli/upgrade.mjs +95 -15
  23. package/src/config/validate.mjs +13 -1
  24. package/src/gates/acceptance.mjs +7 -3
  25. package/src/gates/expand.mjs +25 -2
  26. package/src/gates/run.mjs +38 -8
  27. package/src/install/link.mjs +12 -6
  28. package/src/ledger/report.mjs +29 -7
  29. package/src/review/accept-hit.mjs +22 -4
  30. package/src/review/engine.mjs +30 -10
  31. package/src/review/finding.schema.json +2 -1
  32. package/src/review/fixloop.mjs +79 -14
  33. package/src/review/gate-check.mjs +22 -3
  34. package/src/review/lenses/recheck.md +3 -0
  35. package/src/review/packet.mjs +26 -0
  36. package/src/state/block.mjs +162 -20
  37. package/src/state/run.mjs +35 -8
  38. package/src/util/forbidden.mjs +14 -0
  39. package/src/util/reaper.mjs +3 -3
  40. package/src/worker/engine.mjs +60 -4
  41. package/src/worker/loop.mjs +19 -10
  42. package/src/worker/queue.mjs +5 -2
package/docs/README.md CHANGED
@@ -31,7 +31,7 @@ then 5a. Going away while a run goes on? Read 5b. One small task, no plan? Read
31
31
  | [reference/blocks.json](reference/blocks.json) | the build blocks of this package and what each one owns |
32
32
  | [marketing/code-forge-story.md](marketing/code-forge-story.md) | the marketing content bank (copy, lessons, what not to claim) |
33
33
  | [privacy.md](privacy.md) | what the local error log holds (errors, warnings, the last command names), every cleaning rule, the AI check, the setup check (`--with-doctor`), known fixes, and how to turn the log off or delete it |
34
- | [releasing.md](releasing.md) | for maintainers: record changes (`npm run changelog`) and known fixes (`npm run known-fix`), cut a release with one command (`npm run release`), publish by hand, GitHub Releases, the error-triage Action |
34
+ | [releasing.md](releasing.md) | for maintainers: record changes (`npm run changelog`) and known fixes (`npm run known-fix`); release history lives only in CHANGELOG; releases update the optional README `Latest:` line; checks, commit, tag, manual publish, GitHub Releases, and the error-triage Action |
35
35
  | [`skill/SKILL.md`](../skill/SKILL.md) and [`skill/references/`](../skill/references/) | the Agent Skill the orchestrator follows. The deepest and most exact description of the rules |
36
36
 
37
37
  ## Conventions in these pages
@@ -4,7 +4,7 @@
4
4
  "plans/code-forge-plan-v1.3.md §10.4",
5
5
  "plans/NIGHT-LOG.md"
6
6
  ],
7
- "block_count": 133,
7
+ "block_count": 149,
8
8
  "baseline_ids": ["B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8"],
9
9
  "baseline_note": "Wave 0-1 blocks, landed before v1.3; depends_on may name them, but they have no entry under blocks.",
10
10
  "blocks": {
@@ -2335,6 +2335,425 @@
2335
2335
  "B123"
2336
2336
  ],
2337
2337
  "note": "block reopen <id> --file --reason --yes: the reason must cite evidence (reopen-yes-no-evidence), a fresh judge must agree (reopen-yes-disagreed), at most one agent reopen per block and file per run (reopen-yes-limit); the row is by: agent. An agreed, verified agent reopen supersedes the B123 cap like a human reopen. block close --json lists agent_reopens. Without --yes the verb still needs human confirmation."
2338
+ },
2339
+ "B128": {
2340
+ "title": "CI green on Linux Node 22 and 24: test isolation flag both versions accept; claim fixture publishes its counts atomically",
2341
+ "wave": 14,
2342
+ "level": "L2",
2343
+ "status": "landed",
2344
+ "owned": [
2345
+ "test/no-leak-final.test.mjs",
2346
+ "test/worker/claim.test.mjs"
2347
+ ],
2348
+ "depends_on": [
2349
+ "B115"
2350
+ ],
2351
+ "note": "Root cause: the claim fixture created its completion file before it wrote the count, so a Linux inotify wake could read an empty file as 0. Write to a temp file and rename. Node 22.23 rejects --test-isolation=none; use --experimental-test-isolation=none."
2352
+ },
2353
+ "B130": {
2354
+ "title": "README for new users; per-version history lives only in CHANGELOG; release updates only the Latest line",
2355
+ "wave": 14,
2356
+ "level": "L2",
2357
+ "status": "landed",
2358
+ "owned": [
2359
+ "README.md",
2360
+ "scripts/release.mjs",
2361
+ "docs/releasing.md",
2362
+ "docs/README.md",
2363
+ "CHANGELOG.md",
2364
+ "test/release-readme.test.mjs",
2365
+ "test/release.test.mjs",
2366
+ "test/docs-marketing.test.mjs",
2367
+ "test/skill/structure.test.mjs"
2368
+ ],
2369
+ "depends_on": [
2370
+ "B108"
2371
+ ],
2372
+ "note": "README went from 474 to 171 lines: pitch, problem, install, quickstart, how it works, commands, agents, security, links (incl. public roadmap). Release no longer moves README bullets."
2373
+ },
2374
+ "B129": {
2375
+ "title": "upgrade prints an ASCII code-forge logo, the version change and what's new; --plain for scripts",
2376
+ "wave": 14,
2377
+ "level": "L2",
2378
+ "status": "landed",
2379
+ "owned": [
2380
+ "src/cli/upgrade.mjs",
2381
+ "src/install/link.mjs",
2382
+ "test/install/cli-upgrade.test.mjs",
2383
+ "test/install/link.test.mjs",
2384
+ "docs/getting-started.md",
2385
+ "README.md",
2386
+ "CHANGELOG.md"
2387
+ ],
2388
+ "depends_on": [
2389
+ "B130"
2390
+ ],
2391
+ "note": "Install records get an optional version field. Summary: logo, 'code-forge <v>', '<old> -> <new>' / 'already on' / 'first versioned upgrade', kept record lines, first 5 CHANGELOG bullets, 'Full notes: <path>'."
2392
+ },
2393
+ "B131": {
2394
+ "title": "Budget split counts removed lines; Markdown steps up to full; join reports an outcome per file and queues owned files with no ticket",
2395
+ "wave": 14,
2396
+ "level": "L2",
2397
+ "status": "landed",
2398
+ "owned": [
2399
+ "src/review/engine.mjs",
2400
+ "src/cli/review-file.mjs",
2401
+ "skill/references/review.md",
2402
+ "docs/how-it-works.md",
2403
+ "CHANGELOG.md",
2404
+ "test/review/budget-step-up.test.mjs",
2405
+ "test/worker/wait-block.test.mjs",
2406
+ "test/worker/watch.test.mjs",
2407
+ "test/skill/structure.test.mjs"
2408
+ ],
2409
+ "depends_on": [
2410
+ "B130"
2411
+ ],
2412
+ "note": "split_required only above full_in; --wait-block files carry outcome (approved/findings/stopped/split_required/unavailable/null); split_required gives done:false with reason and next."
2413
+ },
2414
+ "B132": {
2415
+ "title": "A lens budget change reruns a split_required stop for the lens that was measured",
2416
+ "wave": 14,
2417
+ "level": "L2",
2418
+ "status": "landed",
2419
+ "owned": [
2420
+ "src/cli/review-file.mjs",
2421
+ "src/worker/ticket.mjs",
2422
+ "src/worker/queue.mjs",
2423
+ "src/review/fixloop.mjs",
2424
+ "skill/references/review.md",
2425
+ "CHANGELOG.md",
2426
+ "test/worker/fresh-split.test.mjs",
2427
+ "test/worker/fresh.test.mjs"
2428
+ ],
2429
+ "depends_on": [
2430
+ "B131"
2431
+ ],
2432
+ "note": "F2: --fresh re-queues a counted split_required stop when its lens budget changed; the stop keeps its real lens (full, recheck or patch_check)."
2433
+ },
2434
+ "B135": {
2435
+ "title": "Small CLI fixes: unknown ledger slugs, comma path lists, competing worker runs, /bin/ps, close needs green gates, accept-hit per line",
2436
+ "wave": 14,
2437
+ "level": "L1",
2438
+ "status": "landed",
2439
+ "owned": [
2440
+ "src/cli/report.mjs",
2441
+ "src/cli/ledger.mjs",
2442
+ "src/cli/block.mjs",
2443
+ "src/worker/loop.mjs",
2444
+ "src/worker/queue.mjs",
2445
+ "src/util/reaper.mjs",
2446
+ "src/state/run.mjs",
2447
+ "src/review/accept-hit.mjs",
2448
+ "skill/references/code.md",
2449
+ "CHANGELOG.md",
2450
+ "test/ledger/report.test.mjs",
2451
+ "test/ledger/cli.test.mjs",
2452
+ "test/ledger/calibration.test.mjs",
2453
+ "test/cli",
2454
+ "test/worker/registry.test.mjs",
2455
+ "test/util/reaper.test.mjs",
2456
+ "test/state/run.test.mjs",
2457
+ "test/review/close-gate.test.mjs",
2458
+ "test/review/close-gate-field.test.mjs",
2459
+ "test/review/gate-check.test.mjs"
2460
+ ],
2461
+ "depends_on": [
2462
+ "B130"
2463
+ ],
2464
+ "note": "Closed after review, then held: the full suite showed regressions. Its changes landed through B135b."
2465
+ },
2466
+ "B135b": {
2467
+ "title": "Finish B135: future test paths and brace globs allowed, first-use runs gates before close",
2468
+ "wave": 14,
2469
+ "level": "L1",
2470
+ "status": "landed",
2471
+ "owned": [
2472
+ "src/cli/report.mjs",
2473
+ "src/cli/ledger.mjs",
2474
+ "src/cli/block.mjs",
2475
+ "src/worker/loop.mjs",
2476
+ "src/util/reaper.mjs",
2477
+ "src/state/run.mjs",
2478
+ "src/review/accept-hit.mjs",
2479
+ "skill/references/code.md",
2480
+ "CHANGELOG.md",
2481
+ "test/ledger/report.test.mjs",
2482
+ "test/ledger/cli.test.mjs",
2483
+ "test/ledger/calibration.test.mjs",
2484
+ "test/cli",
2485
+ "test/worker/registry.test.mjs",
2486
+ "test/util/reaper.test.mjs",
2487
+ "test/state/run.test.mjs",
2488
+ "test/review/close-gate.test.mjs",
2489
+ "test/review/close-gate-field.test.mjs",
2490
+ "test/review/gate-check.test.mjs",
2491
+ "test/docs-marketing.test.mjs",
2492
+ "scripts/first-use.mjs",
2493
+ "test/first-use.test.mjs",
2494
+ "test/gates/placeholders.test.mjs",
2495
+ "test/proof/worktree-flow.test.mjs",
2496
+ "test/review/external.test.mjs"
2497
+ ],
2498
+ "depends_on": [
2499
+ "B135",
2500
+ "B131"
2501
+ ],
2502
+ "note": "Carries the reviewed B135 changes onto the B131 base. A false critical finding was cleared by an answers ticket (B71), not a waiver."
2503
+ },
2504
+ "B133": {
2505
+ "title": "A recheck must not repeat a stale finding: evidence in the recheck packet, current_lines quote, stale and repeated findings",
2506
+ "wave": 14,
2507
+ "level": "L2",
2508
+ "status": "landed",
2509
+ "owned": [
2510
+ "src/review/fixloop.mjs",
2511
+ "src/review/lenses/recheck.md",
2512
+ "src/review/finding.schema.json",
2513
+ "src/review/validate-review.mjs",
2514
+ "skill/references/review.md",
2515
+ "CHANGELOG.md",
2516
+ "test/review/fixloop.test.mjs",
2517
+ "test/review/validate-review.test.mjs",
2518
+ "test/review/recheck-real.test.mjs"
2519
+ ],
2520
+ "depends_on": [
2521
+ "B132"
2522
+ ],
2523
+ "note": "Stopped after review: the acceptance saved at open had a wrong stale rule. Its changes landed through B133b."
2524
+ },
2525
+ "B133b": {
2526
+ "title": "Finish B133: stale only when a quoted current_lines is not in the file; a missing quote keeps the old behaviour",
2527
+ "wave": 14,
2528
+ "level": "L2",
2529
+ "status": "landed",
2530
+ "owned": [
2531
+ "src/review/fixloop.mjs",
2532
+ "src/review/lenses/recheck.md",
2533
+ "src/review/finding.schema.json",
2534
+ "src/review/validate-review.mjs",
2535
+ "skill/references/review.md",
2536
+ "CHANGELOG.md",
2537
+ "test/review/fixloop.test.mjs",
2538
+ "test/review/validate-review.test.mjs",
2539
+ "test/review/recheck-real.test.mjs"
2540
+ ],
2541
+ "depends_on": [
2542
+ "B133",
2543
+ "B135b"
2544
+ ],
2545
+ "note": "Carries the B133 changes onto main with the corrected acceptance. Fixes issue #18."
2546
+ },
2547
+ "B134": {
2548
+ "title": "Block open records the base branch HEAD; close warns when the base has commits the block lacks; block rebase accepts a closed block and keeps reviewed file blobs",
2549
+ "wave": 14,
2550
+ "level": "L2",
2551
+ "status": "landed",
2552
+ "owned": [
2553
+ "src/state/block.mjs",
2554
+ "src/cli/block.mjs",
2555
+ "skill/references/code.md",
2556
+ "CHANGELOG.md",
2557
+ "test/state/block.test.mjs",
2558
+ "test/cli/block-rebase-closed.test.mjs",
2559
+ "test/cli/block-close-base-warning.test.mjs"
2560
+ ],
2561
+ "depends_on": [
2562
+ "B135b"
2563
+ ],
2564
+ "note": "Fixes issue #21. A fix round removed a false warning when the block commits on its own base branch."
2565
+ },
2566
+ "B136": {
2567
+ "title": "gates.repeat_new_tests: repeat the block's added or changed test files N times; a failed repeat is a red flaky-test gate with signed repeat evidence",
2568
+ "wave": 14,
2569
+ "level": "L2",
2570
+ "status": "landed",
2571
+ "owned": [
2572
+ "src/cli/gates.mjs",
2573
+ "src/gates/run.mjs",
2574
+ "src/gates/expand.mjs",
2575
+ "src/config/validate.mjs",
2576
+ "schema/code-forge.schema.json",
2577
+ "src/ledger/report.mjs",
2578
+ "docs/reference/config.md",
2579
+ "skill/references/code.md",
2580
+ "CHANGELOG.md",
2581
+ "test/gates/run.test.mjs",
2582
+ "test/gates/cli.test.mjs",
2583
+ "test/gates/changed.test.mjs",
2584
+ "test/config/cli-validate.test.mjs",
2585
+ "test/ledger/report.test.mjs",
2586
+ "test/docs-config.test.mjs",
2587
+ "test/config/schema-coverage.test.mjs"
2588
+ ],
2589
+ "depends_on": [
2590
+ "B134"
2591
+ ],
2592
+ "note": "Fixes issue #20. A false critical finding (signed row callback) was cleared by making the sign-and-append call explicit."
2593
+ },
2594
+ "B137": {
2595
+ "title": "A human device check gate: acceptance clauses marked human, block human-pass with a required note and optional proof, close refuses until passed",
2596
+ "wave": 14,
2597
+ "level": "L2",
2598
+ "status": "landed",
2599
+ "owned": [
2600
+ "src/gates/acceptance.mjs",
2601
+ "src/state/block.mjs",
2602
+ "src/state/run.mjs",
2603
+ "src/cli/block.mjs",
2604
+ "src/cli/run.mjs",
2605
+ "src/cli/status.mjs",
2606
+ "src/cli/report.mjs",
2607
+ "src/ledger/report.mjs",
2608
+ "src/util/forbidden.mjs",
2609
+ "skill/references/code.md",
2610
+ "skill/SKILL.md",
2611
+ "docs/how-it-works.md",
2612
+ "CHANGELOG.md",
2613
+ "test/gates/acceptance.test.mjs",
2614
+ "test/cli/block-human-pass.test.mjs",
2615
+ "test/util/forbidden.test.mjs",
2616
+ "test/state/block.test.mjs"
2617
+ ],
2618
+ "depends_on": [
2619
+ "B136"
2620
+ ],
2621
+ "note": "Stopped after review: the acceptance saved at open said --proof was required, but issue #19 makes it optional. Its changes landed through B137b."
2622
+ },
2623
+ "B137b": {
2624
+ "title": "A human device check gate: acceptance clauses marked human, block human-pass with a required note and optional proof, close refuses until passed (corrected acceptance: proof optional)",
2625
+ "wave": 14,
2626
+ "level": "L2",
2627
+ "status": "landed",
2628
+ "owned": [
2629
+ "src/gates/acceptance.mjs",
2630
+ "src/state/block.mjs",
2631
+ "src/state/run.mjs",
2632
+ "src/cli/block.mjs",
2633
+ "src/cli/run.mjs",
2634
+ "src/cli/status.mjs",
2635
+ "src/cli/report.mjs",
2636
+ "src/ledger/report.mjs",
2637
+ "src/util/forbidden.mjs",
2638
+ "skill/references/code.md",
2639
+ "skill/SKILL.md",
2640
+ "docs/how-it-works.md",
2641
+ "CHANGELOG.md",
2642
+ "test/gates/acceptance.test.mjs",
2643
+ "test/cli/block-human-pass.test.mjs",
2644
+ "test/util/forbidden.test.mjs",
2645
+ "test/state/block.test.mjs",
2646
+ "test/engines/builders/argv-snapshots.test.mjs",
2647
+ "test/engines/builders/forbidden-rendering.test.mjs",
2648
+ "test/engines/codex-home.test.mjs"
2649
+ ],
2650
+ "depends_on": [
2651
+ "B137",
2652
+ "B136"
2653
+ ],
2654
+ "note": "Fixes issue #19. Fix round 1 appended the human-pass coder rule and updated the pinned coder-only counts. A false transcript hit (flag text inside an edit script) was accepted by the owner."
2655
+ },
2656
+ "B138": {
2657
+ "title": "One human step per block: block close --decide lists every human-clearable refusal and asks one confirm; close.require_human; autopilot close:routine scope for routine closes",
2658
+ "wave": 14,
2659
+ "level": "L2",
2660
+ "status": "landed",
2661
+ "owned": [
2662
+ "src/cli/block.mjs",
2663
+ "src/state/block.mjs",
2664
+ "src/review/gate-check.mjs",
2665
+ "src/review/accept-hit.mjs",
2666
+ "src/autopilot/scopes.mjs",
2667
+ "src/autopilot/grant.mjs",
2668
+ "src/config/validate.mjs",
2669
+ "src/state/run.mjs",
2670
+ "schema/code-forge.schema.json",
2671
+ "docs/reference/config.md",
2672
+ "skill/references/code.md",
2673
+ "skill/references/autopilot.md",
2674
+ "CHANGELOG.md",
2675
+ "test/cli/block-close-decide.test.mjs",
2676
+ "test/cli/block-close-routine.test.mjs",
2677
+ "test/autopilot/grant.test.mjs",
2678
+ "test/config/schema-coverage.test.mjs",
2679
+ "test/autopilot/delegate.test.mjs",
2680
+ "test/cli/autopilot.test.mjs"
2681
+ ],
2682
+ "depends_on": [
2683
+ "B137b"
2684
+ ],
2685
+ "note": "Issue #16 item 8 (owner F4: one confirm + grant). Fix round 1 pinned close:routine in two old scope-message tests and proved the no answer was asked."
2686
+ },
2687
+ "B139": {
2688
+ "title": "Light block kind: block open --kind light, one batched review per block (max 2), block-test-only gates, light-limits refusal at close",
2689
+ "wave": 14,
2690
+ "level": "L2",
2691
+ "status": "landed",
2692
+ "owned": [
2693
+ "src/cli/block.mjs",
2694
+ "src/state/block.mjs",
2695
+ "src/worker/engine.mjs",
2696
+ "src/worker/loop.mjs",
2697
+ "src/worker/queue.mjs",
2698
+ "src/review/engine.mjs",
2699
+ "src/review/packet.mjs",
2700
+ "src/cli/review-file.mjs",
2701
+ "src/cli/gates.mjs",
2702
+ "src/gates/run.mjs",
2703
+ "src/gates/expand.mjs",
2704
+ "src/config/validate.mjs",
2705
+ "schema/code-forge.schema.json",
2706
+ "docs/reference/config.md",
2707
+ "skill/references/code.md",
2708
+ "skill/references/review.md",
2709
+ "CHANGELOG.md",
2710
+ "test/cli/block-light.test.mjs",
2711
+ "test/worker/light-batch.test.mjs",
2712
+ "test/gates/run.test.mjs",
2713
+ "test/config/schema-coverage.test.mjs"
2714
+ ],
2715
+ "depends_on": [
2716
+ "B138"
2717
+ ],
2718
+ "note": "Issue #16 item 9 (owner F5: --kind light). Fix round 1: a cached light result was reused before the ticket hash check (critical). Fix round 2: test types."
2719
+ },
2720
+ "B107": {
2721
+ "title": "Several review workers in one run: review.workers 1..4, run start --add-worker, worker identity on signed results, pin checks per worker",
2722
+ "wave": 14,
2723
+ "level": "L2",
2724
+ "status": "landed",
2725
+ "owned": [
2726
+ "src/worker/loop.mjs",
2727
+ "src/worker/queue.mjs",
2728
+ "src/worker/engine.mjs",
2729
+ "src/cli/run.mjs",
2730
+ "src/util/forbidden.mjs",
2731
+ "src/state/block.mjs",
2732
+ "src/state/run.mjs",
2733
+ "src/config/validate.mjs",
2734
+ "schema/code-forge.schema.json",
2735
+ "docs/reference/config.md",
2736
+ "skill/references/review.md",
2737
+ "CHANGELOG.md",
2738
+ "test/worker/registry.test.mjs",
2739
+ "test/worker/multi.test.mjs",
2740
+ "test/state/block.test.mjs",
2741
+ "test/util/forbidden.test.mjs",
2742
+ "test/config/schema-coverage.test.mjs",
2743
+ "test/engines/codex-home.test.mjs",
2744
+ "test/engines/builders/forbidden-rendering.test.mjs",
2745
+ "test/engines/builders/argv-snapshots.test.mjs",
2746
+ "test/review/answers.test.mjs",
2747
+ "test/review/reopen.test.mjs",
2748
+ "test/review/route.test.mjs",
2749
+ "test/worker/deletion-review.test.mjs",
2750
+ "test/state/run.test.mjs"
2751
+ ],
2752
+ "depends_on": [
2753
+ "B139",
2754
+ "B106"
2755
+ ],
2756
+ "note": "Issue #16 item 7 (rest of Group E). Fix round 1: results without a worker field keep the old pin check (82 old tests). Fix round 2: a recycled live pid must match its own pin (critical); an added worker is stopped when its probe fails."
2338
2757
  }
2339
2758
  }
2340
2759
  }
@@ -55,6 +55,11 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
55
55
  | `levels.L3.fallback[].effort` | string | | — | |
56
56
  | `levels.coder_floor_docs` | enum: `L0`, `L1`, `L2` | | `"L1"` | |
57
57
  | `orchestrator` | enum: `L0`, `L1`, `L2`, `L3` | | — | |
58
+ | `light` | object | | — | |
59
+ | `light.max_files` | integer | | `5` | min 1; Maximum owned changed files in a light block at close. |
60
+ | `light.max_lines` | integer | | `300` | min 1; Maximum added plus removed lines in a light block at close. |
61
+ | `close` | object | | — | |
62
+ | `close.require_human` | boolean | | `false` | B138: require a terminal-confirmed human close, unless an active close:routine grant covers a routine block. Read from the run snapshot; cannot change by run reload. |
58
63
  | `system1` | object | | — | |
59
64
  | `system1.provider` | enum: `anthropic`, `openai`, `xai` | | — | |
60
65
  | `system1.model` | string | | — | |
@@ -127,6 +132,7 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
127
132
  | `review.routes[].second.fallback[].provider` | enum: `anthropic`, `openai`, `xai` | yes | — | |
128
133
  | `review.routes[].second.fallback[].model` | string | yes | — | minLength 1 |
129
134
  | `review.routes[].second.fallback[].effort` | string | | — | |
135
+ | `review.workers` | integer | | `1` | min 1; max 4; B107: Maximum live workers serving the queue. The orchestrator adds one with run start --add-worker --run <id>. |
130
136
  | `review.max_rounds_per_file` | integer | | `4` | min 2; max 6 |
131
137
  | `review.recheck_scope` | enum: `fix_hunks`, `file` | | `"fix_hunks"` | |
132
138
  | `review.late_findings` | enum: `sweep`, `block` | | `"sweep"` | |
@@ -161,6 +167,7 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
161
167
  | `gates.extra.secret_scan` | boolean | | `true` | |
162
168
  | `gates.extra.safe_edit` | boolean | | `true` | |
163
169
  | `gates.extra.invariants` | string | | — | |
170
+ | `gates.repeat_new_tests` | integer | | — | min 2; max 10; After a passing test gate with --run and --block, run its command this many additional times for only tests added or changed against the block base; absent means off. Requires a whole {test_files} argv item; otherwise prints repeat_new_tests: skipped (gates.test has no {test_files}). A failed repeat makes the gate red with reason flaky-test; output and signed gate rows carry repeats {n, files, failed}, and report shows the count. |
164
171
  | `gates.full_suite_threshold_files` | integer | | `10` | min 1; A block that owns more files than this runs the full suite for a {test_files} gate (reason threshold), not its related tests. Owned files are counted this way. A glob or a directory counts the tracked and new (not ignored) files it covers. A path not created yet counts as 1. Outside git each entry counts 1. A git failure runs the full suite. block open --tests names the test files precisely. With gates run --changed, the threshold counts changed files since the last green gates run --run --block instead. |
165
172
  | `proof` | object | | — | |
166
173
  | `proof.tiers` | object | | — | |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codedology/code-forge",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Plan/harden/code/review orchestration CLI and Agent Skill for cross-model, parallel, evidence-gated feature delivery.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,6 +41,21 @@
41
41
  }
42
42
  },
43
43
  "orchestrator": { "$ref": "#/$defs/levelName" },
44
+ "light": {
45
+ "type": "object",
46
+ "additionalProperties": false,
47
+ "properties": {
48
+ "max_files": { "type": "integer", "minimum": 1, "default": 5, "description": "Maximum owned changed files in a light block at close." },
49
+ "max_lines": { "type": "integer", "minimum": 1, "default": 300, "description": "Maximum added plus removed lines in a light block at close." }
50
+ }
51
+ },
52
+ "close": {
53
+ "type": "object",
54
+ "additionalProperties": false,
55
+ "properties": {
56
+ "require_human": { "type": "boolean", "default": false, "description": "B138: require a terminal-confirmed human close, unless an active close:routine grant covers a routine block. Read from the run snapshot; cannot change by run reload." }
57
+ }
58
+ },
44
59
  "system1": {
45
60
  "type": "object",
46
61
  "additionalProperties": false,
@@ -170,6 +185,7 @@
170
185
  }
171
186
  }
172
187
  },
188
+ "workers": { "type": "integer", "minimum": 1, "maximum": 4, "default": 1, "description": "B107: Maximum live workers serving the queue. The orchestrator adds one with run start --add-worker --run <id>." },
173
189
  "max_rounds_per_file": { "type": "integer", "minimum": 2, "maximum": 6, "default": 4 },
174
190
  "recheck_scope": { "type": "string", "enum": ["fix_hunks", "file"], "default": "fix_hunks" },
175
191
  "late_findings": { "type": "string", "enum": ["sweep", "block"], "default": "sweep" },
@@ -246,6 +262,12 @@
246
262
  "invariants": { "type": "string" }
247
263
  }
248
264
  },
265
+ "repeat_new_tests": {
266
+ "type": "integer",
267
+ "minimum": 2,
268
+ "maximum": 10,
269
+ "description": "After a passing test gate with --run and --block, run its command this many additional times for only tests added or changed against the block base; absent means off. Requires a whole {test_files} argv item; otherwise prints repeat_new_tests: skipped (gates.test has no {test_files}). A failed repeat makes the gate red with reason flaky-test; output and signed gate rows carry repeats {n, files, failed}, and report shows the count."
270
+ },
249
271
  "full_suite_threshold_files": {
250
272
  "type": "integer",
251
273
  "minimum": 1,
@@ -25,8 +25,9 @@
25
25
  * 8 review `code-forge review-file <file>` + `review-file --wait` per owned file
26
26
  * 9 proof `proof export` (lists the export-ignore paths it restored), the test gate inside the
27
27
  * export, `proof red-green` per test the acceptance names, `proof export --remove`
28
- * 10 close `code-forge block close B1` — then the cost of the completed block is printed
29
- * 11 report `code-forge report --slug <slug>`
28
+ * 10 gates `code-forge gates run --run <run> --block B1` — green before close
29
+ * 11 close `code-forge block close B1` — then the cost of the completed block is printed
30
+ * 12 report `code-forge report --slug <slug>`
30
31
  * then `code-forge run end` (always, once the run started: it stops the worker).
31
32
  *
32
33
  * Engines: `harness` is the default (R2: the no-Solo default). `subprocess` is OPT-IN: it is
@@ -60,7 +61,7 @@ const DEGRADED_DOC = path.join(PKG, 'skill', 'references', 'degraded.md');
60
61
 
61
62
  export const BLOCK = 'B1';
62
63
  export const OWNED = Object.freeze(['src/math.mjs', 'test/clamp.test.mjs']);
63
- export const STEPS = Object.freeze(['copy', 'init', 'facts', 'author', 'start', 'open', 'code', 'review', 'proof', 'close', 'report']);
64
+ export const STEPS = Object.freeze(['copy', 'init', 'facts', 'author', 'start', 'open', 'code', 'review', 'proof', 'gates', 'close', 'report']);
64
65
  const ENGINES = ['harness', 'subprocess'];
65
66
  const CODERS = ['scripted', 'harness', 'spawn'];
66
67
  const CLI_TIMEOUT_MS = 30 * 60 * 1000;
@@ -385,7 +386,12 @@ export async function main(argv, io = {}) {
385
386
  await cf(['proof', 'export', BLOCK, '--run', run, '--remove']);
386
387
  if (done('proof')) return 0;
387
388
 
388
- // 10 — the gate, then what the completed block cost
389
+ // 10 — record green gates for this run and block, after the proofs
390
+ step('gates');
391
+ say((await cf(['gates', 'run', '--run', run, '--block', BLOCK])).stdout.trimEnd());
392
+ if (done('gates')) return 0;
393
+
394
+ // 11 — the close check, then what the completed block cost
389
395
  step('close');
390
396
  say((await cf(['block', 'close', BLOCK, '--run', run])).stdout.trimEnd());
391
397
  blockOpen = false;
@@ -398,7 +404,7 @@ export async function main(argv, io = {}) {
398
404
  );
399
405
  if (done('close')) return 0;
400
406
 
401
- // 11 — the report
407
+ // 12 — the report
402
408
  step('report');
403
409
  const report = await cf(['report', '--slug', /** @type {string} */ (summary.slug)]);
404
410
  stdout.write(report.stdout);
package/skill/SKILL.md CHANGED
@@ -22,6 +22,8 @@ State lives in the plan file's header — `facts → planned → hardened → co
22
22
 
23
23
  ## §2 Roles by level (never by model name)
24
24
 
25
+ `block human-pass <id> --run <r> --note <text> [--proof <dir-or-file>]` is human-only: the owner checks the listed device checks and confirms in their own terminal, with no `--yes` and no active autopilot grant. The note is required; proof is optional, must name an existing path when given, and is recorded as `proof: null` when omitted. A successful code close with `kind: human_check` acceptance clauses leaves `awaiting_human_check`, which status and report list; it has no fresh done file until the human passes or stops it. Never run this verb for the human, and do not end the run or treat the block as ready to land while it is awaiting a check (`references/code.md` §5).
26
+
25
27
  | role | level | session | who runs it |
26
28
  |---|---|---|---|
27
29
  | facts delegate | L0 | read-only tools, empty cwd | `forge facts` |
@@ -13,6 +13,8 @@ Autopilot lets the owner leave for a set time. A delegate (a fresh L2 or L3 sess
13
13
 
14
14
  ## §2 During the window
15
15
 
16
+ The allowable scope `close:routine` means “close a routine block.” It lets plain `block close` pass `close.require_human` without a terminal when every changed file has a signed approval, a signed green gate row exists, and the block has no waiver rows, transcript hits or accepted hits. Waived or answered-only reviews do not qualify. Refusal is `close-not-routine: <reason>` (exit 1); success signs `autopilot.close {block, grant}` alongside the normal close. It never permits `block close --decide` or critical waivers.
17
+
16
18
  - **Every owner-level question goes to the delegate first**: `forge autopilot ask --run <r> --scope <scope> --question <text> --options <words> [--block <id>] [--file <path>] [--finding <id>]`. Use the fixed option words, or the action will refuse the answer: a waiver `waive,fix` · an extra round `allow,deny` · a coder level the candidate levels, e.g. `L1,L2`.
17
19
  - **Act only when it acted** (exit 0): run the action with `--decision <id>` from the answer — `forge autopilot waive|round|level … --decision <id>`. Exit 3 means the question goes to the owner: leave it open, it shows under Open questions. Exit 1 means the grant refused it: also the owner's.
18
20
  - **A paused category** (`autopilot paused: … waiting for the owner`): wait. Never raise the cap, never route around it.