@lamentis/naome 1.3.1 → 1.3.3

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 (37) hide show
  1. package/Cargo.lock +2 -2
  2. package/crates/naome-cli/Cargo.toml +1 -1
  3. package/crates/naome-core/Cargo.toml +1 -1
  4. package/crates/naome-core/src/intent/resolver_catalog/active.rs +38 -0
  5. package/crates/naome-core/src/intent/resolver_catalog/baseline.rs +44 -0
  6. package/crates/naome-core/src/intent/resolver_catalog/completed.rs +56 -0
  7. package/crates/naome-core/src/intent/resolver_catalog/dirty.rs +32 -0
  8. package/crates/naome-core/src/intent/resolver_catalog/ready.rs +32 -0
  9. package/crates/naome-core/src/intent/resolver_catalog/system.rs +20 -0
  10. package/crates/naome-core/src/intent/resolver_catalog.rs +12 -166
  11. package/crates/naome-core/src/lib.rs +1 -0
  12. package/crates/naome-core/src/route/quality_gate_config.rs +18 -0
  13. package/crates/naome-core/src/task_state/diff.rs +2 -2
  14. package/crates/naome-core/src/task_state/git_io.rs +5 -2
  15. package/crates/naome-core/src/task_state/types.rs +4 -0
  16. package/crates/naome-core/src/verification_contract.rs +3 -1
  17. package/crates/naome-core/src/verification_contract_policy.rs +52 -0
  18. package/crates/naome-core/tests/harness_health.rs +29 -40
  19. package/crates/naome-core/tests/repo_support/mod.rs +5 -2
  20. package/crates/naome-core/tests/repo_support/verification.rs +28 -42
  21. package/crates/naome-core/tests/repo_support/verification_values.rs +106 -1
  22. package/crates/naome-core/tests/route_user_diff.rs +52 -4
  23. package/crates/naome-core/tests/task_state.rs +12 -26
  24. package/crates/naome-core/tests/task_state_support/mod.rs +2 -1
  25. package/crates/naome-core/tests/task_state_support/states.rs +28 -11
  26. package/crates/naome-core/tests/verification.rs +2 -20
  27. package/crates/naome-core/tests/verification_contract.rs +42 -52
  28. package/crates/naome-core/tests/workflow_integrity.rs +2 -20
  29. package/crates/naome-core/tests/workflow_support/mod.rs +59 -20
  30. package/native/darwin-arm64/naome +0 -0
  31. package/native/linux-x64/naome +0 -0
  32. package/package.json +1 -1
  33. package/templates/naome-root/.naome/bin/check-harness-health.js +1 -1
  34. package/templates/naome-root/.naome/bin/check-task-state.js +1 -1
  35. package/templates/naome-root/.naome/manifest.json +1 -1
  36. package/templates/naome-root/docs/naome/first-run.md +1 -1
  37. package/templates/naome-root/docs/naome/testing.md +1 -1
package/Cargo.lock CHANGED
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
76
76
 
77
77
  [[package]]
78
78
  name = "naome-cli"
79
- version = "1.3.1"
79
+ version = "1.3.3"
80
80
  dependencies = [
81
81
  "naome-core",
82
82
  "serde_json",
@@ -84,7 +84,7 @@ dependencies = [
84
84
 
85
85
  [[package]]
86
86
  name = "naome-core"
87
- version = "1.3.1"
87
+ version = "1.3.3"
88
88
  dependencies = [
89
89
  "serde",
90
90
  "serde_json",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-cli"
3
- version = "1.3.1"
3
+ version = "1.3.3"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-core"
3
- version = "1.3.1"
3
+ version = "1.3.3"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -0,0 +1,38 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_ACTIVE_BLOCKED: Policy = (
4
+ "block_unowned_diff",
5
+ false,
6
+ "The active task is blocked by out-of-scope changes.",
7
+ "Resolve the scope blocker before interpreting new work.",
8
+ );
9
+ pub(crate) const POLICY_ACTIVE_CANCEL: Policy = (
10
+ "cancel_current_task",
11
+ false,
12
+ "The prompt asks to cancel the active task.",
13
+ "Cancel or review the active task before starting another.",
14
+ );
15
+ pub(crate) const POLICY_ACTIVE_CONTINUE: Policy = (
16
+ "continue_current_task",
17
+ true,
18
+ "A task is active and the prompt appears to continue or finish it.",
19
+ "Continue the current task and keep proof current.",
20
+ );
21
+ pub(crate) const POLICY_ACTIVE_NEW_BLOCK: Policy = (
22
+ "block_ambiguous_intent",
23
+ false,
24
+ "A task is already active and the prompt appears to ask for a distinct new goal.",
25
+ "Complete, revise, or cancel the active task before starting another.",
26
+ );
27
+ pub(crate) const POLICY_ACTIVE_NO_COMMIT: Policy = (
28
+ "continue_current_task_without_commit",
29
+ true,
30
+ "A task is active and the prompt blocks committing.",
31
+ "Continue the active task without baselining.",
32
+ );
33
+ pub(crate) const POLICY_ACTIVE_REVIEW: Policy = (
34
+ "review_current_task_diff",
35
+ false,
36
+ "The prompt asks to review the active task diff.",
37
+ "Review the active task before mutating it further.",
38
+ );
@@ -0,0 +1,44 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_BASELINE_BLOCK: Policy = (
4
+ "block_unowned_diff",
5
+ false,
6
+ "Setup, upgrade, or repair changes must be resolved before task routing.",
7
+ "Resolve the harness baseline decision before accepting feature work.",
8
+ );
9
+ pub(crate) const POLICY_BASELINE_CANCEL: Policy = (
10
+ "cancel_upgrade_baseline",
11
+ false,
12
+ "The prompt explicitly asks to cancel setup, upgrade, or repair changes.",
13
+ "Cancel or review the NAOME diff before feature work.",
14
+ );
15
+ pub(crate) const POLICY_BASELINE_COMMIT_UPGRADE: Policy = (
16
+ "commit_upgrade_baseline",
17
+ true,
18
+ "The prompt asks to baseline pending setup, upgrade, or repair changes.",
19
+ "Run the appropriate NAOME baseline flow before feature work.",
20
+ );
21
+ pub(crate) const POLICY_BASELINE_NEW_REFRESH: Policy = (
22
+ "auto_commit_harness_refresh_then_create_new_task",
23
+ true,
24
+ "The prompt asks for a new goal and the only blocker is a deterministic harness refresh.",
25
+ "Baseline the harness refresh automatically, rerun admission, then create the new task in the same worktree.",
26
+ );
27
+ pub(crate) const POLICY_BASELINE_NEW_UPGRADE: Policy = (
28
+ "auto_commit_upgrade_baseline_then_create_new_task",
29
+ true,
30
+ "The prompt asks for a new goal and the only blocker is a completed NAOME setup, upgrade, or repair diff.",
31
+ "Baseline the NAOME diff automatically, rerun admission, then create the new task.",
32
+ );
33
+ pub(crate) const POLICY_BASELINE_NO_COMMIT: Policy = (
34
+ "block_auto_baseline_due_to_no_commit",
35
+ false,
36
+ "The prompt explicitly blocks committing, so NAOME will not auto-baseline setup or repair changes.",
37
+ "Review, cancel, or manually resolve the setup diff before feature work.",
38
+ );
39
+ pub(crate) const POLICY_BASELINE_REVIEW: Policy = (
40
+ "review_diff_first",
41
+ false,
42
+ "The prompt explicitly asks to review setup, upgrade, or repair changes.",
43
+ "Review the NAOME diff before any baseline or new task.",
44
+ );
@@ -0,0 +1,56 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_COMPLETED_CANCEL: Policy = (
4
+ "cancel_task_changes",
5
+ false,
6
+ "The prompt explicitly asks to cancel the completed task changes.",
7
+ "Cancel or review the completed task diff before any new task.",
8
+ );
9
+ pub(crate) const POLICY_COMPLETED_COMMIT: Policy = (
10
+ "commit_task_baseline",
11
+ true,
12
+ "The prompt asks to baseline the completed task diff.",
13
+ "Run the NAOME commit baseline flow for the completed task.",
14
+ );
15
+ pub(crate) const POLICY_COMPLETED_NEW_INVALID: Policy = (
16
+ "block_unsafe_intent",
17
+ false,
18
+ "The prompt asks for a new task, but the current completed task is not safe to auto-baseline.",
19
+ "Review the completed diff and proof before starting new work.",
20
+ );
21
+ pub(crate) const POLICY_COMPLETED_NEW_ISOLATED: Policy = (
22
+ "auto_commit_completed_task_then_create_isolated_task_worktree",
23
+ true,
24
+ "The completed task is valid, and unrelated user edits are present.",
25
+ "Baseline only the completed task paths, preserve unrelated user edits, and create an isolated worktree for the next task.",
26
+ );
27
+ pub(crate) const POLICY_COMPLETED_NEW_REFRESH: Policy = (
28
+ "auto_commit_harness_refresh_then_completed_task_then_create_new_task",
29
+ true,
30
+ "The completed task is valid after separating deterministic harness refresh changes.",
31
+ "Baseline the harness refresh first, then baseline the completed task and create the next task.",
32
+ );
33
+ pub(crate) const POLICY_COMPLETED_NEW_VALID: Policy = (
34
+ "auto_commit_completed_task_then_create_new_task",
35
+ true,
36
+ "The completed task is valid and the prompt asks for a distinct new goal.",
37
+ "Baseline the completed task first, then create the next task.",
38
+ );
39
+ pub(crate) const POLICY_COMPLETED_NO_COMMIT: Policy = (
40
+ "block_auto_baseline_due_to_no_commit",
41
+ false,
42
+ "The prompt explicitly blocks committing, so NAOME will not auto-baseline the completed task.",
43
+ "Review, revise, cancel, or manually resolve the completed task diff.",
44
+ );
45
+ pub(crate) const POLICY_COMPLETED_REVIEW: Policy = (
46
+ "review_task_diff",
47
+ false,
48
+ "The prompt explicitly asks to review the completed task diff.",
49
+ "Review the completed task diff before any baseline or new task.",
50
+ );
51
+ pub(crate) const POLICY_COMPLETED_REVISION: Policy = (
52
+ "reopen_completed_task_revision",
53
+ true,
54
+ "The prompt refers to follow-up correction on the unbaselined completed task.",
55
+ "Reopen the same task as a revision and mark proof stale before editing.",
56
+ );
@@ -0,0 +1,32 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_DIRTY_BLOCK: Policy = (
4
+ "block_unowned_diff",
5
+ false,
6
+ "The repository has unowned changes that must be resolved first.",
7
+ "NAOME will not commit unowned changes. Review them, or route a new task so NAOME can isolate task work in a separate worktree.",
8
+ );
9
+ pub(crate) const POLICY_DIRTY_COMMIT_USER: Policy = (
10
+ "commit_user_diff_with_quality_gate",
11
+ true,
12
+ "The prompt asks to commit unowned user changes.",
13
+ "Run NAOME's user-diff quality gate, then commit only the current changed paths if every required check passes.",
14
+ );
15
+ pub(crate) const POLICY_DIRTY_NEW_ISOLATED: Policy = (
16
+ "auto_commit_harness_refresh_then_create_isolated_task_worktree",
17
+ true,
18
+ "The repository has deterministic harness refresh changes plus unrelated user edits.",
19
+ "Baseline only the harness refresh first, then create an isolated task worktree without touching user edits.",
20
+ );
21
+ pub(crate) const POLICY_DIRTY_NEW_REFRESH: Policy = (
22
+ "auto_commit_harness_refresh_then_create_new_task",
23
+ true,
24
+ "The repository has only deterministic harness refresh changes.",
25
+ "Baseline the harness refresh first, then create the next task in the same worktree.",
26
+ );
27
+ pub(crate) const POLICY_DIRTY_NEW_WORKTREE: Policy = (
28
+ "create_isolated_task_worktree",
29
+ true,
30
+ "The repository has unrelated user changes, and the prompt asks for a new task.",
31
+ "Create an isolated NAOME task worktree so the new task can proceed without touching those user changes.",
32
+ );
@@ -0,0 +1,32 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_READY_COMMIT_BLOCK: Policy = (
4
+ "block_ambiguous_intent",
5
+ false,
6
+ "The repository is already ready for work; there is no open task diff to baseline.",
7
+ "Ask for the next concrete task or inspect status.",
8
+ );
9
+ pub(crate) const POLICY_READY_NEW: Policy = (
10
+ "create_new_task",
11
+ true,
12
+ "The repository is clean and the prompt asks for a new goal.",
13
+ "Create a NAOME task for the new request.",
14
+ );
15
+ pub(crate) const POLICY_READY_NO_COMMIT: Policy = (
16
+ "create_new_task_without_auto_baseline",
17
+ true,
18
+ "The repository is clean, so no commit is needed before the new task.",
19
+ "Create a NAOME task for the new request.",
20
+ );
21
+ pub(crate) const POLICY_READY_REVIEW_STATUS: Policy = (
22
+ "answer_status_only",
23
+ true,
24
+ "The prompt asks for review, but there is no open task diff.",
25
+ "Answer from the current NAOME status without editing files.",
26
+ );
27
+ pub(crate) const POLICY_READY_REVISION_BLOCK: Policy = (
28
+ "block_ambiguous_intent",
29
+ false,
30
+ "The prompt sounds like a correction, but there is no open task diff.",
31
+ "Ask whether this is a new task or a status question.",
32
+ );
@@ -0,0 +1,20 @@
1
+ use super::super::resolver_shared::Policy;
2
+
3
+ pub(crate) const POLICY_FIRST_RUN: Policy = (
4
+ "run_first_run_protocol",
5
+ false,
6
+ "First-run intake must finish before feature work.",
7
+ "Run the NAOME first-run protocol.",
8
+ );
9
+ pub(crate) const POLICY_HARNESS_UNHEALTHY: Policy = (
10
+ "repair_harness_only",
11
+ false,
12
+ "The harness is unhealthy, so normal task work is blocked.",
13
+ "Repair or review the harness before accepting feature work.",
14
+ );
15
+ pub(crate) const POLICY_UPGRADE: Policy = (
16
+ "run_upgrade_protocol",
17
+ false,
18
+ "A NAOME upgrade is pending before feature work.",
19
+ "Run the NAOME upgrade protocol.",
20
+ );
@@ -1,167 +1,13 @@
1
- use super::resolver_shared::Policy;
1
+ mod active;
2
+ mod baseline;
3
+ mod completed;
4
+ mod dirty;
5
+ mod ready;
6
+ mod system;
2
7
 
3
- pub(crate) const POLICY_ACTIVE_BLOCKED: Policy = (
4
- "block_unowned_diff",
5
- false,
6
- "The active task is blocked by out-of-scope changes.",
7
- "Resolve the scope blocker before interpreting new work.",
8
- );
9
- pub(crate) const POLICY_ACTIVE_CANCEL: Policy = (
10
- "cancel_current_task",
11
- false,
12
- "The prompt asks to cancel the active task.",
13
- "Cancel or review the active task before starting another.",
14
- );
15
- pub(crate) const POLICY_ACTIVE_CONTINUE: Policy = (
16
- "continue_current_task",
17
- true,
18
- "A task is active and the prompt appears to continue or finish it.",
19
- "Continue the current task and keep proof current.",
20
- );
21
- pub(crate) const POLICY_ACTIVE_NEW_BLOCK: Policy = (
22
- "block_ambiguous_intent",
23
- false,
24
- "A task is already active and the prompt appears to ask for a distinct new goal.",
25
- "Complete, revise, or cancel the active task before starting another.",
26
- );
27
- pub(crate) const POLICY_ACTIVE_NO_COMMIT: Policy = (
28
- "continue_current_task_without_commit",
29
- true,
30
- "A task is active and the prompt blocks committing.",
31
- "Continue the active task without baselining.",
32
- );
33
- pub(crate) const POLICY_ACTIVE_REVIEW: Policy = (
34
- "review_current_task_diff",
35
- false,
36
- "The prompt asks to review the active task diff.",
37
- "Review the active task before mutating it further.",
38
- );
39
- pub(crate) const POLICY_BASELINE_BLOCK: Policy = (
40
- "block_unowned_diff",
41
- false,
42
- "Setup, upgrade, or repair changes must be resolved before task routing.",
43
- "Resolve the harness baseline decision before accepting feature work.",
44
- );
45
- pub(crate) const POLICY_BASELINE_CANCEL: Policy = (
46
- "cancel_upgrade_baseline",
47
- false,
48
- "The prompt explicitly asks to cancel setup, upgrade, or repair changes.",
49
- "Cancel or review the NAOME diff before feature work.",
50
- );
51
- pub(crate) const POLICY_BASELINE_COMMIT_UPGRADE: Policy = (
52
- "commit_upgrade_baseline",
53
- true,
54
- "The prompt asks to baseline pending setup, upgrade, or repair changes.",
55
- "Run the appropriate NAOME baseline flow before feature work.",
56
- );
57
- pub(crate) const POLICY_BASELINE_NEW_REFRESH: Policy = ("auto_commit_harness_refresh_then_create_new_task", true, "The prompt asks for a new goal and the only blocker is a deterministic harness refresh.", "Baseline the harness refresh automatically, rerun admission, then create the new task in the same worktree.");
58
- pub(crate) const POLICY_BASELINE_NEW_UPGRADE: Policy = ("auto_commit_upgrade_baseline_then_create_new_task", true, "The prompt asks for a new goal and the only blocker is a completed NAOME setup, upgrade, or repair diff.", "Baseline the NAOME diff automatically, rerun admission, then create the new task.");
59
- pub(crate) const POLICY_BASELINE_NO_COMMIT: Policy = ("block_auto_baseline_due_to_no_commit", false, "The prompt explicitly blocks committing, so NAOME will not auto-baseline setup or repair changes.", "Review, cancel, or manually resolve the setup diff before feature work.");
60
- pub(crate) const POLICY_BASELINE_REVIEW: Policy = (
61
- "review_diff_first",
62
- false,
63
- "The prompt explicitly asks to review setup, upgrade, or repair changes.",
64
- "Review the NAOME diff before any baseline or new task.",
65
- );
66
- pub(crate) const POLICY_COMPLETED_CANCEL: Policy = (
67
- "cancel_task_changes",
68
- false,
69
- "The prompt explicitly asks to cancel the completed task changes.",
70
- "Cancel or review the completed task diff before any new task.",
71
- );
72
- pub(crate) const POLICY_COMPLETED_COMMIT: Policy = (
73
- "commit_task_baseline",
74
- true,
75
- "The prompt asks to baseline the completed task diff.",
76
- "Run the NAOME commit baseline flow for the completed task.",
77
- );
78
- pub(crate) const POLICY_COMPLETED_NEW_INVALID: Policy = (
79
- "block_unsafe_intent",
80
- false,
81
- "The prompt asks for a new task, but the current completed task is not safe to auto-baseline.",
82
- "Review the completed diff and proof before starting new work.",
83
- );
84
- pub(crate) const POLICY_COMPLETED_NEW_ISOLATED: Policy = ("auto_commit_completed_task_then_create_isolated_task_worktree", true, "The completed task is valid, and unrelated user edits are present.", "Baseline only the completed task paths, preserve unrelated user edits, and create an isolated worktree for the next task.");
85
- pub(crate) const POLICY_COMPLETED_NEW_REFRESH: Policy = ("auto_commit_harness_refresh_then_completed_task_then_create_new_task", true, "The completed task is valid after separating deterministic harness refresh changes.", "Baseline the harness refresh first, then baseline the completed task and create the next task.");
86
- pub(crate) const POLICY_COMPLETED_NEW_VALID: Policy = (
87
- "auto_commit_completed_task_then_create_new_task",
88
- true,
89
- "The completed task is valid and the prompt asks for a distinct new goal.",
90
- "Baseline the completed task first, then create the next task.",
91
- );
92
- pub(crate) const POLICY_COMPLETED_NO_COMMIT: Policy = (
93
- "block_auto_baseline_due_to_no_commit",
94
- false,
95
- "The prompt explicitly blocks committing, so NAOME will not auto-baseline the completed task.",
96
- "Review, revise, cancel, or manually resolve the completed task diff.",
97
- );
98
- pub(crate) const POLICY_COMPLETED_REVIEW: Policy = (
99
- "review_task_diff",
100
- false,
101
- "The prompt explicitly asks to review the completed task diff.",
102
- "Review the completed task diff before any baseline or new task.",
103
- );
104
- pub(crate) const POLICY_COMPLETED_REVISION: Policy = (
105
- "reopen_completed_task_revision",
106
- true,
107
- "The prompt refers to follow-up correction on the unbaselined completed task.",
108
- "Reopen the same task as a revision and mark proof stale before editing.",
109
- );
110
- pub(crate) const POLICY_DIRTY_BLOCK: Policy = ("block_unowned_diff", false, "The repository has unowned changes that must be resolved first.", "NAOME will not commit unowned changes. Review them, or route a new task so NAOME can isolate task work in a separate worktree.");
111
- pub(crate) const POLICY_DIRTY_COMMIT_USER: Policy = ("commit_user_diff_with_quality_gate", true, "The prompt asks to commit unowned user changes.", "Run NAOME's user-diff quality gate, then commit only the current changed paths if every required check passes.");
112
- pub(crate) const POLICY_DIRTY_NEW_ISOLATED: Policy = ("auto_commit_harness_refresh_then_create_isolated_task_worktree", true, "The repository has deterministic harness refresh changes plus unrelated user edits.", "Baseline only the harness refresh first, then create an isolated task worktree without touching user edits.");
113
- pub(crate) const POLICY_DIRTY_NEW_REFRESH: Policy = (
114
- "auto_commit_harness_refresh_then_create_new_task",
115
- true,
116
- "The repository has only deterministic harness refresh changes.",
117
- "Baseline the harness refresh first, then create the next task in the same worktree.",
118
- );
119
- pub(crate) const POLICY_DIRTY_NEW_WORKTREE: Policy = ("create_isolated_task_worktree", true, "The repository has unrelated user changes, and the prompt asks for a new task.", "Create an isolated NAOME task worktree so the new task can proceed without touching those user changes.");
120
- pub(crate) const POLICY_FIRST_RUN: Policy = (
121
- "run_first_run_protocol",
122
- false,
123
- "First-run intake must finish before feature work.",
124
- "Run the NAOME first-run protocol.",
125
- );
126
- pub(crate) const POLICY_HARNESS_UNHEALTHY: Policy = (
127
- "repair_harness_only",
128
- false,
129
- "The harness is unhealthy, so normal task work is blocked.",
130
- "Repair or review the harness before accepting feature work.",
131
- );
132
- pub(crate) const POLICY_READY_COMMIT_BLOCK: Policy = (
133
- "block_ambiguous_intent",
134
- false,
135
- "The repository is already ready for work; there is no open task diff to baseline.",
136
- "Ask for the next concrete task or inspect status.",
137
- );
138
- pub(crate) const POLICY_READY_NEW: Policy = (
139
- "create_new_task",
140
- true,
141
- "The repository is clean and the prompt asks for a new goal.",
142
- "Create a NAOME task for the new request.",
143
- );
144
- pub(crate) const POLICY_READY_NO_COMMIT: Policy = (
145
- "create_new_task_without_auto_baseline",
146
- true,
147
- "The repository is clean, so no commit is needed before the new task.",
148
- "Create a NAOME task for the new request.",
149
- );
150
- pub(crate) const POLICY_READY_REVIEW_STATUS: Policy = (
151
- "answer_status_only",
152
- true,
153
- "The prompt asks for review, but there is no open task diff.",
154
- "Answer from the current NAOME status without editing files.",
155
- );
156
- pub(crate) const POLICY_READY_REVISION_BLOCK: Policy = (
157
- "block_ambiguous_intent",
158
- false,
159
- "The prompt sounds like a correction, but there is no open task diff.",
160
- "Ask whether this is a new task or a status question.",
161
- );
162
- pub(crate) const POLICY_UPGRADE: Policy = (
163
- "run_upgrade_protocol",
164
- false,
165
- "A NAOME upgrade is pending before feature work.",
166
- "Run the NAOME upgrade protocol.",
167
- );
8
+ pub(crate) use active::*;
9
+ pub(crate) use baseline::*;
10
+ pub(crate) use completed::*;
11
+ pub(crate) use dirty::*;
12
+ pub(crate) use ready::*;
13
+ pub(crate) use system::*;
@@ -14,6 +14,7 @@ mod task_ledger;
14
14
  mod task_state;
15
15
  mod verification;
16
16
  mod verification_contract;
17
+ mod verification_contract_policy;
17
18
  mod workflow;
18
19
 
19
20
  pub use context::{
@@ -98,6 +98,7 @@ pub(super) fn user_diff_check_ids(
98
98
  "No quality checks are configured for these changed paths.",
99
99
  ));
100
100
  }
101
+ enforce_repository_semantic_companion(&mut ids, checks)?;
101
102
 
102
103
  Ok(ids)
103
104
  }
@@ -124,3 +125,20 @@ fn push_unique_string(values: &mut Vec<String>, value: &str) {
124
125
  values.push(value.to_string());
125
126
  }
126
127
  }
128
+
129
+ fn enforce_repository_semantic_companion(
130
+ ids: &mut Vec<String>,
131
+ checks: &HashMap<&str, QualityCheck>,
132
+ ) -> Result<(), NaomeError> {
133
+ if !ids.iter().any(|item| item == "repository-quality-check") {
134
+ return Ok(());
135
+ }
136
+ if checks.contains_key("repository-semantic-check") {
137
+ push_unique_string(ids, "repository-semantic-check");
138
+ return Ok(());
139
+ }
140
+
141
+ Err(NaomeError::new(
142
+ "repository-quality-check requires repository-semantic-check so semantic findings are mandatory quality-gate failures.",
143
+ ))
144
+ }
@@ -6,7 +6,7 @@ use serde_json::Value;
6
6
  use crate::models::NaomeError;
7
7
 
8
8
  use super::git_io::read_git_changed_entries;
9
- use super::types::{is_control_state_path, ChangedEntry, TaskDiff};
9
+ use super::types::{is_control_state_path, is_local_runtime_path, ChangedEntry, TaskDiff};
10
10
  use super::util::{matches_any_pattern, normalize_path, string_array};
11
11
  pub(super) fn validate_changed_paths(
12
12
  active_task: &Value,
@@ -80,7 +80,7 @@ pub(super) fn task_diff_from_entries(active_task: &Value, entries: &[ChangedEntr
80
80
  let diff_paths: Vec<String> = entries
81
81
  .iter()
82
82
  .map(|entry| entry.path.clone())
83
- .filter(|path| !is_control_state_path(path))
83
+ .filter(|path| !is_control_state_path(path) && !is_local_runtime_path(path))
84
84
  .collect();
85
85
  let outside_paths = diff_paths
86
86
  .iter()
@@ -6,7 +6,7 @@ use crate::models::NaomeError;
6
6
 
7
7
  pub(super) use super::git_parse::{parse_name_status_output, split_nul, upsert_changed_entry};
8
8
  pub(super) use super::git_refs::{command_output, git_commit_exists, read_git_head, run_git};
9
- use super::types::ChangedEntry;
9
+ use super::types::{is_local_runtime_path, ChangedEntry};
10
10
  use super::util::normalize_path;
11
11
  pub(super) fn read_git_changed_paths(root: &Path) -> Result<Vec<String>, NaomeError> {
12
12
  Ok(read_git_changed_entries(root)?
@@ -55,6 +55,9 @@ pub(super) fn read_git_changed_entries(root: &Path) -> Result<Vec<ChangedEntry>,
55
55
  }
56
56
 
57
57
  for entry in parse_name_status_output(&output.stdout) {
58
+ if is_local_runtime_path(&entry.path) {
59
+ continue;
60
+ }
58
61
  upsert_changed_entry(&mut entries, entry);
59
62
  }
60
63
  }
@@ -69,7 +72,7 @@ pub(super) fn read_git_changed_entries(root: &Path) -> Result<Vec<ChangedEntry>,
69
72
 
70
73
  for token in split_nul(&untracked.stdout) {
71
74
  let path = normalize_path(token.trim());
72
- if !path.is_empty() {
75
+ if !path.is_empty() && !is_local_runtime_path(&path) {
73
76
  upsert_changed_entry(
74
77
  &mut entries,
75
78
  ChangedEntry {
@@ -97,6 +97,10 @@ pub(super) fn is_control_state_path(path: &str) -> bool {
97
97
  path == CONTROL_STATE_PATH || path.starts_with(TASK_LEDGER_PATH_PREFIX)
98
98
  }
99
99
 
100
+ pub(super) fn is_local_runtime_path(path: &str) -> bool {
101
+ path == ".naome/tmp" || path.starts_with(".naome/tmp/")
102
+ }
103
+
100
104
  pub(super) fn read_complete_active_task(root: &Path) -> Result<Option<(Value, Value)>, NaomeError> {
101
105
  let Some(task_state) = read_task_state_projection(root)? else {
102
106
  return Ok(None);
@@ -5,6 +5,7 @@ use std::path::Path;
5
5
  use serde_json::Value;
6
6
 
7
7
  use crate::models::NaomeError;
8
+ use crate::verification_contract_policy::validate_semantic_quality_gate_policy;
8
9
 
9
10
  const REQUIRED_TESTING_HEADINGS: &[&str] = &[
10
11
  "# Testing And Verification",
@@ -29,7 +30,7 @@ const ALLOWED_TOP_LEVEL_KEYS: &[&str] = &[
29
30
  const MAX_CHECKS: usize = 20;
30
31
  const MAX_PHASES: usize = 8;
31
32
  const MAX_CHANGE_TYPES: usize = 12;
32
- const MAX_RELEASE_GATES: usize = 10;
33
+ const MAX_RELEASE_GATES: usize = 12;
33
34
 
34
35
  pub fn validate_verification_contract(root: &Path) -> Result<Vec<String>, NaomeError> {
35
36
  let mut errors = Vec::new();
@@ -135,6 +136,7 @@ fn validate_contract_shape(contract: &Value, errors: &mut Vec<String>) {
135
136
  }
136
137
  validate_change_types(change_types, &check_ids, errors);
137
138
  validate_release_gates(release_gates, &check_ids, errors);
139
+ validate_semantic_quality_gate_policy(change_types, release_gates, &check_ids, errors);
138
140
 
139
141
  if status == Some("ready") && contains_example_placeholders(contract) {
140
142
  errors.push(
@@ -0,0 +1,52 @@
1
+ use std::collections::HashSet;
2
+
3
+ use serde_json::Value;
4
+
5
+ pub(crate) fn validate_semantic_quality_gate_policy(
6
+ change_types: &[Value],
7
+ release_gates: &[Value],
8
+ check_ids: &HashSet<String>,
9
+ errors: &mut Vec<String>,
10
+ ) {
11
+ if check_ids.contains("repository-quality-check")
12
+ && !check_ids.contains("repository-semantic-check")
13
+ {
14
+ errors.push(
15
+ "checks must include repository-semantic-check whenever repository-quality-check is configured.".to_string(),
16
+ );
17
+ }
18
+
19
+ for (index, change_type) in change_types.iter().enumerate() {
20
+ let Some(required_checks) = change_type
21
+ .get("requiredChecks")
22
+ .and_then(Value::as_array)
23
+ else {
24
+ continue;
25
+ };
26
+ let has_quality = contains_string(required_checks, "repository-quality-check");
27
+ let has_semantic = contains_string(required_checks, "repository-semantic-check");
28
+ if has_quality && !has_semantic {
29
+ errors.push(format!(
30
+ "changeTypes[{index}].requiredChecks must include repository-semantic-check whenever repository-quality-check is required."
31
+ ));
32
+ }
33
+ }
34
+
35
+ let has_quality_release_gate = release_gates.iter().any(|gate| {
36
+ gate.get("checkId").and_then(Value::as_str) == Some("repository-quality-check")
37
+ });
38
+ let has_semantic_release_gate = release_gates.iter().any(|gate| {
39
+ gate.get("checkId").and_then(Value::as_str) == Some("repository-semantic-check")
40
+ });
41
+ if has_quality_release_gate && !has_semantic_release_gate {
42
+ errors.push(
43
+ "releaseGates must include repository-semantic-check whenever repository-quality-check is a release gate.".to_string(),
44
+ );
45
+ }
46
+ }
47
+
48
+ fn contains_string(values: &[Value], expected: &str) -> bool {
49
+ values
50
+ .iter()
51
+ .any(|value| value.as_str() == Some(expected))
52
+ }