@jenga-ai/agent 3.4.0 → 3.5.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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated_at": "2026-09-14T18:42:41.263Z",
2
+ "generated_at": "2026-09-16T15:30:19.120Z",
3
3
  "skill_count": 41,
4
4
  "skills": [
5
5
  "brainstorm",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jenga-ai/agent",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "An agentic development workflow for Claude Code, Copilot, and Codex — with a persistent Epic/Story/Task board, an isolated git worktree per task, and a separate tester agent that runs your test suite before anything is marked done.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -104,10 +104,41 @@ run can never silently relocate directories or edit `.gitignore`.
104
104
  > `skills/distribute/CONFIG_SCHEMA.md` for the root-cause note and the tracked
105
105
  > follow-up to reintroduce it once fixed.
106
106
 
107
- Carry the chosen value into step 3. Do not apply it yourself — the script owns all
107
+ Carry the chosen value into step 4. Do not apply it yourself — the script owns all
108
108
  of the mechanical work.
109
109
 
110
- ### 3. Run the scaffold script
110
+ ### 3. Ask whether the distributed scaffold should be committed
111
+
112
+ This is a **distinct** question from step 2 — `project_files_visibility` (step 2)
113
+ covers only the `project/` working tree (the scrum board, `todo.md`, `queue/`,
114
+ `rapports/`, `logs/`). It has no effect on `.claude/`/`.agents/`, the distributed
115
+ framework scaffold (skill and agent definitions), which is a separate tree with a
116
+ separate lifecycle — it gets overwritten wholesale by every `/distribute` run or npm
117
+ upgrade, unlike `project/`. Kept as its own flag (`scaffold_visibility`) rather than
118
+ folded into `project_files_visibility`'s enum; see
119
+ `skills/distribute/CONFIG_SCHEMA.md`'s "Scaffold visibility" section for the full
120
+ rationale.
121
+
122
+ Ask the user this question, verbatim, before running any script:
123
+
124
+ Should the distributed .claude/.agents Jenga AI framework scaffold (skills, agent
125
+ definitions — implementation detail, not your own code) be committed into this
126
+ project's git history?
127
+ 1. Yes, commit it — keep it tracked and visible, exactly like today
128
+ 2. No, keep it on disk but add it to .gitignore so it's never committed
129
+ 3. Not sure — explain the trade-offs and ask me again
130
+
131
+ If the user picks option 3, explain the trade-offs and re-ask. Do not proceed until
132
+ the answer maps to one of `visible` (option 1) or `ignored` (option 2).
133
+
134
+ If the run is non-interactive (no user available to answer), use the default:
135
+ **`visible`**. It is the only choice that changes nothing on disk, so an unattended
136
+ run reproduces exactly today's behavior — the scaffold is still committed by default.
137
+
138
+ Carry the chosen value into step 4 as well. Do not apply it yourself — the script
139
+ owns all of the mechanical work.
140
+
141
+ ### 4. Run the scaffold script
111
142
 
112
143
  `init.sh` is not guaranteed to live at a single fixed path: in a project that
113
144
  installed Jenga via npm, it was mirrored to `.claude/skills/j-init/scripts/`
@@ -117,7 +148,7 @@ source checkout, where it lives at the bare `skills/j-init/scripts/` path
117
148
  instead. This step runs before `CLAUDE.md`/`AGENTS.md` exist, so it cannot
118
149
  rely on either file's routing instructions to resolve the path — it must
119
150
  locate its own script directly. Execute the init script from the project
120
- root, passing the choice from step 2:
151
+ root, passing the choices from steps 2 and 3:
121
152
 
122
153
  ```bash
123
154
  INIT_SCRIPT=""
@@ -128,11 +159,14 @@ if [[ -z "$INIT_SCRIPT" ]]; then
128
159
  echo "Error: could not locate init.sh under .claude/skills/, .agents/skills/, or skills/" >&2
129
160
  exit 1
130
161
  fi
131
- chmod +x "$INIT_SCRIPT" && "$INIT_SCRIPT" --visibility <visible|ignored>
162
+ chmod +x "$INIT_SCRIPT" && "$INIT_SCRIPT" --visibility <visible|ignored> --scaffold-visibility <visible|ignored>
132
163
  ```
133
164
 
134
165
  Omitting `--visibility` falls back to the `JENGA_PROJECT_FILES_VISIBILITY`
135
- environment variable, then to `visible`.
166
+ environment variable, then to `visible`. Omitting `--scaffold-visibility` falls
167
+ back to the `JENGA_SCAFFOLD_VISIBILITY` environment variable, then to `visible`
168
+ — the same default-preserving fallback chain, applied independently to the
169
+ distributed-scaffold question from step 3.
136
170
 
137
171
  This script handles all scaffolding in one step:
138
172
  1. Initializes the git repository
@@ -148,22 +182,27 @@ This script handles all scaffolding in one step:
148
182
  11. Creates `docs/STRATEGY.md` — a strategic brief stub intended for investors, partners, and the product team
149
183
  12. Creates `CHANGELOG.md` from the shared template — a running log of notable changes, seeded with an `[Unreleased]` section
150
184
  13. Applies the chosen visibility mode via `scripts/apply-project-visibility.sh`, which records it as `project_files_visibility` in `jenga.config.json` and performs any `.gitignore` change
151
- 14. Stages and commits all files with the message `init: scaffold project structure and workflow config`
185
+ 14. Applies the chosen scaffold visibility mode via `scripts/apply-scaffold-visibility.sh`, which records it as `scaffold_visibility` in `jenga.config.json` and, when `ignored`, adds `.claude/` and `.agents/` to `.gitignore`
186
+ 15. Stages and commits all files with the message `init: scaffold project structure and workflow config`
152
187
 
153
- The visibility mode is validated before any scaffolding happens, so an invalid
154
- value fails fast and leaves nothing behind. It is applied before the commit, so
155
- the `.gitignore` entry is captured in the initial commit.
188
+ Both visibility modes are validated before any scaffolding happens, so an invalid
189
+ value fails fast and leaves nothing behind. Both are applied before the commit, so
190
+ any resulting `.gitignore` entries are captured in the initial commit — this is what
191
+ lets `scaffold_visibility: ignored` keep `.claude/`/`.agents/` out of the commit even
192
+ though they may already exist on disk (from npm postinstall or a prior `/distribute`
193
+ run) by the time `/init` runs `git add -A`.
156
194
 
157
195
  If the script fails, check that you are in the project root and that git and `jq`
158
196
  are available.
159
197
 
160
- See `skills/distribute/CONFIG_SCHEMA.md` for the full `project_files_visibility`
161
- field reference.
198
+ See `skills/distribute/CONFIG_SCHEMA.md` for the full `project_files_visibility` and
199
+ `scaffold_visibility` field reference.
162
200
 
163
- ### 4. Prompt next step
201
+ ### 5. Prompt next step
164
202
 
165
203
  Inform the user that setup is complete, and state which visibility mode was applied
166
- and where the working files now live. Mention that `docs/STRATEGY.md` was created as
204
+ for both `project_files_visibility` and `scaffold_visibility`, and where the working
205
+ files and scaffold now live. Mention that `docs/STRATEGY.md` was created as
167
206
  a strategic brief stub for investors, partners, and the product team — they can fill
168
207
  it in now or return to it later. Suggest running `/pi-plan` to define project goals
169
208
  and epics.
@@ -11,5 +11,4 @@ Desktop.ini
11
11
  # Dependency directories
12
12
  node_modules/
13
13
  vendor/
14
- .venv/
15
- EOF
14
+ .venv/
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # apply-scaffold-visibility.sh — apply the `scaffold_visibility` mode to a project.
4
+ #
5
+ # This is a DISTINCT flag from `project_files_visibility` (see
6
+ # apply-project-visibility.sh). `project_files_visibility` covers the
7
+ # project/ working tree (scrum board, todo.md, queue/, rapports/, logs/) —
8
+ # E31_S05's own Background section scopes it to that tree only. This script
9
+ # instead covers the *distributed framework scaffold* — `.claude/` and
10
+ # `.agents/` — which is a different tree with a different lifecycle (it is
11
+ # overwritten wholesale by every `/distribute` run or npm upgrade; project/
12
+ # is not). Filed as new, adjacent scope under E31_S07 rather than folded
13
+ # silently into project_files_visibility's existing enum. See
14
+ # skills/distribute/CONFIG_SCHEMA.md's "Scaffold visibility" section for the
15
+ # full rationale.
16
+ #
17
+ # This is skills/j-init/'s own copy of skills/init/scripts/apply-scaffold-visibility.sh
18
+ # (E31_S07_T03) — skills/j-init/ is a separate, hand-maintained directory, not
19
+ # auto-synced with skills/init/ (scripts/generate-j-alias.sh explicitly excludes
20
+ # this pair), and is the copy that actually ships to public-GitHub-mirror and
21
+ # npm-package consumers. Keep this file's logic in lockstep with skills/init/'s
22
+ # copy — any behavioral change made there should be mirrored here.
23
+ #
24
+ # Usage:
25
+ # apply-scaffold-visibility.sh <mode> [project_root]
26
+ # apply-scaffold-visibility.sh --check-only <mode>
27
+ #
28
+ # Modes:
29
+ # visible Scaffold directories stay where they are. No-op on disk beyond
30
+ # the config write. This is the default — matches the behavior
31
+ # of every /init run before this flag existed.
32
+ # ignored .claude/ and .agents/ are added to the project's .gitignore —
33
+ # present on disk (whenever npm postinstall or /distribute
34
+ # places them, whether that happens before or after this runs),
35
+ # never committed. Entries are written unconditionally, the same
36
+ # way apply-project-visibility.sh gitignores project/ whether or
37
+ # not it exists yet, so a scaffold created by a later
38
+ # /distribute run is covered too, not just one already on disk.
39
+ #
40
+ # Exit codes:
41
+ # 0 Success
42
+ # 1 Bad usage or missing prerequisite
43
+ # 2 Invalid mode (outside the two-value enum)
44
+ # 3 Filesystem apply failure
45
+ # 4 jenga.config.json write failure
46
+
47
+ # Do NOT use set -e globally — each step handles its own errors.
48
+ set -uo pipefail
49
+
50
+ info() { echo "[scaffold-visibility] $*"; }
51
+ warn() { echo "[scaffold-visibility] WARNING: $*"; }
52
+ err() { echo "[scaffold-visibility] ERROR: $*" >&2; }
53
+
54
+ usage() {
55
+ echo "Usage: $(basename "$0") <visible|ignored> [project_root]" >&2
56
+ echo " $(basename "$0") --check-only <visible|ignored>" >&2
57
+ exit 1
58
+ }
59
+
60
+ # The distributed framework scaffold — mirrored copies of skills/agents for
61
+ # Claude Code and Copilot/other agents. Distinct from JENGA_WORKING_PATHS in
62
+ # apply-project-visibility.sh, which covers project/ only.
63
+ JENGA_SCAFFOLD_PATHS=(".claude" ".agents")
64
+
65
+ VALID_MODES="visible ignored"
66
+
67
+ validate_mode() {
68
+ local mode="$1"
69
+ for valid in $VALID_MODES; do
70
+ [ "$mode" = "$valid" ] && return 0
71
+ done
72
+ err "Invalid scaffold_visibility value: '${mode}'"
73
+ err "Allowed values are: ${VALID_MODES// /, }"
74
+ exit 2
75
+ }
76
+
77
+ # ---------------------------------------------------------------------------
78
+ # Argument parsing
79
+ # ---------------------------------------------------------------------------
80
+
81
+ CHECK_ONLY=0
82
+ if [ "${1:-}" = "--check-only" ]; then
83
+ CHECK_ONLY=1
84
+ shift
85
+ fi
86
+
87
+ MODE="${1:-}"
88
+ [ -n "$MODE" ] || usage
89
+
90
+ validate_mode "$MODE"
91
+
92
+ if [ "$CHECK_ONLY" -eq 1 ]; then
93
+ info "Mode '$MODE' is valid."
94
+ exit 0
95
+ fi
96
+
97
+ PROJECT_ROOT="${2:-$PWD}"
98
+ if [ ! -d "$PROJECT_ROOT" ]; then
99
+ err "Project root does not exist: $PROJECT_ROOT"
100
+ exit 1
101
+ fi
102
+ cd "$PROJECT_ROOT" || { err "Cannot enter project root: $PROJECT_ROOT"; exit 1; }
103
+
104
+ if ! command -v jq >/dev/null 2>&1; then
105
+ err "jq is required to write jenga.config.json but was not found on PATH."
106
+ exit 1
107
+ fi
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # ignored — append to .gitignore, without ever duplicating an entry
111
+ # ---------------------------------------------------------------------------
112
+
113
+ gitignore_append() {
114
+ local entry="$1"
115
+ local gitignore=".gitignore"
116
+
117
+ if [ -f "$gitignore" ] && grep -qxF -- "$entry" "$gitignore"; then
118
+ info "'$entry' already present in .gitignore — skipping."
119
+ return 0
120
+ fi
121
+
122
+ # Don't glue our entry onto a final line that lacks a newline.
123
+ if [ -s "$gitignore" ] && [ -n "$(tail -c 1 "$gitignore")" ]; then
124
+ printf '\n' >> "$gitignore"
125
+ fi
126
+
127
+ if ! printf '%s\n' "$entry" >> "$gitignore"; then
128
+ err "Failed to append '$entry' to .gitignore"
129
+ exit 3
130
+ fi
131
+ info "Added '$entry' to .gitignore"
132
+ }
133
+
134
+ # ---------------------------------------------------------------------------
135
+ # jenga.config.json — merge the field in, written atomically (temp + mv)
136
+ # ---------------------------------------------------------------------------
137
+
138
+ write_scaffold_config() {
139
+ local mode="$1"
140
+ local config="jenga.config.json"
141
+ local tmp="${config}.tmp"
142
+ local existing='{}'
143
+
144
+ # /init normally runs before any /distribute, so the file usually does not
145
+ # exist yet. Merge rather than overwrite so other fields survive.
146
+ if [ -f "$config" ]; then
147
+ if ! jq empty "$config" 2>/dev/null; then
148
+ err "$config exists but contains malformed JSON — refusing to overwrite it."
149
+ exit 4
150
+ fi
151
+ existing="$(cat "$config")"
152
+ fi
153
+
154
+ local content
155
+ content="$(jq --arg v "$mode" '.scaffold_visibility = $v' <<< "$existing")"
156
+ if [ -z "$content" ]; then
157
+ err "Failed to construct $config content."
158
+ exit 4
159
+ fi
160
+
161
+ if ! printf '%s\n' "$content" > "$tmp"; then
162
+ err "Failed to write temporary config file: $tmp"
163
+ exit 4
164
+ fi
165
+
166
+ if ! mv "$tmp" "$config"; then
167
+ err "Failed to atomically move $tmp to $config"
168
+ rm -f "$tmp"
169
+ exit 4
170
+ fi
171
+
172
+ info "Wrote scaffold_visibility = \"$mode\" to $config"
173
+ }
174
+
175
+ # ---------------------------------------------------------------------------
176
+ # Apply
177
+ # ---------------------------------------------------------------------------
178
+
179
+ case "$MODE" in
180
+ visible)
181
+ info "Mode 'visible' — scaffold directories stay in place; nothing to change on disk."
182
+ ;;
183
+ ignored)
184
+ for path in "${JENGA_SCAFFOLD_PATHS[@]}"; do
185
+ gitignore_append "${path}/"
186
+ done
187
+ ;;
188
+ esac
189
+
190
+ write_scaffold_config "$MODE"
191
+
192
+ info "Applied scaffold_visibility '$MODE' to $PROJECT_ROOT"
@@ -4,6 +4,7 @@ set -euo pipefail
4
4
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
5
  ASSETS_DIR="$SCRIPT_DIR/../assets"
6
6
  VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-project-visibility.sh"
7
+ SCAFFOLD_VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-scaffold-visibility.sh"
7
8
 
8
9
  # ─── Resolve the package root that owns templates/ and lib/ ──────────────────
9
10
  # postinstall.js mirrors only skills/ and agents/ into .claude/ and .agents/ —
@@ -22,23 +23,33 @@ else
22
23
  exit 1
23
24
  fi
24
25
 
25
- # ─── 0. Resolve project_files_visibility ─────────────────────────────────────
26
+ # ─── 0. Resolve project_files_visibility and scaffold_visibility ─────────────
26
27
  # Defaults to `visible` — the only value that touches nothing on disk — so an
27
28
  # unattended run can never silently relocate directories or edit .gitignore.
29
+ # project_files_visibility covers the project/ working tree (board, todo.md,
30
+ # queue/, rapports/, logs/). scaffold_visibility is a distinct, independent
31
+ # flag (E31_S07_T01, ported here in E31_S07_T03) covering the distributed
32
+ # .claude/.agents framework scaffold — kept separate per
33
+ # skills/distribute/CONFIG_SCHEMA.md's "Scaffold visibility" section, rather
34
+ # than folded into project_files_visibility's existing enum.
28
35
  VISIBILITY="${JENGA_PROJECT_FILES_VISIBILITY:-visible}"
36
+ SCAFFOLD_VISIBILITY="${JENGA_SCAFFOLD_VISIBILITY:-visible}"
29
37
 
30
38
  while [[ $# -gt 0 ]]; do
31
39
  case "$1" in
32
40
  --visibility) VISIBILITY="${2:-}"; shift 2 ;;
33
41
  --visibility=*) VISIBILITY="${1#*=}"; shift ;;
42
+ --scaffold-visibility) SCAFFOLD_VISIBILITY="${2:-}"; shift 2 ;;
43
+ --scaffold-visibility=*) SCAFFOLD_VISIBILITY="${1#*=}"; shift ;;
34
44
  *) echo "Unknown argument: $1" >&2
35
- echo "Usage: $(basename "$0") [--visibility <visible|ignored>]" >&2
45
+ echo "Usage: $(basename "$0") [--visibility <visible|ignored>] [--scaffold-visibility <visible|ignored>]" >&2
36
46
  exit 1 ;;
37
47
  esac
38
48
  done
39
49
 
40
50
  # Validate before scaffolding so a typo cannot leave a half-initialised project.
41
51
  bash "$VISIBILITY_SCRIPT" --check-only "$VISIBILITY"
52
+ bash "$SCAFFOLD_VISIBILITY_SCRIPT" --check-only "$SCAFFOLD_VISIBILITY"
42
53
 
43
54
  # ─── 1. Initialize git repository ────────────────────────────────────────────
44
55
  echo "→ Initializing git repository..."
@@ -101,11 +112,14 @@ cp "$ASSETS_DIR/strategy_stub_template.md" docs/STRATEGY.md
101
112
  echo "→ Creating CHANGELOG.md from template..."
102
113
  cp "$PKG_ROOT/templates/CHANGELOG_TEMPLATE.md" CHANGELOG.md
103
114
 
104
- # ─── 11. Apply project_files_visibility ──────────────────────────────────────
105
- # Runs before the commit so the .gitignore entry (ignored) is captured in the
106
- # initial commit.
115
+ # ─── 11. Apply project_files_visibility and scaffold_visibility ─────────────
116
+ # Both run before the commit so any resulting .gitignore entries (ignored)
117
+ # are captured in the initial commit rather than left for the user to notice
118
+ # after the fact.
107
119
  echo "→ Applying project files visibility ($VISIBILITY)..."
108
120
  bash "$VISIBILITY_SCRIPT" "$VISIBILITY" "$PWD"
121
+ echo "→ Applying scaffold visibility ($SCAFFOLD_VISIBILITY)..."
122
+ bash "$SCAFFOLD_VISIBILITY_SCRIPT" "$SCAFFOLD_VISIBILITY" "$PWD"
109
123
 
110
124
  # ─── 12. Generate CLAUDE.md / AGENTS.md ──────────────────────────────────────
111
125
  # Unconditional — never gated on agentTarget (E41_S04). Applies the J-
@@ -11,5 +11,4 @@ Desktop.ini
11
11
  # Dependency directories
12
12
  node_modules/
13
13
  vendor/
14
- .venv/
15
- EOF
14
+ .venv/
@@ -168,6 +168,7 @@ For genuinely undocumented code, there is often no reliable human oracle to conf
168
168
 
169
169
  - **The deterministic pipeline remains the tool of record for zero-oracle codebases.** `onboard --legacy` and `segment --mode delivery` never depend on anyone confirming intent — they ground everything in mechanical evidence (file structure, dependencies, test coverage) and say so explicitly under `Open Questions` when the evidence doesn't support a conclusion. When there is no one left who understands the code, reach for one of those, not the conversational flow.
170
170
  - **When running the conversational flow, do not manufacture confidence.** If the user's answer is uncertain, hedged, or contradicts what discovery/Investigative Mode found, write the node honestly — do not round an uncertain answer up to a confirmed one. There is no schema field yet to tag confidence (the stub schema is intentionally minimal); until one exists, say so in the node's `description` text itself (e.g. "per the user, this module retries failed charges — unconfirmed against the code, which shows only a single retry attempt") rather than silently dropping the caveat.
171
+ - **`verification_depth: strict` is this guidance's concrete implementation, not a separate idea (E40_S06_T02).** When a candidate's Familiarity Check answer is `No` (Convergence Loop Step 1), Step 4's risk-weighted gating never lets an escalating finding round up to a false confirmation by asking the user to bless it — it auto-flags the node with exactly the hedged-`description` convention this bullet describes and converges it without a prompt. This bullet states the principle; Step 4's `strict` branch is what enforces it mechanically, so the two sections should be read as one mechanism, not two independently-arrived-at claims.
171
172
  - **A confidently wrong answer is not detectable by this flow.** Corroboration against a second signal (commit history, existing docs, a second person) is the only mitigation, and it is not built here — this is the accepted residual risk, not a gap to engineer around mid-conversation.
172
173
 
173
174
  ### Directory Triage
@@ -213,10 +214,56 @@ Silence, a counter-question, or an ambiguous reply is not consent — re-ask, th
213
214
 
214
215
  Runs once per surviving candidate (a subsystem, a named flow, a directory) after Directory Triage. This is the "propose understanding, ask the user to confirm or correct" cycle at the center of the redesign — and the one the scrutiny flagged as having no termination bound and no defense against confirmation fatigue. Both gaps are closed mechanically, not by agent discipline alone:
215
216
 
216
- 1. **Dispatch Investigative Mode.** Per `agents/developer.md`'s and `agents/tester.md`'s Investigative Mode sections (E20_S08_T02), dispatch the developer to trace what the code actually does for the candidate, and the tester to trace what the test suite actually exercises and verifies for the same candidate — two distinct vantage points, not two names for the same read. Both are read-only, worktree-sandboxed, no commits, no board writes.
217
- 2. **Propose understanding.** From both traces, draft the candidate's coarse graph node(s)/edge(s) (per the stub schema) and a plain-language summary of what they represent.
218
- 3. **Risk-weighted gating — not every finding gets a prompt.** This is the fix for confirmation fatigue (solution assessment, Problem 6, Solution B — RECOMMENDED): force an explicit confirmation only for **high-uncertainty or high-impact** findings — a node whose description depends on an inference the traces don't fully support, a node with many outgoing edges (structurally central), or one the Human-Oracle-Availability Limitation above already flagged as uncertain. **Auto-accept** low-risk, high-confidence findings — the traces agree, the finding is narrow in scope, nothing about it is surprising — without a prompt, but **log every auto-accepted node** in the elicitation state's checkpoint data (see below) so the decision is auditable later, per that solution's own mitigation for "the scoring mechanism itself misjudges impact."
219
- 4. **Confirm/correct, one round per call to `elicitation-state.sh turn`.** For a node requiring confirmation, present the draft and ask the user to confirm or correct it (per the Interaction Pattern in `CLAUDE.md` — confirm / correct-with-detail / defer as "unconfirmed" / other). Each round, call:
217
+ 1. **Familiarity Check — once per candidate, before Investigative Mode dispatch.** Ask (per the Interaction Pattern in `CLAUDE.md` — numbered list, free-text last):
218
+
219
+ ```
220
+ Are you familiar with this service/segment?
221
+ 1. Yes
222
+ 2. A little
223
+ 3. No
224
+ 4. Other (describe below)
225
+ ```
226
+
227
+ Silence, a counter-question, or an ambiguous reply is not consent — re-ask, the same convention used at every other confirmation gate in this skill. Map the answer to a `verification_depth` scoped to this candidate only — `Yes` → `shallow`, `A little` → `moderate`, `No` → `strict` — and persist it immediately, keyed by this candidate's node id, via `elicitation-state.sh`'s checkpoint mechanism (see Multi-Session Persistence below for the exact call and merge semantics):
228
+
229
+ ```bash
230
+ printf '{"verification_depth": {"%s": "%s"}}' "<candidate-id>" "<shallow|moderate|strict>" \
231
+ | bash skills/j-uncharted/scripts/elicitation-state.sh checkpoint --id <elicitation-id> --json -
232
+ ```
233
+
234
+ **Check before asking.** A candidate whose `verification_depth` is already present in the state file's `checkpoint.verification_depth` (per Multi-Session Persistence below) has already answered this — do not re-ask it, on a fresh session or otherwise.
235
+
236
+ This question operationalizes the Human-Oracle-Availability Limitation above — it is the mechanism for finding out, per candidate, how much weight the user's own confirmations should carry, rather than assuming a uniform level of trust for every candidate in one run. **`verification_depth` is read back and consumed by Step 4's risk-weighted gating below (`E40_S06_T02`)**, which branches its auto-accept/confirm/auto-flag behavior per depth. The fixed internal/external question template used whenever shallow/moderate gating does decide to prompt (Step 5) is `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (`E40_S06_T03`) — this step's job remains asking the question and making the answer durable for those steps to read.
237
+ 2. **Dispatch Investigative Mode.** Per `agents/developer.md`'s and `agents/tester.md`'s Investigative Mode sections (E20_S08_T02), dispatch the developer to trace what the code actually does for the candidate, and the tester to trace what the test suite actually exercises and verifies for the same candidate — two distinct vantage points, not two names for the same read. Both are read-only, worktree-sandboxed, no commits, no board writes.
238
+ 3. **Propose understanding.** From both traces, draft the candidate's coarse graph node(s)/edge(s) (per the stub schema) and a plain-language summary of what they represent.
239
+ 4. **Risk-weighted gating — not every finding gets a prompt, and `verification_depth` (Step 1) decides how gating itself behaves, not just what counts as risky.** This is the fix for confirmation fatigue (solution assessment, Problem 6, Solution B — RECOMMENDED). The baseline escalation criteria — the three triggers that force an explicit confirmation — are unchanged from before `E40_S06`:
240
+
241
+ - **T1 — inference-dependent:** the node's description depends on an inference the traces don't fully support.
242
+ - **T2 — structurally central:** the node has many outgoing edges.
243
+ - **T3 — already-flagged uncertain:** the Human-Oracle-Availability Limitation above already flagged this finding as uncertain.
244
+
245
+ A finding tripping none of T1-T3 is **low-risk** and auto-accepts regardless of depth. A finding tripping any of T1-T3 is **escalating**, and what happens to it now branches on the current candidate's `verification_depth` (read from `checkpoint.verification_depth.<candidate-id>`, per Step 1):
246
+
247
+ - **`moderate` (the default, unchanged calibration)** — exactly today's behavior: every escalating finding (any of T1-T3) forces a confirm prompt (Step 5); every low-risk finding auto-accepts without a prompt. **Log every auto-accepted node** in the elicitation state's checkpoint data (see Multi-Session Persistence below) so the decision is auditable later, per that solution's own mitigation for "the scoring mechanism itself misjudges impact."
248
+ - **`shallow` (widened auto-accept)** — the concrete widening rule: **drop T2 (structurally central) as an escalation trigger.** A finding tripping T2 alone — structurally central, but not inference-dependent and not already flagged uncertain — is reclassified low-risk and auto-accepted (still logged, same as above) instead of escalating. T1 and T3 still force a confirm prompt exactly as under `moderate`; only the T2-alone case widens. This is the literal reading of "findings that would sit just below today's high-impact bar" from the task's own framing — a purely structural signal with no corroborating uncertainty is no longer, by itself, enough to interrupt the user.
249
+ - **`strict` (no confirm prompt for escalating findings, ever)** — a finding tripping any of T1-T3 is **never presented to the user**. Instead:
250
+ 1. Write the node directly with a hedged, low-confidence `description`, reusing the exact hedging convention the Human-Oracle-Availability Limitation section already specifies (e.g. "unconfirmed — traces did not fully corroborate this," adapted to name the specific gap).
251
+ 2. Call `elicitation-state.sh converge` directly — **do not call `elicitation-state.sh turn` for this node.** No confirmation round is spent; the node goes straight from "proposed" to "converged," never "pending":
252
+
253
+ ```bash
254
+ bash skills/j-uncharted/scripts/elicitation-state.sh converge --id <elicitation-id> --node <node-id> --note "auto-flagged under strict depth: <one-line reason, e.g. 'structurally central, traces disagree on scope'>"
255
+ ```
256
+ 3. **Log the auto-flag** in the elicitation state's checkpoint data, the same way `moderate`/`shallow` auto-accepts are logged — this is an automatic decision, not a silent one, and stays auditable exactly like every other gating outcome.
257
+
258
+ Low-risk findings under `strict` are unaffected — they auto-accept exactly as under `moderate`/`shallow`. `strict` only changes what happens to the escalating case.
259
+
260
+ The fixed internal/external question template used whenever `shallow`/`moderate` gating does decide to prompt is `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (Step 5, `E40_S06_T03`) — dormant under `strict`, since no prompt ever fires there.
261
+ 5. **Confirm/correct, one round per call to `elicitation-state.sh turn`.** Never reached for a `strict`-depth candidate's escalating findings — those converge directly per Step 4 above. For a node requiring confirmation under `shallow`/`moderate`, do **not** present the draft with a fully open-ended "propose understanding, ask to confirm or correct" prompt. Instead use the fixed question set in `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (`E40_S06_T03`), selecting the variant by node kind:
262
+
263
+ - **Internal variant** — the node represents the candidate/service itself (the thing this investigation is about).
264
+ - **External variant** — the node represents a dependency or consumer the traces surfaced outside the candidate (something it calls, or something that calls it).
265
+
266
+ Present the drafted node/edge summary from Step 3 first, then ask the selected variant's fixed questions, then offer the same confirm / correct-with-detail / defer-as-unconfirmed / other choice as before (per the Interaction Pattern in `CLAUDE.md`) — the template file spells out both the questions and this response block verbatim, so read it rather than reconstructing either from memory. Each round, call:
220
267
 
221
268
  ```bash
222
269
  bash skills/j-uncharted/scripts/elicitation-state.sh turn --id <elicitation-id> --node <node-id>
@@ -233,7 +280,7 @@ Runs once per surviving candidate (a subsystem, a named flow, a directory) after
233
280
  ```
234
281
 
235
282
  Option 3 is the only way past the cap, and it is a per-node, explicit, one-time override — it does not raise the cap for the rest of the run.
236
- 5. **On convergence** (confirmed, corrected-and-accepted, or resolved via the cap choice above), call:
283
+ 6. **On convergence** (confirmed, corrected-and-accepted, or resolved via the cap choice above), call:
237
284
 
238
285
  ```bash
239
286
  bash skills/j-uncharted/scripts/elicitation-state.sh converge --id <elicitation-id> --node <node-id> --note "<one-line summary of what was confirmed>"
@@ -252,9 +299,9 @@ A whole-codebase `onboard` conversation, or an investigation of a large director
252
299
  ```
253
300
 
254
301
  Idempotent — safe to call again on a resumed `<elicitation-id>` without resetting progress. Choose `<elicitation-id>` so it is stable and re-derivable across sessions (e.g. `onboard-<root-slug>-<date>`, or `segment-investigate-<target-slug>`), since a resuming session must be able to reconstruct it to call `init` again.
255
- - **`checkpoint` after every converged node and after the Directory Triage confirmation gate** — never only at the end. This is what makes a mid-run pause lossless: `checkpoint --id <id> --json <file>` merges arbitrary progress data (triage results, draft nodes not yet converged, anything else worth surviving a pause) into the state file.
302
+ - **`checkpoint` after every converged node, after the Directory Triage confirmation gate, and after every Familiarity Check answer** — never only at the end. This is what makes a mid-run pause lossless: `checkpoint --id <id> --json <file>` merges arbitrary progress data (triage results, draft nodes not yet converged, per-candidate `verification_depth`, anything else worth surviving a pause) into the state file. `verification_depth` is stored as one object keyed by candidate id — `checkpoint.verification_depth.<candidate-id>` — and, per the script's own merge semantics (see its header), checking one candidate in never clobbers another candidate already recorded there.
256
303
  - **`pause` when a session must end before the elicitation has converged.** Immediately after calling `elicitation-state.sh pause --id <elicitation-id>`, write the scrum-master's own `SessionEnd` handoff (per `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)`'s `handoffs/` convention) with `status: "elicitation_paused"` and both `elicitation_id` and `state_file` set — `hooks/on_session_end.sh` routes that into an `elicitation_resume` trigger on `scrum_triggers.jsonl`, which the next scrum-master session's Drain Scrum Triggers Queue procedure picks up (`agents/scrum-master.md`).
257
- - **On resume**, read `state_file` directly — every converged node, every flagged node, and the checkpoint data (including the confirmed directory-triage lists) are already there. Do not re-run Directory Triage or re-ask about an already-converged node; resume the Convergence Loop only for nodes still `pending` or explicitly deferred.
304
+ - **On resume**, read `state_file` directly — every converged node, every flagged node, and the checkpoint data (including the confirmed directory-triage lists and any per-candidate `verification_depth` already recorded) are already there. Do not re-run Directory Triage, re-ask the Familiarity Check for a candidate already present under `checkpoint.verification_depth`, or re-ask about an already-converged node; resume the Convergence Loop only for nodes still `pending` or explicitly deferred, and only ask the Familiarity Check for a candidate that has neither.
258
305
  - **`complete` when every candidate has converged, been deferred, or been explicitly accepted past the cap.** The state file is left on disk afterward as an audit trail — nothing currently prunes a completed elicitation's state file.
259
306
 
260
307
  ---
@@ -0,0 +1,69 @@
1
+ <!--
2
+ NODE QUESTION TEMPLATE — /uncharted Convergence Loop.
3
+
4
+ Added by E40_S06_T03. Consumed by the Convergence Loop's Step 5
5
+ ("Confirm/correct", skills/j-uncharted/SKILL.md) whenever risk-weighted
6
+ gating (Step 4) decides a finding needs a confirm prompt under
7
+ `verification_depth: shallow` or `moderate`. Never reached under `strict`
8
+ — Step 4's strict branch converges the node directly, without ever
9
+ reaching Step 5, so this template is simply not invoked in that case.
10
+
11
+ Two fixed variants, selected by node kind:
12
+
13
+ INTERNAL — the node represents the candidate/service itself (the thing
14
+ `/uncharted` is investigating).
15
+ EXTERNAL — the node represents something outside the candidate that the
16
+ traces surfaced: a dependency it calls, or a consumer that calls it.
17
+
18
+ This replaces a fully open-ended "propose understanding, ask the user to
19
+ confirm or correct it" prompt for any node that fits one of these two
20
+ kinds — which, per the Convergence Loop, is every node this flow drafts.
21
+ Wording is fixed and matches the brainstorm's agreed phrasing verbatim
22
+ (project/documentation/examples/uncharted-conversational-elicitation-procedure.md);
23
+ do not paraphrase it when presenting the prompt.
24
+
25
+ Usage: present the drafted node/edge summary first (per Step 3's draft),
26
+ then ask the questions below for the selected variant, then offer the
27
+ same confirm / correct-with-detail / defer-as-unconfirmed / other choice
28
+ Step 5 already documents. This file supplies the fixed *questions*; the
29
+ response mechanics (turn cap, converge call) are unchanged and live in
30
+ SKILL.md, not here.
31
+ -->
32
+
33
+ # Node Question Template
34
+
35
+ ## Internal Node
36
+
37
+ Use when the node represents the candidate/service itself — the thing this investigation is about,
38
+ not something external to it.
39
+
40
+ 1. What is this?
41
+ 2. What does it do?
42
+ 3. Who consumes it?
43
+ 4. Other (describe below)
44
+
45
+ ## External Node
46
+
47
+ Use when the node represents a dependency or consumer the traces surfaced outside the candidate —
48
+ something the service calls, or something that calls the service.
49
+
50
+ 1. What is this?
51
+ 2. What does it do?
52
+ 3. Is the service producing to it, or consuming from it?
53
+ 4. Who is the producer, and who is the consumer?
54
+ 5. Other (describe below)
55
+
56
+ ---
57
+
58
+ After the selected question set, present the standard confirm/correct choice (per the Interaction
59
+ Pattern in `CLAUDE.md` and Convergence Loop Step 5):
60
+
61
+ ```
62
+ 1. Confirm the draft as accurate
63
+ 2. Correct it — describe what's wrong
64
+ 3. Defer — mark this node "unconfirmed" for now
65
+ 4. Other (describe below)
66
+ ```
67
+
68
+ Silence, a counter-question, or an ambiguous reply is not consent — re-ask, the same convention used
69
+ at every other confirmation gate in this skill.
@@ -53,7 +53,23 @@
53
53
  # "nodes": {
54
54
  # "<node-id>": { "turns": <int>, "status": "pending"|"converged"|"flagged", "note": "<text>" }
55
55
  # },
56
- # "checkpoint": { ...arbitrary, agent-defined fields, e.g. directory-triage results... }
56
+ # "checkpoint": {
57
+ # ...arbitrary, agent-defined fields, e.g. directory-triage results...
58
+ # "verification_depth": {
59
+ # // Recognized field (E40_S06_T01). Per-candidate Familiarity Check
60
+ # // answer from skills/j-uncharted/SKILL.md's Convergence Loop Step 1,
61
+ # // keyed by candidate/node id so a resumed elicitation can tell which
62
+ # // candidates already answered. Values are "shallow" | "moderate" |
63
+ # // "strict". Written and read by the agent driving /uncharted, same
64
+ # // as every other checkpoint field — this script assigns it no
65
+ # // special handling beyond the dict-merge behavior documented under
66
+ # // `checkpoint` below (which exists so that checking in one
67
+ # // candidate's depth never clobbers another's already recorded
68
+ # // here). Consumed by E40_S06_T02's risk-weighted gating; unread by
69
+ # // anything in this script or E40_S06_T01's own scope.
70
+ # "<candidate-id>": "shallow" | "moderate" | "strict"
71
+ # }
72
+ # }
57
73
  # }
58
74
  #
59
75
  # ---------------------------------------------------------------------------
@@ -79,11 +95,22 @@
79
95
  # the node's note (e.g. a one-line summary of what was confirmed).
80
96
  #
81
97
  # checkpoint --id ID --json FILE
82
- # Shallow-merge the JSON object in FILE (or stdin when FILE is "-")
83
- # into the state's top-level "checkpoint" field. New keys are added;
84
- # existing keys are overwritten by the new value. This is the generic
85
- # "save progress" primitive — directory-triage results, draft node
86
- # content, anything else the flow wants durable before it might pause.
98
+ # Merge the JSON object in FILE (or stdin when FILE is "-") into the
99
+ # state's top-level "checkpoint" field. New keys are added; existing
100
+ # keys are overwritten by the new value — EXCEPT when both the existing
101
+ # value and the new value for a given key are themselves JSON objects,
102
+ # in which case they are merged one level deep instead of one replacing
103
+ # the other (existing sub-keys are kept, new sub-keys are added,
104
+ # conflicting sub-keys take the new value). This one-level dict merge
105
+ # is what lets a map-shaped field addressed by its own sub-keys — e.g.
106
+ # "verification_depth", keyed per candidate id (E40_S06_T01) — accumulate
107
+ # entries across separate checkpoint calls instead of each call
108
+ # clobbering every entry a previous call wrote. Plain (non-dict)
109
+ # values — strings, numbers, lists, directory-triage's own arrays —
110
+ # still simply overwrite, exactly as before this addition. This is the
111
+ # generic "save progress" primitive — directory-triage results, draft
112
+ # node content, anything else the flow wants durable before it might
113
+ # pause.
87
114
  #
88
115
  # pause --id ID
89
116
  # Set status "paused" and update "updated_at". The caller (the agent
@@ -422,7 +449,18 @@ elif subcommand == "checkpoint":
422
449
  state = load()
423
450
  payload = json.loads(checkpoint_json)
424
451
  cp = state.setdefault("checkpoint", {})
425
- cp.update(payload)
452
+ # One-level-deep merge when both sides are dicts (E40_S06_T01) — lets a
453
+ # map-shaped field keyed by its own sub-keys (e.g. verification_depth,
454
+ # keyed per candidate id) accumulate entries across separate checkpoint
455
+ # calls instead of each call replacing the whole field. Anything else
456
+ # (strings, numbers, lists, or a dict landing on a non-dict/absent key)
457
+ # keeps the prior plain overwrite behavior.
458
+ for key, value in payload.items():
459
+ existing = cp.get(key)
460
+ if isinstance(existing, dict) and isinstance(value, dict):
461
+ existing.update(value)
462
+ else:
463
+ cp[key] = value
426
464
  state["updated_at"] = now
427
465
  atomic_write(state)
428
466
  result = {"checkpoint_keys": list(payload.keys())}
@@ -461,18 +461,30 @@ if [ -n "${JENGA_PLAYBOOKS_TEST_ROOT:-}" ]; then
461
461
  # E53_S05_T01 to also cover playbook-config.json resolution). Never set in a real invocation.
462
462
  PKG_ROOT="$JENGA_PLAYBOOKS_TEST_ROOT"
463
463
  PROJECT_DIR="$JENGA_PLAYBOOKS_TEST_ROOT"
464
- # Resolve the jenga-agent PACKAGE root (where the canonical skills/ tree actually lives) — same
465
- # monorepo-checkout vs. installed-npm-package detection used by
466
- # skills/jenga/scripts/load-nl-catalog.sh's PKG_ROOT resolution and skills/init/scripts/init.sh.
467
- elif [ -d "$SCRIPT_DIR/../../../templates" ]; then
468
- PKG_ROOT="$SCRIPT_DIR/../../.."
469
- PROJECT_DIR="${JENGA_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)}}"
470
- elif [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ -d "${CLAUDE_PROJECT_DIR}/node_modules/@jenga-ai/agent/templates" ]; then
471
- PKG_ROOT="${CLAUDE_PROJECT_DIR}/node_modules/@jenga-ai/agent"
472
- PROJECT_DIR="${JENGA_PROJECT_DIR:-$CLAUDE_PROJECT_DIR}"
473
464
  else
474
- echo "Error: could not locate the jenga-agent package root (templates/ not found via monorepo checkout or node_modules/@jenga-ai/agent)." >&2
475
- exit 2
465
+ # Resolve JENGA_PROJECT_DIR the same way every other script in skills/jenga/scripts/ does.
466
+ if [ -f "$SCRIPT_DIR/../../../lib/resolve-project-dir.sh" ]; then
467
+ # shellcheck source=/dev/null
468
+ source "$SCRIPT_DIR/../../../lib/resolve-project-dir.sh"
469
+ elif [ -n "${CLAUDE_PROJECT_DIR:-}" ]; then
470
+ JENGA_PROJECT_DIR="$CLAUDE_PROJECT_DIR"
471
+ else
472
+ JENGA_PROJECT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)"
473
+ fi
474
+
475
+ # Resolve the jenga-agent PACKAGE root (where the canonical skills/ tree actually lives) — same
476
+ # monorepo-checkout vs. installed-npm-package detection used by
477
+ # skills/jenga/scripts/load-nl-catalog.sh's PKG_ROOT resolution and skills/init/scripts/init.sh.
478
+ if [ -d "$SCRIPT_DIR/../../../templates" ]; then
479
+ PKG_ROOT="$SCRIPT_DIR/../../.."
480
+ PROJECT_DIR="$JENGA_PROJECT_DIR"
481
+ elif [ -d "$JENGA_PROJECT_DIR/node_modules/@jenga-ai/agent/templates" ]; then
482
+ PKG_ROOT="$JENGA_PROJECT_DIR/node_modules/@jenga-ai/agent"
483
+ PROJECT_DIR="$JENGA_PROJECT_DIR"
484
+ else
485
+ echo "Error: could not locate the jenga-agent package root (templates/ not found via monorepo checkout or node_modules/@jenga-ai/agent)." >&2
486
+ exit 2
487
+ fi
476
488
  fi
477
489
 
478
490
  PLAYBOOKS_DIR="$PKG_ROOT/skills/jenga/playbooks"