PR #926 이 본문에서 "이 PR 범위 밖" 으로 명시해 이월한 항목. 리뷰에서 근거를 확인해 이슈로 남긴다.
문제
app/models/concerns/posts/federation_ingest.rb 의 로컬 /articles/N 분기에 존재 확인이 없다:
if local && (article_id = in_reply_to[%r{/articles/(\d+)}, 1])
{ article_id: article_id.to_i } # 존재 확인 없음
PR #926 이 바로 아래 /posts/N 분기에는 Post.find_by(id:) 가드를 붙였으므로, 구조가 같은 두 분기가 비대칭이다.
FK 위반 경로 (코드로 확인)
add_foreign_key "posts", "articles" — db/migrate/20260330052834_init_schema.rb:268 존재 (on_delete 없음 = NO ACTION)
belongs_to :article, optional: true — app/models/post.rb:35. parent_id 의 validate_parent_post 같은 대응 검증이 없다
즉 검증 계층이 잡아주지 못하고 곧장 DB 로 간다.
재현:
inReplyTo = "https://ruby-news.dev/articles/999999999"
handle_federated_object? — 로컬 호스트 + /articles/ 포함 → true
reply_target_attributes → { article_id: 999999999 }
find_or_create! → save! → PG::ForeignKeyViolation → ActiveRecord::InvalidForeignKey
- shared inbox 컨트롤러 밖으로 raise → 500 → 발신 서버(Mastodon)가 수일간 백오프 재시도
삭제된(discarded) 기사도 같은 문제다.
제안
/posts/ 분기와 대칭으로 맞춘다. Article.exists? 는 Post.find_by 와 달리 객체를 만들지 않아 비용도 더 낮다.
if local && (article_id = in_reply_to[%r{/articles/(\d+)}, 1]) && Article.exists?(id: article_id)
{ article_id: article_id.to_i }
Article 이 discard 소프트삭제를 쓰므로 discarded 레코드를 참으로 볼지 결정이 필요하다 — FK 관점에서는 참이 맞다(행이 남아 있으므로).
테스트도 대칭으로: federation_ingest_test.rb 의 "local /posts/ URL for a missing post yields no parent_id" 에 대응하는 /articles/ 케이스가 없다.
#936 과의 관계: #936 처럼 handle_federated_object? 단에서 존재를 확인하도록 바꾸면 이 FK 경로도 함께 닫힌다. 두 이슈를 같이 처리하는 편이 나을 수 있다.
관련: #871, #926, #936
PR #926 이 본문에서 "이 PR 범위 밖" 으로 명시해 이월한 항목. 리뷰에서 근거를 확인해 이슈로 남긴다.
문제
app/models/concerns/posts/federation_ingest.rb의 로컬/articles/N분기에 존재 확인이 없다:PR #926 이 바로 아래
/posts/N분기에는Post.find_by(id:)가드를 붙였으므로, 구조가 같은 두 분기가 비대칭이다.FK 위반 경로 (코드로 확인)
add_foreign_key "posts", "articles"—db/migrate/20260330052834_init_schema.rb:268존재 (on_delete없음 = NO ACTION)belongs_to :article, optional: true—app/models/post.rb:35.parent_id의validate_parent_post같은 대응 검증이 없다즉 검증 계층이 잡아주지 못하고 곧장 DB 로 간다.
재현:
handle_federated_object?— 로컬 호스트 +/articles/포함 →truereply_target_attributes→{ article_id: 999999999 }find_or_create!→save!→PG::ForeignKeyViolation→ActiveRecord::InvalidForeignKey삭제된(discarded) 기사도 같은 문제다.
제안
/posts/분기와 대칭으로 맞춘다.Article.exists?는Post.find_by와 달리 객체를 만들지 않아 비용도 더 낮다.Article이 discard 소프트삭제를 쓰므로 discarded 레코드를 참으로 볼지 결정이 필요하다 — FK 관점에서는 참이 맞다(행이 남아 있으므로).테스트도 대칭으로:
federation_ingest_test.rb의"local /posts/ URL for a missing post yields no parent_id"에 대응하는/articles/케이스가 없다.#936 과의 관계: #936 처럼
handle_federated_object?단에서 존재를 확인하도록 바꾸면 이 FK 경로도 함께 닫힌다. 두 이슈를 같이 처리하는 편이 나을 수 있다.관련: #871, #926, #936