fix(polling_source): exclude _content_hash from _combine column config (ITL-616) - #259
Conversation
…sh leak (ITL-616)
…g (ITL-616) _combine passed all_info=True to as_table(), which triggered content_hash=True and injected the synthetic _content_hash column into the concatenated table. ArrowTableStream.__init__ stored it as a data column, corrupting the schema on the second combine and raising SchemaInconsistencyError on the third fetch. Add _STREAM_COMBINE_COLUMNS = ColumnConfig(system_tags=True, source=True, context=True) and use it in place of all_info=True. content_hash is excluded because it is a synthetic, on-demand output — not a stored column.
…order (ITL-616) Switch test_async_three_fetches_no_content_hash_leak to call src.keys() and src.output_schema() instead of accessing the private _accumulated_stream attribute. Also reorder PS3 metadata block in DESIGN_ISSUES.md to match the file-wide convention (Status, Severity, Issue then Fix at end of body). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Fixes a schema-corruption bug in PollingSource._combine where calling as_table(all_info=True) caused ArrowTableStream.as_table() to synthesize _content_hash, which then got persisted into the accumulated stream’s stored data schema during pa.concat_tables.
Changes:
- Introduce a dedicated
_STREAM_COMBINE_COLUMNS(ColumnConfig(system_tags=True, source=True, context=True)) and use it in_combineto avoid persisting the synthetic_content_hashcolumn. - Add sync + async regression tests covering the “third fetch / second combine” failure mode and asserting
_content_hashdoes not leak into data keys/schema. - Document the issue and resolution in
DESIGN_ISSUES.md(PS3) and add supporting plan/spec artifacts undersuperpowers/.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/orcapod/core/sources/polling_source.py |
Fix _combine to concatenate tables without requesting content_hash (prevents _content_hash from becoming a stored data column). |
tests/test_channels/test_polling_source.py |
Add regression coverage for repeated combines (sync + async) ensuring schema stability and no _content_hash leakage. |
DESIGN_ISSUES.md |
Add PS3 entry documenting the root cause and fix; mark as resolved. |
superpowers/specs/2026-08-25-itl-616-polling-source-combine-content-hash-fix.md |
Spec write-up of the bug mechanism and the chosen fix. |
superpowers/plans/2026-08-25-itl-616-polling-source-combine-content-hash-fix.md |
Implementation plan/checklist for the fix and regression tests. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thanks for the review, @copilot-pull-request-reviewer! The Copilot review generated no inline comments — no code changes required. The PR is ready for human review. |
Summary
PollingSource._combinewas callingas_table(all_info=True)on both streams before concatenating them.all_info=Trueincludescontent_hash=True, which causesArrowTableStream.as_table()to dynamically append a synthetic_content_hashcolumn.pa.concat_tablesthen baked_content_hashinto the combined table passed toArrowTableStream.__init__, which stored it as a user data column — corrupting the data schema._validate_combining_schemasdetected_content_hashin the accumulated stream's keys but not in the new batch's keys, raisingSchemaInconsistencyError._STREAM_COMBINE_COLUMNS = ColumnConfig(system_tags=True, source=True, context=True)module-level constant and replacedas_table(all_info=True)withas_table(columns=_STREAM_COMBINE_COLUMNS)in_combine.content_hashis intentionally excluded — it is a synthetic output column, never a stored one.Test Plan
TestPollingSourceSchemaValidation:test_sync_three_fetches_no_content_hash_leak— 3 synciter_data()calls, asserts row accumulation and no_content_hashin data keys/schematest_async_three_fetches_no_content_hash_leak— 3-batch async drain, same assertions via publicsrc.keys()/src.output_schema()DESIGN_ISSUES.mdupdated with PS3 entry (status: resolved)Fixes ITL-616
🤖 Generated with Claude Code