From 562d57c4ce7a01430619877661fc8402c5ecff66 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:37:02 -0800 Subject: [PATCH 01/26] Add MNCS syntax metrics crate --- crates/mncs-syntax/Cargo.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 crates/mncs-syntax/Cargo.toml diff --git a/crates/mncs-syntax/Cargo.toml b/crates/mncs-syntax/Cargo.toml new file mode 100644 index 0000000..658312c --- /dev/null +++ b/crates/mncs-syntax/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mncs-syntax" +description = "Tokenizer-neutral source syntax metrics for MNCS language experiments" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +serde.workspace = true From 534c5b8b858bd688f58498b95c95dd1e55f70d3d Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:37:34 -0800 Subject: [PATCH 02/26] Implement deterministic syntax metrics --- crates/mncs-syntax/src/lib.rs | 216 ++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 crates/mncs-syntax/src/lib.rs diff --git a/crates/mncs-syntax/src/lib.rs b/crates/mncs-syntax/src/lib.rs new file mode 100644 index 0000000..945e366 --- /dev/null +++ b/crates/mncs-syntax/src/lib.rs @@ -0,0 +1,216 @@ +use std::collections::BTreeSet; + +use serde::Serialize; + +/// Tokenizer-neutral measurements for one source representation. +/// +/// `lexical_units` is not intended to predict any particular model tokenizer. +/// It counts identifiers, literals, and punctuation/operator groups after +/// comments and whitespace are removed. This makes comparisons deterministic +/// across machines and independent of a vendor-specific vocabulary. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct SourceMetrics { + pub bytes: usize, + pub characters: usize, + pub non_whitespace_characters: usize, + pub lines: usize, + pub lexical_units: usize, + pub identifiers: usize, + pub unique_identifiers: usize, + pub numeric_literals: usize, + pub string_literals: usize, + pub comments: usize, + pub max_nesting_depth: usize, +} + +pub fn analyze(source: &str) -> SourceMetrics { + let chars: Vec = source.chars().collect(); + let mut index = 0; + let mut lexical_units = 0; + let mut identifiers = 0; + let mut unique_identifiers = BTreeSet::new(); + let mut numeric_literals = 0; + let mut string_literals = 0; + let mut comments = 0; + let mut nesting_depth = 0usize; + let mut max_nesting_depth = 0usize; + + while index < chars.len() { + let current = chars[index]; + + if current.is_whitespace() { + index += 1; + continue; + } + + if current == '/' && chars.get(index + 1) == Some(&'/') { + comments += 1; + index += 2; + while index < chars.len() && chars[index] != '\n' { + index += 1; + } + continue; + } + + if current == '/' && chars.get(index + 1) == Some(&'*') { + comments += 1; + index += 2; + let mut depth = 1usize; + while index < chars.len() && depth > 0 { + if chars[index] == '/' && chars.get(index + 1) == Some(&'*') { + depth += 1; + index += 2; + } else if chars[index] == '*' && chars.get(index + 1) == Some(&'/') { + depth -= 1; + index += 2; + } else { + index += 1; + } + } + continue; + } + + if current == '"' || current == '\'' { + lexical_units += 1; + string_literals += 1; + let delimiter = current; + index += 1; + while index < chars.len() { + if chars[index] == '\\' { + index = (index + 2).min(chars.len()); + } else if chars[index] == delimiter { + index += 1; + break; + } else { + index += 1; + } + } + continue; + } + + if is_identifier_start(current) { + let start = index; + index += 1; + while index < chars.len() && is_identifier_continue(chars[index]) { + index += 1; + } + + let identifier: String = chars[start..index].iter().collect(); + unique_identifiers.insert(identifier); + identifiers += 1; + lexical_units += 1; + continue; + } + + if current.is_ascii_digit() { + numeric_literals += 1; + lexical_units += 1; + index += 1; + while index < chars.len() + && (chars[index].is_ascii_alphanumeric() + || matches!(chars[index], '_' | '.' | 'x' | 'X')) + { + index += 1; + } + continue; + } + + match current { + '(' | '[' | '{' => { + nesting_depth += 1; + max_nesting_depth = max_nesting_depth.max(nesting_depth); + } + ')' | ']' | '}' => { + nesting_depth = nesting_depth.saturating_sub(1); + } + _ => {} + } + + lexical_units += 1; + index += operator_width(&chars[index..]); + } + + SourceMetrics { + bytes: source.len(), + characters: chars.len(), + non_whitespace_characters: chars.iter().filter(|value| !value.is_whitespace()).count(), + lines: if source.is_empty() { + 0 + } else { + source.bytes().filter(|byte| *byte == b'\n').count() + 1 + }, + lexical_units, + identifiers, + unique_identifiers: unique_identifiers.len(), + numeric_literals, + string_literals, + comments, + max_nesting_depth, + } +} + +fn is_identifier_start(value: char) -> bool { + value == '_' || value.is_alphabetic() +} + +fn is_identifier_continue(value: char) -> bool { + value == '_' || value.is_alphanumeric() +} + +fn operator_width(remaining: &[char]) -> usize { + const THREE_CHARACTER_OPERATORS: [&str; 3] = ["...", "<<=", ">>="]; + const TWO_CHARACTER_OPERATORS: [&str; 21] = [ + "->", "=>", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&&", "||", + "::", "..", "<<", ">>", "&=", "|=", "^=", "??", + ]; + + for operator in THREE_CHARACTER_OPERATORS { + if starts_with(remaining, operator) { + return 3; + } + } + + for operator in TWO_CHARACTER_OPERATORS { + if starts_with(remaining, operator) { + return 2; + } + } + + 1 +} + +fn starts_with(remaining: &[char], expected: &str) -> bool { + let expected: Vec = expected.chars().collect(); + remaining.len() >= expected.len() && remaining[..expected.len()] == expected +} + +#[cfg(test)] +mod tests { + use super::analyze; + + #[test] + fn ignores_comments_when_counting_lexical_units() { + let without_comment = analyze("let value = 1;"); + let with_comment = analyze("let value = 1; // req hidden_claim\n"); + + assert_eq!(with_comment.comments, 1); + assert_eq!(with_comment.lexical_units, without_comment.lexical_units); + assert_eq!(with_comment.identifiers, without_comment.identifiers); + } + + #[test] + fn groups_common_operators() { + let metrics = analyze("req amount >= 0 && balance != 0;"); + + assert_eq!(metrics.lexical_units, 9); + assert_eq!(metrics.numeric_literals, 2); + } + + #[test] + fn records_structural_depth() { + let metrics = analyze("fn f(a: T) T { if (a.ok) { return a; } }"); + + assert_eq!(metrics.max_nesting_depth, 3); + assert!(metrics.unique_identifiers <= metrics.identifiers); + } +} From d4c07850cff658733d9f7cc003adfc8f5d9f410d Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:38:21 -0800 Subject: [PATCH 03/26] Add syntax metrics crate to workspace --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5c62e14..8cd2890 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["crates/mncs-model", "crates/mncs-cli"] +members = ["crates/mncs-model", "crates/mncs-cli", "crates/mncs-syntax"] resolver = "2" [workspace.package] From 1f1131df39008b4949f86abf697e1328c300a428 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:38:39 -0800 Subject: [PATCH 04/26] Add syntax tournament dependencies --- crates/mncs-cli/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/mncs-cli/Cargo.toml b/crates/mncs-cli/Cargo.toml index 9a3464a..d089113 100644 --- a/crates/mncs-cli/Cargo.toml +++ b/crates/mncs-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mncs-cli" -description = "Command-line validator for MNCS semantic manifests" +description = "Command-line tools for MNCS semantic manifests and syntax experiments" version.workspace = true edition.workspace = true license.workspace = true @@ -13,4 +13,6 @@ path = "src/main.rs" [dependencies] mncs-model = { path = "../mncs-model" } +mncs-syntax = { path = "../mncs-syntax" } +serde.workspace = true serde_json.workspace = true From e2fed0c26fa4dc38f12e77de6e2ed3b4f5caa879 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:39:03 -0800 Subject: [PATCH 05/26] Add syntax metrics and tournament commands --- crates/mncs-cli/src/main.rs | 187 +++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 13 deletions(-) diff --git a/crates/mncs-cli/src/main.rs b/crates/mncs-cli/src/main.rs index 843f684..f694d89 100644 --- a/crates/mncs-cli/src/main.rs +++ b/crates/mncs-cli/src/main.rs @@ -1,6 +1,12 @@ -use std::{env, fs, process::ExitCode}; +use std::{ + env, fs, + path::Path, + process::ExitCode, +}; use mncs_model::Program; +use mncs_syntax::{analyze, SourceMetrics}; +use serde::{Deserialize, Serialize}; fn main() -> ExitCode { let mut args = env::args().skip(1); @@ -22,6 +28,22 @@ fn main() -> ExitCode { } validate(&path) } + "syntax-metrics" => { + let paths: Vec = args.collect(); + syntax_metrics(paths) + } + "syntax-tournament" => { + let Some(path) = args.next() else { + eprintln!("error: syntax-tournament requires a tournament manifest"); + print_usage(); + return ExitCode::from(2); + }; + if args.next().is_some() { + eprintln!("error: unexpected additional arguments"); + return ExitCode::from(2); + } + syntax_tournament(&path) + } "--help" | "-h" | "help" => { print_usage(); ExitCode::SUCCESS @@ -35,12 +57,9 @@ fn main() -> ExitCode { } fn validate(path: &str) -> ExitCode { - let input = match fs::read_to_string(path) { + let input = match read_source(path) { Ok(input) => input, - Err(error) => { - eprintln!("error: unable to read {path:?}: {error}"); - return ExitCode::from(2); - } + Err(code) => return code, }; let program = match Program::from_json(&input) { @@ -52,12 +71,8 @@ fn validate(path: &str) -> ExitCode { }; let report = program.validate(); - match serde_json::to_string_pretty(&report) { - Ok(json) => println!("{json}"), - Err(error) => { - eprintln!("error: unable to serialize validation report: {error}"); - return ExitCode::from(2); - } + if print_json(&report).is_err() { + return ExitCode::from(2); } if report.valid { @@ -67,9 +82,155 @@ fn validate(path: &str) -> ExitCode { } } +#[derive(Debug, Serialize)] +struct SourceReport { + path: String, + metrics: SourceMetrics, +} + +fn syntax_metrics(paths: Vec) -> ExitCode { + if paths.is_empty() { + eprintln!("error: syntax-metrics requires at least one source path"); + print_usage(); + return ExitCode::from(2); + } + + let mut reports = Vec::with_capacity(paths.len()); + for path in paths { + let input = match read_source(&path) { + Ok(input) => input, + Err(code) => return code, + }; + reports.push(SourceReport { + path, + metrics: analyze(&input), + }); + } + + match print_json(&reports) { + Ok(()) => ExitCode::SUCCESS, + Err(()) => ExitCode::from(2), + } +} + +#[derive(Debug, Deserialize)] +struct TournamentManifest { + name: String, + semantic_claims: Vec, + candidates: Vec, +} + +#[derive(Debug, Deserialize)] +struct TournamentCandidate { + name: String, + role: String, + path: String, +} + +#[derive(Debug, Serialize)] +struct TournamentReport { + name: String, + claim_count: usize, + candidates: Vec, +} + +#[derive(Debug, Serialize)] +struct CandidateReport { + name: String, + role: String, + path: String, + lexical_units_per_claim_milli: usize, + non_whitespace_characters_per_claim_milli: usize, + metrics: SourceMetrics, +} + +fn syntax_tournament(path: &str) -> ExitCode { + let input = match read_source(path) { + Ok(input) => input, + Err(code) => return code, + }; + + let manifest: TournamentManifest = match serde_json::from_str(&input) { + Ok(manifest) => manifest, + Err(error) => { + eprintln!("error: unable to parse tournament manifest {path:?}: {error}"); + return ExitCode::from(2); + } + }; + + if manifest.semantic_claims.is_empty() { + eprintln!("error: tournament must declare at least one semantic claim"); + return ExitCode::from(2); + } + if manifest.candidates.is_empty() { + eprintln!("error: tournament must declare at least one candidate"); + return ExitCode::from(2); + } + + let base = Path::new(path).parent().unwrap_or_else(|| Path::new(".")); + let claim_count = manifest.semantic_claims.len(); + let mut candidates = Vec::with_capacity(manifest.candidates.len()); + + for candidate in manifest.candidates { + let resolved_path = base.join(&candidate.path); + let display_path = resolved_path.to_string_lossy().into_owned(); + let input = match read_source(&display_path) { + Ok(input) => input, + Err(code) => return code, + }; + let metrics = analyze(&input); + + candidates.push(CandidateReport { + name: candidate.name, + role: candidate.role, + path: candidate.path, + lexical_units_per_claim_milli: metrics.lexical_units.saturating_mul(1000) + / claim_count, + non_whitespace_characters_per_claim_milli: metrics + .non_whitespace_characters + .saturating_mul(1000) + / claim_count, + metrics, + }); + } + + let report = TournamentReport { + name: manifest.name, + claim_count, + candidates, + }; + + match print_json(&report) { + Ok(()) => ExitCode::SUCCESS, + Err(()) => ExitCode::from(2), + } +} + +fn read_source(path: &str) -> Result { + fs::read_to_string(path).map_err(|error| { + eprintln!("error: unable to read {path:?}: {error}"); + ExitCode::from(2) + }) +} + +fn print_json(value: &T) -> Result<(), ()> { + match serde_json::to_string_pretty(value) { + Ok(json) => { + println!("{json}"); + Ok(()) + } + Err(error) => { + eprintln!("error: unable to serialize report: {error}"); + Err(()) + } + } +} + fn print_usage() { - eprintln!("MNCS semantic manifest validator"); + eprintln!("MNCS language research tools"); eprintln!(); eprintln!("Usage:"); eprintln!(" mncs validate "); + eprintln!(" mncs syntax-metrics [source ...]"); + eprintln!(" mncs syntax-tournament "); } From 9482890a95ea029a606f6f7597e637770152e490 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:39:18 -0800 Subject: [PATCH 06/26] Add Zig-influenced syntax candidate --- .../syntax/zig-like/account-transfer.mncs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 examples/syntax/zig-like/account-transfer.mncs diff --git a/examples/syntax/zig-like/account-transfer.mncs b/examples/syntax/zig-like/account-transfer.mncs new file mode 100644 index 0000000..fdaa982 --- /dev/null +++ b/examples/syntax/zig-like/account-transfer.mncs @@ -0,0 +1,52 @@ +module banking.transfer; + +const Account = struct { + id: AccountId, + balance: Money, + status: AccountStatus, +}; + +cap AccountWrite(id: AccountId); +cap AuditAppend; + +pub fn transfer( + src: *mut Account, + dst: *mut Account, + amount: Money, + src_write: AccountWrite(src.id), + dst_write: AccountWrite(dst.id), + audit: AuditAppend, +) TransferError!Receipt +spec { + req amount > 0; + req src.status == .active; + req dst.status == .active; + req src.balance >= amount; + + post src.balance == old(src.balance) - amount; + post dst.balance == old(dst.balance) + amount; + keep src.balance + dst.balance; + + read src.{status, balance}; + read dst.{status, balance}; + write src.balance with src_write; + write dst.balance with dst_write; + emit Audit.transfer with audit; + + fail atomic; + cost time O(1), mem <= 512B; +} +{ + guard amount > 0 else return error.InvalidAmount; + guard src.status == .active else return error.AccountLocked; + guard dst.status == .active else return error.AccountLocked; + guard src.balance >= amount else return error.InsufficientFunds; + + atomic { + src.balance -= amount; + dst.balance += amount; + try audit.append(src.id, dst.id, amount); + } + + return Receipt.init(src.id, dst.id, amount); +} From 51bdf8ff46a2b3d0d488f8555ef3ca80ed955a3f Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:39:30 -0800 Subject: [PATCH 07/26] Add fully structured syntax candidate --- .../syntax/structured/account-transfer.mncs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 examples/syntax/structured/account-transfer.mncs diff --git a/examples/syntax/structured/account-transfer.mncs b/examples/syntax/structured/account-transfer.mncs new file mode 100644 index 0000000..d4683a0 --- /dev/null +++ b/examples/syntax/structured/account-transfer.mncs @@ -0,0 +1,76 @@ +module banking.transfer { + type Account { + field id: AccountId; + field balance: Money; + field status: AccountStatus; + } + + capability AccountWrite { + parameter id: AccountId; + } + + capability AuditAppend; + + function transfer { + parameters { + src: mutable_pointer; + dst: mutable_pointer; + amount: Money; + src_write: AccountWrite(src.id); + dst_write: AccountWrite(dst.id); + audit: AuditAppend; + } + + returns TransferError!Receipt; + + specification { + requirements { + amount > 0; + src.status == active; + dst.status == active; + src.balance >= amount; + } + + postconditions { + src.balance == old(src.balance) - amount; + dst.balance == old(dst.balance) + amount; + } + + preserves { + src.balance + dst.balance; + } + + effects { + read src.status; + read src.balance; + read dst.status; + read dst.balance; + write src.balance using src_write; + write dst.balance using dst_write; + emit Audit.transfer using audit; + } + + failure atomic; + + resources { + time <= O(1); + memory <= 512B; + } + } + + body { + guard amount > 0 else return error.InvalidAmount; + guard src.status == active else return error.AccountLocked; + guard dst.status == active else return error.AccountLocked; + guard src.balance >= amount else return error.InsufficientFunds; + + atomic { + src.balance = src.balance - amount; + dst.balance = dst.balance + amount; + try audit.append(src.id, dst.id, amount); + } + + return Receipt.init(src.id, dst.id, amount); + } + } +} From ff6ab2fdbea8dc5588437c7c73e9c554ca3583bf Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:39:53 -0800 Subject: [PATCH 08/26] Add compact syntax candidate --- examples/syntax/minimal/account-transfer.mncs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/syntax/minimal/account-transfer.mncs diff --git a/examples/syntax/minimal/account-transfer.mncs b/examples/syntax/minimal/account-transfer.mncs new file mode 100644 index 0000000..84508a2 --- /dev/null +++ b/examples/syntax/minimal/account-transfer.mncs @@ -0,0 +1,44 @@ +module banking.transfer; + +record Account(id: AccountId, balance: Money, status: AccountStatus); +capability AccountWrite(id: AccountId); +capability AuditAppend; + +pub fn transfer( + src: mutable Account, + dst: mutable Account, + amount: Money, + src_write: AccountWrite(src.id), + dst_write: AccountWrite(dst.id), + audit: AuditAppend, +) -> TransferError!Receipt { + req { + amount > 0; + src.status == active; + dst.status == active; + src.balance >= amount; + } + post { + src.balance == old(src.balance) - amount; + dst.balance == old(dst.balance) + amount; + } + keep src.balance + dst.balance; + read src.{status, balance}, dst.{status, balance}; + write src.balance with src_write, dst.balance with dst_write; + emit Audit.transfer with audit; + fail atomic; + cost time O(1), memory <= 512B; + + guard amount > 0 else return InvalidAmount; + guard src.status == active else return AccountLocked; + guard dst.status == active else return AccountLocked; + guard src.balance >= amount else return InsufficientFunds; + + atomic { + src.balance = src.balance - amount; + dst.balance = dst.balance + amount; + try audit.append(src.id, dst.id, amount); + } + + return Receipt.init(src.id, dst.id, amount); +} From 09facb3f49abc19ede4951b0c8b88ba81ba4c9fd Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:40:02 -0800 Subject: [PATCH 09/26] Add canonical agent semantic form --- examples/canonical/account-transfer.mncs-sem | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/canonical/account-transfer.mncs-sem diff --git a/examples/canonical/account-transfer.mncs-sem b/examples/canonical/account-transfer.mncs-sem new file mode 100644 index 0000000..7ebc951 --- /dev/null +++ b/examples/canonical/account-transfer.mncs-sem @@ -0,0 +1,17 @@ +m banking.transfer + +t Account=[id:AccountId,balance:Money,status:AccountStatus] +c AccountWrite(AccountId) +c AuditAppend + +f transfer +in [src:mut Account,dst:mut Account,amount:Money] +cap [src_write:AccountWrite(src.id),dst_write:AccountWrite(dst.id),audit:AuditAppend] +out TransferError!Receipt +req [amount>0,src.status=active,dst.status=active,src.balance>=amount] +post [src.balance=old(src.balance)-amount,dst.balance=old(dst.balance)+amount] +keep [src.balance+dst.balance] +fx [r(src.status,src.balance,dst.status,dst.balance),w(src.balance|src_write),w(dst.balance|dst_write),emit(Audit.transfer|audit)] +fail atomic +cost [time=O(1),memory<=512B] +body [guard(amount>0|InvalidAmount),guard(src.status=active|AccountLocked),guard(dst.status=active|AccountLocked),guard(src.balance>=amount|InsufficientFunds),atomic(src.balance-=amount,dst.balance+=amount,try audit.append(src.id,dst.id,amount)),return Receipt.init(src.id,dst.id,amount)] From 0129aa4ebbb8cfc3aa8fb012281e14a1fbf77fd7 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:40:11 -0800 Subject: [PATCH 10/26] Add semantic repair patch example --- .../patches/close-audit-effect.mncs-patch | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/patches/close-audit-effect.mncs-patch diff --git a/examples/patches/close-audit-effect.mncs-patch b/examples/patches/close-audit-effect.mncs-patch new file mode 100644 index 0000000..a1706ba --- /dev/null +++ b/examples/patches/close-audit-effect.mncs-patch @@ -0,0 +1,29 @@ +patch banking.transfer.transfer { + cause effect_closure { + operation audit.append; + requires AuditAppend; + missing function.capabilities; + } + + add parameter audit: AuditAppend; + bind emit Audit.transfer with audit; + + preserve { + contract Conservation; + public result TransferError!Receipt; + failure atomic; + cost time O(1); + } + + forbid { + unrelated_source_change; + capability_expansion beyond AuditAppend; + evidence_promotion; + } + + budget { + candidates <= 4; + verifier_calls <= 12; + recursion_depth <= 2; + } +} From b1db4672276d88415282be1440037e65fe439c88 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:40:24 -0800 Subject: [PATCH 11/26] Add account transfer syntax tournament --- .../syntax/account-transfer.tournament.json | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/syntax/account-transfer.tournament.json diff --git a/examples/syntax/account-transfer.tournament.json b/examples/syntax/account-transfer.tournament.json new file mode 100644 index 0000000..1c079d7 --- /dev/null +++ b/examples/syntax/account-transfer.tournament.json @@ -0,0 +1,50 @@ +{ + "name": "account-transfer-equivalent-semantics", + "semantic_claims": [ + "module identity is banking.transfer", + "Account has id, balance, and status fields", + "AccountWrite authority is scoped by account identity", + "AuditAppend authority is explicit", + "transfer receives mutable source account state", + "transfer receives mutable destination account state", + "amount has Money type", + "source write authority is bound to source identity", + "destination write authority is bound to destination identity", + "audit authority is passed as a value", + "result is Receipt or TransferError", + "amount must be positive", + "source account must be active", + "destination account must be active", + "source balance must cover amount", + "source post-balance equals old balance minus amount", + "destination post-balance equals old balance plus amount", + "combined balance is conserved", + "status and balance reads are declared", + "source balance write is authorized", + "destination balance write is authorized", + "audit emission is authorized", + "failure is atomic with constant-time and 512-byte bounds" + ], + "candidates": [ + { + "name": "zig-like-source", + "role": "human-source", + "path": "zig-like/account-transfer.mncs" + }, + { + "name": "fully-structured-source", + "role": "human-source", + "path": "structured/account-transfer.mncs" + }, + { + "name": "minimal-source", + "role": "human-source", + "path": "minimal/account-transfer.mncs" + }, + { + "name": "canonical-semantic-form", + "role": "agent-and-tooling-form", + "path": "../canonical/account-transfer.mncs-sem" + } + ] +} From 1b6fa4ad73da7e5b9d94b3d0caf2f02267fe069b Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:41:14 -0800 Subject: [PATCH 12/26] Add source representation and semantic density RFC --- ...ce-representations-and-semantic-density.md | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 rfcs/0005-source-representations-and-semantic-density.md diff --git a/rfcs/0005-source-representations-and-semantic-density.md b/rfcs/0005-source-representations-and-semantic-density.md new file mode 100644 index 0000000..d03eb1d --- /dev/null +++ b/rfcs/0005-source-representations-and-semantic-density.md @@ -0,0 +1,238 @@ +# RFC 0005: Source Representations and Semantic Density + +- **Status:** Proposed +- **Authors:** MNCS Language Project +- **Target:** syntax research track + +## Summary + +MNCS Language should use three related representations rather than forcing human source, agent communication, and backend lowering into one notation: + +1. a readable, Zig-influenced human source form; +2. a compact canonical semantic form for agents, Forge, RAVEL, and micro-verifiers; +3. verified intermediate representations for control flow, state, memory, and backend lowering. + +The project should optimize for **verified semantic density**: the amount of explicit, unambiguous, independently checkable meaning communicated per representation unit. It should not optimize only for bytes, characters, or one vendor's tokenizer. + +This RFC establishes an experimental syntax laboratory. It does not select a final grammar. + +## Motivation + +A language designed only for minimum character count can hide authority, failure behavior, assumptions, or verification obligations. A language designed only for human familiarity can force agents to repeatedly ingest large source files and analyzer reports. + +MNCS needs both: + +- human-readable code suitable for review and intentional modification; +- compact semantic slices suitable for recursive debugging and targeted repair. + +The largest token reduction should come from retrieving only relevant semantic nodes, not from making ordinary source cryptic. + +## Representation model + +```text +human source + ↕ deterministic semantic round trip +canonical semantic graph/form + ↓ verified lowering +high MNCS IR + ↓ +verified SSA + ↓ +backend IR and machine code +``` + +A semantic patch targets stable semantic identities and relationships. It does not perform unrestricted textual search and replacement. + +## Human source direction + +The leading candidate is a restrained, brace-based systems syntax influenced by Zig: + +- explicit declarations; +- braces and semicolons; +- deterministic evaluation order; +- explicit mutation, allocation, effects, errors, and capabilities; +- compact error-union notation where it remains unambiguous; +- short semantic keywords such as `req`, `post`, `keep`, `read`, `write`, `emit`, `fail`, and `cost`; +- a structured `spec` region adjacent to a function; +- no unrestricted textual macros; +- canonical formatting. + +Zig is an influence, not a compatibility target. MNCS semantics determine the language. + +## Canonical semantic form + +The canonical semantic form is intended for bounded machine exchange. It may use shorter, stable operators because it is generated and parsed mechanically rather than authored as ordinary application source. + +Example: + +```text +f transfer +in [src:mut Account,dst:mut Account,amount:Money] +cap [src_write:AccountWrite(src.id),dst_write:AccountWrite(dst.id),audit:AuditAppend] +out TransferError!Receipt +req [amount>0,src.status=active,dst.status=active,src.balance>=amount] +post [src.balance=old(src.balance)-amount,dst.balance=old(dst.balance)+amount] +keep [src.balance+dst.balance] +fx [r(src.status,src.balance,dst.status,dst.balance),w(src.balance|src_write),w(dst.balance|dst_write),emit(Audit.transfer|audit)] +fail atomic +cost [time=O(1),memory<=512B] +``` + +The canonical form MUST: + +- preserve stable semantic identities; +- have one canonical serialization; +- expose all declared effects, capabilities, assumptions, and evidence relationships; +- support bounded subgraph projection; +- round-trip without hidden semantic loss; +- be versioned independently from surface syntax. + +It is not the default human programming language. + +## Semantic patch form + +Recursive tooling should exchange semantic transformations rather than whole-file rewrites when possible. + +A patch MUST identify: + +- the subject identity; +- the diagnostic or causal basis; +- requested graph changes; +- protected properties; +- forbidden authority or scope expansion; +- expected invalidation; +- refinement budgets. + +Patch application creates an isolated candidate. It does not directly alter the trusted baseline or promote its own evidence. + +## Semantic density + +Semantic density is not a single number. The initial laboratory records: + +- bytes; +- characters; +- non-whitespace characters; +- deterministic lexical units; +- lines; +- identifier count and repetition; +- nesting depth; +- declared semantic-claim count; +- lexical units per claim; +- non-whitespace characters per claim. + +Future experiments should add: + +- model-tokenizer counts across multiple tokenizer families; +- parse success and recovery; +- source-to-graph round-trip accuracy; +- agent generation success; +- localized repair success; +- human comprehension; +- omission rates for effects and capabilities; +- semantic diff size; +- verifier workload. + +No syntax wins solely because it has the fewest lexical units. A candidate that omits required meaning is not equivalent and must not be compared as though it were. + +## Tokenizer neutrality + +The language MUST NOT depend on one model tokenizer. Token vocabularies change by model and provider. Early metrics therefore use a deterministic lexical proxy and explicit semantic claims. + +Model-specific token counts MAY be collected as additional evidence, but they must identify the tokenizer and version. + +## Syntax tournament + +Equivalent candidate programs should be stored with a tournament manifest declaring their shared semantic claims. The initial account-transfer corpus compares: + +- Zig-influenced human source; +- fully structured human source; +- compact minimal human source; +- canonical agent/tooling form. + +Additional corpora should cover: + +- arithmetic and pure functions; +- bounded buffers; +- filesystem effects; +- network capabilities; +- concurrency; +- unsafe hardware access; +- foreign-function boundaries; +- recursive repair proposals; +- generics and collections. + +## Canonical formatting + +Every accepted surface candidate MUST define one canonical formatter. Formatting must not alter semantics. Source order should affect meaning only where order is explicitly semantic. + +Equivalent sugar must lower deterministically to the same semantic graph or be rejected. + +## Reflection and self-repair + +Source reflection should expose semantic graph views rather than unrestricted source strings. Repair systems should request bounded slices such as: + +```text +subject +failed obligation +minimal causal slice +affected evidence +protected properties +available authority +``` + +The response should normally be a semantic patch, not a complete regenerated file. + +## Macro and compile-time generation constraints + +Generated code is permitted only when: + +- expansion is deterministic; +- expanded semantics are inspectable; +- generated effects and capabilities are visible; +- expansion contributes to semantic identity; +- diagnostics map to generator and generated nodes; +- no macro bypasses verification or capability closure. + +Unrestricted textual macros are outside the proposed language model. + +## Security consequences + +Compactness must never erase: + +- authority boundaries; +- effects; +- assumptions; +- failure behavior; +- unsafe regions; +- evidence status; +- candidate-versus-baseline identity. + +The canonical form is security-sensitive. Ambiguous parsing, non-canonical serialization, or lossy source projection could attach evidence to the wrong subject or permit semantic substitution. + +## Compatibility + +This RFC adds an experimental track and tooling. It does not make the example syntax valid production source, select a file extension, or promise compatibility with later grammars. + +## Unresolved questions + +- ownership and borrowing notation; +- type and generic syntax; +- exact error-union representation; +- location and shape of `spec` blocks; +- whether compact semantic keywords are reserved globally; +- canonical semantic binary encoding; +- stable identity syntax; +- parser and formatter implementation strategy; +- acceptable compile-time generation model; +- how semantic density should weight readability, omission risk, and verifier cost. + +## Acceptance criteria + +This RFC is sufficiently implemented for the current phase when: + +- at least three human source candidates express the same declared claims; +- a canonical semantic candidate expresses those claims; +- a semantic patch example exists; +- deterministic metrics are executable from the CLI; +- CI runs the tournament; +- project documentation clearly states that no final grammar has been selected. From 82ccaaf0e56c3d9c1864210300e7b2620d68e94e Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:41:36 -0800 Subject: [PATCH 13/26] Document source syntax laboratory --- docs/source-syntax-lab.md | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 docs/source-syntax-lab.md diff --git a/docs/source-syntax-lab.md b/docs/source-syntax-lab.md new file mode 100644 index 0000000..aeff0c4 --- /dev/null +++ b/docs/source-syntax-lab.md @@ -0,0 +1,103 @@ +# Source Syntax Laboratory + +MNCS Language does not yet have a selected surface grammar. The repository now contains an evidence-producing syntax laboratory rather than a single speculative syntax declaration. + +## Current hypothesis + +The strongest human-source candidate is a restrained systems language influenced by Zig: + +- ordinary declarations, braces, and semicolons; +- explicit mutation and error propagation; +- short contract and effect keywords; +- capabilities represented as typed authority; +- specification information adjacent to implementation; +- deterministic formatting and lowering. + +The canonical agent representation is intentionally separate and more compact. + +## Why three forms + +### Human source + +Optimized for comprehension, review, and intentional authoring. It must remain complete enough that authority and behavior are not hidden behind tooling. + +### Canonical semantic form + +Optimized for retrieval, comparison, micro-verification, and agent exchange. It contains no irrelevant whitespace or optional sugar and can be projected as a bounded semantic slice. + +### Verified IR + +Optimized for explicit control flow, state transitions, proof obligations, and backend lowering. It is not intended for ordinary source authoring. + +## Semantic density + +The laboratory compares equivalent representations against an explicit claim list. This prevents a shorter candidate from appearing efficient by dropping meaning. + +Run the current tournament: + +```bash +cargo run -p mncs-cli -- syntax-tournament \ + examples/syntax/account-transfer.tournament.json +``` + +Inspect raw measurements: + +```bash +cargo run -p mncs-cli -- syntax-metrics \ + examples/syntax/zig-like/account-transfer.mncs \ + examples/syntax/structured/account-transfer.mncs \ + examples/syntax/minimal/account-transfer.mncs \ + examples/canonical/account-transfer.mncs-sem +``` + +The initial lexical metric is deterministic and tokenizer-neutral. It is a comparison baseline, not a claim about exact inference cost on any model. + +## Candidate roles + +The tournament manifest records a role for every candidate. A canonical semantic form should not automatically replace the human source merely because it is smaller. Candidate roles should be compared both within-role and across the whole pipeline. + +## Evaluation dimensions + +Later syntax studies should record: + +- semantic claims represented; +- lexical and model-token counts; +- parse reliability; +- formatting stability; +- graph round-trip fidelity; +- human comprehension; +- agent generation and repair success; +- effect or capability omission rate; +- semantic patch size; +- evidence invalidation precision; +- verifier cost. + +## Recursive improvement + +Syntax itself can participate in bounded MNCS refinement: + +1. compile a shared semantic corpus into each candidate form; +2. collect density, parser, repair, and comprehension evidence; +3. localize recurrent ambiguity or unnecessary repetition; +4. propose a syntax transformation; +5. regenerate the corpus in isolation; +6. verify semantic equivalence and compare evidence; +7. promote or reject the proposal under explicit policy. + +This is recursive language improvement without allowing the language generator to silently redefine correctness. + +## Current artifacts + +- `rfcs/0005-source-representations-and-semantic-density.md` +- `spec/source-representations.md` +- `examples/syntax/account-transfer.tournament.json` +- `examples/syntax/zig-like/` +- `examples/syntax/structured/` +- `examples/syntax/minimal/` +- `examples/canonical/` +- `examples/patches/` +- `crates/mncs-syntax/` + +## Status warning + +All example syntax is experimental. It may be changed or removed without compatibility guarantees. The examples test representation choices; they are not yet accepted MNCS programs. From ad1afd3fba73d9b8aad0ab62c8d90c582d32434c Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:42:05 -0800 Subject: [PATCH 14/26] Specify source representation requirements --- spec/source-representations.md | 156 +++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 spec/source-representations.md diff --git a/spec/source-representations.md b/spec/source-representations.md new file mode 100644 index 0000000..ccf4068 --- /dev/null +++ b/spec/source-representations.md @@ -0,0 +1,156 @@ +# Source Representations + +This document defines early requirements for source, canonical semantic, and semantic patch representations. It does not define a complete grammar. + +## Representation classes + +An MNCS implementation SHOULD distinguish: + +1. **human source**, intended for normal authoring and review; +2. **canonical semantic form**, intended for deterministic machine exchange and bounded graph projection; +3. **semantic patch form**, intended to propose isolated graph transformations; +4. **verified IR**, intended for explicit control flow, state, and lowering. + +A tool MUST identify which representation class it consumes or emits. + +## Human source requirements + +Human source MUST: + +- parse deterministically; +- lower to an inspectable semantic graph; +- expose declared effects and authorizing capabilities; +- preserve contract, assumption, failure, and evidence relationships; +- support canonical formatting; +- map diagnostics to stable semantic subjects and source spans; +- avoid semantics that exist only in comments or formatting; +- avoid unrestricted textual macro expansion. + +Human source SHOULD: + +- use common ASCII delimiters and short recognizable keywords; +- make simple functions visually simple; +- allow specification clauses to be grouped without repeating their subject; +- use deterministic evaluation order; +- require explicit returns, mutation, error propagation, and ambient-resource access. + +## Canonical semantic form requirements + +Canonical semantic form MUST: + +- be versioned; +- serialize one semantic graph in one canonical way; +- retain stable subject, property, capability, assumption, evidence, and transformation identities; +- expose every declared effect and its authority edge; +- distinguish baseline, candidate, and promoted identities; +- support bounded projection by semantic identity; +- be lossless with respect to defined language semantics; +- reject ambiguous or duplicate encodings. + +Canonical semantic form MAY be less readable and more compact than human source. It MUST remain inspectable with standard tooling. + +## Semantic patch requirements + +A semantic patch MUST identify: + +- target semantic identity; +- diagnostic, obligation, or explicit user intent motivating the patch; +- requested node and edge additions, removals, or replacements; +- protected properties; +- forbidden changes; +- required authority; +- expected evidence invalidation; +- refinement and resource budgets. + +Applying a patch MUST create a candidate identity before verification. Patch application MUST NOT automatically promote evidence or modify the trusted baseline. + +## Round-trip requirements + +Once a grammar is selected, the following should hold for supported source: + +```text +parse(format(parse(source))) == parse(source) +``` + +and: + +```text +semantic(parse(render(semantic_graph))) == semantic_graph +``` + +where equality is defined over canonical semantic identity rather than incidental source trivia. + +## Semantic density measurement + +A syntax comparison MUST declare the semantic claims shared by all candidates. A candidate missing a claim is not equivalent. + +The initial deterministic metrics are: + +- lexical units after comments and whitespace are removed; +- non-whitespace characters; +- lines; +- identifiers and unique identifiers; +- literal counts; +- maximum delimiter nesting; +- lexical units per semantic claim; +- non-whitespace characters per semantic claim. + +A report MUST state that these metrics are tokenizer-neutral proxies. Model-specific token counts MUST name the tokenizer and version. + +## Keyword direction + +The experimental compact vocabulary includes: + +- `req` — caller obligation or precondition; +- `post` — postcondition; +- `keep` — preserved property; +- `read` — read effect; +- `write` — write effect and authority binding; +- `emit` — event or append effect and authority binding; +- `call` — component or external call effect; +- `assume` — named assumption; +- `prove` — evidence requirement; +- `fail` — failure semantics; +- `cost` — resource or complexity bound; +- `guard` — runtime-checked condition. + +These names are experimental. Single-character semantic keywords are discouraged because they reduce inspectability and may not improve tokenization consistently. + +## Zig influence + +The leading surface candidate may adopt Zig-like characteristics such as explicit declarations, compact error unions, braces, semicolons, and visible low-level operations. Compatibility with Zig syntax or semantics is not required. + +## Token efficiency constraints + +Token efficiency MUST NOT justify hiding or dropping: + +- authority; +- effects; +- assumptions; +- failure behavior; +- unsafe boundaries; +- evidence status; +- semantic identity; +- candidate state. + +The preferred optimization order is: + +1. retrieve a smaller semantic slice; +2. remove representational repetition through canonical grouping; +3. use short stable keywords; +4. reduce punctuation only when ambiguity does not increase; +5. consider model-specific token behavior only as additional evidence. + +## Open requirements + +The following remain unresolved: + +- ownership and reference notation; +- generic syntax; +- compile-time execution; +- pattern matching; +- concurrency syntax; +- exact `spec` placement; +- error propagation syntax; +- stable identity notation; +- canonical binary representation. From 81e2d51eea8fa0cf26004a7c1137eceff27e406f Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:42:33 -0800 Subject: [PATCH 15/26] Index source representation specification --- spec/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/README.md b/spec/README.md index a58b384..a65fed2 100644 --- a/spec/README.md +++ b/spec/README.md @@ -9,6 +9,7 @@ Normative terms such as **MUST**, **SHOULD**, and **MAY** indicate intended requ - [Semantic Core](semantic-core.md) - [Contracts and Evidence](contracts-and-evidence.md) - [Effects and Capabilities](effects-and-capabilities.md) +- [Source Representations](source-representations.md) - [Verified Intermediate Representation](verified-ir.md) - [Recursive Introspection and Refinement](recursive-refinement.md) From 48024df02ae538a0bea9e43cd7d8026ac6241f13 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:42:41 -0800 Subject: [PATCH 16/26] Index syntax representation RFC --- rfcs/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rfcs/README.md b/rfcs/README.md index b1c7088..95a5d00 100644 --- a/rfcs/README.md +++ b/rfcs/README.md @@ -5,9 +5,18 @@ RFCs record substantial semantic and architectural proposals before they are con ## Status values - **Draft** — open for design work. +- **Proposed** — concrete direction implemented experimentally but not selected as final. - **Accepted** — approved direction, potentially not implemented. - **Implemented** — represented in the prototype and tests. - **Superseded** — replaced by another RFC. - **Rejected** — considered and intentionally declined. RFC acceptance does not imply production stability. The repository remains pre-specification research. + +## Current RFCs + +- [RFC 0001: Semantic Foundation](0001-semantic-foundation.md) +- [RFC 0002: Contract and Evidence Model](0002-contract-evidence-model.md) +- [RFC 0003: Verified Intermediate Representation](0003-verified-ir.md) +- [RFC 0004: Recursive Introspection and Refinement](0004-recursive-introspection-and-refinement.md) +- [RFC 0005: Source Representations and Semantic Density](0005-source-representations-and-semantic-density.md) From 023396f7dd8cae0b5a7b3d185d1013e5760567f3 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:42:49 -0800 Subject: [PATCH 17/26] Run syntax tournament in CI --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 754eca9..827052f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,3 +31,7 @@ jobs: echo "invalid example was unexpectedly accepted" >&2 exit 1 fi + - name: Run source syntax tournament + run: >- + cargo run -p mncs-cli -- syntax-tournament + examples/syntax/account-transfer.tournament.json From 809e4a1c6b2bbd8e26697d2ff2afe0696643a034 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:43:16 -0800 Subject: [PATCH 18/26] Correct syntax nesting test --- crates/mncs-syntax/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/mncs-syntax/src/lib.rs b/crates/mncs-syntax/src/lib.rs index 945e366..78f9985 100644 --- a/crates/mncs-syntax/src/lib.rs +++ b/crates/mncs-syntax/src/lib.rs @@ -210,7 +210,7 @@ mod tests { fn records_structural_depth() { let metrics = analyze("fn f(a: T) T { if (a.ok) { return a; } }"); - assert_eq!(metrics.max_nesting_depth, 3); + assert_eq!(metrics.max_nesting_depth, 2); assert!(metrics.unique_identifiers <= metrics.identifiers); } } From c286ddb47807a2beb0be3ef0a8eb97b7a9d02ec6 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:43:56 -0800 Subject: [PATCH 19/26] Document source syntax laboratory --- README.md | 58 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 4f24889..83bcb89 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Research and reference implementation for a general-purpose, verification-native programming language built on Machine-Native Complexity Standard (MNCS) principles. -> **Project status:** semantic-model research and executable prototype. No surface-language syntax, compiler stability, or production suitability is claimed yet. +> **Project status:** semantic-model and source-representation research with executable prototypes. No final grammar, compiler stability, or production suitability is claimed yet. ## Why this project exists @@ -27,14 +27,15 @@ An MNCS-oriented program should make it possible to answer: ## What is in this repository -- `docs/` — vision, architecture, recursive refinement, terminology, trust model, and explicit non-goals. -- `spec/` — early normative semantic documents. +- `docs/` — vision, architecture, syntax research, recursive refinement, terminology, trust model, and explicit non-goals. +- `spec/` — early normative semantic and representation documents. - `rfcs/` — design proposals that can evolve independently of the specification. - `crates/mncs-model/` — an executable Rust model of the initial semantic objects and validation rules. -- `crates/mncs-cli/` — a small validator for experimental JSON semantic manifests. -- `examples/` — one accepted manifest and one intentionally rejected manifest. +- `crates/mncs-syntax/` — deterministic, tokenizer-neutral source representation metrics. +- `crates/mncs-cli/` — validation and syntax-tournament commands. +- `examples/` — semantic manifests, competing source candidates, canonical semantic forms, and semantic patches. -The JSON manifests are not proposed source syntax. They are a temporary, inspectable transport representation used to test the semantic model before committing to a parser or grammar. +The JSON manifests and source candidates are experimental transport and research representations. They are not yet a selected production grammar. ## Current semantic objects @@ -52,7 +53,7 @@ The 0.1 model contains: A key initial rule is that every effect must identify an authorizing capability, and that capability must be declared by the function. Evidence must reference a declared contract property rather than floating as unbound metadata. -## Try the prototype +## Try the semantic prototype ```bash cargo run -p mncs-cli -- validate examples/account-transfer.mncs.json @@ -66,14 +67,39 @@ The following example intentionally performs a network effect without declaring cargo run -p mncs-cli -- validate examples/invalid-undeclared-effect.mncs.json ``` +## Explore the source syntax laboratory + +The current hypothesis uses three related representations: + +```text +Zig-influenced human source + ↕ deterministic semantic round trip +compact canonical semantic form + ↓ +high-level MNCS IR and verified SSA +``` + +Recursive tooling also exchanges semantic patches that target stable graph identities rather than unrestricted source-text replacement. + +Run the account-transfer tournament: + +```bash +cargo run -p mncs-cli -- syntax-tournament \ + examples/syntax/account-transfer.tournament.json +``` + +The tournament compares three human-source candidates and one canonical machine form against the same 23 declared semantic claims. It reports deterministic lexical units and non-whitespace characters per claim. These are tokenizer-neutral comparison metrics, not exact token counts for a particular model. + +See [Source Syntax Laboratory](docs/source-syntax-lab.md), [Source Representations](spec/source-representations.md), and [RFC 0005](rfcs/0005-source-representations-and-semantic-density.md). + ## Intended compilation model The current direction is: ```text -source syntax (undecided) - ↓ -MNCS semantic graph +human source syntax (experimental candidates) + ↕ +canonical semantic graph/form ↓ high-level MNCS IR ↓ @@ -115,7 +141,7 @@ A generator must not silently modify the trusted baseline or certify its own rep - **MNCS** defines the broader standard, contracts, complexity concepts, and verification philosophy. - **MNCDS** explores deterministic and structural representation where applicable. -- **MNCS Language** investigates how those relationships can be expressed directly in a general-purpose language, including the semantic structures needed for recursive introspection and repair. +- **MNCS Language** investigates how those relationships can be expressed directly in a general-purpose language, including semantic structures for recursive introspection and repair. - **MNCS Forge** can analyze, verify, localize failures, test candidate transformations, and produce evidence for MNCS-language components and conventional code. - **RAVEL** can coordinate recursive, distributed, multi-agent, and multi-verifier refinement across machines and trust boundaries. @@ -123,7 +149,7 @@ MNCS must remain applicable to existing languages even if this project never bec ## Design principles -1. **Semantics before syntax.** The project will not optimize punctuation before establishing what must be represented. +1. **Semantics before syntax.** Surface choices must preserve the semantic model rather than define it accidentally. 2. **Explicit authority.** Ambient filesystem, network, process, clock, randomness, and credential access should not be assumed. 3. **Closed effects.** Undeclared effects should be rejected or isolated at a visible trust boundary. 4. **Named assumptions.** Verification results must state the assumptions on which they depend. @@ -133,15 +159,17 @@ MNCS must remain applicable to existing languages even if this project never bec 8. **Incremental verification.** A change should invalidate the smallest defensible evidence subgraph. 9. **Human inspectability.** Machine-native structure must remain understandable without an LLM. 10. **Backend conservatism.** Optimization promises should be generated from established facts. -11. **Recursive refinement is bounded and reviewable.** Diagnostics and repair proposals may feed later cycles, but promotion requires explicit policy, protected-property checks, and sufficient independent evidence. +11. **Recursive refinement is bounded and reviewable.** Promotion requires explicit policy, protected-property checks, and sufficient independent evidence. +12. **Semantic density beats character density.** Representation efficiency is measured against complete, equivalent claims rather than raw brevity. +13. **Role-specific representations are allowed.** Human source, canonical agent form, semantic patches, and verified IR need not use the same notation. ## Roadmap -The immediate target is **Milestone 0.1 — Executable Semantic Model**. See [ROADMAP.md](ROADMAP.md) for acceptance criteria and later phases. +The immediate target is **Milestone 0.1 — Executable Semantic Model**, with the source syntax laboratory operating as a cross-cutting research track. See [ROADMAP.md](ROADMAP.md). ## Contributing -The project is early enough that a precise counterexample is often more valuable than a large implementation. Read [CONTRIBUTING.md](CONTRIBUTING.md), then use an RFC for changes that alter the semantic model. +The project is early enough that a precise counterexample is often more valuable than a large implementation. Read [CONTRIBUTING.md](CONTRIBUTING.md), then use an RFC for changes that alter the semantic model or source representation requirements. ## License From bbec8e9556648081785947225e14024a79d6247a Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:44:20 -0800 Subject: [PATCH 20/26] Add semantic density track to roadmap --- ROADMAP.md | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 93ec7b7..887bc61 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,21 @@ # Roadmap -This roadmap deliberately separates semantic research from surface-language design while treating recursive introspection and refinement as a cross-cutting requirement. +This roadmap separates semantic research from final surface-language selection while treating recursive introspection, representation efficiency, and refinement as cross-cutting requirements. + +## Active cross-cutting track — source representations + +The project now maintains an experimental syntax laboratory before committing to a grammar. + +Current work: + +- compare Zig-influenced, fully structured, and minimal human-source candidates; +- maintain a distinct compact canonical semantic form for agents and tooling; +- represent recursive changes as semantic patches rather than unrestricted text replacement; +- declare equivalent semantic claims before comparing candidate density; +- collect deterministic tokenizer-neutral metrics in CI; +- extend later studies with multiple model tokenizers, parser behavior, repair success, human comprehension, and verifier cost. + +A final grammar must not be selected from character count alone. ## 0.1 — Executable semantic model @@ -15,7 +30,7 @@ Acceptance criteria: - emit deterministic, machine-readable diagnostics; - include accepted and intentionally rejected examples; - document trust boundaries, recursive-refinement requirements, and non-goals; -- run formatting, linting, tests, and example validation in CI. +- run formatting, linting, tests, example validation, and syntax measurements in CI. ## 0.2 — Semantic graph, identity, and recursive artifacts @@ -25,7 +40,8 @@ Acceptance criteria: - distinguish source identity, semantic identity, implementation identity, candidate identity, and evidence identity; - produce a first evidence-manifest schema; - define schemas for diagnostic obligations, causal slices, repair proposals, refinement budgets, semantic deltas, evidence deltas, and promotion decisions; -- ensure observation and mutation require distinct capabilities. +- ensure observation and mutation require distinct capabilities; +- version the canonical semantic representation independently from human syntax. ## 0.3 — High-level MNCS IR @@ -35,7 +51,8 @@ Acceptance criteria: - define deterministic lowering from the semantic graph; - preserve source-to-semantic traceability; - preserve enough structure to identify bounded repair regions and protected properties; -- represent candidate transformations without modifying the trusted baseline. +- represent candidate transformations without modifying the trusted baseline; +- demonstrate lossless projection from human source to canonical semantic form for the supported subset. ## 0.4 — Verified SSA and micro-debugging @@ -63,12 +80,15 @@ Acceptance criteria: ## 0.6 — Surface-language and self-description experiments -- develop at least two competing syntax proposals; -- test human readability, agent repairability, canonical formatting, and parser stability; +- expand the syntax tournament to a representative corpus; +- implement parsers and canonical formatters for at least two competing source candidates; +- measure human readability, agent generation, localized repair, model-token counts, parser recovery, canonical formatting, graph round trips, omission rates, and verifier workload; +- ensure every compared candidate represents the same declared semantic claims; - avoid syntax that cannot round-trip to the semantic graph without hidden meaning; +- select or reject the Zig-influenced direction using collected evidence; - expose compiler and verifier contracts through the same introspection model used for ordinary programs; - begin a limited self-hosting experiment without obscuring bootstrap trust; -- select a grammar only after semantic coverage is demonstrated. +- select a grammar only after semantic coverage and repairability are demonstrated. ## 1.0 research threshold @@ -77,11 +97,12 @@ A 1.0 designation would indicate a coherent research language and toolchain, not - a versioned specification; - a stable semantic core; - deterministic parsing and canonical formatting; +- a versioned canonical semantic representation; - at least one executable backend; - an evidence manifest with verifiable artifacts; - bounded unsafe and foreign-function interfaces; - a versioned recursive diagnostic and refinement protocol; - isolated candidate transformations and explicit promotion policy; -- documented recursion, authority, and resource limits; +- documented recursion, authority, resource, and representation limits; - documented soundness and bootstrap limits; - conformance tests and independent implementation guidance. From 8b0c9409a9d9e33add70060123a18cf710534e84 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:45:16 -0800 Subject: [PATCH 21/26] Harden syntax CLI for strict linting --- crates/mncs-cli/src/main.rs | 43 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/crates/mncs-cli/src/main.rs b/crates/mncs-cli/src/main.rs index f694d89..c6ed255 100644 --- a/crates/mncs-cli/src/main.rs +++ b/crates/mncs-cli/src/main.rs @@ -1,8 +1,4 @@ -use std::{ - env, fs, - path::Path, - process::ExitCode, -}; +use std::{env, fs, path::Path, process::ExitCode}; use mncs_model::Program; use mncs_syntax::{analyze, SourceMetrics}; @@ -71,7 +67,7 @@ fn validate(path: &str) -> ExitCode { }; let report = program.validate(); - if print_json(&report).is_err() { + if !print_json(&report) { return ExitCode::from(2); } @@ -107,9 +103,10 @@ fn syntax_metrics(paths: Vec) -> ExitCode { }); } - match print_json(&reports) { - Ok(()) => ExitCode::SUCCESS, - Err(()) => ExitCode::from(2), + if print_json(&reports) { + ExitCode::SUCCESS + } else { + ExitCode::from(2) } } @@ -184,12 +181,11 @@ fn syntax_tournament(path: &str) -> ExitCode { name: candidate.name, role: candidate.role, path: candidate.path, - lexical_units_per_claim_milli: metrics.lexical_units.saturating_mul(1000) - / claim_count, - non_whitespace_characters_per_claim_milli: metrics - .non_whitespace_characters - .saturating_mul(1000) - / claim_count, + lexical_units_per_claim_milli: per_claim_milli(metrics.lexical_units, claim_count), + non_whitespace_characters_per_claim_milli: per_claim_milli( + metrics.non_whitespace_characters, + claim_count, + ), metrics, }); } @@ -200,12 +196,17 @@ fn syntax_tournament(path: &str) -> ExitCode { candidates, }; - match print_json(&report) { - Ok(()) => ExitCode::SUCCESS, - Err(()) => ExitCode::from(2), + if print_json(&report) { + ExitCode::SUCCESS + } else { + ExitCode::from(2) } } +fn per_claim_milli(value: usize, claim_count: usize) -> usize { + value.saturating_mul(1000) / claim_count +} + fn read_source(path: &str) -> Result { fs::read_to_string(path).map_err(|error| { eprintln!("error: unable to read {path:?}: {error}"); @@ -213,15 +214,15 @@ fn read_source(path: &str) -> Result { }) } -fn print_json(value: &T) -> Result<(), ()> { +fn print_json(value: &T) -> bool { match serde_json::to_string_pretty(value) { Ok(json) => { println!("{json}"); - Ok(()) + true } Err(error) => { eprintln!("error: unable to serialize report: {error}"); - Err(()) + false } } } From 8fefb74e0d54e87026f15bdd9521a30d864a4751 Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:46:03 -0800 Subject: [PATCH 22/26] Avoid allocation in operator matching --- crates/mncs-syntax/src/lib.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/mncs-syntax/src/lib.rs b/crates/mncs-syntax/src/lib.rs index 78f9985..614af8c 100644 --- a/crates/mncs-syntax/src/lib.rs +++ b/crates/mncs-syntax/src/lib.rs @@ -180,8 +180,17 @@ fn operator_width(remaining: &[char]) -> usize { } fn starts_with(remaining: &[char], expected: &str) -> bool { - let expected: Vec = expected.chars().collect(); - remaining.len() >= expected.len() && remaining[..expected.len()] == expected + let mut expected = expected.chars(); + + for actual in remaining { + match expected.next() { + Some(value) if *actual == value => {} + Some(_) => return false, + None => return true, + } + } + + expected.next().is_none() } #[cfg(test)] From 966435f7127eb74b598e7654f805ce81bbe5957d Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:48:15 -0800 Subject: [PATCH 23/26] Pin CI to workspace Rust version --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 827052f..e79b0fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: + toolchain: 1.79.0 components: rustfmt, clippy - name: Format run: cargo fmt --all -- --check From 5237ee6552e58c9d67544560f961699fd10602ba Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:51:00 -0800 Subject: [PATCH 24/26] Apply workspace rustfmt correction --- crates/mncs-model/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/mncs-model/src/lib.rs b/crates/mncs-model/src/lib.rs index 5e0330e..4bcf585 100644 --- a/crates/mncs-model/src/lib.rs +++ b/crates/mncs-model/src/lib.rs @@ -174,7 +174,11 @@ impl Program { } if self.module.trim().is_empty() { - errors.push(diagnostic("MNCS002", "module", "module name must not be empty")); + errors.push(diagnostic( + "MNCS002", + "module", + "module name must not be empty", + )); } let assumption_ids = collect_unique_ids( From df2de22c36bc8f866a876645abf3fe5141f3ccea Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:51:34 -0800 Subject: [PATCH 25/26] Apply rustfmt operator layout --- crates/mncs-syntax/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/mncs-syntax/src/lib.rs b/crates/mncs-syntax/src/lib.rs index 614af8c..5219680 100644 --- a/crates/mncs-syntax/src/lib.rs +++ b/crates/mncs-syntax/src/lib.rs @@ -160,8 +160,8 @@ fn is_identifier_continue(value: char) -> bool { fn operator_width(remaining: &[char]) -> usize { const THREE_CHARACTER_OPERATORS: [&str; 3] = ["...", "<<=", ">>="]; const TWO_CHARACTER_OPERATORS: [&str; 21] = [ - "->", "=>", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&&", "||", - "::", "..", "<<", ">>", "&=", "|=", "^=", "??", + "->", "=>", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&&", "||", "::", "..", + "<<", ">>", "&=", "|=", "^=", "??", ]; for operator in THREE_CHARACTER_OPERATORS { From 90b78a26806f755d654ff3c4023a30722f6464dd Mon Sep 17 00:00:00 2001 From: epi13 Date: Sun, 2 Aug 2026 23:53:12 -0800 Subject: [PATCH 26/26] Resolve strict Clippy baseline lint --- crates/mncs-model/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/mncs-model/src/lib.rs b/crates/mncs-model/src/lib.rs index 4bcf585..826f791 100644 --- a/crates/mncs-model/src/lib.rs +++ b/crates/mncs-model/src/lib.rs @@ -458,7 +458,7 @@ mod tests { #[test] fn rejects_evidence_for_unknown_property() { let mut program = valid_program(); - program.functions[0].evidence[0].property = "missing".to_owned(); + "missing".clone_into(&mut program.functions[0].evidence[0].property); let report = program.validate(); assert!(!report.valid); assert!(report.errors.iter().any(|error| error.code == "MNCS012"));