Commit 14f9dca
fix(operations): refuse
Delta review of the previous three commits found the insert refusal guarding the
wrong condition. It keyed on `requires_no_existing` — the insert flag — so the
same silent partial write was still reachable one branch over:
`insertUpdateValidate` requires a primary key only for `update`, so
`{operation:'upsert', records:[{name:'Penny', color:'black', __unset__:['color']}]}`
took the `id == undefined → Table.create` path and stored an auto-keyed record with
`color` stripped, returning 200. An `upsert` naming a primary key that isn't stored
had the same shape.
Now keyed on `!existingRecord`, which is the actual invariant: no stored record
means nothing to remove from, so the directive can only be a misunderstanding. That
covers insert, upsert-without-a-key, and upsert-of-an-absent-key together. `update`
never reaches it — a missing record is already skipped upstream.
This is the fix-one-of-N-surfaces mistake: the condition was written from the
operation that exhibited the bug rather than from the property being protected.
Also from the review:
- Managed timestamps are refused off `Table.createdTimeProperty`/
`updatedTimeProperty` instead of the validator's static legacy list, so a
schema-declared `createdAt: Float @createdTime` is caught too. Those properties
resolve `assignCreatedTime` OR the legacy `__createdtime__` spelling
(resources/Table.ts:504-505), so one check covers both and there is no second
list to drift. The validator's list is removed rather than kept alongside it.
- The malformed-directive warning is latched and names the table, following
`warnedNullSourcePut` in resources/Table.ts — it sits on the write and
replication apply path, where one line per record buries the log under a single
bad batch.
- Comment density trimmed. Both reviews flagged it; the removed lines narrated
review history or addressed the reviewer rather than the next reader. Kept: why
the malformed case warns instead of throwing, why the refusals live in this layer,
and the falsy-vs-nullish reasoning.
Tests: 33 in the suite, all passing, and the new guards are mutation-checked —
reverting to the insert flag fails the two new upsert probes, and removing the
managed-timestamp loop fails both timestamp probes. 118 more across security,
terminology and auto-fields still pass.
One test correction worth noting: the first version of the upsert probe asserted
"no record with this name and null breed/color", which matched eight records other
probes had legitimately stripped attributes from. It now uses a name unique to the
probe.
Still open from the review, unfixed: `__unset__` remains a whole-record put under
contention (#2350), the directive refusals happen after dynamic attribute
expansion so a rejected write can still have registered new attributes on an open
table, and the bulk-load authorization fix has no test because the JSON bulk path
needs S3/URL input. The CSV entry point takes a different attribute list
(bulkLoad.ts:82, papaparse header fields) which this change does not touch, and
CSV cannot express the array anyway.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>__unset__ whenever there is no record to remove from1 parent a3bab5c commit 14f9dca
3 files changed
Lines changed: 135 additions & 44 deletions
File tree
- dataLayer/harperBridge
- integrationTests/database
- validation
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
| |||
280 | 282 | | |
281 | 283 | | |
282 | 284 | | |
283 | | - | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
284 | 291 | | |
285 | 292 | | |
286 | 293 | | |
287 | 294 | | |
288 | 295 | | |
289 | 296 | | |
290 | 297 | | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
291 | 307 | | |
292 | 308 | | |
293 | 309 | | |
| |||
808 | 824 | | |
809 | 825 | | |
810 | 826 | | |
811 | | - | |
812 | | - | |
813 | | - | |
814 | | - | |
815 | | - | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
816 | 832 | | |
817 | | - | |
818 | | - | |
819 | | - | |
820 | | - | |
821 | | - | |
| 833 | + | |
822 | 834 | | |
823 | 835 | | |
824 | | - | |
825 | | - | |
826 | | - | |
| 836 | + | |
| 837 | + | |
827 | 838 | | |
828 | | - | |
829 | | - | |
830 | | - | |
831 | | - | |
832 | | - | |
833 | | - | |
834 | | - | |
| 839 | + | |
835 | 840 | | |
836 | | - | |
| 841 | + | |
837 | 842 | | |
838 | 843 | | |
839 | | - | |
840 | | - | |
841 | | - | |
842 | | - | |
843 | | - | |
844 | | - | |
845 | | - | |
846 | | - | |
847 | 844 | | |
848 | | - | |
849 | | - | |
850 | | - | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
851 | 850 | | |
852 | | - | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
853 | 859 | | |
854 | 860 | | |
855 | 861 | | |
| 862 | + | |
856 | 863 | | |
857 | 864 | | |
858 | 865 | | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
859 | 875 | | |
860 | 876 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
530 | 530 | | |
531 | 531 | | |
532 | 532 | | |
533 | | - | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
534 | 539 | | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
535 | 549 | | |
536 | | - | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
537 | 558 | | |
538 | 559 | | |
539 | 560 | | |
540 | 561 | | |
541 | | - | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
542 | 581 | | |
543 | 582 | | |
544 | 583 | | |
| |||
639 | 678 | | |
640 | 679 | | |
641 | 680 | | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
642 | 717 | | |
643 | 718 | | |
644 | 719 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| |||
0 commit comments