Repository navigation
Make SchemaNode one wire type that the store fills, with extends and relationships (closes #3442) - #3490
Conversation
Pragmatic Code Review: PR #3490Review Type: Initial review (no prior reviews or comments on the PR). Reviewed at Summary: The consolidation does what the issue asks. There is one How I checked: I read the substantive files in full (not just the diff), read ADR-086 §1, the node type sequence and the Requirements Check
The questions you asked
Code Review Findings🟡 Important1. A schema node read as a plain node silently drops its
2. The path that rewrites the
🟢 Suggestions3. "Only the store fills a 4. Guards made dead by the consolidation 5. 6. 7. Doc example no longer matches the type 8. Undisclosed behaviour change in the Tauri list command Nits
RecommendationAPPROVE. The change is a clear net improvement and meets every acceptance criterion. Findings 1 and 2 are worth addressing before merge: both are small, and both concern the exact contract this PR establishes. |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review: APPROVE (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Review feedback addressed (commits
|
Pragmatic Code Review: PR #3490Review Type: Re-Review. Scope: Previous Review Summary
How I checked: I read the full diff and the code around each fix, and traced every caller of the two functions that gained logic. I ran three tests at Verification of previous findings1. 🟡 Generic read of a schema row dropped
2. 🟡
3. 🟢 "Only the store fills a 4. 🟢 Dead guards: addressed. Both 5. 🟢 Fold the 6. 🟢 7. 🟢 Doc example: addressed ( 8. 🟢 Undisclosed behaviour change: addressed. The PR body lists the Tauri fail-on-decode change, the new write refusal and the whole-row schema read. Nits: all four addressed. The reserved-names doc block is on New findingsNo blocking or important issues. Three nits, none of which need a re-review.
RecommendationAPPROVE. Both fixes that added logic are correct for every caller I traced, the new tests fail without them, and the fix commits introduce no new problem. The three nits are optional comment touch-ups. |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review): APPROVE (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Re-review feedback addressed (
|
|
Merge queue: #3490 was taken out of the queue — it conflicts with main in: packages/core/src/models/mod.rs, packages/daemon/src/services/node_service.rs, packages/desktop-app/src/lib/types/generated/index.ts, packages/nodespace-types/src/convert.rs, packages/nodespace-types/src/lib.rs. Rebase onto origin/main, push, and re-run |
fb04e4e to
811a1de
Compare
…relationships (closes #3442) One SchemaNode, in nodespace-types, filled by the store from the schema's row and its declaration edges. Core's second struct is replaced by storage mapping functions. The schema RPCs carry the typed SchemaNode and typed CreateSchemaParams / UpdateSchemaParams; Tauri, the dev-proxy and the CLI pass the typed schema through. SchemaNode.description is removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
811a1de to
e5c99a0
Compare
Closes #3442.
What changed
SchemaNodeis now one wire type, defined innodespace-typesand filled by the store (ADR-086 §1). Core's second struct is gone.nodespace_types::SchemaNodecarries the envelope,fields,relationships,extends,abstract, the structural rules and the two templates.descriptionis removed (it was always empty; a schema's description is its child subtree).packages/core/src/models/schema_node.rsnow holds no struct, only the storage mapping:from_storage(node, declarations),to_node,to_properties,to_declarations. A schema can only be built from a row together with its declaration edges, so there is no unfilledSchemaNode. Theextendsedge becomesSchemaNode::extendsand is never an entry inrelationships.properties.into_wire_nodeis deleted. The schema RPCs return the typedSchemaNode(SchemaResponse/SchemaListResponse, JSON-encoded like the other typed payloads on this proto).CreateSchemaParams,UpdateSchemaParams,FieldRename,FieldValueAddition,CreateSchemaOutputandSchemaUpdateOutputare wire types innodespace-types, with generated TypeScript. Core exposes typedcreate_schema/update_schema; the daemon decodes the RPC payload into the typed params and answers with the typed output.handle_create_schema/handle_update_schemaremain as the agent's JSON tool-call adapters over them.SchemaNodethrough unchanged (the dev-proxy previously droppedrelationshipsandextends). The CLI prints a schema under the keys the parameters take.Node-type sequence:
schemais a concrete core type (the meta-type), category Structured. No field, relationship or rule is added. Removed:SchemaNode.description. Docs: theschemasheet incomponents/node-types.md, pluscomponents/schema-management.mdanddevelopment/standards/naming-conventions.mdin nodespace-docs.Behaviour changes to review
A schema node read as a plain node keeps the generic shape.
node_to_typed_valueno longer builds aSchemaNodefrom a row, because it has no store to fill it from; that conversion used to return a schema with emptyrelationships. The frontend only ever read typed schemas throughgetSchema/getAllSchemas, so nothing there changes. The agent'sget_nodeon a schema id andrelationship getnow return the stored definition underproperties.extendsis no longer a traversable relationship name. With the parent out ofrelationships,get_related_nodes(…, "extends")on an instance is refused as undeclared instead of returning an empty result, and a subtype'sextendsedge no longer shows up as an inbound relationship on its base type.CLI output.
schema get --jsonprints the schema with snake_case top-level keys (title_template,is_core,schema_version, …) and noproperties;schema list --jsonis{"count", "schemas"}instead of{"count", "nodes"}.packages/skill/references/cli.mdis updated.create_schemaresult carriesextendsas its own key; it used to appear as anextendsentry inrelationships.Workspace context fetches the schema corpus before semantic retrieval (same one read per turn with a query) and resolves hits against it, so a hit is never a bare row. If that read fails, schema retrieval is skipped for the turn rather than returning hits without relationships.
Tauri
get_all_schemasfails on a schema it cannot decode instead of skipping it. The daemon serializes a typed struct, so a decode failure is a contract break, not a bad row.A declaration write that drops the parent is refused.
set_schema_relationshipsis a full replace, and a schema'srelationshipsno longer holds theextendsedge, so a set without it would have unlinked the type from its base. A parent is re-targeted, never cleared.A schema row is read whole on a generic read. Its structural rules (
children,parent) are objects and were dropped by the flat-properties rule; they now come back underpropertieswith the rest of the stored definition.Tests
nodespace-types: wire round trip ofSchemaNode; params decode, unknown-key refusal and round trip.models/schema_node.rs), search-hit resolution, re-target keeps oneextendsedge.get_all_schemasandget_schema_definitionreturn typed schemas withrelationshipsandextends; the write RPCs carry typed params and outputs.schema_read_tauri_seam_testagainst a real daemon;decode_schemaunit tests.schema-seeding.e2e.tsagainst a real daemon; adapter unit tests.schema getreads a schema under the keysschema createtakes.bun run test:changedpasses (frontend, browser, scripts, skill, generated-TypeScript drift, Rust workspace). The e2e suite passes locally against a daemon built from this branch (50 tests).🤖 Generated with Claude Code