From d6444786757bbbf41ea5697bebaa2f323a6d6862 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 17 Sep 2026 01:39:17 +0000 Subject: [PATCH 1/3] test: assert observed results instead of pins Replace constant pins, absence-only checks, and weak is_ok/is_err assertions with calls that match a literal observed result. Co-authored-by: Zack Jackson --- .../src/advisory/github_runtime/protocol.rs | 19 +++- crates/tracedecay-code-index/src/clones.rs | 4 +- .../src/production/sealed_codec.rs | 14 ++- .../ignored_source_admissions.rs | 1 - .../tests/code_index_suite/import_evidence.rs | 3 +- .../contracts_suite/workflow_coordination.rs | 9 +- .../canonical_identity_wire_stability.rs | 99 ++++++++++++++++--- .../src/configuration/registry.rs | 34 ++++--- .../src/payload/filesystem_authority.rs | 7 +- crates/tracedecay-privacy/src/tests.rs | 40 +++++--- .../claude_observation_benchmark/artifact.rs | 1 - dashboard/src/app/runtime.test.ts | 15 +-- .../src/workspaces/code/codeRead.test.ts | 48 +++++---- .../settings/SettingsPage.dom.test.tsx | 3 + .../work/workEvidenceQueries.test.ts | 6 ++ plugin/opencode/tracedecay.test.ts | 8 +- 16 files changed, 222 insertions(+), 89 deletions(-) diff --git a/crates/tracedecay-application/src/advisory/github_runtime/protocol.rs b/crates/tracedecay-application/src/advisory/github_runtime/protocol.rs index bc16278501..207e14dca2 100644 --- a/crates/tracedecay-application/src/advisory/github_runtime/protocol.rs +++ b/crates/tracedecay-application/src/advisory/github_runtime/protocol.rs @@ -207,6 +207,19 @@ mod tests { const ENDPOINT: &str = "https://api.github.com/repos/owner/repository/releases"; + fn assert_accepted_delay(header: &str, delay_seconds: i64) { + let before = tracedecay_contracts::now_micros().0; + let accepted = retry_after_at(&headers_with("retry-after", header)) + .unwrap_or_else(|| panic!("retry-after {header} must land {delay_seconds}s after now")); + let after = tracedecay_contracts::now_micros().0; + let delay_micros = delay_seconds * 1_000_000; + assert!( + (before + delay_micros..=after + delay_micros).contains(&accepted.0), + "retry-after {header} stamped {}, outside {before}+{delay_micros}..={after}+{delay_micros}", + accepted.0 + ); + } + #[test] fn retry_after_rejects_negative_and_beyond_24h_delays() { assert!(retry_after_at(&headers_with("retry-after", "-1")).is_none()); @@ -214,10 +227,10 @@ mod tests { assert!(retry_after_at(&headers_with("retry-after", "86401")).is_none()); assert!(retry_after_at(&headers_with("retry-after", "9999999999")).is_none()); assert!(retry_after_at(&headers_with("retry-after", "not-a-number")).is_none()); - assert!(retry_after_at(&headers_with("retry-after", "0")).is_some()); - assert!(retry_after_at(&headers_with("retry-after", "60")).is_some()); - assert!(retry_after_at(&headers_with("retry-after", "86400")).is_some()); assert!(retry_after_at(&ureq::http::HeaderMap::new()).is_none()); + assert_accepted_delay("0", 0); + assert_accepted_delay("60", 60); + assert_accepted_delay("86400", 86_400); } #[test] diff --git a/crates/tracedecay-code-index/src/clones.rs b/crates/tracedecay-code-index/src/clones.rs index 8e1a79689d..081c47ea8f 100644 --- a/crates/tracedecay-code-index/src/clones.rs +++ b/crates/tracedecay-code-index/src/clones.rs @@ -1172,7 +1172,7 @@ mod fingerprint_tests { }; use super::{ - CLONE_FINGERPRINT_K_V1, CLONE_FINGERPRINT_WINDOW_V1, CloneAlignmentStopReasonV1, + CLONE_FINGERPRINT_K_V1, CloneAlignmentStopReasonV1, CloneBodyPayloadV1, CloneNormalizationClassV1, CloneTokenAnchorV1, align_clone_tokens, select_rightmost_minima, verify_clone_token_anchor, verify_exact_clone_payload, winnow_clone_tokens, @@ -1210,8 +1210,6 @@ mod fingerprint_tests { .len(), 1 ); - assert_eq!(CLONE_FINGERPRINT_K_V1, 7); - assert_eq!(CLONE_FINGERPRINT_WINDOW_V1, 8); } #[test] diff --git a/crates/tracedecay-code-index/src/production/sealed_codec.rs b/crates/tracedecay-code-index/src/production/sealed_codec.rs index bc56af9a3e..c1e83f99dd 100644 --- a/crates/tracedecay-code-index/src/production/sealed_codec.rs +++ b/crates/tracedecay-code-index/src/production/sealed_codec.rs @@ -1287,18 +1287,16 @@ mod tests { #[test] fn format_gate_accepts_only_the_monolithic_and_partitioned_revisions() { - assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12); - assert_eq!(MINIMUM_SEALED_GENERATION_FORMAT_REVISION, 9); - assert!(sealed_generation_format_revision_is_compatible(9)); - assert!(sealed_generation_format_revision_is_compatible(12)); - assert!(!sealed_generation_format_revision_is_compatible(8)); + assert_eq!(sealed_generation_format_revision_is_compatible(9), true); + assert_eq!(sealed_generation_format_revision_is_compatible(12), true); + assert_eq!(sealed_generation_format_revision_is_compatible(8), false); // Revision 10 stored generation-bound symbol occurrence lists. // Revision 11 sealed generation-independent symbol identities but a // full-corpus `full_replay_digest`. Revision 12 seals that digest as // a parent-delta, so 11 is rebuilt rather than decoded as corruption. - assert!(!sealed_generation_format_revision_is_compatible(10)); - assert!(!sealed_generation_format_revision_is_compatible(11)); - assert!(!sealed_generation_format_revision_is_compatible(13)); + assert_eq!(sealed_generation_format_revision_is_compatible(10), false); + assert_eq!(sealed_generation_format_revision_is_compatible(11), false); + assert_eq!(sealed_generation_format_revision_is_compatible(13), false); } struct LargestAllocationRecorderV1; diff --git a/crates/tracedecay-code-index/tests/code_index_suite/ignored_source_admissions.rs b/crates/tracedecay-code-index/tests/code_index_suite/ignored_source_admissions.rs index 76e81e3010..2a41d59806 100644 --- a/crates/tracedecay-code-index/tests/code_index_suite/ignored_source_admissions.rs +++ b/crates/tracedecay-code-index/tests/code_index_suite/ignored_source_admissions.rs @@ -451,7 +451,6 @@ fn sealed_state_digest_changes_when_ignored_source_roster_changes() { #[test] fn sealed_format_refuses_superseded_revisions_beside_the_partitioned_revision() { - assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12); let generation = publish(request_with_ignored_sources(vec![admission( PRIMARY_IGNORED_PATH, )])); diff --git a/crates/tracedecay-code-index/tests/code_index_suite/import_evidence.rs b/crates/tracedecay-code-index/tests/code_index_suite/import_evidence.rs index 275b5b568c..639ddeaf3d 100644 --- a/crates/tracedecay-code-index/tests/code_index_suite/import_evidence.rs +++ b/crates/tracedecay-code-index/tests/code_index_suite/import_evidence.rs @@ -10,7 +10,7 @@ use tracedecay_code_index::{ production::{ CodeIndexBuildRequestV1, CodeIndexCapturedFileV1, CodeIndexProductionErrorV1, CodeIndexProductionOwnerV1, CodeIndexPublishedGenerationV1, - SEALED_GENERATION_FORMAT_REVISION_V1, sealed_generation_payload_digest, + sealed_generation_payload_digest, }, }; use tracedecay_domain::{ @@ -857,7 +857,6 @@ fn raw_use_and_imported_bindings_never_become_canonical_symbols() { #[test] fn sealed_revision_nine_import_generation_round_trips_to_identical_bytes() { - assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12); let first = published_import_generation(); let first_sealed = first.encode_sealed().expect("first generation seals"); let second_sealed = published_import_generation() diff --git a/crates/tracedecay-contracts/tests/contracts_suite/workflow_coordination.rs b/crates/tracedecay-contracts/tests/contracts_suite/workflow_coordination.rs index b1ffef1cbd..f3f7eeabe3 100644 --- a/crates/tracedecay-contracts/tests/contracts_suite/workflow_coordination.rs +++ b/crates/tracedecay-contracts/tests/contracts_suite/workflow_coordination.rs @@ -4,10 +4,10 @@ use std::sync::{Arc, Mutex}; use schemars::schema_for; use tracedecay_contracts::{ CancellationContext, CapabilityGrantSnapshot, Deadline, DisclosureClass, RequestContext, - RequestId, ResolvedScope, TASK_HANDOFF_LIFETIME_MICROS, TaskHandoffAuthorityError, - TaskHandoffAuthorityPort, TaskHandoffConsumeOutcome, TaskHandoffError, TaskHandoffGrant, - TaskHandoffIssueRequest, TaskHandoffRedeemRequest, TaskHandoffScope, TaskHandoffService, - TaskHandoffToken, WorkHandoffFrontierV1, WorkHandoffLineageV1, WorkflowCatalogAdmissionError, + RequestId, ResolvedScope, TaskHandoffAuthorityError, TaskHandoffAuthorityPort, + TaskHandoffConsumeOutcome, TaskHandoffError, TaskHandoffGrant, TaskHandoffIssueRequest, + TaskHandoffRedeemRequest, TaskHandoffScope, TaskHandoffService, TaskHandoffToken, + WorkHandoffFrontierV1, WorkHandoffLineageV1, WorkflowCatalogAdmissionError, WorkflowCoordinationError, WorkflowDefinitionAuthorityError, WorkflowDefinitionAuthorityPort, WorkflowDefinitionDisposition, WorkflowDefinitionLifecycleCommand, WorkflowDefinitionLifecycleState, WorkflowDefinitionService, WorkflowDefinitionTransitionEntry, @@ -450,7 +450,6 @@ fn frontier() -> WorkHandoffFrontierV1 { #[test] fn handoff_enforces_authorization_scope_expiry_and_single_use_without_bearer_leakage() { - assert_eq!(TASK_HANDOFF_LIFETIME_MICROS, UtcMicros(60_000_000)); let authority = FakeHandoffAuthority::default(); let service = TaskHandoffService::new(authority); let scope = handoff_scope(); diff --git a/crates/tracedecay-domain/tests/domain_suite/canonical_identity_wire_stability.rs b/crates/tracedecay-domain/tests/domain_suite/canonical_identity_wire_stability.rs index d80a802a5b..563eae6e76 100644 --- a/crates/tracedecay-domain/tests/domain_suite/canonical_identity_wire_stability.rs +++ b/crates/tracedecay-domain/tests/domain_suite/canonical_identity_wire_stability.rs @@ -9,8 +9,8 @@ use tracedecay_domain::code_intelligence::{CodeGenerationId, ContentDigest}; use tracedecay_domain::configuration::UserProfileId; use tracedecay_domain::feedback::{FeedbackCycleId, GitHubReviewIdV1, ProximityWarningIdV1}; use tracedecay_domain::observation::CanonicalObservationIdV1; -use tracedecay_domain::research::{EntityId, canonical_sha256}; -use tracedecay_domain::retrieval::PrincipalId; +use tracedecay_domain::research::{DomainError, EntityId, canonical_sha256}; +use tracedecay_domain::retrieval::{PrincipalId, RetrievalContractError}; use tracedecay_domain::session::{MessageOccurrenceIdV1, ProjectionOutputOrdinalV1}; /// Every family serializes as the bare string, with no wrapper object. @@ -111,18 +111,87 @@ fn derived_identities_match_their_independent_pre_image() { #[test] fn identity_families_reject_the_same_values() { for bad in ["", " lead", "trail ", "in\tner", "\u{7f}"] { - assert!(EntityId::new(bad).is_err(), "accepted {bad:?}"); - assert!(CodeGenerationId::new(bad).is_err(), "accepted {bad:?}"); - assert!(PrincipalId::new(bad).is_err(), "accepted {bad:?}"); - assert!(UserProfileId::new(bad).is_err(), "accepted {bad:?}"); - assert!(FeedbackCycleId::new(bad).is_err(), "accepted {bad:?}"); - assert!(ProximityWarningIdV1::new(bad).is_err(), "accepted {bad:?}"); - assert!(GitHubReviewIdV1::new(bad).is_err(), "accepted {bad:?}"); + let empty = bad.is_empty(); + let domain = |field: &'static str| { + if empty { + DomainError::Empty { field } + } else { + DomainError::NonCanonical { field } + } + }; + assert_eq!( + EntityId::new(bad).unwrap_err(), + domain("EntityId"), + "{bad:?}" + ); + assert_eq!( + CodeGenerationId::new(bad).unwrap_err(), + DomainError::NonCanonical { + field: "CodeGenerationId" + }, + "{bad:?}" + ); + assert_eq!( + PrincipalId::new(bad).unwrap_err(), + RetrievalContractError::InvalidIdentity { + field: "PrincipalId" + }, + "{bad:?}" + ); + assert_eq!( + UserProfileId::new(bad).unwrap_err(), + domain("user profile id"), + "{bad:?}" + ); + assert_eq!( + FeedbackCycleId::new(bad).unwrap_err(), + domain("feedback cycle id"), + "{bad:?}" + ); + assert_eq!( + ProximityWarningIdV1::new(bad).unwrap_err(), + domain("proximity warning id"), + "{bad:?}" + ); + assert_eq!( + GitHubReviewIdV1::new(bad).unwrap_err(), + domain("github review id"), + "{bad:?}" + ); } - assert!(EntityId::new("x".repeat(512)).is_ok()); - assert!(EntityId::new("x".repeat(513)).is_err()); - assert!(UserProfileId::new("x".repeat(512)).is_ok()); - assert!(UserProfileId::new("x".repeat(513)).is_err()); - assert!(PrincipalId::new("x".repeat(512)).is_ok()); - assert!(PrincipalId::new("x".repeat(513)).is_err()); + let accepted = "x".repeat(512); + assert_eq!( + EntityId::new(accepted.clone()) + .expect("512-byte identity") + .as_str(), + accepted + ); + assert_eq!( + EntityId::new("x".repeat(513)).unwrap_err(), + DomainError::NonCanonical { field: "EntityId" } + ); + assert_eq!( + UserProfileId::new(accepted.clone()) + .expect("512-byte profile id") + .as_str(), + accepted + ); + assert_eq!( + UserProfileId::new("x".repeat(513)).unwrap_err(), + DomainError::NonCanonical { + field: "user profile id" + } + ); + assert_eq!( + PrincipalId::new(accepted) + .expect("512-byte principal") + .as_str(), + "x".repeat(512) + ); + assert_eq!( + PrincipalId::new("x".repeat(513)).unwrap_err(), + RetrievalContractError::InvalidIdentity { + field: "PrincipalId" + } + ); } diff --git a/crates/tracedecay-global-db/src/configuration/registry.rs b/crates/tracedecay-global-db/src/configuration/registry.rs index 5f8a716c76..9b8926c86d 100644 --- a/crates/tracedecay-global-db/src/configuration/registry.rs +++ b/crates/tracedecay-global-db/src/configuration/registry.rs @@ -744,7 +744,6 @@ mod user_profile_settings_tests { #[test] fn code_index_workers_default_is_automatic_and_zero_exact_is_denied() { - assert_eq!(CONFIGURATION_REGISTRY_SCHEMA_REVISION, 7); let key = SettingKey::new(USER_CODE_INDEX_WORKERS_SETTING_KEY).expect("key"); let project_registry = ConfigurationRegistry::core().expect("project registry"); assert!(matches!( @@ -757,6 +756,7 @@ mod user_profile_settings_tests { assert_eq!(registry.definitions().count(), 1); let definition = registry.definition(&key).expect("definition"); + assert_eq!(definition.schema_revision, 7); assert_eq!(definition.scope, SettingScopeV1::UserProfile); assert_eq!( definition.value_kind, @@ -772,15 +772,27 @@ mod user_profile_settings_tests { definition.restart_requirement, RestartRequirementV1::DaemonRestart ); - assert!( - registry - .validate_value( - &key, - &ConfigurationValueV1::CodeIndexWorkerSelection( - CodeIndexWorkerSelectionV1::Exact { workers: 0 }, - ), - ) - .is_err() - ); + assert!(matches!( + registry.validate_value( + &key, + &ConfigurationValueV1::CodeIndexWorkerSelection( + CodeIndexWorkerSelectionV1::Exact { workers: 2 }, + ), + ), + Ok(()) + )); + assert!(matches!( + registry.validate_value( + &key, + &ConfigurationValueV1::CodeIndexWorkerSelection( + CodeIndexWorkerSelectionV1::Exact { workers: 0 }, + ), + ), + Err(ConfigurationRegistryError::InvalidDefinition( + tracedecay_domain::DomainError::NonCanonical { + field: "code index worker count", + } + )) + )); } } diff --git a/crates/tracedecay-lcm/src/payload/filesystem_authority.rs b/crates/tracedecay-lcm/src/payload/filesystem_authority.rs index c71ebcb95a..49f5e8ffe1 100644 --- a/crates/tracedecay-lcm/src/payload/filesystem_authority.rs +++ b/crates/tracedecay-lcm/src/payload/filesystem_authority.rs @@ -1071,7 +1071,6 @@ mod windows_tests { assert_eq!(align_of::(), 8); assert_eq!(offset_of!(FileIdInfo, volume_serial_number), 0); assert_eq!(offset_of!(FileIdInfo, file_id), 8); - assert_eq!(FILE_ID_INFO_CLASS, 18); } #[test] @@ -1115,7 +1114,7 @@ mod windows_tests { let identity = query_windows_file_identity_with( std::ptr::null_mut(), |_, information_class, information, buffer_size| { - assert_eq!(information_class, FILE_ID_INFO_CLASS); + assert_eq!(information_class, 18); assert_eq!(buffer_size as usize, size_of::()); // SAFETY: The seam supplies a writable `FileIdInfo` buffer. unsafe { @@ -1148,7 +1147,7 @@ mod windows_tests { let volume_only = query_windows_file_identity_with( std::ptr::null_mut(), |_, information_class, information, buffer_size| { - assert_eq!(information_class, FILE_ID_INFO_CLASS); + assert_eq!(information_class, 18); assert_eq!(buffer_size as usize, size_of::()); // SAFETY: The seam supplies a writable `FileIdInfo` buffer. unsafe { @@ -1167,7 +1166,7 @@ mod windows_tests { std::ptr::null_mut(), |_, information_class, _, buffer_size| { calls.set(calls.get() + 1); - assert_eq!(information_class, FILE_ID_INFO_CLASS); + assert_eq!(information_class, 18); assert_eq!(buffer_size as usize, size_of::()); 0 }, diff --git a/crates/tracedecay-privacy/src/tests.rs b/crates/tracedecay-privacy/src/tests.rs index d28785d57d..a00a988497 100644 --- a/crates/tracedecay-privacy/src/tests.rs +++ b/crates/tracedecay-privacy/src/tests.rs @@ -13,13 +13,13 @@ use super::detect::{ DetectionError, SanitizationDetectorOriginV1, SanitizationDetectorRevisionV1, SanitizationRemediationClassV1, SanitizationScanBoundaryV1, SanitizationScannedCoverageV1, }; -use super::sanitize::{CLAUDE_SANITIZER_VERSION_V1, OBSERVATION_SANITIZER_VERSION_V1}; +use super::sanitize::OBSERVATION_SANITIZER_VERSION_V1; use super::{ CODE_SOURCE_SANITIZER_VERSION_V1, ClaudeRecordParseErrorV1, ClaudeRecordSanitizerV1, ClaudeSanitizationOutcomeV1, ClaudeSanitizerPolicyV1, CodeSourceShapeV1, DetectionConfidenceV1, - LcmSensitiveRedactionPolicyV1, MAX_OBSERVATION_RECORD_BYTES, MEMORY_FACT_SANITIZER_VERSION_V1, - MemoryFactSanitizationV1, PrivacyDetectorV1, PrivacySanitizerError, SanitizationActionV1, - SanitizationFindingV1, SanitizedPayloadVerificationError, parse_claude_record_v1, + LcmSensitiveRedactionPolicyV1, MEMORY_FACT_SANITIZER_VERSION_V1, MemoryFactSanitizationV1, + PrivacyDetectorV1, PrivacySanitizerError, SanitizationActionV1, SanitizationFindingV1, + SanitizedPayloadVerificationError, parse_claude_record_v1, parse_normalized_observation_record_v1, parse_observation_record_v1, redact_lcm_sensitive_payload, sanitize_code_source_bytes, sanitize_memory_fact_payload, sanitize_provider_metadata_json, verify_memory_fact_sanitization, @@ -271,7 +271,21 @@ fn parsed_record_rejects_mismatched_range_and_canonical_oversize() { Some(ClaudeRecordParseErrorV1::RangeLengthMismatch) ); - let oversized = vec![b' '; MAX_OBSERVATION_RECORD_BYTES + 1]; + let at_limit = format!( + r#"{{"message":"{}"}}"#, + "a".repeat(1_048_576 - br#"{"message":""}"#.len()) + ); + assert_eq!(at_limit.len(), 1_048_576); + let at_limit_range = + ObservationSourceRangeV1::new(0, 1_048_576).expect("non-empty at-limit range"); + let admitted = parse_claude_record_v1(at_limit.as_bytes(), at_limit_range) + .expect("a record at the one-mebibyte limit is admitted"); + assert_eq!( + admitted.value()["message"].as_str().map(str::len), + Some(1_048_576 - br#"{"message":""}"#.len()) + ); + + let oversized = vec![b' '; 1_048_577]; let oversized_range = ObservationSourceRangeV1::new(0, oversized.len() as u64) .expect("non-empty oversized range"); assert_eq!( @@ -1329,12 +1343,10 @@ fn structure_bound_failures_are_quarantined_without_payloads() { #[test] fn receipt_ids_are_deterministic_and_use_the_fixed_sanitizer_version() { - assert_eq!(CLAUDE_SANITIZER_VERSION_V1, "privacy.claude-record.v1"); - assert_eq!(MAX_OBSERVATION_RECORD_BYTES, 1_048_576); let sanitizer = ClaudeRecordSanitizerV1::claude_v1().expect("valid Claude V1 sanitizer"); assert_eq!( sanitizer.policy().version().as_str(), - CLAUDE_SANITIZER_VERSION_V1 + "privacy.claude-record.v1" ); let record = serde_json::to_vec(&json!({ "message": "ordinary deterministic fixture" })) @@ -1349,7 +1361,7 @@ fn receipt_ids_are_deterministic_and_use_the_fixed_sanitizer_version() { ); assert_eq!( first.receipt().receipt().sanitizer_version().as_str(), - CLAUDE_SANITIZER_VERSION_V1 + "privacy.claude-record.v1" ); let changed_record = @@ -1472,12 +1484,16 @@ fn lcm_sensitive_redaction_rejects_duplicate_json_keys_before_materialization() #[test] fn lcm_sensitive_redaction_rejects_payloads_above_the_canonical_raw_byte_limit() { let policy = LcmSensitiveRedactionPolicyV1::enabled(["api_key"]); - let raw = format!("{{{}", " ".repeat(MAX_OBSERVATION_RECORD_BYTES)); + let admitted = redact_lcm_sensitive_payload(r#"{"safe":"kept"}"#, &policy) + .expect("a record inside the byte limit is redacted"); + assert_eq!(admitted.text(), r#"{"safe":"kept"}"#); + assert_eq!(admitted.patterns(), &[] as &[String]); - assert!(matches!( + let raw = format!("{{{}", " ".repeat(1_048_576)); + assert_eq!( redact_lcm_sensitive_payload(&raw, &policy), Err(DetectionError::ScanLimitExceeded) - )); + ); } #[test] diff --git a/crates/tracedecay/tests/claude_observation_benchmark/artifact.rs b/crates/tracedecay/tests/claude_observation_benchmark/artifact.rs index e75a5cb3e4..f63658b160 100644 --- a/crates/tracedecay/tests/claude_observation_benchmark/artifact.rs +++ b/crates/tracedecay/tests/claude_observation_benchmark/artifact.rs @@ -881,7 +881,6 @@ pub(super) fn git_snapshot() -> GitSnapshot { } fn validate_source_archive() -> (GitSnapshot, usize) { - assert_eq!(BUILD_SOURCE_MODE, Some("git_archive_read_only_v1")); let manifest_path = repository_root().join(".tracedecay-benchmark-source-manifest"); let manifest = fs::read(&manifest_path).expect("read immutable source manifest"); assert_eq!( diff --git a/dashboard/src/app/runtime.test.ts b/dashboard/src/app/runtime.test.ts index 5db6b7873b..30954965a6 100644 --- a/dashboard/src/app/runtime.test.ts +++ b/dashboard/src/app/runtime.test.ts @@ -1,12 +1,15 @@ import { describe, expect, it } from 'vitest'; -import { - dashboardRouterBasename, - HERMES_EMBED_BASENAME, -} from './embedBasename.ts'; +import { dashboardRouterBasename } from './embedBasename.ts'; describe('dashboardRouterBasename', () => { - it('does not treat sibling or ordinary dashboard paths as the embed', () => { - expect(dashboardRouterBasename(`${HERMES_EMBED_BASENAME}-evil`)).toBeUndefined(); + it('uses the embed path only as an exact prefix', () => { + expect(dashboardRouterBasename('/api/plugins/tracedecay/embed')).toBe( + '/api/plugins/tracedecay/embed', + ); + expect(dashboardRouterBasename('/api/plugins/tracedecay/embed/agents')).toBe( + '/api/plugins/tracedecay/embed', + ); + expect(dashboardRouterBasename('/api/plugins/tracedecay/embed-evil')).toBeUndefined(); expect(dashboardRouterBasename('/delivery')).toBeUndefined(); expect(dashboardRouterBasename('/')).toBeUndefined(); }); diff --git a/dashboard/src/workspaces/code/codeRead.test.ts b/dashboard/src/workspaces/code/codeRead.test.ts index 3340a79ff9..1c85bdd79f 100644 --- a/dashboard/src/workspaces/code/codeRead.test.ts +++ b/dashboard/src/workspaces/code/codeRead.test.ts @@ -4,22 +4,34 @@ import { codeReadState, describeCodeReadReason } from './codeRead.ts'; describe('code-read reason wording', () => { it('words every typed reason the two routes emit and passes unknown ones through', () => { - for (const reason of [ - 'selected_source_not_found', - 'invalid_request', - 'selected_revision_changed', - 'code_read_authority_unavailable', - 'code_generation_unavailable', - 'code_read_capacity_unavailable', - 'code_index_reset_required', - 'request_cancelled', - 'request_timed_out', - 'code_read_failed', - ]) { - const sentence = describeCodeReadReason(reason); - expect(sentence).not.toBe(reason); - expect(sentence).toMatch(/\.$/); - } + expect(describeCodeReadReason('selected_source_not_found')).toBe( + 'The selected occurrence is not in the retained clone index: it is stale, unknown, or outside the retained scope.', + ); + expect(describeCodeReadReason('invalid_request')).toBe( + 'The request was malformed; the daemon refused it before reading anything.', + ); + expect(describeCodeReadReason('selected_revision_changed')).toBe( + 'A selected reference no longer points at its expected revision. The comparison was not made against a different commit.', + ); + expect(describeCodeReadReason('code_read_authority_unavailable')).toBe( + 'The code-read authority is not mounted on this daemon.', + ); + expect(describeCodeReadReason('code_generation_unavailable')).toBe( + 'No sealed code-index generation is available for this scope yet.', + ); + expect(describeCodeReadReason('code_read_capacity_unavailable')).toBe( + 'A retained generation exceeds the bounded-read limits, so the daemon refused rather than read it partially.', + ); + expect(describeCodeReadReason('code_index_reset_required')).toBe( + 'The clone index reports corruption and requires an explicit reset; nothing was read.', + ); + expect(describeCodeReadReason('request_cancelled')).toBe( + 'The read was cancelled before it finished.', + ); + expect(describeCodeReadReason('request_timed_out')).toBe( + 'The read did not finish within its deadline.', + ); + expect(describeCodeReadReason('code_read_failed')).toBe('The read failed inside the daemon.'); expect(describeCodeReadReason('something_new')).toBe('something_new'); expect(describeCodeReadReason(undefined)).toBeUndefined(); }); @@ -33,7 +45,9 @@ describe('code-read reason wording', () => { expect(state.kind).toBe('blocked'); if (state.kind !== 'blocked') throw new Error('unreachable'); expect(state.state).toBe('stale'); - expect(state.detail).toMatch(/no longer points at its expected revision/); + expect(state.detail).toBe( + 'A selected reference no longer points at its expected revision. The comparison was not made against a different commit.', + ); const bare = codeReadState(false, { outcome: 'transport', state: 'offline' }, { loading: 'l', transport: 't' }); if (bare.kind !== 'blocked') throw new Error('unreachable'); diff --git a/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx b/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx index e57c3886d1..cf0ead67d5 100644 --- a/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx +++ b/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx @@ -866,6 +866,9 @@ describe('Settings section navigation', () => { }); it('resolves nothing for an id no section carries, rather than the first one', () => { + expect(findConfigSection(sectionsFixture(AWKWARD), 'odd"group')?.dataset['section']).toBe( + 'odd"group', + ); expect(findConfigSection(sectionsFixture(AWKWARD), 'absent')).toBeUndefined(); // Not a prefix or substring match either: `project` must not answer for // `project.sync`. diff --git a/dashboard/src/workspaces/work/workEvidenceQueries.test.ts b/dashboard/src/workspaces/work/workEvidenceQueries.test.ts index 2973bf90bc..34cb2be30b 100644 --- a/dashboard/src/workspaces/work/workEvidenceQueries.test.ts +++ b/dashboard/src/workspaces/work/workEvidenceQueries.test.ts @@ -114,6 +114,12 @@ describe('TaskSession evidence requests', () => { workGraphTimeline([{ tasks: [{ taskId: 'task.alpha' }] }]), ), }; + expect(workEvidenceRequest(current(), 'task.alpha', { kind: 'current' }, null, 123)?.task_id).toBe( + 'task.alpha', + ); + expect( + workEvidenceRequest(current(), 'task.alpha', { kind: 'current' }, null, 123)?.observed_at, + ).toBe(123); expect( workEvidenceRequest(timeline, 'task.alpha', { kind: 'current' }, null, 123), ).toBeUndefined(); diff --git a/plugin/opencode/tracedecay.test.ts b/plugin/opencode/tracedecay.test.ts index f343b23fc1..4900070e76 100644 --- a/plugin/opencode/tracedecay.test.ts +++ b/plugin/opencode/tracedecay.test.ts @@ -10,8 +10,14 @@ test("OpenCode discovers one v1 server entrypoint per installed module", () => { }) test("dispatch lets the hook child finish instead of killing before durable spool", async () => { - const startedAt = performance.now() + const guided = await dispatch( + "TraceDecay guidance", + { event: "file.edited" }, + "/usr/bin/printf", + ) + expect(guided).toBe("TraceDecay guidance") + const startedAt = performance.now() const guidance = await dispatch("0.05", { event: "file.edited" }, "/bin/sleep") expect(guidance).toBeUndefined() From 76e6f42fbf21180b2f0014b4896e0929c302b046 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 17 Sep 2026 01:49:05 +0000 Subject: [PATCH 2/3] test: lock observed values across rejection and readout Assert typed refusals and the text users see instead of is_err, is_ok, and toBeTruthy checks that pass for any result. Co-authored-by: Zack Jackson --- .../src/configuration/tests.rs | 21 ++++++- .../tracedecay-contracts/src/feedback/read.rs | 22 +++++++- .../src/remote/query_tests.rs | 51 +++++++++++++---- .../src/result/problem/tests.rs | 23 +++++++- .../src/storage/identity.rs | 22 +++++--- .../contracts_suite/source_edit_effect.rs | 31 +++++++--- .../src/code_intelligence/index.rs | 23 ++++++-- .../src/code_intelligence/language.rs | 25 +++++++-- .../src/code_intelligence/search.rs | 15 ++++- .../src/configuration/topology.rs | 20 +++++-- .../src/feedback/ci_localization.rs | 48 +++++++++++++--- .../src/feedback/proximity.rs | 11 +++- .../src/app/shell/StatusStrip.dom.test.tsx | 2 +- dashboard/src/ui/ActivityColumns.dom.test.tsx | 4 +- dashboard/src/ui/StateChip.dom.test.tsx | 2 +- dashboard/src/ui/instrument.dom.test.tsx | 4 +- .../agents/AgentFailureContext.dom.test.tsx | 10 ++-- .../agents/AgentHandoffs.dom.test.tsx | 14 ++--- .../agents/AgentToolActivity.dom.test.tsx | 6 +- .../workspaces/agents/AgentsPage.dom.test.tsx | 8 +-- .../brain/BrainInteraction.dom.test.tsx | 6 +- .../brain/ProjectInspector.dom.test.tsx | 10 ++-- .../workspaces/brain/ScopedBrain.dom.test.tsx | 12 ++-- .../workspaces/brain/SignalPanel.dom.test.tsx | 10 ++-- .../code/CodeDiagnostics.dom.test.tsx | 12 ++-- .../src/workspaces/code/CodePage.dom.test.tsx | 10 ++-- .../code/IndexFreshness.dom.test.tsx | 56 +++++++++---------- .../workspaces/code/TraceView.dom.test.tsx | 2 +- .../costs/CanonicalCosts.dom.test.tsx | 8 +-- .../workspaces/costs/CostsPage.dom.test.tsx | 10 ++-- .../delivery/DeliveryPage.dom.test.tsx | 10 ++-- .../explorer/ExplorerPage.dom.test.tsx | 18 +++--- .../knowledge/KnowledgePage.dom.test.tsx | 6 +- .../src/workspaces/loom/LoomPage.dom.test.tsx | 28 +++++----- .../workspaces/loom/WeaveCanvas.dom.test.tsx | 4 +- .../CanonicalObservations.dom.test.tsx | 12 ++-- .../observatory/DoctorInspector.dom.test.tsx | 6 +- .../observatory/ObservatoryPage.dom.test.tsx | 18 +++--- .../PerformanceBudgets.dom.test.tsx | 2 +- .../sessions/SessionInspector.dom.test.tsx | 4 +- .../settings/SettingsPage.dom.test.tsx | 22 ++++---- .../work/WorkEvidencePanel.dom.test.tsx | 2 +- .../workflows/WorkflowsPage.dom.test.tsx | 4 +- 43 files changed, 413 insertions(+), 221 deletions(-) diff --git a/crates/tracedecay-contracts/src/configuration/tests.rs b/crates/tracedecay-contracts/src/configuration/tests.rs index 4bf4abc811..9a975246ea 100644 --- a/crates/tracedecay-contracts/src/configuration/tests.rs +++ b/crates/tracedecay-contracts/src/configuration/tests.rs @@ -128,9 +128,24 @@ fn empty_configuration_requests_reject_transport_arguments() { #[test] fn configuration_schema_refs_reject_unknown_operations() { - assert!(configuration_surface_request_schema("configuration_get").is_ok()); - assert!(configuration_surface_result_schema("configuration_get").is_ok()); - assert!(configuration_surface_request_schema("configuration_unknown").is_err()); + let request = + configuration_surface_request_schema("configuration_get").expect("get request schema"); + assert_eq!( + request.schema_id().as_str(), + "schema.application.configuration.configuration_get.request" + ); + let result = + configuration_surface_result_schema("configuration_get").expect("get result schema"); + assert_eq!( + result.schema_id().as_str(), + "schema.application.configuration.configuration_get.result" + ); + assert_eq!( + configuration_surface_request_schema("configuration_unknown").unwrap_err(), + ApplicationContractError::Inconsistent { + field: "configuration surface operation", + } + ); } #[test] diff --git a/crates/tracedecay-contracts/src/feedback/read.rs b/crates/tracedecay-contracts/src/feedback/read.rs index 0fd6097ea9..83680fb469 100644 --- a/crates/tracedecay-contracts/src/feedback/read.rs +++ b/crates/tracedecay-contracts/src/feedback/read.rs @@ -692,6 +692,8 @@ mod invocation_tests { CommitId, ManifestDigest, ProjectId, RepositoryId, RetrievalAnchorId, WorktreeId, }; + use crate::error::ApplicationContractError; + use super::{ CanonicalAffectedTestsProjectionV1, CanonicalFeedbackImpactProjectionV1, FeedbackDiagnosticsReadResultV1, FeedbackExpandResultV1, FeedbackFindingReadV1, @@ -702,9 +704,23 @@ mod invocation_tests { #[test] fn invocation_handle_rejects_unbounded_or_noncanonical_feedback_reads() { - assert!(FeedbackHandleRequestV1::new("feedback.handle.v1").is_ok()); - assert!(FeedbackHandleRequestV1::new(" feedback.handle.v1").is_err()); - assert!(FeedbackHandleRequestV1::new("x".repeat(257)).is_err()); + assert_eq!( + FeedbackHandleRequestV1::new("feedback.handle.v1") + .expect("canonical handle") + .request_handle, + "feedback.handle.v1" + ); + let rejected = ApplicationContractError::InvalidIdentifier { + field: "feedback request handle", + }; + assert_eq!( + FeedbackHandleRequestV1::new(" feedback.handle.v1").unwrap_err(), + rejected + ); + assert_eq!( + FeedbackHandleRequestV1::new("x".repeat(257)).unwrap_err(), + rejected + ); } #[test] diff --git a/crates/tracedecay-contracts/src/remote/query_tests.rs b/crates/tracedecay-contracts/src/remote/query_tests.rs index 5fc2d4ab77..009e9b54b5 100644 --- a/crates/tracedecay-contracts/src/remote/query_tests.rs +++ b/crates/tracedecay-contracts/src/remote/query_tests.rs @@ -22,7 +22,7 @@ use super::query::{ validate_returned_authority, validate_returned_observation_identity, validate_returned_provenance, }; -use crate::{RequestId, ResolvedScope}; +use crate::{ApplicationContractError, RequestId, ResolvedScope}; use tracedecay_domain::{ AuthorityEpoch, BrainId, BrainNodeId, CanonicalObservationIdV1, CurrentRemoteAuthorityStateV1, CurrentRemoteAuthorityV1, EnrollmentCredentialRecordV1, EntityId, EvidenceAvailabilityV1, @@ -133,36 +133,67 @@ fn exact_observation_absence_round_trips_as_explicit_state() { #[test] fn remote_query_request_enforces_shard_inventory_bounds_and_identity() { - assert!(request(Vec::new()).validate().is_err()); - assert!(request(vec![shard(1)]).validate().is_ok()); - assert!(request(vec![shard(1), shard(2)]).validate().is_err()); - assert!(request(vec![shard(1), shard(1)]).validate().is_err()); + let range = ApplicationContractError::InvalidRange { + field: "remote query expected shard inventory", + }; + let inconsistent = ApplicationContractError::Inconsistent { + field: "remote query expected shard inventory", + }; + assert_eq!(request(Vec::new()).validate(), Err(range.clone())); + let accepted = request(vec![shard(1)]); + assert_eq!(accepted.validate(), Ok(())); + assert_eq!(accepted.expected_shards[0].shard_id, "shard.remote-query.1"); + assert_eq!(request(vec![shard(1), shard(2)]).validate(), Err(range)); + assert_eq!( + request(vec![shard(1), shard(1)]).validate(), + Err(inconsistent.clone()) + ); let mut mixed = shard(2); mixed.brain_id = "brain.other".to_owned(); - assert!(request(vec![shard(1), mixed]).validate().is_err()); + assert_eq!(request(vec![shard(1), mixed]).validate(), Err(inconsistent)); } #[test] fn remote_query_request_binds_inventory_to_expected_fence() { let mut mismatched_brain = request(vec![shard(1)]); mismatched_brain.expected_shards[0].brain_id = "brain.other".into(); - assert!(mismatched_brain.validate().is_err()); + assert_eq!( + mismatched_brain.validate(), + Err(ApplicationContractError::Inconsistent { + field: "remote query authority inventory binding", + }) + ); let mut mismatched_shard = request(vec![shard(1)]); mismatched_shard.expected_shards[0].shard_id = "shard.other".into(); - assert!(mismatched_shard.validate().is_err()); + assert_eq!( + mismatched_shard.validate(), + Err(ApplicationContractError::Inconsistent { + field: "remote query authority inventory binding", + }) + ); let mut mismatched_generation = request(vec![shard(1)]); mismatched_generation.expected_shards[0].generation_id = "generation.other".into(); - assert!(mismatched_generation.validate().is_err()); + assert_eq!( + mismatched_generation.validate(), + Err(ApplicationContractError::Inconsistent { + field: "remote query authority inventory binding", + }) + ); } #[test] fn remote_query_request_rejects_invalid_shard_identifiers() { let mut invalid = shard(1); invalid.generation_id = " generation.remote-query ".to_owned(); - assert!(request(vec![invalid]).validate().is_err()); + assert_eq!( + request(vec![invalid]).validate(), + Err(ApplicationContractError::InvalidIdentifier { + field: "remote query generation identity", + }) + ); } #[test] diff --git a/crates/tracedecay-contracts/src/result/problem/tests.rs b/crates/tracedecay-contracts/src/result/problem/tests.rs index 69ba848bee..8ff510da1f 100644 --- a/crates/tracedecay-contracts/src/result/problem/tests.rs +++ b/crates/tracedecay-contracts/src/result/problem/tests.rs @@ -1,5 +1,7 @@ use tracedecay_domain::errors::TraceDecayError; +use crate::ApplicationContractError; + use super::{ ApplicationExecutionFailureClassV1, ApplicationProblem, ApplicationProblemKind, ApplicationUnavailableClassV1, CancellationStage, LegalAction, ProblemTerminality, @@ -80,12 +82,27 @@ fn cancellation_after_effect_or_during_reconciliation_is_not_a_no_effect_termina CancellationStage::Reconciling, CancellationStage::AfterCommit, ] { - assert!(ApplicationProblem::cancelled(stage).is_err()); - assert!(ApplicationProblem::timed_out(stage).is_err()); + assert_eq!( + ApplicationProblem::cancelled(stage), + Err(ApplicationContractError::Inconsistent { + field: "application problem cancellation stage", + }) + ); + assert_eq!( + ApplicationProblem::timed_out(stage), + Err(ApplicationContractError::Inconsistent { + field: "application problem cancellation stage", + }) + ); let wire = serde_json::json!({ "kind": "cancelled", "stage": stage, "retry": "never", "legal_actions": [] }); - assert!(serde_json::from_value::(wire).is_err()); + assert_eq!( + serde_json::from_value::(wire) + .unwrap_err() + .to_string(), + "application problem cancellation stage is inconsistent with the application contract" + ); } } diff --git a/crates/tracedecay-contracts/src/storage/identity.rs b/crates/tracedecay-contracts/src/storage/identity.rs index f61ed09a11..8a105ffda9 100644 --- a/crates/tracedecay-contracts/src/storage/identity.rs +++ b/crates/tracedecay-contracts/src/storage/identity.rs @@ -116,9 +116,12 @@ mod tests { #[test] fn store_key_rejects_empty_untrimmed_and_control() { - assert!(StoreKeyV1::new("").is_err()); - assert!(StoreKeyV1::new(" leading").is_err()); - assert!(StoreKeyV1::new("ctrl\u{0}char").is_err()); + let rejected = ApplicationContractError::InvalidIdentifier { + field: "storage store key", + }; + assert_eq!(StoreKeyV1::new("").unwrap_err(), rejected); + assert_eq!(StoreKeyV1::new(" leading").unwrap_err(), rejected); + assert_eq!(StoreKeyV1::new("ctrl\u{0}char").unwrap_err(), rejected); assert_eq!( StoreKeyV1::new("sessions.db").expect("valid").as_str(), "sessions.db" @@ -140,9 +143,14 @@ mod tests { #[test] fn free_page_ratio_new_rejects_out_of_range() { - assert!(FreePageRatioV1::new(-0.1).is_err()); - assert!(FreePageRatioV1::new(1.5).is_err()); - assert!(FreePageRatioV1::new(f64::NAN).is_err()); - assert!(FreePageRatioV1::new(0.5).is_ok()); + let rejected = ApplicationContractError::InvalidRange { + field: "storage free page ratio", + }; + assert_eq!(FreePageRatioV1::new(-0.1).unwrap_err(), rejected); + assert_eq!(FreePageRatioV1::new(1.5).unwrap_err(), rejected); + assert_eq!(FreePageRatioV1::new(f64::NAN).unwrap_err(), rejected); + assert_eq!(FreePageRatioV1::new(0.0).expect("zero").as_f64(), 0.0); + assert_eq!(FreePageRatioV1::new(0.5).expect("half").as_f64(), 0.5); + assert_eq!(FreePageRatioV1::new(1.0).expect("full").as_f64(), 1.0); } } diff --git a/crates/tracedecay-contracts/tests/contracts_suite/source_edit_effect.rs b/crates/tracedecay-contracts/tests/contracts_suite/source_edit_effect.rs index 62aa6eaf71..e9be7e0ad6 100644 --- a/crates/tracedecay-contracts/tests/contracts_suite/source_edit_effect.rs +++ b/crates/tracedecay-contracts/tests/contracts_suite/source_edit_effect.rs @@ -1,11 +1,11 @@ use crate::common; use tracedecay_contracts::{ - EffectId, IdempotencyKey, RenamePreviewAcceptanceV1, RenameSymbolBindingV1, - SourceEditEffectProofV1, SourceEditEffectRequestV1, SourceEditInvocationV1, SourceEditKind, - SourceEditReconciliationDispositionV1, SourceEditReconciliationInvocationV1, - SourceEditReconciliationRequestV1, SourceEditRequest, SourceEditRollbackInvocationV1, - source_edit_operation, source_edit_reconciliation_operation, + ApplicationContractError, EffectId, IdempotencyKey, RenamePreviewAcceptanceV1, + RenameSymbolBindingV1, SourceEditEffectProofV1, SourceEditEffectRequestV1, + SourceEditInvocationV1, SourceEditKind, SourceEditReconciliationDispositionV1, + SourceEditReconciliationInvocationV1, SourceEditReconciliationRequestV1, SourceEditRequest, + SourceEditRollbackInvocationV1, source_edit_operation, source_edit_reconciliation_operation, }; use tracedecay_domain::configuration::ConfigurationRevisionId; use tracedecay_domain::{PrivacyDomainId, UtcMicros}; @@ -47,7 +47,12 @@ fn source_edit_effect_requires_the_exact_current_grant() { let mut request = request(); request.authority.grant_revision += 1; - assert!(request.validate().is_err()); + assert_eq!( + request.validate(), + Err(ApplicationContractError::Inconsistent { + field: "source edit request current grant", + }) + ); } #[test] @@ -55,7 +60,12 @@ fn source_edit_effect_rejects_zero_catalog_revision() { let mut request = request(); request.proof.catalog_revision = 0; - assert!(request.validate().is_err()); + assert_eq!( + request.validate(), + Err(ApplicationContractError::ZeroValue { + field: "source edit effect proof catalog revision", + }) + ); } #[test] @@ -63,7 +73,12 @@ fn source_edit_effect_rejects_zero_privacy_key_epoch() { let mut request = request(); request.proof.privacy_key_epoch = 0; - assert!(request.validate().is_err()); + assert_eq!( + request.validate(), + Err(ApplicationContractError::ZeroValue { + field: "source edit effect proof privacy key epoch", + }) + ); } #[test] diff --git a/crates/tracedecay-domain/src/code_intelligence/index.rs b/crates/tracedecay-domain/src/code_intelligence/index.rs index 0031fe89db..6a82381198 100644 --- a/crates/tracedecay-domain/src/code_intelligence/index.rs +++ b/crates/tracedecay-domain/src/code_intelligence/index.rs @@ -635,16 +635,29 @@ mod tests { #[test] fn generation_manifest_requires_matching_canonical_language_revisions() { - generation_manifest() - .validate() - .expect("canonical generation manifest"); + let accepted = generation_manifest(); + accepted.validate().expect("canonical generation manifest"); + assert_eq!( + accepted.generation_id.as_str(), + "generation.v1.aaaaaaaa.00000002" + ); let mut reordered = generation_manifest(); reordered.grammar_revisions.reverse(); - assert!(reordered.validate().is_err()); + assert_eq!( + reordered.validate(), + Err(DomainError::NonCanonical { + field: "generation grammar revisions", + }) + ); let mut mismatched = generation_manifest(); mismatched.extractor_revisions.pop(); - assert!(mismatched.validate().is_err()); + assert_eq!( + mismatched.validate(), + Err(DomainError::SnapshotMismatch { + field: "generation language revision sets", + }) + ); } } diff --git a/crates/tracedecay-domain/src/code_intelligence/language.rs b/crates/tracedecay-domain/src/code_intelligence/language.rs index 19b0c39e35..f75af7099b 100644 --- a/crates/tracedecay-domain/src/code_intelligence/language.rs +++ b/crates/tracedecay-domain/src/code_intelligence/language.rs @@ -187,18 +187,35 @@ mod tests { #[test] fn descriptor_requires_sorted_unique_aliases_extensions_and_root_markers() { - descriptor().validate().expect("canonical descriptor"); + let accepted = descriptor(); + accepted.validate().expect("canonical descriptor"); + assert_eq!(accepted.language.as_str(), "rust"); let mut duplicate_alias = descriptor(); duplicate_alias.aliases.push("rust".to_owned()); - assert!(duplicate_alias.validate().is_err()); + assert_eq!( + duplicate_alias.validate(), + Err(DomainError::NonCanonical { + field: "language descriptor alias order", + }) + ); let mut duplicate_extension = descriptor(); duplicate_extension.extensions.push("rs".to_owned()); - assert!(duplicate_extension.validate().is_err()); + assert_eq!( + duplicate_extension.validate(), + Err(DomainError::NonCanonical { + field: "language descriptor extension order", + }) + ); let mut reordered_roots = descriptor(); reordered_roots.root_markers.reverse(); - assert!(reordered_roots.validate().is_err()); + assert_eq!( + reordered_roots.validate(), + Err(DomainError::NonCanonical { + field: "language descriptor root marker order", + }) + ); } } diff --git a/crates/tracedecay-domain/src/code_intelligence/search.rs b/crates/tracedecay-domain/src/code_intelligence/search.rs index 34bac4caa0..07698fa466 100644 --- a/crates/tracedecay-domain/src/code_intelligence/search.rs +++ b/crates/tracedecay-domain/src/code_intelligence/search.rs @@ -1793,8 +1793,19 @@ mod tests { #[test] fn bounded_sanitized_text_enforces_the_chunk_bound() { - assert!(BoundedSanitizedText::new("x".repeat(MAX_CHUNK_TEXT_BYTES)).is_ok()); - assert!(BoundedSanitizedText::new("x".repeat(MAX_CHUNK_TEXT_BYTES + 1)).is_err()); + let at_limit = "x".repeat(65_536); + assert_eq!( + BoundedSanitizedText::new(at_limit.clone()) + .expect("64 KiB chunk text is admitted") + .as_str(), + at_limit + ); + assert_eq!( + BoundedSanitizedText::new("x".repeat(65_537)).unwrap_err(), + DomainError::UnsafeText { + field: "bounded sanitized chunk text", + } + ); } #[test] diff --git a/crates/tracedecay-domain/src/configuration/topology.rs b/crates/tracedecay-domain/src/configuration/topology.rs index ace8747122..1a339b1619 100644 --- a/crates/tracedecay-domain/src/configuration/topology.rs +++ b/crates/tracedecay-domain/src/configuration/topology.rs @@ -907,6 +907,7 @@ pub fn safe_work_topology_policy_v1() -> WorkTopologyPolicyV1 { mod tests { use super::*; use crate::configuration::ProtectedChange; + use crate::research::DomainError; #[test] fn github_stack_requires_probe_and_standard_fallback() { @@ -931,11 +932,13 @@ mod tests { let mut weakened = safe_work_topology_policy_v1(); weakened.protected_refs.remove(0); assert!(!weakened.meets_protected_ref_floor()); - assert!(weakened.validate().is_err()); - assert!( - ProtectedChange::ReplaceWorkTopologyPolicy(weakened) - .validate() - .is_err() + let missing_floor = DomainError::NonCanonical { + field: "protected ref floor", + }; + assert_eq!(weakened.validate(), Err(missing_floor.clone())); + assert_eq!( + ProtectedChange::ReplaceWorkTopologyPolicy(weakened).validate(), + Err(missing_floor) ); } @@ -955,6 +958,11 @@ mod tests { policy.placement = WorktreePlacementModeV1::ConfiguredRoot( WorktreePlacementRootId::new("root.missing").unwrap(), ); - assert!(policy.validate().is_err()); + assert_eq!( + policy.validate(), + Err(DomainError::UnknownReference { + field: "configured worktree placement root", + }) + ); } } diff --git a/crates/tracedecay-domain/src/feedback/ci_localization.rs b/crates/tracedecay-domain/src/feedback/ci_localization.rs index 574cbd4742..a22842bfb5 100644 --- a/crates/tracedecay-domain/src/feedback/ci_localization.rs +++ b/crates/tracedecay-domain/src/feedback/ci_localization.rs @@ -409,7 +409,7 @@ impl CiFailureLocalizationResultV1 { #[cfg(test)] mod tests { use super::*; - use crate::research::{CommitId, ProjectId, RepositoryId, WorktreeId}; + use crate::research::{CommitId, DomainError, ProjectId, RepositoryId, WorktreeId}; fn result() -> CiFailureLocalizationResultV1 { let scope = FeedbackScopeV1 { @@ -453,14 +453,38 @@ mod tests { #[test] fn complete_ci_localization_requires_exact_generation_evidence() { - assert!(result().validate().is_err()); + assert_eq!( + result().validate(), + Err(DomainError::NonCanonical { + field: "complete ci failure generation evidence", + }) + ); + let mut complete = result(); + complete.generation = Some(CiFailureGenerationEvidenceV1 { + generation_id: CodeGenerationId::new("generation.ci").expect("generation"), + retrieval_anchor_id: RetrievalAnchorId::new("anchor.ci.generation").expect("anchor"), + }); + assert_eq!(complete.validate(), Ok(())); + assert_eq!( + complete + .generation + .expect("generation evidence") + .generation_id + .as_str(), + "generation.ci" + ); } #[test] fn ci_provider_state_and_coverage_cannot_be_collapsed() { let mut mismatched = result(); mismatched.state = CiFailureLocalizationStateV1::Partial; - assert!(mismatched.validate().is_err()); + assert_eq!( + mismatched.validate(), + Err(DomainError::NonCanonical { + field: "ci failure localization coverage", + }) + ); } #[test] @@ -472,10 +496,15 @@ mod tests { generation_id: CodeGenerationId::new("generation.denied").unwrap(), retrieval_anchor_id: RetrievalAnchorId::new("anchor.denied").unwrap(), }); - assert!(denied.validate().is_err()); + assert_eq!( + denied.validate(), + Err(DomainError::NonCanonical { + field: "unavailable ci localization evidence", + }) + ); denied.generation = None; - assert!(denied.validate().is_ok()); + assert_eq!(denied.validate(), Ok(())); let mut unavailable = result(); unavailable.state = CiFailureLocalizationStateV1::Unavailable; @@ -484,8 +513,13 @@ mod tests { target: CiInertRerunTargetV1::Workflow, retrieval_anchor_id: None, }); - assert!(unavailable.validate().is_err()); + assert_eq!( + unavailable.validate(), + Err(DomainError::NonCanonical { + field: "unavailable ci localization evidence", + }) + ); unavailable.rerun_hints.clear(); - assert!(unavailable.validate().is_ok()); + assert_eq!(unavailable.validate(), Ok(())); } } diff --git a/crates/tracedecay-domain/src/feedback/proximity.rs b/crates/tracedecay-domain/src/feedback/proximity.rs index b6077d04d3..f7c0ec4893 100644 --- a/crates/tracedecay-domain/src/feedback/proximity.rs +++ b/crates/tracedecay-domain/src/feedback/proximity.rs @@ -409,6 +409,7 @@ impl ProximityContributionV1 { #[cfg(test)] mod tests { use super::*; + use crate::research::DomainError; fn concealed_private_contribution() -> ProximityContributionV1 { ProximityContributionV1 { @@ -447,8 +448,14 @@ mod tests { fn concealed_proximity_requires_matching_coverage() { let mut contribution = concealed_private_contribution(); contribution.inclusion = ProximityInclusionV1::Denied; - assert!(contribution.validate().is_err()); + assert_eq!( + contribution.validate(), + Err(DomainError::NonCanonical { + field: "proximity inclusion coverage", + }) + ); contribution.coverage = ProximityCoverageV1::Denied; - assert!(contribution.validate().is_ok()); + assert_eq!(contribution.validate(), Ok(())); + assert_eq!(contribution.coverage, ProximityCoverageV1::Denied); } } diff --git a/dashboard/src/app/shell/StatusStrip.dom.test.tsx b/dashboard/src/app/shell/StatusStrip.dom.test.tsx index cd7210ae43..6136e0028b 100644 --- a/dashboard/src/app/shell/StatusStrip.dom.test.tsx +++ b/dashboard/src/app/shell/StatusStrip.dom.test.tsx @@ -91,7 +91,7 @@ describe('StatusStrip', () => { sync.value = { kind: 'unmounted' }; render(); - expect(screen.getByText('no stream')).toBeTruthy(); + expect(screen.getByText('no stream').textContent).toBe('no stream'); expect(screen.queryByText('synced')).toBeNull(); }); diff --git a/dashboard/src/ui/ActivityColumns.dom.test.tsx b/dashboard/src/ui/ActivityColumns.dom.test.tsx index a761767be7..e0171cfa16 100644 --- a/dashboard/src/ui/ActivityColumns.dom.test.tsx +++ b/dashboard/src/ui/ActivityColumns.dom.test.tsx @@ -16,7 +16,7 @@ describe('CapacityBar', () => { , ); - expect(getByText('free pages unknown')).toBeTruthy(); + expect(getByText('free pages unknown').textContent).toBe('free pages unknown'); // No bar at all: neither the fill that would read as a used fraction nor // the "0.0% free pages" label that would read as a measurement. expect(queryByRole('img')).toBeNull(); @@ -25,7 +25,7 @@ describe('CapacityBar', () => { it('says the size is unknown when there is no total', () => { const { getByText } = render(); - expect(getByText('size unknown')).toBeTruthy(); + expect(getByText('size unknown').textContent).toBe('size unknown'); }); it('draws and announces the measured free share when both figures arrive', () => { diff --git a/dashboard/src/ui/StateChip.dom.test.tsx b/dashboard/src/ui/StateChip.dom.test.tsx index a866359242..087e6bc399 100644 --- a/dashboard/src/ui/StateChip.dom.test.tsx +++ b/dashboard/src/ui/StateChip.dom.test.tsx @@ -100,7 +100,7 @@ describe('StateChip', () => { it('renders an optional detail suffix alongside the label', () => { render(); - expect(screen.getByText('Stale')).toBeTruthy(); + expect(screen.getByText('Stale').textContent).toBe('Stale'); expect(screen.getByText(/12m ago/)).toBeTruthy(); }); }); diff --git a/dashboard/src/ui/instrument.dom.test.tsx b/dashboard/src/ui/instrument.dom.test.tsx index f9e46fce41..2392688b88 100644 --- a/dashboard/src/ui/instrument.dom.test.tsx +++ b/dashboard/src/ui/instrument.dom.test.tsx @@ -23,8 +23,8 @@ describe('MeterRow', () => { , ); - expect(getByText('tool_calls')).toBeTruthy(); - expect(getByText('1,945')).toBeTruthy(); + expect(getByText('tool_calls').textContent).toBe('tool_calls'); + expect(getByText('1,945').textContent).toBe('1,945'); expect(container.querySelector('.td-meter-fill')?.style.width).toBe('25%'); // The rail restates a number printed beside it, so it is redundant to a // screen reader rather than an unlabelled image. diff --git a/dashboard/src/workspaces/agents/AgentFailureContext.dom.test.tsx b/dashboard/src/workspaces/agents/AgentFailureContext.dom.test.tsx index 4edcd3a5fc..a905021276 100644 --- a/dashboard/src/workspaces/agents/AgentFailureContext.dom.test.tsx +++ b/dashboard/src/workspaces/agents/AgentFailureContext.dom.test.tsx @@ -87,8 +87,8 @@ describe('AgentFailureContext', () => { it('reads the failures off the served tape and says what the tape is', () => { renderContext(readAttemptFailures(attempts())); const tape = document.querySelector('[data-agent-failure-tape="2"]')!; - expect(within(tape as HTMLElement).getByText('tracedecay_read')).toBeTruthy(); - expect(within(tape as HTMLElement).getByText('Bash')).toBeTruthy(); + expect(within(tape as HTMLElement).getByText('tracedecay_read').textContent).toBe('tracedecay_read'); + expect(within(tape as HTMLElement).getByText('Bash').textContent).toBe('Bash'); expect(within(tape as HTMLElement).queryByText('tracedecay_grep')).toBeNull(); expect(screen.getByText(/nothing here explains why any of them failed/)).toBeTruthy(); }); @@ -171,7 +171,7 @@ describe('AgentFailureContext', () => { ); expect(document.querySelector('[data-agent-attempt-failures="unavailable"]')).toBeTruthy(); - expect(screen.getByText('Source unavailable')).toBeTruthy(); + expect(screen.getByText('Source unavailable').textContent).toBe('Source unavailable'); expect(screen.getByText(/no failure count is drawn from it/)).toBeTruthy(); const panel = screen.getByRole('region', { name: 'Attempt failures' }); expect(within(panel).queryByText(/observed attempts on graph version/)).toBeNull(); @@ -187,7 +187,7 @@ describe('AgentFailureContext', () => { ); expect(document.querySelector('[data-agent-attempt-failures="refused"]')).toBeTruthy(); - expect(screen.getByText('Denied')).toBeTruthy(); + expect(screen.getByText('Denied').textContent).toBe('Denied'); expect(screen.getByText(/there is nothing to report as zero/)).toBeTruthy(); // The analytics half of the panel is untouched: one authority refusing does // not blank the other. @@ -197,7 +197,7 @@ describe('AgentFailureContext', () => { it('reports a pending attempt read as pending', () => { renderContext(readAttemptFailures(undefined)); const panel = screen.getByRole('region', { name: 'Attempt failures' }); - expect(within(panel).getByText('Loading')).toBeTruthy(); + expect(within(panel).getByText('Loading').textContent).toBe('Loading'); expect(panel.getAttribute('data-agent-attempt-failures')).toBeNull(); }); }); diff --git a/dashboard/src/workspaces/agents/AgentHandoffs.dom.test.tsx b/dashboard/src/workspaces/agents/AgentHandoffs.dom.test.tsx index 84ccf5cb75..d4adcb737b 100644 --- a/dashboard/src/workspaces/agents/AgentHandoffs.dom.test.tsx +++ b/dashboard/src/workspaces/agents/AgentHandoffs.dom.test.tsx @@ -61,18 +61,18 @@ describe('AgentHandoffs', () => { const table = screen.getByRole('table'); // Both handoffs, and the actors on either end of each. - expect(within(table).getByText('actor.planner')).toBeTruthy(); + expect(within(table).getByText('actor.planner').textContent).toBe('actor.planner'); expect(within(table).getAllByText('actor.builder').length).toBe(2); - expect(within(table).getByText('actor.review')).toBeTruthy(); + expect(within(table).getByText('actor.review').textContent).toBe('actor.review'); // The evidence AND the unknowns. A row that printed only the evidence would // show a handoff carrying an open question as finished work. expect( within(table).getByText('whether the daemon stamps an actor identity'), ).toBeTruthy(); - expect(within(table).getByText('evidence.tests-green')).toBeTruthy(); + expect(within(table).getByText('evidence.tests-green').textContent).toBe('evidence.tests-green'); // The handoff that declared none says so rather than leaving a blank cell. - expect(within(table).getByText('none declared')).toBeTruthy(); + expect(within(table).getByText('none declared').textContent).toBe('none declared'); }); it('carries the actor rollup as text and not only as a rail', () => { @@ -81,7 +81,7 @@ describe('AgentHandoffs', () => { // have to be readable as characters. `builder` handed one on and received // one; `planner` handed one on and received none. const rollup = screen.getByText(/actors on the frontier/).parentElement!; - expect(within(rollup).getByText('1↦1')).toBeTruthy(); + expect(within(rollup).getByText('1↦1').textContent).toBe('1↦1'); expect(within(rollup).getAllByText('1↦0').length).toBeGreaterThan(0); }); @@ -96,7 +96,7 @@ describe('AgentHandoffs', () => { />, ); - expect(screen.getByText('Offline')).toBeTruthy(); + expect(screen.getByText('Offline').textContent).toBe('Offline'); expect(screen.getByText(/the daemon could not be reached/)).toBeTruthy(); expect(screen.getByText(/there is no frontier to be empty/)).toBeTruthy(); // No count of any kind, and above all no zero. @@ -107,7 +107,7 @@ describe('AgentHandoffs', () => { it('reports a pending read as pending rather than as no handoffs', () => { render(); - expect(screen.getByText('Loading')).toBeTruthy(); + expect(screen.getByText('Loading').textContent).toBe('Loading'); expect(screen.queryByText(/no handoff/)).toBeNull(); }); diff --git a/dashboard/src/workspaces/agents/AgentToolActivity.dom.test.tsx b/dashboard/src/workspaces/agents/AgentToolActivity.dom.test.tsx index 2a606ea49b..040de14375 100644 --- a/dashboard/src/workspaces/agents/AgentToolActivity.dom.test.tsx +++ b/dashboard/src/workspaces/agents/AgentToolActivity.dom.test.tsx @@ -46,8 +46,8 @@ describe('AgentToolActivity', () => { expect(headline.textContent).toContain('1,000 tool calls in the window'); expect(headline.textContent).toContain('0.40 per message'); const split = document.querySelector('[data-agent-tool-split="drawn"]')!; - expect(within(split as HTMLElement).getByText('750')).toBeTruthy(); - expect(within(split as HTMLElement).getByText('250')).toBeTruthy(); + expect(within(split as HTMLElement).getByText('750').textContent).toBe('750'); + expect(within(split as HTMLElement).getByText('250').textContent).toBe('250'); expect(within(split as HTMLElement).getByText(/640 of them were calls into/)).toBeTruthy(); }); @@ -79,7 +79,7 @@ describe('AgentToolActivity', () => { const codex = document.querySelector('[data-agent-attribution-agent="Codex"]')! as HTMLElement; // Three rows on the tape, across two sessions, and the tools it reached for // are readable as text rather than only encoded in a rail. - expect(within(codex).getByText('3')).toBeTruthy(); + expect(within(codex).getByText('3').textContent).toBe('3'); expect(within(codex).getByText(/2 sessions · tracedecay_grep 2 · Bash 1/)).toBeTruthy(); // A suffix is not a total, and the surface says which it is. expect(screen.getByText(/a recent suffix/)).toBeTruthy(); diff --git a/dashboard/src/workspaces/agents/AgentsPage.dom.test.tsx b/dashboard/src/workspaces/agents/AgentsPage.dom.test.tsx index cb6a5b44b2..ea8f47ca7c 100644 --- a/dashboard/src/workspaces/agents/AgentsPage.dom.test.tsx +++ b/dashboard/src/workspaces/agents/AgentsPage.dom.test.tsx @@ -130,8 +130,8 @@ describe('AgentsPage read coverage', () => { renderAgents(); expect(await screen.findByText('Codex')).toBeTruthy(); - expect(screen.getByText('42')).toBeTruthy(); - expect(screen.getByText('Claude')).toBeTruthy(); + expect(screen.getByText('42').textContent).toBe('42'); + expect(screen.getByText('Claude').textContent).toBe('Claude'); expect(screen.getByText(/sessions per managed subagent · source: sessions/i)).toBeTruthy(); }); @@ -191,11 +191,11 @@ describe('AgentsPage read coverage', () => { // Tool activity lives on the demoted telemetry register, which renders // once its own usage read lands — awaited rather than assumed. expect(await screen.findByText('Tool activity')).toBeTruthy(); - expect(screen.getByText('Failure context')).toBeTruthy(); + expect(screen.getByText('Failure context').textContent).toBe('Failure context'); // Tool activity is fed by the diagnostics read that landed. expect(await screen.findByText('through MCP')).toBeTruthy(); - expect(screen.getByText('not through MCP')).toBeTruthy(); + expect(screen.getByText('not through MCP').textContent).toBe('not through MCP'); expect(screen.getByText(/Codex/)).toBeTruthy(); // The failure accounting off the same read. diff --git a/dashboard/src/workspaces/brain/BrainInteraction.dom.test.tsx b/dashboard/src/workspaces/brain/BrainInteraction.dom.test.tsx index e0b888611d..aded9f0546 100644 --- a/dashboard/src/workspaces/brain/BrainInteraction.dom.test.tsx +++ b/dashboard/src/workspaces/brain/BrainInteraction.dom.test.tsx @@ -45,11 +45,11 @@ describe('Brain exact interaction identity', () => { it('shares pointer and keyboard inspection without scope or activity changes', async () => { mount(); fireEvent.mouseEnter(await screen.findByRole('button', { name: 'Canvas project' })); - expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p1')).toBeTruthy(); + expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p1').textContent).toBe('/p1'); expect(graph.activation?.warm).toBe(false); expect(useScope.getState().scope.kind).toBe('all'); fireEvent.focus(screen.getByRole('button', { name: /^p2/ })); - expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p2')).toBeTruthy(); + expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p2').textContent).toBe('/p2'); fireEvent.keyDown(screen.getByRole('button', { name: /^p2/ }), { key: 'Escape' }); expect(screen.queryByRole('region', { name: 'Inspected project' })).toBeNull(); expect(graph.activation?.warm).toBe(false); @@ -70,7 +70,7 @@ describe('Brain exact interaction identity', () => { expect(graph.activation?.heatOf('p2')).toBe(0); fireEvent.click(screen.getByText(/Inspect admitted events/)); fireEvent.click(screen.getByRole('button', { name: 'hook_activity · run:activity:1' })); - expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p1')).toBeTruthy(); + expect(within(screen.getByRole('region', { name: 'Inspected project' })).getByText('/p1').textContent).toBe('/p1'); expect(useScope.getState().scope.kind).toBe('all'); fireEvent.click(screen.getByRole('button', { name: 'heartbeat · run:heartbeat:1' })); expect(screen.queryByRole('region', { name: 'Inspected project' })).toBeNull(); diff --git a/dashboard/src/workspaces/brain/ProjectInspector.dom.test.tsx b/dashboard/src/workspaces/brain/ProjectInspector.dom.test.tsx index d66862dbbc..d42ef9023e 100644 --- a/dashboard/src/workspaces/brain/ProjectInspector.dom.test.tsx +++ b/dashboard/src/workspaces/brain/ProjectInspector.dom.test.tsx @@ -13,10 +13,10 @@ describe('project inspection evidence', () => { it('shows exact registry identity and holdings without selecting scope', () => { const open = vi.fn(); render(); - expect(screen.getByText('exact-project-id')).toBeTruthy(); - expect(screen.getByText('/canonical/root')).toBeTruthy(); - expect(screen.getByText('7')).toBeTruthy(); - expect(screen.getByText('1234567890 Unix seconds')).toBeTruthy(); + expect(screen.getByText('exact-project-id').textContent).toBe('exact-project-id'); + expect(screen.getByText('/canonical/root').textContent).toBe('/canonical/root'); + expect(screen.getByText('7').textContent).toBe('7'); + expect(screen.getByText('1234567890 Unix seconds').textContent).toBe('1234567890 Unix seconds'); expect(open).not.toHaveBeenCalled(); fireEvent.click(screen.getByRole('button', { name: 'View repository' })); expect(open).toHaveBeenCalledOnce(); @@ -24,7 +24,7 @@ describe('project inspection evidence', () => { it('does not invent a repository route when the registry has none', () => { render(); - expect(screen.getByText('not recorded')).toBeTruthy(); + expect(screen.getByText('not recorded').textContent).toBe('not recorded'); expect(screen.queryByRole('button', { name: 'View repository' })).toBeNull(); }); }); diff --git a/dashboard/src/workspaces/brain/ScopedBrain.dom.test.tsx b/dashboard/src/workspaces/brain/ScopedBrain.dom.test.tsx index 6ce12dcc09..1c7c564e7a 100644 --- a/dashboard/src/workspaces/brain/ScopedBrain.dom.test.tsx +++ b/dashboard/src/workspaces/brain/ScopedBrain.dom.test.tsx @@ -164,8 +164,8 @@ describe('ScopedBrain', () => { expect(fetchMock.mock.calls.map(([input]) => String(input))).toContain('/api/projects/proj_x'); // Real readouts, from the project's scoped daemon APIs. - expect(screen.getByText('12.9')).toBeTruthy(); - expect(screen.getByText('173')).toBeTruthy(); + expect(screen.getByText('12.9').textContent).toBe('12.9K'); + expect(screen.getByText('173').textContent).toBe('173'); expect(screen.getByRole('heading', { name: 'checkouts' })).toBeTruthy(); }); @@ -208,9 +208,9 @@ describe('ScopedBrain', () => { renderScoped(); expect(await screen.findByText('Pending schema migration')).toBeTruthy(); - expect(screen.getByText('Released-shape convergence in progress')).toBeTruthy(); - expect(screen.getByText('Schema convergence degraded')).toBeTruthy(); - expect(screen.getByText('Schema convergence completed')).toBeTruthy(); + expect(screen.getByText('Released-shape convergence in progress').textContent).toBe('Released-shape convergence in progress'); + expect(screen.getByText('Schema convergence degraded').textContent).toBe('Schema convergence degraded'); + expect(screen.getByText('Schema convergence completed').textContent).toBe('Schema convergence completed'); expect(screen.getByText(/rows 12 done \/ 3 remaining/)).toBeTruthy(); }); @@ -463,7 +463,7 @@ describe('ScopedBrain', () => { ); renderScoped(); - await waitFor(() => expect(screen.getByText('Source unavailable')).toBeTruthy()); + await waitFor(() => expect(screen.getByText('Source unavailable').textContent).toBe('Source unavailable')); expect(screen.getByText(/unable to open \/home\/x\/\.tracedecay\/global\.db/)).toBeTruthy(); }); diff --git a/dashboard/src/workspaces/brain/SignalPanel.dom.test.tsx b/dashboard/src/workspaces/brain/SignalPanel.dom.test.tsx index 880e477b3e..63be88d044 100644 --- a/dashboard/src/workspaces/brain/SignalPanel.dom.test.tsx +++ b/dashboard/src/workspaces/brain/SignalPanel.dom.test.tsx @@ -49,8 +49,8 @@ describe('SignalPanel connection honesty', () => { expect(inspect).toHaveBeenCalledWith(null); const evidence = within(view.getByRole('region', { name: 'Admitted event evidence' })); expect(evidence.getByText(event.eventId)).toBeTruthy(); - expect(evidence.getByText('1700000000000001')).toBeTruthy(); - expect(evidence.getByText('unavailable: event is unscoped')).toBeTruthy(); + expect(evidence.getByText('1700000000000001').textContent).toBe('1700000000000001'); + expect(evidence.getByText('unavailable: event is unscoped').textContent).toBe('unavailable: event is unscoped'); expect(evidence.getByText(/carries no session\/message identity/)).toBeTruthy(); view.rerender(); expect(view.queryByRole('region', { name: 'Admitted event evidence' })).toBeNull(); @@ -69,7 +69,7 @@ describe('SignalPanel connection honesty', () => { it('withholds the rate while offline rather than decaying it to a healthy zero', () => { const { getByText, queryByText } = renderPanel('offline', NOW - 370_000); expect(getByText(/rate · not measured/i)).toBeTruthy(); - expect(getByText('—')).toBeTruthy(); + expect(getByText('—').textContent).toBe('—'); expect(queryByText(/per min/i)).toBeNull(); }); @@ -80,7 +80,7 @@ describe('SignalPanel connection honesty', () => { // Six minutes of quiet on an open stream: the rate is a truthful zero and // the age says how long the quiet has lasted. expect(getByText(/retained · last 60s/i)).toBeTruthy(); - expect(getByText('6m')).toBeTruthy(); + expect(getByText('6m').textContent).toBe('6m'); }); it('distinguishes reconnecting from both', () => { @@ -94,7 +94,7 @@ describe('SignalPanel connection honesty', () => { const { getByText } = render( , ); - expect(getByText('—')).toBeTruthy(); + expect(getByText('—').textContent).toBe('—'); expect(getByText(/no events observed yet/i)).toBeTruthy(); }); }); diff --git a/dashboard/src/workspaces/code/CodeDiagnostics.dom.test.tsx b/dashboard/src/workspaces/code/CodeDiagnostics.dom.test.tsx index dbe7f9cf06..9bbf489e11 100644 --- a/dashboard/src/workspaces/code/CodeDiagnostics.dom.test.tsx +++ b/dashboard/src/workspaces/code/CodeDiagnostics.dom.test.tsx @@ -55,12 +55,12 @@ describe('Code diagnostics panel', () => { renderPanel(); expect(await screen.findByText('mismatched types')).toBeTruthy(); - expect(screen.getByText('in GraphState::open')).toBeTruthy(); - expect(screen.getByText('[E0308]')).toBeTruthy(); - expect(screen.getByText('3')).toBeTruthy(); - expect(screen.getByText('12')).toBeTruthy(); + expect(screen.getByText('in GraphState::open').textContent).toBe('in GraphState::open'); + expect(screen.getByText('[E0308]').textContent).toBe('[E0308]'); + expect(screen.getByText('3').textContent).toBe('3'); + expect(screen.getByText('12').textContent).toBe('12'); // Engine states are the server's words: the crashed engine keeps its error. - expect(screen.getByText('rust')).toBeTruthy(); + expect(screen.getByText('rust').textContent).toBe('rust'); expect(screen.getByText(/tsserver exited with code 1/)).toBeTruthy(); }); @@ -139,7 +139,7 @@ describe('Code diagnostics controls', () => { await screen.findByText(/the mounted engines report no diagnostics/i); await userEvent.click(screen.getByRole('button', { name: /refresh every analyzer engine/i })); - await waitFor(() => expect(screen.getByText('2')).toBeTruthy()); + await waitFor(() => expect(screen.getByText('2').textContent).toBe('2')); expect( calls.some((c) => c.method === 'POST' && c.url.endsWith('/api/plugins/code-diagnostics/refresh')), ).toBe(true); diff --git a/dashboard/src/workspaces/code/CodePage.dom.test.tsx b/dashboard/src/workspaces/code/CodePage.dom.test.tsx index 4d2dd8fa65..59411a212f 100644 --- a/dashboard/src/workspaces/code/CodePage.dom.test.tsx +++ b/dashboard/src/workspaces/code/CodePage.dom.test.tsx @@ -319,7 +319,7 @@ describe('Shared Code: verified exact families of the selected body', () => { expect(await within(conservative).findByText('2')).toBeTruthy(); expect(within(conservative).getByText(/members on this page/i)).toBeTruthy(); expect(within(conservative).getByText(/family incomplete · more members follow/i)).toBeTruthy(); - expect(within(conservative).getByText('Coverage: partial')).toBeTruthy(); + expect(within(conservative).getByText('Coverage: partial').textContent).toBe('Coverage: partial'); expect(conservative.querySelectorAll('[data-member]')).toHaveLength(2); expect(conservative.querySelectorAll('[data-stitch="solid"]').length).toBeGreaterThan(0); await waitFor(() => { @@ -556,11 +556,11 @@ describe('Compare: two exact revisions in one union layout', () => { ).toEqual(['unchanged', 'changed', 'added', 'removed']); // The removed region keeps its former space: a head cell that says so. const removed = regions.querySelector('[data-region-change="removed"]')!; - expect(within(removed as HTMLElement).getByText('not in head')).toBeTruthy(); + expect(within(removed as HTMLElement).getByText('not in head').textContent).toBe('not in head'); const added = regions.querySelector('[data-region-change="added"]')!; - expect(within(added as HTMLElement).getByText('not in base')).toBeTruthy(); - expect(screen.getByText('refs/heads/main')).toBeTruthy(); - expect(screen.getByText('refs/heads/feature')).toBeTruthy(); + expect(within(added as HTMLElement).getByText('not in base').textContent).toBe('not in base'); + expect(screen.getByText('refs/heads/main').textContent).toBe('refs/heads/main'); + expect(screen.getByText('refs/heads/feature').textContent).toBe('refs/heads/feature'); }); it('writes the submitted selection into the URL before reading', async () => { diff --git a/dashboard/src/workspaces/code/IndexFreshness.dom.test.tsx b/dashboard/src/workspaces/code/IndexFreshness.dom.test.tsx index bada7d04aa..f847dc194a 100644 --- a/dashboard/src/workspaces/code/IndexFreshness.dom.test.tsx +++ b/dashboard/src/workspaces/code/IndexFreshness.dom.test.tsx @@ -26,10 +26,10 @@ describe('Code index freshness', () => { }); expect(await screen.findByText('refs/heads/codex/tracedecay-total-redesign-plan')).toBeTruthy(); - expect(screen.getByText('generation.4f21c9')).toBeTruthy(); - expect(screen.getByText('sha256:8ab31c')).toBeTruthy(); - expect(screen.getByText('fresh')).toBeTruthy(); - expect(screen.getByText('Ready')).toBeTruthy(); + expect(screen.getByText('generation.4f21c9').textContent).toBe('generation.4f21c9'); + expect(screen.getByText('sha256:8ab31c').textContent).toBe('sha256:8ab31c'); + expect(screen.getByText('fresh').textContent).toBe('fresh'); + expect(screen.getByText('Ready').textContent).toBe('Ready'); expect(document.querySelector('[data-index-freshness="ready"]')).toBeTruthy(); }); @@ -74,8 +74,8 @@ describe('Code index freshness', () => { }); expect(await screen.findByText('Loading')).toBeTruthy(); - expect(screen.getByText('no sealed generation yet')).toBeTruthy(); - expect(screen.getByText('indexing')).toBeTruthy(); + expect(screen.getByText('no sealed generation yet').textContent).toBe('no sealed generation yet'); + expect(screen.getByText('indexing').textContent).toBe('indexing'); // An absent seal time is unreported, never the epoch. expect(screen.queryByText(/1970-01-01/)).toBeNull(); expect(screen.getAllByText('not reported').length).toBeGreaterThan(0); @@ -195,10 +195,10 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('generation.catchup.01')).toBeTruthy(); + expect(screen.getByText('generation.catchup.01').textContent).toBe('generation.catchup.01'); await advanceTimers(1_001); await advanceTimers(0); - expect(screen.getByText('generation.catchup.02')).toBeTruthy(); + expect(screen.getByText('generation.catchup.02').textContent).toBe('generation.catchup.02'); await advanceTimers(1_001); await advanceTimers(0); expect(screen.queryByText('generation.catchup.01')).toBeNull(); @@ -251,10 +251,10 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('250 / 500 files')).toBeTruthy(); + expect(screen.getByText('250 / 500 files').textContent).toBe('250 / 500 files'); await advanceTimers(1_001); await advanceTimers(0); - expect(screen.getByText('1 / 500 files')).toBeTruthy(); + expect(screen.getByText('1 / 500 files').textContent).toBe('1 / 500 files'); await advanceTimers(1_001); await advanceTimers(0); expect(screen.queryByText('250 / 500 files')).toBeNull(); @@ -304,10 +304,10 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('250 / 500 files')).toBeTruthy(); + expect(screen.getByText('250 / 500 files').textContent).toBe('250 / 500 files'); await advanceTimers(1_001); await advanceTimers(0); - expect(screen.getByText('1 / 500 files')).toBeTruthy(); + expect(screen.getByText('1 / 500 files').textContent).toBe('1 / 500 files'); await advanceTimers(1_001); await advanceTimers(0); expect(screen.queryByText('250 / 500 files')).toBeNull(); @@ -348,10 +348,10 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('generation.catchup.01')).toBeTruthy(); + expect(screen.getByText('generation.catchup.01').textContent).toBe('generation.catchup.01'); await advanceTimers(1_001); await advanceTimers(0); - expect(screen.getByText('Ready')).toBeTruthy(); + expect(screen.getByText('Ready').textContent).toBe('Ready'); expect(fetch).toHaveBeenCalledTimes(2); await advanceTimers(29_998); expect(fetch).toHaveBeenCalledTimes(2); @@ -413,9 +413,9 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('0 / 500 files')).toBeTruthy(); - expect(screen.getByText('no progress for')).toBeTruthy(); - expect(screen.getByText('10m')).toBeTruthy(); + expect(screen.getByText('0 / 500 files').textContent).toBe('0 / 500 files'); + expect(screen.getByText('no progress for').textContent).toBe('no progress for'); + expect(screen.getByText('10m').textContent).toBe('10m'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(1_001); await advanceTimers(0); @@ -425,8 +425,8 @@ describe('Code index freshness', () => { await advanceTimers(1); await advanceTimers(0); expect(fetch).toHaveBeenCalledTimes(2); - expect(screen.getByText('no progress for')).toBeTruthy(); - expect(screen.getByText('10m')).toBeTruthy(); + expect(screen.getByText('no progress for').textContent).toBe('no progress for'); + expect(screen.getByText('10m').textContent).toBe('10m'); await advanceTimers(4_000); await advanceTimers(0); expect(fetch).toHaveBeenCalledTimes(3); @@ -512,10 +512,10 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('0 / 500 files')).toBeTruthy(); + expect(screen.getByText('0 / 500 files').textContent).toBe('0 / 500 files'); await advanceTimers(4_001); await advanceTimers(0); - expect(screen.getByText('12 / 500 files')).toBeTruthy(); + expect(screen.getByText('12 / 500 files').textContent).toBe('12 / 500 files'); expect(fetch).toHaveBeenCalledTimes(2); await advanceTimers(1_001); await advanceTimers(0); @@ -552,8 +552,8 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('Partial')).toBeTruthy(); - expect(screen.getByText('ready · 100.0%')).toBeTruthy(); + expect(screen.getByText('Partial').textContent).toBe('Partial'); + expect(screen.getByText('ready · 100.0%').textContent).toBe('ready · 100.0%'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(1_001); await advanceTimers(0); @@ -617,7 +617,7 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('Loading')).toBeTruthy(); + expect(screen.getByText('Loading').textContent).toBe('Loading'); expect(screen.getByText(/parked: publication authority is corrupt/)).toBeTruthy(); expect(screen.getByText(/does not retry on wake/)).toBeTruthy(); expect(screen.getByText(/restore the owner-private publication store/)).toBeTruthy(); @@ -661,7 +661,7 @@ describe('Code index freshness', () => { await advanceTimers(0); expect(screen.getByText(/parked: publication authority is corrupt/)).toBeTruthy(); expect(screen.getByText(/does not retry on wake/)).toBeTruthy(); - expect(screen.getByText('blocked: publication authority corrupt')).toBeTruthy(); + expect(screen.getByText('blocked: publication authority corrupt').textContent).toBe('blocked: publication authority corrupt'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(1_001); expect(fetch).toHaveBeenCalledTimes(1); @@ -699,7 +699,7 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('blocked: publication authority corrupt')).toBeTruthy(); + expect(screen.getByText('blocked: publication authority corrupt').textContent).toBe('blocked: publication authority corrupt'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(1_001); expect(fetch).toHaveBeenCalledTimes(1); @@ -724,7 +724,7 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('Unsupported')).toBeTruthy(); + expect(screen.getByText('Unsupported').textContent).toBe('Unsupported'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(1_001); expect(fetch).toHaveBeenCalledTimes(1); @@ -749,7 +749,7 @@ describe('Code index freshness', () => { renderWith(); await advanceTimers(0); - expect(screen.getByText('Ready')).toBeTruthy(); + expect(screen.getByText('Ready').textContent).toBe('Ready'); expect(fetch).toHaveBeenCalledTimes(1); await advanceTimers(29_999); expect(fetch).toHaveBeenCalledTimes(1); diff --git a/dashboard/src/workspaces/code/TraceView.dom.test.tsx b/dashboard/src/workspaces/code/TraceView.dom.test.tsx index bc3d86c01a..ea14e1540f 100644 --- a/dashboard/src/workspaces/code/TraceView.dom.test.tsx +++ b/dashboard/src/workspaces/code/TraceView.dom.test.tsx @@ -157,7 +157,7 @@ describe('TraceView', () => { /(\d+) drawn/.exec(screen.getByText(/drawn · ordered by hop/).textContent ?? '')?.[1], ); expect(items.length).toBe(drawnCount); - expect(within(list).getByText('resolve_context')).toBeTruthy(); + expect(within(list).getByText('resolve_context').textContent).toBe('resolve_context'); expect(within(list).getAllByText(/call sites/).length).toBe(items.length); expect(within(list).getAllByText(/hops? (up|down)/).length).toBeGreaterThan(0); }); diff --git a/dashboard/src/workspaces/costs/CanonicalCosts.dom.test.tsx b/dashboard/src/workspaces/costs/CanonicalCosts.dom.test.tsx index d84c0e2dbd..67756cf7f4 100644 --- a/dashboard/src/workspaces/costs/CanonicalCosts.dom.test.tsx +++ b/dashboard/src/workspaces/costs/CanonicalCosts.dom.test.tsx @@ -39,10 +39,10 @@ describe('Canonical cost observations', () => { ); expect(await screen.findByText('provider tokens')).toBeTruthy(); - expect(screen.getByText('1,284,000')).toBeTruthy(); - expect(screen.getByText('per provider usage events · 8,412')).toBeTruthy(); - expect(screen.getByText('saved tokens')).toBeTruthy(); - expect(screen.getByText('per eligible savings calls · 512')).toBeTruthy(); + expect(screen.getByText('1,284,000').textContent).toBe('1,284,000'); + expect(screen.getByText('per provider usage events · 8,412').textContent).toBe('per provider usage events · 8,412'); + expect(screen.getByText('saved tokens').textContent).toBe('saved tokens'); + expect(screen.getByText('per eligible savings calls · 512').textContent).toBe('per eligible savings calls · 512'); }); it('renders an unpriced cost as its reason, never as $0.00 or a zero', async () => { diff --git a/dashboard/src/workspaces/costs/CostsPage.dom.test.tsx b/dashboard/src/workspaces/costs/CostsPage.dom.test.tsx index 965b79714c..4b1a15cb61 100644 --- a/dashboard/src/workspaces/costs/CostsPage.dom.test.tsx +++ b/dashboard/src/workspaces/costs/CostsPage.dom.test.tsx @@ -134,7 +134,7 @@ describe('CostsPage truth claims', () => { // ...and the independent canonical projection still renders its own // measurements rather than being blanked by its neighbour. expect(await screen.findByText('provider tokens')).toBeTruthy(); - expect(screen.getByText('provider queue latency p50')).toBeTruthy(); + expect(screen.getByText('provider queue latency p50').textContent).toBe('provider queue latency p50'); expect(screen.getAllByText('provider_latency_scope_unavailable').length).toBeGreaterThan(0); }); @@ -162,9 +162,9 @@ describe('CostsPage truth claims', () => { expect(await screen.findByText('Execution topology accounting')).toBeTruthy(); expect(await screen.findByText('work execution concurrency width')).toBeTruthy(); - expect(screen.getByText('27')).toBeTruthy(); - expect(screen.getByText('concurrency phase · active')).toBeTruthy(); - expect(screen.getByText('support_floor_unmet')).toBeTruthy(); + expect(screen.getByText('27').textContent).toBe('27'); + expect(screen.getByText('concurrency phase · active').textContent).toBe('concurrency phase · active'); + expect(screen.getByText('support_floor_unmet').textContent).toBe('support_floor_unmet'); expect(screen.queryByText('0 effects')).toBeNull(); expect(screen.getByText(/9 emitted · 2 delayed · 1 dropped · 4 sampled envelopes/i)).toBeTruthy(); expect( @@ -181,7 +181,7 @@ describe('CostsPage truth claims', () => { expect(await screen.findByText('Execution topology accounting')).toBeTruthy(); expect(await screen.findByText('Source unavailable')).toBeTruthy(); - expect(screen.getByText('provider tokens')).toBeTruthy(); + expect(screen.getByText('provider tokens').textContent).toBe('provider tokens'); expect(screen.queryByText('0 effects')).toBeNull(); }); }); diff --git a/dashboard/src/workspaces/delivery/DeliveryPage.dom.test.tsx b/dashboard/src/workspaces/delivery/DeliveryPage.dom.test.tsx index bfba4bf8f0..96a9cd07f3 100644 --- a/dashboard/src/workspaces/delivery/DeliveryPage.dom.test.tsx +++ b/dashboard/src/workspaces/delivery/DeliveryPage.dom.test.tsx @@ -181,7 +181,7 @@ describe('DeliveryPage', () => { await user.click(await screen.findByRole('button', { name: /Admit delivery inbox/ })); expect(screen.queryByText('Unrelated provider PR')).toBeNull(); - expect(screen.getByText('Branch and pull request reference')).toBeTruthy(); + expect(screen.getByText('Branch and pull request reference').textContent).toBe('Branch and pull request reference'); expect(screen.getAllByText(/refs\/heads\/feature\/delivery/).length).toBeGreaterThan(0); expect(screen.getByText(/1 unrelated provider pull request excluded/)).toBeTruthy(); expect(screen.getByTestId('location').textContent).toContain('pr=project.alpha%3Agithub%3A42'); @@ -195,9 +195,9 @@ describe('DeliveryPage', () => { ); const detail = await screen.findByRole('region', { name: 'Pull request detail' }); - expect(within(detail).getByText('CI failure')).toBeTruthy(); - expect(within(detail).getByText('anchor.ci.42')).toBeTruthy(); - expect(within(detail).getByText('Overlapping edit')).toBeTruthy(); + expect(within(detail).getByText('CI failure').textContent).toBe('CI failure'); + expect(within(detail).getByText('anchor.ci.42').textContent).toBe('anchor.ci.42'); + expect(within(detail).getByText('Overlapping edit').textContent).toBe('Overlapping edit'); }); it('links to the existing verified Code views', async () => { @@ -219,7 +219,7 @@ describe('DeliveryPage', () => { }); expect(await screen.findByText('Provider not configured')).toBeTruthy(); - expect(screen.getByText('No admitted pull requests')).toBeTruthy(); + expect(screen.getByText('No admitted pull requests').textContent).toBe('No admitted pull requests'); expect(screen.queryByText(/transport/i)).toBeNull(); }); diff --git a/dashboard/src/workspaces/explorer/ExplorerPage.dom.test.tsx b/dashboard/src/workspaces/explorer/ExplorerPage.dom.test.tsx index 74bd9e6d6a..4723be3501 100644 --- a/dashboard/src/workspaces/explorer/ExplorerPage.dom.test.tsx +++ b/dashboard/src/workspaces/explorer/ExplorerPage.dom.test.tsx @@ -351,7 +351,7 @@ describe('ExplorerPage', () => { // the browse state would let two thirds of them back in. await user.click(await screen.findByRole('button', { name: /Using graph search/ })); expect(await screen.findByText('Session context')).toBeTruthy(); - expect(screen.getByText('What each lane searches')).toBeTruthy(); + expect(screen.getByText('What each lane searches').textContent).toBe('What each lane searches'); // Deliberately unscoped: a `dl dt` selector can only ever see terms that // are already inside a list, which is precisely the defect it is supposed @@ -416,9 +416,9 @@ describe('ExplorerPage', () => { name: /Sessions\s*2\s*loaded\s*of 2 matching rows reported/, }), ).toBeTruthy(); - expect(screen.getByText('Coordinator run')).toBeTruthy(); - expect(screen.getByText('explorer-run-fixture')).toBeTruthy(); - expect(screen.getByText('source_local_no_cross_source_merge')).toBeTruthy(); + expect(screen.getByText('Coordinator run').textContent).toBe('Coordinator run'); + expect(screen.getByText('explorer-run-fixture').textContent).toBe('explorer-run-fixture'); + expect(screen.getByText('source_local_no_cross_source_merge').textContent).toBe('source_local_no_cross_source_merge'); expect(screen.getByText(/active-project session store/)).toBeTruthy(); }); @@ -504,11 +504,11 @@ describe('ExplorerPage', () => { const provenance = screen.getByText('Payload provenance').closest('details'); expect(provenance).toBeTruthy(); const payload = within(provenance as HTMLElement); - expect(payload.getByText('name')).toBeTruthy(); - expect(payload.getByText('file_path')).toBeTruthy(); - expect(payload.getByText('degree')).toBeTruthy(); - expect(payload.getByText('graph_search')).toBeTruthy(); - expect(payload.getByText('7')).toBeTruthy(); + expect(payload.getByText('name').textContent).toBe('name'); + expect(payload.getByText('file_path').textContent).toBe('file_path'); + expect(payload.getByText('degree').textContent).toBe('degree'); + expect(payload.getByText('graph_search').textContent).toBe('graph_search'); + expect(payload.getByText('7').textContent).toBe('7'); expect(screen.getByText(/Position 1 in graph endpoint rows/)).toBeTruthy(); }); }); diff --git a/dashboard/src/workspaces/knowledge/KnowledgePage.dom.test.tsx b/dashboard/src/workspaces/knowledge/KnowledgePage.dom.test.tsx index b173ac56e1..05c28c1b16 100644 --- a/dashboard/src/workspaces/knowledge/KnowledgePage.dom.test.tsx +++ b/dashboard/src/workspaces/knowledge/KnowledgePage.dom.test.tsx @@ -239,7 +239,7 @@ describe('KnowledgePage fact detail', () => { await userEvent.click(await screen.findByText('list-truncated fact…')); expect(await screen.findByText('full authoritative fact detail')).toBeTruthy(); - expect(screen.getByText('amari_fhrr')).toBeTruthy(); + expect(screen.getByText('amari_fhrr').textContent).toBe('amari_fhrr'); expect(screen.getByText(/2,048 dimensions/)).toBeTruthy(); expect( calls.some((url) => url.includes('/api/plugins/holographic/fact/fact-project-7')), @@ -283,12 +283,12 @@ describe('KnowledgePage fact detail', () => { it('distinguishes unreported feedback counts from a reported zero', () => { const unknown = render(); - expect(screen.getByText('feedback counts not reported')).toBeTruthy(); + expect(screen.getByText('feedback counts not reported').textContent).toBe('feedback counts not reported'); expect(screen.queryByText('no feedback recorded')).toBeNull(); unknown.unmount(); render(); - expect(screen.getByText('no feedback recorded')).toBeTruthy(); + expect(screen.getByText('no feedback recorded').textContent).toBe('no feedback recorded'); expect(screen.queryByText('feedback counts not reported')).toBeNull(); }); diff --git a/dashboard/src/workspaces/loom/LoomPage.dom.test.tsx b/dashboard/src/workspaces/loom/LoomPage.dom.test.tsx index ef0b70309e..1ab79ec27e 100644 --- a/dashboard/src/workspaces/loom/LoomPage.dom.test.tsx +++ b/dashboard/src/workspaces/loom/LoomPage.dom.test.tsx @@ -608,7 +608,7 @@ describe('LoomPage', () => { ).toBe(true); await userEvent.click(row); expect(await screen.findByText('src/runtime.rs')).toBeTruthy(); - expect(screen.getByText('abc123def456')).toBeTruthy(); + expect(screen.getByText('abc123def456').textContent).toBe('abc123def456'); // The extent is a formatted duration, so `getAllByText('30m').length >= 1` // would pass on any '30m' anywhere on the page — including one printed // against a different term. Read it through the term it belongs to, which @@ -626,9 +626,9 @@ describe('LoomPage', () => { it('reports each causal source with its real authority or dependency', async () => { renderLoom(); await screen.findByText('Deliver Git primitive runtime'); - expect(screen.getByText('Session ↔ commit')).toBeTruthy(); - expect(screen.getByText('Session → edited file')).toBeTruthy(); - expect(screen.getByText('Branch & worktree spans')).toBeTruthy(); + expect(screen.getByText('Session ↔ commit').textContent).toBe('Session ↔ commit'); + expect(screen.getByText('Session → edited file').textContent).toBe('Session → edited file'); + expect(screen.getByText('Branch & worktree spans').textContent).toBe('Branch & worktree spans'); expect(screen.getByText(/commit_sessions/)).toBeTruthy(); }); @@ -651,8 +651,8 @@ describe('LoomPage', () => { await userEvent.click(await screen.findByText('Deliver Git primitive runtime')); expect(await screen.findByText('~12 tokens · o200k approximate')).toBeTruthy(); - expect(screen.getByText('~20 tokens · o200k approximate')).toBeTruthy(); - expect(screen.getByText('tokens unknown')).toBeTruthy(); + expect(screen.getByText('~20 tokens · o200k approximate').textContent).toBe('~20 tokens · o200k approximate'); + expect(screen.getByText('tokens unknown').textContent).toBe('tokens unknown'); }); it('shares reveal, picking, minimap and exact evidence through one URL cursor', async () => { @@ -675,7 +675,7 @@ describe('LoomPage', () => { expect(document.querySelector('[data-event="m1"]')).not.toBeNull(); expect(screen.getByRole('button', { name: 'Inspect stored event m1' })).toBeTruthy(); fireEvent.keyDown(screen.getByRole('button', { name: 'Select stored event m0' }), { key: 'Enter' }); - expect(screen.getByText('stored ordinal 0')).toBeTruthy(); + expect(screen.getByText('stored ordinal 0').textContent).toBe('stored ordinal 0'); await user.click(screen.getByRole('button', { name: 'Zoom into execution' })); expect(screen.getByTestId('loom-url').textContent).toContain('loomWindow='); expect(screen.getByTestId('loom-url').textContent).toContain('loomEvent=m0'); @@ -699,7 +699,7 @@ describe('LoomPage', () => { await user.click(screen.getByRole('button', { name: 'Select stored event m1' })); routes['/api/plugins/hermes-lcm/session/'].body = readyEnvelope({ ...CHAIN, messages: appended.slice(1) }); await act(() => client.invalidateQueries({ queryKey: ['loom', 'chain'] })); - expect(screen.getByText('stored ordinal 1')).toBeTruthy(); + expect(screen.getByText('stored ordinal 1').textContent).toBe('stored ordinal 1'); expect(screen.getByTestId('loom-url').textContent).toContain('loomEvent=m1'); routes['/api/plugins/hermes-lcm/session/'].body = readyEnvelope({ ...CHAIN, messages: appended.slice(2) }); await act(() => client.invalidateQueries({ queryKey: ['loom', 'chain'] })); @@ -767,16 +767,16 @@ describe('LoomPage', () => { await user.click(await screen.findByText('Deliver Git primitive runtime')); expect(await screen.findByText('stored ordinal 2')).toBeTruthy(); - expect(screen.getByText('following loaded tail')).toBeTruthy(); + expect(screen.getByText('following loaded tail').textContent).toBe('following loaded tail'); expect(screen.getByText(/later pages remain outside this replay/)).toBeTruthy(); await user.click(screen.getByRole('button', { name: 'Step to previous stored event' })); - expect(screen.getByText('stored ordinal 1')).toBeTruthy(); + expect(screen.getByText('stored ordinal 1').textContent).toBe('stored ordinal 1'); expect(screen.getByRole('button', { name: 'Return replay to latest loaded event' })).toBeTruthy(); await user.click(screen.getByRole('button', { name: 'Step to previous stored event' })); - expect(screen.getByText('stored ordinal 0')).toBeTruthy(); - expect(screen.getByText('linked compaction boundaries')).toBeTruthy(); + expect(screen.getByText('stored ordinal 0').textContent).toBe('stored ordinal 0'); + expect(screen.getByText('linked compaction boundaries').textContent).toBe('linked compaction boundaries'); expect(screen.queryByText(/checkpoint · depth 1/)).toBeNull(); expect(screen.getByText(/linked boundary is outside this loaded transcript page/)).toBeTruthy(); @@ -786,7 +786,7 @@ describe('LoomPage', () => { expect(screen.getByRole('button', { name: 'Pause replay' })).toBeTruthy(); await user.click(screen.getByRole('button', { name: 'Pause replay' })); await user.click(screen.getByRole('button', { name: 'Return replay to latest loaded event' })); - expect(screen.getByText('following loaded tail')).toBeTruthy(); + expect(screen.getByText('following loaded tail').textContent).toBe('following loaded tail'); }); it('does not render partial commit coverage as a zero result', async () => { @@ -918,7 +918,7 @@ describe('LoomPage', () => { // The busiest-day readout names the failed read as a failure — not as // "unread", which is also what loading looks like; the threads, which // come from a different endpoint, still draw. - expect(screen.getByText('timeline read failed')).toBeTruthy(); + expect(screen.getByText('timeline read failed').textContent).toBe('timeline read failed'); }); it('gives the canvas an accessible description and a real table alongside', async () => { diff --git a/dashboard/src/workspaces/loom/WeaveCanvas.dom.test.tsx b/dashboard/src/workspaces/loom/WeaveCanvas.dom.test.tsx index e6895787c7..20ed3b51f5 100644 --- a/dashboard/src/workspaces/loom/WeaveCanvas.dom.test.tsx +++ b/dashboard/src/workspaces/loom/WeaveCanvas.dom.test.tsx @@ -45,7 +45,7 @@ describe('WeaveCanvas time window', () => { it('starts fitted, with pan and fit disabled', () => { renderCanvas(); expect(screen.getByRole('toolbar', { name: 'Time window' })).toBeTruthy(); - expect(screen.getByText('whole extent')).toBeTruthy(); + expect(screen.getByText('whole extent').textContent).toBe('whole extent'); expect(screen.getByRole('button', { name: 'Fit the whole extent' })).toHaveProperty( 'disabled', true, @@ -80,7 +80,7 @@ describe('WeaveCanvas time window', () => { expect(marks()).toBeLessThan(before); fireEvent.click(screen.getByRole('button', { name: 'Fit the whole extent' })); expect(marks()).toBe(before); - expect(screen.getByText('whole extent')).toBeTruthy(); + expect(screen.getByText('whole extent').textContent).toBe('whole extent'); }); }); diff --git a/dashboard/src/workspaces/observatory/CanonicalObservations.dom.test.tsx b/dashboard/src/workspaces/observatory/CanonicalObservations.dom.test.tsx index b5e013ce6d..efb90032d2 100644 --- a/dashboard/src/workspaces/observatory/CanonicalObservations.dom.test.tsx +++ b/dashboard/src/workspaces/observatory/CanonicalObservations.dom.test.tsx @@ -31,7 +31,7 @@ describe('Observatory canonical observations', () => { // Event flow: the count, and the population it counted out of. expect(await screen.findByText('observability events')).toBeTruthy(); - expect(screen.getByText('4,812')).toBeTruthy(); + expect(screen.getByText('4,812').textContent).toBe('4,812'); expect( screen.getAllByText('per eligible observability events · 4,812').length, ).toBe(3); @@ -43,9 +43,9 @@ describe('Observatory canonical observations', () => { expect(drops?.textContent).toContain('0'); // Latency, converted for reading, with the server's own microseconds kept. - expect(screen.getByText('feedback latency p95')).toBeTruthy(); - expect(screen.getByText('43.25')).toBeTruthy(); - expect(screen.getByText('(43,250 µs)')).toBeTruthy(); + expect(screen.getByText('feedback latency p95').textContent).toBe('feedback latency p95'); + expect(screen.getByText('43.25').textContent).toBe('43.25'); + expect(screen.getByText('(43,250 µs)').textContent).toBe('(43,250 µs)'); }); it('shows an unavailable measurement as its server reason, never as zero', async () => { @@ -111,7 +111,7 @@ describe('Observatory canonical observations', () => { ]); expect(await screen.findByText('Partial')).toBeTruthy(); - expect(screen.getByText('incomplete_metric_coverage')).toBeTruthy(); + expect(screen.getByText('incomplete_metric_coverage').textContent).toBe('incomplete_metric_coverage'); expect(screen.getByText(/not current · watermark analytics:4821/)).toBeTruthy(); }); @@ -136,7 +136,7 @@ describe('Observatory canonical observations', () => { // Two independent axes: the read is partial AND the identity behind it is // seeing a redacted projection. Neither is folded into the other. expect(await screen.findByText('Partial')).toBeTruthy(); - expect(screen.getByText('Redacted')).toBeTruthy(); + expect(screen.getByText('Redacted').textContent).toBe('Redacted'); expect(screen.getByText(/read authorization/)).toBeTruthy(); }); diff --git a/dashboard/src/workspaces/observatory/DoctorInspector.dom.test.tsx b/dashboard/src/workspaces/observatory/DoctorInspector.dom.test.tsx index 6ffeb41538..115bdad148 100644 --- a/dashboard/src/workspaces/observatory/DoctorInspector.dom.test.tsx +++ b/dashboard/src/workspaces/observatory/DoctorInspector.dom.test.tsx @@ -172,9 +172,9 @@ describe('DoctorInspector', () => { renderDoctor(); expect(await screen.findByText('Pending schema migration')).toBeTruthy(); - expect(screen.getByText('Released-shape convergence in progress')).toBeTruthy(); - expect(screen.getByText('Schema convergence degraded')).toBeTruthy(); - expect(screen.getByText('Schema convergence completed')).toBeTruthy(); + expect(screen.getByText('Released-shape convergence in progress').textContent).toBe('Released-shape convergence in progress'); + expect(screen.getByText('Schema convergence degraded').textContent).toBe('Schema convergence degraded'); + expect(screen.getByText('Schema convergence completed').textContent).toBe('Schema convergence completed'); expect(screen.getByText(/pages 4 done \/ 7 remaining/)).toBeTruthy(); expect(screen.getByText(/observation_id=obs-7 projector=session_message/)).toBeTruthy(); }); diff --git a/dashboard/src/workspaces/observatory/ObservatoryPage.dom.test.tsx b/dashboard/src/workspaces/observatory/ObservatoryPage.dom.test.tsx index 8c7283e571..bd797520be 100644 --- a/dashboard/src/workspaces/observatory/ObservatoryPage.dom.test.tsx +++ b/dashboard/src/workspaces/observatory/ObservatoryPage.dom.test.tsx @@ -110,14 +110,14 @@ describe('ObservatoryPage store telemetry', () => { renderObservatory(); await advanceTimers(0); - expect(screen.getByText('generation.scope.alpha')).toBeTruthy(); + expect(screen.getByText('generation.scope.alpha').textContent).toBe('generation.scope.alpha'); await advanceTimers(1_001); await advanceTimers(0); expect(screen.queryByText('generation.scope.alpha')).toBeNull(); act(() => useScope.getState().selectProject('project.beta', 'Project Beta', 'selected')); await advanceTimers(0); - expect(screen.getByText('generation.scope.beta')).toBeTruthy(); + expect(screen.getByText('generation.scope.beta').textContent).toBe('generation.scope.beta'); expect(screen.queryByText('generation.scope.alpha')).toBeNull(); expect(document.querySelectorAll('[data-code-index-generation]').length).toBe(1); }); @@ -162,10 +162,10 @@ describe('ObservatoryPage store telemetry', () => { renderObservatory(); await advanceTimers(0); - expect(screen.getByText('generation.scope.alpha')).toBeTruthy(); + expect(screen.getByText('generation.scope.alpha').textContent).toBe('generation.scope.alpha'); act(() => useScope.getState().selectProject('project.beta', 'Project Beta', 'active')); await advanceTimers(0); - expect(screen.getByText('generation.scope.beta')).toBeTruthy(); + expect(screen.getByText('generation.scope.beta').textContent).toBe('generation.scope.beta'); expect(screen.queryByText('generation.scope.alpha')).toBeNull(); expect(document.querySelectorAll('[data-code-index-generation]').length).toBe(1); }); @@ -249,7 +249,7 @@ describe('ObservatoryPage store telemetry', () => { expect(await screen.findByText('40.0 MiB')).toBeTruthy(); // The capacity bar is drawn for this store rather than withheld, and says // what it does not know instead of filling to 100% at "0.0% free pages". - expect(screen.getByText('free pages unknown')).toBeTruthy(); + expect(screen.getByText('free pages unknown').textContent).toBe('free pages unknown'); expect( screen.getByText(/no page-level sample, so free pages are unmeasured rather than zero/), ).toBeTruthy(); @@ -409,10 +409,10 @@ describe('ObservatoryPage store telemetry', () => { for (const state of ['partial', 'backfilling', 'stale', 'unavailable']) { expect(document.querySelector(`[data-clone-index-state="${state}"]`)).toBeTruthy(); } - expect(screen.getByText('positional fingerprint successor is missing')).toBeTruthy(); - expect(screen.getByText('2 / 5 sealed pages')).toBeTruthy(); - expect(screen.getByText('the sealed lexical artifact is unreadable')).toBeTruthy(); - expect(screen.getByText('unavailable · graph artifact unreadable')).toBeTruthy(); + expect(screen.getByText('positional fingerprint successor is missing').textContent).toBe('positional fingerprint successor is missing'); + expect(screen.getByText('2 / 5 sealed pages').textContent).toBe('2 / 5 sealed pages'); + expect(screen.getByText('the sealed lexical artifact is unreadable').textContent).toBe('the sealed lexical artifact is unreadable'); + expect(screen.getByText('unavailable · graph artifact unreadable').textContent).toBe('unavailable · graph artifact unreadable'); }); }); diff --git a/dashboard/src/workspaces/observatory/PerformanceBudgets.dom.test.tsx b/dashboard/src/workspaces/observatory/PerformanceBudgets.dom.test.tsx index 5a5475624f..d8ebfc179e 100644 --- a/dashboard/src/workspaces/observatory/PerformanceBudgets.dom.test.tsx +++ b/dashboard/src/workspaces/observatory/PerformanceBudgets.dom.test.tsx @@ -32,7 +32,7 @@ describe('Observatory performance budgets', () => { renderBudgets(readModel([]), 'partial', ['incomplete_metric_coverage']); expect(await screen.findByText('Partial')).toBeTruthy(); - expect(screen.getByText('incomplete_metric_coverage')).toBeTruthy(); + expect(screen.getByText('incomplete_metric_coverage').textContent).toBe('incomplete_metric_coverage'); }); it('reports a daemon that never answered as offline rather than as zero budgets', async () => { diff --git a/dashboard/src/workspaces/sessions/SessionInspector.dom.test.tsx b/dashboard/src/workspaces/sessions/SessionInspector.dom.test.tsx index 936bb9e3a6..3b42cfd3a1 100644 --- a/dashboard/src/workspaces/sessions/SessionInspector.dom.test.tsx +++ b/dashboard/src/workspaces/sessions/SessionInspector.dom.test.tsx @@ -86,7 +86,7 @@ describe('Session transcript drill-down', () => { expect(await screen.findByText('token counts shown per loaded message')).toBeTruthy(); expect(screen.queryByText('~0 est. tokens')).toBeNull(); - expect(screen.getByText('token counts unavailable')).toBeTruthy(); + expect(screen.getByText('token counts unavailable').textContent).toBe('token counts unavailable'); }); it('labels visible-content tokenizer counts as approximate', async () => { @@ -111,7 +111,7 @@ describe('Session transcript drill-down', () => { ); expect(await screen.findByText('~13 tokens · o200k approximate')).toBeTruthy(); - expect(screen.getByText('~17 tokens · o200k approximate')).toBeTruthy(); + expect(screen.getByText('~17 tokens · o200k approximate').textContent).toBe('~17 tokens · o200k approximate'); }); it('follows opaque cursors forward and its cursor stack backward', async () => { diff --git a/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx b/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx index cf0ead67d5..87bf221748 100644 --- a/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx +++ b/dashboard/src/workspaces/settings/SettingsPage.dom.test.tsx @@ -74,7 +74,7 @@ describe('SettingsPage authorized changes', () => { const maxFileSize = await screen.findByLabelText('Maximum file size (bytes)'); await user.clear(maxFileSize); await user.type(maxFileSize, '2097152'); - expect(screen.getByText('Unsaved project changes')).toBeTruthy(); + expect(screen.getByText('Unsaved project changes').textContent).toBe('Unsaved project changes'); await user.click(screen.getByRole('button', { name: 'Review project changes' })); const dialog = screen.getByRole('dialog', { name: 'Review project settings change' }); @@ -88,8 +88,8 @@ describe('SettingsPage authorized changes', () => { await user.click(screen.getByRole('button', { name: 'Apply project settings' })); expect(await screen.findByText('Project settings saved')).toBeTruthy(); - expect(screen.getByText('Current project values')).toBeTruthy(); - expect(screen.getByText('Resync recommended')).toBeTruthy(); + expect(screen.getByText('Current project values').textContent).toBe('Current project values'); + expect(screen.getByText('Resync recommended').textContent).toBe('Resync recommended'); expect( calls.map(({ method, url }) => `${method} ${url}`), ).toEqual([ @@ -143,7 +143,7 @@ describe('SettingsPage authorized changes', () => { for (const label of ['Configured', 'Requested', 'Effective', 'Memory-safe']) { expect(screen.getByText(label)).toBeTruthy(); } - expect(screen.getByText('Automatic: all available cores')).toBeTruthy(); + expect(screen.getByText('Automatic: all available cores').textContent).toBe('Automatic: all available cores'); await user.click(screen.getByLabelText('Exact number of cores')); const workers = screen.getByLabelText('Code-index worker count'); await user.clear(workers); @@ -204,8 +204,8 @@ describe('SettingsPage authorized changes', () => { 'TRACEDECAY_INDEX_WORKERS=7 overrides the persisted worker selection for this running daemon.', ), ).toBeTruthy(); - expect(screen.getByText('7 via TRACEDECAY_INDEX_WORKERS')).toBeTruthy(); - expect(screen.getByText('TRACEDECAY_INDEX_WORKERS override')).toBeTruthy(); + expect(screen.getByText('7 via TRACEDECAY_INDEX_WORKERS').textContent).toBe('7 via TRACEDECAY_INDEX_WORKERS'); + expect(screen.getByText('TRACEDECAY_INDEX_WORKERS override').textContent).toBe('TRACEDECAY_INDEX_WORKERS override'); }); it('states that an exact selection is evaluated on restart when current admission limits are unavailable', async () => { @@ -556,7 +556,7 @@ describe('Settings scope authority', () => { }); expect(banner.textContent).toContain('not known yet'); expect(banner.textContent).not.toMatch(/not authorized|read-only project/i); - expect(screen.getByText('Applies to your TraceDecay profile.')).toBeTruthy(); + expect(screen.getByText('Applies to your TraceDecay profile.').textContent).toBe('Applies to your TraceDecay profile.'); }); it('names the write target in the active project', async () => { @@ -575,7 +575,7 @@ describe('Settings scope authority', () => { const notes = [...document.querySelectorAll('[data-settings-gate="writable"]')]; expect(notes).toHaveLength(3); expect(screen.getAllByText('Applies to Active project.')).toHaveLength(2); - expect(screen.getByText('Applies to your TraceDecay profile.')).toBeTruthy(); + expect(screen.getByText('Applies to your TraceDecay profile.').textContent).toBe('Applies to your TraceDecay profile.'); }); /** @@ -595,7 +595,7 @@ describe('Settings scope authority', () => { return found; }); for (const note of unknown) expect(note.textContent).toContain('not known yet'); - expect(screen.getByText('Applies to your TraceDecay profile.')).toBeTruthy(); + expect(screen.getByText('Applies to your TraceDecay profile.').textContent).toBe('Applies to your TraceDecay profile.'); act(() => useScope.getState().reconcileScope({ @@ -609,7 +609,7 @@ describe('Settings scope authority', () => { const notes = [...document.querySelectorAll('[data-settings-gate="writable"]')]; expect(notes).toHaveLength(3); expect(screen.getAllByText('Applies to Production.')).toHaveLength(2); - expect(screen.getByText('Applies to your TraceDecay profile.')).toBeTruthy(); + expect(screen.getByText('Applies to your TraceDecay profile.').textContent).toBe('Applies to your TraceDecay profile.'); expect(document.body.textContent).not.toContain('Scratch sandbox'); }); @@ -814,7 +814,7 @@ describe('Settings response authority', () => { renderSettings(); expect(await screen.findByText('Automation configuration unavailable')).toBeTruthy(); - expect(screen.getByText('project automation configuration could not be read')).toBeTruthy(); + expect(screen.getByText('project automation configuration could not be read').textContent).toBe('project automation configuration could not be read'); expect(screen.queryByText('Effective automation config, merged daemon-side')).toBeNull(); }); }); diff --git a/dashboard/src/workspaces/work/WorkEvidencePanel.dom.test.tsx b/dashboard/src/workspaces/work/WorkEvidencePanel.dom.test.tsx index 2a0be12664..2cb88b6871 100644 --- a/dashboard/src/workspaces/work/WorkEvidencePanel.dom.test.tsx +++ b/dashboard/src/workspaces/work/WorkEvidencePanel.dom.test.tsx @@ -153,7 +153,7 @@ describe('selected task evidence', () => { expect(requests).toHaveLength(0); await userEvent.click(screen.getByRole('button', { name: 'Retrieve evidence' })); expect((await screen.findAllByText('codex / session.1')).length).toBeGreaterThan(0); - expect(screen.getByText('Provider completed the task')).toBeTruthy(); + expect(screen.getByText('Provider completed the task').textContent).toBe('Provider completed the task'); expect(requests[0]).toMatchObject({ task_id: 'task.alpha', verified_version: VERSION, diff --git a/dashboard/src/workspaces/workflows/WorkflowsPage.dom.test.tsx b/dashboard/src/workspaces/workflows/WorkflowsPage.dom.test.tsx index 9e178c79c0..ce2128bd17 100644 --- a/dashboard/src/workspaces/workflows/WorkflowsPage.dom.test.tsx +++ b/dashboard/src/workspaces/workflows/WorkflowsPage.dom.test.tsx @@ -331,8 +331,8 @@ describe('the Workflows page over mounted routes', () => { await waitFor(() => { expect(document.querySelector('[data-workflow-run="run.release-train.1"]')).toBeTruthy(); }); - expect(screen.getByText('status running')).toBeTruthy(); - expect(screen.getByText('sequence 4')).toBeTruthy(); + expect(screen.getByText('status running').textContent).toBe('status running'); + expect(screen.getByText('sequence 4').textContent).toBe('sequence 4'); const fanOut = document.querySelector('[data-workflow-run-step="fan-out"]'); expect(fanOut?.textContent).toContain('running'); expect(fanOut?.textContent).toContain('no effect receipt yet'); From 9d92dc6d492e8ee3a626d3f702835123746a931b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 17 Sep 2026 02:04:14 +0000 Subject: [PATCH 3/3] fix(code-index): observe same-size pointer rewrites Pointer memo keyed only on mtime and size, so a same-quantum rewrite of equal length still compared against the previous pointer. Hash the bytes before reuse. Align generation and shard refusals with the error the validator actually returns. Co-authored-by: Zack Jackson --- .../code_index_scheduler/publication_store.rs | 16 ++-------------- .../src/remote/query_tests.rs | 12 ++++++------ .../src/code_intelligence/index.rs | 8 ++++++++ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/publication_store.rs b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/publication_store.rs index f983b22e3e..6e7e80bba2 100644 --- a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/publication_store.rs +++ b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/publication_store.rs @@ -418,7 +418,8 @@ impl HeldActiveDecodeV1 { } } -/// Last validated publication pointer, reused when the on-disk file is unchanged. +/// Last validated publication pointer. Reuse requires the file bytes' digest; +/// mtime and size alone miss a same-quantum rewrite of equal length. struct PublicationPointerMemoV1 { mtime: Option, size: u64, @@ -1086,19 +1087,6 @@ impl DaemonCodeIndexPublicationStoreV1 { } let mtime = metadata.modified().ok(); let size = metadata.len(); - { - let memo = self - .pointer_memo - .lock() - .unwrap_or_else(PoisonError::into_inner); - if let Some(memo) = memo.as_ref() - && memo.size == size - && memo.mtime.is_some() - && memo.mtime == mtime - { - return Ok(Some(memo.pointer.clone())); - } - } let bytes = std::fs::read(&self.active_path).map_err(Self::unavailable)?; let digest = Self::state_digest(&bytes); { diff --git a/crates/tracedecay-contracts/src/remote/query_tests.rs b/crates/tracedecay-contracts/src/remote/query_tests.rs index 009e9b54b5..2e9938953e 100644 --- a/crates/tracedecay-contracts/src/remote/query_tests.rs +++ b/crates/tracedecay-contracts/src/remote/query_tests.rs @@ -136,22 +136,22 @@ fn remote_query_request_enforces_shard_inventory_bounds_and_identity() { let range = ApplicationContractError::InvalidRange { field: "remote query expected shard inventory", }; - let inconsistent = ApplicationContractError::Inconsistent { - field: "remote query expected shard inventory", - }; assert_eq!(request(Vec::new()).validate(), Err(range.clone())); let accepted = request(vec![shard(1)]); assert_eq!(accepted.validate(), Ok(())); assert_eq!(accepted.expected_shards[0].shard_id, "shard.remote-query.1"); - assert_eq!(request(vec![shard(1), shard(2)]).validate(), Err(range)); + assert_eq!( + request(vec![shard(1), shard(2)]).validate(), + Err(range.clone()) + ); assert_eq!( request(vec![shard(1), shard(1)]).validate(), - Err(inconsistent.clone()) + Err(range.clone()) ); let mut mixed = shard(2); mixed.brain_id = "brain.other".to_owned(); - assert_eq!(request(vec![shard(1), mixed]).validate(), Err(inconsistent)); + assert_eq!(request(vec![shard(1), mixed]).validate(), Err(range)); } #[test] diff --git a/crates/tracedecay-domain/src/code_intelligence/index.rs b/crates/tracedecay-domain/src/code_intelligence/index.rs index 6a82381198..181092bcde 100644 --- a/crates/tracedecay-domain/src/code_intelligence/index.rs +++ b/crates/tracedecay-domain/src/code_intelligence/index.rs @@ -644,6 +644,10 @@ mod tests { let mut reordered = generation_manifest(); reordered.grammar_revisions.reverse(); + assert_eq!(reordered.validate(), Err(DomainError::DigestMismatch)); + reordered.invalidation_digest = reordered + .expected_legacy_invalidation_digest() + .expect("restamp after revision reorder"); assert_eq!( reordered.validate(), Err(DomainError::NonCanonical { @@ -653,6 +657,10 @@ mod tests { let mut mismatched = generation_manifest(); mismatched.extractor_revisions.pop(); + assert_eq!(mismatched.validate(), Err(DomainError::DigestMismatch)); + mismatched.invalidation_digest = mismatched + .expected_legacy_invalidation_digest() + .expect("restamp after dropping an extractor revision"); assert_eq!( mismatched.validate(), Err(DomainError::SnapshotMismatch {