forge-orkes 0.72.2 → 0.74.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.
@@ -114,5 +114,58 @@ else
114
114
  bad 'unknown flag refused loudly (exit 2)' "rc=$RC out=$OUT"
115
115
  fi
116
116
 
117
+ # --- 9-12. BARE BRANCH LOOSENING (issue #25): a worktree glob against REAL git worktrees on
118
+ # bare m-<id>-slug / m<digits>-slug branches (no forge/ prefix) — FORGE_JARVIS_REPO_ROOT
119
+ # points the git-worktree glob at a throwaway fixture repo instead of --worktree-root's
120
+ # root-scan (which bypasses branch matching entirely). ------------------------------------
121
+ GITROOT="$ROOT/git-fixture"; mkdir -p "$GITROOT/main"
122
+ (
123
+ cd "$GITROOT/main" || exit 1
124
+ git init -q .
125
+ git config user.email t@t.com; git config user.name test
126
+ mkdir -p .forge/state
127
+ printf 'id: 176\n' > .forge/state/milestone-176.yml
128
+ printf 'id: 167\n' > .forge/state/milestone-167.yml
129
+ printf 'id: R61-002\n' > .forge/state/milestone-R61-002.yml
130
+ git add .forge >/dev/null 2>&1 || : > .gitkeep
131
+ git add -A; git commit -q -m init
132
+ git worktree add -q -b m-176-marcy-mcp "$GITROOT/bare-1" >/dev/null 2>&1
133
+ git worktree add -q -b m167-close-sync "$GITROOT/bare-2" >/dev/null 2>&1
134
+ git worktree add -q -b m-R61-002-cleanup "$GITROOT/bare-3" >/dev/null 2>&1
135
+ git worktree add -q -b fix-issue-2 "$GITROOT/guard-1" >/dev/null 2>&1
136
+ ) >/dev/null 2>&1
137
+
138
+ OUT="$(FORGE_JARVIS_REPO_ROOT="$GITROOT/main" FORGE_JARVIS_FOLD="$FOLDSTUB" FORGE_JARVIS_BOARD="$BOARDSTUB" \
139
+ sh "$AWARE" --dry-run 2>&1)"
140
+
141
+ # 9. bare branch m-176-marcy-mcp discovered with milestone id m-176 (previously silently absent)
142
+ if printf '%s' "$OUT" | grep -qE 'm-176[[:space:]]+m-176-marcy-mcp'; then
143
+ ok 'bare branch m-176-marcy-mcp is discovered as milestone id m-176'
144
+ else
145
+ bad 'bare branch m-176-marcy-mcp is discovered as milestone id m-176' "$OUT"
146
+ fi
147
+
148
+ # 10. bare branch m167-close-sync (no hyphen after m) discovered with milestone id m-167
149
+ if printf '%s' "$OUT" | grep -qE 'm-167[[:space:]]+m167-close-sync'; then
150
+ ok 'bare branch m167-close-sync is discovered as milestone id m-167'
151
+ else
152
+ bad 'bare branch m167-close-sync is discovered as milestone id m-167' "$OUT"
153
+ fi
154
+
155
+ # 11. hyphenated id: m-R61-002-cleanup resolves via the longest-matching state-file prefix,
156
+ # not the naive first-hyphen-segment (which would wrongly stop at m-R61)
157
+ if printf '%s' "$OUT" | grep -qE 'm-R61-002[[:space:]]+m-R61-002-cleanup'; then
158
+ ok 'hyphenated milestone id: m-R61-002-cleanup resolves to m-R61-002 (longest state-file prefix)'
159
+ else
160
+ bad 'hyphenated milestone id: m-R61-002-cleanup resolves to m-R61-002 (longest state-file prefix)' "$OUT"
161
+ fi
162
+
163
+ # 12. GUARD: a bare-number branch (fix-issue-2, no m- token) is NEVER discovered
164
+ if ! printf '%s' "$OUT" | grep -q 'fix-issue-2'; then
165
+ ok 'guard: bare-number branch fix-issue-2 (no m- token) is not discovered'
166
+ else
167
+ bad 'guard: bare-number branch fix-issue-2 (no m- token) is not discovered' "$OUT"
168
+ fi
169
+
117
170
  printf '\nforge-jarvis-awareness.test.sh: %s passed, %s failed\n' "$PASSED" "$FAILED"
118
171
  [ "$FAILED" -eq 0 ]
@@ -403,6 +403,56 @@ if [ "$rc" = 0 ] && printf '%s' "$err24" | grep -q 'using it as-is'; then
403
403
  else
404
404
  bad "legacy materialized order" "rc=$rc err=$err24"
405
405
  fi
406
+
407
+ # --- 25-27. BARE BRANCH LOOSENING (issue #25): the branch-derived milestone-dir pick also
408
+ # matches a bare m-<id>-slug / m<digits>-slug branch (no forge/ prefix) — same match family
409
+ # as awareness/relay. A bare slug can carry several descriptive words, so the pick walks
410
+ # truncations of the last hyphen-segment until an existing milestone dir is found.
411
+
412
+ # 25. bare branch m-176-marcy-mcp (hyphenated id + 2-word slug) picks milestone-176 among
413
+ # several dirs
414
+ BSLICE="$ROOT/bare-wt"
415
+ mkdir -p "$BSLICE/.forge/phases/milestone-176/1-num" "$BSLICE/.forge/phases/milestone-5/1-decoy"
416
+ printf 'bare plan\n' > "$BSLICE/.forge/phases/milestone-176/1-num/plan-01.md"
417
+ printf 'decoy\n' > "$BSLICE/.forge/phases/milestone-5/1-decoy/plan-01.md"
418
+ mkbranch "$BSLICE" m-176-marcy-mcp
419
+ err25="$(sh "$DISPATCH" --slice "$BSLICE" --materialize-only 2>&1)"; rc=$?
420
+ if [ "$rc" = 0 ] && grep -q '^ - 1-num$' "$BSLICE/slice.yml" 2>/dev/null \
421
+ && grep -q 'bare plan' "$BSLICE/phases/1-num/plan.md" 2>/dev/null && [ ! -d "$BSLICE/phases/1-decoy" ]; then
422
+ ok "bare branch m-176-marcy-mcp: branch picks milestone-176 among several dirs (no forge/ prefix)"
423
+ else
424
+ bad "bare-branch pick (hyphenated id)" "rc=$rc err=$err25"
425
+ fi
426
+
427
+ # 26. bare branch m167-close-sync (no hyphen after m, 2-word slug) picks milestone-167
428
+ CSLICE="$ROOT/bare-wt2"
429
+ mkdir -p "$CSLICE/.forge/phases/milestone-167/1-num" "$CSLICE/.forge/phases/milestone-9/1-decoy"
430
+ printf 'bare plan\n' > "$CSLICE/.forge/phases/milestone-167/1-num/plan-01.md"
431
+ printf 'decoy\n' > "$CSLICE/.forge/phases/milestone-9/1-decoy/plan-01.md"
432
+ mkbranch "$CSLICE" m167-close-sync
433
+ err26="$(sh "$DISPATCH" --slice "$CSLICE" --materialize-only 2>&1)"; rc=$?
434
+ if [ "$rc" = 0 ] && grep -q '^ - 1-num$' "$CSLICE/slice.yml" 2>/dev/null \
435
+ && grep -q 'bare plan' "$CSLICE/phases/1-num/plan.md" 2>/dev/null && [ ! -d "$CSLICE/phases/1-decoy" ]; then
436
+ ok "bare branch m167-close-sync: branch picks milestone-167 among several dirs (m immediately followed by digits)"
437
+ else
438
+ bad "bare-branch pick (numeric, no hyphen)" "rc=$rc err=$err26"
439
+ fi
440
+
441
+ # 27. GUARD: a bare-number branch (fix-issue-2, no m- token) does NOT resolve — several
442
+ # milestone dirs with no branch-derived pick still refuses as ambiguous
443
+ NSLICE="$ROOT/guard-wt"
444
+ mkdir -p "$NSLICE/.forge/phases/milestone-1/1-a" "$NSLICE/.forge/phases/milestone-2/1-b"
445
+ printf 'a\n' > "$NSLICE/.forge/phases/milestone-1/1-a/plan-01.md"
446
+ printf 'b\n' > "$NSLICE/.forge/phases/milestone-2/1-b/plan-01.md"
447
+ mkbranch "$NSLICE" fix-issue-2
448
+ err27="$(sh "$DISPATCH" --slice "$NSLICE" --materialize-only 2>&1)"; rc=$?
449
+ if [ "$rc" != 0 ] && [ ! -f "$NSLICE/slice.yml" ] && printf '%s' "$err27" | grep -q 'REFUSED' \
450
+ && printf '%s' "$err27" | grep -q 'no forge/m-\* or bare m-<id> branch'; then
451
+ ok "guard: bare-number branch fix-issue-2 (no m- token) refuses ambiguous pick, names both accepted forms"
452
+ else
453
+ bad "guard: bare-number branch fix-issue-2" "rc=$rc err=$err27"
454
+ fi
455
+
406
456
  # --- summary -----------------------------------------------------------------
407
457
  printf '\n%s: %d passed, %d failed\n' "$(basename "$0")" "$PASSED" "$FAILED"
408
458
  [ "$FAILED" = 0 ]
@@ -130,6 +130,36 @@ case "$out" in
130
130
  *) bad "catchup summary" "no while-you-were-away line: $out" ;;
131
131
  esac
132
132
 
133
+ # --- 14-15. BARE BRANCH LOOSENING (issue #25): --list-logs glob against REAL git worktrees on
134
+ # bare m-<id>-slug branches (no forge/ prefix) — --list-logs only needs the notify-log
135
+ # PATH, no id derivation, so this pins the match extension alone (FORGE_JARVIS_REPO_ROOT
136
+ # points the glob at a throwaway fixture repo). --------------------------------------------
137
+ GITROOT="$ROOT/git-fixture"; mkdir -p "$GITROOT/main"
138
+ (
139
+ cd "$GITROOT/main" || exit 1
140
+ git init -q .
141
+ git config user.email t@t.com; git config user.name test
142
+ : > .gitkeep; git add .gitkeep; git commit -q -m init
143
+ git worktree add -q -b m-176-marcy-mcp "$GITROOT/bare-1" >/dev/null 2>&1
144
+ git worktree add -q -b fix-issue-2 "$GITROOT/guard-1" >/dev/null 2>&1
145
+ ) >/dev/null 2>&1
146
+
147
+ out="$(FORGE_JARVIS_REPO_ROOT="$GITROOT/main" sh "$RELAY" --list-logs 2>/dev/null)"
148
+
149
+ # 14. bare branch m-176-marcy-mcp emits its notify-log path (pings reach the phone)
150
+ if printf '%s' "$out" | grep -q "$GITROOT/bare-1/.forge/runner-work/notify.log"; then
151
+ ok "bare branch m-176-marcy-mcp: --list-logs emits its notify-log path"
152
+ else
153
+ bad "bare branch --list-logs path" "$out"
154
+ fi
155
+
156
+ # 15. GUARD: a bare-number branch (fix-issue-2, no m- token) emits NO log path
157
+ if ! printf '%s' "$out" | grep -q 'guard-1'; then
158
+ ok "guard: bare-number branch fix-issue-2 (no m- token) emits no log path"
159
+ else
160
+ bad "guard: bare-number branch fix-issue-2 (no m- token) emits no log path" "$out"
161
+ fi
162
+
133
163
  # --- summary -----------------------------------------------------------------
134
164
  printf '\n%s: %d passed, %d failed\n' "$(basename "$0")" "$PASSED" "$FAILED"
135
165
  [ "$FAILED" = 0 ]
@@ -154,6 +154,12 @@ models:
154
154
  # # no flag (platform default). TRUST WARNING: bypassPermissions means
155
155
  # # phone-spawned sessions act without prompts — opt in only where the
156
156
  # # phone lane carries the same trust as an attended terminal.
157
+ # dev_lane_cmd: "" # OPTIONAL. Shell command Jarvis runs (in the slice worktree) to spin up
158
+ # # the LOCAL dev server for the operator's UAT after a `done` ping — the
159
+ # # UAT-gated dispatch seam (m-48). Stack-specific: Forge owns no dev-server
160
+ # # concept, so the project supplies the "how" (e.g. its `dev:all` lane).
161
+ # # Absent → Jarvis tells the operator to start the lane manually (no failure).
162
+ # # The PR opens only AFTER the operator's explicit in-session UAT — never here.
157
163
 
158
164
  # attribution: # OPT-IN Driven-by attribution (hold-waiver patch) — default OFF.
159
165
  # driven_by: true # When true, the merge-floor check-quality lint
@@ -1,46 +1,16 @@
1
- # Forge Desire-Path Observation — APPEND-ONLY
2
- #
3
- # One observation = one new file under state/desire-paths/. NEVER edit an
4
- # existing observation in place and NEVER keep a mutable occurrence counter
5
- # that is what used to make state/index.yml conflict across worktrees.
6
- #
7
- # Filename: state/desire-paths/{YYYY-MM-DD}-{type}-{milestone}-{slug}.yml
8
- # e.g. state/desire-paths/2026-06-10-recurring_friction-m7-uncommitted-state.yml
9
- # The date+type+milestone+slug make the name unique, so concurrent agents in
10
- # different worktrees only ever ADD files — git never has to merge content.
11
- #
12
- # Occurrence counts are DERIVED: the `forge` skill globs this directory and
13
- # groups by (type + normalized note). A pattern appearing in 3+ files is a
14
- # candidate for framework evolution, surfaced at `forge` boot — the single
15
- # review owner (see ADR-012).
16
- #
17
- # SCOPE decides where a 3+ pattern's fix lands:
18
- # project = fix targets user-owned files (constitution.md, design-system.md,
19
- # context.md). Stays in-project.
20
- # framework = fix targets Forge's own skills/templates. Eligible for UPSTREAM
21
- # transport — forge review writes a portable block to
22
- # state/desire-paths/upstream/ and (when gh + forge.upstream_repo
23
- # are available) offers a GH issue against the Forge repo.
24
- # Lazy migration: a file with no `scope` is read as `project`.
1
+ # Forge Desire-Path Observation — one file per observation
2
+ # Copy to .forge/state/desire-paths/{YYYY-MM-DD}-{type}-{milestone}-{slug}.yml
3
+ # Append-only: never edit an existing observation file; recurrence is derived
4
+ # by globbing (type + normalized note), not a counter. See FORGE.md § state/desire-paths/.
25
5
 
26
- type: "" # deviation_pattern | tier_override | skipped_step |
27
- # recurring_friction | agent_struggle | user_correction
28
- scope: "" # project | framework set AT CAPTURE by the writing
29
- # skill, from the file its suggested fix targets.
30
- # Absent project (lazy migration).
31
- suggestion_target: "" # optional: the skill/file the fix would touch
32
- # (e.g. "planning/executing skills", "constitution.md")
33
- milestone: "" # e.g. "m7" (or "global" if not milestone-scoped)
34
- skill: "" # skill that observed it (executing, planning, verifying, ...)
35
- first_seen: null # ISO 8601 date this observation was recorded
36
- related_files: [] # source files involved, if any
37
- note: "" # one-line description — the grouping key for occurrence counts
38
-
39
- # Optional type-specific detail (fill what applies to `type`):
40
- detail:
41
- detected: "" # tier_override: what Forge detected
42
- overridden_to: "" # tier_override: what the user chose
43
- rule: null # deviation_pattern: 1 | 2 | 3
44
- correction: "" # user_correction: the repeated correction
45
- failure_pattern: "" # agent_struggle: how the task fails
46
- step: "" # skipped_step: the step skipped
6
+ type: "" # recurring_friction | agent_struggle | user_correction (etc. — free-form, grouped by exact string)
7
+ date: "" # ISO 8601 date the observation was made, e.g. "2026-07-23"
8
+ milestone: "" # milestone id, or a short label for non-milestone work (e.g. "quick-task (...)")
9
+ scope: project # project | framework absent project (this repo only; framework ⇒ upstream-eligible per ADR-012)
10
+ suggestion_target: "" # the file/skill this observation would change if acted on
11
+ note: >
12
+ What was observed concrete enough that a future review can judge recurrence
13
+ (same type + normalized note) without re-reading the original session.
14
+ suggestion: >
15
+ What to do about it, if a fix is proposed. Omit this key when the observation
16
+ has no concrete suggestion yet.