diff --git a/crates/cyber-server/tests/location_activity.rs b/crates/cyber-server/tests/location_activity.rs index 334bb477..4e2f38d5 100644 --- a/crates/cyber-server/tests/location_activity.rs +++ b/crates/cyber-server/tests/location_activity.rs @@ -3,7 +3,7 @@ mod support; use cyber_server::runtime::*; use futures::future::BoxFuture; use std::sync::{ - Arc, + Arc, Mutex, atomic::{AtomicBool, AtomicUsize, Ordering}, }; use std::time::Duration; @@ -17,6 +17,9 @@ struct Activity { deny: AtomicBool, shell_unresponsive: AtomicBool, claim_unresponsive: AtomicBool, + preserve_binding: AtomicBool, + fail_settlement: AtomicBool, + cwd_hooks: Mutex>, } struct Guard { @@ -26,6 +29,9 @@ struct Guard { impl LocationGuard for Guard { fn settle(mut self: Box) -> Result<(), String> { + if self.activity.fail_settlement.swap(false, Ordering::SeqCst) { + return Err("previous Location settlement unacknowledged".into()); + } self.settled = true; Ok(()) } @@ -58,10 +64,15 @@ impl ToolHost for Host { { return Err("checkout admission refused".into()); } - assert!(creating || info.worktree_id.as_deref() == Some("wt_test")); + let preserve_binding = self.activity.preserve_binding.load(Ordering::SeqCst); + assert!(preserve_binding || creating || info.worktree_id.as_deref() == Some("wt_test")); self.activity.active.fetch_add(1, Ordering::SeqCst); - let lease = LocationLease::managed( - "wt_test".into(), + let lease = LocationLease::guarded( + if preserve_binding { + info.worktree_id.clone() + } else { + Some("wt_test".into()) + }, Box::new(Guard { activity: Arc::clone(&self.activity), settled: false, @@ -75,6 +86,17 @@ impl ToolHost for Host { }) } + fn lifecycle_hooks( + &self, + event: LifecycleHook, + _: CancellationToken, + ) -> BoxFuture<'_, Result> { + if event.kind == "CwdChanged" { + self.activity.cwd_hooks.lock().unwrap().push(event); + } + Box::pin(async { Ok(LifecycleVerdict::default()) }) + } + fn definitions(&self, turn: &TurnContext) -> Vec { self.tools.definitions(turn) } @@ -452,3 +474,126 @@ fn retained_location_proof_preserves_acknowledged_guard_until_disposal() { assert!(!activity.unknown.load(Ordering::SeqCst)); drop(LocationLease::unmanaged().settle_retained().unwrap()); } + +#[tokio::test] +async fn cwd_changed_requires_acknowledged_previous_location_settlement() { + use cyber_core::worktrees::Managed; + + for unacknowledged in [false, true] { + let h = Harness::new(Setup { + scripts: vec![( + "test/main", + vec![tools(&[("lease_call", "read", "{}")]), text("done")], + )], + ..Default::default() + }); + h.tools.set("read", Behavior::Gated); + let (runtime, activity) = owned_runtime(&h); + activity.preserve_binding.store(true, Ordering::SeqCst); + let info = create(&runtime, &h, "test/main").await; + assert!(info.worktree_id.is_none()); + let destination = h.dir.path().join("destination"); + std::fs::create_dir(&destination).unwrap(); + let managed = Managed { + id: "wt_test".into(), + name: "destination".into(), + path: destination.clone(), + branch: "cyber/destination".into(), + base: "main".into(), + common_dir: h.repo.join(".git"), + ready: true, + included: vec![], + }; + runtime + .admit(&info.id, Admission::text("run", Delivery::Queue)) + .await + .unwrap(); + tokio::time::timeout(Duration::from_secs(5), h.tools.started.notified()) + .await + .unwrap(); + assert_eq!(activity.active.load(Ordering::SeqCst), 1); + activity + .fail_settlement + .store(unacknowledged, Ordering::SeqCst); + let result = tokio::time::timeout( + Duration::from_secs(5), + runtime.enter_worktree( + &info.id, + "lease_call", + &managed, + false, + CancellationToken::new(), + ), + ) + .await + .unwrap(); + // The path is committed before settlement of the previous admission. An + // uncertain acknowledgement must not turn that record into a success hook. + let state = runtime.state(&info.id).await.unwrap(); + assert_eq!(state.info.directory, destination.display().to_string()); + assert_eq!(state.info.worktree_id.as_deref(), Some("wt_test")); + let events = h + .store + .read_events(&info.id, -1, cyber_store::MAX_PAGE_LIMIT) + .unwrap() + .events; + let entered: Vec<_> = events + .iter() + .filter(|event| event.kind == "session.worktree.entered.1") + .collect(); + assert_eq!(entered.len(), 1); + assert!(!activity.fail_settlement.load(Ordering::SeqCst)); + assert_eq!(activity.unknown.load(Ordering::SeqCst), unacknowledged); + { + let hooks = activity.cwd_hooks.lock().unwrap(); + if unacknowledged { + assert!( + hooks.is_empty(), + "an unacknowledged transition emitted CwdChanged" + ); + assert!( + result + .unwrap_err() + .to_string() + .contains("settlement unacknowledged") + ); + } else { + result.unwrap(); + assert_eq!(hooks.len(), 1); + assert_eq!(hooks[0].directory, state.info.directory); + assert_eq!(hooks[0].fields["transition_id"], entered[0].id); + assert_eq!(hooks[0].fields["transition_sequence"], entered[0].seq); + } + } + if unacknowledged { + let error = runtime.exit_idle_worktree(&info.id).await.unwrap_err(); + assert!(error.to_string().contains("Location outcome unknown")); + let error = runtime + .check_enterable(&info.id, "lease_call") + .await + .unwrap_err(); + assert!(error.to_string().contains("Location outcome unknown")); + assert_eq!( + h.store + .read_events(&info.id, -1, cyber_store::MAX_PAGE_LIMIT) + .unwrap() + .events + .len(), + events.len() + ); + assert!(activity.cwd_hooks.lock().unwrap().is_empty()); + } + h.tools.release.notify_one(); + tokio::time::timeout(Duration::from_secs(5), runtime.wait_idle(&info.id)) + .await + .unwrap(); + tokio::time::timeout(Duration::from_secs(5), runtime.shutdown()) + .await + .unwrap(); + assert_eq!(activity.active.load(Ordering::SeqCst), 0); + assert_eq!( + activity.cwd_hooks.lock().unwrap().len(), + usize::from(!unacknowledged) + ); + } +} diff --git a/docs/goal-delivery.md b/docs/goal-delivery.md index 5638603d..f1575cac 100644 --- a/docs/goal-delivery.md +++ b/docs/goal-delivery.md @@ -64,12 +64,22 @@ native result witness and deterministic missing-guard regression passed Intel and arm64; that accepts the verifier correction rather than production native admission or the historical unknown race cause. -Continue the first workstream on the single follow-up branch -`test/file-observer-windows-alias-acceptance`: native Windows retarget acceptance, -retained source-bound native evidence, and the DirectoryAdded prerequisite design -for review. Keep native activation and Linux dependency changes behind their -existing review/acceptance gates. The Setup marker choices and DirectoryAdded -proposal also require their recorded review before implementation. +PR #85 merged at `5d5826b7` after all 19 checks passed. It accepts bounded +FileChanged task 5.2 with verified native Windows retarget coverage and a reviewed +main composition; see the +[acceptance audit](../openspec/changes/complete-plugin-hook-runtime/file-observation-acceptance.md). +PR #88 merged at `9cbbf08b` after all 18 checks passed, including all five +CwdChanged lifecycle cases on Windows. + +Continue the first workstream in PR #89 on `test/cwd-unknown-settlement`: +unacknowledged Location settlement must not emit successful CwdChanged, and the +FileChanged acceptance record is reconciled against accepted main. The regression +uses the actual runtime/Store with a simulated lease owner; its local positive +suite and behavioral negative control pass, while current-head hosted acceptance +is required. No production native activation or protocol implementation is +claimed. Keep native activation and Linux dependency changes behind their +existing review/acceptance gates. The complete Setup marker/migration choices +and DirectoryAdded proposal also need their recorded review before implementation. Native confinement foundations and regressions exist, but production enforcement and the remaining plugin/hook scope are incomplete. The diff --git a/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-b08a1f5c.json b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-b08a1f5c.json new file mode 100644 index 00000000..33ad20d1 --- /dev/null +++ b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-b08a1f5c.json @@ -0,0 +1,273 @@ +{ + "head": "b08a1f5c12491451ca8c9f011aab8427010039c3", + "platforms": { + "linux": { + "tested_merge": "151144ea4f94f53866710ff9a25d74d64ca6a605", + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546533/job/124599977235", + "suites_passed_ignored": [ + [ + "13", + "0" + ], + [ + "1", + "0" + ], + [ + "58", + "1" + ], + [ + "7", + "1" + ], + [ + "17", + "0" + ], + [ + "24", + "0" + ], + [ + "2", + "0" + ], + [ + "30", + "0" + ] + ], + "log_sha256": "963b3b1bfba2f77590c764b1968269c81d1087714967b0fcf09c77062923497e" + }, + "macos": { + "tested_merge": "151144ea4f94f53866710ff9a25d74d64ca6a605", + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546533/job/124599977368", + "suites_passed_ignored": [ + [ + "13", + "0" + ], + [ + "1", + "0" + ], + [ + "58", + "1" + ], + [ + "6", + "1" + ], + [ + "17", + "0" + ], + [ + "24", + "0" + ], + [ + "2", + "0" + ], + [ + "30", + "0" + ] + ], + "log_sha256": "172795fc0d39673b14dd82c8ccc445ed1a34160c50e67783d56655783ea8fce4" + }, + "windows": { + "tested_merge": "151144ea4f94f53866710ff9a25d74d64ca6a605", + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546533/job/124599976970", + "suites_passed_ignored": [ + [ + "13", + "0" + ], + [ + "1", + "0" + ], + [ + "49", + "0" + ], + [ + "2", + "0" + ], + [ + "17", + "0" + ], + [ + "24", + "0" + ], + [ + "2", + "0" + ], + [ + "29", + "0" + ] + ], + "log_sha256": "daf65a2301f6d17a7159f40e78f7581eb8dab028adbaf7525f1df567ca221b10" + } + }, + "tested_tree": "4ead043efe3fd5908a55a134544cdd1efaa139ec", + "head_tree_equal": true, + "requirements_checked": { + "builtin_write_and_edit_produce_observations_without_language_services": [ + "linux", + "macos", + "windows" + ], + "directory_registration_limit_is_visible_and_reconciliation_covers_its_tail": [ + "linux", + "macos", + "windows" + ], + "hard_link_scope_allows_owned_aliases_and_suppresses_private_state_aliases": [ + "linux", + "macos", + "windows" + ], + "hook_writes_stop_at_the_durable_feedback_limit_after_quiet_time": [ + "linux", + "macos", + "windows" + ], + "location_limit_is_visible_without_disabling_other_location_observations": [ + "linux", + "macos", + "windows" + ], + "long_path_inventory_publishes_a_partial_baseline_and_keeps_existing_files_live": [ + "linux", + "macos", + "windows" + ], + "native_foreground_and_background_shell_writes_are_observed_after_the_turn": [ + "linux", + "macos", + "windows" + ], + "native_formatter_settlement_produces_a_file_observation": [ + "linux", + "macos", + "windows" + ], + "native_owner_delivers_external_edits_rename_removal_to_shared_sessions_and_joins": [ + "linux", + "macos", + "windows" + ], + "native_owner_feedback_renews_only_for_new_committed_user_input": [ + "linux", + "macos", + "windows" + ], + "readmission_reuses_one_pending_replacement_until_previous_owner_settles": [ + "linux", + "macos", + "windows" + ], + "session_limit_is_visible_and_released_membership_admits_a_waiting_session": [ + "linux", + "macos", + "windows" + ], + "symlink_retarget_loses_old_delivery_and_user_input_admits_the_new_physical_scope": [ + "linux", + "macos", + "windows" + ], + "unused_user_acknowledgement_cannot_follow_a_retargeted_alias": [ + "linux", + "macos", + "windows" + ] + }, + "broad": { + "linux": { + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546523/job/124600042654", + "log_sha256": "fbb5e60dc594c1ebdb2790c44aadb3be9aecbf94cbda3a21b4dbbdd77be7e5b5", + "summaries": [ + "Summary [ 859.487s] 5504 tests run: 5504 passed (1 slow), 21 skipped" + ], + "warnings": [] + }, + "macos": { + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546523/job/124600042618", + "log_sha256": "604c1d958d51a133fd2625345953a4b2260b76604f903f68f8ac4d6df095f1af", + "summaries": [ + "Summary [1333.486s] 5504 tests run: 5504 passed (2 slow), 23 skipped" + ], + "warnings": [] + }, + "windows": { + "job_url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41222546523/job/124600042571", + "log_sha256": "5055d9012c5003fbc0d8a3b557c344d26439e97386702d4ce7af251156f46af2", + "summaries": [ + "Summary [1042.035s] 3775 tests run: 3775 passed (1 leaky), 648 skipped", + "Summary [ 0.030s] 4 tests run: 4 passed, 387 skipped", + "Summary [ 0.094s] 9 tests run: 9 passed, 0 skipped", + "Summary [ 1.905s] 18 tests run: 18 passed, 0 skipped" + ], + "warnings": [ + "LEAK [ 20.250s] ( 520/3775) cyber-cli::messages_cli an_exec_session_refuses_messages_unless_it_accepts_them" + ] + } + }, + "checks_passed": 19, + "accepted_merge": "5d5826b72d41d6a833b523237bdbbd85ac51d31a", + "accepted_tree": "ad445cb227b0a7d1cc8593cc25d7cd3efc4b9e3f", + "limits": "Windows selected suite and Unix subprocess-helper ignores are explicit; leaked-process cause unverified; this is FileChanged acceptance, not plugin confinement or complete producer acceptance.", + "additional_component_contracts": { + "queue_loss_is_reported_even_without_another_successful_callback": [ + "linux", + "macos", + "windows" + ], + "coalesced_tool_and_native_hints_stay_bounded_and_signal_lost_names": [ + "linux", + "macos", + "windows" + ], + "registrations_are_bounded_and_partial_scans_preserve_existing_coverage": [ + "linux", + "macos", + "windows" + ], + "removing_membership_cancels_held_delivery_without_stopping_other_members": [ + "linux", + "macos", + "windows" + ], + "protected_subtrees_are_excluded_without_reading_contents": [ + "linux", + "macos", + "windows" + ], + "unknown_file_handler_delivery_remains_consumed_without_reexecution": [ + "linux", + "macos", + "windows" + ], + "readmitting_membership_does_not_revive_a_held_batch": [ + "linux", + "macos", + "windows" + ], + "incomplete_scan_prioritizes_existing_updates_and_preserves_unknown_preimages": [ + "linux", + "macos", + "windows" + ] + } +} diff --git a/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-ecce8b38.json b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-ecce8b38.json new file mode 100644 index 00000000..46af4b5f --- /dev/null +++ b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-ecce8b38.json @@ -0,0 +1,157 @@ +{ + "head": "ecce8b381c91e22f25b43f9a1cf6f8761c991cce", + "scope": "Exact PR85 native platform acceptance; all relevant test/source bytes match the tested merge tree. Broader PR checks and merge review remain separate. This does not establish plugin confinement or Setup completion.", + "suite_order": [ + "core records", + "core envelope", + "native/scanner/owner", + "runtime roots", + "Store/runtime", + "HTTP callbacks", + "AppHost forwarding", + "MCP" + ], + "jobs": [ + { + "platform": "windows", + "job_id": 124555532039, + "url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41207519078/job/124555532039", + "tested_merge": "8de13b5445509a214d4f70f1082728a65b202df1", + "tree": "119568e94fdef8498056b4448a17980c440f483f", + "verified_tree_matches_head": true, + "log_sha256": "90f80e014e4eac8bd08b360299261cccc14776a91325a2b961362d3b24e2a244", + "named_retarget_cases_executed": [ + "unused_user_acknowledgement_cannot_follow_a_retargeted_alias", + "symlink_retarget_loses_old_delivery_and_user_input_admits_the_new_physical_scope" + ], + "suite_counts": [ + { + "passed": 13, + "ignored": 0 + }, + { + "passed": 1, + "ignored": 0 + }, + { + "passed": 49, + "ignored": 0 + }, + { + "passed": 2, + "ignored": 0 + }, + { + "passed": 17, + "ignored": 0 + }, + { + "passed": 24, + "ignored": 0 + }, + { + "passed": 2, + "ignored": 0 + }, + { + "passed": 29, + "ignored": 0 + } + ] + }, + { + "platform": "linux", + "job_id": 124555531908, + "url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41207519078/job/124555531908", + "tested_merge": "8de13b5445509a214d4f70f1082728a65b202df1", + "tree": "119568e94fdef8498056b4448a17980c440f483f", + "verified_tree_matches_head": true, + "log_sha256": "b8d397f46a5c00ecbe9a619497042161b360ce5ca5a743f187e6fc147afc9bd3", + "named_retarget_cases_executed": [ + "unused_user_acknowledgement_cannot_follow_a_retargeted_alias", + "symlink_retarget_loses_old_delivery_and_user_input_admits_the_new_physical_scope" + ], + "suite_counts": [ + { + "passed": 13, + "ignored": 0 + }, + { + "passed": 1, + "ignored": 0 + }, + { + "passed": 58, + "ignored": 1 + }, + { + "passed": 7, + "ignored": 1 + }, + { + "passed": 17, + "ignored": 0 + }, + { + "passed": 24, + "ignored": 0 + }, + { + "passed": 2, + "ignored": 0 + }, + { + "passed": 30, + "ignored": 0 + } + ] + }, + { + "platform": "macos", + "job_id": 124555532069, + "url": "https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41207519078/job/124555532069", + "tested_merge": "8de13b5445509a214d4f70f1082728a65b202df1", + "tree": "119568e94fdef8498056b4448a17980c440f483f", + "verified_tree_matches_head": true, + "log_sha256": "2e9854e6f144ecbb6393cfe015c1e77ba8b22efd2bb0a0890c4874ed286daf6d", + "named_retarget_cases_executed": [ + "unused_user_acknowledgement_cannot_follow_a_retargeted_alias", + "symlink_retarget_loses_old_delivery_and_user_input_admits_the_new_physical_scope" + ], + "suite_counts": [ + { + "passed": 13, + "ignored": 0 + }, + { + "passed": 1, + "ignored": 0 + }, + { + "passed": 58, + "ignored": 1 + }, + { + "passed": 6, + "ignored": 1 + }, + { + "passed": 17, + "ignored": 0 + }, + { + "passed": 24, + "ignored": 0 + }, + { + "passed": 2, + "ignored": 0 + }, + { + "passed": 30, + "ignored": 0 + } + ] + } + ] +} diff --git a/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post86-composition.json b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post86-composition.json new file mode 100644 index 00000000..0e939a16 --- /dev/null +++ b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post86-composition.json @@ -0,0 +1,20 @@ +{ + "tested_head": "ecce8b381c91e22f25b43f9a1cf6f8761c991cce", + "tested_merge": "8de13b5445509a214d4f70f1082728a65b202df1", + "tested_tree": "119568e94fdef8498056b4448a17980c440f483f", + "current_base": "92a3240dafdf8aac37c7bd647f36b551453deacb", + "prospective_tree": "d8b104a7d4573f2ebcd33e2333d00dbf95d6a5d4", + "differences_from_tested_tree": [ + "openspec/changes/complete-plugin-hook-runtime/setup-design.md" + ], + "code_build_test_workflow_inputs_identical": true, + "ci_tested_prospective_tree": false, + "note": "Only the independently reviewed Setup design document differs. Combined strict OpenSpec/lint validation is recorded separately; original CI remains evidence for identical executable/test inputs.", + "combined_local_validation": { + "openspec_passed": 114, + "openspec_failed": 0, + "spec_lint_errors": 0, + "spec_lint_warnings": 25, + "whitespace_passed": true + } +} diff --git a/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post88-composition.json b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post88-composition.json new file mode 100644 index 00000000..db8859c1 --- /dev/null +++ b/openspec/changes/complete-plugin-hook-runtime/evidence/file-observation-post88-composition.json @@ -0,0 +1,58 @@ +{ + "head": "b08a1f5c12491451ca8c9f011aab8427010039c3", + "base": "9cbbf08b3382622625335210360928a729a47e33", + "tree": "ad445cb227b0a7d1cc8593cc25d7cd3efc4b9e3f", + "changes_from_tested_head": [ + "crates/cyber-tools/tests/worktree_setup.rs", + "openspec/changes/complete-plugin-hook-runtime/tasks.md" + ], + "binding": "FileChanged test files and nextest configuration equal tested PR85 head; CwdChanged test file equals accepted PR88 main; no production source changes.", + "checks": [ + { + "command": [ + "cargo", + "fmt", + "--all", + "--check" + ], + "exit_code": 0, + "summary": [] + }, + { + "command": [ + "git", + "diff", + "--cached", + "--check" + ], + "exit_code": 0, + "summary": [] + }, + { + "command": [ + "node", + "/Users/edvane/.npm/_npx/0aaef5be8686a8bb/node_modules/@fission-ai/openspec/bin/openspec.js", + "validate", + "--all", + "--strict" + ], + "exit_code": 0, + "summary": [ + "Totals: 114 passed, 0 failed (114 items)" + ] + }, + { + "command": [ + "python3", + "scripts/spec_lint.py" + ], + "exit_code": 0, + "summary": [ + "0 errors, 25 warnings" + ] + } + ], + "accepted_merge": "5d5826b72d41d6a833b523237bdbbd85ac51d31a", + "accepted_tree": "ad445cb227b0a7d1cc8593cc25d7cd3efc4b9e3f", + "accepted_tree_matches": true +} diff --git a/openspec/changes/complete-plugin-hook-runtime/file-observation-acceptance.md b/openspec/changes/complete-plugin-hook-runtime/file-observation-acceptance.md index 9f481662..327daf3f 100644 --- a/openspec/changes/complete-plugin-hook-runtime/file-observation-acceptance.md +++ b/openspec/changes/complete-plugin-hook-runtime/file-observation-acceptance.md @@ -1,6 +1,6 @@ # FileChanged acceptance audit -Task 5.2 is implemented and under final acceptance review. This audit does not +Task 5.2 is accepted by merged PR #85 at `5d5826b7`. This audit does not close native plugin enforcement, the remaining producers, or the full goal. ## Requirements and direct evidence @@ -11,7 +11,7 @@ close native plugin enforcement, the remaining producers, or the full goal. | External, foreground and background edits; rename/delete | `native.rs`/`scan.rs`/`owner.rs`; `native_owner_delivers_external_edits_rename_removal_to_shared_sessions_and_joins`, `native_foreground_and_background_shell_writes_are_observed_after_the_turn` | Composed platform suite passes. | | Bounded observation, queue loss, partial inventory and recovery | Native queue/registration component cases; real-runtime `location_limit_is_visible_without_disabling_other_location_observations`, `session_limit_is_visible_and_released_membership_admits_a_waiting_session`, `directory_registration_limit_is_visible_and_reconciliation_covers_its_tail`, `long_path_inventory_publishes_a_partial_baseline_and_keeps_existing_files_live` | Composed platform suite passes; incomplete coverage remains visible and is not treated as absence. | | Private state, symlinks and hard-link scope | Pinned root/private identities, no-follow metadata scanner and link accounting; actual AppHost moved-private-root check, `hard_link_scope_allows_owned_aliases_and_suppresses_private_state_aliases`, both known-private retirement HTTP regressions | Composed platform suite passes. | -| Session scope, aliases and current project identity | Native leases, writer-validated scope records and admission-time physical input; alias-first sharing, root replacement, archive/resume and idle return regressions | Spelling aliases and both retarget/unused-old-ack cases pass on Linux, macOS and Windows at 01535d49. | +| Session scope, aliases and current project identity | Native leases, writer-validated scope records and admission-time physical input; alias-first sharing, root replacement, archive/resume and idle return regressions | Spelling aliases and both retarget/unused-old-ack cases pass on Linux, macOS and Windows at the final `b08a1f5c` source. | | Feedback, deduplication and unknown-effect recovery | Durable finite credit and owned user-ack validation; `hook_writes_stop_at_the_durable_feedback_limit_after_quiet_time`, `native_owner_feedback_renews_only_for_new_committed_user_input`, exhausted-credit/restart and unknown-handler Store regressions | Composed platform suite passes; quiet time or replay cannot manufacture renewal. | | Cancellation and bounded resource lifetime | Per-membership cancellation, held-batch identity, joined scanner/observer shutdown and pending-owner reuse; all held-member HTTP cases and `readmission_reuses_one_pending_replacement_until_previous_owner_settles` | Composed platform suite passes; Linux missing-fix controls also pass their required failure assertions. | @@ -22,7 +22,7 @@ claims based solely on test names: the workflow results, actual checkout and source composition are inspected separately. Native observations supply metadata and scoped handler admission, never permission or authenticated writer identity. -## Platform evidence and outstanding check +## Earlier platform evidence The [verified job receipt](evidence/file-observation-3f7067dd.json) records actual checkout checks, original log hashes, suite counts and platform exclusions. @@ -54,8 +54,9 @@ and passed on every platform. Windows now runs 17 Store/runtime and 24 HTTP case matching the corresponding Unix suites. This is actual Windows execution, not cross-compilation or an optional skip. Local Windows execution was unavailable. -Current-source relevant PR checks and final merge review remain required before -task 5.2 is closed. Parent plugin/native support and other producer tasks stay open. +These are historical receipts. Final current-source acceptance and the accepted +merge are recorded below. Parent plugin/native support and other producer tasks +stay open. ## Review and local checks @@ -89,5 +90,45 @@ per-attempt slow timeout. The existing single retry is retained, so a retried case can consume two attempts. Timeouts remain failures; this bounds future stalls without claiming an application deadlock fix or FileChanged acceptance. The largest reported passing-test times in those PR #87 runs were 99.147 seconds -on Linux and 75.484 on macOS. Current-revision CI and final review remain -required before task 5.2 closes. +on Linux and 75.484 on macOS. The final run below supplies current-source +acceptance; the earlier incomplete workspace run is not treated as passing. + + +## Final accepted source and merge + +The [final receipt](evidence/file-observation-b08a1f5c.json) binds all three focused +jobs to actual checkout `151144ea4f94f53866710ff9a25d74d64ca6a605`, tree +`4ead043efe3fd5908a55a134544cdd1efaa139ec`, equal to PR #85 head +`b08a1f5c12491451ca8c9f011aab8427010039c3`. Each platform passes all eight +focused suites, including all 14 named regressions in this audit, with 17 +Store/runtime and 24 real HTTP cases per platform. Both alias-retarget cases +actually execute on native Windows. Full counts, intentional helper ignores, +platform exclusions and original log hashes are explicit in the receipt. + +All 19 current-head PR checks passed. Broad Linux/macOS workspace jobs each pass +5,504 tests (21/23 skipped); Windows passes 3,775 selected tests (648 skipped), +plus four metadata, nine migration and 18 AppContainer cases. The Windows job +reports a leaked-process warning in +`messages_cli::an_exec_session_refuses_messages_unless_it_accepts_them`; its cause +is unverified. The previously stalled stats case passes in these Linux/macOS/ +Windows runs, which does not establish the earlier stall's cause or a code fix. + +Main advanced independently through PR #88. The +[composition check](evidence/file-observation-post88-composition.json) verifies +that only the accepted CwdChanged test file and task ledger differ from the tested +PR #85 tree: FileChanged production/test inputs and the nextest configuration are +unchanged. The exact composed tree passes formatting, whitespace, strict OpenSpec +(114/0) and spec lint (0 errors/25 warnings). It does not claim a new full workspace +run on that documentation/test composition. PR #85 merged at +`5d5826b72d41d6a833b523237bdbbd85ac51d31a`, whose tree +`ad445cb227b0a7d1cc8593cc25d7cd3efc4b9e3f` equals the reviewed composition. + +The earlier [ecce8b38 receipt](evidence/file-observation-ecce8b38.json) and +[post-#86 composition](evidence/file-observation-post86-composition.json) are +retained as historical evidence, superseded by the final receipt above. Neither +is used to claim that its cancelled or pending workspace run passed. + +This closes bounded FileChanged task 5.2, including alias admission, finite +feedback, bounded publication and joined observer lifetime. The full producer +acceptance task 5.3, DirectoryAdded/Setup, native plugin enforcement and protocols, +daily coding and binary editor work remain incomplete. diff --git a/openspec/changes/complete-plugin-hook-runtime/file-observation-implementation.md b/openspec/changes/complete-plugin-hook-runtime/file-observation-implementation.md index 4ad1c9b8..884d7855 100644 --- a/openspec/changes/complete-plugin-hook-runtime/file-observation-implementation.md +++ b/openspec/changes/complete-plugin-hook-runtime/file-observation-implementation.md @@ -1,5 +1,12 @@ # File observation implementation notes +Status: bounded FileChanged task 5.2 is accepted by merged PR #85. The +[final acceptance audit](file-observation-acceptance.md#final-accepted-source-and-merge) +records the actual source-bound platform results and accepted composition. +Incremental results and then-pending checks below are historical development +notes, superseded by that final record. Other plugin/hook tasks remain open. + + Status: **in progress; task 5.2 remains open**. The observer is implemented; this is not an event without a producer. The #76 foundations milestone merged at `ec31ff9f` after its applicable CI passed, without closing the full acceptance diff --git a/openspec/changes/complete-plugin-hook-runtime/tasks.md b/openspec/changes/complete-plugin-hook-runtime/tasks.md index 74dfafc8..0417ed79 100644 --- a/openspec/changes/complete-plugin-hook-runtime/tasks.md +++ b/openspec/changes/complete-plugin-hook-runtime/tasks.md @@ -80,7 +80,7 @@ does not close tasks 2.1–2.4. ## 5. Missing event producers - [ ] 5.1 Implement committed `DirectoryAdded`/`CwdChanged`, complete existing `Setup` init/marker semantics and fill proven isolated-child `WorktreeCreate` coverage gaps without moving its pre-effect veto. Isolated-child creation/recreation admission is implemented with regression coverage in `isolated_subagents.rs`; at source commit `b5ff9553`, all 16 broad CI jobs and both Linux/macOS before/after regression jobs passed ([broad CI](https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/40572548204), [regressions](https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/40572548267)). The parent task remains incomplete. Committed CwdChanged is implemented by PR #57; code revision d9932631 passed all 36 focused worktree tests on Linux/macOS plus broader CI. DirectoryAdded/Setup and combined event acceptance remain open. -- [ ] 5.2 Implement bounded `FileChanged` observation/reconciliation for tools, formatters, shell/background and external edits, including overflow and self-write loop prevention. Verify alias-aware Session admission and resource/lifecycle behavior before closing this task. See [file-observation-implementation.md](file-observation-implementation.md) for implementation and verification evidence. +- [x] 5.2 Implement bounded `FileChanged` observation/reconciliation for tools, formatters, shell/background and external edits, including overflow and self-write loop prevention. Verify alias-aware Session admission and resource/lifecycle behavior before closing this task. See [file-observation-implementation.md](file-observation-implementation.md) for implementation and verification evidence. - [ ] 5.3 Test no false post-effect success for refused/failed/unknown transitions, pre-effect WorktreeCreate veto/no Git mutation, stable event identity, correct scope/order, rename/delete, multiple Sessions, shutdown/restart and unknown handler outcomes. The CwdChanged regression @@ -93,10 +93,15 @@ exit is silent. This is a known before-append failure, not proof of an unknown commit outcome. All five HTTP CwdChanged cases are enabled on Unix and Windows with unchanged assertions. The Windows CI profile already selects the complete `worktree_setup` binary, so these cases must execute there. All five pass locally -on macOS; Windows execution is unavailable locally and hosted Windows acceptance -remains required. Task 5.3 stays open. +on macOS; the [merged PR #88 native Windows job](https://github.com/CyberdyneCorp/cybercode-cli/actions/runs/41221552314/job/124597023928) +also executes all five successfully. Its Linux/macOS checks pass as well. This +accepts those cases, not the full producer matrix; task 5.3 stays open. -Task 5.2 is in progress. The full focused suite at `3e852288` passed Linux/macOS/Windows. At `c0cc40e3`, complete Linux/Windows jobs also passed all 18 HTTP/runtime scenarios, including idle-return ownership, archive/resume and native burst recovery; macOS remained queued. Review then reproduced an oversized metadata baseline within the count/path limits. The new publication/batch byte-budget fix passes 63 local source-library tests and scoped Clippy, and its focused owner/application regression workflow at `5aa08018` now passes on Linux/macOS/Windows. Combined producer acceptance is pending on this integration branch. Remaining resource/lifecycle acceptance, broader workspace checks and substantive review are still open. See [the scope integration design](file-observation-scope-design.md) and [implementation notes](file-observation-implementation.md). +Task 5.2 is accepted by merged PR #85 (`5d5826b7`). The +[acceptance audit](file-observation-acceptance.md) maps the complete FileChanged +contract to actual native/runtime results, all three final platform jobs, broad +checks and the exact accepted main composition. Earlier byte-budget, private +retirement and pending-owner regressions are included in this acceptance. The [DirectoryAdded prerequisite proposal](directory-added-design.md) maps the unimplemented additional-directory owner operation to permission, sandbox and @@ -116,21 +121,31 @@ expand task 5.1 without closing it or the other producer obligations. - [ ] 6.4 Record accepted first-workstream evidence, then begin the reviewed Daily coding workstream. Archive only after accepted merge and reconcile overlapping deltas. -Composed-review follow-up: `6385cabe` passed all 16 broad and seven focused jobs, -then review reproduced false deletion dispatch when a known private inode/subtree -replaces a public baseline name. The new silent-retirement correction has two -real HTTP regressions and a missing-fix behavioral control. Task 5.2 remains open -for current-source platform acceptance; see the integration evidence above. +## CwdChanged acknowledgement regression -The [pending observer owner correction](file-observation-pending-owner.md) bounds -remove/readmit replacement behind a settling owner while retaining cancellation -and joined shutdown. Focused and platform acceptance remain required; task 5.2 -stays open. +`location_activity::cwd_changed_requires_acknowledged_previous_location_settlement` +compares successful previous-Location settlement with an injected unacknowledged +settlement after the new Location has committed. Both paths retain one durable +enter record. Only acknowledged settlement emits CwdChanged with that record's +identity; the uncertain path returns an error, emits no success observation, and +refuses subsequent entry/idle-exit until recovery. It also checks that releasing +the running call and shutting down releases the remaining admission without a +delayed success hook. This exercises the real runtime and Store with a simulated +Location owner, not native OS confinement or an uncertain Store commit. -## FileChanged acceptance after main integration +The complete 12-case Location activity suite passes locally on macOS. A behavioral +negative control that falls through after failed settlement executes this exact +case and fails because it emitted CwdChanged; production source is restored. +Hosted platform acceptance and final review remain required. Task 5.3 stays open +for the complete producer matrix, including DirectoryAdded and Setup. -Task 5.2 is in progress. The [acceptance audit](file-observation-acceptance.md) maps the full producer contract to actual native/runtime evidence and records verified Windows retarget coverage and the remaining PR/merge acceptance. +## FileChanged acceptance after main integration -PR #85 now incorporates the accepted Setup design and CwdChanged regression from -main. Fresh checks of this composed revision and final merge review remain -required; the earlier focused receipts do not close task 5.2 by themselves. +PR #85 merged after all 19 current-head checks passed. Final source-bound +Linux/macOS/Windows suites pass both retarget regressions, bounded native and +runtime observation, durable feedback, private-state retirement and joined +observer/pending-owner lifetime checks. The accepted merge tree equals the +reviewed composition with PR #88. See the +[acceptance audit](file-observation-acceptance.md) and its final receipts for the +scope, intentional skips and unverified Windows leaked-process warning. This +closes only task 5.2; tasks 5.1, 5.3 and full workstream acceptance stay open.