Repository navigation
Give a schema a bound chat: explain the type, change it knowing what may change and what it breaks (closes #3742) - #3782
Conversation
Pragmatic code review: PR 3782Review type: INITIAL (no prior reviews). Static read of the diff; no builds or tests run. Requirements check (issue 3742)
AGENTS.md checks (literal node_type comparisons, lifecycle reads, compat code, issue numbers, console logging): clean. Findings🟡 Important
🟢 Suggestions
Nitpicks
Notes on the specific concerns
Recommendation: COMMENT (REQUEST CHANGES on findings 1 and 2; 3-9 discretionary)Well-scoped and tested; meets the acceptance criteria. I would approve once 1 (wrong model-facing statement) and 2 (guard asks for a force core never honors) are fixed or justified. Posted as a comment because GitHub blocks self-review. |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review: COMMENT, requesting changes on findings 1 and 2 (posted as a comment, GitHub blocks self-review). Full report is in the preceding PR comment.
Address review: summaryAddressed
Skipped
Checks: Re-Review DecisionDecision: RE-REVIEW NEEDED Rationale: the guard's behavior and a tool parameter changed ( |
Pragmatic code review: PR 3782 (re-review of 26e40fc)Review type: Re-Review. Static read of Previous review summary
Verification of the author's claims
Findings🟡 A. The guard's premise "a built-in field is refused by the schema write itself" is only true for Core/System protection📁 🟡 B. A rename of a field a title template names is not blocked by core: it commits, then errors📁 🟢 C. Duplicate helper📁 🟢 Nit
Skipped items
Recommendation: APPROVEThe previous Critical-class concerns (mislabelled user field, asking for a force core will not honour, one |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review): APPROVE. Findings 1-4, 6, 8 and the stale-comment nit are addressed; confirmed is stripped before core's deny_unknown_fields parse; golden diff is the parameter rename only. Two non-blocking notes (a User-protected declared field such as task.priority is described as unchangeable but core allows it; a rename of a template-named field commits before core's template validation errors) are in the preceding comment. Posted as a comment because GitHub blocks self-review.
Address review (re-review round): summaryThe re-review was APPROVE with two non-blocking findings and a nit. Addressed
Not changed
Checks: Re-Review DecisionDecision: RE-REVIEW NEEDED (narrow) Rationale: a validation was added to core's |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (narrow re-review): APPROVE
Narrow re-review of e3e22bb (previous: 6144483048)
Verdict: APPROVE. The rename-vs-stored-template finding is resolved. One doc-comment nit, nothing blocking.
Checked
- Placement: The pre-check sits after every validation (
validate_type_system_changes, context paths, relationship removal, play impact, core-prefix, redeclaration) and before Phase 1. Nothing betweenschema_beforeand Phase 1 writes, so a refusal changes nothing. - Snapshot and token form:
schema_before.title_templateis the stored template, which is whatrename_schema_field->update_node_unchecked_in_tx->validate_templated_contentvalidates at rekey time. The match is the exact{name}token.validate_template_tokensalso takes the bytes between{and}verbatim (no trim, no dotted or nested form, defined set = the schema's ownfields). So{ first_name }is already refused as an undefined field at write time and cannot be stored; there is no spaced form to miss. - No false blocks:
from == torelabels are filtered. A rename of a field the template does not name passes. A subtype cannot rename a parent field, and a template only names its own schema's fields, so a parent's template never trips it. A call that setstitle_template: ""together with a rename is refused, but that is not a regression: Phase 1 runs against the stored template, so it already failed after beginning the rekey. Core has no in-call ordering that makes it work, so the message's three-step advice is correct. - Skill sentence and message: Both are accurate. An empty-string
title_templateclears, and the sequence in the message is the one the test exercises. super::has_namespace_prefix: A private fn in the parent module is visible to its child module, and the body is identical to the deletedis_prefixed(ns:bare, exactly one colon, both non-empty). Fine, and it removes a duplicate.
Findings
- 🟢 Nit
📁 packages/core/src/schema/schema_test.rs(test doc comment, ~line 321): "A call that also sets a template that uses the new name goes through" is not true and not tested. The stored template is what is validated at rename time, so a single call that renames and sets the new template is refused. The test only proves the three separate calls. Reword to "The sequence the refusal names (three calls) goes through" (accuracy of comments, why not what). - 🟢 Nit
📁 packages/core/src/schema/mod.rs:3243: The pre-check runs after the play-impact check, so a caller withoutforceon an affected play sees that error first, then this one. Harmless (this refusal is not forceable) but you could move it ahead of the impact analysis, next to the otherforce-independent Phase 0 checks.
Recommendation
APPROVE. The change is minimal, correctly scoped, and tested on both the refusal and the working sequence. Fix the test comment if convenient.
Address review (narrow re-review): summaryAddressed: the test's doc comment now says the rename goes through in three calls, which is what the test exercises (the previous wording claimed a single call worked). Skipped: moving the title-template check ahead of the play-impact check. It is harmless: neither refusal can be forced past the other, and the order only changes which message a caller without Re-Review DecisionDecision: NO RE-REVIEW NEEDED Rationale: the only change since the approving narrow re-review is a test comment. The reviewer's verdict on the code was APPROVE with no re-review needed. |
…may change and what it breaks (closes #3742) - Opens on a description built from the stored definition: built in or the user's own, what it extends, each field with type, values, required, default and the type that declares it - Understanding and Changing a Type skill (procedure lane), pinned by the chat - A schema read lists the saved queries, plays and title templates that name each field, with what was searched - update_schema refuses a rename or removal that something names, with the list, until repeated with force - The type's page offers Ask beside its view controls Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… its own parameter, and describe a prefixed field as the user's - A user's prefixed field on a built-in type is no longer described as built in - update_schema's rename/removal guard skips a built-in field (the schema write refuses it whatever is agreed) and logs when it cannot look a field up - The guard's agreement is its own 'confirmed' parameter, not the schema write's 'force' (which waives the play-impact check and stays out of the tool's parameters) - The refusal's list is capped, with the rest counted - searched says what the play match does not cover; stale nodeType comment corrected Skipped: moving the check into core (wider than this change; CLI callers get no warning today), the scan-cost rewrite (premature), the skill's 'a template blocks removal' wording (core's own test asserts it), loosening the live rename test (it is deterministic: 3/3). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e anything is written - update_schema refuses renaming a field the stored title template names, with the order that works (template without it, rename, template with the new name); core could not do it in one call and rekeyed before failing - The describer uses core's namespace-prefix check instead of a copy - The type skill says a template-named field is renamed in that order Skipped: encoding that core does not yet refuse a built-in type's User-protected fields (core's gap to close, ADR-086 states the type is closed). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Skipped: moving the title-template check ahead of the play-impact check (harmless, neither is forceable past the other). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
e99a51f to
d5527f9
Compare
Implements ADR-100 §3 to §5 for schemas.
What changes
schema::description::describe_schema): the chat opens on the type's purpose, whether it is built in (closed) or the user's own (open), what it extends, then each field with type, allowed values, required, default and the type that declares it. Built from stored data, no model call.schema::field_references): saved queries (filters, sorting, board grouping), plays that trigger on the type (trigger, conditions, actions) and title templates. A schemaget_nodecarries it asfield_references, with what was searched.update_schemarefuses a rename or removal that something names, with the list in its first sentence, until it is repeated withforce. This holds whichever skill led the turn.Verification
bun run test:changedpasses (frontend, scripts, browser, types:check, node-types:check, Rust workspace); clippy clean on core, agent and daemon.live_type_chat_options, ignored by default):field_referencesand the type are in what the model was sent.Known gap
A bare one-shot "Rename state to status" (free text, not a picked option) is not led by the pinned skill (ADR-090 §5 leaves a free-text request to retrieval). On the locked model the first reply does not read the type and says nothing names the field. Nothing is written, and the refusal above names the saved query as soon as the user agrees. A fix that reached the first reply would be a change to how a pinned chat leads a free-text turn, which touches play and view chats too, so it is not made here.
Notes
find_field_referencesto the extends-chain-blindness allowlist: it reads own fields on purpose, since only a type's own fields can be renamed or removed there.components/seeded-nodes.mdupdated (pushed to nodespace-docs).🤖 Generated with Claude Code