Add polyglot orchestrator feature requests, sprint plan, and test projects

Feature requests I-N cover: LanguageFitnessScorer, PolyglotFFIGlueGenerator,
CrossLanguageSymbolIndex, LSP Orchestrator, DAP Orchestrator, Polyglot Test Harness.
Sprint plan maps 75 steps across sprints 271-285 in 5 phases.
Test projects: poly-sort (Rust+Python), poly-api (Go+TS), poly-parse (C++/Haskell),
poly-pipeline (5 lang), poly-compiler (5 lang), poly-everything (all languages).
Theoretical goal: lossless polyglot transpiling proven as a construction.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-28 23:01:40 -07:00
parent de5bdd358f
commit d1e883dd38
3 changed files with 922 additions and 0 deletions

View File

@@ -2,6 +2,22 @@
> Backlog of feature ideas to triage into future sprints (e.g., Sprint 6/7). > Backlog of feature ideas to triage into future sprints (e.g., Sprint 6/7).
## Title Convention (Semantic Logging)
Feature request titles must include derivation source so provenance is explicit.
Required title prefix format:
- `[Derived:<source>] <feature title>`
Examples:
- `[Derived:DataPipeline-LoRA] Semantic Validation Gate APIs for Taskitem Promotion`
- `[Derived:UserFeedback-HiveMind] Resource Lock Constraints on TaskItems`
- `[Derived:RunLogs-NativeTools] MCP Tool-Call Completion Diagnostics`
Source tags should map to where the signal came from (run logs, user request, external project, postmortem, etc.), not just the proposed implementation area.
## Security Vulnerability Awareness (Dependencies) — IMPLEMENTED (Sprint 6, Steps 190195) ## Security Vulnerability Awareness (Dependencies) — IMPLEMENTED (Sprint 6, Steps 190195)
**Goal:** Warn when a dependency has known vulnerabilities and surface safer alternatives. **Goal:** Warn when a dependency has known vulnerabilities and surface safer alternatives.
@@ -141,6 +157,127 @@
- Provide recommended defaults for CLI tools vs GUI apps - Provide recommended defaults for CLI tools vs GUI apps
- Include guidance for minimizing startup latency and bundle size - Include guidance for minimizing startup latency and bundle size
## [Derived:PersonalVaultTool-MultiPlatform] Platform-Agnostic Projection via SemAnno Adapter Boundaries — PROPOSED
**Filed:** 2026-02-27
**Filed by:** personal_vault_tool session (2026-02-27)
**Priority:** High — required for any real-world cross-platform projection (Python → Android/Kotlin, Python → Swift/iOS, etc.)
**Source context:** `personal_vault_tool/vault_core.py` — clean business logic and platform I/O are entangled in the same class with no annotation boundary.
### Problem
Whetstone's projector today treats a source file as a unit. When projecting `VaultStore`
to Kotlin, it faithfully projects `sqlite3.connect()` — which doesn't exist on Android.
The projector has no way to distinguish:
- **Pure logic nodes** — `share_evaluate()` selector scoring, audit hash chain computation,
grant TTL enforcement — zero platform dependency, projectable to any target.
- **Platform adapter nodes** — `sqlite3.connect()`, `Fernet.encrypt()`, `socket.bind()`
completely platform-specific, must be substituted per-target, not projected literally.
This is not a generator quality issue (GR-022/023/024). It is an architectural gap:
the AST has no annotation that marks where the platform boundary is.
### The Correct Architecture (already implied by SemAnno's design goals)
```
Source file with SemAnno annotations
├── @pure.logic nodes → project as-is to any language
│ share_evaluate()
│ audit_hash_chain()
│ grant_scope_check()
└── @platform.storage → generate abstract interface + per-target impl
│ _db() / read_records() / write_record() → Python: sqlite3
│ → Android: Room DAO
│ → iOS: CoreData
├── @platform.crypto → generate abstract interface + per-target impl
│ FernetEncryptor → Python: cryptography.Fernet
│ → Android: Android Keystore AES
└── @platform.network → omit on mobile (caller drives transport)
ThreadingHTTPServer
```
The platform adapters become **generated abstract interfaces** with per-target
implementations, not projected concrete calls.
### Feature Request A: SemAnno Platform Boundary Annotations
**New annotation tags:**
- `@pure.logic` — no I/O, no platform imports; freely projectable
- `@platform.storage` — interacts with a persistence layer; requires adapter
- `@platform.crypto` — interacts with a key/encryption service; requires adapter
- `@platform.network` — interacts with sockets/HTTP; usually omitted on mobile
- `@platform.os` — interacts with filesystem, env vars, signals
**Generator behavior:** annotated nodes are flagged before projection; the projector
emits an `AdapterInterface` node instead of projecting the implementation.
**Validation gate:** `whetstone_validate_taskitem` or a new `whetstone_check_platform_purity`
tool should verify that `@pure.logic` nodes have zero `@platform.*` imports in their
transitive dependency graph.
### Feature Request B: Platform Profile System
**New concept:** a named platform profile describes what substitutions exist for each
`@platform.*` category.
```json
{
"profile": "android-kotlin",
"substitutions": {
"platform.storage": "androidx.room.RoomDatabase",
"platform.crypto": "android.security.keystore.KeyGenParameterSpec",
"platform.network": null
}
}
```
Built-in profiles to start:
- `python-stdlib` (current, implicit)
- `android-kotlin` (Room + Android Keystore)
- `swift-ios` (CoreData + CryptoKit)
- `node-js` (better-sqlite3 + node:crypto)
**Generator behavior:** when projecting with a profile active, `@platform.*` nodes
are replaced by the profile's adapter interface stub rather than the source
implementation. The developer fills the stub; the logic layer is complete.
### Feature Request C: Multi-Target Projection Command
**Tool:** extend `whetstone_run_pipeline` or add `whetstone_project_multiplatform`
**Input:** annotated source file + list of target profiles
**Output:** one generated artifact per target, plus a shared pure-logic module
that all targets import unchanged.
**Acceptance criteria:**
- `personal_vault_tool/vault_core.py` (fully annotated) projects to:
- `out/python/vault_logic.py` + `out/python/adapters/sqlite_adapter.py`
- `out/kotlin/VaultLogic.kt` + `out/kotlin/adapters/RoomAdapter.kt` (stub)
- All `@pure.logic` methods are byte-identical in content between targets (modulo syntax).
- `@platform.*` methods emit only the interface signature + a `TODO` body in each target.
### Relationship to existing gaps
| Gap | Relationship |
|-----|-------------|
| GR-006 | Complex class generation — same root; multi-method class projection needed for VaultStore |
| GR-007 | Cross-language class node emission — must be closed before this works |
| GR-022/023/024 | Python generator string/import/comment bugs — must fix before Python→Python round-trip is clean enough to annotate |
### Suggested sprint scope
- Sprint N: SemAnno tags `@pure.logic`, `@platform.storage`, `@platform.crypto` (schema + parser + editor UI)
- Sprint N+1: Platform profile schema + substitution registry (2 built-in profiles: python-stdlib, android-kotlin)
- Sprint N+2: Projection gate — `whetstone_check_platform_purity` tool
- Sprint N+3: Multi-target pipeline output with stub generation
---
## Python/C++/JS-TS Support Enhancements <20> PROPOSED ## Python/C++/JS-TS Support Enhancements <20> PROPOSED
**Goal:** Expand first-class support for Python, C++, and JS/TS beyond current parse/generate. **Goal:** Expand first-class support for Python, C++, and JS/TS beyond current parse/generate.
@@ -218,6 +355,23 @@ HiveMind's scheduler knows the dispatch target node and enforces accordingly.
## Deterministic MCP Debugging Workflow for SLM Agents — PROPOSED ## Deterministic MCP Debugging Workflow for SLM Agents — PROPOSED
## [Derived:DataPipeline-LoRA] Semantic + Recursive Taskitem Validation APIs — PROPOSED
**Goal:** Expose first-class MCP/editor APIs to score task completion beyond test-pass and feed recursive quality signals back into taskitem generation.
**Why derived:** Current dataset curation needs semantic validity checks and recursive re-validation loops to avoid local minima in training data.
**Scope:**
- Semantic completion validator API (invariant checks, intent/diff consistency, equivalence hooks).
- Recursive taskitem quality scorer (self-containment, dependency correctness, blocker detectability).
- Promotion-grade result packet (`execution_pass`, `semantic_pass`, `recursive_pass`, confidence).
- MCP endpoints for batch scoring and audit export.
**Data-pipeline impact:**
- Reduces script-only heuristics.
- Enables consistent promotion gates across projects.
- Improves good/bad labeling quality for LoRA datasets.
**Filed by:** Whetstone execution session (2026-02-21) **Filed by:** Whetstone execution session (2026-02-21)
**Priority:** Critical for self-improving low-context agents **Priority:** Critical for self-improving low-context agents
**Goal:** Make generation + debugging robust enough that small/local models can complete tasks without expert intuition. **Goal:** Make generation + debugging robust enough that small/local models can complete tasks without expert intuition.
@@ -389,3 +543,214 @@ A fix may pass one test but silently break prior working behavior.
- deterministic regression guard set, - deterministic regression guard set,
- MCP tool schema checks, - MCP tool schema checks,
- with full repro packet trace and no manual intervention. - with full repro packet trace and no manual intervention.
---
## Polyglot Orchestrator — PROPOSED
> Origin: design session 2026-02-28. Goal: true lossless polyglot code generation —
> every component of a project written in the language best suited to it, with
> type-safe boundaries, unified editing (LSP), and unified debugging (DAP),
> all driven from a single shared AST.
>
> This is a multi-phase capability that extends Whetstone from a single-target
> code generator into a polyglot orchestration platform. The theoretical proof
> is a project where every supported generation language participates, each
> responsible for the component it is most fit for, with no manual FFI code.
### Feature Request I: Language Fitness Scorer
**Tool name:** `whetstone_score_language_fitness`
**Derived:** `[Derived:DesignSession-Polyglot] Language Fitness Scorer`
**Problem:**
Language selection today is implicit — the caller picks a target language. There is no
mechanism to analyze an AST subtree and recommend which language best fits its
computational shape. This means the caller must already know the answer, which defeats
the purpose of language-agnostic AST representation.
**Requirements:**
- Extract structural features from an AST node or spec section:
- mutation ratio (writes/reads per node)
- recursion shape (tail-recursive, tree-recursive, flat loop)
- concurrency primitives present (channels, shared memory, actors)
- memory lifetime pattern (arena, GC, borrow-shaped)
- type complexity (simple generics, dependent types, none)
- I/O pattern (blocking, async, event-driven)
- Score each supported generation language against a language idiom profile.
- Return ranked list with per-language score and feature explanation.
**Acceptance criteria:**
- Given an AST node representing a data-parallel reduction loop, scores Julia/Rust
above Python/Lisp.
- Given an AST node representing a supervision tree with restart policies, scores
Erlang/Elixir above C++/Go.
- Ranking rationale is human-readable (per-feature delta from ideal profile).
- Tool runs in < 50ms on AST subtrees up to 500 nodes.
---
### Feature Request J: Polyglot FFI Glue Generator
**Tool name:** `whetstone_generate_ffi_glue`
**Derived:** `[Derived:DesignSession-Polyglot] Polyglot FFI Glue Generator`
**Problem:**
When a project uses multiple languages, the boundary between them (FFI, C ABI,
ctypes, JNI, pybind11, etc.) is written by hand. This is the primary source of
polyglot integration failures — type mismatches, lifetime errors, and ABI drift
are all caught only at runtime. The shared AST already encodes the type information
needed to generate these boundaries correctly.
**Requirements:**
- Given an AST boundary node (a function or struct visible to two language targets):
- Emit the correct binding on both sides (e.g. Rust `extern "C"` + Python ctypes struct)
- Emit a C ABI header as the neutral intermediary when needed
- Annotate the boundary with source AST node ID for cross-language debug symbol linking
- Support at minimum: Rust↔Python, Go↔C++, C++↔JavaScript (N-API), Rust↔Go (CGo)
- Generated glue must compile and pass a round-trip type check
**Acceptance criteria:**
- A Rust function callable from Python via generated ctypes binding, where the
binding was produced entirely from the shared AST — no hand-written glue.
- Round-trip test: Python calls Rust, Rust returns value, Python receives correct type.
- Boundary annotations present in generated DWARF (for DAP orchestrator).
---
### Feature Request K: Cross-Language Symbol Index Emitter
**Tool name:** `whetstone_emit_symbol_index`
**Derived:** `[Derived:DesignSession-Polyglot] Cross-Language Symbol Index`
**Problem:**
LSPs are language-specific and share no state. Cross-language goto-definition,
rename, and find-references are broken in all polyglot projects. The shared AST
already contains the symbol graph — it just isn't being emitted in a queryable format.
**Requirements:**
- Emit a SCIP-format (Sourcegraph Code Intelligence Protocol) symbol index from
the shared AST after multi-language generation.
- Index must include:
- Definition sites (per-language file + line)
- Reference sites across all generated languages
- Type information at language boundaries
- Cross-language "same symbol" links (Rust `my_fn` ↔ Python `my_fn` ↔ C ABI `my_fn`)
- Index is updated incrementally on re-generation of any language target.
**Acceptance criteria:**
- A symbol defined in Rust and called from Python: goto-definition from Python
resolves to Rust source file and line.
- Rename in the shared AST propagates to all language targets and updates index.
- Index generation adds < 200ms to a full polyglot generation run.
---
### Feature Request L: LSP Orchestration Layer
**Tool name:** (editor integration, no standalone MCP tool)
**Derived:** `[Derived:DesignSession-Polyglot] LSP Orchestrator`
**Problem:**
Editors run one LSP per language. Cross-language queries (goto-definition, hover,
rename) are silently broken at language seams. There is no mechanism to route an
LSP request through the shared AST when the answer crosses a language boundary.
**Requirements:**
- A thin LSP proxy that sits between the editor and all per-language LSP servers.
- Intercepts requests at known cross-language boundary symbols (identified via symbol index).
- For intra-language requests: forwards directly to the appropriate language server.
- For cross-language requests: resolves via the SCIP symbol index and returns a
synthesized response to the editor.
- Supports: textDocument/definition, textDocument/references, textDocument/rename,
textDocument/hover (shows both-side type information at boundaries).
**Acceptance criteria:**
- Goto-definition from a Python call site lands on Rust function definition.
- Rename of a boundary symbol in the orchestrator propagates rename requests to
both the Rust LSP and the Python LSP simultaneously.
- Hover at a Rust↔Python boundary shows the C ABI type as well as both native types.
---
### Feature Request M: DAP Orchestration Layer
**Tool name:** (debugger integration, no standalone MCP tool)
**Derived:** `[Derived:DesignSession-Polyglot] DAP Orchestrator`
**Problem:**
Debuggers are language-specific. A polyglot stack trace (Rust → Go → Lisp) is
unreadable — native frames, goroutine scheduler frames, and Lisp continuations
are interleaved with no cross-language annotation. Stepping across a language
boundary is not possible.
**Requirements:**
- A DAP proxy sitting above per-language debug adapters (CodeLLDB for Rust,
Delve for Go, etc.).
- Uses DWARF boundary annotations (emitted by FFI Glue Generator) to identify
language seam frames in a mixed stack.
- Presents a unified, annotated stack trace: each frame labeled with its origin
language, AST node ID, and source location.
- Supports cross-language step-over: stepping past a boundary call executes
the foreign call and pauses at the next source line in the calling language.
- Breakpoints set by AST node ID fire in all generated language targets
simultaneously.
**Acceptance criteria:**
- Single debugger session, stack trace shows Rust frames and Python frames
correctly interleaved and labeled.
- Step-over at a Rust→Python call boundary pauses at the next Rust line
(Python call executes atomically).
- Breakpoint on AST boundary node fires when either the Rust or Python side
of the call is entered.
---
### Feature Request N: Polyglot Project Test Harness
**Tool name:** `whetstone_run_polyglot_suite`
**Derived:** `[Derived:DesignSession-Polyglot] Polyglot Test Harness`
**Problem:**
There is no systematic way to verify that a multi-language generation round-trip
is semantically correct — that the same intent expressed in N languages produces
equivalent observable behavior. Without this, "lossless polyglot transpiling"
is a claim, not a proof.
**Requirements:**
- Given a spec and a set of target languages, generate all language variants.
- Run each variant against the same black-box test suite (input/output pairs).
- Compare outputs across all variants; report any semantic divergence.
- Track parity over time: if adding a new language breaks an existing variant's
parity, block the generation.
**Acceptance criteria:**
- A sorting algorithm spec generates Python, Rust, Go, and Haskell variants.
- All four variants produce identical output for the same 1000 random inputs.
- Introducing a deliberate bug in the Rust generator causes the harness to flag
Rust as divergent without affecting the Python/Go/Haskell parity report.
---
### Rollout Plan (Polyglot Orchestrator)
1. **Phase 1 — Language Fitness** (Sprint 271-272): `LanguageFitnessScorer` + 2-language test projects
2. **Phase 2 — FFI + Symbol Index** (Sprint 273-275): `PolyglotFFIGlueGenerator` + `CrossLanguageSymbolIndexEmitter`
3. **Phase 3 — LSP Orchestration** (Sprint 276-278): LSP proxy + cross-language goto/rename/hover
4. **Phase 4 — DAP Orchestration** (Sprint 279-281): DAP proxy + unified stack traces + boundary breakpoints
5. **Phase 5 — Proof** (Sprint 282-285): Full polyglot test harness + all-language test projects
### Done definition for "lossless polyglot transpiling"
- A single spec generates N language variants (N = all supported Whetstone generators).
- All variants pass an identical black-box test suite.
- Cross-language calls work at runtime via generated FFI glue (no hand-written bindings).
- Goto-definition, rename, and hover work across all language seams in the editor.
- A unified debugger session can step through a call that crosses three or more language boundaries.
- The only hand-written artifact is the spec.

View File

@@ -0,0 +1,267 @@
# Polyglot Orchestrator — Sprint Plan
> Created: 2026-02-28
> Follows: Sprint 270 (all 26 generator readiness gaps closed)
> Goal: True lossless polyglot code generation with unified editing and debugging
---
## What We Are Building
A system where:
1. A single spec drives code generation into multiple languages simultaneously
2. Each language gets the component it is best suited for (fitness-scored)
3. FFI boundaries between languages are generated, not written by hand
4. A single editor session understands all languages via an LSP orchestrator
5. A single debugger session can step across language boundaries via a DAP orchestrator
6. A test harness proves behavioral parity across all language variants
The theoretical endpoint: a project with components in every supported Whetstone
generation language, each component calling the next, with no hand-written glue,
unified editing, and unified debugging. This proves lossless polyglot transpiling
as a construction, not a claim.
---
## Phase 1 — Language Fitness Scorer (Sprint 271-272)
**Steps 1883-1892**
The ability to analyze an AST subtree and recommend a ranked list of target languages
based on computational shape. Prerequisite for everything else — you can't route
generation to the right language without knowing what "right" means.
### Sprint 271: LanguageFitnessScorer core (Steps 1883-1887)
| Step | Component | What |
|------|-----------|------|
| 1883 | `ASTFeatureExtractor` | Extract scalar features from AST subtrees: mutation ratio, recursion shape, concurrency primitives, I/O pattern, type complexity |
| 1884 | `LanguageIdiomProfile` | Static profiles for each supported language: ideal feature vector per language |
| 1885 | `LanguageFitnessScorer` | Score AST features against profiles, return ranked list with rationale |
| 1886 | `whetstone_score_language_fitness` | MCP tool wiring |
| 1887 | Sprint 271 integration | Cross-component test: spec section → features → scores → ranked list |
### Sprint 272: Fitness-routed 2-language test projects (Steps 1888-1892)
| Step | Component | What |
|------|-----------|------|
| 1888 | `PolyglotProjectSpec` | Spec format extension: per-section language hints + fitness override |
| 1889 | Test project: `poly-sort` | Rust (sort core) + Python (data gen/validation) — fitness-routed |
| 1890 | Test project: `poly-api` | Go (HTTP server) + TypeScript (client) — fitness-routed |
| 1891 | Test project: `poly-parse` | C++ (lexer/parser) + Haskell (AST transformation) — fitness-routed |
| 1892 | Sprint 272 integration | All 3 test projects: generate → compile → run → output matches expected |
---
## Phase 2 — FFI Glue + Symbol Index (Sprint 273-275)
**Steps 1893-1907**
Generate the boundaries between languages from the shared AST. This is what makes
the boundaries type-safe and eliminates hand-written glue code.
### Sprint 273: PolyglotFFIGlueGenerator (Steps 1893-1897)
| Step | Component | What |
|------|-----------|------|
| 1893 | `ABIBoundaryExtractor` | Identify AST nodes that cross language boundaries (exported functions, shared structs) |
| 1894 | `CHeaderEmitter` | Emit C ABI header as neutral intermediary for any language pair |
| 1895 | `RustPythonBindingEmitter` | Rust `extern "C"` + Python ctypes binding from same AST node |
| 1896 | `GoCppBindingEmitter` | CGo + C++ extern from same AST node |
| 1897 | Sprint 273 integration | Rust↔Python round-trip: Python calls Rust via generated binding |
### Sprint 274: More binding pairs + DWARF annotations (Steps 1898-1902)
| Step | Component | What |
|------|-----------|------|
| 1898 | `CppJSBindingEmitter` | C++ N-API binding from AST node |
| 1899 | `RustGoBindingEmitter` | Rust FFI + CGo binding from AST node |
| 1900 | `DWARFBoundaryAnnotator` | Annotate generated DWARF with cross-language AST node IDs (needed for DAP orchestrator) |
| 1901 | `whetstone_generate_ffi_glue` | MCP tool wiring |
| 1902 | Sprint 274 integration | Go↔C++ round-trip: Go calls C++ via generated binding |
### Sprint 275: Cross-Language Symbol Index (Steps 1903-1907)
| Step | Component | What |
|------|-----------|------|
| 1903 | `SCIPEmitter` | Emit SCIP-format symbol index from shared AST after multi-language generation |
| 1904 | `CrossLanguageSymbolTable` | In-memory symbol table linking same-origin symbols across all generated languages |
| 1905 | `SymbolIndexUpdater` | Incremental update on re-generation (don't rebuild from scratch on every change) |
| 1906 | `whetstone_emit_symbol_index` | MCP tool wiring |
| 1907 | Sprint 275 integration | poly-sort: generate Rust+Python → emit index → verify cross-language symbol links |
---
## Phase 3 — LSP Orchestration (Sprint 276-278)
**Steps 1908-1922**
An LSP proxy that routes editor queries through the symbol index. The editor
sees one language server; the orchestrator fans out to the right per-language
server or resolves via the symbol index for cross-language queries.
### Sprint 276: LSP proxy core (Steps 1908-1912)
| Step | Component | What |
|------|-----------|------|
| 1908 | `LSPProxyServer` | LSP protocol handler that forwards to per-language servers |
| 1909 | `LanguageServerRouter` | Route by file extension / detected language |
| 1910 | `CrossLanguageBoundaryDetector` | Identify request targets that are cross-language boundary symbols |
| 1911 | `CrossLanguageDefinitionResolver` | Resolve goto-definition across language seams via symbol index |
| 1912 | Sprint 276 integration | poly-sort: goto-definition from Python call site lands on Rust source |
### Sprint 277: Hover + references + rename (Steps 1913-1917)
| Step | Component | What |
|------|-----------|------|
| 1913 | `CrossLanguageHoverProvider` | Hover at boundary shows both-side types + C ABI type |
| 1914 | `CrossLanguageReferencesProvider` | Find all references across all language targets |
| 1915 | `CrossLanguageRenameOrchestrator` | Rename propagates to all LSPs + updates symbol index |
| 1916 | `LSPProxyConfig` | Config file: which languages, which LSP servers, which port |
| 1917 | Sprint 277 integration | poly-api: rename shared type in Go+TS simultaneously |
### Sprint 278: LSP proxy hardening (Steps 1918-1922)
| Step | Component | What |
|------|-----------|------|
| 1918 | `LSPRequestCache` | Cache intra-language responses to reduce round-trip latency |
| 1919 | `LSPServerHealthMonitor` | Detect crashed language servers, route to degraded mode |
| 1920 | `LSPProxyDiagnosticAggregator` | Merge per-language diagnostics into unified list (no duplicates at boundaries) |
| 1921 | LSP proxy test suite | End-to-end: proxy running, 3 language servers, cross-language queries correct |
| 1922 | Sprint 278 integration | All 3 Phase 1 test projects: LSP proxy running, cross-language navigation verified |
---
## Phase 4 — DAP Orchestration (Sprint 279-281)
**Steps 1923-1937**
A DAP proxy that presents a unified debugger session across all language runtimes.
Stack traces are annotated, stepping across language boundaries works, breakpoints
can be set on AST nodes (firing in any language target).
### Sprint 279: DAP proxy core + stack annotation (Steps 1923-1927)
| Step | Component | What |
|------|-----------|------|
| 1923 | `DAPProxyServer` | DAP protocol handler forwarding to per-language debug adapters |
| 1924 | `DebugAdapterRouter` | Route by active frame language (detected from DWARF annotations) |
| 1925 | `PolyglotStackTraceDecoder` | Annotate mixed-language stack with origin language + AST node ID per frame |
| 1926 | `LanguageSeamFrameDetector` | Identify frames that sit at a language boundary (from DWARF annotations) |
| 1927 | Sprint 279 integration | poly-sort: unified stack trace shows Rust + Python frames labeled correctly |
### Sprint 280: Cross-language step + breakpoints (Steps 1928-1932)
| Step | Component | What |
|------|-----------|------|
| 1928 | `CrossLanguageStepOverHandler` | Step-over at a boundary call executes foreign call atomically, pauses in caller |
| 1929 | `CrossLanguageStepIntoHandler` | Step-into at a boundary call switches active debug adapter to foreign language |
| 1930 | `ASTNodeBreakpointMapper` | Set breakpoint by AST node ID, fires in all language targets that implement that node |
| 1931 | `BreakpointSyncOrchestrator` | Keep breakpoints in sync across all active debug adapters |
| 1932 | Sprint 280 integration | poly-api: breakpoint on Go handler fires; step-into crosses into TS call |
### Sprint 281: DAP hardening + multi-adapter coordination (Steps 1933-1937)
| Step | Component | What |
|------|-----------|------|
| 1933 | `DAPSessionLifecycleManager` | Launch/attach/detach per-language adapters as the debug session progresses |
| 1934 | `UnifiedVariableInspector` | Inspect variables across the boundary (translate types to editor representation) |
| 1935 | `DAPHealthMonitor` | Handle adapter crashes, fall back to single-language mode gracefully |
| 1936 | DAP proxy test suite | Step-into, step-over, breakpoint, variable inspect — all cross-language |
| 1937 | Sprint 281 integration | poly-parse: C++↔Haskell debug session — step across AST transformation boundary |
---
## Phase 5 — The Proof (Sprint 282-285)
**Steps 1938-1957**
The full polyglot test harness and the all-language test projects. This is the
demonstration that the system is real — not a claim but a construction.
### Sprint 282: Polyglot test harness (Steps 1938-1942)
| Step | Component | What |
|------|-----------|------|
| 1938 | `PolyglotSpecRunner` | Generate N language variants from one spec, compile and run all |
| 1939 | `BehavioralParityChecker` | Compare outputs across variants for same inputs, flag divergence |
| 1940 | `ParityRegressionGuard` | Block new language additions that break existing parity |
| 1941 | `whetstone_run_polyglot_suite` | MCP tool wiring |
| 1942 | Sprint 282 integration | poly-sort: Python+Rust+Go+Haskell — all produce identical output for 1000 inputs |
### Sprint 283: Wacky project 1 — poly-pipeline (Steps 1943-1947)
A data pipeline where each stage is a different language:
- Python (CSV ingestion + schema validation)
- Rust (data normalization + outlier detection, perf-critical)
- Go (fan-out routing to multiple sinks, concurrency)
- Haskell (statistical transformation, pure function)
- JavaScript/TypeScript (JSON serialization + HTTP push to consumer)
| Step | What |
|------|------|
| 1943 | Spec: poly-pipeline — all 5 components, interfaces defined in shared AST |
| 1944 | Generate all 5 language targets + FFI glue at each boundary |
| 1945 | Integration: end-to-end CSV in → HTTP push out, all 5 stages running |
| 1946 | LSP + DAP: unified editing and debugging across all 5 languages |
| 1947 | Parity check: replace each stage with a reference Python implementation, verify same output |
### Sprint 284: Wacky project 2 — poly-compiler (Steps 1948-1952)
A toy compiler where each phase is the language most suited to it:
- C++ (lexer — character-level performance, no GC pressure)
- Haskell (parser — recursive descent, algebraic data types)
- Rust (type checker — borrow-safe, zero-cost ownership tracking)
- Lisp/Scheme (optimizer — s-expression AST manipulation, homoiconicity)
- Go (code emitter — goroutine-parallel emission, simple concurrency)
| Step | What |
|------|------|
| 1948 | Spec: poly-compiler — 5 phases, shared IR type defined in AST |
| 1949 | Generate all 5 language targets + FFI glue |
| 1950 | Integration: source string in → bytecode out, all 5 phases connected |
| 1951 | LSP + DAP: cross-language navigation and debugging in the compiler itself |
| 1952 | Parity check: each phase replaceable with Python reference implementation |
### Sprint 285: Wacky project 3 — poly-everything (Steps 1953-1957)
One project, every supported generation language. Each language owns one function.
The chain: Language A calls B, B calls C, ... last language returns to A.
Fitness scorer assigns each language to the function most suited to it.
All FFI glue generated. All boundaries in the symbol index. Full LSP + DAP.
This is the theoretical proof: a single shared AST produced working code in every
supported language, connected at runtime, navigable in a single editor session,
debuggable in a single debugger session.
| Step | What |
|------|------|
| 1953 | Spec: poly-everything — one function per language, fitness-assigned |
| 1954 | Generate all N language targets + all FFI glue in one pipeline run |
| 1955 | Integration: full chain executes, output correct |
| 1956 | LSP + DAP: navigate and debug across all N language boundaries |
| 1957 | Parity report: all N language functions individually replaceable, parity confirmed |
---
## Success Definition
The sprint plan is complete when:
1. A spec with no target language hint produces a fitness-ranked recommendation
2. A 2-language project (any pair) generates with correct FFI glue — no hand-written bindings
3. Goto-definition from language A lands on the definition in language B
4. A single debugger session steps across a language A → language B call
5. poly-pipeline (5 languages) passes end-to-end with all stages running
6. poly-compiler (5 languages) compiles and runs a "hello world" source string
7. poly-everything (all languages) executes the full chain and parity is confirmed
At step 7, lossless polyglot transpiling is proven as a construction.
---
## Notes on Scope
- LSP and DAP orchestration layers are editor integrations, not MCP tools.
They run as separate processes alongside the whetstone_mcp binary.
- The SCIP symbol index is the shared data structure. It must be written to
a known path on generation and read by both the LSP and DAP orchestrators.
- Phase 5 test projects are not production software. They are proofs of concept
designed to stress the boundaries of the orchestration system.
- The practical value is not the test projects themselves but the integration
layer capability they prove: any project that needs FFI between two environments
can use Whetstone to generate the boundary from a shared spec.

View File

@@ -0,0 +1,290 @@
# Polyglot Test Projects
> Created: 2026-02-28
> Purpose: Validate the polyglot orchestrator at each phase. Projects are ordered
> by complexity — 2-language pairs first, then multi-language, then all-language.
> None of these are production software. They are boundary stress tests.
---
## Tier 1: 2-Language Projects
These prove the basic pipeline: fitness scoring, FFI glue generation, symbol
index, and cross-language LSP. They use language pairs with well-understood
interop stories so failures are clearly attributable to the orchestrator.
---
### poly-sort
**Languages:** Rust + Python
**Pattern:** Performance core in Rust, scripting/validation layer in Python
```
Python (test runner)
│ generates random arrays, validates output
│ calls via ctypes (generated from shared AST)
Rust (sort implementations)
│ merge sort, quick sort, radix sort
│ exposed as C ABI functions
└─ returns sorted array to Python
```
**Fitness rationale:**
- Rust: flat array mutation, cache-coherent loops, zero GC pressure → systems fitness
- Python: test orchestration, random generation, human-readable assertions → scripting fitness
**What it tests:**
- `LanguageFitnessScorer` recommends Rust for the sort functions, Python for the harness
- `RustPythonBindingEmitter` generates ctypes bindings for `sort_merge`, `sort_quick`, `sort_radix`
- Symbol index links Python `sort_merge` call site to Rust `sort_merge` definition
- Goto-definition from Python lands on Rust
- Debugger can step from Python test into Rust sort function
**Acceptance test:**
- 1000 random arrays of integers: all three sort variants produce output matching Python's `sorted()`
- No hand-written FFI code in the project
---
### poly-api
**Languages:** Go + TypeScript
**Pattern:** API server in Go, typed client in TypeScript
```
TypeScript (browser/Node client)
│ typed API client generated from shared AST
│ calls HTTP endpoints
Go (HTTP server)
│ router, handlers, response serialization
│ types defined in shared AST
└─ serves JSON responses
```
**Fitness rationale:**
- Go: goroutine-based HTTP handling, simple concurrency, excellent standard library → concurrency fitness
- TypeScript: strong types for API contracts, browser-compatible, React/Node ecosystem → typed scripting fitness
**What it tests:**
- Shared type definitions (request/response structs) generated in both Go and TypeScript from same AST nodes
- No OpenAPI spec written by hand — the shared AST is the source of truth
- Symbol index links TypeScript `UserResponse` interface to Go `UserResponse` struct
- Rename of a field in shared AST propagates to both Go and TypeScript simultaneously
**Acceptance test:**
- TypeScript client calls Go server, receives typed response
- Field rename via LSP orchestrator compiles cleanly in both languages
- No hand-written type definitions or API client code
---
### poly-parse
**Languages:** C++ + Haskell
**Pattern:** High-performance lexer/tokenizer in C++, algebraic parser in Haskell
```
Haskell (parser)
│ recursive descent, pattern matching on token ADT
│ calls C++ tokenizer via FFI
C++ (lexer)
│ character-level scanning, zero allocation
│ exposes token stream as C ABI iterator
└─ returns tokens to Haskell
```
**Fitness rationale:**
- C++: character-level loops, cache-coherent buffers, zero allocation → systems fitness
- Haskell: recursive ADT pattern matching, algebraic data types → functional fitness
**What it tests:**
- C++ → Haskell FFI (unusual direction; most polyglot FFI is C calling higher-level)
- `CHeaderEmitter` for the token stream iterator
- `GoCppBindingEmitter` is not used here — this exercises a new binding pair (C++↔Haskell via C ABI)
- Debugger: step from Haskell parser into C++ lexer and back
**Acceptance test:**
- Parse a sample grammar (JSON or a simple expression language)
- Output AST from Haskell matches reference Python parser for the same input
- No hand-written FFI
---
## Tier 2: Multi-Language Projects
These stress the orchestrator beyond two-language pairs. Each adds languages
that stress different aspects of the system (more binding pairs, more LSP
servers, larger symbol index, more complex debug adapter coordination).
---
### poly-pipeline
**Languages:** Python + Rust + Go + Haskell + TypeScript (5 languages)
**Pattern:** Data pipeline where each stage is the best language for that computation
```
Python CSV ingestion, schema validation, error reporting
↓ FFI (ctypes)
Rust Data normalization, outlier detection, statistics
↓ FFI (CGo)
Go Fan-out routing to multiple sinks, concurrent dispatch
↓ FFI (C ABI)
Haskell Statistical transformation, pure functional reduction
↓ FFI (N-API)
TypeScript JSON serialization, HTTP push to downstream consumer
```
**Fitness rationale:**
- Python: schema parsing, human-readable error messages, ecosystem (pandas for validation) → scripting
- Rust: numerical normalization on large arrays, no GC pauses at this stage → systems
- Go: goroutines for fan-out, select for concurrent dispatch → concurrency
- Haskell: pure reduction functions (fold, map), referential transparency at this stage → functional
- TypeScript: JSON is native, HTTP client ecosystem mature, consumer-facing → typed scripting
**What it tests:**
- 4 FFI boundaries generated from shared AST (Python↔Rust, Rust↔Go, Go↔Haskell, Haskell↔TS)
- Symbol index with 5 language targets — navigation across 4 boundaries
- LSP orchestrator running 5 language servers simultaneously
- DAP orchestrator stepping through 5-language call chain
- Parity: replace each stage with Python reference implementation, output must match
**Acceptance test:**
- CSV file in → HTTP POST to mock consumer
- All 5 stages running as one connected process (not microservices)
- End-to-end wall time within 2x of a pure Python reference implementation
---
### poly-compiler
**Languages:** C++ + Haskell + Rust + Lisp (Scheme) + Go (5 languages)
**Pattern:** A toy compiler where each phase is the language most fit for it
```
C++ Lexer — character-level scanning, no allocations per token
↓ C ABI
Haskell Parser — recursive descent, algebraic token → AST types
↓ C ABI
Rust Type checker — ownership-tracking symbol table, zero-cost
↓ C ABI
Lisp/Scheme Optimizer — s-expression AST rewriting, pattern-matched rules
↓ C ABI
Go Code emitter — parallel emission of bytecode, concurrent writes
```
**Fitness rationale:**
- C++: character-level tight loops, arena allocation for token buffer → systems
- Haskell: token ADTs, recursive descent naturally expressed as algebraic functions → functional
- Rust: symbol table with lifetime-safe references, borrow checker prevents dangling refs → systems/safety
- Lisp: the optimizer manipulates an AST that is itself S-expressions — homoiconicity → meta-programming
- Go: parallel bytecode emission with goroutines, simple coordination → concurrency
**What it tests:**
- The most philosophically interesting FFI direction: Lisp optimizing Rust's output then handing to Go
- The Lisp binding pair (Scheme↔C ABI) is a new surface for the glue generator
- poly-compiler is itself written in the languages it compiles — not intentionally self-hosting,
but the structural similarity is notable
**Acceptance test:**
- Compiles the following source string: `(let x 42) (+ x 1)` → bytecode `[PUSH 42, STORE x, LOAD x, PUSH 1, ADD]`
- Each phase independently replaceable with Python reference implementation (parity check)
---
## Tier 3: The Proof
---
### poly-everything
**Languages:** All supported Whetstone generation languages
**Pattern:** One function per language, fitness-assigned. Each calls the next.
The fitness scorer assigns each language to the function most suited to it.
The chain is determined by the scorer, not specified manually.
All FFI glue generated. All boundaries in the symbol index.
Full LSP + DAP.
**Current supported generation languages in Whetstone:**
Python, C++, Rust, Go, JavaScript/TypeScript, Java, Haskell, Elixir, Lisp/Scheme,
Julia, PHP, Rust (embedded), WASM (via Rust), Kotlin, Swift, Zig
**Suggested chain** (fitness scorer should reproduce this independently):
```
Zig Memory-mapped file reader (ultra-low-level, no runtime)
C++ Binary deserialization (struct parsing, no GC)
Rust Validation and normalization (safety-critical, owned types)
Haskell Schema transformation (pure functional, algebraic types)
Lisp/Scheme Rule application (S-expression pattern matching)
Julia Statistical analysis (array operations, broadcasting)
Python Result formatting (readable output, ecosystem)
Go HTTP dispatch (concurrency, fan-out)
TypeScript JSON response (typed client contract)
Java Persistent storage (JDBC, enterprise ecosystem)
Kotlin Android notification (Kotlin coroutines, Android SDK)
Swift iOS notification (Swift async/await, Apple SDK)
Elixir Real-time broadcast (actor model, Phoenix channels)
PHP CMS integration (WordPress hook, legacy ecosystem)
WASM Browser computation (sandboxed, portable)
└─ returns to Zig (closes the chain)
```
**What it proves:**
- The shared AST can represent computations across the full spectrum of
language paradigms: systems, functional, OO, scripting, actor, array, meta
- FFI glue can be generated for every adjacent pair in the chain
- The symbol index spans all language targets
- The LSP orchestrator can route queries across N language boundaries
- The DAP orchestrator can present a coherent stack trace spanning all languages
- Parity: every function replaceable by a Python reference implementation
**Acceptance test:**
- Binary file in → push notification + browser computation + CMS update + database write
- No hand-written FFI, no hand-written bindings, no hand-written type definitions
- The only human artifact is the spec
**Parity acceptance test:**
- Replace each language stage with a Python reference implementation
- Output must be identical for all 100 test inputs
- This is the formal proof of lossless transpiling
---
## What This Actually Means
If poly-everything passes, we have demonstrated:
1. **For integration layers**: Any environment boundary (Python↔C++, Go↔Java, Rust↔WASM)
can be generated from a shared spec. This was previously only possible for major projects
with dedicated platform integration teams (GraalVM, JPype, pybind11, etc.).
2. **For legacy modernization**: An existing system in language A can have a spec written
from it, and a reimplementation in language B generated with correct type-safe boundaries.
The language A and language B versions run in parallel and their outputs are compared
automatically to verify the migration.
3. **For new projects**: Language selection stops being a permanent architectural decision.
A component can be written in the fitness-optimal language and later regenerated in a
different language if the fitness profile changes (e.g. scaling requirements shift
from scripting-friendly to systems-performance).
The practical value is the integration layer capability. The theoretical value is
the proof that language is a generation parameter, not an architectural commitment.