Repository navigation
Keep a type listing whose links escape their ids, and route start-tracking requests to Schema Creation (closes #3268) - #3515
Conversation
Pragmatic Code Review: PR #3515 (issue #3268)Review Type: Initial review (no earlier reviews or comments on the PR). Reviewed at SummaryThe change is small, atomic to the three folded-in failures, and a net improvement. The normalizer is correct and cannot weaken the fabricated-id guard. No Critical findings. Two Important findings concern what the new retrieval guards accept or leave unguarded, and the issue's acceptance criteria are all "3/3 in a live run", which this PR does not yet show. What I ran: Requirements Check
None is unmet in code. The three folded-in criteria cannot be ticked, and the PR should not close the issue, until the live numbers are posted. Verified as correct
Findings🔴 CriticalNone. 🟡 Important1. The single-record guard accepts an add request that leads with Node Deletion. The test comment records that "add the cache invalidation decision to our architecture decisions" leads with Node Deletion, and asserts only that Bulk Import does not lead and Node Creation is in the top 3. But This is probably not caused by this PR (Node Deletion's description is unchanged), but I could not measure before and after, and the test now writes the state down as acceptable. Principle: ADR-038 gates the expensive error hardest; a guard should not record a destructive lead on a non-destructive request as passing. Suggested, in order of preference:
2. The Schema Creation change has no cost-side control. The Node Creation change ships with a control for what it could cost ( 🟢 Suggestions3. The regex can unescape text past the end of the id. The match runs to whitespace, 4. Two behaviours the change relies on are not pinned by a test.
5. The single-record guard measures one rep. It calls 6. Nit: "The measured reply". The test's reply uses developer-domain ids; the measured one was 7. Nit: the new Node Creation clause as a "added to the ones already listed" follows the description's own list (tasks, text notes, Spec, ADR, Ticket), so to the Stage-2 model the antecedent reads as that list, not the user's. The wording is tuned for the embedding and the comment says so; worth a glance at the Stage-2 trace in the live run. RecommendationCOMMENT. The code is sound and I would approve it on its own. Before merge: post the three live 3/3 results the issue's criteria require, and address or answer findings 1 and 2. Findings 3 to 7 are optional. 🤖 Generated with Claude Code |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review: COMMENT (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Review addressed (
|
Pragmatic Code Review: PR #3515 (issue #3268)Review Type: Re-Review. The first review was at Previous Review Summary
What I ran: Status of the earlier findings
Finding 1, in detail. The first review offered two ways out: fix it, or say in the comment that
That is enough for merge: the defect is not introduced here, the one fix suggested was tried and cost a real deletion request its lead, and the test no longer describes the state as fine. Two things I would still ask for, neither blocking:
The rewritten regex
One difference from the old pattern: it now matches every New findings🔴 CriticalNone. 🟡 ImportantNone. 🟢 SuggestionsA. The ordering test passes under either order. The name and comment say the unescape must run before the two steps that read the URI. Neither assertion depends on that. In The order only matters when the two sides differ. One changed input pins it: B. The new control accepts Schema Creation leading a request about an existing record, and says so only in the PR thread. The assertion is sound for what it claims: Node Creation and Graph Editing both whitelist It does not look at who leads. The author's response reports that "start tracking the offline sync spec's sign-off" leads with Schema Creation at 0.852, so that turn is recorded as routed to the type skill with C. Nit: two comments now disagree about what an id holds. The regex's doc comment says it matches "the characters an id can hold", and the class includes Tests added in this commit, against their names
No standards issues in the commit: no issue numbers in comments, no lint suppression, no compatibility code, no node-type or Pro-boundary surface touched. RecommendationCOMMENT. The commit resolves what the first review asked for, the regex is correct, and nothing in it blocks. I would approve the code as it stands. Before merge, unchanged from the first review: post the three live 3/3 results the issue's criteria require ( 🤖 Generated with Claude Code |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review): COMMENT (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Re-review addressed (
|
Pragmatic Code Review: PR #3515 (issue #3268)Review Type: Re-Review (second). The last review was at Previous Review Summary
What I ran: What I did not run: the ignored Status of the second review's suggestions
|
| Test | Asserts what it claims? |
|---|---|
unescapes_a_uri_id_before_the_steps_that_read_it (changed) |
Yes, now. Run here, passes. |
updates_to_one_record_do_not_lead_with_schema_creation (new) |
Yes for the three requests listed, on every rep. The name is general and one measured request is excluded (finding 1). Not run here. |
tracking_one_existing_record_still_reaches_a_record_skill (comment only) |
Unchanged in logic. Not run here. |
stage2_candidate_block_matches_golden |
Yes. Run here, passes. |
Recommendation
COMMENT. The narrowing is the right response to what the decision run showed, the three suggestions were taken as described, and the code, comment and golden agree. Nothing here blocks on the code.
Before merge, with the live three-rep results already owed: the before-ranking for "mark the offline sync spec as signed off" and that request in the live run (finding 1). Turning its "update_node is still offered" into an assertion is a one-line addition to an existing test. Findings 2 to 4 are optional. Still open from the first review: the Stage-2 trace read for the Node Creation clause.
🤖 Generated with Claude Code
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review 2): COMMENT (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Third review addressed, and one fix withdrawn (
|
| Request | main |
This branch |
|---|---|---|
| start tracking planning cycles | Graph Editing 0.828, Schema Creation fourth at 0.778 | Schema Creation 0.872 |
| update Northwind Trading booking to April | Graph Editing 0.793, Schema Creation 0.774 | Graph Editing 0.793, Schema Creation 0.787 |
| change the owner of the Q4 cycle to Priya | Graph Editing 0.794, Schema Creation 0.759 | Graph Editing 0.794, Schema Creation 0.766 |
| mark the offline sync spec as signed off | Graph Editing 0.790, Schema Creation 0.773 | Schema Creation 0.791, Graph Editing 0.790 |
Tests: nodespace-agent 1005 passed, test:scripts 1340 passed, live retrieval suite 23/23. The targeted live runs on this commit are in progress and will be posted with the PR description update.
Re-Review Decision
Decision: RE-REVIEW NEEDED
Rationale: a production description was reverted, a new expectation shape and scoring branch were added to the decision fixture, and two live guards changed their assertions.
Pragmatic Code Review: PR #3515 (issue #3268)Review Type: Re-Review (third). The last review was at Previous Review Summary
What I ran, from the worktree:
What I did not run: the ignored The revert
The new expectation:
|
| # | Finding | Status |
|---|---|---|
| 1 | The request left out of the update guard is a lead this PR moves, and the comment did not say so | Addressed, two of three parts. The comment now gives the before-measurement (Graph Editing 0.790 to 0.773 without the opening) and calls it a cost recorded and not accepted (live_skill_retrieval_stability.rs:1246-1253). The request is in completion_state_updates_route_graph_editing (:487). The live three-rep run of it is deferred: the fixture's workspace holds no spec record. That is a fair reason, and it leaves the Stage-2 behaviour on that request unmeasured. |
| 2 | The update guard checked only who does not lead | Addressed. holds now requires Schema Creation not first and Graph Editing or Node Creation in the list, on every rep (:1274-1282). An empty ranking now counts as a miss, which is right for the second half. Both named skills hold update_node (skill_pipeline.rs:173, :275). |
| 3 | "the same margins" | Addressed in both files ("margins no larger", "margins as large"). |
| 4 | Two leftovers | Addressed. "tracking verb" at :1194; the spliced paragraph went with the removed test. |
Does the added request assert what the other comment says? The comment at :1251-1253 says the completion-state test "asserts Graph Editing still reaches Stage 2 on it, so update_node is offered". The test calls routing_misses(.., "Graph Editing", false), which requires Graph Editing among the RETRIEVAL_TOP_K names on every rep (:445-453). That is presence in the top 3, which is what the file means by reaching Stage 2 throughout, and stage2_permitted_names offers the union of the eligible candidates' tools. So yes, with the usual limit of these guards: they check rank, not the score bar, and at 0.790 the bar is not in question.
Tests in this commit, against their names
| Test | Asserts what it claims? |
|---|---|
a must-not-lead skill expectation fails only on the named skill (new) |
Yes for the four cases: two near-tied leaders pass, Schema Creation fails, a null leader fails. It scores the real scenario, so it also pins that skill-instance-request carries this expectation. Run here, passes. See nit 5 on the name. |
completion_state_updates_route_graph_editing (one request added) |
Yes, top 3 on every rep. Not run here. |
updates_to_one_record_do_not_lead_with_schema_creation (changed) |
Yes, both halves, and the failure message names both. Not run here. |
stage2_candidate_block_matches_golden |
Yes. Run here, passes. |
Standards
No issue numbers in code comments in the four touched source files. No lint suppression, no any, no compatibility code, no leftover diagnostics (the eprintln! calls are the file's existing pattern). Nothing touches node types or the Pro boundary. The change is atomic: one revert and the fixture change that replaces it, plus the review items.
Recommendation
COMMENT. The revert is clean and complete, the new expectation is typed and scored correctly, and the third review's findings are addressed as claimed. Nothing blocks on correctness of the code as written.
Before merge: finding 1. The scenario's recorded reason is "the record is created whichever skill leads", the scenario does not check that, the guard that did was removed here, and the margin it depends on is 0.003 against a skill whose score this PR raises. One added condition on the scenario, or two requests in an existing-shaped guard, closes it. With the live runs already owed, report whether create_node ran on each rep of skill-instance-request and which build the 0.734 is from. Findings 2 to 5 are optional; 4 should be done before the squash.
🤖 Generated with Claude Code
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review 3): COMMENT (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Fourth review addressed (
|
Pragmatic Code Review: PR #3515 (issue #3268)Review Type: Re-Review (fifth pass). The last review was at Nothing here blocks the merge. One finding (1) is a comment and description that understate a cost; I recommend one sentence before the squash. The rest is optional. Previous Review Summary
What I ran, from the worktree:
What I did not run: the ignored Fourth review's findings, against the code
Finding 1 of the fourth review, in detail📁
The new live guard📁
Findings🔴 CriticalNone. 🟡 Important1. The two recorded costs are described as "the tool is still offered". The lead does more than that in the code. The seed comment says "The tool each needs is still offered", the guard says "Node Creation is in the top 3, so
So the cost is: the tool is offered, in its undeclared form, with the type skill first in the candidate block. Neither request was run through Stage 2 (the fixture holds no spec record), so the effect on what the model does is unmeasured, and the comments do not say that either. This does not block. The margins on both sides are inside what the PR itself calls chance, the tool surface is the same set as on 🟢 Suggestions2. The scenario and guard comments give the distance to "the next skill down" from The scenario says "the next skill down is 0.003 to 0.005 behind" Node Creation; the guard says "the skill behind them takes its place, and 3.
4. Nit: the description's live table predates the Scores, checked against each other
The live suite count in the description (24/24) matches the 24 tests in the file. Title and description against the diff
StandardsNo issue numbers in code comments in the touched files. No lint suppression, no RecommendationCOMMENT. No blocker remains. The fourth review's five findings are closed, the new expectation is typed and scored correctly, its patterns match the whitelists, and the new guard asserts what it claims. Recommended before the squash, one sentence each in the seed comment and the description: finding 1, that losing the lead also drops the record tool's declared fields and that Stage 2 was not measured on the two spec requests. Findings 2 to 4 are optional. 🤖 Generated with Claude Code |
malibio
left a comment
There was a problem hiding this comment.
Automated pragmatic-code-review (re-review 4): COMMENT (posted as a comment — GitHub blocks self-approval). Full findings in the review comment above.
Fifth review addressed (
|
…cking requests to Schema Creation (closes #3268)
b173ccd to
4d4b49f
Compare
Closes #3268.
Three scenario failures were left on
mainafter #3504. Each reproduced at 0/3 onb1d0e287(gemma-4-e4b-q4km, database purged and daemon restarted between reps) before anything was changed.What ships
Two production changes and one scenario expectation.
1. A type listing whose links escape their ids is kept (
outcome-list-types). "What schemas do we have here?" ransearch_nodes, and the model wrote a correct listing, but escaped the underscores of a type id inside its link:[Company Sold To](nodespace://company\_sold\_to). The escaped form matched no id a tool returned, so the fabricated-id guard replaced the whole reply with the request to confirm. Reply normalization now unescapes\_and\-inside anodespace://URI before the guards read it (response_processing::unescape_uri_ids). The reply stands, and the existing type-listing backstop appends the types it left out. The guard is not weakened: the unescaped id is still compared by exact match against tool-result ids.2. Schema Creation's description opens with "Start tracking:" (
indirect-schema-freelance). "start tracking our planning cycles" reached retrieval as "start tracking planning cycles", which ranked Graph Editing 0.828, Relationship Management 0.800, Node Creation 0.786, Schema Creation 0.778.create_schemawas not offered and the turn retriedcreate_nodeuntil it gave up. The description said "keep track of" and never "start tracking". With the two-word opening it leads at 0.872.3.
skill-instance-requestasserts what it is for. "Add Contoso Ltd to the companies we sell to." scores Bulk Import 0.742, Organization 0.741, Node Creation 0.737: which of them leads is chance, and the turn creates the record either way. The scenario named the skills that should lead and failed on that chance. It now asserts that Schema Creation does not lead and that a skill holdingcreate_nodeis among the candidates, through a new{ decision: "skill"; not; reaches }expectation. The issue's criterion allows this with the reason recorded, and it is recorded on the scenario.What was tried and withdrawn
exclusionon Node Deletion, suggested in review for an add request it leads. It did nothing for that request and cost a real deletion request its lead. Reverted.Known costs of the opening
Both are on requests naming a spec, which Schema Creation's description lists. Both are recorded in the guards and in the seed's comment as costs not accepted. In both the needed tool is still offered, but without its declared fields:
routing::declare_write_tool_fieldsdeclares them only from the candidates at the turn's top score, which is now Schema Creation. Neither request was run through the model (the decision fixture holds no spec record), so the effect on what Stage 2 does is unmeasured.mainLive measurement
gemma-4-e4b-q4km, three reps, database purged and daemon restarted between reps.
On the final production code (
4b58d77a), targeted run:outcome-list-typesskill-instance-requestcreate_noderan and landed in every rep; scored before the expectation gained itsreacheshalf, which the recorded candidates also satisfy)op-read-then-writemain)skill-type-request-indirectindirect-schema-freelanceinstance-not-schema-invoiceFull runs, on the earlier wording (the wide opening and the Node Creation clause, both since withdrawn):
eval:routing: 19/19 scenarios passed all three reps.eval:decisions: 22/24 passed all three reps. The two that flipped (op-read-then-write,outcome-follow-up-statement-keeps-its-answer) each failed one rep onDecode Error -3, an inference-engine failure in which the turn never reached the model.The full fixtures were not re-run on the final wording. The targeted set covers the scenarios the two wording changes could reach.
Two observations from the traces, not addressed here:
op-read-then-writepasses while itsupdate_nodecall errors (it grades the tool chosen, not the write), andindirect-schema-freelancepasses while making three to five schema calls for one request.Tests
response_processing: unit tests for the unescape (ids in links and bare, escapes in prose and after the id left alone, ordering before the steps that read the URI).agent_loop: a listing with escaped ids is kept and completed; an escaped link to an unknown type name keeps its label.decisions.test.ts: the new expectation fails on the named skill leading, on no leader, and on no candidate that can create the record.live_skill_retrieval_stability(ignored, needs the embedding model), 24/24:start_tracking_requests_route_schema_creation, and three cost-side controls for the opening:tracking_one_existing_record_still_reaches_a_record_skill,updates_to_one_record_do_not_lead_with_schema_creation,adds_to_an_existing_list_keep_a_skill_that_can_create.completion_state_updates_route_graph_editinggains one request, and theagent_looptype-listing test helper takes its listing as a parameter.nodespace-agent1005 passed;test:scripts1340 passed.🤖 Generated with Claude Code