fv-skills-baif 2.3.5 → 2.3.6

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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.3.6] - 2026-09-29
10
+
11
+ ### Added
12
+
13
+ - `/fvs:map-code`, `/fvs:fc-plan`, and `/fvs:trust-audit` first check whether the project has a
14
+ verified probe-aeneas: its Aeneas, Charon, and Lean versions must match a tested combination and
15
+ every helper must report the tested version. On macOS arm64, FVS can install the pinned official
16
+ probe-aeneas v0.20.0 into its own versioned directory after you agree, and it runs extraction in
17
+ a sandbox with no network access and no writes outside the project's build directories, the
18
+ output, and a private temporary directory. Without a verified probe you can set it up, continue
19
+ without a graph (qualitative notes only, no counts or verdicts), or cancel. Linux support is
20
+ tracked in #77 (#69).
21
+ - Crypto and Lean specification reviews report how many grounding signature lines they charge and
22
+ the first reference that exceeds the budget. A read-only `preflight` checks a request without
23
+ contacting a reviewer (#73).
24
+ - In Codex marketplace installs, a workflow that requests an unregistered FVS specialist now warns.
25
+ It then runs a labeled generic agent, or stops before dispatch when the step depends on the
26
+ specialist's settings. The README explains how to switch to the direct Codex installation, which
27
+ registers the specialist roles (#71).
28
+
29
+ ### Fixed
30
+
31
+ - Completed Claude and Codex reviews are no longer rejected when the reviewer writes one plain
32
+ progress sentence before the required title (#72).
33
+ - Native reviewers run in their own process group with a 20-minute review deadline and a 30-second
34
+ version and authentication deadline (`FVS_REVIEW_TIMEOUT_MS`, `FVS_REVIEW_AUTH_TIMEOUT_MS`). On
35
+ timeout or interruption FVS stops the whole group, including descendants. Cleanup is tested on
36
+ macOS and Linux; Windows refuses to launch native reviewers (#75).
37
+ - When its sync metadata is missing, `/fvs:sync-aeneas-verif` points only to `/fvs:update`, which
38
+ updates the installation you already have, and no longer suggests the npm installer.
39
+
9
40
  ## [2.3.5] - 2026-09-21
10
41
 
11
42
  ### Added
package/README.md CHANGED
@@ -90,7 +90,31 @@ codex plugin add fvs@beneficial-ai-foundation
90
90
  ```
91
91
 
92
92
  Start a new session after installation. Run `/fvs:help` in Claude Code or mention `$fvs:help` in
93
- Codex. To refresh an existing install, update the catalog and then update or reinstall FVS:
93
+ Codex.
94
+
95
+ On Codex, the marketplace plugin ships the FVS agent prompts as Markdown but does not register them
96
+ as Codex agent roles. When a workflow asks for an FVS specialist that Codex has not registered, FVS
97
+ warns you. If the step does not depend on that specialist's settings, FVS runs a generic Codex agent
98
+ with the specialist's prompt and labels its output, but Codex then does not guarantee the
99
+ specialist's identity, sandbox, model, or reasoning effort. If the step does depend on them, FVS
100
+ stops before starting the agent or writing files. A role registered some other way still has its
101
+ settings checked at run time.
102
+
103
+ #### Codex specialist roles
104
+
105
+ Use one FVS installation per runtime. The npm installer installs a complete, separately managed FVS
106
+ for Codex: skills as `$fvs-<name>`, scripts, hooks, a `config.toml` block, and the `fvs-*` agent
107
+ roles. To get registered roles today, switch installations rather than adding a second copy:
108
+
109
+ ```bash
110
+ codex plugin remove fvs@beneficial-ai-foundation
111
+ npx fv-skills-baif --codex --global
112
+ ```
113
+
114
+ Adding or updating the marketplace plugin, including with `$fvs:update`, never registers roles or
115
+ runs the npm installer.
116
+
117
+ To refresh an existing install, update the catalog and then update or reinstall FVS:
94
118
 
95
119
  ```bash
96
120
  # Claude Code
package/bin/install.js CHANGED
@@ -878,13 +878,13 @@ function getCodexSkillAdapterHeader(skillName, options = {}) {
878
878
  ? `\n## D. Shared Plugin Syntax\n- This file is shared with Claude Code. On Codex, interpret \`/${pluginName}:<name>\` references as \`$${pluginName}:<name>\`.\n- Treat \`$ARGUMENTS\` in the shared body as \`{{FVS_ARGS}}\`.\n- \`\${CLAUDE_PLUGIN_ROOT}\` is the installed plugin root. If a host leaves that token unexpanded, resolve the plugin root as two directories above this SKILL.md.\n`
879
879
  : '';
880
880
  const typedDispatchQualification = pluginName
881
- ? `\nEven when \`agent_type\` is present, typed dispatch is available only if the exact requested FVS type is advertised by the tool schema or a confirmed runtime registry. Codex marketplace plugins do not register the bundled Claude agent Markdown as typed Codex agents, so otherwise use the bundled-agent workaround below.\n`
881
+ ? `\n**Requested specialist gate (at dispatch only):** When a workflow requests a named FVS specialist, check BOTH the visible \`spawn_agent\` schema and whether the exact requested \`agent_type\` is advertised there or in a confirmed runtime registry. An \`agent_type\` field alone is not evidence that this role is registered; bundled \`agents/*.md\` are instructions, not registered Codex specialists. If the exact role is registered and \`agent_type\` is available, use typed mapping below WITHOUT a missing-role warning. Otherwise, even if \`agent_type\` is present, warn the user in plain language: Requested FVS specialist <agent-name> is not registered in this Codex session; the bundled Markdown cannot supply typed identity. Do not warn merely for opening help, installing, or mentioning a skill without requesting specialist dispatch. Apply the settings gate below before considering the generic-agent workaround. Never run an installer on the user's behalf.\n`
882
882
  : '';
883
883
  const typedModelNote = pluginName
884
- ? 'The marketplace plugin does not install Codex agent TOML. Use this mapping only when the exact FVS agent type is registered independently; otherwise use the bundled-agent workaround.'
885
- : 'Installed agent TOML supplies only a fallback effort; it does not prove that the command-level stage selection was applied.';
884
+ ? 'The marketplace plugin does not install Codex agent TOML; use typed mapping only for an independently registered exact role.'
885
+ : 'Installed agent TOML pins its own effort, which overrides a per-call value; check the pinned effort against the confirmed selection.';
886
886
  const fallbackSteps = pluginName
887
- ? `1. Read \`\${CLAUDE_PLUGIN_ROOT}/agents/<agent-name>.md\` and extract its instructions. If the token is still literal, resolve the path from this SKILL.md as described above.\n2. Spawn a generic/default agent and inject those instructions as a role preamble before the task prompt.\n3. Label results clearly as \"generic-agent workaround\" so the user knows typed guarantees are not in effect.\n4. Where typed dispatch is mandatory for correctness, fail closed and report the schema limitation rather than silently degrading.`
887
+ ? `1. Read \`\${CLAUDE_PLUGIN_ROOT}/agents/<agent-name>.md\` and extract its instructions. If the token is still literal, resolve the path from this SKILL.md as described above.\n2. Only when the settings gate permits generic execution, spawn a generic/default child with those instructions as a role preamble before the task prompt. Do not pass an unregistered \`agent_type\`.\n3. Label output \"generic-agent workaround\". This is NOT equivalent to a registered specialist: the preamble does not assure typed identity, sandbox, model, or reasoning effort.\n4. If required guarantees cannot be honored, stop before dispatch or artifact writes; explain which guarantee is missing. Typed FVS roles currently require the direct Codex installation, a separate complete FVS install: point the user to "Codex specialist roles" in the FVS README and never suggest keeping both channels. Even after switching, confirm exact registration and settings in the runtime.`
888
888
  : `1. Resolve your active Codex config root (the directory containing your \`config.toml\`), then read \`agents/<agent-name>.toml\` relative to that root to extract the agent's instructions.\n2. Inject those instructions as a role-preamble into a generic \`spawn_agent(message=...)\` call.\n3. Label results clearly as \"generic-agent workaround\" so the user knows typed guarantees are not in effect.\n4. Where typed dispatch is mandatory for correctness, fail closed and report the schema limitation rather than silently degrading.`;
889
889
  return `<codex_skill_adapter>
890
890
  This block applies only when this shared skill runs in Codex. Claude Code must ignore it and use the
@@ -921,25 +921,25 @@ Execute mode fallback:
921
921
  ## C. Task() -> spawn_agent Mapping
922
922
  FVS workflows use \`Task(...)\` (Claude Code syntax). Translate to Codex collaboration tools:
923
923
 
924
- **Schema detection (required first step):** Codex exposes two \`spawn_agent\` schemas:
925
- - **agent_type-capable schema:** \`spawn_agent\` accepts \`agent_type\`, \`message\`, \`reasoning_effort\`, \`fork_context\`, etc. — typed FVS agent dispatch is available.
926
- - **Generic schema:** \`spawn_agent\` accepts only \`message\`, \`items\`, \`fork_context\` — there is **no \`agent_type\` field**. Typed FVS agent dispatch is unavailable in this session.
924
+ **Schema detection (required first step):** Inspect the visible \`spawn_agent\` schema. It may have \`agent_type\` or be generic (no \`agent_type\`); inspect \`model\` and \`reasoning_effort\` fields independently rather than assuming either exists. An available \`agent_type\` field does not establish that a particular FVS role is registered.
927
925
 
928
926
  Before spawning, inspect the \`spawn_agent\` tool's visible parameter schema to determine which form is active.${typedDispatchQualification}
929
927
 
930
- Selection-capability gate (before manifest confirmation):
931
- - Compare the requested model with the exact active/inherited Codex model. Because \`spawn_agent\` has no inline model field, any different requested model is unresolved. Rebuild the manifest around the actual active model and ask explicitly, choose a capable external runner, or fail before dispatch in noninteractive mode.
932
- - When \`reasoning_effort\` is absent from the schema, compare the requested effort with the installed/runtime default. A mismatch is unresolved and follows the same rebuild/ask-or-fail rule.
933
- - Never confirm a requested model or effort and then omit it with a warning. ${typedModelNote}
928
+ Selection-capability gate (before manifest confirmation, child dispatch, or artifact writes):
929
+ - Check required specialist identity and sandbox against the exact registered role and effective child settings. A generic role preamble cannot meet a mandatory typed identity or sandbox requirement; stop and explain the unavailable guarantee before dispatch or artifact writes.
930
+ - If \`model\` is exposed for this child, pass the requested model. Otherwise compare it with the exact active/inherited Codex model; a different or unconfirmed model is unresolved. Rebuild the manifest around confirmed settings and ask explicitly, choose a capable external runner, or fail before dispatch in noninteractive mode.
931
+ - If \`reasoning_effort\` is exposed for this child, pass the requested effort. Otherwise compare it with the confirmed effective installed/runtime default; a different or unconfirmed effort is unresolved and follows the same rebuild/ask-or-fail rule.
932
+ - Model and effort are separate values: pass an exact catalog model id and an effort that model lists. A registered role that pins \`model\` or \`reasoning_effort\` (its role description says the setting is locked, or its TOML sets it) overrides the per-call value, so the pinned value is the effective one; if it differs from the confirmed selection it is unresolved.
933
+ - Never confirm a requested specialist setting and then omit it with a warning. ${typedModelNote}
934
934
 
935
- Typed mapping (agent_type-capable schema only):
935
+ Typed mapping (only when the exact requested FVS role is registered AND agent_type is exposed):
936
936
  - \`Task(subagent_type="X", prompt="Y")\` -> \`spawn_agent(agent_type="X", message="Y")\`
937
- - \`Task(model="...")\` -> omit only after the selection-capability gate proves it equals the active/inherited model.
938
- - \`Task(reasoning_effort="...")\` -> \`spawn_agent(reasoning_effort="...")\` when that field is present. If absent, dispatch only after the gate proves the installed/runtime default equals the confirmed effort.
937
+ - \`Task(model="...")\` -> pass \`model\` if available for this child; otherwise omit only after the selection-capability gate proves it equals the active/inherited model.
938
+ - \`Task(reasoning_effort="...")\` -> pass \`reasoning_effort\` if available for this child and the role does not pin it; otherwise omit only after the gate proves the effective (pinned or default) effort equals the confirmed effort.
939
939
  - \`fork_context: false\` by default -- FVS agents load their own context via \`<files_to_read>\` blocks.
940
940
 
941
- Generic-agent workaround (schema with NO agent_type field):
942
- When only the generic schema is available, typed FVS agent dispatch (${dispatchExamples}, etc.) is NOT possible. This workaround is NOT equivalent to typed execution — FVS agents carry verification-aware prompts and sandbox settings a generic subagent lacks. Fallback:
941
+ Generic-agent workaround (missing exact registered role OR no agent_type field):
942
+ If the requested FVS type (${dispatchExamples}, etc.) is not registered, typed dispatch is NOT possible even with an \`agent_type\` field. If the field is absent, typed dispatch is also unavailable. Fallback:
943
943
  ${fallbackSteps}
944
944
 
945
945
  Parallel fan-out:
@@ -85,6 +85,20 @@ scout. Save a fresh inventory under this topic's `reviews/_grounding/` and set
85
85
  `GROUNDING_FILE` to its project-relative path. Check the plan's `## Reuse audit`;
86
86
  missing analysis belongs in reviewer findings, not a fabricated scout result.
87
87
 
88
+ Check the signature-line budget first. This is read-only: it creates no review files and
89
+ contacts no reviewer.
90
+
91
+ ```bash
92
+ node ~/.claude/scripts/fvs-codex-think.mjs review-preflight \
93
+ --topic "$ROOT" --iteration "n$N" --target "$TARGET_KIND" --grounding "$GROUNDING_FILE"
94
+ ```
95
+
96
+ It prints charged lines out of 200, with analog and `cited_apis` subtotals. Every span occurrence
97
+ is charged, including repeats; the distinct-span count is informational only. On overrun it
98
+ names the first span that crossed the limit and exits nonzero. Narrow the inventory or review
99
+ scope as `review-grounding.md` describes (never compact repeated spans) and rerun it until it
100
+ passes. Then run the review, which repeats the same check against current sources:
101
+
88
102
  ```bash
89
103
  node ~/.claude/scripts/fvs-codex-think.mjs review \
90
104
  --topic "$ROOT" --iteration "n$N" --target "$TARGET_KIND" \
@@ -8,6 +8,7 @@ allowed-tools:
8
8
  - Glob
9
9
  - Grep
10
10
  - Write
11
+ - AskUserQuestion
11
12
  - Task
12
13
  ---
13
14
 
@@ -19,7 +20,8 @@ The helper owns membership, edges, endpoint sets, statuses, and progress. The re
19
20
  executor add only complexity, risk, and recommendation prose keyed by canonical atom ID.
20
21
 
21
22
  Output: .formalising/PLAN.md with qualitative target recommendations and a pointer to CODEMAP's
22
- checked generated facts.
23
+ checked generated facts. Without a verified probe the user may continue without a graph; that
24
+ exploratory run writes only `.formalising/PLAN-exploratory.md`.
23
25
  </objective>
24
26
 
25
27
  <execution_context>
@@ -30,14 +32,82 @@ checked generated facts.
30
32
  <context>
31
33
  Target function: $ARGUMENTS (optional -- narrows the displayed functions and progress denominator)
32
34
 
33
- Require `.formalising/CODEMAP.md`. A target changes only the selected view; endpoint membership
34
- still uses the complete project graph.
35
+ Verified mode requires `.formalising/CODEMAP.md`. A target changes only the selected view;
36
+ endpoint membership still uses the complete project graph.
35
37
  </context>
36
38
 
37
39
  <process>
38
40
 
41
+ ## Step 0: Choose verified or exploratory mode
42
+
43
+ `PROJECT_ROOT` is the current directory.
44
+
45
+ This is the first operational decision. Run it before path prompts, model selection,
46
+ `.formalising/` writes, cache or build work, and any agent dispatch. The resolver is read-only:
47
+ it compares the project's generated `translation.json`, its Aeneas pin in `lake-manifest.json`
48
+ and `aeneas-config.yml`, and `lean-toolchain` with the tested tuples shipped in
49
+ `fvs-probe-inventory.mjs`, then checks the probe-aeneas executable and the preinstalled helpers
50
+ (probe-rust, probe-lean, scip, rust-analyzer). It reports `verified`, `missing`, `incompatible`,
51
+ `unknown` (missing or conflicting provenance) or `unsupported-platform`, and never installs
52
+ anything.
53
+
54
+ ```bash
55
+ # fvs:probe-mode
56
+ PROJECT_ROOT=$(cd "${PROJECT_ROOT:-$PWD}" && pwd -P) || exit 1
57
+ INVENTORY_SCRIPT=~/.claude/scripts/fvs-probe-inventory.mjs
58
+ PROBE_STATUS=$(node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format status) || exit 1
59
+ node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format text
60
+ FVS_MODE=
61
+ if [ "$PROBE_STATUS" = verified ]; then FVS_MODE=verified; fi
62
+ ```
63
+
64
+ `verified` continues without a prompt. For any other status in an interactive session, ask
65
+ (AskUserQuestion; on Codex or Pi a plain-text question, then wait) with exactly these choices
66
+ before doing anything else:
67
+
68
+ - **Set up the verified probe.** When `resolve --format json` reports `install.available`, show
69
+ `node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --manifest` (official URL,
70
+ pinned SHA-256, FVS-owned versioned destination, no PATH or shell-profile change) and ask
71
+ Install / Show manual instructions / Cancel. Install runs
72
+ `node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --consent interactive`; then
73
+ rerun this step and continue verified only if it now reports `verified`. Missing or
74
+ incompatible helpers get the printed manual steps only: FVS never installs a helper. After
75
+ showing manual steps, stop so the user can rerun.
76
+ - **Continue without graph.** Set `FVS_MODE=exploratory`.
77
+ - **Cancel.** Stop now. Nothing has been written.
78
+
79
+ A noninteractive run never prompts and never infers consent. Installing needs
80
+ `FVS_PROBE_INSTALL_POLICY=install`; continuing without a graph needs the separate opt-in
81
+ `FVS_ALLOW_EXPLORATORY=1`:
82
+
83
+ ```bash
84
+ # fvs:probe-mode-noninteractive
85
+ if [ -z "$FVS_MODE" ] && [ "${FVS_PROBE_INSTALL_POLICY:-}" = install ]; then
86
+ if node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --consent policy; then
87
+ PROBE_STATUS=$(node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format status)
88
+ if [ "$PROBE_STATUS" = verified ]; then FVS_MODE=verified; fi
89
+ fi
90
+ fi
91
+ if [ -z "$FVS_MODE" ]; then
92
+ if [ "${FVS_ALLOW_EXPLORATORY:-}" = 1 ]; then
93
+ FVS_MODE=exploratory
94
+ else
95
+ echo "FVS >> probe-aeneas is $PROBE_STATUS for this project; set FVS_ALLOW_EXPLORATORY=1 to continue without a graph" >&2
96
+ exit 1
97
+ fi
98
+ fi
99
+ ```
100
+
101
+ Exploratory mode never writes the managed CODEMAP block, canonical counts, graph, endpoint or
102
+ progress facts, or an audit verdict. Only verified mode runs the probe, and only through
103
+ `fvs-probe-inventory.mjs run`, which invokes the resolved probe-aeneas by absolute path under an
104
+ FVS-generated sandbox (no network; writes limited to the project's build directories, the
105
+ output directory and a private tmp; every tool home and bin directory denied).
106
+
39
107
  ## Step 1: Check CODEMAP
40
108
 
109
+ Verified mode only; exploratory mode does not require CODEMAP.
110
+
41
111
  ```bash
42
112
  [ -f .formalising/CODEMAP.md ] && echo "CODEMAP found" || echo "CODEMAP missing"
43
113
  ```
@@ -51,26 +121,22 @@ HALT. fc-plan refreshes an existing managed block; it does not create CODEMAP.
51
121
 
52
122
  ## Step 2: Refresh deterministic graph and progress facts
53
123
 
54
- Run a fresh probe from the current project root. Accurate public API data is optional: request it
55
- when `cargo-public-api` exists, but retry the core extract without it if that path fails.
124
+ Verified mode only. Run a fresh confined `probe-aeneas extract` for the project resolved in
125
+ Step 0. Accurate public API data is optional: request it when `cargo-public-api` exists, but retry
126
+ the core extract without it if that path fails.
56
127
 
57
128
  ```bash
58
- PROJECT_ROOT=$(pwd -P)
129
+ # Verified mode only.
59
130
  PROBE_TMP=$(mktemp -d "${TMPDIR:-/tmp}/fvs-probe-inventory.XXXXXX") || exit 1
60
131
  RAW_PROBE_JSON="$PROBE_TMP/extract.json"
61
- INVENTORY_SCRIPT=~/.claude/scripts/fvs-probe-inventory.mjs
62
132
  TARGET_ARGS=()
63
133
  PUBLIC_API_ARGS=()
64
134
  [ -n "$ARGUMENTS" ] && TARGET_ARGS=(--target "$ARGUMENTS")
65
-
66
- command -v probe-aeneas >/dev/null 2>&1 || {
67
- echo "probe-aeneas >= 0.19.0 is required. Install or upgrade it, then retry."
68
- exit 1
69
- }
135
+ PROBE_RUN=(node "$INVENTORY_SCRIPT" run --project-root "$PROJECT_ROOT" --output "$RAW_PROBE_JSON")
136
+ PROBE_FAILED='confined probe-aeneas extract failed; fix the reported error and retry.'
70
137
  if command -v cargo-public-api >/dev/null 2>&1; then
71
138
  PROBE_LOG="$PROBE_TMP/public-api.log"
72
- if probe-aeneas extract "$PROJECT_ROOT" --with-public-api \
73
- --output "$RAW_PROBE_JSON" >"$PROBE_LOG" 2>&1; then
139
+ if "${PROBE_RUN[@]}" --with-public-api >"$PROBE_LOG" 2>&1; then
74
140
  cat "$PROBE_LOG"
75
141
  if grep -Fq 'cargo-public-api found' "$PROBE_LOG"; then
76
142
  PUBLIC_API_ARGS=(--public-api-exact)
@@ -80,16 +146,10 @@ if command -v cargo-public-api >/dev/null 2>&1; then
80
146
  else
81
147
  cat "$PROBE_LOG"
82
148
  echo "Public API extraction unavailable; retrying the core inventory without it."
83
- probe-aeneas extract "$PROJECT_ROOT" --output "$RAW_PROBE_JSON" || {
84
- echo "probe-aeneas extract failed; fix the reported extraction error and retry."
85
- exit 1
86
- }
149
+ "${PROBE_RUN[@]}" || { echo "$PROBE_FAILED"; rm -rf -- "$PROBE_TMP"; exit 1; }
87
150
  fi
88
151
  else
89
- probe-aeneas extract "$PROJECT_ROOT" --output "$RAW_PROBE_JSON" || {
90
- echo "probe-aeneas extract failed; fix the reported extraction error and retry."
91
- exit 1
92
- }
152
+ "${PROBE_RUN[@]}" || { echo "$PROBE_FAILED"; rm -rf -- "$PROBE_TMP"; exit 1; }
93
153
  fi
94
154
  CANONICAL_INVENTORY=$(node "$INVENTORY_SCRIPT" "$RAW_PROBE_JSON" \
95
155
  --project-root "$PROJECT_ROOT" "${TARGET_ARGS[@]}" "${PUBLIC_API_ARGS[@]}" --format json) || {
@@ -116,6 +176,28 @@ For a target, `inScopeDependencies` contains selected dependencies and
116
176
  `outsideTargetDependencies` retains project dependencies outside the selection. This prevents a
117
177
  false entry point.
118
178
 
179
+ ## Exploratory route (continue without graph)
180
+
181
+ Exploratory mode only. Do not run the probe or touch CODEMAP's managed block. Give the agents
182
+ CODEMAP's qualitative notes (if CODEMAP exists) with the generated block removed, so stale counts
183
+ are never presented as current:
184
+
185
+ ```bash
186
+ # fvs:exploratory-codemap
187
+ CODEMAP_NOTES=
188
+ if [ -f .formalising/CODEMAP.md ]; then
189
+ CODEMAP_NOTES=$(sed '/<!-- fvs:probe-inventory:start -->/,/<!-- fvs:probe-inventory:end -->/d' .formalising/CODEMAP.md)
190
+ fi
191
+ ```
192
+
193
+ Dispatch the same agents with the same models. The researcher (`Research mode: plan
194
+ (exploratory)`) reads the target or the files the user names and returns qualitative complexity,
195
+ risk and approach notes keyed by Lean or Rust name. It states no membership, counts, edges,
196
+ endpoints, statuses, progress, readiness or order. The executor writes only
197
+ `.formalising/PLAN-exploratory.md`, headed `Exploratory plan: no verified probe graph`. This route
198
+ leaves `.formalising/CODEMAP.md` and `.formalising/PLAN.md` unchanged and reports
199
+ `FVS >> PLAN (EXPLORATORY)`.
200
+
119
201
  ## Step 3: Resolve models + effort and inline references
120
202
 
121
203
  Read the complete config and the canonical contract in `model-profiles.md`. Declare `research` for
@@ -279,7 +361,10 @@ Target selected: {function_name}
279
361
  </process>
280
362
 
281
363
  <success_criteria>
282
- - [ ] CODEMAP.md exists and its managed block is refreshed from a fresh probe extract
364
+ - [ ] The read-only resolver classifies the probe before any prompt, write, or dispatch
365
+ - [ ] Non-verified status offers setup / continue without graph / cancel; noninteractive runs need explicit opt-ins
366
+ - [ ] Exploratory runs strip CODEMAP's generated block and write only PLAN-exploratory.md
367
+ - [ ] CODEMAP.md exists and its managed block is refreshed from a fresh confined probe extract
283
368
  - [ ] Optional public API extraction falls back without blocking the core inventory
284
369
  - [ ] Target filtering retains project-wide endpoint truth and outside-target dependencies
285
370
  - [ ] Both agents receive the same canonical inventory used to refresh CODEMAP
@@ -8,6 +8,7 @@ allowed-tools:
8
8
  - Glob
9
9
  - Grep
10
10
  - Write
11
+ - AskUserQuestion
11
12
  - Task
12
13
  ---
13
14
 
@@ -18,7 +19,8 @@ Analyze an Aeneas-generated Lean project to produce `.formalising/CODEMAP.md`.
18
19
  A two-phase subagent pipeline adds qualitative annotations without changing those facts.
19
20
 
20
21
  Output: .formalising/CODEMAP.md with a generated function graph/progress block and separate
21
- complexity, risk, and recommendation notes.
22
+ complexity, risk, and recommendation notes. Without a verified probe the user may continue without
23
+ a graph; that exploratory run writes only `.formalising/CODEMAP-exploratory.md`.
22
24
  </objective>
23
25
 
24
26
  <execution_context>
@@ -38,6 +40,73 @@ This command can run anytime to refresh the codebase map.
38
40
 
39
41
  <process>
40
42
 
43
+ ## Step 0: Choose verified or exploratory mode
44
+
45
+ Set `PROJECT_ROOT` to `$ARGUMENTS` when supplied, otherwise leave it unset for the current
46
+ directory.
47
+
48
+ This is the first operational decision. Run it before path prompts, model selection,
49
+ `.formalising/` writes, cache or build work, and any agent dispatch. The resolver is read-only:
50
+ it compares the project's generated `translation.json`, its Aeneas pin in `lake-manifest.json`
51
+ and `aeneas-config.yml`, and `lean-toolchain` with the tested tuples shipped in
52
+ `fvs-probe-inventory.mjs`, then checks the probe-aeneas executable and the preinstalled helpers
53
+ (probe-rust, probe-lean, scip, rust-analyzer). It reports `verified`, `missing`, `incompatible`,
54
+ `unknown` (missing or conflicting provenance) or `unsupported-platform`, and never installs
55
+ anything.
56
+
57
+ ```bash
58
+ # fvs:probe-mode
59
+ PROJECT_ROOT=$(cd "${PROJECT_ROOT:-$PWD}" && pwd -P) || exit 1
60
+ INVENTORY_SCRIPT=~/.claude/scripts/fvs-probe-inventory.mjs
61
+ PROBE_STATUS=$(node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format status) || exit 1
62
+ node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format text
63
+ FVS_MODE=
64
+ if [ "$PROBE_STATUS" = verified ]; then FVS_MODE=verified; fi
65
+ ```
66
+
67
+ `verified` continues without a prompt. For any other status in an interactive session, ask
68
+ (AskUserQuestion; on Codex or Pi a plain-text question, then wait) with exactly these choices
69
+ before doing anything else:
70
+
71
+ - **Set up the verified probe.** When `resolve --format json` reports `install.available`, show
72
+ `node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --manifest` (official URL,
73
+ pinned SHA-256, FVS-owned versioned destination, no PATH or shell-profile change) and ask
74
+ Install / Show manual instructions / Cancel. Install runs
75
+ `node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --consent interactive`; then
76
+ rerun this step and continue verified only if it now reports `verified`. Missing or
77
+ incompatible helpers get the printed manual steps only: FVS never installs a helper. After
78
+ showing manual steps, stop so the user can rerun.
79
+ - **Continue without graph.** Set `FVS_MODE=exploratory`.
80
+ - **Cancel.** Stop now. Nothing has been written.
81
+
82
+ A noninteractive run never prompts and never infers consent. Installing needs
83
+ `FVS_PROBE_INSTALL_POLICY=install`; continuing without a graph needs the separate opt-in
84
+ `FVS_ALLOW_EXPLORATORY=1`:
85
+
86
+ ```bash
87
+ # fvs:probe-mode-noninteractive
88
+ if [ -z "$FVS_MODE" ] && [ "${FVS_PROBE_INSTALL_POLICY:-}" = install ]; then
89
+ if node "$INVENTORY_SCRIPT" install --project-root "$PROJECT_ROOT" --consent policy; then
90
+ PROBE_STATUS=$(node "$INVENTORY_SCRIPT" resolve --project-root "$PROJECT_ROOT" --format status)
91
+ if [ "$PROBE_STATUS" = verified ]; then FVS_MODE=verified; fi
92
+ fi
93
+ fi
94
+ if [ -z "$FVS_MODE" ]; then
95
+ if [ "${FVS_ALLOW_EXPLORATORY:-}" = 1 ]; then
96
+ FVS_MODE=exploratory
97
+ else
98
+ echo "FVS >> probe-aeneas is $PROBE_STATUS for this project; set FVS_ALLOW_EXPLORATORY=1 to continue without a graph" >&2
99
+ exit 1
100
+ fi
101
+ fi
102
+ ```
103
+
104
+ Exploratory mode never writes the managed CODEMAP block, canonical counts, graph, endpoint or
105
+ progress facts, or an audit verdict. Only verified mode runs the probe, and only through
106
+ `fvs-probe-inventory.mjs run`, which invokes the resolved probe-aeneas by absolute path under an
107
+ FVS-generated sandbox (no network; writes limited to the project's build directories, the
108
+ output directory and a private tmp; every tool home and bin directory denied).
109
+
41
110
  ## Step 1: Detect project
42
111
 
43
112
  Check for an Aeneas project. Look for config first, then auto-detect:
@@ -107,24 +176,20 @@ fail before dispatch with exact remediation.
107
176
 
108
177
  ## Step 4: Generate the canonical function inventory
109
178
 
110
- Resolve `$PROJECT_ROOT` to the confirmed absolute project root. Require `probe-aeneas` on PATH,
111
- create a private temporary directory, and run a fresh extract:
179
+ Verified mode only; exploratory mode skips to the exploratory route below. `$PROJECT_ROOT` is the
180
+ absolute root resolved in Step 0 (rerun Step 0 if the user pointed at a different root in Step 1).
181
+ Run a fresh confined `probe-aeneas extract` into a private temporary directory:
112
182
 
113
183
  ```bash
114
- PROJECT_ROOT=$(cd "$PROJECT_ROOT" && pwd -P)
184
+ # Verified mode only.
115
185
  PROBE_TMP=$(mktemp -d "${TMPDIR:-/tmp}/fvs-probe-inventory.XXXXXX") || exit 1
116
186
  RAW_PROBE_JSON="$PROBE_TMP/extract.json"
117
- INVENTORY_SCRIPT=~/.claude/scripts/fvs-probe-inventory.mjs
118
187
  PUBLIC_API_ARGS=()
119
-
120
- command -v probe-aeneas >/dev/null 2>&1 || {
121
- echo "probe-aeneas >= 0.19.0 is required. Install or upgrade it, then retry."
122
- exit 1
123
- }
188
+ PROBE_RUN=(node "$INVENTORY_SCRIPT" run --project-root "$PROJECT_ROOT" --output "$RAW_PROBE_JSON")
189
+ PROBE_FAILED='confined probe-aeneas extract failed; fix the reported error and retry.'
124
190
  if command -v cargo-public-api >/dev/null 2>&1; then
125
191
  PROBE_LOG="$PROBE_TMP/public-api.log"
126
- if probe-aeneas extract "$PROJECT_ROOT" --with-public-api \
127
- --output "$RAW_PROBE_JSON" >"$PROBE_LOG" 2>&1; then
192
+ if "${PROBE_RUN[@]}" --with-public-api >"$PROBE_LOG" 2>&1; then
128
193
  cat "$PROBE_LOG"
129
194
  if grep -Fq 'cargo-public-api found' "$PROBE_LOG"; then
130
195
  PUBLIC_API_ARGS=(--public-api-exact)
@@ -134,16 +199,10 @@ if command -v cargo-public-api >/dev/null 2>&1; then
134
199
  else
135
200
  cat "$PROBE_LOG"
136
201
  echo "Public API extraction unavailable; retrying the core inventory without it."
137
- probe-aeneas extract "$PROJECT_ROOT" --output "$RAW_PROBE_JSON" || {
138
- echo "probe-aeneas extract failed; fix the reported extraction error and retry."
139
- exit 1
140
- }
202
+ "${PROBE_RUN[@]}" || { echo "$PROBE_FAILED"; rm -rf -- "$PROBE_TMP"; exit 1; }
141
203
  fi
142
204
  else
143
- probe-aeneas extract "$PROJECT_ROOT" --output "$RAW_PROBE_JSON" || {
144
- echo "probe-aeneas extract failed; fix the reported extraction error and retry."
145
- exit 1
146
- }
205
+ "${PROBE_RUN[@]}" || { echo "$PROBE_FAILED"; rm -rf -- "$PROBE_TMP"; exit 1; }
147
206
  fi
148
207
  CANONICAL_INVENTORY=$(node "$INVENTORY_SCRIPT" "$RAW_PROBE_JSON" \
149
208
  --project-root "$PROJECT_ROOT" "${PUBLIC_API_ARGS[@]}" --format json) || exit 1
@@ -158,7 +217,7 @@ definition of a function in scope is exactly:
158
217
 
159
218
  `language=rust && kind=exec && is-relevant=true && untracked=false`
160
219
 
161
- If the tool is missing, old, malformed, fails, or produces an empty inventory, HALT. Never fall
220
+ If the confined run is refused, fails, or produces malformed or empty output, HALT. Never fall
162
221
  back to grep or model enumeration.
163
222
 
164
223
  The helper derives direct `dependents`, `topLevelFunctions`, `entryPointFunctions`, and both
@@ -311,8 +370,21 @@ rm -rf -- "$PROBE_TMP"
311
370
 
312
371
  If this fails, HALT: CODEMAP is not current and must not be used for planning.
313
372
 
373
+ ## Exploratory route (continue without graph)
374
+
375
+ Skip Step 4 and the post-write check. Dispatch the same two agents with the same models, but give
376
+ the researcher `Research mode: map-code (exploratory)` with the source paths and no canonical
377
+ inventory, and tell both agents that no verified function list exists: they describe files,
378
+ modules and types qualitatively, keyed by file path, and state no function count, membership,
379
+ dependency edges, endpoint sets, progress or public-API facts. The executor writes only
380
+ `.formalising/CODEMAP-exploratory.md`, headed `Exploratory map: no verified probe graph`. This
381
+ route never creates or modifies `.formalising/CODEMAP.md` or its managed block.
382
+
314
383
  ## Step 8: Display summary with FVS >> banner
315
384
 
385
+ In exploratory mode show `FVS >> MAP (EXPLORATORY)`, `Functions: not counted (no verified probe
386
+ graph)` and `Written: .formalising/CODEMAP-exploratory.md` instead of the verified summary.
387
+
316
388
  ```
317
389
  FVS >> MAP COMPLETE
318
390
 
@@ -335,6 +407,9 @@ Written: .formalising/CODEMAP.md
335
407
  </process>
336
408
 
337
409
  <success_criteria>
410
+ - [ ] The read-only resolver classifies the probe before any prompt, write, or dispatch
411
+ - [ ] Non-verified status offers setup / continue without graph / cancel; noninteractive runs need explicit opt-ins
412
+ - [ ] Verified extraction runs only through the confined `run` path, never a PATH lookup
338
413
  - [ ] Project detected via lakefile.toml + lean-toolchain (or fvs-config.json)
339
414
  - [ ] .formalising/ directory created
340
415
  - [ ] Model profile resolved from .formalising/fvs-config.json (or quality default)
@@ -69,8 +69,8 @@ SYNC_META="$HOME/.claude/fv-skills/upstream/aeneas/_sync-meta.json"
69
69
  if [ ! -s "$SYNC_META" ]; then
70
70
  echo "FVS >> AENEAS SYNC METADATA MISSING"
71
71
  echo "The installed fv-skills/upstream/aeneas/_sync-meta.json mapping is absent."
72
- echo "Run /fvs:update, or run: npx fv-skills-baif@latest"
73
- echo "Choose your current runtime in the normal installer flow; there is no separate Aeneas option."
72
+ echo "Run /fvs:update to refresh this installation."
73
+ echo "There is no separate Aeneas install option."
74
74
  exit 1
75
75
  fi
76
76
 
@@ -82,7 +82,7 @@ node -e '
82
82
  m.extraction_inputs.some(x => !x.repository || !x.upstream_path || !x.snapshot_target) ||
83
83
  !m.tactic_renames || typeof m.tactic_renames !== "object") process.exit(2);
84
84
  ' "$SYNC_META" || {
85
- echo "FVS >> Aeneas sync metadata is invalid. Run /fvs:update or npx fv-skills-baif@latest."
85
+ echo "FVS >> Aeneas sync metadata is invalid. Run /fvs:update to refresh this installation."
86
86
  exit 1
87
87
  }
88
88
  ```