Skip to content

fix(member-fields): reconcile rows that carry no referenceName - #160

Merged
2000game merged 2 commits into
mainfrom
fix/159-review-findings
Aug 28, 2026
Merged

fix(member-fields): reconcile rows that carry no referenceName#160
2000game merged 2 commits into
mainfrom
fix/159-review-findings

Conversation

@2000game

Copy link
Copy Markdown
Contributor

Review follow-up to #159 (7 findings from /code-review high).

High

  • A live row carrying no referenceName was matched by the documented name fallback and then rejected by every consumer (memberFieldReferenceName(row) !== spec.referenceName), so it could be neither updated nor created — the plan went INCOMPLETE and ct apply aborted the entire run. Only a row carrying a different reference name is a contradiction now (conflictingReferenceName), in the fold, in apply and in the resolver.
  • The identity-mismatch diagnostics offered only ct destroy --member-field …, which is destructive and, for a row without a reference name, did not even match: destroy resolved the live row by local key alone, reported "already absent", dropped the state binding and let the next apply POST a duplicate. destroy (and its backup fetch) now prefer the state-bound id, and every message names the non-destructive fix — declare the live referenceName — beside the destructive one.

Medium

  • Delete-candidate false positive: declared rows were tested against a set of declared reference names via ?? "", so a declared field whose live row has none was reported as "not declared — DELETE CANDIDATE". The pass now skips rows a declaration claimed.
  • A ref into a group that is adopted but declares no memberFields fell back to the raw ref string with exact matching, hard-throwing on live stand-bewerbung vs. ref.groupMemberField(g, "stand_bewerbung"). With no declaration there is no exact identity to hold the row to, so those refs keep the normalised local-key match.
  • A live field sharing only a declaration's display name (its own CT-minted referenceName) turned a create into a fold error and thereby aborted apply for every other resource. It now warns, names the referenceName to declare, and plans the create. A near-identity — a live reference name differing only in punctuation or case — is still refused.

Low

  • The duplicate-match error no longer claims "no row has the exact referenceName" when the matches are precisely the rows that do.
  • The resolver renders a missing reference name as missing and no longer asserts a state binding that may not exist.

Also: the actual side reports the declared reference name for a row that carries none — ct never PATCHes one, so diffing it would propose the same update forever.

Docs re-read and re-signed. npm test (1083 passing), tsc --noEmit, eslint src tests all clean; 9 regression tests added.

https://claude.ai/code/session_01PNmsG3pmvxQNA9sNmnAvYJ

Review follow-up to #159. Making `referenceName` the exact identity left the
documented name fallback unreachable and pointed several diagnostics at a
remedy that did not work.

- A live row with no `referenceName` was matched by name and then rejected by
  every consumer, so it could be neither updated nor created: the plan went
  INCOMPLETE and apply aborted the whole run. Only a row carrying a DIFFERENT
  reference name is a contradiction now (`conflictingReferenceName`).
- The actual side reports the declared reference name for such a row, since ct
  never PATCHes one onto it and diffing it would never converge.
- A declared field whose live row has no reference name is no longer reported
  as a DELETE CANDIDATE; the pass now skips rows a declaration claimed.
- Identity-mismatch messages offer the non-destructive fix (declare the live
  `referenceName`) beside `ct destroy`, and `ct destroy --member-field` resolves
  the STATE-BOUND row — it previously matched on the local key alone, reported
  "already absent", dropped the binding and let the next apply POST a duplicate.
- A live field that only shares a declaration's display name now warns and
  creates instead of failing the run; a near-identity (same string up to
  punctuation/case) is still refused.
- A ref into a group that is adopted but declares no `memberFields` states no
  exact identity, so it keeps matching on the normalised local key.
- The duplicate-match error no longer claims no row carries the exact reference
  name when the matches are the rows that do.

Claude-Session: https://claude.ai/code/session_01PNmsG3pmvxQNA9sNmnAvYJ
@2000game
2000game merged commit fd0b43e into main Aug 28, 2026
3 checks passed
@2000game
2000game deleted the fix/159-review-findings branch August 28, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant