Title: Diagram.trace: descend through master-part boundaries (Merge-table upstream tracing) · Issue #1481 · datajoint/datajoint-python · GitHub
Open Graph Title: Diagram.trace: descend through master-part boundaries (Merge-table upstream tracing) · Issue #1481 · datajoint/datajoint-python
X Title: Diagram.trace: descend through master-part boundaries (Merge-table upstream tracing) · Issue #1481 · datajoint/datajoint-python
Description: Summary Diagram.trace() (and therefore self.upstream) walks ancestor FK edges only. It does not descend from an ancestor Master into that Master's Parts. In the merge-table shape used by Spyglass — Parent → Master.Part → Master → Child —...
Open Graph Description: Summary Diagram.trace() (and therefore self.upstream) walks ancestor FK edges only. It does not descend from an ancestor Master into that Master's Parts. In the merge-table shape used by Spyglass —...
X Description: Summary Diagram.trace() (and therefore self.upstream) walks ancestor FK edges only. It does not descend from an ancestor Master into that Master's Parts. In the merge-table shape used by Spygla...
Opengraph URL: https://github.com/datajoint/datajoint-python/issues/1481
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Diagram.trace: descend through master-part boundaries (Merge-table upstream tracing)","articleBody":"## Summary\n\n`Diagram.trace()` (and therefore `self.upstream`) walks **ancestor FK edges only**. It does not descend from an ancestor Master into that Master's Parts. In the merge-table shape used by Spyglass —\n\n```\nParent → Master.Part → Master → Child\n```\n\n— `trace(Child \u0026 key)` reaches `Master`, but `trace[Master.Part]` and `trace[Parent]` raise `DataJointError`. The true upstream source (`Parent`) is unreachable through the merge point.\n\nThis matches the shipped spec (provenance.md §2, \"Allowed table set\": an ancestor's Part is included only when the Part itself lies on an FK path to the seed) and is now pinned by `test_trace_stops_at_master_no_part_down_collection`. However, the design comment on discussion #1232 described a symmetric down-collection (\"when a Master is reached, add its Parts to the trace, and continue upward from the Parts' FK parents\") that was **never implemented** — a correction has been posted there. This issue tracks actually building that capability.\n\n## Proposed behavior (opt-in or default — design question)\n\nWhen the upward walk reaches a Master, additionally:\n1. Restrict the Master's Parts downward from the Master's restriction (the existing forward rules).\n2. Continue **upward** from the Parts' other FK parents (the upward rules), OR-merging into the trace.\n3. Multi-pass until stable (mirror of the downstream `part_integrity=\"cascade\"` mechanics — this is its upward analog, cf. `_propagate_part_to_master`).\n\n## Design questions\n\n- Default-on (a Part is semantically an extension of its Master, so \"what contributed\" arguably includes contributions through Parts) vs. opt-in flag (`trace(expr, through_parts=True)`) to preserve current semantics.\n- OR-merge and termination through alias nodes; interaction with the (part, master)-pair dedup introduced for the downstream analog.\n- Effect on `self.upstream`'s allowed-table set under `strict_provenance` — the merge pattern is exactly where downstream `make()`s need to read through the merge point.\n\n## Motivation\n\n- Spyglass Merge tables (discussion #1232, @CBroz1): versioned pipelines route provenance through Master/Part merge points; upstream tracing that stops at the merge master cannot answer \"which Parent produced this result.\"\n- Without it, strict-provenance mode makes such reads *impossible* rather than merely unergonomic (the true parent is not in the allowed set).\n","author":{"url":"https://github.com/dimitri-yatsenko","@type":"Person","name":"dimitri-yatsenko"},"datePublished":"2026-07-04T20:40:04.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/1481/datajoint-python/issues/1481"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:24611965-b8f9-455a-1e3f-a12a20ff6720 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 9B78:9775E:1D781FF:285DA6C:6A4F28A0 |
| html-safe-nonce | 5f9ceb654595178c4c8766cc88ec56fd025c635f934950ec1fdc4948bfe66d11 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5Qjc4Ojk3NzVFOjFENzgxRkY6Mjg1REE2Qzo2QTRGMjhBMCIsInZpc2l0b3JfaWQiOiI5NTAyODkyNTcyMTczMzc1MDQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 64ccb4ecc6b338e3dd302664d29068bcf18d86b289e13e39a057bed264f73558 |
| hovercard-subject-tag | issue:4810479760 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/datajoint/datajoint-python/1481/issue_layout |
| twitter:image | https://opengraph.githubassets.com/1e879a8d91e559492ca3182750ed4f5eaa4ec5d90038d1499455ec5976ce6d95/datajoint/datajoint-python/issues/1481 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/1e879a8d91e559492ca3182750ed4f5eaa4ec5d90038d1499455ec5976ce6d95/datajoint/datajoint-python/issues/1481 |
| og:image:alt | Summary Diagram.trace() (and therefore self.upstream) walks ancestor FK edges only. It does not descend from an ancestor Master into that Master's Parts. In the merge-table shape used by Spyglass —... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | dimitri-yatsenko |
| hostname | github.com |
| expected-hostname | github.com |
| None | b92d11c0aa4a77d54ef4af1078b6a15fb5a70a215b30c4ecf28889d5a8e656d9 |
| turbo-cache-control | no-preview |
| go-import | github.com/datajoint/datajoint-python git https://github.com/datajoint/datajoint-python.git |
| octolytics-dimension-user_id | 2375501 |
| octolytics-dimension-user_login | datajoint |
| octolytics-dimension-repository_id | 5866704 |
| octolytics-dimension-repository_nwo | datajoint/datajoint-python |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 5866704 |
| octolytics-dimension-repository_network_root_nwo | datajoint/datajoint-python |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 2b8f23afb982271f1b22258a94aede67a6b77760 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width