Skip to content

Commit 0a45a92

Browse files
hyperpolymathclaude
andcommitted
feat: close all neurosymbolic feedback loops — PanLL is now a complete eNSAID
Add GovernanceEngine orchestrator (M1), OrbitalSync consumer (M2), Jaccard divergence (M3/S3), Anti-Crash→Vexometer feedback (M4), Panel Bus dispatch (M5), Tentacles OODA progression (S1), 7 Tauri event subscriptions (S2), ECHIDNA→OODA feedback (S4), Hypatia confidence propagation (S5). Also adds MyLang, TypeLL, and ProtocolSquisher panels with engines, models, and commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ef4d65e commit 0a45a92

30 files changed

Lines changed: 4111 additions & 63 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ npm-debug.log*
5151
runtime/.env
5252
runtime/.env.*
5353

54+
# Hypatia scanning artifacts
55+
.hypatia/
56+
5457
# IDE and OS files
5558
.idea/
5659
.vscode/

src-tauri/src/main.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,6 +1706,157 @@ mod echidna_tests {
17061706
}
17071707
}
17081708

1709+
// ===========================================================================
1710+
// Protocol-Squisher CLI Bridge
1711+
// ===========================================================================
1712+
1713+
const DEFAULT_PROTOCOL_SQUISHER_BIN: &str = "protocol-squisher";
1714+
1715+
/// Resolve the protocol-squisher binary path from environment or default.
1716+
fn protocol_squisher_bin() -> String {
1717+
std::env::var("PROTOCOL_SQUISHER_BIN")
1718+
.unwrap_or_else(|_| DEFAULT_PROTOCOL_SQUISHER_BIN.to_string())
1719+
}
1720+
1721+
/// Check whether the protocol-squisher CLI binary is available.
1722+
#[tauri::command]
1723+
fn protocol_squisher_check() -> Result<String, String> {
1724+
let output = std::process::Command::new(protocol_squisher_bin())
1725+
.arg("--version")
1726+
.output()
1727+
.map_err(|e| format!("CLI not found: {}", e))?;
1728+
1729+
if output.status.success() {
1730+
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
1731+
Ok(format!("{{\"available\":true,\"version\":\"{}\"}}", version))
1732+
} else {
1733+
Err("protocol-squisher CLI not available".to_string())
1734+
}
1735+
}
1736+
1737+
/// Analyse a schema file using `protocol-squisher analyze`.
1738+
/// Returns JSON analysis result.
1739+
#[tauri::command]
1740+
fn protocol_squisher_analyze(file_path: String) -> Result<String, String> {
1741+
let output = std::process::Command::new(protocol_squisher_bin())
1742+
.args(["analyze", &file_path, "--format", "json"])
1743+
.output()
1744+
.map_err(|e| format!("Analysis failed: {}", e))?;
1745+
1746+
if output.status.success() {
1747+
Ok(String::from_utf8_lossy(&output.stdout).to_string())
1748+
} else {
1749+
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
1750+
Err(format!("Analysis error: {}", stderr))
1751+
}
1752+
}
1753+
1754+
/// Compare two schema files using `protocol-squisher compare`.
1755+
/// Returns JSON compatibility result.
1756+
#[tauri::command]
1757+
fn protocol_squisher_compare(left_path: String, right_path: String) -> Result<String, String> {
1758+
let output = std::process::Command::new(protocol_squisher_bin())
1759+
.args(["compare", &left_path, &right_path, "--format", "json"])
1760+
.output()
1761+
.map_err(|e| format!("Comparison failed: {}", e))?;
1762+
1763+
if output.status.success() {
1764+
Ok(String::from_utf8_lossy(&output.stdout).to_string())
1765+
} else {
1766+
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
1767+
Err(format!("Comparison error: {}", stderr))
1768+
}
1769+
}
1770+
1771+
// ===========================================================================
1772+
// My-Lang CLI Bridge
1773+
// ===========================================================================
1774+
1775+
const DEFAULT_MYLANG_BIN: &str = "my";
1776+
1777+
/// Resolve the my-lang binary path from environment or default.
1778+
fn mylang_bin() -> String {
1779+
std::env::var("MYLANG_BIN").unwrap_or_else(|_| DEFAULT_MYLANG_BIN.to_string())
1780+
}
1781+
1782+
/// Check whether the my-lang CLI binary is available.
1783+
#[tauri::command]
1784+
fn mylang_check() -> Result<String, String> {
1785+
let output = std::process::Command::new(mylang_bin())
1786+
.arg("--version")
1787+
.output()
1788+
.map_err(|e| format!("CLI not found: {}", e))?;
1789+
1790+
if output.status.success() {
1791+
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
1792+
Ok(format!("{{\"available\":true,\"version\":\"{}\"}}", version))
1793+
} else {
1794+
Err("my-lang CLI not available".to_string())
1795+
}
1796+
}
1797+
1798+
/// Compile source code in a given dialect.
1799+
/// Writes source to a temp file, runs `my compile`, returns JSON result.
1800+
#[tauri::command]
1801+
fn mylang_compile(source: String, dialect: String) -> Result<String, String> {
1802+
use std::io::Write;
1803+
1804+
let ext = match dialect.to_lowercase().as_str() {
1805+
"solo" => "solo",
1806+
"duet" => "duet",
1807+
"ensemble" => "ens",
1808+
"me" => "me",
1809+
_ => "solo",
1810+
};
1811+
1812+
let tmp_dir = std::env::temp_dir().join("panll-mylang");
1813+
std::fs::create_dir_all(&tmp_dir)
1814+
.map_err(|e| format!("Failed to create temp dir: {}", e))?;
1815+
1816+
let tmp_file = tmp_dir.join(format!("input.{}", ext));
1817+
let mut f = std::fs::File::create(&tmp_file)
1818+
.map_err(|e| format!("Failed to create temp file: {}", e))?;
1819+
f.write_all(source.as_bytes())
1820+
.map_err(|e| format!("Failed to write source: {}", e))?;
1821+
1822+
let start = std::time::Instant::now();
1823+
let output = std::process::Command::new(mylang_bin())
1824+
.args(["compile", tmp_file.to_str().unwrap_or("input"), "--format", "json"])
1825+
.output()
1826+
.map_err(|e| format!("Compilation failed: {}", e))?;
1827+
let elapsed_ms = start.elapsed().as_millis();
1828+
1829+
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
1830+
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
1831+
1832+
// Construct a JSON result
1833+
let success = output.status.success();
1834+
Ok(format!(
1835+
"{{\"success\":{},\"output\":{},\"diagnostics\":{},\"error_count\":0,\"warning_count\":0,\"compile_time_ms\":{}}}",
1836+
success,
1837+
serde_json::to_string(&stdout).unwrap_or_else(|_| "\"\"".to_string()),
1838+
serde_json::to_string(&stderr).unwrap_or_else(|_| "\"\"".to_string()),
1839+
elapsed_ms
1840+
))
1841+
}
1842+
1843+
/// Evaluate a REPL input line.
1844+
/// Runs `my repl --eval` with the given input and dialect.
1845+
#[tauri::command]
1846+
fn mylang_repl(input: String, dialect: String) -> Result<String, String> {
1847+
let output = std::process::Command::new(mylang_bin())
1848+
.args(["repl", "--eval", &input, "--dialect", &dialect.to_lowercase()])
1849+
.output()
1850+
.map_err(|e| format!("REPL eval failed: {}", e))?;
1851+
1852+
if output.status.success() {
1853+
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
1854+
} else {
1855+
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
1856+
Err(if stderr.is_empty() { "Evaluation error".to_string() } else { stderr })
1857+
}
1858+
}
1859+
17091860
fn main() {
17101861
tauri::Builder::default()
17111862
.plugin(tauri_plugin_shell::init())
@@ -1851,6 +2002,14 @@ fn main() {
18512002
typell::commands::typell_compute,
18522003
typell::commands::typell_list_signatures,
18532004
typell::commands::typell_universes,
2005+
// Protocol-Squisher — 13-format schema analysis CLI bridge
2006+
protocol_squisher_check,
2007+
protocol_squisher_analyze,
2008+
protocol_squisher_compare,
2009+
// My-Lang — AI-native language CLI bridge
2010+
mylang_check,
2011+
mylang_compile,
2012+
mylang_repl,
18542013
])
18552014
.setup(|_app| {
18562015
Ok(())

src/Model.res

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ include CladeBrowserModel
248248
/// tentaclesState) for the 7-Tentacles compiler agent panel — seven colour-coded
249249
/// agents representing compiler subsystems with progressive cephalopod staging.
250250
include TentaclesModel
251+
include ProtocolSquisherModel
252+
include MyLangModel
253+
include TypeLLModel
251254

252255
/// The complete Model — composes all domain slices into a single record.
253256
/// This is the "Gravitational Centre" of the Binary Star system.
@@ -404,6 +407,15 @@ type model = {
404407
// Tentacles — 7-Tentacles compiler agent panel (within/without ECHIDNA)
405408
tentacles: tentaclesState,
406409

410+
// Protocol-Squisher — 13-format schema analysis and compatibility
411+
protocolSquisher: protocolSquisherState,
412+
413+
// My-Lang — AI-native language workbench (Solo/Duet/Ensemble/Me dialects)
414+
myLang: myLangState,
415+
416+
// TypeLL — Verification kernel (cross-panel type intelligence)
417+
typell: typellState,
418+
407419
// ENSAID_CONFIG — cross-panel config generation state
408420
ensaidConfigPreview: option<string>,
409421
ensaidConfigError: option<string>,
@@ -670,6 +682,9 @@ let init = (): model => {
670682
clades: CladeBrowserEngine.builtinClades,
671683
},
672684
tentacles: TentaclesEngine.init(),
685+
protocolSquisher: ProtocolSquisherEngine.defaultState,
686+
myLang: MyLangEngine.defaultState,
687+
typell: TypeLLEngine.defaultState,
673688
ensaidConfigPreview: None,
674689
ensaidConfigError: None,
675690
undoStack: [],

src/Msg.res

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,93 @@ type keybindingsMsg =
15621562
/// Reset all bindings to defaults.
15631563
| ResetAllBindings
15641564

1565+
/// Protocol-Squisher format analysis messages.
1566+
type protocolSquisherMsg =
1567+
/// Set the active category tab.
1568+
| SetPsCategory(protocolSquisherCategory)
1569+
/// Check whether CLI binary is available.
1570+
| CheckPsCli
1571+
/// CLI check result.
1572+
| PsCliResult(result<string, string>)
1573+
/// Update the analyse file path input.
1574+
| SetAnalyseInput(string)
1575+
/// Run analysis on the current input path.
1576+
| RunAnalysis
1577+
/// Analysis result from Tauri backend.
1578+
| AnalysisResult(result<string, string>)
1579+
/// Update the left comparison input.
1580+
| SetCompareLeft(string)
1581+
/// Update the right comparison input.
1582+
| SetCompareRight(string)
1583+
/// Run comparison between left and right schemas.
1584+
| RunComparison
1585+
/// Comparison result from Tauri backend.
1586+
| ComparisonResult(result<string, string>)
1587+
1588+
/// My-Lang AI-native language messages.
1589+
type myLangMsg =
1590+
/// Set the active category tab.
1591+
| SetMlCategory(myLangCategory)
1592+
/// Switch the active dialect.
1593+
| SetDialect(myLangDialect)
1594+
/// Check whether CLI binary is available.
1595+
| CheckMlCli
1596+
/// CLI check result.
1597+
| MlCliResult(result<string, string>)
1598+
/// Update editor content.
1599+
| UpdateEditor(string)
1600+
/// Compile the current editor content.
1601+
| Compile
1602+
/// Compilation result from Tauri backend.
1603+
| CompileResult(result<string, string>)
1604+
/// Update REPL input.
1605+
| UpdateReplInput(string)
1606+
/// Evaluate the current REPL input.
1607+
| EvalRepl
1608+
/// REPL evaluation result from Tauri backend.
1609+
| ReplResult(result<string, string>)
1610+
1611+
/// TypeLL verification kernel messages.
1612+
type typellMsg =
1613+
/// Set the active category tab.
1614+
| SetTlCategory(typellCategory)
1615+
/// Set the view layer (progressive disclosure level).
1616+
| SetViewLayer(viewLayer)
1617+
/// Check TypeLL server health.
1618+
| CheckTlHealth
1619+
/// Health check result.
1620+
| TlHealthResult(result<string, string>)
1621+
/// Update checker input.
1622+
| UpdateCheckerInput(string)
1623+
/// Run type check on current input.
1624+
| RunCheck
1625+
/// Type check result.
1626+
| CheckResult(result<string, string>)
1627+
/// Run type inference on current input.
1628+
| RunInfer
1629+
/// Type inference result.
1630+
| InferResult(result<string, string>)
1631+
/// Load signatures from server.
1632+
| LoadSignatures
1633+
/// Signatures loaded.
1634+
| SignaturesLoaded(result<string, string>)
1635+
/// Load universe hierarchy.
1636+
| LoadUniverses
1637+
/// Universes loaded.
1638+
| UniversesLoaded(result<string, string>)
1639+
/// Set signature search filter.
1640+
| SetSignatureFilter(string)
1641+
/// Set tier filter.
1642+
| SetTierFilter(option<typeTier>)
1643+
/// Update refinement spec.
1644+
| UpdateRefinementSpec(string)
1645+
/// Update refinement constraints.
1646+
| UpdateRefinementConstraints(string)
1647+
/// Run refinement.
1648+
| RunRefine
1649+
/// Refinement result.
1650+
| RefineResult(result<string, string>)
1651+
15651652
/// The unified message type
15661653
type msg =
15671654
| PaneL(paneLMsg)
@@ -1615,6 +1702,9 @@ type msg =
16151702
| Boj(bojMsg) // Bundle of Joy cartridge server
16161703
| CladeBrowser(cladeBrowserMsg) // Clade taxonomy browser
16171704
| Tentacles(tentaclesMsg) // 7-Tentacles compiler agent orchestra
1705+
| ProtocolSquisher(protocolSquisherMsg) // Format analysis and compatibility
1706+
| MyLang(myLangMsg) // AI-native language workbench
1707+
| TypeLL(typellMsg) // Verification kernel (cross-panel type intelligence)
16181708
| EnsaidConfig(ensaidConfigMsg) // Cross-panel ENSAID_CONFIG generation and I/O
16191709
| Undo // Undo last significant action
16201710
| Redo // Redo last undone action

src/SubscriptionsFixed.res

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,73 @@ let inferenceSubscriptions = (model: model): Tea_Sub.t<msg> => {
9595
}
9696
}
9797

98+
/// S2: Tauri backend event subscriptions — real-time neurosymbolic streaming.
99+
/// These fire when the Rust backend receives events from ECHIDNA, Tentacles,
100+
/// VeriSimDB, or Hypatia. Only active when the relevant panel is connected.
101+
let neurosymbolicSubscriptions = (_model: model): Tea_Sub.t<msg> => {
102+
Tea_Sub.batch(list{
103+
// ECHIDNA proof progress → feed into proof session state.
104+
TauriEvents.onEchidnaProgress(payload =>
105+
Echidna(ProofResult(Ok(payload)))
106+
),
107+
// ECHIDNA tactic suggestions → populate suggestion ribbon.
108+
TauriEvents.onEchidnaTactics(payload =>
109+
Echidna(TacticSuggestionsLoaded(Ok(payload)))
110+
),
111+
// Tentacles agent phase changes → advance OODA indicators.
112+
// Payload expected as "agentId:phaseId" string from FFI.
113+
TauriEvents.onTentaclesPhaseChange(payload => {
114+
// Parse "0:2" as agent Red, phase Decide — graceful fallback.
115+
let parts = String.split(payload, ":")
116+
let agentIdx = parts[0]->Option.getOr("0")->Int.fromString->Option.getOr(0)
117+
let agentId = switch agentIdx {
118+
| 0 => TentaclesModel.Red
119+
| 1 => TentaclesModel.Orange
120+
| 2 => TentaclesModel.Yellow
121+
| 3 => TentaclesModel.Green
122+
| 4 => TentaclesModel.Blue
123+
| 5 => TentaclesModel.Indigo
124+
| _ => TentaclesModel.Violet
125+
}
126+
let phaseIdx = parts[1]->Option.getOr("0")->Int.fromString->Option.getOr(0)
127+
let phase = switch phaseIdx {
128+
| 0 => PaneModel.Observe
129+
| 1 => PaneModel.Orient
130+
| 2 => PaneModel.Decide
131+
| _ => PaneModel.Act
132+
}
133+
Tentacles(AgentPhaseAdvanced(agentId, phase))
134+
}),
135+
// Tentacles agent broadcasts → deliver as reasoning share.
136+
TauriEvents.onTentaclesBroadcast(payload =>
137+
Tentacles(BroadcastFromAgent(Red, ReasoningShare({
138+
agent: Red,
139+
phase: Observe,
140+
summary: payload,
141+
detail: None,
142+
timestamp: 0.0,
143+
})))
144+
),
145+
// VeriSimDB drift alerts → refresh drift display.
146+
TauriEvents.onVeriSimDBDrift(payload =>
147+
VeriSimDB(DriftLoaded(Ok(payload)))
148+
),
149+
// Hypatia neural network status → refresh network grid.
150+
TauriEvents.onHypatiaStatus(payload =>
151+
Hypatia(ScansLoaded(Ok(payload)))
152+
),
153+
// Governance signals → Anti-Crash intervention request.
154+
TauriEvents.onGovernanceSignal(payload =>
155+
AntiCrash(RequestOperatorIntervention(payload))
156+
),
157+
})
158+
}
159+
98160
/// Combined subscriptions.
99161
let all = (model: model): Tea_Sub.t<msg> => {
100-
Tea_Sub.batch(list{subscriptions(model), inferenceSubscriptions(model)})
162+
Tea_Sub.batch(list{
163+
subscriptions(model),
164+
inferenceSubscriptions(model),
165+
neurosymbolicSubscriptions(model),
166+
})
101167
}

0 commit comments

Comments
 (0)