Skip to content

Validate node type and compute title in upsert create branch; drop test- id exemption - #3038

Merged
malibio merged 2 commits into
mainfrom
issue-3013-upsert-create-validation
Sep 25, 2026
Merged

malibio merged 2 commits into
mainfrom
issue-3013-upsert-create-validation

Conversation

@malibio

@malibio malibio commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Closes #3013
Closes #3012

#3013 — upsert_node_with_parent create branch

  • Extracted the registered-behavior-or-schema check from prepare_create_node_with_parent into ensure_known_node_type, and applied it to upsert_node_with_parent when the node doesn't exist yet. The check runs before the missing parent is auto-created, so a rejected call leaves no orphan date node behind.
  • The create branch now calls compute_title (always non-root) instead of hardcoding title: None.

#3012 — test- id exemption

  • Removed the provided_id.starts_with("test-") carve-out from caller-supplied id validation. Non-date/non-schema ids must be UUIDs. No test relied on it (full nodespace-core suite green).

Tests

  • test_upsert_node_with_parent_create_branch_computes_title
  • test_upsert_node_with_parent_create_branch_rejects_unknown_type (also asserts no parent left in the store)
  • test_create_node_with_parent_rejects_test_prefixed_id

Pre-push gate (test:all + daemon build + e2e) passed.

🤖 Generated with Claude Code

…st- id exemption (closes #3013, closes #3012)

- Extract ensure_known_node_type from prepare_create_node_with_parent and
  apply it in upsert_node_with_parent's create branch, checked before the
  missing parent is auto-created so a rejected call leaves nothing behind.
- upsert_node_with_parent's create branch now computes the title instead of
  hardcoding None.
- Remove the shipped "test-" prefix carve-out from caller-supplied id UUID
  validation; no test relied on it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@malibio

malibio commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

Pragmatic Code Review — Initial Review

Summary: This is a small, focused change and it improves the code. Both issues are fixed as specified. Pulling the type check out into ensure_known_node_type removes duplicated code, and the new tests would fail on the old code. None of the findings block merge.

Requirements Check

Findings

🟡 create_node_with_parent still creates a date container before rejecting an unknown type
📁 packages/core/src/services/node_service/crud.rs:444-451

  • Step 1 (ensure_date_exists) runs before Step 2 (ensure_known_node_type).
  • So a bogus type under a missing date parent creates an empty date node and then returns an error.
  • Fix: swap the two steps and add a mirroring regression test.
  • Principle: validate before side effects, the same way on both entry points.

🟡 The upsert create branch has no UUID validation for the caller's node id — follow-up
📁 packages/core/src/services/node_service/crud.rs:2182-2200

🟡 The upsert create branch skips the rest of the create-path validation, and its doc comment claims a "single transaction" that isn't there — follow-up

  • It skips three checks: collection-with-parent, lifecycle/schema validation, and date-only auto-parent.
  • Fix: route the upsert create through prepare_create_node_with_parent + create_node_with_parent_in_tx.

🟢 Moving the existence check earlier adds no real race risk. Races fail the same way as before: a concurrent create hits a primary-key conflict, a concurrent delete fails the update. It also saves one store round-trip.

🟢 The title normalization is equivalent. Properties are always {}, so normalizing them first would change nothing.

🟢 Test nit: the title test uses task, whose title doesn't depend on rootness, so nothing pins the Some(false) choice. A text child created via upsert should get title == None; asserting that would catch a change to Some(true).

🟢 Nit: the deprecated _root_id parameter should be deleted. That's a follow-up, because removing it touches the proto, the daemon and the Tauri command.

Recommendation: APPROVE

@malibio malibio left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated pragmatic-code-review: APPROVE (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.

…t rootness

- prepare_create_node_with_parent now checks the node type before
  ensure_date_exists, so a rejected create leaves no date container behind
  (same rule the upsert path now follows); regression test added.
- Upsert create-branch title test also asserts a text child stays untitled,
  pinning the is_root = false choice.
- Correct upsert_node_with_parent's doc comment: its steps are separate
  store writes, not a single transaction.

Deferred to a follow-up issue (changes gRPC behavior beyond #3012/#3013):
UUID validation of the upsert node id, routing upsert's create branch
through the create_node_with_parent pipeline, removing _root_id.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@malibio

malibio commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

Review feedback addressed (121e9c7)

✅ Addressed

  • 🟡 prepare_create_node_with_parent now checks the node type before ensure_date_exists, so a rejected create leaves no date container behind. Added regression test test_create_node_with_parent_unknown_type_leaves_no_date_parent.
  • 🟡 (partial) Corrected upsert_node_with_parent's doc comment. It no longer claims a single transaction.
  • 🟢 The upsert create-branch title test also asserts that a text child stays untitled, which pins is_root = false.

⏭️ Deferred to #3040. These change gRPC-facing behavior beyond #3012 and #3013:

  • UUID validation of the upsert node_id.
  • Routing upsert's create branch through the canonical create pipeline, in one transaction.
  • Removing _root_id end to end.

🟢 No action needed on the existence-check race or the title-normalization equivalence (both confirmed fine).

Core suite green; pre-push gate (test:all + daemon build + e2e) passed.

Re-review: not needed. The changes are a statement reorder, a comment fix and added tests.

@malibio
malibio merged commit 04bb517 into main Sep 25, 2026
@malibio
malibio deleted the issue-3013-upsert-create-validation branch September 25, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant