Problem
src/simlin-engine/src/project_io.proto (lines 402-459) defines a family of patch messages:
ProjectPatch { project_ops, models }
ModelPatch { name, ops }
ProjectOperation (oneof: SetSimSpecsOp, SetSourceOp)
ModelOperation (oneof: UpsertStockOp, UpsertFlowOp, UpsertAuxOp, UpsertModuleOp, DeleteVariableOp, RenameVariableOp, UpsertViewOp, DeleteViewOp, UpdateStockFlowsOp)
- the associated
*Op payload messages (UpsertModuleOp, etc.)
These compile to prost types in src/simlin-engine/src/project_io.gen.rs (ProjectPatch at line 819, ModelOperation at 848, UpsertModuleOp at 908).
No Rust code references the prost-generated patch types. A repo-wide grep for project_io::ProjectPatch / project_io::ModelPatch / project_io::ModelOperation / project_io::UpsertModuleOp returns zero matches, and src/simlin-engine/src/serde.rs has no conversion functions for them.
The actually-exercised patch path is JSON-only and uses a separate, hand-written native type that is unrelated to protobuf:
src/simlin-engine/src/patch.rs defines a native ProjectPatch / ModelPatch / ModelOperation (plain Rust structs/enums over datamodel::*, not prost-derived).
src/libsimlin/src/patch.rs defines JsonProjectPatch / JsonModelOperation (serde) and converts them to the native engine::ProjectPatch via convert_json_project_patch / convert_json_model_operation, called from the simlin_project_apply_patch FFI entry point.
src/simlin-mcp-core/src/tools/edit_model.rs likewise builds the native simlin_engine::ProjectPatch directly.
So there are two same-named-but-unrelated ProjectPatch families, and the protobuf one is dead: it has a generated Rust type but no conversion path and no caller.
Why it matters
- Maintainability / latent inconsistency: a contributor extending the patch surface (e.g. for Vensim macro support, where this was discovered) reasonably assumes
project_io.proto is the source of truth and may add proto messages that are never wired up — or may not realize the proto definitions exist and are stale.
- Protobuf versioning discipline: the repo treats
project_io.proto as a versioned wire format (there is a DB of serialized instances). Carrying dead patch messages in that file muddies which messages are actually load-bearing.
- It is either (a) genuinely dead schema that should be deleted, or (b) an intended-but-never-implemented proto patch path. Either way the current state is undocumented and confusing.
Component(s) affected
src/simlin-engine/src/project_io.proto
src/simlin-engine/src/project_io.gen.rs (generated)
- (contrast with the live path:
src/simlin-engine/src/patch.rs, src/libsimlin/src/patch.rs, src/simlin-mcp-core/src/tools/edit_model.rs)
Possible approaches
- Delete the dead messages from
project_io.proto (ProjectPatch, ModelPatch, ProjectOperation, ModelOperation, and the *Op payload messages that are not used elsewhere) and regenerate. Since these messages are never serialized to the DB (only Project is), removing them is wire-safe. Verify each *Op's inner payload message isn't shared with a live message before deleting.
- Or decide proto is meant to be the patch wire format, and implement the
project_io <-> patch.rs conversion in serde.rs plus a proto FFI entry, retiring the bespoke JsonProjectPatch in libsimlin. This is the larger change and should only happen if there's a real need for a binary patch format.
Given the JSON path is the one with full FFI + MCP coverage, option 1 (delete) is the likely answer, but the choice should be made deliberately.
Discovery context
Identified during a codebase investigation for Vensim macro support; out of scope for that work.
Problem
src/simlin-engine/src/project_io.proto(lines 402-459) defines a family of patch messages:ProjectPatch{project_ops,models}ModelPatch{name,ops}ProjectOperation(oneof:SetSimSpecsOp,SetSourceOp)ModelOperation(oneof:UpsertStockOp,UpsertFlowOp,UpsertAuxOp,UpsertModuleOp,DeleteVariableOp,RenameVariableOp,UpsertViewOp,DeleteViewOp,UpdateStockFlowsOp)*Oppayload messages (UpsertModuleOp, etc.)These compile to prost types in
src/simlin-engine/src/project_io.gen.rs(ProjectPatchat line 819,ModelOperationat 848,UpsertModuleOpat 908).No Rust code references the prost-generated patch types. A repo-wide grep for
project_io::ProjectPatch/project_io::ModelPatch/project_io::ModelOperation/project_io::UpsertModuleOpreturns zero matches, andsrc/simlin-engine/src/serde.rshas no conversion functions for them.The actually-exercised patch path is JSON-only and uses a separate, hand-written native type that is unrelated to protobuf:
src/simlin-engine/src/patch.rsdefines a nativeProjectPatch/ModelPatch/ModelOperation(plain Rust structs/enums overdatamodel::*, not prost-derived).src/libsimlin/src/patch.rsdefinesJsonProjectPatch/JsonModelOperation(serde) and converts them to the nativeengine::ProjectPatchviaconvert_json_project_patch/convert_json_model_operation, called from thesimlin_project_apply_patchFFI entry point.src/simlin-mcp-core/src/tools/edit_model.rslikewise builds the nativesimlin_engine::ProjectPatchdirectly.So there are two same-named-but-unrelated
ProjectPatchfamilies, and the protobuf one is dead: it has a generated Rust type but no conversion path and no caller.Why it matters
project_io.protois the source of truth and may add proto messages that are never wired up — or may not realize the proto definitions exist and are stale.project_io.protoas a versioned wire format (there is a DB of serialized instances). Carrying dead patch messages in that file muddies which messages are actually load-bearing.Component(s) affected
src/simlin-engine/src/project_io.protosrc/simlin-engine/src/project_io.gen.rs(generated)src/simlin-engine/src/patch.rs,src/libsimlin/src/patch.rs,src/simlin-mcp-core/src/tools/edit_model.rs)Possible approaches
project_io.proto(ProjectPatch,ModelPatch,ProjectOperation,ModelOperation, and the*Oppayload messages that are not used elsewhere) and regenerate. Since these messages are never serialized to the DB (onlyProjectis), removing them is wire-safe. Verify each*Op's inner payload message isn't shared with a live message before deleting.project_io<->patch.rsconversion inserde.rsplus a proto FFI entry, retiring the bespokeJsonProjectPatchinlibsimlin. This is the larger change and should only happen if there's a real need for a binary patch format.Given the JSON path is the one with full FFI + MCP coverage, option 1 (delete) is the likely answer, but the choice should be made deliberately.
Discovery context
Identified during a codebase investigation for Vensim macro support; out of scope for that work.