@lamentis/naome 1.3.6 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +9 -3
  3. package/crates/naome-cli/Cargo.toml +1 -1
  4. package/crates/naome-core/Cargo.toml +1 -1
  5. package/crates/naome-core/src/context/select.rs +58 -4
  6. package/crates/naome-core/src/git.rs +1 -26
  7. package/crates/naome-core/src/information_architecture.rs +15 -26
  8. package/crates/naome-core/src/install_plan.rs +2 -0
  9. package/crates/naome-core/src/intent/classifier.rs +56 -81
  10. package/crates/naome-core/src/intent/envelope.rs +173 -19
  11. package/crates/naome-core/src/intent/legacy_response.rs +2 -0
  12. package/crates/naome-core/src/intent/model.rs +6 -0
  13. package/crates/naome-core/src/intent/resolver.rs +25 -0
  14. package/crates/naome-core/src/intent/risk.rs +11 -1
  15. package/crates/naome-core/src/intent.rs +1 -1
  16. package/crates/naome-core/src/lib.rs +1 -0
  17. package/crates/naome-core/src/paths.rs +27 -0
  18. package/crates/naome-core/src/quality/scanner/repo_paths.rs +2 -47
  19. package/crates/naome-core/src/repo_paths.rs +76 -0
  20. package/crates/naome-core/src/repository_model/path_scan.rs +2 -23
  21. package/crates/naome-core/src/route/context.rs +8 -0
  22. package/crates/naome-core/src/task_ledger/write.rs +6 -0
  23. package/crates/naome-core/src/task_ledger.rs +50 -2
  24. package/crates/naome-core/src/task_state/util.rs +21 -17
  25. package/crates/naome-core/tests/context.rs +92 -0
  26. package/crates/naome-core/tests/decision.rs +2 -10
  27. package/crates/naome-core/tests/information_architecture.rs +7 -10
  28. package/crates/naome-core/tests/install_plan.rs +2 -0
  29. package/crates/naome-core/tests/intent.rs +98 -18
  30. package/crates/naome-core/tests/intent_support/mod.rs +39 -1
  31. package/crates/naome-core/tests/intent_v2.rs +299 -10
  32. package/crates/naome-core/tests/quality_structure_support/mod.rs +6 -25
  33. package/crates/naome-core/tests/repo_support/mod.rs +3 -5
  34. package/crates/naome-core/tests/repo_support/repo_helpers.rs +2 -9
  35. package/crates/naome-core/tests/repo_support/routes.rs +8 -2
  36. package/crates/naome-core/tests/repo_support/verification.rs +1 -8
  37. package/crates/naome-core/tests/repo_support/verification_values.rs +20 -18
  38. package/crates/naome-core/tests/route_baseline.rs +29 -0
  39. package/crates/naome-core/tests/route_completion.rs +26 -5
  40. package/crates/naome-core/tests/route_harness_refresh.rs +7 -1
  41. package/crates/naome-core/tests/route_user_diff.rs +1 -1
  42. package/crates/naome-core/tests/task_ledger.rs +69 -1
  43. package/crates/naome-core/tests/task_state_compact.rs +7 -1
  44. package/crates/naome-core/tests/task_state_compact_support/states.rs +10 -8
  45. package/crates/naome-core/tests/task_state_support/states.rs +8 -8
  46. package/crates/naome-core/tests/workflow_support/mod.rs +2 -0
  47. package/native/darwin-arm64/naome +0 -0
  48. package/native/linux-x64/naome +0 -0
  49. package/package.json +1 -1
  50. package/templates/naome-root/.naome/manifest.json +3 -3
  51. package/templates/naome-root/.naomeignore +1 -0
  52. package/templates/naome-root/docs/naome/agent-workflow.md +22 -15
  53. package/templates/naome-root/docs/naome/architecture.md +17 -8
  54. package/templates/naome-root/docs/naome/task-ledger.md +20 -17
  55. package/crates/naome-core/src/intent/patterns.rs +0 -170
@@ -9,6 +9,12 @@ use repo_support::{
9
9
  TestRepo,
10
10
  };
11
11
 
12
+ fn repair_prompt(prompt: &str) -> String {
13
+ format!(
14
+ "```naome-prompt-envelope-v1\n{{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"fix\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"repair_request\",\"taskIntent\":\"none\",\"risk\":\"none\",\"requestedActions\":[\"repair\"],\"referencedPaths\":[],\"constraints\":[],\"uncertainties\":[]}}\n```\n\n{prompt}"
15
+ )
16
+ }
17
+
12
18
  #[test]
13
19
  fn execute_route_baselines_harness_refresh_before_dirty_repo_worktree() {
14
20
  let repo = TestRepo::dirty_harness_refresh_repo("route-dirty-harness-refresh-worktree", true);
@@ -66,7 +72,7 @@ fn execute_route_repair_request_baselines_harness_refresh_only() {
66
72
 
67
73
  let route = evaluate_route(
68
74
  repo.path(),
69
- "please repair all",
75
+ &repair_prompt("please repair all"),
70
76
  RouteOptions {
71
77
  execute: true,
72
78
  evaluation: EvaluationOptions::offline(),
@@ -27,7 +27,7 @@ fn execute_route_does_not_mutate_or_offer_clear_commit_for_dirty_unowned_diff()
27
27
  )
28
28
  .unwrap();
29
29
 
30
- assert_eq!(route.policy_action, "block_unowned_diff");
30
+ assert_eq!(route.policy_action, "normalize_prompt_first");
31
31
  assert!(!route.mutation_performed);
32
32
  assert!(!route.can_create_task);
33
33
  assert_eq!(route.executed_actions, Vec::<String>::new());
@@ -190,6 +190,70 @@ fn task_state_validation_reports_stale_rendered_projection_when_ledger_exists()
190
190
  }));
191
191
  }
192
192
 
193
+ #[test]
194
+ fn ignored_local_runtime_ledger_does_not_stale_committed_projection() {
195
+ let repo = TestRepo::new("ignored-runtime-ledger");
196
+ repo.init_git();
197
+ repo.write_file(".naomeignore", ".naome/archive/\n.naome/tasks/\n");
198
+ repo.write_file("README.md", "# Baseline\n");
199
+ repo.write_base_harness(Some(idle_state()));
200
+ repo.git(&["add", "."]);
201
+ repo.git(&["commit", "-m", "baseline"]);
202
+ let head = repo.git_stdout(&["rev-parse", "HEAD"]);
203
+ repo.write_complete_ledger(&head);
204
+ repo.write_naome_json("task-state.json", compact_complete_state(&head));
205
+ repo.write_file("README.md", "# Changed\n");
206
+
207
+ let report = validate_task_state(repo.path(), TaskStateOptions::default()).unwrap();
208
+
209
+ assert!(report.errors.is_empty(), "{:?}", report.errors);
210
+ }
211
+
212
+ #[test]
213
+ fn compact_completed_task_state_survives_incomplete_local_runtime_ledger() {
214
+ let repo = TestRepo::new("compact-over-runtime-ledger");
215
+ repo.init_git();
216
+ repo.write_file("README.md", "# Baseline\n");
217
+ repo.write_base_harness(Some(idle_state()));
218
+ repo.git(&["add", "."]);
219
+ repo.git(&["commit", "-m", "baseline"]);
220
+ let head = repo.git_stdout(&["rev-parse", "HEAD"]);
221
+ repo.write_naome_json("task-state.json", compact_complete_state(&head));
222
+ repo.write_file(
223
+ ".naome/tasks/active.json",
224
+ &format_json(object([
225
+ ("schema", json!("naome.task-ledger-active.v1")),
226
+ ("version", json!(1)),
227
+ ("primaryTaskId", json!("old-local-task")),
228
+ (
229
+ "worklanes",
230
+ json!([{ "id": "default", "taskId": "old-local-task", "status": "active" }]),
231
+ ),
232
+ ])),
233
+ );
234
+ repo.write_file(
235
+ ".naome/tasks/old-local-task/task.json",
236
+ &format_json(task_spec_record_with_id(&head, "old-local-task")),
237
+ );
238
+ repo.write_file(
239
+ ".naome/tasks/old-local-task/events.jsonl",
240
+ concat!(
241
+ "{\"schema\":\"naome.task-ledger-event.v1\",\"type\":\"status\",\"status\":\"implementing\",\"recordedAt\":\"2026-05-08T00:00:01.000Z\"}\n",
242
+ "{\"schema\":\"naome.task-ledger-event.v1\",\"type\":\"status\",\"status\":\"complete\",\"recordedAt\":\"2026-05-08T00:00:02.000Z\"}\n"
243
+ ),
244
+ );
245
+ repo.write_file("README.md", "# Changed\n");
246
+
247
+ let projected = read_task_state_projection(repo.path()).unwrap().unwrap();
248
+
249
+ assert_eq!(
250
+ projected["activeTask"]["proofBatches"][0]["proofs"][0]["checkId"],
251
+ "diff-check"
252
+ );
253
+ let report = validate_task_state(repo.path(), TaskStateOptions::default()).unwrap();
254
+ assert!(report.errors.is_empty(), "{:?}", report.errors);
255
+ }
256
+
193
257
  trait LedgerHarness {
194
258
  fn write_base_harness(&self, task_state: Option<Value>);
195
259
  fn write_complete_ledger(&self, admission_head: &str);
@@ -298,10 +362,14 @@ fn compact_active_task(admission_head: &str) -> Value {
298
362
  }
299
363
 
300
364
  fn task_spec_record(admission_head: &str) -> Value {
365
+ task_spec_record_with_id(admission_head, "readme-task")
366
+ }
367
+
368
+ fn task_spec_record_with_id(admission_head: &str, task_id: &str) -> Value {
301
369
  object([
302
370
  ("schema", json!("naome.task-ledger-task.v1")),
303
371
  ("version", json!(1)),
304
- ("id", json!("readme-task")),
372
+ ("id", json!(task_id)),
305
373
  ("request", json!("Update README.")),
306
374
  ("userPrompt", user_prompt()),
307
375
  ("admission", admission_record(admission_head)),
@@ -6,6 +6,12 @@ use task_state_compact_support::{
6
6
  compact_state, large_compact_state, large_expanded_state, legacy_state, MiniRepo,
7
7
  };
8
8
 
9
+ fn new_task_prompt(prompt: &str) -> String {
10
+ format!(
11
+ "```naome-prompt-envelope-v1\n{{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"implementation\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"none\",\"taskIntent\":\"new_task\",\"risk\":\"none\",\"requestedActions\":[],\"referencedPaths\":[],\"constraints\":[],\"uncertainties\":[]}}\n```\n\n{prompt}"
12
+ )
13
+ }
14
+
9
15
  #[test]
10
16
  fn legacy_v1_proof_results_remain_valid() {
11
17
  let repo = MiniRepo::new();
@@ -30,7 +36,7 @@ fn compact_path_sets_and_batches_cover_completion_commit_and_route() {
30
36
 
31
37
  let route = evaluate_route(
32
38
  repo.path(),
33
- "new task",
39
+ &new_task_prompt("new task"),
34
40
  RouteOptions {
35
41
  execute: false,
36
42
  evaluation: EvaluationOptions::offline(),
@@ -129,14 +129,16 @@ fn base_state(admission_head: &str, proof_payload: Value) -> Value {
129
129
  task.as_object_mut()
130
130
  .unwrap()
131
131
  .extend(proof_payload.as_object().unwrap().clone());
132
- json!({
133
- "schema": "naome.task-state.v2",
134
- "version": 2,
135
- "status": "complete",
136
- "activeTask": task,
137
- "blocker": null,
138
- "updatedAt": T0
139
- })
132
+ let mut state: Value = serde_json::from_str(include_str!(
133
+ "../../../../templates/naome-root/.naome/task-state.json"
134
+ ))
135
+ .unwrap();
136
+ state["schema"] = json!("naome.task-state.v2");
137
+ state["version"] = json!(2);
138
+ state["status"] = json!("complete");
139
+ state["activeTask"] = task;
140
+ state["updatedAt"] = json!(T0);
141
+ state
140
142
  }
141
143
 
142
144
  fn proof(check_id: &str, command: &str, cwd: &str) -> Value {
@@ -13,14 +13,14 @@ pub fn complete_task_state(overrides: Value) -> Value {
13
13
  }
14
14
 
15
15
  fn task_state_record(status: &str, active_task: Value, updated_at: Value) -> Value {
16
- json!({
17
- "schema": "naome.task-state.v1",
18
- "version": 1,
19
- "status": status,
20
- "activeTask": active_task,
21
- "blocker": null,
22
- "updatedAt": updated_at
23
- })
16
+ let mut state: Value = serde_json::from_str(include_str!(
17
+ "../../../../templates/naome-root/.naome/task-state.json"
18
+ ))
19
+ .unwrap();
20
+ state["status"] = json!(status);
21
+ state["activeTask"] = active_task;
22
+ state["updatedAt"] = updated_at;
23
+ state
24
24
  }
25
25
 
26
26
  pub fn active_task(overrides: Value) -> Value {
@@ -1,3 +1,5 @@
1
+ #![allow(dead_code)]
2
+
1
3
  use std::fs;
2
4
  use std::path::{Path, PathBuf};
3
5
  use std::process::Command;
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  {
2
- "harnessVersion": "1.2.0",
2
+ "harnessVersion": "1.3.8",
3
3
  "installedAt": null,
4
4
  "integrity": {
5
5
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
@@ -8,12 +8,12 @@
8
8
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
9
9
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
10
10
  "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
11
- "docs/naome/agent-workflow.md": "sha256:2fd1fd02eb6849133b9e8227421914580b1c469a60388a063c1b6ed48016b48d",
11
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
12
12
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
13
13
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
14
14
  "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
15
15
  "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
16
- "docs/naome/task-ledger.md": "sha256:ac637a31abdd13eee15a49086594e63f5c88fe12a5cf621b227310788ae7e583",
16
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
17
17
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
18
18
  },
19
19
  "machineOwned": [
@@ -3,3 +3,4 @@
3
3
 
4
4
  .naome/archive/
5
5
  .naome/cache/
6
+ .naome/tasks/
@@ -11,11 +11,20 @@ Use this workflow after first-run intake is complete.
11
11
  `canCreateTask` fields instead of inventing routing or final-response text.
12
12
  If route returns a `taskRoot` different from the current directory, continue
13
13
  the task from that path and leave the original worktree untouched.
14
- When preparing the route prompt file, prepend a fenced `naome-intent-v2`
15
- JSON envelope that states `workflowAction`, `taskIntent`, and `risk` using
16
- canonical NAOME schema constants such as `commit_request`,
17
- `task_revision`, and `credential_context`. Keep the original user text below
18
- it. Do not derive workflow actions from natural-language keywords.
14
+ When preparing the route prompt file, first normalize the user's raw prompt
15
+ into a fenced `naome-prompt-envelope-v1` JSON envelope. The envelope is the
16
+ routing input; the raw user text below it is audit text. Use canonical NAOME
17
+ schema fields such as `requestKind`, `mutationIntent`,
18
+ `publicationIntent`, `requestedActions`, `referencedPaths`, `constraints`,
19
+ `uncertainties`, `workflowAction`, `taskIntent`, and `risk`. Do not derive
20
+ workflow actions from natural-language keywords, localized words, or the
21
+ prompt's prose language. If a prompt file has no envelope, route returns a
22
+ non-mutating `normalize_prompt_first` decision and the agent must add the
23
+ deterministic envelope before retrying. `naome-intent-v2` is not supported.
24
+ Unknown envelope values require normalization, and conflicting envelope
25
+ fields block as ambiguous instead of mutating. Put concrete files in
26
+ `referencedPaths`; prompt context selection treats those paths as the
27
+ primary source of path intent.
19
28
  3. Use `node .naome/bin/naome.js explain --prompt-file <path> --json` only when
20
29
  debugging why a policy won.
21
30
  4. Run `node .naome/bin/naome.js status --json` when reporting state without
@@ -110,22 +119,20 @@ Use this workflow after first-run intake is complete.
110
119
  1. Identify changed files.
111
120
  2. Match them against `.naome/verification.json`.
112
121
  3. Run the required checks when available.
113
- 4. Prefer ledger-backed task updates. `naome sync` migrates active legacy
122
+ 4. Prefer local ledger-backed task updates. `naome sync` migrates active legacy
114
123
  task-state automatically; if a legacy-only active task is still present, run
115
124
  `node .naome/bin/naome.js task migrate-ledger --write --json` before adding
116
125
  completion proof.
117
- 5. Record proof as compact `proofPathSets` and `proofBatches` in
118
- `.naome/tasks/<task-id>/task.json` when many checks share evidence paths.
119
- Use `.naome/tasks/<task-id>/proofs/` only when separate per-check files are
120
- needed for parallel writers or durable audit detail. If legacy compatibility
121
- work is unavoidable, use the same compact fields in `.naome/task-state.json`
122
- and include every changed in-scope path reported by git in expanded proof
123
- evidence.
126
+ 5. Record proof as compact `proofPathSets` and `proofBatches` in the local
127
+ ledger when many checks share evidence paths. Use local per-check proof files
128
+ only when separate writers need them during the run. The committed release
129
+ artifact is `.naome/task-state.json`; include every changed in-scope path
130
+ reported by git in expanded proof evidence.
124
131
  6. Run `node .naome/bin/naome.js task render-state --write --json` before
125
132
  external compatibility checks. Do not hand-edit the rendered projection when
126
133
  `.naome/tasks/active.json` exists.
127
- 7. Do not list `.naome/task-state.json` or `.naome/tasks/` as task scope or
128
- proof evidence.
134
+ 7. Do not list `.naome/task-state.json` or local task runtime folders as task
135
+ scope or proof evidence.
129
136
  8. Stop tracked long-running processes or mark them explicitly allowed in
130
137
  `.naome/processes.json`.
131
138
  9. Set task status to `complete` in the ledger event stream or legacy task
@@ -8,16 +8,25 @@ Status: Uninitialized
8
8
 
9
9
  ## Known Boundaries
10
10
 
11
- - NAOME information falls into durable project state, durable task ledger,
12
- generated projection, local runtime state, run evidence, and product source.
11
+ - NAOME information falls into durable project state, generated projection,
12
+ local runtime state, run evidence, and product source.
13
13
  - Durable project state is committed repository or package state needed to
14
14
  reinstall or reconstruct the harness.
15
- - `.naome/task-state.json` is a generated compatibility projection when
16
- `.naome/tasks/active.json` exists. Render it from the ledger instead of
17
- hand-editing it.
18
- - `.naome/tmp/` is local runtime state and must not be committed.
19
- - Per-check proof files are run evidence. Prefer compact ledger proof batches
20
- when many release checks share the same evidence paths.
15
+ - `.naome/task-state.json` is the committed compact task-state projection.
16
+ - `.naome/tmp/` and `.naome/tasks/` are local runtime state and must not be
17
+ committed.
18
+ - Per-check proof files are local run evidence. Prefer compact proof batches in
19
+ the committed task-state projection when many release checks share the same
20
+ evidence paths.
21
+ - Prompt routing uses fenced `naome-prompt-envelope-v1` JSON envelopes as the
22
+ deterministic routing input. Raw natural-language prompts are audit text and
23
+ must not be treated as workflow authority until an agent normalizes them into
24
+ canonical fields such as `requestKind`, `mutationIntent`,
25
+ `publicationIntent`, `requestedActions`, `workflowAction`, `taskIntent`, and
26
+ `risk`. Legacy `naome-intent-v2` envelopes are not supported. Unknown
27
+ envelope values require prompt normalization, conflicting fields block as
28
+ ambiguous, and `referencedPaths` is the primary context-selection source for
29
+ prompt-mentioned files.
21
30
 
22
31
  ## Assumed Boundaries
23
32
 
@@ -1,8 +1,9 @@
1
1
  # Task Ledger
2
2
 
3
- NAOME task state is moving from one mutable aggregate file to a canonical task
4
- ledger. The compatibility file `.naome/task-state.json` remains supported, but
5
- new deterministic task tooling can use `.naome/tasks/` as the source of truth.
3
+ NAOME task state is moving from one mutable aggregate file to a local task
4
+ ledger. The compatibility file `.naome/task-state.json` remains the compact
5
+ committed projection, while `.naome/tasks/` is machine-local runtime state for
6
+ efficient task updates.
6
7
 
7
8
  ## Layout
8
9
 
@@ -33,9 +34,10 @@ new deterministic task tooling can use `.naome/tasks/` as the source of truth.
33
34
  ## Compatibility
34
35
 
35
36
  Existing `naome.task-state.v1` and `naome.task-state.v2` files remain valid. If
36
- `.naome/tasks/active.json` exists, NAOME readers build a canonical task model
37
- from the ledger and render a `naome.task-state.v2` projection. If no ledger is
38
- present, readers fall back to `.naome/task-state.json`.
37
+ a current local ledger exists, NAOME readers build a canonical task model from
38
+ it and render a `naome.task-state.v2` projection. If no local ledger is present,
39
+ or an older local completed ledger lacks proof detail that the committed compact
40
+ projection still has, readers fall back to `.naome/task-state.json`.
39
41
 
40
42
  Use this command when an external tool needs the compatibility file refreshed:
41
43
 
@@ -44,21 +46,22 @@ node .naome/bin/naome.js task render-state --write --json
44
46
  ```
45
47
 
46
48
  `naome sync` automatically splits an active legacy `task-state` file into the
47
- ledger layout. The explicit command remains available for repair or tests:
49
+ local ledger layout. The explicit command remains available for repair or
50
+ tests:
48
51
 
49
52
  ```text
50
53
  node .naome/bin/naome.js task migrate-ledger --write --json
51
54
  ```
52
55
 
53
56
  After `.naome/tasks/active.json` exists, `.naome/task-state.json` is a rendered
54
- compatibility projection. NAOME gates reject a stale projection and report the
55
- render command instead of accepting hand-edited aggregate state.
57
+ compatibility projection. NAOME gates reject a stale active projection and
58
+ report the render command instead of accepting hand-edited aggregate state.
56
59
 
57
60
  ## Conflict Policy
58
61
 
59
- `.naome/tasks/` is NAOME control state. It is not task feature scope and is not
60
- required as proof evidence. Gates ignore ledger control files when checking
61
- whether product changes stay inside `allowedPaths`.
62
+ `.naome/tasks/` is local NAOME runtime state. It is ignored, untracked by
63
+ `naome sync`, and not task feature scope or proof evidence. Gates ignore ledger
64
+ control files when checking whether product changes stay inside `allowedPaths`.
62
65
 
63
66
  The intended long-term model is:
64
67
 
@@ -76,8 +79,8 @@ instead of all competing for `.naome/task-state.json`.
76
79
  ## Information Policy
77
80
 
78
81
  Use `node .naome/bin/naome.js workflow information --path <path> --json` before
79
- changing NAOME control files whose retention is unclear. Durable configuration,
80
- templates, task specs, and task events are restored from repository or package
81
- state. `.naome/task-state.json` is generated from durable state. `.naome/tmp/`
82
- is local runtime state. Per-check proof files are run evidence; compact release
83
- proof batches keep release diffs readable without losing verification coverage.
82
+ changing NAOME control files whose retention is unclear. Durable configuration
83
+ and templates are restored from repository or package state.
84
+ `.naome/task-state.json` is the committed compact task projection. `.naome/tmp/`
85
+ and `.naome/tasks/` are local runtime state. Compact release proof batches keep
86
+ release diffs readable without tracking per-task runtime folders.
@@ -1,170 +0,0 @@
1
- use super::model::IntentKind;
2
-
3
- pub(crate) fn normalized(text: &str) -> String {
4
- text.to_lowercase()
5
- .chars()
6
- .map(|ch| if ch.is_alphanumeric() { ch } else { ' ' })
7
- .collect::<String>()
8
- .split_whitespace()
9
- .collect::<Vec<_>>()
10
- .join(" ")
11
- }
12
-
13
- pub(crate) fn lexical_tokens(text: &str) -> Vec<String> {
14
- text.split_whitespace()
15
- .map(|token| {
16
- token
17
- .trim_matches(|ch: char| !ch.is_alphanumeric() && ch != '_' && ch != '-')
18
- .to_lowercase()
19
- })
20
- .filter(|token| !token.is_empty())
21
- .collect()
22
- }
23
-
24
- pub(crate) fn structured_workflow_intents(text: &str) -> Vec<IntentKind> {
25
- let tokens = lexical_tokens(text);
26
- let mut intents = Vec::new();
27
-
28
- if let Some(intent) = structured_action(&tokens) {
29
- intents.push(intent);
30
- }
31
- if let Some(intent) = legacy_v1_short_action_request(&tokens) {
32
- intents.push(intent);
33
- }
34
- if legacy_v1_no_commit(&tokens) {
35
- intents.push(IntentKind::NoCommitRequest);
36
- }
37
- if has_structured_token(&tokens, &["no_commit", "without_commit"]) {
38
- intents.push(IntentKind::NoCommitRequest);
39
- }
40
-
41
- intents.sort_by_key(|kind| kind.as_str());
42
- intents.dedup();
43
- intents
44
- }
45
-
46
- pub(crate) fn command_workflow_intents(text: &str) -> Vec<IntentKind> {
47
- let tokens = lexical_tokens(text);
48
- let mut intents = Vec::new();
49
- if let Some(intent) = cli_action(&tokens) {
50
- intents.push(intent);
51
- }
52
- intents
53
- }
54
-
55
- pub(crate) fn explicit_task_intent(text: &str) -> Option<IntentKind> {
56
- let tokens = lexical_tokens(text);
57
- if has_structured_token(&tokens, &["task_revision", "current_task", "active_task"]) {
58
- return Some(IntentKind::TaskRevision);
59
- }
60
- if has_structured_token(&tokens, &["new_task", "create_new_task", "separate_task"]) {
61
- return Some(IntentKind::NewTask);
62
- }
63
- None
64
- }
65
-
66
- pub(crate) fn is_generic_work_request(text: &str) -> bool {
67
- !lexical_tokens(text).is_empty()
68
- }
69
-
70
- fn structured_action(tokens: &[String]) -> Option<IntentKind> {
71
- policy_action(tokens)
72
- }
73
-
74
- fn policy_action(tokens: &[String]) -> Option<IntentKind> {
75
- for token in tokens {
76
- let intent = match token.as_str() {
77
- "commit_task_baseline" | "commit_user_diff" | "commit_upgrade_baseline" => {
78
- IntentKind::CommitRequest
79
- }
80
- "review_task_diff" | "review_current_task_diff" | "review_unowned_diff" => {
81
- IntentKind::ReviewRequest
82
- }
83
- "repair_harness" | "repair_harness_only" => IntentKind::RepairRequest,
84
- "cancel_task_changes" | "cancel_current_task" => IntentKind::CancelRequest,
85
- "continue_current_task" | "task_complete" | "complete_task" => {
86
- IntentKind::TaskCompletion
87
- }
88
- "answer_status_only" => IntentKind::StatusQuestion,
89
- "clear_or_commit_unowned_diff" => IntentKind::Ambiguous,
90
- _ => continue,
91
- };
92
- return Some(intent);
93
- }
94
- None
95
- }
96
-
97
- fn cli_action(tokens: &[String]) -> Option<IntentKind> {
98
- match (
99
- tokens.first().map(String::as_str),
100
- tokens.get(1).map(String::as_str),
101
- ) {
102
- (Some("naome"), Some("commit")) => Some(IntentKind::CommitRequest),
103
- (Some("naome"), Some("status")) => Some(IntentKind::StatusQuestion),
104
- (Some("naome"), Some("sync" | "update" | "install")) => Some(IntentKind::RepairRequest),
105
- (Some("git"), Some("commit")) => Some(IntentKind::CommitRequest),
106
- _ => None,
107
- }
108
- }
109
-
110
- // Kept only so pre-v2 route callers keep their existing conservative behavior.
111
- // A naome-intent-v2 envelope clears these candidates before policy resolution.
112
- fn legacy_v1_short_action_request(tokens: &[String]) -> Option<IntentKind> {
113
- let action_index = tokens
114
- .iter()
115
- .position(|token| legacy_v1_action_intent(token).is_some())?;
116
- if action_index > 1 || tokens.len() > 6 {
117
- return None;
118
- }
119
-
120
- let intent = legacy_v1_action_intent(&tokens[action_index])?;
121
- if intent == IntentKind::StatusQuestion || tokens.len() <= 3 {
122
- return Some(intent);
123
- }
124
- if tokens.len() <= 2 || legacy_v1_has_action_scope(tokens) {
125
- return Some(intent);
126
- }
127
- None
128
- }
129
-
130
- fn legacy_v1_no_commit(tokens: &[String]) -> bool {
131
- tokens
132
- .windows(3)
133
- .any(|window| window[0] == "do" && window[1] == "not" && window[2] == "commit")
134
- || tokens
135
- .windows(2)
136
- .any(|window| matches!(window[0].as_str(), "no" | "without") && window[1] == "commit")
137
- }
138
-
139
- fn legacy_v1_action_intent(token: &str) -> Option<IntentKind> {
140
- match token {
141
- "commit" | "baseline" => Some(IntentKind::CommitRequest),
142
- "review" => Some(IntentKind::ReviewRequest),
143
- "repair" | "sync" => Some(IntentKind::RepairRequest),
144
- "cancel" => Some(IntentKind::CancelRequest),
145
- "complete" | "completion" => Some(IntentKind::TaskCompletion),
146
- "status" => Some(IntentKind::StatusQuestion),
147
- _ => None,
148
- }
149
- }
150
-
151
- fn legacy_v1_has_action_scope(tokens: &[String]) -> bool {
152
- has_structured_token(
153
- tokens,
154
- &[
155
- "task",
156
- "diff",
157
- "harness",
158
- "baseline",
159
- "state",
160
- "current_task",
161
- "active_task",
162
- ],
163
- )
164
- }
165
-
166
- fn has_structured_token(tokens: &[String], accepted: &[&str]) -> bool {
167
- tokens
168
- .iter()
169
- .any(|token| accepted.iter().any(|accepted| token == accepted))
170
- }