fix(provenance): scope attachments to originating post + scroll-cap the list
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 18s
CI / backend-lint-and-test (push) Successful in 26s
CI / integration (push) Successful in 3m19s

The Attachments section aggregated PostAttachment rows across EVERY post an
image was pHash-linked to. When one of those was a 'High Resolution Files'
mega-bundle (dozens of unrelated archives), the list ballooned past the
viewport and overwhelmed the modal's right rail.

- for_image() now scopes attachments to ImageRecord.primary_post_id (the post
  the file was actually captured from), falling back to all linked posts only
  when primary_post_id is unset (older rows / filesystem imports).
- ProvenancePanel wraps the list in a max-height scroll container with a count
  in the heading, mirroring the cards' independent-scroll treatment.

Note: FC stores archives as opaque blobs and never records which archive an
extracted image came from, so attachments can't yet be scoped tighter than the
post. Capturing image->archive containment is tracked as separate work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 21:27:36 -04:00
parent 311fe0ee9c
commit 068def2f24
3 changed files with 99 additions and 9 deletions
@@ -70,14 +70,19 @@
</div>
<div v-if="attachments.length" class="fc-prov__attach">
<h4 class="fc-prov__attach-title">Attachments</h4>
<a
v-for="at in attachments" :key="at.id"
class="fc-prov__attach-row"
:href="at.download_url" :download="at.original_filename"
>⬇ {{ at.original_filename }}
<span class="fc-prov__attach-size">({{ at.size_bytes }} B)</span>
</a>
<h4 class="fc-prov__attach-title">Attachments ({{ attachments.length }})</h4>
<!-- Scroll-capped: a single post can carry dozens of archives (HR
bundle posts), which previously ballooned the panel past the
viewport. Mirror the cards' independent-scroll treatment. -->
<div class="fc-prov__attach-list">
<a
v-for="at in attachments" :key="at.id"
class="fc-prov__attach-row"
:href="at.download_url" :download="at.original_filename"
> {{ at.original_filename }}
<span class="fc-prov__attach-size">({{ at.size_bytes }} B)</span>
</a>
</div>
</div>
</section>
</template>
@@ -229,6 +234,15 @@ function openPost(postId, artistId) {
font-size: 13px; color: rgb(var(--v-theme-on-surface-variant));
margin: 8px 0 4px;
}
.fc-prov__attach-list {
/* ~7 rows visible before scrolling; the clipped row hints at more.
Hairline scrollbar matching .fc-prov__cards. */
max-height: 180px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: rgb(var(--v-theme-surface-light)) transparent;
padding-right: 4px;
}
.fc-prov__attach-row {
display: block; font-size: 13px; text-decoration: none;
color: rgb(var(--v-theme-accent)); padding: 2px 0;