@lamentis/naome 1.3.9 → 1.3.10

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 (38) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +5 -0
  3. package/bin/naome.js +1 -1
  4. package/crates/naome-cli/Cargo.toml +1 -1
  5. package/crates/naome-cli/src/architecture_commands.rs +123 -0
  6. package/crates/naome-cli/src/cli_args.rs +4 -0
  7. package/crates/naome-cli/src/dispatcher.rs +2 -0
  8. package/crates/naome-cli/src/main.rs +6 -0
  9. package/crates/naome-core/Cargo.toml +1 -1
  10. package/crates/naome-core/src/architecture/config/parser/scalar.rs +26 -0
  11. package/crates/naome-core/src/architecture/config/parser/sections.rs +137 -0
  12. package/crates/naome-core/src/architecture/config/parser.rs +96 -0
  13. package/crates/naome-core/src/architecture/config.rs +114 -0
  14. package/crates/naome-core/src/architecture/model.rs +80 -0
  15. package/crates/naome-core/src/architecture/output.rs +178 -0
  16. package/crates/naome-core/src/architecture/rules.rs +140 -0
  17. package/crates/naome-core/src/architecture/scan/graph_builder/emit.rs +56 -0
  18. package/crates/naome-core/src/architecture/scan/graph_builder/facts.rs +88 -0
  19. package/crates/naome-core/src/architecture/scan/graph_builder.rs +134 -0
  20. package/crates/naome-core/src/architecture/scan/path_scan.rs +92 -0
  21. package/crates/naome-core/src/architecture/scan.rs +75 -0
  22. package/crates/naome-core/src/architecture.rs +31 -0
  23. package/crates/naome-core/src/install_plan.rs +2 -0
  24. package/crates/naome-core/src/lib.rs +16 -8
  25. package/crates/naome-core/tests/architecture.rs +209 -0
  26. package/crates/naome-core/tests/harness_health.rs +1 -0
  27. package/installer/harness-files.js +3 -0
  28. package/native/darwin-arm64/naome +0 -0
  29. package/native/linux-x64/naome +0 -0
  30. package/package.json +1 -1
  31. package/templates/naome-root/.naome/bin/check-harness-health.js +7 -7
  32. package/templates/naome-root/.naome/bin/check-task-state.js +7 -7
  33. package/templates/naome-root/.naome/bin/naome.js +2 -2
  34. package/templates/naome-root/.naome/manifest.json +10 -8
  35. package/templates/naome-root/.naome/verification.json +15 -1
  36. package/templates/naome-root/docs/naome/architecture-fitness.md +97 -0
  37. package/templates/naome-root/docs/naome/index.md +4 -3
  38. package/templates/naome-root/docs/naome/testing.md +6 -3
@@ -0,0 +1,92 @@
1
+ use std::fs;
2
+ use std::path::Path;
3
+
4
+ use crate::models::NaomeError;
5
+ use crate::paths;
6
+
7
+ use crate::architecture::config::ArchitectureConfig;
8
+
9
+ pub(super) fn repository_files(
10
+ root: &Path,
11
+ config: &ArchitectureConfig,
12
+ ) -> Result<Vec<String>, NaomeError> {
13
+ let ignored_patterns = ignored_patterns(root, config);
14
+ let mut files = Vec::new();
15
+ collect_files(root, root, &ignored_patterns, &mut files)?;
16
+ files.sort();
17
+ Ok(files)
18
+ }
19
+
20
+ fn collect_files(
21
+ root: &Path,
22
+ dir: &Path,
23
+ ignored_patterns: &[String],
24
+ files: &mut Vec<String>,
25
+ ) -> Result<(), NaomeError> {
26
+ for entry in fs::read_dir(dir)? {
27
+ let entry = entry?;
28
+ let path = entry.path();
29
+ let relative = normalize_path(path.strip_prefix(root).unwrap_or(&path));
30
+ if is_ignored(&relative, ignored_patterns) {
31
+ continue;
32
+ }
33
+ let metadata = fs::symlink_metadata(&path)?;
34
+ if metadata.is_symlink() {
35
+ continue;
36
+ }
37
+ if metadata.is_dir() {
38
+ collect_files(root, &path, ignored_patterns, files)?;
39
+ } else if metadata.is_file() {
40
+ files.push(relative);
41
+ }
42
+ }
43
+ Ok(())
44
+ }
45
+
46
+ fn is_ignored(path: &str, ignored_patterns: &[String]) -> bool {
47
+ path.is_empty() || is_default_ignored_path(path) || paths::matches_any(path, ignored_patterns)
48
+ }
49
+
50
+ fn ignored_patterns(root: &Path, config: &ArchitectureConfig) -> Vec<String> {
51
+ let mut patterns = paths::naomeignore_patterns(root);
52
+ patterns.extend([
53
+ ".git/**".to_string(),
54
+ ".naome/archive/**".to_string(),
55
+ ".naome/cache/**".to_string(),
56
+ ".naome/local/**".to_string(),
57
+ ".naome/tasks/**".to_string(),
58
+ "node_modules/**".to_string(),
59
+ "target/**".to_string(),
60
+ "dist/**".to_string(),
61
+ "build/**".to_string(),
62
+ ]);
63
+ patterns.extend(config.ignore.iter().map(|rule| rule.path.clone()));
64
+ patterns
65
+ }
66
+
67
+ fn is_default_ignored_path(path: &str) -> bool {
68
+ path == ".git"
69
+ || path.starts_with(".git/")
70
+ || path == ".naome/archive"
71
+ || path.starts_with(".naome/archive/")
72
+ || path == ".naome/cache"
73
+ || path.starts_with(".naome/cache/")
74
+ || path == ".naome/local"
75
+ || path.starts_with(".naome/local/")
76
+ || path == ".naome/tasks"
77
+ || path.starts_with(".naome/tasks/")
78
+ || path == ".npm"
79
+ || path.starts_with(".npm/")
80
+ || path == "node_modules"
81
+ || path.contains("/node_modules/")
82
+ || path == "target"
83
+ || path.contains("/target/")
84
+ || path == "dist"
85
+ || path.contains("/dist/")
86
+ || path == "build"
87
+ || path.contains("/build/")
88
+ }
89
+
90
+ fn normalize_path(path: impl AsRef<Path>) -> String {
91
+ path.as_ref().to_string_lossy().replace('\\', "/")
92
+ }
@@ -0,0 +1,75 @@
1
+ use std::collections::BTreeMap;
2
+ use std::path::{Path, PathBuf};
3
+
4
+ use serde::Serialize;
5
+
6
+ use crate::git;
7
+ use crate::models::NaomeError;
8
+
9
+ use super::config::{read_architecture_config, ArchitectureConfig};
10
+ use super::model::ArchitectureGraph;
11
+
12
+ mod graph_builder;
13
+ mod path_scan;
14
+
15
+ #[derive(Debug, Clone, Default)]
16
+ pub struct ArchitectureScanOptions {
17
+ pub config_path: Option<PathBuf>,
18
+ pub changed_only: bool,
19
+ }
20
+
21
+ #[derive(Debug, Clone, Serialize)]
22
+ #[serde(rename_all = "camelCase")]
23
+ pub struct ArchitectureScanReport {
24
+ pub schema: String,
25
+ pub graph: ArchitectureGraph,
26
+ pub files_scanned: usize,
27
+ pub changed_only_requested: bool,
28
+ pub changed_only_degraded_to_full_scan: bool,
29
+ pub changed_paths: Vec<String>,
30
+ #[serde(skip_serializing)]
31
+ pub config: ArchitectureConfig,
32
+ #[serde(skip_serializing)]
33
+ pub file_facts: BTreeMap<String, FileFact>,
34
+ }
35
+
36
+ #[derive(Debug, Clone, Serialize)]
37
+ #[serde(rename_all = "camelCase")]
38
+ pub struct FileFact {
39
+ pub path: String,
40
+ pub language: Option<String>,
41
+ pub line_count: usize,
42
+ pub layers: Vec<String>,
43
+ pub contexts: Vec<String>,
44
+ pub ignored: Option<String>,
45
+ }
46
+
47
+ pub fn scan_architecture(
48
+ root: &Path,
49
+ options: ArchitectureScanOptions,
50
+ ) -> Result<ArchitectureScanReport, NaomeError> {
51
+ let config = read_architecture_config(root, options.config_path.as_deref())?;
52
+ let changed_paths = changed_paths(root, options.changed_only)?;
53
+ let files = path_scan::repository_files(root, &config)?;
54
+ let (mut graph, file_facts) = graph_builder::build_path_graph(root, files, &config);
55
+
56
+ graph.sort_stable();
57
+ Ok(ArchitectureScanReport {
58
+ schema: "naome.arch.scan.v1".to_string(),
59
+ files_scanned: file_facts.len(),
60
+ graph,
61
+ changed_only_requested: options.changed_only,
62
+ changed_only_degraded_to_full_scan: options.changed_only,
63
+ changed_paths,
64
+ config,
65
+ file_facts,
66
+ })
67
+ }
68
+
69
+ fn changed_paths(root: &Path, changed_only: bool) -> Result<Vec<String>, NaomeError> {
70
+ if changed_only {
71
+ git::changed_paths(root)
72
+ } else {
73
+ Ok(Vec::new())
74
+ }
75
+ }
@@ -0,0 +1,31 @@
1
+ mod config;
2
+ mod model;
3
+ mod output;
4
+ mod rules;
5
+ mod scan;
6
+
7
+ use std::path::Path;
8
+
9
+ use crate::models::NaomeError;
10
+
11
+ pub use config::{
12
+ default_architecture_config_text, ArchitectureConfig, ContextConfig, LayerConfig, RuleConfig,
13
+ };
14
+ pub use model::{
15
+ ArchitectureEdge, ArchitectureEdgeKind, ArchitectureGraph, ArchitectureMetadata,
16
+ ArchitectureNode, ArchitectureNodeKind, SourceRange,
17
+ };
18
+ pub use output::{
19
+ format_architecture_explain, format_architecture_scan, format_architecture_validation,
20
+ ArchitectureAgentFeedback, ArchitectureValidation, ArchitectureViolation, Severity,
21
+ ViolationSummary,
22
+ };
23
+ pub use scan::{scan_architecture, ArchitectureScanOptions, ArchitectureScanReport};
24
+
25
+ pub fn validate_architecture(
26
+ root: &Path,
27
+ options: ArchitectureScanOptions,
28
+ ) -> Result<ArchitectureValidation, NaomeError> {
29
+ let scan = scan_architecture(root, options)?;
30
+ Ok(rules::validate_scan(scan))
31
+ }
@@ -12,6 +12,7 @@ pub const MACHINE_OWNED_PATHS: &[&str] = &[
12
12
  "docs/naome/agent-workflow.md",
13
13
  "docs/naome/context-economy.md",
14
14
  "docs/naome/task-ledger.md",
15
+ "docs/naome/architecture-fitness.md",
15
16
  "docs/naome/execution.md",
16
17
  "docs/naome/upgrade.md",
17
18
  ];
@@ -48,6 +49,7 @@ pub const LOCAL_ONLY_MACHINE_OWNED_PATHS: &[&str] = &[
48
49
  "docs/naome/agent-workflow.md",
49
50
  "docs/naome/context-economy.md",
50
51
  "docs/naome/task-ledger.md",
52
+ "docs/naome/architecture-fitness.md",
51
53
  "docs/naome/execution.md",
52
54
  "docs/naome/upgrade.md",
53
55
  ];
@@ -1,3 +1,4 @@
1
+ mod architecture;
1
2
  mod context;
2
3
  mod decision;
3
4
  mod git;
@@ -19,6 +20,14 @@ mod verification_contract;
19
20
  mod verification_contract_policy;
20
21
  mod workflow;
21
22
 
23
+ pub use architecture::{
24
+ default_architecture_config_text, format_architecture_explain, format_architecture_scan,
25
+ format_architecture_validation, scan_architecture, validate_architecture,
26
+ ArchitectureAgentFeedback, ArchitectureConfig, ArchitectureEdge, ArchitectureEdgeKind,
27
+ ArchitectureGraph, ArchitectureMetadata, ArchitectureNode, ArchitectureNodeKind,
28
+ ArchitectureScanOptions, ArchitectureScanReport, ArchitectureValidation, ArchitectureViolation,
29
+ ContextConfig, LayerConfig, RuleConfig, Severity, SourceRange, ViolationSummary,
30
+ };
22
31
  pub use context::{
23
32
  select_context_for_changed_paths, select_context_for_prompt, ContextBudgetLedger,
24
33
  ContextCapsule, ContextItem, ContextSelection,
@@ -36,14 +45,13 @@ pub use journal::{append_task_journal, TaskJournalEntry};
36
45
  pub use models::{Decision, NaomeError};
37
46
  pub use quality::{
38
47
  check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
39
- check_semantic_legacy_paths,
40
- clear_quality_cache, explain_repository_structure, init_repository_quality,
41
- init_repository_quality_with_mode, plan_quality_cleanup, quality_cache_status,
42
- reconcile_repository_quality, route_quality_cleanup, semantic_route_for_finding,
43
- QualityCacheStatus, QualityCleanupPlan, QualityCleanupRoute, QualityCleanupTask,
44
- QualityInitMode, QualityInitResult, QualityMode, QualityReconcileReport, QualityReport,
45
- QualitySummary, QualityViolation, RepositoryQualityConfig, RepositoryStructureConfig,
46
- SemanticFinding, SemanticReport, StructurePathExplanation,
48
+ check_semantic_legacy_paths, clear_quality_cache, explain_repository_structure,
49
+ init_repository_quality, init_repository_quality_with_mode, plan_quality_cleanup,
50
+ quality_cache_status, reconcile_repository_quality, route_quality_cleanup,
51
+ semantic_route_for_finding, QualityCacheStatus, QualityCleanupPlan, QualityCleanupRoute,
52
+ QualityCleanupTask, QualityInitMode, QualityInitResult, QualityMode, QualityReconcileReport,
53
+ QualityReport, QualitySummary, QualityViolation, RepositoryQualityConfig,
54
+ RepositoryStructureConfig, SemanticFinding, SemanticReport, StructurePathExplanation,
47
55
  };
48
56
  pub use repository_model::{
49
57
  explain_repository_model_path, refresh_repository_model, repository_model_drift,
@@ -0,0 +1,209 @@
1
+ use std::fs;
2
+ use std::path::{Path, PathBuf};
3
+ use std::process::Command;
4
+ use std::sync::atomic::{AtomicU64, Ordering};
5
+ use std::time::{SystemTime, UNIX_EPOCH};
6
+
7
+ use naome_core::{
8
+ default_architecture_config_text, scan_architecture, validate_architecture, ArchitectureConfig,
9
+ ArchitectureScanOptions,
10
+ };
11
+
12
+ static FIXTURE_COUNTER: AtomicU64 = AtomicU64::new(0);
13
+
14
+ #[test]
15
+ fn parses_starter_architecture_config() {
16
+ let config = ArchitectureConfig::parse(default_architecture_config_text(), "test").unwrap();
17
+
18
+ assert!(config.layers.contains_key("application"));
19
+ assert_eq!(
20
+ config.rule("max_file_lines").value,
21
+ Some(400),
22
+ "starter config should seed a production file-size budget"
23
+ );
24
+ assert_eq!(
25
+ config.ignore[0].reason,
26
+ "Generated code is not architecture-owned."
27
+ );
28
+ }
29
+
30
+ #[test]
31
+ fn path_extractor_builds_language_agnostic_graph_for_mixed_repo() {
32
+ let repo = FixtureRepo::new();
33
+ repo.write("src/domain/event.ts", "export const event = 1;\n");
34
+ repo.write("src/infrastructure/db.py", "client = object()\n");
35
+ repo.write("cmd/server/main.go", "package main\n");
36
+ repo.write(
37
+ "naome.arch.yaml",
38
+ r#"
39
+ layers:
40
+ domain:
41
+ paths:
42
+ - "src/domain/**"
43
+ infrastructure:
44
+ paths:
45
+ - "src/infrastructure/**"
46
+ contexts:
47
+ app:
48
+ paths:
49
+ - "src/**"
50
+ public_api:
51
+ - "src/index.ts"
52
+ rules:
53
+ max_file_lines:
54
+ enabled: true
55
+ value: 400
56
+ severity: warning
57
+ "#,
58
+ );
59
+
60
+ let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
61
+
62
+ assert!(scan
63
+ .graph
64
+ .nodes
65
+ .iter()
66
+ .any(|node| node.id == "file:src/domain/event.ts"));
67
+ assert!(scan
68
+ .graph
69
+ .nodes
70
+ .iter()
71
+ .any(|node| node.id == "layer:domain"));
72
+ assert!(scan
73
+ .graph
74
+ .edges
75
+ .iter()
76
+ .any(|edge| { edge.from == "layer:domain" && edge.to == "file:src/domain/event.ts" }));
77
+ assert_eq!(
78
+ scan.file_facts
79
+ .get("cmd/server/main.go")
80
+ .unwrap()
81
+ .language
82
+ .as_deref(),
83
+ Some("go")
84
+ );
85
+ }
86
+
87
+ #[test]
88
+ fn validates_file_size_budget_with_stable_json_shape() {
89
+ let repo = FixtureRepo::new();
90
+ repo.write(
91
+ "naome.arch.yaml",
92
+ r#"
93
+ rules:
94
+ max_file_lines:
95
+ enabled: true
96
+ value: 2
97
+ severity: error
98
+ "#,
99
+ );
100
+ repo.write("src/too_big.rs", "one\ntwo\nthree\n");
101
+
102
+ let report = validate_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
103
+ let json = serde_json::to_string(&report).unwrap();
104
+
105
+ assert_eq!(report.status, "fail");
106
+ assert!(json.contains("\"schema\":\"naome.arch.validation.v1\""));
107
+ assert!(json.contains("\"id\":\"arch.max_file_lines\""));
108
+ let violation = report
109
+ .violations
110
+ .iter()
111
+ .find(|violation| violation.path.as_deref() == Some("src/too_big.rs"))
112
+ .expect("expected src/too_big.rs file-size violation");
113
+ assert_eq!(violation.agent_instruction, "Reduce src/too_big.rs below 2 lines or add a justified generated-code ignore rule if it is not manually owned.");
114
+ }
115
+
116
+ #[test]
117
+ fn changed_only_generated_boundary_reports_changed_generated_file() {
118
+ let repo = FixtureRepo::new();
119
+ repo.init_git();
120
+ repo.write(
121
+ "naome.arch.yaml",
122
+ r#"
123
+ rules:
124
+ generated_manual_boundary:
125
+ enabled: true
126
+ severity: error
127
+ ignore:
128
+ - path: "generated/**"
129
+ reason: "Generated code is not manually edited."
130
+ "#,
131
+ );
132
+ repo.write("generated/client.ts", "export const generated = true;\n");
133
+
134
+ let report = validate_architecture(
135
+ repo.path(),
136
+ ArchitectureScanOptions {
137
+ changed_only: true,
138
+ config_path: None,
139
+ },
140
+ )
141
+ .unwrap();
142
+
143
+ assert_eq!(report.status, "fail");
144
+ assert!(report.changed_only_degraded_to_full_scan);
145
+ assert_eq!(report.violations[0].id, "arch.generated_manual_boundary");
146
+ assert_eq!(
147
+ report.violations[0].path.as_deref(),
148
+ Some("generated/client.ts")
149
+ );
150
+ }
151
+
152
+ struct FixtureRepo {
153
+ root: PathBuf,
154
+ }
155
+
156
+ impl FixtureRepo {
157
+ fn new() -> Self {
158
+ let nonce = SystemTime::now()
159
+ .duration_since(UNIX_EPOCH)
160
+ .unwrap()
161
+ .as_nanos();
162
+ let counter = FIXTURE_COUNTER.fetch_add(1, Ordering::Relaxed);
163
+ let root = std::env::temp_dir().join(format!(
164
+ "naome-arch-fixture-{}-{nonce}-{counter}",
165
+ std::process::id()
166
+ ));
167
+ fs::create_dir_all(&root).unwrap();
168
+ fs::write(
169
+ root.join(".naomeignore"),
170
+ ".naome/archive/\n.naome/tasks/\n",
171
+ )
172
+ .unwrap();
173
+ Self { root }
174
+ }
175
+
176
+ fn path(&self) -> &Path {
177
+ &self.root
178
+ }
179
+
180
+ fn write(&self, relative_path: &str, content: &str) {
181
+ let path = self.root.join(relative_path);
182
+ fs::create_dir_all(path.parent().unwrap()).unwrap();
183
+ fs::write(path, content).unwrap();
184
+ }
185
+
186
+ fn init_git(&self) {
187
+ run_git(&self.root, &["init"]);
188
+ run_git(&self.root, &["config", "user.email", "naome@example.com"]);
189
+ run_git(&self.root, &["config", "user.name", "NAOME Test"]);
190
+ self.write("README.md", "# Fixture\n");
191
+ run_git(&self.root, &["add", "."]);
192
+ run_git(&self.root, &["commit", "-m", "baseline"]);
193
+ }
194
+ }
195
+
196
+ fn run_git(root: &Path, args: &[&str]) {
197
+ let result = Command::new("git")
198
+ .args(args)
199
+ .current_dir(root)
200
+ .output()
201
+ .unwrap();
202
+ assert!(
203
+ result.status.success(),
204
+ "git {:?} failed: {}{}",
205
+ args,
206
+ String::from_utf8_lossy(&result.stdout),
207
+ String::from_utf8_lossy(&result.stderr)
208
+ );
209
+ }
@@ -19,6 +19,7 @@ const MACHINE_OWNED_PATHS: &[&str] = &[
19
19
  "docs/naome/first-run.md",
20
20
  "docs/naome/agent-workflow.md",
21
21
  "docs/naome/context-economy.md",
22
+ "docs/naome/architecture-fitness.md",
22
23
  "docs/naome/execution.md",
23
24
  "docs/naome/task-ledger.md",
24
25
  "docs/naome/upgrade.md",
@@ -22,6 +22,7 @@ export function ensureCoreHarnessFiles(ctx, archiveDirName) {
22
22
  replaceHarnessFile(ctx, "docs/naome/task-ledger.md", archiveDirName);
23
23
  ensureTemplateFile(ctx, "docs/naome/repository-model.md");
24
24
  ensureTemplateFile(ctx, "docs/naome/security.md");
25
+ ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
25
26
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
26
27
  }
27
28
 
@@ -39,6 +40,7 @@ export function ensureTaskControlHarnessFiles(ctx, archiveDirName) {
39
40
  replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
40
41
  replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
41
42
  replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
43
+ ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
42
44
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
43
45
  }
44
46
 
@@ -57,6 +59,7 @@ export function ensureHarnessHealthFiles(ctx, archiveDirName) {
57
59
  replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
58
60
  replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
59
61
  ensureTemplateFile(ctx, "docs/naome/security.md");
62
+ ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
60
63
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
61
64
  ensureNaomeIgnore(ctx);
62
65
  }
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.3.9",
3
+ "version": "1.3.10",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -10,18 +10,18 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
10
  const expectedNativeBinaryIntegrity = "sha256:generated";
11
11
 
12
12
  const expectedMachineOwnedIntegrity = Object.freeze({
13
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
14
- ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
- ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
13
  ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
14
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
15
+ ".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
16
+ ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
18
17
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
19
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
18
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
21
19
  "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
22
20
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
- "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
24
21
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
22
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
23
+ "docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
24
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
25
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
26
26
  });
27
27
 
@@ -10,18 +10,18 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
10
  const expectedNativeBinaryIntegrity = "sha256:generated";
11
11
 
12
12
  const expectedMachineOwnedIntegrity = Object.freeze({
13
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
14
- ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
- ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
13
  ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
14
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
15
+ ".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
16
+ ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
18
17
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
19
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
18
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
21
19
  "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
22
20
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
- "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
24
21
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
22
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
23
+ "docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
24
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
25
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
26
26
  });
27
27
 
@@ -27,7 +27,7 @@ function main(argv) {
27
27
  return;
28
28
  }
29
29
 
30
- if (["status", "next", "intent", "route", "explain", "context", "doctor", "task", "quality", "semantic", "repo", "structure", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
30
+ if (["status", "next", "intent", "route", "explain", "context", "doctor", "task", "quality", "semantic", "arch", "repo", "structure", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
31
31
  runNativeDecisionCommand(command, args);
32
32
  return;
33
33
  }
@@ -367,7 +367,7 @@ function findAncestorWithAnyMarker(startPath, markers) {
367
367
  }
368
368
 
369
369
  function printHelp() {
370
- const commands = "naome status [--json]|naome next [--json]|naome intent --prompt-file <path> [--json]|naome intent --prompt <text> [--json]|naome route --prompt-file <path> [--execute] [--json]|naome route --prompt <text> [--execute] [--json]|naome explain --prompt-file <path> [--json]|naome explain --prompt <text> [--json]|naome context select --changed [--json]|naome context select --prompt-file <path> [--json]|naome context select --prompt <text> [--json]|naome doctor [--json]|naome task render-state [--write] [--json]|naome task migrate-ledger [--write] [--json]|naome quality init [--baseline|--deep-baseline] [--json]|naome quality check --changed [--include-scanned-paths] [--json]|naome quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]|naome quality report [--deep] [--include-scanned-paths] [--json]|naome quality cache status [--json]|naome quality cache clear|naome semantic report [--deep] [--json]|naome semantic check --changed [--json]|naome semantic check --path <path> [--path <path>...] [--json]|naome semantic route --finding <id> [--json]|naome semantic loop [--json]|naome repo model [--write] [--json]|naome repo check [--json]|naome repo explain --path <path> [--json]|naome structure report [--json]|naome structure explain --path <path> [--json]|naome cleanup plan [--json]|naome cleanup route --path <path> [--json]|naome refresh-integrity [--json]|naome workflow agent-plan|context-delta|proof-plan|capabilities|edit-watchdog|decision-gate|digest [--json]|naome workflow search-profile|check-search|phases|processes|mutations [--json]|naome install|naome sync|naome commit -m \"type(scope): message\"|node .naome/bin/naome.js commit -m \"type(scope): message\"".split("|");
370
+ const commands = "naome status [--json]|naome next [--json]|naome intent --prompt-file <path> [--json]|naome intent --prompt <text> [--json]|naome route --prompt-file <path> [--execute] [--json]|naome route --prompt <text> [--execute] [--json]|naome explain --prompt-file <path> [--json]|naome explain --prompt <text> [--json]|naome context select --changed [--json]|naome context select --prompt-file <path> [--json]|naome context select --prompt <text> [--json]|naome doctor [--json]|naome task render-state [--write] [--json]|naome task migrate-ledger [--write] [--json]|naome quality init [--baseline|--deep-baseline] [--json]|naome quality check --changed [--include-scanned-paths] [--json]|naome quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]|naome quality report [--deep] [--include-scanned-paths] [--json]|naome quality cache status [--json]|naome quality cache clear|naome semantic report [--deep] [--json]|naome semantic check --changed [--json]|naome semantic check --path <path> [--path <path>...] [--json]|naome semantic route --finding <id> [--json]|naome semantic loop [--json]|naome arch init [--config <path>] [--json]|naome arch explain [--config <path>] [--json]|naome arch scan [--config <path>] [--changed-only] [--write] [--output <path>] [--json]|naome arch validate [--config <path>] [--changed-only] [--json|--agent-feedback]|naome repo model [--write] [--json]|naome repo check [--json]|naome repo explain --path <path> [--json]|naome structure report [--json]|naome structure explain --path <path> [--json]|naome cleanup plan [--json]|naome cleanup route --path <path> [--json]|naome refresh-integrity [--json]|naome workflow agent-plan|context-delta|proof-plan|capabilities|edit-watchdog|decision-gate|digest [--json]|naome workflow search-profile|check-search|phases|processes|mutations [--json]|naome install|naome sync|naome commit -m \"type(scope): message\"|node .naome/bin/naome.js commit -m \"type(scope): message\"".split("|");
371
371
  console.log(["Usage:", ...commands.map((command) => ` ${command}`)].join("\n"));
372
372
  }
373
373
 
@@ -1,19 +1,20 @@
1
1
  {
2
- "harnessVersion": "1.3.9",
2
+ "harnessVersion": "1.3.10",
3
3
  "installedAt": null,
4
4
  "integrity": {
5
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
6
- ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
7
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
8
- ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
9
5
  ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
6
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
7
+ ".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
8
+ ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
10
9
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
11
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
12
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
10
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
13
11
  "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
12
+ "docs/naome/architecture-fitness.md": "sha256:ec2cff9f2090d9b6bfeb2464a650cff97790c4d3e626fd40a42374d5f79c7c38",
14
13
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
15
- "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
16
14
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
15
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
16
+ "docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
17
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
17
18
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
18
19
  },
19
20
  "machineOwned": [
@@ -28,6 +29,7 @@
28
29
  "docs/naome/agent-workflow.md",
29
30
  "docs/naome/context-economy.md",
30
31
  "docs/naome/task-ledger.md",
32
+ "docs/naome/architecture-fitness.md",
31
33
  "docs/naome/execution.md",
32
34
  "docs/naome/upgrade.md"
33
35
  ],
@@ -65,6 +65,19 @@
65
65
  ".naome/repository-quality-baseline.json"
66
66
  ],
67
67
  "lastVerified": null
68
+ },
69
+ {
70
+ "id": "architecture-fitness-check",
71
+ "command": "node .naome/bin/naome.js arch validate --changed-only",
72
+ "cwd": ".",
73
+ "purpose": "Validate changed files against deterministic NAOME architecture fitness rules.",
74
+ "cost": "fast",
75
+ "source": "NAOME built-in",
76
+ "evidence": [
77
+ "naome.arch.yaml",
78
+ "docs/naome/architecture-fitness.md"
79
+ ],
80
+ "lastVerified": null
68
81
  }
69
82
  ],
70
83
  "phases": [
@@ -81,7 +94,8 @@
81
94
  "order": 20,
82
95
  "checkIds": [
83
96
  "repository-quality-check",
84
- "repository-semantic-check"
97
+ "repository-semantic-check",
98
+ "architecture-fitness-check"
85
99
  ]
86
100
  },
87
101
  {