Skip to content

feat(sim): describe_project — the frozen IR as a protocol description - #15

Merged
Kinflou merged 2 commits into
masterfrom
feat/sim-1a-describe-project
Sep 2, 2026
Merged

feat(sim): describe_project — the frozen IR as a protocol description#15
Kinflou merged 2 commits into
masterfrom
feat/sim-1a-describe-project

Conversation

@Kinflou

@Kinflou Kinflou commented Sep 2, 2026

Copy link
Copy Markdown
Member

Milestone 1a of playground simulation — the one read-only WASM function the simulator is built on.

describe_project(files)ProjectShape: per schema, the ::-namespace, ir_hash, every protocol (name, framing from @framing, functions), errors, and types (structs / enums). All read off the frozen units interpret_project already produces — no new comline-core surface.

Function shapes carry:

  • index — 0-based position = the Call id resolveKind matches (same order as the generated CHAT_CALLS)
  • oneway_return is None
  • args / returns as a TypeRef (prim / ref / array / unit / union), classified from the Namespaced("T[]") strings the freezer emits; struct/enum names resolve project-wide so a cross-file type still reads as ref
  • throwsu16 ordinals joined to the error table by ordinal

ir_hash parity — the risk the spec flagged

ir_hash is comline_core::schema::ir::frozen::schema_ir_hash(units) — the exact call comline-codegen-rust and comline-codegen-typescript both make. Verified against the built wasm: describe_project(chat+types).schemas[chat].ir_hash === the IR_HASH constant generate_project(…, "typescript") emits. Identical by construction; the field doc records the invariant.

Also confirmed: arrays freeze as KindValue::Namespaced("T[]") — the spec's open question. TypeRef handles the [] suffix; the doc's "unconfirmed" note can drop.

Scope

shape.ts mirrors the output 1:1; the worker gains a describeProject command. No UI — that's 1d.

wasm-pack build + tsc --noEmit + vite build green; the 1a acceptance assertions (protocol / indices / oneway / throws / ir_hash parity) pass against the built binary.

Milestone 1a of the playground simulation (docs: design/playground-simulation.md).

`describe_project(files)` returns a `ProjectShape`: per schema, the
`::`-namespace, `ir_hash`, every protocol (name, framing from `@framing`,
functions), errors (ordinal, name, message, fields) and types (structs /
enums) — all read straight off the frozen units `interpret_project`
already produces. No new `comline-core` surface.

Function shapes carry the 0-based index (the `Call` id `resolveKind`
matches), `oneway` (`_return` is None), args and return as a `TypeRef`
(`prim` / `ref` / `array` / `unit` / `union` — classified from the
`Namespaced("T[]")` strings the freezer emits), and `throws` joined to
the error table.

`ir_hash` is `comline_core::schema::ir::frozen::schema_ir_hash(units)` —
the exact call both generators make — so a sim connection's handshake
mirrors a real one. Verified: `describe_project`'s `ir_hash` equals the
`IR_HASH` constant `generate_project` emits for the same schema.

`shape.ts` mirrors the output 1:1; the worker gains a `describeProject`
command. No UI yet (that's 1d).
Comment thread wasm/src/lib.rs Outdated
const PRIM_NAMES: &[&str] = &[
"bool", "u8", "u16", "u32", "u64", "u128", "s8", "s16", "s32", "s64", "s128", "f32", "f64",
"float", "str", "string",
];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Primitive names often get repeated across repositories, i wonder if it can be improved with some single source of truth

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — turns out the list wasn't just duplicated, it was doing nothing.

name_ref only needs to answer "is this a type declared in this project?" (render its fields) vs. "anything else" (one scalar input). The grammar reserves the primitive keywords, so a declared struct/enum name can never be u64/string/etc. — meaning known.contains(n) is already the whole decision. A primitive falls through to the same Prim arm as an unresolved import, which is the intended fallback for both.

So I dropped the list entirely rather than centralizing it — known (built from the frozen IR) is the single source of truth. comline-core does keep its own private PRIMITIVE_NAMES in validation::validator; making that pub would be the fix if a real need for a shared list comes up, but it'd be a core-lockstep bump for a 16-element array, so not now.

Pushed as 962d80e; output is byte-identical (the 1a smoke still passes, including nested string[]).

Per PR review — it duplicated knowledge that lives in comline-core (which
keeps its own private copy in validation::validator). It was also
redundant: the grammar reserves the primitive keywords, so a declared
struct/enum name can never be `u64` / `string` / etc. `name_ref` now only
asks whether a name is a type declared in this project (the IR-built
`known` set); anything else — a primitive or an unresolved import —
renders as one scalar input, which is the intended fallback either way.

Output is byte-identical: the 1a smoke (indices, oneway, throws, nested
`string[]`, ir_hash parity) still passes.
@Kinflou
Kinflou merged commit 7fb6165 into master Sep 2, 2026
2 checks passed
@Kinflou
Kinflou deleted the feat/sim-1a-describe-project branch September 2, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant