@lamentis/naome 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/Cargo.toml +1 -1
- package/LICENSE +180 -21
- package/README.md +49 -6
- package/bin/naome.js +54 -16
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/check_commands.rs +135 -0
- package/crates/naome-cli/src/cli_args.rs +5 -0
- package/crates/naome-cli/src/dispatcher.rs +36 -0
- package/crates/naome-cli/src/install_bridge.rs +83 -0
- package/crates/naome-cli/src/main.rs +57 -341
- package/crates/naome-cli/src/prompt_commands.rs +68 -0
- package/crates/naome-cli/src/quality_commands.rs +141 -0
- package/crates/naome-cli/src/simple_commands.rs +53 -0
- package/crates/naome-cli/src/workflow_commands.rs +153 -0
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/harness_health/integrity.rs +96 -0
- package/crates/naome-core/src/harness_health.rs +14 -126
- package/crates/naome-core/src/install_plan.rs +3 -0
- package/crates/naome-core/src/intent/classifier.rs +171 -0
- package/crates/naome-core/src/intent/envelope.rs +108 -0
- package/crates/naome-core/src/intent/legacy.rs +138 -0
- package/crates/naome-core/src/intent/legacy_response.rs +76 -0
- package/crates/naome-core/src/intent/model.rs +71 -0
- package/crates/naome-core/src/intent/patterns.rs +170 -0
- package/crates/naome-core/src/intent/resolver.rs +162 -0
- package/crates/naome-core/src/intent/resolver_active.rs +17 -0
- package/crates/naome-core/src/intent/resolver_baseline.rs +55 -0
- package/crates/naome-core/src/intent/resolver_catalog.rs +167 -0
- package/crates/naome-core/src/intent/resolver_policy.rs +72 -0
- package/crates/naome-core/src/intent/resolver_shared.rs +55 -0
- package/crates/naome-core/src/intent/risk.rs +40 -0
- package/crates/naome-core/src/intent/segment.rs +170 -0
- package/crates/naome-core/src/intent.rs +64 -879
- package/crates/naome-core/src/journal.rs +9 -20
- package/crates/naome-core/src/lib.rs +13 -0
- package/crates/naome-core/src/quality/adapters.rs +178 -0
- package/crates/naome-core/src/quality/baseline.rs +75 -0
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +175 -0
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +130 -0
- package/crates/naome-core/src/quality/checks.rs +228 -0
- package/crates/naome-core/src/quality/cleanup.rs +72 -0
- package/crates/naome-core/src/quality/config.rs +109 -0
- package/crates/naome-core/src/quality/mod.rs +90 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +103 -0
- package/crates/naome-core/src/quality/scanner.rs +367 -0
- package/crates/naome-core/src/quality/types.rs +289 -0
- package/crates/naome-core/src/route.rs +62 -0
- package/crates/naome-core/src/task_state/admission.rs +63 -0
- package/crates/naome-core/src/task_state/admission_proof.rs +72 -0
- package/crates/naome-core/src/task_state/api.rs +130 -0
- package/crates/naome-core/src/task_state/commit_gate.rs +138 -0
- package/crates/naome-core/src/task_state/compact_proof.rs +160 -0
- package/crates/naome-core/src/task_state/completed_refresh.rs +89 -0
- package/crates/naome-core/src/task_state/completion.rs +72 -0
- package/crates/naome-core/src/task_state/deleted_paths.rs +47 -0
- package/crates/naome-core/src/task_state/diff.rs +95 -0
- package/crates/naome-core/src/task_state/evidence.rs +154 -0
- package/crates/naome-core/src/task_state/git_io.rs +86 -0
- package/crates/naome-core/src/task_state/git_parse.rs +86 -0
- package/crates/naome-core/src/task_state/git_refs.rs +37 -0
- package/crates/naome-core/src/task_state/human_review_state.rs +31 -0
- package/crates/naome-core/src/task_state/mod.rs +38 -0
- package/crates/naome-core/src/task_state/process_guard.rs +40 -0
- package/crates/naome-core/src/task_state/progress.rs +123 -0
- package/crates/naome-core/src/task_state/proof.rs +139 -0
- package/crates/naome-core/src/task_state/proof_entry.rs +66 -0
- package/crates/naome-core/src/task_state/proof_model.rs +70 -0
- package/crates/naome-core/src/task_state/proof_sources.rs +76 -0
- package/crates/naome-core/src/task_state/push_gate.rs +49 -0
- package/crates/naome-core/src/task_state/reconcile.rs +7 -0
- package/crates/naome-core/src/task_state/repair.rs +168 -0
- package/crates/naome-core/src/task_state/shape.rs +117 -0
- package/crates/naome-core/src/task_state/task_diff_api.rs +170 -0
- package/crates/naome-core/src/task_state/task_records.rs +131 -0
- package/crates/naome-core/src/task_state/task_references.rs +126 -0
- package/crates/naome-core/src/task_state/types.rs +87 -0
- package/crates/naome-core/src/task_state/util.rs +137 -0
- package/crates/naome-core/src/verification/render.rs +122 -0
- package/crates/naome-core/src/verification.rs +176 -58
- package/crates/naome-core/src/verification_contract.rs +49 -21
- package/crates/naome-core/src/workflow/integrity.rs +123 -0
- package/crates/naome-core/src/workflow/integrity_normalize.rs +7 -0
- package/crates/naome-core/src/workflow/integrity_support.rs +110 -0
- package/crates/naome-core/src/workflow/mod.rs +18 -0
- package/crates/naome-core/src/workflow/mutation.rs +68 -0
- package/crates/naome-core/src/workflow/output.rs +111 -0
- package/crates/naome-core/src/workflow/phase_inference.rs +73 -0
- package/crates/naome-core/src/workflow/phases.rs +169 -0
- package/crates/naome-core/src/workflow/policy.rs +156 -0
- package/crates/naome-core/src/workflow/processes.rs +91 -0
- package/crates/naome-core/src/workflow/types.rs +42 -0
- package/crates/naome-core/tests/harness_health.rs +3 -0
- package/crates/naome-core/tests/intent.rs +97 -792
- package/crates/naome-core/tests/intent_support/mod.rs +133 -0
- package/crates/naome-core/tests/intent_v2.rs +90 -0
- package/crates/naome-core/tests/quality.rs +425 -0
- package/crates/naome-core/tests/route.rs +88 -188
- package/crates/naome-core/tests/task_state.rs +3 -0
- package/crates/naome-core/tests/task_state_compact.rs +110 -0
- package/crates/naome-core/tests/task_state_compact_support/mod.rs +5 -0
- package/crates/naome-core/tests/task_state_compact_support/repo.rs +130 -0
- package/crates/naome-core/tests/task_state_compact_support/states.rs +151 -0
- package/crates/naome-core/tests/workflow_integrity.rs +85 -0
- package/crates/naome-core/tests/workflow_policy.rs +139 -0
- package/crates/naome-core/tests/workflow_support/mod.rs +194 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +2 -2
- package/templates/naome-root/.naome/bin/check-harness-health.js +66 -85
- package/templates/naome-root/.naome/bin/check-task-state.js +9 -10
- package/templates/naome-root/.naome/bin/naome.js +34 -63
- package/templates/naome-root/.naome/manifest.json +20 -18
- package/templates/naome-root/.naome/repository-quality-baseline.json +5 -0
- package/templates/naome-root/.naome/repository-quality.json +24 -0
- package/templates/naome-root/.naome/task-contract.schema.json +93 -11
- package/templates/naome-root/.naome/upgrade-state.json +1 -1
- package/templates/naome-root/.naome/verification.json +37 -0
- package/templates/naome-root/AGENTS.md +3 -0
- package/templates/naome-root/docs/naome/agent-workflow.md +25 -12
- package/templates/naome-root/docs/naome/execution.md +25 -21
- package/templates/naome-root/docs/naome/index.md +4 -3
- package/templates/naome-root/docs/naome/repository-quality.md +43 -0
- package/templates/naome-root/docs/naome/testing.md +12 -0
- package/crates/naome-core/src/task_state.rs +0 -2210
|
@@ -203,6 +203,94 @@ fn execute_route_commits_user_diff_after_quality_gate_passes() {
|
|
|
203
203
|
assert!(route.user_message.contains("quality gates passed"));
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
#[test]
|
|
207
|
+
fn execute_route_runs_repository_quality_check_without_shelling_to_repo_command() {
|
|
208
|
+
let repo = TestRepo::new("route-repository-quality-check");
|
|
209
|
+
repo.init_git();
|
|
210
|
+
repo.write_file(
|
|
211
|
+
".naome/repository-quality.json",
|
|
212
|
+
r#"{
|
|
213
|
+
"schema": "naome.repository-quality.v1",
|
|
214
|
+
"version": 1,
|
|
215
|
+
"status": "ready",
|
|
216
|
+
"limits": {
|
|
217
|
+
"maxFileLines": 5,
|
|
218
|
+
"maxNewFileLines": 5,
|
|
219
|
+
"maxDiffAddedLines": 200,
|
|
220
|
+
"maxFunctionLines": 40,
|
|
221
|
+
"maxTopLevelSymbols": 30,
|
|
222
|
+
"duplicateBlockLines": 4,
|
|
223
|
+
"nearDuplicateSimilarity": 0.9
|
|
224
|
+
},
|
|
225
|
+
"disabledChecks": [],
|
|
226
|
+
"ignoredPaths": [],
|
|
227
|
+
"generatedPaths": []
|
|
228
|
+
}
|
|
229
|
+
"#,
|
|
230
|
+
);
|
|
231
|
+
repo.write_file(
|
|
232
|
+
"src/large.js",
|
|
233
|
+
"export function legacy() {\n one();\n two();\n three();\n four();\n}\n",
|
|
234
|
+
);
|
|
235
|
+
repo.write_base_naome_state(json!({ "status": "idle", "activeTask": null }));
|
|
236
|
+
repo.write_naome_json(
|
|
237
|
+
"verification.json",
|
|
238
|
+
json!({
|
|
239
|
+
"schema": "naome.verification.v1",
|
|
240
|
+
"version": 1,
|
|
241
|
+
"status": "ready",
|
|
242
|
+
"checks": [
|
|
243
|
+
{
|
|
244
|
+
"id": "repository-quality-check",
|
|
245
|
+
"command": "naome quality check --changed",
|
|
246
|
+
"cwd": ".",
|
|
247
|
+
"purpose": "Validate changed files against repository quality rules.",
|
|
248
|
+
"cost": "fast",
|
|
249
|
+
"source": "NAOME built-in",
|
|
250
|
+
"evidence": ["src/**"],
|
|
251
|
+
"lastVerified": null
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
"changeTypes": [
|
|
255
|
+
{
|
|
256
|
+
"id": "source",
|
|
257
|
+
"description": "Source changes.",
|
|
258
|
+
"paths": ["src/**"],
|
|
259
|
+
"requiredChecks": ["repository-quality-check"],
|
|
260
|
+
"recommendedChecks": [],
|
|
261
|
+
"humanReview": false
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
"releaseGates": []
|
|
265
|
+
}),
|
|
266
|
+
);
|
|
267
|
+
repo.git(&["add", "."]);
|
|
268
|
+
repo.git(&["commit", "-m", "baseline"]);
|
|
269
|
+
repo.write_file(
|
|
270
|
+
"src/large.js",
|
|
271
|
+
"export function legacy() {\n one();\n two();\n three();\n four();\n five();\n}\n",
|
|
272
|
+
);
|
|
273
|
+
let before_head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
274
|
+
|
|
275
|
+
let route = evaluate_route(
|
|
276
|
+
repo.path(),
|
|
277
|
+
"commit my changes",
|
|
278
|
+
RouteOptions {
|
|
279
|
+
execute: true,
|
|
280
|
+
evaluation: EvaluationOptions::offline(),
|
|
281
|
+
},
|
|
282
|
+
)
|
|
283
|
+
.unwrap();
|
|
284
|
+
|
|
285
|
+
assert_eq!(route.policy_action, "commit_user_diff_with_quality_gate");
|
|
286
|
+
assert!(!route.allowed);
|
|
287
|
+
assert!(!route.mutation_performed);
|
|
288
|
+
assert_eq!(route.executed_actions, vec!["run_user_diff_quality_gate"]);
|
|
289
|
+
assert_eq!(repo.git_stdout(&["rev-parse", "HEAD"]), before_head);
|
|
290
|
+
assert!(route.user_message.contains("repository-quality-check"));
|
|
291
|
+
assert!(route.user_message.contains("file-length"));
|
|
292
|
+
}
|
|
293
|
+
|
|
206
294
|
#[test]
|
|
207
295
|
fn execute_route_commits_product_diff_with_declared_safe_quality_checks() {
|
|
208
296
|
let repo = TestRepo::new("route-product-diff-quality-pass");
|
|
@@ -482,79 +570,6 @@ fn execute_route_refuses_user_diff_commit_when_quality_gate_fails() {
|
|
|
482
570
|
assert!(route.user_message.contains("quality gate failed"));
|
|
483
571
|
}
|
|
484
572
|
|
|
485
|
-
#[test]
|
|
486
|
-
fn execute_route_refuses_user_diff_commit_when_dogfood_health_finds_integrity_mismatch() {
|
|
487
|
-
let repo = TestRepo::from_template("route-user-diff-dogfood-health-integrity");
|
|
488
|
-
repo.init_git();
|
|
489
|
-
repo.write_base_naome_state(json!({ "status": "idle", "activeTask": null }));
|
|
490
|
-
repo.write_dogfood_readme_quality_verification();
|
|
491
|
-
repo.write_file(
|
|
492
|
-
".naome/bin/check-task-state.js",
|
|
493
|
-
"#!/usr/bin/env node\nconsole.log('already tampered');\n",
|
|
494
|
-
);
|
|
495
|
-
repo.git(&["add", "."]);
|
|
496
|
-
repo.git(&["commit", "-m", "baseline"]);
|
|
497
|
-
repo.write_file("README.md", "# Local edit\n");
|
|
498
|
-
let before_head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
499
|
-
|
|
500
|
-
let route = evaluate_route(
|
|
501
|
-
repo.path(),
|
|
502
|
-
"commit my changes",
|
|
503
|
-
RouteOptions {
|
|
504
|
-
execute: true,
|
|
505
|
-
evaluation: EvaluationOptions::offline(),
|
|
506
|
-
},
|
|
507
|
-
)
|
|
508
|
-
.unwrap();
|
|
509
|
-
|
|
510
|
-
assert_eq!(route.policy_action, "commit_user_diff_with_quality_gate");
|
|
511
|
-
assert!(!route.allowed);
|
|
512
|
-
assert!(!route.mutation_performed);
|
|
513
|
-
assert_eq!(route.executed_actions, vec!["run_user_diff_quality_gate"]);
|
|
514
|
-
assert_eq!(repo.git_stdout(&["rev-parse", "HEAD"]), before_head);
|
|
515
|
-
assert!(repo.git_status_short().contains("README.md"));
|
|
516
|
-
assert!(route.user_message.contains("quality gate failed"));
|
|
517
|
-
assert!(route.user_message.contains("integrity mismatch"));
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
#[test]
|
|
521
|
-
fn execute_route_refuses_user_diff_commit_when_task_state_check_finds_template_integrity_mismatch()
|
|
522
|
-
{
|
|
523
|
-
let repo = TestRepo::new("route-user-diff-task-state-integrity");
|
|
524
|
-
repo.init_git();
|
|
525
|
-
repo.write_file("README.md", "# Baseline\n");
|
|
526
|
-
repo.write_base_naome_state(json!({ "status": "idle", "activeTask": null }));
|
|
527
|
-
repo.write_task_state_readme_quality_verification();
|
|
528
|
-
repo.copy_packaged_template_to_route_template_root();
|
|
529
|
-
repo.write_file(
|
|
530
|
-
"packages/naome/templates/naome-root/.naome/bin/check-task-state.js",
|
|
531
|
-
"#!/usr/bin/env node\nconsole.log('already tampered');\n",
|
|
532
|
-
);
|
|
533
|
-
repo.git(&["add", "."]);
|
|
534
|
-
repo.git(&["commit", "-m", "baseline"]);
|
|
535
|
-
repo.write_file("README.md", "# Local edit\n");
|
|
536
|
-
let before_head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
537
|
-
|
|
538
|
-
let route = evaluate_route(
|
|
539
|
-
repo.path(),
|
|
540
|
-
"commit my changes",
|
|
541
|
-
RouteOptions {
|
|
542
|
-
execute: true,
|
|
543
|
-
evaluation: EvaluationOptions::offline(),
|
|
544
|
-
},
|
|
545
|
-
)
|
|
546
|
-
.unwrap();
|
|
547
|
-
|
|
548
|
-
assert_eq!(route.policy_action, "commit_user_diff_with_quality_gate");
|
|
549
|
-
assert!(!route.allowed);
|
|
550
|
-
assert!(!route.mutation_performed);
|
|
551
|
-
assert_eq!(route.executed_actions, vec!["run_user_diff_quality_gate"]);
|
|
552
|
-
assert_eq!(repo.git_stdout(&["rev-parse", "HEAD"]), before_head);
|
|
553
|
-
assert!(repo.git_status_short().contains("README.md"));
|
|
554
|
-
assert!(route.user_message.contains("quality gate failed"));
|
|
555
|
-
assert!(route.user_message.contains("integrity mismatch"));
|
|
556
|
-
}
|
|
557
|
-
|
|
558
573
|
#[test]
|
|
559
574
|
fn execute_route_baselines_harness_refresh_before_dirty_repo_worktree() {
|
|
560
575
|
let repo = TestRepo::new("route-dirty-harness-refresh-worktree");
|
|
@@ -1049,27 +1064,6 @@ impl TestRepo {
|
|
|
1049
1064
|
Self { root }
|
|
1050
1065
|
}
|
|
1051
1066
|
|
|
1052
|
-
fn from_template(name: &str) -> Self {
|
|
1053
|
-
let repo = Self::new(name);
|
|
1054
|
-
let template_root = packaged_template_root();
|
|
1055
|
-
copy_dir(&template_root, repo.path());
|
|
1056
|
-
fs::create_dir_all(repo.path().join(".naome/archive")).unwrap();
|
|
1057
|
-
repo
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
fn copy_packaged_template_to_route_template_root(&self) {
|
|
1061
|
-
copy_dir(&packaged_template_root(), &self.route_template_root());
|
|
1062
|
-
fs::create_dir_all(self.route_template_root().join(".naome/archive")).unwrap();
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
fn route_template_root(&self) -> PathBuf {
|
|
1066
|
-
self.root
|
|
1067
|
-
.join("packages")
|
|
1068
|
-
.join("naome")
|
|
1069
|
-
.join("templates")
|
|
1070
|
-
.join("naome-root")
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
1067
|
fn completed_task_with_diff(name: &str) -> Self {
|
|
1074
1068
|
let repo = Self::new(name);
|
|
1075
1069
|
repo.init_git();
|
|
@@ -1273,74 +1267,6 @@ impl TestRepo {
|
|
|
1273
1267
|
);
|
|
1274
1268
|
}
|
|
1275
1269
|
|
|
1276
|
-
fn write_dogfood_readme_quality_verification(&self) {
|
|
1277
|
-
self.write_naome_json(
|
|
1278
|
-
"verification.json",
|
|
1279
|
-
json!({
|
|
1280
|
-
"schema": "naome.verification.v1",
|
|
1281
|
-
"version": 1,
|
|
1282
|
-
"status": "ready",
|
|
1283
|
-
"checks": [
|
|
1284
|
-
{
|
|
1285
|
-
"id": "dogfood-health",
|
|
1286
|
-
"command": "npm run dogfood:health",
|
|
1287
|
-
"cwd": ".",
|
|
1288
|
-
"purpose": "Validate installed harness integrity.",
|
|
1289
|
-
"cost": "fast",
|
|
1290
|
-
"source": "test",
|
|
1291
|
-
"evidence": [".naome/bin/check-task-state.js"],
|
|
1292
|
-
"lastVerified": null
|
|
1293
|
-
}
|
|
1294
|
-
],
|
|
1295
|
-
"changeTypes": [
|
|
1296
|
-
{
|
|
1297
|
-
"id": "installed-self-hosted-harness",
|
|
1298
|
-
"description": "Installed harness files.",
|
|
1299
|
-
"paths": ["README.md"],
|
|
1300
|
-
"requiredChecks": ["dogfood-health"],
|
|
1301
|
-
"recommendedChecks": [],
|
|
1302
|
-
"humanReview": false
|
|
1303
|
-
}
|
|
1304
|
-
],
|
|
1305
|
-
"releaseGates": []
|
|
1306
|
-
}),
|
|
1307
|
-
);
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
fn write_task_state_readme_quality_verification(&self) {
|
|
1311
|
-
self.write_naome_json(
|
|
1312
|
-
"verification.json",
|
|
1313
|
-
json!({
|
|
1314
|
-
"schema": "naome.verification.v1",
|
|
1315
|
-
"version": 1,
|
|
1316
|
-
"status": "ready",
|
|
1317
|
-
"checks": [
|
|
1318
|
-
{
|
|
1319
|
-
"id": "task-state-check",
|
|
1320
|
-
"command": "npm run check:task-state",
|
|
1321
|
-
"cwd": ".",
|
|
1322
|
-
"purpose": "Validate template task-state and harness integrity.",
|
|
1323
|
-
"cost": "fast",
|
|
1324
|
-
"source": "test",
|
|
1325
|
-
"evidence": ["packages/naome/templates/naome-root/.naome/bin/check-task-state.js"],
|
|
1326
|
-
"lastVerified": null
|
|
1327
|
-
}
|
|
1328
|
-
],
|
|
1329
|
-
"changeTypes": [
|
|
1330
|
-
{
|
|
1331
|
-
"id": "installed-self-hosted-harness",
|
|
1332
|
-
"description": "Installed harness files.",
|
|
1333
|
-
"paths": ["README.md"],
|
|
1334
|
-
"requiredChecks": ["task-state-check"],
|
|
1335
|
-
"recommendedChecks": [],
|
|
1336
|
-
"humanReview": false
|
|
1337
|
-
}
|
|
1338
|
-
],
|
|
1339
|
-
"releaseGates": []
|
|
1340
|
-
}),
|
|
1341
|
-
);
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
1270
|
fn write_naome_json(&self, file_name: &str, value: serde_json::Value) {
|
|
1345
1271
|
let path = self.root.join(".naome").join(file_name);
|
|
1346
1272
|
fs::write(
|
|
@@ -1404,32 +1330,6 @@ impl TestRepo {
|
|
|
1404
1330
|
}
|
|
1405
1331
|
}
|
|
1406
1332
|
|
|
1407
|
-
fn packaged_template_root() -> PathBuf {
|
|
1408
|
-
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
1409
|
-
.join("..")
|
|
1410
|
-
.join("..")
|
|
1411
|
-
.join("templates")
|
|
1412
|
-
.join("naome-root")
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
fn copy_dir(from: &Path, to: &Path) {
|
|
1416
|
-
fs::create_dir_all(to).unwrap();
|
|
1417
|
-
for entry in fs::read_dir(from).unwrap() {
|
|
1418
|
-
let entry = entry.unwrap();
|
|
1419
|
-
let from_path = entry.path();
|
|
1420
|
-
let to_path = to.join(entry.file_name());
|
|
1421
|
-
let file_type = entry.file_type().unwrap();
|
|
1422
|
-
if file_type.is_dir() {
|
|
1423
|
-
copy_dir(&from_path, &to_path);
|
|
1424
|
-
} else if file_type.is_file() {
|
|
1425
|
-
if let Some(parent) = to_path.parent() {
|
|
1426
|
-
fs::create_dir_all(parent).unwrap();
|
|
1427
|
-
}
|
|
1428
|
-
fs::copy(&from_path, &to_path).unwrap();
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
1333
|
fn completed_task_state(admission_head: &str) -> serde_json::Value {
|
|
1434
1334
|
json!({
|
|
1435
1335
|
"schema": "naome.task-state.v1",
|
|
@@ -32,9 +32,12 @@ const PROJECT_OWNED_PATHS: &[&str] = &[
|
|
|
32
32
|
".naome/task-state.json",
|
|
33
33
|
".naome/upgrade-state.json",
|
|
34
34
|
".naome/verification.json",
|
|
35
|
+
".naome/repository-quality.json",
|
|
36
|
+
".naome/repository-quality-baseline.json",
|
|
35
37
|
"docs/naome/architecture.md",
|
|
36
38
|
"docs/naome/decisions.md",
|
|
37
39
|
"docs/naome/repo-profile.md",
|
|
40
|
+
"docs/naome/repository-quality.md",
|
|
38
41
|
"docs/naome/security.md",
|
|
39
42
|
"docs/naome/testing.md",
|
|
40
43
|
];
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
mod task_state_compact_support;
|
|
2
|
+
|
|
3
|
+
use naome_core::{evaluate_route, EvaluationOptions, RouteOptions, TaskStateMode};
|
|
4
|
+
use serde_json::{json, Value};
|
|
5
|
+
use task_state_compact_support::{
|
|
6
|
+
compact_state, large_compact_state, large_expanded_state, legacy_state, MiniRepo,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
#[test]
|
|
10
|
+
fn legacy_v1_proof_results_remain_valid() {
|
|
11
|
+
let repo = MiniRepo::new();
|
|
12
|
+
let head = repo.seed();
|
|
13
|
+
repo.change_readme();
|
|
14
|
+
repo.write_task_state(legacy_state(&head));
|
|
15
|
+
|
|
16
|
+
let report = repo.validate(TaskStateMode::State);
|
|
17
|
+
|
|
18
|
+
assert_eq!(report.errors, Vec::<String>::new());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[test]
|
|
22
|
+
fn compact_path_sets_and_batches_cover_completion_commit_and_route() {
|
|
23
|
+
let repo = MiniRepo::new();
|
|
24
|
+
let head = repo.seed();
|
|
25
|
+
repo.change_readme();
|
|
26
|
+
repo.write_task_state(compact_state(&head));
|
|
27
|
+
|
|
28
|
+
let completion = repo.validate(TaskStateMode::State);
|
|
29
|
+
assert_eq!(completion.errors, Vec::<String>::new());
|
|
30
|
+
|
|
31
|
+
let route = evaluate_route(
|
|
32
|
+
repo.path(),
|
|
33
|
+
"new task",
|
|
34
|
+
RouteOptions {
|
|
35
|
+
execute: false,
|
|
36
|
+
evaluation: EvaluationOptions::offline(),
|
|
37
|
+
},
|
|
38
|
+
)
|
|
39
|
+
.unwrap();
|
|
40
|
+
assert_eq!(
|
|
41
|
+
route.policy_action,
|
|
42
|
+
"auto_commit_completed_task_then_create_new_task"
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
repo.git(["add", "README.md", ".naome/task-state.json"]);
|
|
46
|
+
let commit_gate = repo.validate(TaskStateMode::CommitGate);
|
|
47
|
+
assert_eq!(commit_gate.errors, Vec::<String>::new());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[test]
|
|
51
|
+
fn compact_missing_required_proof_is_reported() {
|
|
52
|
+
let repo = MiniRepo::new();
|
|
53
|
+
let head = repo.seed();
|
|
54
|
+
repo.change_readme();
|
|
55
|
+
let mut state = compact_state(&head);
|
|
56
|
+
state["activeTask"]["proofBatches"][0]["proofs"] = json!([
|
|
57
|
+
{
|
|
58
|
+
"checkId": "alpha",
|
|
59
|
+
"exitCode": 0
|
|
60
|
+
}
|
|
61
|
+
]);
|
|
62
|
+
repo.write_task_state(state);
|
|
63
|
+
|
|
64
|
+
let report = repo.validate(TaskStateMode::State);
|
|
65
|
+
|
|
66
|
+
assert!(
|
|
67
|
+
report
|
|
68
|
+
.errors
|
|
69
|
+
.iter()
|
|
70
|
+
.any(|error| error.contains("missing proof result: beta")),
|
|
71
|
+
"{:?}",
|
|
72
|
+
report.errors
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[test]
|
|
77
|
+
fn compact_missing_evidence_is_reported() {
|
|
78
|
+
let repo = MiniRepo::new();
|
|
79
|
+
let head = repo.seed();
|
|
80
|
+
repo.change_readme();
|
|
81
|
+
let mut state = compact_state(&head);
|
|
82
|
+
state["activeTask"]["proofBatches"][0]["evidencePathSet"] = Value::Null;
|
|
83
|
+
state["activeTask"]["proofBatches"][0]["proofs"][0]["evidencePathSet"] = Value::Null;
|
|
84
|
+
repo.write_task_state(state);
|
|
85
|
+
|
|
86
|
+
let report = repo.validate(TaskStateMode::State);
|
|
87
|
+
|
|
88
|
+
assert!(
|
|
89
|
+
report
|
|
90
|
+
.errors
|
|
91
|
+
.iter()
|
|
92
|
+
.any(|error| error.contains("evidence must be an evidence array or path-set reference")),
|
|
93
|
+
"{:?}",
|
|
94
|
+
report.errors
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#[test]
|
|
99
|
+
fn compact_writer_payload_is_smaller_than_expanded_equivalent() {
|
|
100
|
+
let compact = large_compact_state("abcdef");
|
|
101
|
+
let expanded = large_expanded_state("abcdef");
|
|
102
|
+
|
|
103
|
+
let compact_len = serde_json::to_string(&compact).unwrap().len();
|
|
104
|
+
let expanded_len = serde_json::to_string(&expanded).unwrap().len();
|
|
105
|
+
|
|
106
|
+
assert!(
|
|
107
|
+
compact_len * 100 / expanded_len < 75,
|
|
108
|
+
"compact={compact_len} expanded={expanded_len}"
|
|
109
|
+
);
|
|
110
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
use std::fs;
|
|
2
|
+
use std::path::{Path, PathBuf};
|
|
3
|
+
use std::process::Command;
|
|
4
|
+
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
5
|
+
use std::time::{SystemTime, UNIX_EPOCH};
|
|
6
|
+
|
|
7
|
+
use naome_core::{validate_task_state, TaskStateMode, TaskStateOptions};
|
|
8
|
+
use serde_json::{json, Value};
|
|
9
|
+
|
|
10
|
+
static REPO_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
|
11
|
+
|
|
12
|
+
pub struct MiniRepo {
|
|
13
|
+
root: PathBuf,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl MiniRepo {
|
|
17
|
+
pub fn new() -> Self {
|
|
18
|
+
let stamp = SystemTime::now()
|
|
19
|
+
.duration_since(UNIX_EPOCH)
|
|
20
|
+
.unwrap()
|
|
21
|
+
.as_nanos();
|
|
22
|
+
let counter = REPO_COUNTER.fetch_add(1, Ordering::SeqCst);
|
|
23
|
+
let root = std::env::temp_dir().join(format!("naome-compact-proof-{stamp}-{counter}"));
|
|
24
|
+
fs::create_dir_all(root.join(".naome")).unwrap();
|
|
25
|
+
let repo = Self { root };
|
|
26
|
+
repo.git(["init"]);
|
|
27
|
+
repo.git(["config", "user.email", "compact@example.test"]);
|
|
28
|
+
repo.git(["config", "user.name", "Compact Proof"]);
|
|
29
|
+
repo
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn path(&self) -> &Path {
|
|
33
|
+
&self.root
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn seed(&self) -> String {
|
|
37
|
+
fs::write(self.root.join(".naomeignore"), "").unwrap();
|
|
38
|
+
fs::write(self.root.join("README.md"), "before\n").unwrap();
|
|
39
|
+
fs::write(
|
|
40
|
+
self.root.join(".naome/init-state.json"),
|
|
41
|
+
json_text(json!({
|
|
42
|
+
"schema": "naome.init-state.v1",
|
|
43
|
+
"version": 1,
|
|
44
|
+
"initialized": true,
|
|
45
|
+
"intakeStatus": "complete"
|
|
46
|
+
})),
|
|
47
|
+
)
|
|
48
|
+
.unwrap();
|
|
49
|
+
fs::write(
|
|
50
|
+
self.root.join(".naome/upgrade-state.json"),
|
|
51
|
+
json_text(json!({
|
|
52
|
+
"schema": "naome.upgrade-state.v1",
|
|
53
|
+
"version": 1,
|
|
54
|
+
"status": "complete",
|
|
55
|
+
"fromVersion": "1.1.2",
|
|
56
|
+
"toVersion": "1.2.0",
|
|
57
|
+
"pending": [],
|
|
58
|
+
"completed": []
|
|
59
|
+
})),
|
|
60
|
+
)
|
|
61
|
+
.unwrap();
|
|
62
|
+
fs::write(
|
|
63
|
+
self.root.join(".naome/verification.json"),
|
|
64
|
+
json_text(verification_contract()),
|
|
65
|
+
)
|
|
66
|
+
.unwrap();
|
|
67
|
+
self.git(["add", "."]);
|
|
68
|
+
self.git(["commit", "-m", "seed"]);
|
|
69
|
+
self.git_stdout(["rev-parse", "HEAD"])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn change_readme(&self) {
|
|
73
|
+
fs::write(self.root.join("README.md"), "after\n").unwrap();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
pub fn write_task_state(&self, state: Value) {
|
|
77
|
+
fs::write(self.root.join(".naome/task-state.json"), json_text(state)).unwrap();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn validate(&self, mode: TaskStateMode) -> naome_core::TaskStateReport {
|
|
81
|
+
validate_task_state(
|
|
82
|
+
&self.root,
|
|
83
|
+
TaskStateOptions {
|
|
84
|
+
mode,
|
|
85
|
+
harness_health: None,
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
.unwrap()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub fn git<const N: usize>(&self, args: [&str; N]) {
|
|
92
|
+
let output = Command::new("git")
|
|
93
|
+
.args(args)
|
|
94
|
+
.current_dir(&self.root)
|
|
95
|
+
.output()
|
|
96
|
+
.unwrap();
|
|
97
|
+
assert!(
|
|
98
|
+
output.status.success(),
|
|
99
|
+
"{}",
|
|
100
|
+
String::from_utf8_lossy(&output.stderr)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fn git_stdout<const N: usize>(&self, args: [&str; N]) -> String {
|
|
105
|
+
let output = Command::new("git")
|
|
106
|
+
.args(args)
|
|
107
|
+
.current_dir(&self.root)
|
|
108
|
+
.output()
|
|
109
|
+
.unwrap();
|
|
110
|
+
assert!(output.status.success());
|
|
111
|
+
String::from_utf8_lossy(&output.stdout).trim().to_string()
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fn verification_contract() -> Value {
|
|
116
|
+
json!({
|
|
117
|
+
"schema": "naome.verification.v1",
|
|
118
|
+
"version": 1,
|
|
119
|
+
"status": "ready",
|
|
120
|
+
"checks": [
|
|
121
|
+
{ "id": "alpha", "command": "npm run alpha", "cwd": ".", "evidence": ["README.md"] },
|
|
122
|
+
{ "id": "beta", "command": "npm run beta", "cwd": ".", "evidence": ["README.md"] }
|
|
123
|
+
],
|
|
124
|
+
"changeTypes": []
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn json_text(value: Value) -> String {
|
|
129
|
+
format!("{}\n", serde_json::to_string_pretty(&value).unwrap())
|
|
130
|
+
}
|