fix: store all DB hash columns as large_binary (ITL-539)#241
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-539) Switch _function_signature_hash and _function_content_hash from to_string() (str) to to_prefixed_digest() (bytes) in PythonDataFunction, and update get_function_variation_data_schema() to declare those fields as bytes. Add TestVariationHashSchema covering the new behaviour and update the now-stale test_all_values_are_strings assertion.
…tation (ITL-539) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…539) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ENT_HASH_COL (ITL-539)
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR completes the ITL-539 cleanup to ensure all pipeline/result DB hash-related columns are stored as Arrow large_binary by switching remaining producers to emit prefixed digests as bytes, removing now-dead string→bytes tolerance code, adding regression tests, and documenting the remaining migration gap for OperatorJobNode.
Changes:
- Emit variation/content hashes as
bytes(to_prefixed_digest()) so Arrow tables store them aslarge_binary(notlarge_string). - Remove the
ResultCachevariation-hash conversion shim and add tests asserting binary column types + round-tripping viaContentHash.from_prefixed_digest. - Update
OperatorJobNodeand side-effect invocation logging to store/compare hash columns aslarge_binary, and document the lack of an operator-node migration utility.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/orcapod/core/data_function.py |
Switch variation hash fields + schema to bytes so they become large_binary in Arrow. |
src/orcapod/core/result_cache.py |
Remove v0 tolerance shim; adjust lookup API typing (hash constraints now naturally bytes at the source). |
src/orcapod/core/nodes/operator_node.py |
Store NODE_CONTENT_HASH_COL as large_binary and compare using binary digests. |
src/orcapod/side_effects.py |
Store record_id_hash as large_binary; update _write_invocation_row signature accordingly. |
tests/test_core/data_function/test_data_function.py |
Update tests for bytes-based variation hash schema + round-trip decoding. |
tests/test_core/test_result_cache.py |
Add assertions that variation hash columns are large_binary in stored records. |
tests/test_core/operators/test_operator_node.py |
Add coverage for binary NODE_CONTENT_HASH_COL storage and filtering. |
tests/test_core/side_effect_pod/test_side_effect_pod.py |
Add coverage that invocation log stores record_id_hash as large_binary and preserves bytes. |
DESIGN_ISSUES.md |
Document the OperatorJobNode migration gap for NODE_CONTENT_HASH_COL. |
superpowers/specs/2026-07-21-hash-columns-large-binary-design.md |
Add design/spec artifact describing remaining gaps + intended fixes/tests for ITL-539. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def lookup( | ||
| self, | ||
| input_data: DataProtocol, | ||
| additional_constraints: dict[str, str] | None = None, | ||
| additional_constraints: dict[str, bytes] | None = None, | ||
| ) -> DataProtocol | None: |
There was a problem hiding this comment.
Fixed. Changed to dict[str, Any] (and the local constraints dict inside the method body). The annotation was overly restrictive — callers legitimately pass string values for non-hash columns like function_name. Also added Any to the from typing import line. Matches the underlying ArrowDatabaseProtocol.get_records_with_column_value(column_values: Mapping[str, Any]) signature.
| own_hash = self.content_hash().to_prefixed_digest() | ||
| mask = pc.equal(table.column(col_name), own_hash) | ||
| return table.filter(mask) |
There was a problem hiding this comment.
Fixed. Added a type check for the column before calling pc.equal. If NODE_CONTENT_HASH_COL exists but is large_string (old schema), the method now raises ValueError with a message explaining the cause and pointing to DESIGN_ISSUES.md ON1 for the remediation steps (drop and recreate the affected tables), rather than letting PyArrow throw a cryptic type error.
…ditional_constraints to Any (ITL-539)
Review round 1 — addressed in 8c69184Two fixes in a single commit:
|
Summary
data_function.py: variation hash fields (function_signature_hash,function_content_hash) now stored asbytesviato_prefixed_digest(), schema changed fromstr→bytesso they emitlarge_binaryArrow columns.result_cache.py: removed_hash_val_to_binary()tolerance shim and the_HASH_VAR_COLSconversion loop (dead code now that the source produces bytes directly). Fixedlookup()type annotation fromdict[str, str]todict[str, bytes].operator_node.py:NODE_CONTENT_HASH_COLwritten aslarge_binaryusingto_prefixed_digest();_filter_by_content_hash()updated to compare against binary digest.side_effects.py:record_id_hashstored aslarge_binary;_write_invocation_rowparameter renamed fromrecord_id_hash_str: strtorecord_id_hash_bytes: bytes.DESIGN_ISSUES.md: documents the OperatorJobNode migration gap (no v0→v1 migration utility exists forNODE_CONTENT_HASH_COL).Breaking change: Existing pipeline DBs written by
OperatorJobNodewith the oldlarge_stringschema will fail on next write due to Arrow schema mismatch. Manual table recreation is required (seeDESIGN_ISSUES.mdON1). Accepted for pre-v0.1.0.Test plan
Fixes ITL-539
🤖 Generated with Claude Code