nubos-pilot 1.3.3 → 1.3.5

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.
@@ -219,6 +219,10 @@ SPAWN_HEADLESS_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.hea
219
219
  SPAWN_HEADLESS_AGENTS=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.headless.agents 2>/dev/null || echo '["np-critic","np-researcher"]')
220
220
  SPAWN_HEADLESS_FALLBACK=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.headless.fallback_on_error 2>/dev/null || echo true)
221
221
  CONF_INJECT_CRITERIA=$(node .nubos-pilot/bin/np-tools.cjs config-get conformance.inject_criteria 2>/dev/null || echo true)
222
+ # Round-1 prep agents (default on; backfilled on install/update). When a toggle
223
+ # is false the matching ACTION CONTRACT (Step 2b / Step 2c) is skipped wholesale.
224
+ ARCHITECT_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get agents.architect 2>/dev/null || echo true)
225
+ TEST_WRITER_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get agents.test_writer 2>/dev/null || echo true)
222
226
  # Milestone success_criteria as the executor's acceptance target (rendered once from the INIT payload).
223
227
  # Intent-level only (ADR-0019): these describe what "done right" means, NOT how to build it.
224
228
  SUCCESS_CRITERIA_BLOCK=$(echo "$INIT" | node -e 'process.stdin.on("data",d=>{try{const c=JSON.parse(d).success_criteria||[];console.log(c.map(x=>"- "+(x.id?x.id+": ":"")+(x.text||x)).join("\n"))}catch(e){console.log("")}})')
@@ -414,6 +418,131 @@ for WAVE_INDEX in 0 1 2 ...; do
414
418
  CONSENSUS_PATTERN=""
415
419
  fi
416
420
 
421
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
422
+ # ACTION CONTRACT — Step 2b: Per-Task Architect (Round 1, config-gated)
423
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
424
+ # WHEN: $ROUND -eq 1 AND $ARCHITECT_ENABLED = true. Skip wholesale otherwise
425
+ # (agents.architect=false → no architect this run; R≥2 build-fixer rounds
426
+ # never run it).
427
+ # SKIP-GUARD: loop-post-architect-missing-spawn-audit (needs 1 architect audit).
428
+ #
429
+ # Execute EXACTLY these three groups, in order:
430
+ #
431
+ # (1) ONE Agent tool-call (real, not bash):
432
+ # Agent(subagent_type="np-task-architect", prompt=<…>)
433
+ # Prompt fields:
434
+ # <files_to_read>: task plan, slice plan, CONTEXT.md, RULES.md,
435
+ # M<NNN>-ARCHITECTURE.md (if present), .nubos-pilot/codebase/INDEX.md
436
+ # <consensus_pattern>: $CONSENSUS_PATTERN (researcher output; may be empty)
437
+ # <lang_directive>: $LANG_DIRECTIVE
438
+ # Curated skills (quality bar) — instruct the agent to Read each that
439
+ # applies from .claude/skills/<skill>/SKILL.md: np-system-design,
440
+ # np-service-boundary, np-api-design, np-composition-patterns,
441
+ # np-error-handling, np-adr (only for a costly-to-reverse choice).
442
+ # The agent is READ-ONLY: it emits its Task-Architecture spec as its FINAL
443
+ # MESSAGE (markdown per its Output Contract). Write that message verbatim
444
+ # to "$ARCH_CONSTRAINTS_PATH".
445
+ #
446
+ # (2) ONE Bash audit-stamp (same round) — architect is NOT Rule-9 audited,
447
+ # so an empty tool-use log is correct:
448
+ # node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" \
449
+ # --agent np-task-architect --tool-use-log '[]'
450
+ #
451
+ # (3) ONE Bash advance:
452
+ # node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" \
453
+ # --phase post-architect
454
+ #
455
+ # $ARCH_CONSTRAINTS is injected as <architecture_constraints> into the
456
+ # test-writer (Step 2c) AND executor (Step 3) prompts.
457
+ #
458
+ # Rationale: ADR-0023 — a per-task structural pass before tests/code so the
459
+ # test-writer and executor build against a decided shape, honouring RULES.md
460
+ # Conventions. Ephemeral ($TMPDIR, never committed) → plan-lint untouched.
461
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
462
+ ARCH_CONSTRAINTS=""
463
+ ARCH_CONSTRAINTS_PATH="${TMPDIR:-/tmp}/np-arch-${TASK_ID}.md"
464
+ if [ "$ROUND" -eq 1 ] && [ "$ARCHITECT_ENABLED" = "true" ]; then
465
+ # Off-host (ADR-0021): np-task-architect is read-only (Read/Grep/Glob), not
466
+ # Rule-9 audited, writes no files — run via spawn-offhost with default cwd
467
+ # when it routes to an openai-compat provider; its spec returns as the
468
+ # spawn's final message (content).
469
+ ARCHITECT_KIND=$(node .nubos-pilot/bin/np-tools.cjs resolve-model np-task-architect --json 2>/dev/null \
470
+ | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).kind||"native")}catch{console.log("native")}})')
471
+ if [ "$ARCHITECT_KIND" = "openai-compat" ]; then
472
+ A_PROMPT="${TMPDIR:-/tmp}/np-offhost-task-architect-${TASK_ID}.md"
473
+ # … render the files_to_read block + consensus + skills + $LANG_DIRECTIVE into "$A_PROMPT" …
474
+ A_OUT=$(node .nubos-pilot/bin/np-tools.cjs spawn-offhost \
475
+ --agent np-task-architect --task-file "$A_PROMPT" --task-id "$TASK_ID" \
476
+ --read-only --no-audit ${SLICE_CWD:+--cwd "$SLICE_CWD"})
477
+ echo "$A_OUT" | ARCH_PATH="$ARCH_CONSTRAINTS_PATH" node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{let c="";try{c=JSON.parse(s).content||""}catch{}require("fs").writeFileSync(process.env.ARCH_PATH,c)})'
478
+ else
479
+ true # → execute group (1): native Agent spawn; write its final message to "$ARCH_CONSTRAINTS_PATH".
480
+ fi
481
+ node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" --agent np-task-architect --tool-use-log '[]'
482
+ node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" --phase post-architect
483
+ [ -f "$ARCH_CONSTRAINTS_PATH" ] && ARCH_CONSTRAINTS=$(cat "$ARCH_CONSTRAINTS_PATH")
484
+ fi
485
+
486
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
487
+ # ACTION CONTRACT — Step 2c: Test-Writer / TDD (Round 1, config-gated)
488
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
489
+ # WHEN: $ROUND -eq 1 AND $TEST_WRITER_ENABLED = true. Runs AFTER the architect,
490
+ # BEFORE the executor. Skip wholesale otherwise.
491
+ # SKIP-GUARD: loop-post-test-writer-missing-spawn-audit (needs 1 test-writer audit).
492
+ #
493
+ # Execute EXACTLY these three groups, in order:
494
+ #
495
+ # (1) ONE Agent tool-call (real, not bash):
496
+ # Agent(subagent_type="np-test-writer", prompt=<…>)
497
+ # Prompt fields:
498
+ # <files_to_read>: task plan, slice plan, RULES.md, neighbouring tests
499
+ # <architecture_constraints>: $ARCH_CONSTRAINTS (the architect's required
500
+ # test surfaces; empty when the architect is disabled)
501
+ # <success_criteria>: $SUCCESS_CRITERIA_BLOCK + slice UAT path (intent-level)
502
+ # <lang_directive>: $LANG_DIRECTIVE
503
+ # Curated skill (quality bar) — instruct the agent to Read
504
+ # .claude/skills/np-test-strategy/SKILL.md and satisfy its Verification bar.
505
+ # RULES — the agent writes REAL, VALID test files for every required surface;
506
+ # it MUST NOT skip/stub/weaken assertions (Rule 10). Tests MAY be red now;
507
+ # the executor makes them green. The agent emits a JSON envelope whose
508
+ # tests_written paths you collect into $TDD_TESTS.
509
+ #
510
+ # (2) ONE Bash audit-stamp (same round) — test-writer is NOT Rule-9 audited:
511
+ # node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" \
512
+ # --agent np-test-writer --tool-use-log '[]'
513
+ #
514
+ # (3) ONE Bash advance — pass the written test paths so they are recorded in
515
+ # the checkpoint (nubosloop.tdd_tests) and commit-task folds them into the
516
+ # commit even when files_modified did not enumerate them:
517
+ # node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" \
518
+ # --phase post-test-writer --tests "$TDD_TESTS"
519
+ #
520
+ # Rationale: ADR-0023 — TDD inside the loop. The mechanical verify gate
521
+ # (Step 4) runs only AFTER the executor, so red-until-executor is expected
522
+ # and not a failure. The np-critic-tests axis (Step 5) re-audits for any
523
+ # skipped/vacuous assertions that slipped through.
524
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
525
+ TDD_TESTS=""
526
+ if [ "$ROUND" -eq 1 ] && [ "$TEST_WRITER_ENABLED" = "true" ]; then
527
+ # Off-host (ADR-0021): np-test-writer writes test files, so off-host needs
528
+ # worktree isolation exactly like the executor (model-driven Write confined
529
+ # + ff-merged back). When worktree isolation is off, it runs native.
530
+ TEST_WRITER_KIND=$(node .nubos-pilot/bin/np-tools.cjs resolve-model np-test-writer --json 2>/dev/null \
531
+ | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).kind||"native")}catch{console.log("native")}})')
532
+ if [ "$TEST_WRITER_KIND" = "openai-compat" ] && [ "$WORKTREE_ISOLATION" = "true" ] && [ -n "$SLICE_CWD" ] && [ "$SLICE_CWD" != "." ]; then
533
+ TW_PROMPT="${TMPDIR:-/tmp}/np-offhost-test-writer-${TASK_ID}.md"
534
+ # … render files_to_read + architecture_constraints + success_criteria + skill + $LANG_DIRECTIVE into "$TW_PROMPT" …
535
+ TW_OUT=$(node .nubos-pilot/bin/np-tools.cjs spawn-offhost \
536
+ --agent np-test-writer --task-file "$TW_PROMPT" --task-id "$TASK_ID" \
537
+ --cwd "$SLICE_CWD" --allow-bash --no-audit)
538
+ TDD_TESTS=$(echo "$TW_OUT" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const j=JSON.parse(JSON.parse(s).content||"{}");console.log((j.tests_written||[]).join(", "))}catch{console.log("")}})')
539
+ else
540
+ true # → execute group (1): native Agent spawn; collect tests_written from the envelope into $TDD_TESTS.
541
+ fi
542
+ node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" --agent np-test-writer --tool-use-log '[]'
543
+ node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" --phase post-test-writer --tests "$TDD_TESTS"
544
+ fi
545
+
417
546
  # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
418
547
  # ACTION CONTRACT — Step 3: Executor (R1) / Build-Fixer (R≥2)
419
548
  # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -424,6 +553,13 @@ for WAVE_INDEX in 0 1 2 ...; do
424
553
  # Prompt fields:
425
554
  # <files_to_read>: task plan, slice plan, prior slice SUMMARYs, CONTEXT.md
426
555
  # <consensus_pattern>: $CONSENSUS_PATTERN (with [VERIFIED]/[PROVISIONAL]/[CACHED])
556
+ # <architecture_constraints>: $ARCH_CONSTRAINTS — the per-task architect's
557
+ # decided structure + constraints (empty when agents.architect is off).
558
+ # The executor builds against this shape; it is intent-level, not a code spec.
559
+ # <tdd_tests>: $TDD_TESTS — test files np-test-writer wrote (R1, empty when off).
560
+ # The executor MUST make them green WITHOUT deleting, skipping, or weakening
561
+ # any assertion. They are in scope alongside files_modified (recorded in the
562
+ # checkpoint at post-test-writer) and commit-task commits them with the diff.
427
563
  # <success_criteria>: when $CONF_INJECT_CRITERIA = true, include the milestone
428
564
  # acceptance target — $SUCCESS_CRITERIA_BLOCK plus the slice UAT path
429
565
  # (.nubos-pilot/milestones/M<NNN>/slices/S<NNN>/S<NNN>-UAT.md). Frame it as
@@ -437,7 +573,8 @@ for WAVE_INDEX in 0 1 2 ...; do
437
573
  # ultra) instruct the agent to APPLY the np-executor "Climb the ladder"
438
574
  # discipline before writing (prevention-first). When $ECONOMY_MODE = off,
439
575
  # instruct it to SKIP the ladder (no economy pressure this run).
440
- # RULES — Agent MUST: edit ONLY paths in files_modified (D-04 scope guard) —
576
+ # RULES — Agent MUST: edit ONLY paths in files_modified plus the <tdd_tests>
577
+ # paths (D-04 scope guard; the TDD tests are the sole sanctioned addition) —
441
578
  # success_criteria are the acceptance target, NEVER a licence to touch other files,
442
579
  # run `node np-tools.cjs knowledge-search "<q>" --task $TASK_ID` via Bash
443
580
  # ≥1× (Rule 9 — the --task flag writes the audit evidence ledger),
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  command: np:plan-phase
3
3
  description: Plans a milestone (M<NNN>) — breaks it into slices (waves) and tasks. Spawns np-planner (opus) + np-plan-checker (opus), 2-iteration verification, then scaffolds every task file.
4
- argument-hint: <milestone-number> [--research] [--repromote]
4
+ argument-hint: <milestone-number> [--research] [--architect] [--repromote]
5
5
  ---
6
6
 
7
7
  # np:plan-phase
@@ -41,17 +41,19 @@ Output layout:
41
41
  ```bash
42
42
  PHASE=""
43
43
  RESEARCH_FLAG=0
44
+ ARCHITECT_FLAG=0
44
45
  REPROMOTE_FLAG=0
45
46
  for arg in "$@"; do
46
47
  case "$arg" in
47
48
  --research) RESEARCH_FLAG=1 ;;
49
+ --architect) ARCHITECT_FLAG=1 ;;
48
50
  --repromote) REPROMOTE_FLAG=1 ;;
49
51
  --*) echo "Unknown flag: $arg" >&2; exit 2 ;;
50
52
  *) [[ -z "$PHASE" ]] && PHASE="$arg" ;;
51
53
  esac
52
54
  done
53
55
  if [[ -z "$PHASE" ]]; then
54
- echo "Usage: /np:plan-phase <milestone-number> [--research] [--repromote]" >&2
56
+ echo "Usage: /np:plan-phase <milestone-number> [--research] [--architect] [--repromote]" >&2
55
57
  exit 2
56
58
  fi
57
59
  ```
@@ -154,6 +156,19 @@ fi
154
156
 
155
157
  **Exit code 42 contract:** orchestrator sees exit 42 → runs `/np:research-phase $PHASE` → re-enters `/np:plan-phase $PHASE` without the `--research` flag.
156
158
 
159
+ ### Gate 2b — Optional architecture pass (`--architect`)
160
+
161
+ The `--architect` flag auto-dispatches `/np:architect-phase` before planning, so a structural ADR pass (`M<NNN>-ARCHITECTURE.md`) is decided up front and the planner consumes it like an extension of CONTEXT.md. Dispatched AFTER research (the established flow is research → architect → plan): when both flags are set, the research re-entry strips `--research`, leaving `--architect` to dispatch on the next pass.
162
+
163
+ ```bash
164
+ if [[ "$ARCHITECT_FLAG" == "1" ]]; then
165
+ echo "architect-auto: dispatching /np:architect-phase $PHASE before planning" >&2
166
+ exit 43
167
+ fi
168
+ ```
169
+
170
+ **Exit code 43 contract:** orchestrator sees exit 43 → runs `/np:architect-phase $PHASE` → re-enters `/np:plan-phase $PHASE` without the `--architect` flag. The milestone `np-architect` stays intent-level (ADR-0019): its decisions inform the plan; they do not bake schema/filenames/code-style into `PLAN.md`.
171
+
157
172
  **Researcher-Schwarm semantics (ADR-0011).** The dispatched `/np:research-phase` runs in Schwarm mode by default (`swarm.research.k=3`). The cache-bypass at Pre-flight short-circuits the swarm whenever the milestone goal + requirements match a stored learning at similarity ≥ `swarm.research.threshold` and `occurrence ≥ swarm.research.minOccurrence`. The merged consensus carries a `<consensus_meta>` block (`k`, `agreement_score`, `flagged_decisions`) which `np-plan-checker` reads to weight downstream verdicts. No additional flags needed at this site — the swarm runs automatically when `--research` is set.
158
173
 
159
174
  ### Gate 3 — Milestone already planned