Skip to content

Add provider-neutral ticket attachment metadata service - #662

Draft
adriandemian wants to merge 2 commits into
mainfrom
ralphx/ralphx/agent-bed0bf4a
Draft

Add provider-neutral ticket attachment metadata service#662
adriandemian wants to merge 2 commits into
mainfrom
ralphx/ralphx/agent-bed0bf4a

Conversation

@adriandemian

@adriandemian adriandemian commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a provider-neutral backend service for listing ticket attachments from Jira, Linear, and ClickUp through the existing integration services.
  • Moves ticket identity normalization into a shared helper module so attachment lookup and ticketing operations use the same provider/key rules.
  • Returns bounded attachment metadata only, with redaction applied to provider-supplied text and URL-like content.

User Impact

  • Backend code can now enumerate attachments for supported ticket references as structured metadata.
  • Attachment records include provider, ticket identity, source, size, MIME type, author, timestamps where available, and a retrievable flag for later fetch work.
  • This change does not expose new MCP tools or a live attachment download/cache endpoint yet.

Technical Context

  • New ticket_attachment_service normalizes TicketingTicketIdentity, fetches provider content through the existing Jira, Linear, and ClickUp integration services, and maps attachments into TicketAttachmentList / TicketAttachmentMetadata DTOs.
  • The service distinguishes ticket-level and comment-level attachment sources, including recursive ClickUp comment replies.
  • Output is intentionally constrained with caps on attachment count and text length, and it redacts URL- and secret-shaped tokens before returning data.
  • ticketing_identity now owns provider constants and identity normalization helpers, and ticketing_service reuses those shared helpers instead of keeping the duplicate logic inline.
  • Tests cover Jira, Linear, and ClickUp attachment mapping, redaction, bounded output, unsupported provider handling, missing/disabled integration failures, and source tagging.

Risks / Follow-Ups

  • The sanitization rules are heuristic and may need adjustment if provider content introduces new secret or URL patterns.
  • The service only returns metadata; later download or cache work will need to preserve the same provider identity and redaction boundaries.
  • ClickUp attachment traversal currently follows comment replies recursively, so future changes to comment shapes or attachment locations may need additional coverage.
View full plan

Goal

User wording: "Implement phase 1 of the Ticket Attachment MCP Access automation as a scoped PR." The run should add a provider-neutral backend attachment domain/service layer for Jira, Linear, and ClickUp ticket references, with tests, while deliberately not exposing MCP tools or a live download/cache endpoint yet.

Interpretation: create backend-only Rust application/domain models and a service that accepts the existing normalized ticket identity shape, fetches the current provider ticket through existing integrations, returns bounded safe attachment metadata, and marks retrievability without returning provider URLs, download URLs, credentials, or trusted-content wording.

Assumptions:

  • The phase-1 caller is backend/internal test code only; external MCP/API/UI exposure is a later phase.
  • Retrieval can be represented as a safe boolean/status derived from provider metadata. This phase does not need to persist opaque locators or cache downloaded bytes.
  • Existing provider fetch methods remain the source of truth: Jira via Atlassian, Linear via Linear, ClickUp via ClickUp.

Evidence

  • src-tauri/src/application/ticketing_service.rs already owns provider-neutral ticket identity and routing for Jira, Linear, and ClickUp through TicketingTicketIdentity, provider constants, and normalize_ticket_identity.
  • src-tauri/src/application/atlassian_integration_service.rs exposes fetch_resource_content(...) and AtlassianJiraAttachment { id, filename, mime_type, size, author, content_url, thumbnail_url, created_at }.
  • src-tauri/src/application/linear_integration_service.rs exposes fetch_issue_content(...) and LinearAttachment { id, title, subtitle, url }.
  • src-tauri/src/application/clickup_integration_service.rs exposes fetch_task(...) and ClickUpAttachment { id, filename, mime_type, size, url }; ClickUp comments can also contain attachments.
  • src-tauri/src/commands/ticketing_commands/mod.rs already has provider detail routing in get_ticket_detail, but phase 1 should not add endpoint exposure there.
  • Existing prompt expansion code in Atlassian/Linear uses bounded content and untrusted-context language; the new service should return data, not prompt prose.

Affected Files

  • .artifacts/specs/ticket-attachment-mcp/tracker.md - create/update first in implementation mode with findings, decisions, validation, and PR handoff notes.
  • src-tauri/src/application/ticketing_identity.rs - add a small shared provider-neutral identity module if needed; move or centralize provider constants, external-kind mapping, and normalized ticket identity validation now private to ticketing_service.rs.
  • src-tauri/src/application/ticketing_service.rs - import shared identity helpers instead of owning a second normalization implementation; preserve existing public behavior and tests.
  • src-tauri/src/application/ticket_attachment_service.rs - add the new provider-neutral attachment service, safe output models, provider fetch routing, bounding, and redaction helpers.
  • src-tauri/src/application/ticket_attachment_service_tests.rs - add focused tests for Jira, Linear, ClickUp normalization, missing/disabled integrations, unsupported providers, bounded output, and URL/secret redaction.
  • src-tauri/src/application/mod.rs - wire/re-export the new service and any shared identity types needed by tests or future backend callers.
  • src-tauri/src/application/ticketing_service_tests.rs - update imports/assertions only if identity helpers move; keep behavior assertions intact.
  • Provider service test files only if necessary: atlassian_integration_service_tests.rs, linear_integration_service_tests.rs, clickup_integration_service_tests.rs for touched fetch behavior, but avoid expanding scope if the new service can use existing fakes.

Constraints

  • Read and obey CLAUDE.md, src-tauri/CLAUDE.md, code quality, CodeQL path safety, runtime-root, MCP tool alignment, Rust API stability, PR description, and Rust test execution rules before editing.
  • TDD-first for the new service: add failing focused tests before production implementation.
  • Keep domain/application clean: no infrastructure dependency in pure normalization/output models.
  • Treat all provider attachment fields as untrusted external context; output should be data-only and must not imply trusted content.
  • No database migration, no new persistence, no filesystem cache, no HTTP route, no Tauri command, no MCP server/tool registration, no prompt/frontmatter/config allowlist changes in this phase.
  • Use stable Rust APIs only. Do not use unstable std helpers.
  • Avoid broad formatting. If needed, run rustfmt --edition 2021 only on touched leaf Rust files, not mod.rs roots.
  • Preserve legacy ticketing and integration behavior; existing commands and prompt expansion should keep working.

Avoid

  • Do not add plugins/app/ralphx-mcp-server tools, schemas, handlers, allowlists, or rebuild requirements in phase 1.
  • Do not add download/cache endpoints or filesystem writes for provider attachments.
  • Do not expose content_url, thumbnail_url, Linear url, ClickUp url/downloadUrl, auth tokens, secret refs, or raw provider payloads in the returned agent-facing model.
  • Do not duplicate provider identity normalization in multiple production callsites if a small shared helper can centralize it.
  • Do not rely on conversation Jira/Linear cached attachments_json; fetch provider content through the existing integration services so output is current and provider-neutral.
  • Do not add migration-diary prompt prose or mention unavailable future tools in live agent surfaces.

Data / State

  • New safe output model should include bounded metadata only, for example: ticket identity summary, provider, attachment id if safe, display name/title, MIME type if available, size bytes if valid, optional author/created timestamp when bounded and redacted, source location such as ticket/comment, and retrievable or retrievalStatus.
  • Provider URLs should be consumed only to determine retrievability and then discarded from the public result.
  • No persistent state is introduced in phase 1. Later phases can re-fetch provider metadata by ticket identity plus attachment id/index before downloading.
  • No path sinks should be added. If tests need temp data, keep it pure/in-memory; CodeQL path safety still applies to tests.

Agent And MCP Surface

  • No new MCP tools are exposed in this PR.
  • No agent prompt, agents/*/agent.yaml, config/ralphx.yaml, plugins/app/ralphx-mcp-server/src/tools.ts, or MCP handler route changes are part of this phase.
  • The new service can be called by future backend MCP/HTTP layers, but this PR should leave those layers untouched.

UI / UX

  • No frontend UI changes in this phase.
  • No user-visible attachment download behavior changes.
  • PR description should state that this is backend groundwork only, with MCP access and download/cache behavior deferred.

Progression Scenarios

  1. Jira ticket reference resolves through Atlassian fetch_resource_content; service maps each Jira attachment to safe bounded metadata, redacts URLs, and marks retrievable when a provider content URL exists.
  2. Linear issue reference resolves through Linear fetch_issue_content; service maps Linear attachments from content.attachments, redacts url/URL-like fields, and marks retrievability based on safe provider metadata presence.
  3. ClickUp task reference resolves through ClickUp fetch_task; service maps task-level attachments and, if intentionally included, comment attachments with source metadata, while redacting all URLs.
  4. Unsupported provider, malformed/blank ticket identity, missing provider service, disabled integration, or provider fetch failure returns a typed/string error consistent with existing application service conventions and does not fail open with empty success.
  5. Hostile provider fields containing URLs, token-looking strings, markup, huge strings, or many attachments produce bounded redacted metadata and never include raw provider download/content URLs.

Decisions

  • Build beside existing ticketing services under src-tauri/src/application/, not in commands, HTTP handlers, plugins, or infrastructure.
  • Reuse or extract TicketingTicketIdentity normalization rather than inventing a second ticket-reference format.
  • Return a safe metadata DTO and retrievability flag/status only; do not return internal download locators in this phase.
  • Prefer pure tests with fake provider clients and memory settings/secret stores; no network, DB migration, or filesystem dependency is needed.
  • Use a scoped PR with reviewer-focused description: context, user impact, decisions, risks, validation, and explicit deferred phases.

Proof Obligations

  • New tests prove Jira, Linear, and ClickUp attachments normalize into one provider-neutral shape.
  • Tests prove provider URLs/download URLs/content URLs/thumbnails and token-looking values do not appear in serialized service output.
  • Tests prove output is bounded by attachment count and string lengths, including hostile long fields.
  • Tests prove unsupported provider and missing/disabled integrations fail closed with useful errors.
  • Existing ticketing service behavior remains intact after any shared identity extraction.
  • Repo scan/diff confirms no MCP, prompt, config allowlist, command, route, migration, or download/cache endpoint was added.
  • Final diff review confirms no unrelated formatting churn and no broad refactor beyond the shared identity seam if used.

Testing Strategy

  • Add tests first under the new service sidecar: cargo test --manifest-path src-tauri/Cargo.toml ticket_attachment_service --lib.
  • If shared ticket identity is extracted, run the existing ticketing service filter: cargo test --manifest-path src-tauri/Cargo.toml ticketing_service --lib.
  • If provider service fetch behavior is touched, run the relevant provider filter only: cargo test --manifest-path src-tauri/Cargo.toml atlassian_integration_service --lib, linear_integration_service --lib, or clickup_integration_service --lib.
  • Run python3 scripts/check-layering.py if the new module/export changes application/domain layering.
  • Before publishing, review git diff for every touched file, fetch/rebase onto latest origin/main, push the branch, and open the scoped PR with the required reviewer-focused description.

Generated by RalphX

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.58599% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...tauri/src/application/ticket_attachment_service.rs 93.84% 17 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant