From fe3039fb9582ee3f44c0bf21522aa19d347ec351 Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:08:40 +0200 Subject: [PATCH 1/9] test(runtime): align DSL fixture validation subset --- docs/RUNTIME_CONTRACT.md | 22 ++++++++++ examples/basic.ctxt | 13 +----- src/runtime.rs | 89 +++++++++++++++++++++++++++++++--------- tests/cli_smoke.rs | 81 ++++++++++++++++++++++++++++++++++-- 4 files changed, 171 insertions(+), 34 deletions(-) diff --git a/docs/RUNTIME_CONTRACT.md b/docs/RUNTIME_CONTRACT.md index 87f9d47..f7ad7ab 100644 --- a/docs/RUNTIME_CONTRACT.md +++ b/docs/RUNTIME_CONTRACT.md @@ -42,6 +42,28 @@ are returned as JSON-RPC error responses on stdout instead of CLI stderr. A malformed server invocation or server I/O failure still follows normal CLI error handling. +## DSL Fixture Validation + +`ctxt dsl validate ` validates a small local fixture subset only. It does +not claim full legacy DSL compatibility and does not execute skills, tools, +tasks, providers, shell commands, OAuth flows, network resources, or MCP tool +definitions. + +The current accepted subset is: + +| Syntax | Meaning | +| --- | --- | +| `use:` | Counts a local use directive. | +| `$skill-name` | Counts a skill-shaped reference without invoking it. | +| `@workspace/path` | Counts a local resource-shaped reference without reading or resolving it. | +| `C;P:FIB` style lines | Parses a symbolic command using the existing symbolic parser. | + +The validator rejects executable legacy semantics, including `tool { ... }` +blocks, `task { ... }` blocks, OAuth/network resource URLs, provider +declarations, and shell execution statements. With `--json`, the report includes +`subset: "local-fixture-v1"`, stable counts for accepted syntax, accepted syntax +labels, rejected semantic labels, and an ordered error list. + ## MCP JSON-RPC Contract MCP request responses use JSON-RPC-style objects: diff --git a/examples/basic.ctxt b/examples/basic.ctxt index ce37abd..90ba992 100644 --- a/examples/basic.ctxt +++ b/examples/basic.ctxt @@ -1,13 +1,4 @@ +use:ctxt-runtime $ctxt-runtime @workspace/README.md - -tool read_context { - name: "read_context" - description: "Read context from an allowed root." -} - -task validate_basic { - name: "validate_basic" - description: "Validate the basic CompText DSL fixture." - handler: validate_basic -} +C;P:FIB diff --git a/src/runtime.rs b/src/runtime.rs index 74f80c1..e8cdc8e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -445,10 +445,10 @@ fn validate_modifier(modifier: &str) -> Result<&str, String> { fn validate_dsl(text: &str) -> serde_json::Value { let mut errors = Vec::new(); let mut counts = json!({ + "use_directives": 0, "skills": 0, "resources": 0, - "tools": 0, - "tasks": 0 + "symbolic_commands": 0 }); let lines: Vec<&str> = text.lines().collect(); @@ -459,6 +459,15 @@ fn validate_dsl(text: &str) -> serde_json::Value { i += 1; continue; } + if line.starts_with("use:") { + if valid_use_directive(line) { + counts["use_directives"] = json!(counts["use_directives"].as_u64().unwrap() + 1); + } else { + errors.push(format!("invalid use directive on line {}", i + 1)); + } + i += 1; + continue; + } if line.starts_with('$') { if valid_prefixed_identifier(line, '$') { counts["skills"] = json!(counts["skills"].as_u64().unwrap() + 1); @@ -490,24 +499,22 @@ fn validate_dsl(text: &str) -> serde_json::Value { block.push('\n'); block.push_str(lines[i]); } - if !block.contains('{') || !block.contains('}') { - errors.push(format!( - "unterminated {kind} block starting on line {start_line}" - )); - } else if kind == "tool" - && (!block.contains("name:") || !block.contains("description:")) - { - errors.push(format!( - "tool block on line {start_line} requires name and description" - )); - } else if kind == "task" && (!block.contains("name:") || !block.contains("handler:")) { - errors.push(format!( - "task block on line {start_line} requires name and handler" - )); - } else { - let key = if kind == "tool" { "tools" } else { "tasks" }; - counts[key] = json!(counts[key].as_u64().unwrap() + 1); - } + errors.push(format!( + "unsupported executable legacy {kind} block starting on line {start_line}" + )); + i += 1; + continue; + } + if looks_like_block_legacy_semantic(line) { + errors.push(format!( + "unsupported executable legacy statement on line {}", + i + 1 + )); + i += 1; + continue; + } + if parse_symbolic(line).is_ok() { + counts["symbolic_commands"] = json!(counts["symbolic_commands"].as_u64().unwrap() + 1); i += 1; continue; } @@ -518,13 +525,37 @@ fn validate_dsl(text: &str) -> serde_json::Value { json!({ "ok": errors.is_empty(), "valid": errors.is_empty(), + "subset": "local-fixture-v1", + "accepted_syntax": [ + "use:", + "$skill-name", + "@workspace/path", + "symbolic command lines" + ], + "rejected_semantics": [ + "tool blocks", + "task blocks", + "OAuth or network resources", + "shell execution", + "provider calls", + "automatic skill invocation" + ], "counts": counts, "errors": errors }) } +fn valid_use_directive(line: &str) -> bool { + let name = line.trim_start_matches("use:"); + valid_identifier_body(name) +} + fn valid_prefixed_identifier(line: &str, prefix: char) -> bool { let name = line.trim_start_matches(prefix); + valid_identifier_body(name) +} + +fn valid_identifier_body(name: &str) -> bool { !name.is_empty() && name .chars() @@ -533,16 +564,34 @@ fn valid_prefixed_identifier(line: &str, prefix: char) -> bool { fn valid_resource_ref(line: &str) -> bool { let value = line.trim_start_matches('@'); + if value.contains("://") || value.contains(':') { + return false; + } + let path = Path::new(value); !value.is_empty() && !value.starts_with('/') && !value.starts_with('\\') + && !path.is_absolute() && !value.split('/').any(|part| part == "..") && !value.split('\\').any(|part| part == "..") + && reject_sensitive_path(path).is_ok() && value .chars() .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '/' | '.')) } +fn looks_like_block_legacy_semantic(line: &str) -> bool { + let lower = line.to_ascii_lowercase(); + lower.starts_with("oauth") + || lower.starts_with("provider") + || lower.starts_with("shell ") + || lower.starts_with("exec ") + || lower.starts_with("run ") + || lower.starts_with("http://") + || lower.starts_with("https://") + || lower.starts_with("resource://") +} + fn serve_mcp(allowed_root: &Path) -> Result<(), String> { let stdin = io::stdin(); let mut stdout = io::stdout(); diff --git a/tests/cli_smoke.rs b/tests/cli_smoke.rs index 67fddd3..d3d916f 100644 --- a/tests/cli_smoke.rs +++ b/tests/cli_smoke.rs @@ -350,10 +350,21 @@ fn ctxt_dsl_validate_accepts_basic_fixture() { let value: serde_json::Value = serde_json::from_str(&stdout).expect("DSL validate JSON should parse"); assert_eq!(value["valid"], true); + assert_eq!(value["subset"], "local-fixture-v1"); + assert_eq!(value["counts"]["use_directives"], 1); assert_eq!(value["counts"]["skills"], 1); assert_eq!(value["counts"]["resources"], 1); - assert_eq!(value["counts"]["tools"], 1); - assert_eq!(value["counts"]["tasks"], 1); + assert_eq!(value["counts"]["symbolic_commands"], 1); + assert!(value["accepted_syntax"] + .as_array() + .unwrap() + .iter() + .any(|entry| entry == "use:")); + assert!(value["rejected_semantics"] + .as_array() + .unwrap() + .iter() + .any(|entry| entry == "tool blocks")); } #[test] @@ -363,7 +374,7 @@ fn ctxt_dsl_validate_rejects_invalid_fixture() { let _fixture_guard = FileGuard::new(fixture); std::fs::write( fixture, - "$bad skill\n@../secret\ntool missing_description { name: demo }\ntask broken {\n", + "$bad skill\n@../secret\nuse:bad value\nnot-a-symbolic command\n", ) .unwrap(); @@ -386,6 +397,70 @@ fn ctxt_dsl_validate_rejects_invalid_fixture() { .unwrap() .iter() .any(|error| error.as_str().unwrap().contains("invalid resource"))); + assert!(report["errors"] + .as_array() + .unwrap() + .iter() + .any(|error| error.as_str().unwrap().contains("invalid use directive"))); +} + +#[test] +fn ctxt_dsl_validate_rejects_executable_legacy_semantics() { + let _guard = test_lock(); + let fixture = std::path::Path::new("examples/invalid-executable-semantics.ctxt"); + let _fixture_guard = FileGuard::new(fixture); + std::fs::write( + fixture, + [ + "tool read_context {", + " name: \"read_context\"", + " description: \"Read context from an allowed root.\"", + "}", + "task validate_basic {", + " name: \"validate_basic\"", + " handler: validate_basic", + "}", + "@https://example.com/resource", + "@resource://database/users", + "provider openai", + "shell echo hi", + ] + .join("\n"), + ) + .unwrap(); + + let output = std::process::Command::new(env!("CARGO_BIN_EXE_ctxt")) + .args([ + "dsl", + "validate", + "examples/invalid-executable-semantics.ctxt", + "--json", + ]) + .output() + .expect("ctxt binary should run"); + assert!(!output.status.success()); + let stdout = String::from_utf8(output.stdout).expect("stdout should be UTF-8"); + let report: serde_json::Value = + serde_json::from_str(&stdout).expect("DSL invalid report should parse"); + assert_eq!(report["valid"], false); + assert_eq!(report["subset"], "local-fixture-v1"); + let errors = report["errors"].as_array().unwrap(); + assert!(errors.iter().any(|error| error + .as_str() + .unwrap() + .contains("unsupported executable legacy tool block"))); + assert!(errors.iter().any(|error| error + .as_str() + .unwrap() + .contains("unsupported executable legacy task block"))); + assert!(errors.iter().any(|error| error + .as_str() + .unwrap() + .contains("invalid resource reference"))); + assert!(errors.iter().any(|error| error + .as_str() + .unwrap() + .contains("unsupported executable legacy statement"))); } #[test] From 55b21c0bcd5b0fd69516c851ed5b94ed01200437 Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:18:16 +0200 Subject: [PATCH 2/9] docs(runtime): add deterministic validation matrix --- docs/RUNTIME_CONTRACT.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/RUNTIME_CONTRACT.md b/docs/RUNTIME_CONTRACT.md index f7ad7ab..fd57098 100644 --- a/docs/RUNTIME_CONTRACT.md +++ b/docs/RUNTIME_CONTRACT.md @@ -134,3 +134,29 @@ reports `sha256_scope: "returned_bytes"` for that reason. `ctxt evidence hash ` hashes the validated local file bytes that are read for that command. It does not read denied, sensitive, outside-root, traversal, or oversized paths. + +## Deterministic Validation Matrix + +This matrix maps the current local runtime surface to deterministic evidence. +It is not an LLM judge, production-readiness claim, full MCP compliance claim, +full DSL compatibility claim, hidden chain-of-thought capture claim, or +universal token-reduction claim. Correctness is bounded to local command +outputs, stable JSON contracts, deterministic hashes, exact exit codes, smoke +tests, and `cargo test`. + +| Capability | Command or test area | Positive evidence | Negative evidence | JSON contract evidence | Security boundary evidence | Current test names | Missing test gaps | Claim boundary | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Parse symbolic command | `ctxt parse --json` | Parses `C;P:FIB` into command, language, task, and raw fields. | Rejects invalid command code, invalid language segment, invalid modifier, duplicate language, missing task, malformed segments, and invalid task characters. | JSON object includes symbolic command fields and machine-readable JSON error on failure. | No file read, network, provider, shell, or apply path is involved. | `ctxt_parse_json_roundtrips_symbolic_command`; `ctxt_rejects_invalid_command_language_and_modifier`; `ctxt_rejects_ambiguous_and_malformed_symbolic_commands` | None for the current symbolic subset. | Validates only the local symbolic subset. | +| Encode symbolic command | `ctxt encode --command --task [--language ] --json` | Emits `C;P:FIB` for CODE/PYTHON/FIB and can report parsed JSON when JSON mode is used. | Rejects invalid language and missing required values through parser/command validation. | JSON mode returns `ok`, `encoded`, and `parsed`. | No file read, network, provider, shell, or apply path is involved. | `ctxt_encode_emits_expected_symbolic_command`; `ctxt_rejects_invalid_command_language_and_modifier` | Add a dedicated encode JSON-shape smoke test if encode JSON becomes a public contract dependency. | Encodes only the local command/language/modifier vocabulary. | +| Batch symbolic expression | `ctxt batch --json` | Parses `B:[D:SUM]\|[C;P:FIB]` into deterministic `SEQ` items. | Rejects missing `B:` prefix, unwrapped items, empty trailing items, and invalid nested symbolic commands. | JSON object includes `ok`, `mode`, and ordered `items`. | No file read, network, provider, shell, or apply path is involved. | `ctxt_batch_parses_items`; `ctxt_batch_rejects_malformed_items` | None for the current batch subset. | Batch is parsing only, not execution or scheduling. | +| DSL local-fixture-v1 validation | `ctxt dsl validate --json` | Accepts `use:`, `$skill-name`, local `@workspace/path`, and symbolic command fixture lines. | Rejects malformed skill/use/resource syntax, unsupported fixture lines, executable legacy `tool` and `task` blocks, URL resources, provider declarations, shell statements, traversal, and symlink escape where supported. | JSON report includes `ok`, `valid`, `subset`, `accepted_syntax`, `rejected_semantics`, `counts`, and ordered `errors`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, sensitive-path denied, and UTF-8 checked. Resource-shaped lines are not read or resolved. | `ctxt_dsl_validate_accepts_basic_fixture`; `ctxt_dsl_validate_rejects_invalid_fixture`; `ctxt_dsl_validate_rejects_executable_legacy_semantics`; `ctxt_dsl_validate_rejects_symlink_escape_when_supported` | Consider a dedicated sensitive-path DSL fixture test if DSL fixture paths expand beyond current runtime input checks. | Fixture validation only; no full legacy DSL compatibility, skill execution, MCP tool execution, OAuth, network, provider calls, or task execution. | +| Evidence hash | `ctxt evidence hash --json` | Produces stable SHA-256 for local files, including the empty-file vector. | Rejects sensitive names, traversal, and symlink escape where supported. | JSON includes `ok`, `algorithm`, normalized `path`, `bytes`, and `sha256`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, and sensitive-path denied before read. | `ctxt_evidence_hash_is_stable_sha256`; `ctxt_evidence_hash_matches_empty_file_vector`; `ctxt_evidence_hash_rejects_sensitive_and_traversal_paths`; `ctxt_evidence_hash_rejects_symlink_escape_when_supported` | Add an oversized-file test if evidence hashing max-size behavior becomes a release gate. | Hashes only validated local bytes; no provenance or legal/compliance assurance. | +| MCP-style stdio file-read adapter | `ctxt mcp serve --allowed-root ` | Handles `initialize`, `tools/list`, and `tools/call` for `ctxt.read_file` under an explicit root. | Rejects malformed JSON, invalid request shape, missing/non-string methods, unknown methods, invalid params, traversal, sensitive paths, symlink escape where supported, outside-root paths, and oversized files. Notifications without `id` produce no response. | JSON-RPC responses include `jsonrpc`, `id`, `result`; errors include stable `code`, `message`, `data.kind`, and bounded `data.detail`. File reads report returned-byte hash scope. | Explicit allowed root, canonical containment, sensitive-path denial before and after canonicalization, max file-size gate, and `max_bytes` bounded returned content. | `ctxt_mcp_allows_rooted_file_read`; `ctxt_mcp_returns_structured_parse_error_for_malformed_json`; `ctxt_mcp_returns_structured_invalid_request_for_missing_method`; `ctxt_mcp_returns_structured_invalid_request_for_non_string_method`; `ctxt_mcp_notification_with_no_id_produces_no_response`; `ctxt_mcp_returns_structured_method_not_found`; `ctxt_mcp_returns_structured_invalid_params`; `ctxt_mcp_blocks_traversal`; `ctxt_mcp_blocks_sensitive_paths_without_reading_content`; `ctxt_mcp_blocks_symlink_escape_when_supported`; `ctxt_mcp_reports_returned_byte_hash_scope`; `ctxt_mcp_blocks_file_too_large` | Add additional invalid `max_bytes` edge cases if the adapter contract expands. | Local stdio adapter only; no full MCP compliance, network transport, OAuth, provider calls, shell execution, or general filesystem access. | +| Trace heuristic detection | `ctxt detect-illegible-cot --json` | Flags deterministic phrase fixtures and reports finding IDs. | File-read errors follow runtime input validation; no current negative no-finding fixture is asserted. | JSON includes `ok`, `detected`, `findings`, and `scope`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, sensitive-path denied, and UTF-8 checked. | `ctxt_detect_illegible_cot_flags_trace_fixture` | Add a no-finding fixture test and sensitive/traversal tests if trace triage becomes a release gate. | Phrase heuristic only; no hidden chain-of-thought capture or correctness claim about model reasoning. | +| Proposal contract behavior | `ctxt proposals list/inspect/validate --json` | Lists valid proposal artifacts, inspects bounded proposal content, accepts valid `proposal.v1`, and supports `latest` positional and `--id latest`. | Rejects missing required fields, id mismatch, malformed JSON, traversal IDs, invalid `max_bytes`, and duplicate IDs. | JSON contracts are discoverable through `ctxt --json schema` and `ctxt --json capabilities`; proposal command outputs include command identity, schema version, validity, paths, and errors. | Proposal artifacts are untrusted local files; inspection is bounded; validation does not apply changes. | `proposals_list_missing_root_returns_empty`; `proposals_list_shows_valid_proposal`; `proposals_inspect_latest_reads_proposal_object`; `proposals_inspect_latest_flag_id_matches_positional`; `proposals_validate_latest_accepts_valid_contract`; `proposals_validate_latest_flag_id_accepts_valid_contract`; `proposals_validate_missing_required_field_returns_invalid`; `proposals_validate_id_mismatch_returns_invalid`; `proposals_validate_malformed_json_returns_invalid`; `proposals_reject_path_traversal_id_with_json_error`; `proposals_reject_invalid_max_bytes_with_json_error`; `proposals_reject_duplicate_id_with_json_error`; `schema_json_reports_proposal_contract_details`; `capabilities_json_reports_proposal_capabilities` | Add proposal artifact size-limit tests if proposal inspection limits become a release gate. | Contract validation only; no approval, generation, apply, provider, network, or git action. | +| Review contract behavior | `ctxt reviews list/inspect/validate --json`; `ctxt review workflow --json` | Lists valid review artifacts, inspects bounded review content, accepts valid `review.v1`, validates workflow contract, and reports disabled execution/apply flags. | Rejects missing required fields, id mismatch, malformed JSON, traversal IDs, invalid `max_bytes`, duplicate IDs, invalid role IDs, safety flags set to true, and unsupported review workflow commands. | JSON contracts are discoverable through `ctxt --json schema`; review outputs include command identity, schema version, validity, role IDs, safety flags, and errors. | Review artifacts are untrusted local evidence; inspection is bounded; runtime does not execute subagents, generate reviews, apply recommendations, use network, or write git history. | `reviews_list_missing_root_returns_empty`; `reviews_list_shows_valid_review`; `reviews_inspect_latest_reads_review_object`; `reviews_inspect_latest_flag_id_matches_positional`; `reviews_validate_latest_accepts_valid_contract`; `reviews_validate_latest_flag_id_accepts_valid_contract`; `reviews_validate_missing_required_field_returns_invalid`; `reviews_validate_id_mismatch_returns_invalid`; `reviews_validate_malformed_json_returns_invalid_and_listable`; `reviews_reject_path_traversal_id_with_json_error`; `reviews_reject_invalid_max_bytes_with_json_error`; `reviews_reject_duplicate_id_with_json_error`; `reviews_validate_true_safety_flag_returns_invalid`; `reviews_validate_invalid_role_id_returns_invalid`; `reviews_unknown_commands_fail_with_json_errors`; `review_workflow_json_reports_static_contract`; `review_workflow_unknown_commands_fail_with_json_errors`; `schema_json_reports_review_contract_details`; `schema_json_reports_review_workflow_contract_details` | Add bounded-size review artifact tests if inspection limits become a release gate. | Contract-only review workflow; no subagent execution, LLM judge, apply, provider, network, or git action. | +| Provider dry-run and network-deny behavior | `ctxt ask/propose/benchmark/agent run` provider-related smoke tests | Dummy provider paths succeed locally; dry-run reports artifacts without provider call; proposal-only agent run returns execution plans when explicitly allowed. | Ollama respects network-deny policy; unsupported benchmark provider is rejected; external agent run defaults to dry-run for Codex and Antigravity. | JSON outputs report provider/artifact fields, safety flags, and execution-plan fields in covered paths. | Network default deny, provider output treated as untrusted, external agents not invoked by default, and proposal-only mode does not apply changes. | `ask_json_dry_run_reports_artifacts_without_provider_call`; `ask_dummy_provider_succeeds`; `ask_ollama_provider_respects_network_deny_policy`; `propose_dummy_provider_succeeds`; `propose_json_reports_proposal_artifacts`; `agent_run_dummy_writes_run_artifact`; `agent_run_codex_is_dry_run_by_default`; `agent_run_antigravity_is_dry_run_by_default`; `agent_run_codex_allow_external_proposal_only_returns_execution_plan`; `agent_run_antigravity_allow_external_proposal_only_returns_execution_plan`; `unknown_agent_kind_fails_with_json_error`; unit tests `provider::tests::test_openai_fails_closed_without_network`, `provider::tests::test_openai_no_network_call_made`, `provider::tests::test_openai_request_serialization_shape`, `provider::tests::test_ollama_local_offline_error`, `provider::tests::test_ollama_missing_auth_env`, `cli::tests::test_unsupported_provider_benchmark_rejected` | Add explicit JSON assertions for every safety flag if these paths become external-review gates. | Local dry-run/network-deny evidence only; no live provider correctness, performance, production, or availability claim. | + +Validation for this matrix is `cargo fmt --check`, `cargo test`, stable JSON +smoke tests, deterministic hashes, exact exit codes, and git status. Claims +outside those checks remain out of scope. From e9d6d0b860405193101141173261ac0f6130ac34 Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:30:04 +0200 Subject: [PATCH 3/9] test(runtime): cover encode JSON shape --- tests/cli_smoke.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/cli_smoke.rs b/tests/cli_smoke.rs index d3d916f..731ed41 100644 --- a/tests/cli_smoke.rs +++ b/tests/cli_smoke.rs @@ -262,6 +262,31 @@ fn ctxt_encode_emits_expected_symbolic_command() { assert_eq!(stdout.trim(), "C;P:FIB"); } +#[test] +fn ctxt_encode_json_reports_stable_shape() { + let _guard = test_lock(); + let stdout = run(&[ + "encode", + "--command", + "CODE", + "--language", + "PYTHON", + "--task", + "FIB", + "--json", + ]); + let value: serde_json::Value = serde_json::from_str(&stdout).expect("encode JSON should parse"); + assert_eq!(value["ok"], true); + assert_eq!(value["encoded"], "C;P:FIB"); + assert_eq!(value["parsed"]["command"], "CODE"); + assert_eq!(value["parsed"]["command_code"], "C"); + assert_eq!(value["parsed"]["language"], "PYTHON"); + assert_eq!(value["parsed"]["language_code"], "P"); + assert_eq!(value["parsed"]["task"], "FIB"); + assert_eq!(value["parsed"]["modifiers"].as_array().unwrap().len(), 0); + assert_eq!(value["parsed"]["raw"], "C;P:FIB"); +} + #[test] fn ctxt_batch_parses_items() { let _guard = test_lock(); From 12cf18601a6169674e49deaab7b7f505e753d87f Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:35:50 +0200 Subject: [PATCH 4/9] test(runtime): cover clean trace heuristic result --- examples/trace-clean.txt | 3 +++ tests/cli_smoke.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 examples/trace-clean.txt diff --git a/examples/trace-clean.txt b/examples/trace-clean.txt new file mode 100644 index 0000000..bd0ef89 --- /dev/null +++ b/examples/trace-clean.txt @@ -0,0 +1,3 @@ +event=startup_check status=ok +event=context_pack status=prepared +event=validation status=passed diff --git a/tests/cli_smoke.rs b/tests/cli_smoke.rs index 731ed41..727af39 100644 --- a/tests/cli_smoke.rs +++ b/tests/cli_smoke.rs @@ -856,6 +856,20 @@ fn ctxt_detect_illegible_cot_flags_trace_fixture() { assert_eq!(value["findings"].as_array().unwrap().len(), 1); } +#[test] +fn ctxt_detect_illegible_cot_reports_clean_trace() { + let _guard = test_lock(); + let stdout = run(&["detect-illegible-cot", "examples/trace-clean.txt", "--json"]); + let value: serde_json::Value = serde_json::from_str(&stdout).expect("detect JSON should parse"); + assert_eq!(value["ok"], true); + assert_eq!(value["detected"], false); + assert_eq!(value["findings"].as_array().unwrap().len(), 0); + assert_eq!( + value["scope"], + "deterministic phrase heuristic for trace review triage" + ); +} + #[test] fn help_mentions_safety_defaults() { let _guard = test_lock(); From 1aea5b7797f378d5caf9fd18139330cf2a9fbba7 Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 14:10:13 +0200 Subject: [PATCH 5/9] docs(runtime): refresh deterministic validation matrix --- docs/RUNTIME_CONTRACT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/RUNTIME_CONTRACT.md b/docs/RUNTIME_CONTRACT.md index fd57098..208bb23 100644 --- a/docs/RUNTIME_CONTRACT.md +++ b/docs/RUNTIME_CONTRACT.md @@ -147,12 +147,12 @@ tests, and `cargo test`. | Capability | Command or test area | Positive evidence | Negative evidence | JSON contract evidence | Security boundary evidence | Current test names | Missing test gaps | Claim boundary | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Parse symbolic command | `ctxt parse --json` | Parses `C;P:FIB` into command, language, task, and raw fields. | Rejects invalid command code, invalid language segment, invalid modifier, duplicate language, missing task, malformed segments, and invalid task characters. | JSON object includes symbolic command fields and machine-readable JSON error on failure. | No file read, network, provider, shell, or apply path is involved. | `ctxt_parse_json_roundtrips_symbolic_command`; `ctxt_rejects_invalid_command_language_and_modifier`; `ctxt_rejects_ambiguous_and_malformed_symbolic_commands` | None for the current symbolic subset. | Validates only the local symbolic subset. | -| Encode symbolic command | `ctxt encode --command --task [--language ] --json` | Emits `C;P:FIB` for CODE/PYTHON/FIB and can report parsed JSON when JSON mode is used. | Rejects invalid language and missing required values through parser/command validation. | JSON mode returns `ok`, `encoded`, and `parsed`. | No file read, network, provider, shell, or apply path is involved. | `ctxt_encode_emits_expected_symbolic_command`; `ctxt_rejects_invalid_command_language_and_modifier` | Add a dedicated encode JSON-shape smoke test if encode JSON becomes a public contract dependency. | Encodes only the local command/language/modifier vocabulary. | +| Encode symbolic command | `ctxt encode --command --task [--language ] --json` | Emits `C;P:FIB` for CODE/PYTHON/FIB and can report parsed JSON when JSON mode is used. | Rejects invalid language and missing required values through parser/command validation. | JSON mode returns `ok`, `encoded`, and `parsed`. | No file read, network, provider, shell, or apply path is involved. | `ctxt_encode_emits_expected_symbolic_command`; `ctxt_encode_json_reports_stable_shape`; `ctxt_rejects_invalid_command_language_and_modifier` | None for the current encode JSON shape. | Encodes only the local command/language/modifier vocabulary. | | Batch symbolic expression | `ctxt batch --json` | Parses `B:[D:SUM]\|[C;P:FIB]` into deterministic `SEQ` items. | Rejects missing `B:` prefix, unwrapped items, empty trailing items, and invalid nested symbolic commands. | JSON object includes `ok`, `mode`, and ordered `items`. | No file read, network, provider, shell, or apply path is involved. | `ctxt_batch_parses_items`; `ctxt_batch_rejects_malformed_items` | None for the current batch subset. | Batch is parsing only, not execution or scheduling. | | DSL local-fixture-v1 validation | `ctxt dsl validate --json` | Accepts `use:`, `$skill-name`, local `@workspace/path`, and symbolic command fixture lines. | Rejects malformed skill/use/resource syntax, unsupported fixture lines, executable legacy `tool` and `task` blocks, URL resources, provider declarations, shell statements, traversal, and symlink escape where supported. | JSON report includes `ok`, `valid`, `subset`, `accepted_syntax`, `rejected_semantics`, `counts`, and ordered `errors`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, sensitive-path denied, and UTF-8 checked. Resource-shaped lines are not read or resolved. | `ctxt_dsl_validate_accepts_basic_fixture`; `ctxt_dsl_validate_rejects_invalid_fixture`; `ctxt_dsl_validate_rejects_executable_legacy_semantics`; `ctxt_dsl_validate_rejects_symlink_escape_when_supported` | Consider a dedicated sensitive-path DSL fixture test if DSL fixture paths expand beyond current runtime input checks. | Fixture validation only; no full legacy DSL compatibility, skill execution, MCP tool execution, OAuth, network, provider calls, or task execution. | | Evidence hash | `ctxt evidence hash --json` | Produces stable SHA-256 for local files, including the empty-file vector. | Rejects sensitive names, traversal, and symlink escape where supported. | JSON includes `ok`, `algorithm`, normalized `path`, `bytes`, and `sha256`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, and sensitive-path denied before read. | `ctxt_evidence_hash_is_stable_sha256`; `ctxt_evidence_hash_matches_empty_file_vector`; `ctxt_evidence_hash_rejects_sensitive_and_traversal_paths`; `ctxt_evidence_hash_rejects_symlink_escape_when_supported` | Add an oversized-file test if evidence hashing max-size behavior becomes a release gate. | Hashes only validated local bytes; no provenance or legal/compliance assurance. | | MCP-style stdio file-read adapter | `ctxt mcp serve --allowed-root ` | Handles `initialize`, `tools/list`, and `tools/call` for `ctxt.read_file` under an explicit root. | Rejects malformed JSON, invalid request shape, missing/non-string methods, unknown methods, invalid params, traversal, sensitive paths, symlink escape where supported, outside-root paths, and oversized files. Notifications without `id` produce no response. | JSON-RPC responses include `jsonrpc`, `id`, `result`; errors include stable `code`, `message`, `data.kind`, and bounded `data.detail`. File reads report returned-byte hash scope. | Explicit allowed root, canonical containment, sensitive-path denial before and after canonicalization, max file-size gate, and `max_bytes` bounded returned content. | `ctxt_mcp_allows_rooted_file_read`; `ctxt_mcp_returns_structured_parse_error_for_malformed_json`; `ctxt_mcp_returns_structured_invalid_request_for_missing_method`; `ctxt_mcp_returns_structured_invalid_request_for_non_string_method`; `ctxt_mcp_notification_with_no_id_produces_no_response`; `ctxt_mcp_returns_structured_method_not_found`; `ctxt_mcp_returns_structured_invalid_params`; `ctxt_mcp_blocks_traversal`; `ctxt_mcp_blocks_sensitive_paths_without_reading_content`; `ctxt_mcp_blocks_symlink_escape_when_supported`; `ctxt_mcp_reports_returned_byte_hash_scope`; `ctxt_mcp_blocks_file_too_large` | Add additional invalid `max_bytes` edge cases if the adapter contract expands. | Local stdio adapter only; no full MCP compliance, network transport, OAuth, provider calls, shell execution, or general filesystem access. | -| Trace heuristic detection | `ctxt detect-illegible-cot --json` | Flags deterministic phrase fixtures and reports finding IDs. | File-read errors follow runtime input validation; no current negative no-finding fixture is asserted. | JSON includes `ok`, `detected`, `findings`, and `scope`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, sensitive-path denied, and UTF-8 checked. | `ctxt_detect_illegible_cot_flags_trace_fixture` | Add a no-finding fixture test and sensitive/traversal tests if trace triage becomes a release gate. | Phrase heuristic only; no hidden chain-of-thought capture or correctness claim about model reasoning. | +| Trace heuristic detection | `ctxt detect-illegible-cot --json` | Flags deterministic phrase fixtures and reports finding IDs, and reports no findings for a clean trace fixture. | File-read errors follow runtime input validation. | JSON includes `ok`, `detected`, `findings`, and `scope`. | Runtime file input is relative, canonicalized under the worktree, size-bounded, sensitive-path denied, and UTF-8 checked. | `ctxt_detect_illegible_cot_flags_trace_fixture`; `ctxt_detect_illegible_cot_reports_clean_trace` | Add sensitive/traversal tests if trace triage becomes a release gate. | Phrase heuristic only; no hidden chain-of-thought capture or correctness claim about model reasoning. | | Proposal contract behavior | `ctxt proposals list/inspect/validate --json` | Lists valid proposal artifacts, inspects bounded proposal content, accepts valid `proposal.v1`, and supports `latest` positional and `--id latest`. | Rejects missing required fields, id mismatch, malformed JSON, traversal IDs, invalid `max_bytes`, and duplicate IDs. | JSON contracts are discoverable through `ctxt --json schema` and `ctxt --json capabilities`; proposal command outputs include command identity, schema version, validity, paths, and errors. | Proposal artifacts are untrusted local files; inspection is bounded; validation does not apply changes. | `proposals_list_missing_root_returns_empty`; `proposals_list_shows_valid_proposal`; `proposals_inspect_latest_reads_proposal_object`; `proposals_inspect_latest_flag_id_matches_positional`; `proposals_validate_latest_accepts_valid_contract`; `proposals_validate_latest_flag_id_accepts_valid_contract`; `proposals_validate_missing_required_field_returns_invalid`; `proposals_validate_id_mismatch_returns_invalid`; `proposals_validate_malformed_json_returns_invalid`; `proposals_reject_path_traversal_id_with_json_error`; `proposals_reject_invalid_max_bytes_with_json_error`; `proposals_reject_duplicate_id_with_json_error`; `schema_json_reports_proposal_contract_details`; `capabilities_json_reports_proposal_capabilities` | Add proposal artifact size-limit tests if proposal inspection limits become a release gate. | Contract validation only; no approval, generation, apply, provider, network, or git action. | | Review contract behavior | `ctxt reviews list/inspect/validate --json`; `ctxt review workflow --json` | Lists valid review artifacts, inspects bounded review content, accepts valid `review.v1`, validates workflow contract, and reports disabled execution/apply flags. | Rejects missing required fields, id mismatch, malformed JSON, traversal IDs, invalid `max_bytes`, duplicate IDs, invalid role IDs, safety flags set to true, and unsupported review workflow commands. | JSON contracts are discoverable through `ctxt --json schema`; review outputs include command identity, schema version, validity, role IDs, safety flags, and errors. | Review artifacts are untrusted local evidence; inspection is bounded; runtime does not execute subagents, generate reviews, apply recommendations, use network, or write git history. | `reviews_list_missing_root_returns_empty`; `reviews_list_shows_valid_review`; `reviews_inspect_latest_reads_review_object`; `reviews_inspect_latest_flag_id_matches_positional`; `reviews_validate_latest_accepts_valid_contract`; `reviews_validate_latest_flag_id_accepts_valid_contract`; `reviews_validate_missing_required_field_returns_invalid`; `reviews_validate_id_mismatch_returns_invalid`; `reviews_validate_malformed_json_returns_invalid_and_listable`; `reviews_reject_path_traversal_id_with_json_error`; `reviews_reject_invalid_max_bytes_with_json_error`; `reviews_reject_duplicate_id_with_json_error`; `reviews_validate_true_safety_flag_returns_invalid`; `reviews_validate_invalid_role_id_returns_invalid`; `reviews_unknown_commands_fail_with_json_errors`; `review_workflow_json_reports_static_contract`; `review_workflow_unknown_commands_fail_with_json_errors`; `schema_json_reports_review_contract_details`; `schema_json_reports_review_workflow_contract_details` | Add bounded-size review artifact tests if inspection limits become a release gate. | Contract-only review workflow; no subagent execution, LLM judge, apply, provider, network, or git action. | | Provider dry-run and network-deny behavior | `ctxt ask/propose/benchmark/agent run` provider-related smoke tests | Dummy provider paths succeed locally; dry-run reports artifacts without provider call; proposal-only agent run returns execution plans when explicitly allowed. | Ollama respects network-deny policy; unsupported benchmark provider is rejected; external agent run defaults to dry-run for Codex and Antigravity. | JSON outputs report provider/artifact fields, safety flags, and execution-plan fields in covered paths. | Network default deny, provider output treated as untrusted, external agents not invoked by default, and proposal-only mode does not apply changes. | `ask_json_dry_run_reports_artifacts_without_provider_call`; `ask_dummy_provider_succeeds`; `ask_ollama_provider_respects_network_deny_policy`; `propose_dummy_provider_succeeds`; `propose_json_reports_proposal_artifacts`; `agent_run_dummy_writes_run_artifact`; `agent_run_codex_is_dry_run_by_default`; `agent_run_antigravity_is_dry_run_by_default`; `agent_run_codex_allow_external_proposal_only_returns_execution_plan`; `agent_run_antigravity_allow_external_proposal_only_returns_execution_plan`; `unknown_agent_kind_fails_with_json_error`; unit tests `provider::tests::test_openai_fails_closed_without_network`, `provider::tests::test_openai_no_network_call_made`, `provider::tests::test_openai_request_serialization_shape`, `provider::tests::test_ollama_local_offline_error`, `provider::tests::test_ollama_missing_auth_env`, `cli::tests::test_unsupported_provider_benchmark_rejected` | Add explicit JSON assertions for every safety flag if these paths become external-review gates. | Local dry-run/network-deny evidence only; no live provider correctness, performance, production, or availability claim. | From 3c1d5cd0f5f799ad3a9e26be75f0f8de8d650a94 Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:23:39 +0200 Subject: [PATCH 6/9] fix(runtime): clear release readiness blockers --- Cargo.toml | 24 ++++++++++++++++++++++++ README.md | 10 +++++----- src/runtime.rs | 4 +--- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cc379b..380ac33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,30 @@ edition = "2021" description = "Experimental terminal context client for deterministic Context Packs." license = "MIT" repository = "https://github.com/ProfRandom92/comptext-cli" +readme = "README.md" +keywords = ["cli", "context", "agents", "json", "deterministic"] +categories = ["command-line-utilities", "development-tools"] +exclude = [ + ".agent/**", + ".agents/**", + ".codex/**", + ".comptext/**", + ".github/**", + "Cargo.toml.orig", + "CREATE_REPO.md", + "MANIFEST.json", + "PROJEKT.md", + "context/**", + "mcp/**", + "prompts/**", + "reports/**", + "reviews/**", + "reviews.smoke-backup-*/**", + "scripts/**", + "tasks/**", + "templates/**", + "proposals/**", +] [[bin]] name = "ctxt" diff --git a/README.md b/README.md index d10716d..faf5fed 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ It does not execute external agents, use network, call providers, apply proposal ![External agents: disabled](https://img.shields.io/badge/external%20agents-disabled-lightgrey) ![Apply: disabled](https://img.shields.io/badge/apply-disabled-lightgrey) ![Subagent runtime: disabled](https://img.shields.io/badge/subagent%20runtime-disabled-lightgrey) -![MCP server: not implemented](https://img.shields.io/badge/MCP%20server-not%20implemented-lightgrey) +![MCP-style stdio: local-only](https://img.shields.io/badge/MCP--style%20stdio-local--only-lightgrey) ![Windows: validated](https://img.shields.io/badge/windows-validated-blue) ![v0.1.0: release candidate](https://img.shields.io/badge/v0.1.0-release%20candidate-purple) ![Contracts: deterministic](https://img.shields.io/badge/contracts-deterministic-brightgreen) @@ -29,7 +29,7 @@ It does not execute external agents, use network, call providers, apply proposal > **Safety boundary** > -> `ctxt` is local-first. Network is denied by default. Provider calls are not part of the documented workflow. External agent execution is disabled. Proposal and review artifacts are evidence, not instructions to auto-apply. Subagent role contracts are available, but subagents do not execute. No MCP server implementation is claimed. +> `ctxt` is local-first. Network is denied by default. Provider calls are not part of the documented workflow. External agent execution is disabled. Proposal and review artifacts are evidence, not instructions to auto-apply. Subagent role contracts are available, but subagents do not execute. The MCP-style stdio adapter is local-only and experimental; no production MCP support or full MCP compliance is claimed. CompText `ctxt` v0.1.0 is a release candidate until the release is tagged. @@ -157,7 +157,7 @@ For the local runtime experiment, see [docs/RUNTIME_CONTRACT.md](docs/RUNTIME_CO | Run artifact inspection | Available | Local evidence inspection | | Local validation | Available | `validate --run` contract | | Binary/media context-pack exclusion | Available | README assets do not break context packing | -| MCP server | Not implemented | No server availability claim | +| MCP-style stdio adapter | Experimental local-only | No production MCP support or full MCP compliance claim | | Provider gateway | Not implemented | No live provider gateway claim | | External agent execution | Disabled | Contracts and discovery do not execute agents | | Proposal or review application | Disabled | Artifacts are not auto-applied | @@ -231,7 +231,7 @@ flowchart LR allowed --> reads["Bounded Artifact Reads"] allowed --> validation["Validation"] allowed --> approval["User Approval"] - disabled["Disabled"] --> gates["Network / Providers / Agents / Auto Apply / MCP"] + disabled["Disabled"] --> gates["Network / Providers / Agents / Auto Apply / Production MCP"] classDef safe fill:#ecfdf5,stroke:#059669,color:#111827 classDef blocked fill:#fef2f2,stroke:#dc2626,color:#111827 @@ -250,7 +250,7 @@ flowchart LR | Proposal apply | Disabled | Proposal artifacts are untrusted evidence | | Review apply | Disabled | Review artifacts are untrusted evidence | | Subagent runtime execution | Disabled | Subagent role contracts are available only as definitions | -| MCP server | Not implemented | No MCP server implementation claim | +| MCP-style stdio adapter | Local-only experiment | No production MCP support or full MCP compliance claim | | Provider gateway | Not implemented | No provider gateway claim | | Hooks and plugins | Disabled for this flow | Not required for release-candidate validation | | Arbitrary shell | Out of scope | Use declared local validation commands | diff --git a/src/runtime.rs b/src/runtime.rs index e8cdc8e..8d005e8 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -635,9 +635,7 @@ fn handle_mcp_request( McpError::invalid_request("request method must be a string"), )); }; - if request.get("id").is_none() { - return None; - } + request.get("id")?; let result = match method { "initialize" => Ok(json!({ "protocolVersion": "2025-06-18", From a1646ea53402d23e3cae3e97de859d1b16d5328d Mon Sep 17 00:00:00 2001 From: ProfRandom92 <159939812+ProfRandom92@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:32:57 +0200 Subject: [PATCH 7/9] docs(release): align v0.1.0 release notes --- RELEASE_NOTES_v0.1.0.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES_v0.1.0.md b/RELEASE_NOTES_v0.1.0.md index 06c62d9..5506e88 100644 --- a/RELEASE_NOTES_v0.1.0.md +++ b/RELEASE_NOTES_v0.1.0.md @@ -1,8 +1,10 @@ # CompText CLI v0.1.0 Release Notes -Status: Release candidate, tag only after CI green. +Status: GitHub pre-release candidate only. Tag only after CI is green. -CompText CLI `ctxt` is a local-first Rust CLI for deterministic, schema-oriented review workflow contracts. The v0.1.0 release candidate focuses on stable local evidence, explicit disabled gates, and contract-first startup behavior. +CompText CLI `ctxt` is a local-first Rust CLI for deterministic, schema-oriented review workflow contracts. The v0.1.0 release candidate focuses on local evidence, explicit disabled gates, and contract-first startup behavior. + +This release candidate is not published to crates.io yet. ## Highlights @@ -10,18 +12,33 @@ CompText CLI `ctxt` is a local-first Rust CLI for deterministic, schema-oriented - Deterministic JSON contracts for machine-readable runtime state. - Startup, readiness, review workflow, and capability contracts. - Proposal, review, run, and validation artifact inspection contracts. +- Experimental local runtime contract covering command output, JSON behavior, bounded local reads, and MCP-style stdio errors. +- DSL validation for the `local-fixture-v1` subset only. +- Encode JSON shape coverage for the current symbolic command vocabulary. +- Clean trace heuristic coverage for traces without deterministic finding phrases. +- Release-readiness blocker cleanup for clippy, Cargo package metadata, package exclusions, and README MCP wording. - README brand assets for the v0.1.0 release-candidate presentation. - Binary README and media assets are excluded from context packing. - Offline/local-first safety boundary by default. ## Boundaries -- No MCP server implementation claim. +- GitHub pre-release candidate only; no crates.io publish has occurred. +- MCP-style local stdio adapter only. +- No production MCP support claim. +- No full MCP compliance claim. - No external agent execution claim. - No provider gateway or live provider claim. - No proposal or review auto-apply claim. - No claim of hidden network activity. +## Runtime Contract Scope + +- `ctxt parse`, `ctxt encode`, `ctxt batch`, `ctxt dsl validate`, `ctxt evidence hash`, `ctxt mcp serve --allowed-root`, and `ctxt detect-illegible-cot` are documented as local runtime surfaces. +- DSL validation is limited to `local-fixture-v1`; it does not execute skills, tools, tasks, providers, shell commands, OAuth flows, network resources, or MCP tool definitions. +- MCP behavior is limited to the local stdio adapter contract and JSON-RPC-style error shapes under an explicit allowed root. +- Correctness claims are bounded to local command outputs, JSON contracts, deterministic hashes, exact exit codes, smoke tests, and `cargo test`. + ## Validation Commands ```powershell From ba9a5f11001e9c7ab3220e23426fd91833090416 Mon Sep 17 00:00:00 2001 From: ProfRandom92 Date: Tue, 16 Jun 2026 12:19:42 +0200 Subject: [PATCH 8/9] fix(runtime): address review suggestions --- src/runtime.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/runtime.rs b/src/runtime.rs index 8d005e8..f35f62e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -546,8 +546,8 @@ fn validate_dsl(text: &str) -> serde_json::Value { } fn valid_use_directive(line: &str) -> bool { - let name = line.trim_start_matches("use:"); - valid_identifier_body(name) + line.strip_prefix("use:") + .map_or(false, valid_identifier_body) } fn valid_prefixed_identifier(line: &str, prefix: char) -> bool { @@ -581,15 +581,19 @@ fn valid_resource_ref(line: &str) -> bool { } fn looks_like_block_legacy_semantic(line: &str) -> bool { - let lower = line.to_ascii_lowercase(); - lower.starts_with("oauth") - || lower.starts_with("provider") - || lower.starts_with("shell ") - || lower.starts_with("exec ") - || lower.starts_with("run ") - || lower.starts_with("http://") - || lower.starts_with("https://") - || lower.starts_with("resource://") + let starts_with_ignore_case = |prefix: &str| { + line.get(..prefix.len()) + .map_or(false, |head| head.eq_ignore_ascii_case(prefix)) + }; + + starts_with_ignore_case("oauth") + || starts_with_ignore_case("provider") + || starts_with_ignore_case("shell ") + || starts_with_ignore_case("exec ") + || starts_with_ignore_case("run ") + || starts_with_ignore_case("http://") + || starts_with_ignore_case("https://") + || starts_with_ignore_case("resource://") } fn serve_mcp(allowed_root: &Path) -> Result<(), String> { @@ -1028,3 +1032,4 @@ mod tests { assert!(parse_symbolic("C;P:FIB;MOD:UNSAFE").is_err()); } } + From bd21a5e8bbaead361b17f1731736d78ff6bf48be Mon Sep 17 00:00:00 2001 From: ProfRandom92 Date: Tue, 16 Jun 2026 12:22:13 +0200 Subject: [PATCH 9/9] fix(runtime): satisfy clippy review follow-up --- src/runtime.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/runtime.rs b/src/runtime.rs index f35f62e..63a0881 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -546,8 +546,7 @@ fn validate_dsl(text: &str) -> serde_json::Value { } fn valid_use_directive(line: &str) -> bool { - line.strip_prefix("use:") - .map_or(false, valid_identifier_body) + line.strip_prefix("use:").is_some_and(valid_identifier_body) } fn valid_prefixed_identifier(line: &str, prefix: char) -> bool { @@ -583,7 +582,7 @@ fn valid_resource_ref(line: &str) -> bool { fn looks_like_block_legacy_semantic(line: &str) -> bool { let starts_with_ignore_case = |prefix: &str| { line.get(..prefix.len()) - .map_or(false, |head| head.eq_ignore_ascii_case(prefix)) + .is_some_and(|head| head.eq_ignore_ascii_case(prefix)) }; starts_with_ignore_case("oauth") @@ -1032,4 +1031,3 @@ mod tests { assert!(parse_symbolic("C;P:FIB;MOD:UNSAFE").is_err()); } } -