Github 최종 결정 반영(2026-07-29) · 코드 반영 전

Social Fetcher URL Structure Audit — 2026-07-19
관련 코드: social-fetcher.router.ts(classifyGithub) · fetchers/github.fetcher.ts
관련 데이터: samples/github.json
소스 채택 권장도 narrow-adopt — 러그/사칭 스크리닝 전용, 모멘텀 소스 아님
github에는 '게시물'도 참여 속도(engagement velocity)도 없음. 밈 모멘텀이 실제로 사는 곳은 X/Telegram이고, github는 애초에 그 모멘텀을 관측할 수 있는 구조가 아님(REST API가 star/follower/pushedAt만 줌 — 전부 밈 트레이더 관점에선 게이머블하거나 무관). 반면 createdAt(계정/repo 신선도)·owner/login(핸들 대조)·pushedAt(방치 여부) 3개는 '이 팀이 진짜인가, 급조된 스캐폴드/사칭인가'를 가르는 이진 tell로 쓸 수 있어, social-field-loss-filter 실험에서 github 존재 자체가 loser 22% vs winner 8%로 갈린 관측과도 방향이 맞음. stars/forks/followers/publicRepos는 부풀리기 쉬워 신뢰 안 함.
트레이더 관점: 차트 열어놓고 초 단위로 매수/매도 결정할 때 github을 열어볼 시간도 이유도 없다. 다만 진입 전 30초 여유가 있으면 계정 생성일이랑 owner 핸들만 훑는다 — 어제 만든 계정에 방금 커밋 하나 올려놓고 '우리 팀 코드입니다' 하면 그건 스타 개수보다 훨씬 정직한 러그 신호다. star/follower 숫자는 무시한다, 다 살 수 있는 거 안다.
✅ 최종 결정 (수기 audit 반영)
원칙: sourceKey는 unique & immutable & linkable. audit 질문("handle, owner, login 이거 다 같은건가? 변경 비용 크거나 불가한가?")에 대한 답: 셋 다 같은 것(API 실체는 login 하나, owner는 repo의 login, handle은 통칭) 이고 변경 가능하다. 더구나 옛 username을 타인이 선점할 수 있고, GitHub이 주는 리다이렉트도 새 주인이 같은 이름의 repo를 만들면 덮어써져 깨진다. → handle 계열은 키 부적격, 숫자 id로 통일. audit의 "profile 제거대상: id"는 handle 안정성을 모르는 상태의 판단이라 뒤집는다.
조인 키
객체비고
Creator (user/org 프로필)id (숫자 계정 ID)무료 GitHub API 실측: GET /users/{login}id: 48523873. login은 alias(router sourceKey)로 병행 기록하되 조인·dedup 금지 — 변경+재할당 시 다른 계정을 가리킬 수 있음.
Content (repo)id (repo 숫자 ID) + owner.id (creator 링크)실측: GET /repos/{owner}/{repo}id: 1166408297, owner.id: 48523873. repo 응답이 owner.id를 추가 쿼리 없이 제공 → audit이 짚은 "repo에 owner가 있으니 매핑가능" 구조가 login이 아니라 숫자 id 수준에서 성립. repo name도 rename 가능하므로 full_name은 표시/alias.
sourceType 통합 맵
최종 타입포함 패턴
github_repo (신규 분리)audit 지시("github.com/{owner}/{repo} ← 여기서 repo가 end니 github_repo처럼"): /{owner}/{repo} 및 하위경로(/tree/..., /blob/..., /pull/...) — router sourceKey는 owner/repo(alias), canonical 조인키는 repo id
github_owner (신규 분리)audit 지시("github.com/{login}, {login}.github.io ← github_owner?"): /{login}, {login}.github.io — sourceKey는 login(alias), canonical은 user id. Pages의 path(sub-project)를 버리는 현행은 의도적 설계로 문서화
gist (gap — 기존 제안 유지)gist.github.com/{login}/{gistId} — classify()의 host 매칭에 gist.github.com 추가 후 gist 전용 분기. 현재는 website로 새고 있음. ⚠ 실측 확인: username 변경 시 gist URL은 리다이렉트 없이 404
예약경로 방어 (gap — 기존 제안 유지)/sponsors/{login}, /orgs/{org}/..., /apps/{name} 등이 owner/repo로 오인됨 → GITHUB_RESERVED_ROOTS Set 신설 후 classifyGithub 진입부에서 배제
구조 결정 — 필드 단위 key/keep/remove로 표현할 수 없는 결정
항목내용
handle 명칭 통일 — login 하나로audit: "handle, owner, login 여러 종류로 불리는데 다 동일하다면 이걸 하나의 명칭으로 관리". API 실측상 실체는 login 하나이고, repo 응답의 owner.login·full_name(= {login}/{repo})도 같은 값이다. → 코드·문서·스키마 전반에서 login으로 명칭 통일, handle/owner는 별칭 표기로만 사용. 단 저장 키는 login이 아니라 숫자 id(위 조인 키 참조).
README는 별도 엔드포인트 1회 호출이 필요audit: "README 는 있으면 어떤건지 파악하기 좋을 듯". 실측: GET /repos/{owner}/{repo}/readme200(무료). 조달 가능하므로 decision=keep으로 승격. ⚠ 다만 repo API 1콜에 딸려오지 않고 별도 호출 1회가 추가로 필요하다(무료지만 rate limit 소모). 본문이 길어 저장 정책(전문 vs 앞부분 N자 vs 해시)은 코드 반영 단계에서 별도 결정.
archived — audit 제거 지시를 뒤집어 keepaudit "제거대상: license / archived". 그러나 완료 rubric 11a(actionable인데 제외된 필드)가 이 충돌을 적발. 문서 판정은 archived=true = 팀이 스스로 프로젝트 종료를 선언한 강한 러그 tell로 actionable. license(밈코인 repo 대부분 무관·부재)와 한 줄에 묶여 함께 제거된 것으로 보이나 성격이 다르고, 불리언 1개라 저장비용이 사실상 0 → keep으로 확정(사용자 확인). license는 audit대로 remove 유지.
이 문서에서 쓰는 pill 범례
관측 source-data에서 실제 발견됨 웹리서치/실측 검색·curl·실제 호출로 확인 정상/유지 차단·버그·갭·drop 신규/분리 타입 fixed / mutable confidence: high medium low
목차   1a. 개념 글로서리 · 1b. URL 패턴 · 2. sourceType/sourceKey 판정 · 3. Fetch 테스트 + 획득 방법 · 4. 필드 통합 (변동성·파싱·판정) · 다음 액션

1a. 플랫폼 개념 글로서리

이 플랫폼을 이해하는 데 필요한 도메인 개념. URL/필드 설명에서 참조.

개념설명
repo URL (owner/repo)github.com/{owner}/{repo} 형태의 저장소 프로필 URL. 표본에서 가장 흔한 템플릿(74/151)으로, owner/repo 조합을 식별자로 사용. 관측
user profile URLgithub.com/{username} 형태의 개인/조직 프로필 URL. 두 번째로 흔한 템플릿(68/151). 관측
GitHub Pages URL{username}.github.io 또는 {username}.github.io/{repo} 형태의 정적 사이트 URL. github.com이 아닌 서브도메인 패턴이지만 sourceType은 여전히 github로 분류되며, 종종 user 데이터로 fetch됨(예: selforg-npa.github.io, dhekatz.github.io/DhEKaTz-). 관측
deep link 하위경로 (tree/blob/pull)repo URL 뒤에 /tree/{branch}/{path}, /blob/{branch}/{file}, /pull/{number} 등이 붙는 형태. 특정 브랜치의 디렉터리(tree), 특정 파일(blob), PR(pull)을 가리키며, 이 표본에서도 sourceKey 정규화는 owner/repo까지만 축약하고 하위경로는 버려짐. 관측
sourceKey 정규화(대소문자)관측 데이터상 sourceKey는 owner/repo 또는 username을 모두 소문자로 정규화(예: RentAHuman → rentahuman, JayChauhan2/NaviSimulation → jaychauhan2/navisimulation). 반면 fetched.data.login/owner는 GitHub API가 반환하는 원래 대소문자(예: RentAHuman, JayChauhan2)를 보존. 관측
login/username 대소문자 비민감성GitHub는 계정명(login)을 URL 및 API 조회 시 대소문자 구분 없이 처리하지만(case-insensitive), 실제 표시/저장되는 login 값은 가입 시 지정한 원래 대소문자를 유지한다. 즉 URL의 대소문자와 무관하게 동일 계정으로 매칭된다. 웹리서치/실측
repo 이름의 owner-scoped 유일성저장소 이름은 전역 유일이 아니라 owner(사용자 또는 조직) 범위 내에서만 유일하다. 동일 이름의 저장소가 서로 다른 owner 하에 존재할 수 있어, 식별자는 반드시 owner/repo 쌍으로 취급해야 한다. 웹리서치/실측
kind: repo vs user이 감사 파이프라인이 fetch 시 구분하는 두 개체 종류. repo는 owner/repo URL에서, user는 단일 username URL(및 GitHub Pages)에서 얻어지며 반환 필드 스키마가 다르다(repo: createdAt/pushedAt/stars/forks/owner, user: createdAt/publicRepos/followers/login). 관측
stars(지표)저장소에 대한 즐겨찾기/추천 지표(GitHub star). repo 데이터에서 mutable 값으로 관측됨(예: 24310, 5467, 24). 관측
forks(지표)저장소를 복제해 독립적으로 발전시킨 파생 저장소 수. repo 데이터에서 mutable 값으로 관측됨. 관측
followers(지표)GitHub 사용자 계정을 팔로우하는 다른 사용자 수. user 데이터에서 mutable 값으로 관측됨(예: 5, 117, 0). 관측
publicRepos(지표)해당 사용자가 소유한 공개 저장소 개수. user 데이터에서 mutable 값으로 관측됨. 관측
createdAt / pushedAt(시각성)createdAt(저장소/계정 생성 시각)은 fixed(불변)로, pushedAt(마지막 커밋 push 시각)은 mutable(활동에 따라 계속 변함)로 valueNature에 명시적으로 구분되어 있음. 활성도 판단에 pushedAt이 유용. 관측
watchers(참고 지표, 미관측)저장소를 구독(notification 수신)하는 사용자 수를 나타내는 GitHub 지표. star와 별개 개념이나 UI에서 종종 혼동됨. 이 표본 데이터에는 필드로 나타나지 않음. 웹리서치/실측
organization(조직 계정)여러 사용자가 공동 소유하는 GitHub 계정 유형으로, URL 상으로는 user profile과 동일한 github.com/{name} 형태를 취해 URL만으로는 개인 계정과 구분 불가하고 API kind로만 구분 가능. 웹리서치/실측
README / 저장소 설명(social proof 소재)저장소 루트의 README.md는 프로젝트 소개·정당성 근거로 흔히 인용되며, 토큰 프로젝트 audit 맥락에서 신뢰도 판단 소재가 될 수 있으나 이 표본 fetch 스키마에는 포함되지 않음(별도 콘텐츠 fetch 필요). 웹리서치/실측

1b. URL 패턴

github.com{owner}{repo}/tree/main/... (선택, 무시됨)
github.com/{owner}/{repo}[/extra...] → repo 식별. extra는 라우터가 버림
github.com{login}
github.com/{login} 또는 {login}.github.io → user/org 식별
URL 패턴의미ID 후보관측출처/비고
github.com/{owner}/{repo}레포지토리 프로필. sourceKey = ${segments[0]}/${segments[1]}.toLowerCase() (classifyGithub). fetcher는 sourceKey에 '/' 포함 여부로 repo 판정, GET https://api.github.com/repos/{owner}/{repo} 호출. 반환: createdAt(fixed), owner(fixed, 원래 대소문자 login 그대로), stars/forks(mutable), pushedAt(mutable).owner/repo (GitHub 레포 slug, case-insensitive라 라우터가 소문자 정규화해도 API 조회엔 문제 없음)관측 74건github.json structures[0], count=74. tree/blob/pull 등 하위 경로가 붙은 4개 template(각 1~2건, 합 6건)도 segments[0]/[1]만 취해져 결국 이 패턴과 동일 sourceKey로 수렴함(예: github.com/{owner}/{repo}/tree/main/... , /blob/..., /pull/732).
github.com/{login}사용자(또는 조직) 프로필. sourceKey = segments[0].toLowerCase(). fetcher는 '/' 없으므로 user로 판정, GET https://api.github.com/users/{login}. 반환: createdAt(fixed), login(fixed, 실제 대소문자 원형), followers/publicRepos(mutable).login (GitHub 계정 handle, case-insensitive)관측 68건github.json structures[1], count=68. GitHub REST /users/{login}는 개인 계정뿐 아니라 조직(org)도 동일 엔드포인트로 응답하므로 organization 프로필도 이 경로로 흡수됨(라우터/페처가 구분하지 않음).
{login}.github.ioGitHub Pages 서브도메인. classifyGithub이 host.endsWith('.github.io')를 먼저 체크해 path는 무시하고 host에서 '.github.io' 접미사만 제거해 sourceKey로 씀(라우터의 host 정규화가 이미 소문자화됨). fetcher는 '/' 없으므로 user 취급, /users/{login} 호출.login (Pages 소유자의 GitHub 계정 handle)관측 5건github.json structures[2]='selforg-npa.github.io/'(2건), structures[5]='dhekatz.github.io/DhEKaTz-'(1건), structures[8]='nostalgicgarethdev.github.io/unlockladder'(1건) — 3개 template, 합 4건이나 selforg가 동일 sourceUrl 중복 샘플(실질 unique는 페이지 상 selforg 1 + dhekatz 1 + nostalgicgareth 1 = 최소 3). 페이지 내부 경로(/unlockladder, /#growing 등)는 라우터가 아예 안 봄 — GitHub Pages는 프로젝트별 sub-path를 가질 수 있어 실제로는 여러 레포를 가리켜도 계정 단위로만 뭉뚱그려짐.
gist.github.com/{login}/{gistId}(미관측, 웹지식 보완) GitHub Gist 링크. 현재 라우터는 host==='github.com' 또는 endsWith('.github.io')만 매칭하므로 gist.github.com은 이 두 조건 모두 불일치 → classify()의 마지막 fallback { sourceType: 'website', sourceKey: apexDomain(host) }로 빠져 sourceKey='github.com'이 되고 sourceType도 'github'이 아닌 'website'로 오분류될 것으로 추정됨.gistId (또는 login/gistId)웹리서치/실측표본 151건, unknown.json에 github 관련 항목 없음 — 실측에 gist 링크 자체가 없어 검증 불가. 라우터 host 매칭 목록(github.com / *.github.io)에 gist.github.com이 빠져 있다는 코드 구조상 사실만 근거.
github.com/sponsors/{login} · github.com/orgs/{org}/... · github.com/apps/{name}(미관측, 웹지식 보완) GitHub 예약 루트 경로. classifyGithub은 segments[0]/[1]을 무조건 owner/repo로 취급하므로 'sponsors/{login}', 'orgs/{org}'가 실제로는 owner/repo가 아닌데도 그대로 sourceKey가 되어 GET /repos/sponsors/{login} 등 존재하지 않는 레포 조회로 흘러가 status='not_found'가 될 가능성.없음 — 현재 구현상 오분류(잘못된 sourceKey)로 귀결되는 예약어 루트웹리서치/실측표본에 없었음. X(twitter) 라우팅에는 X_RESERVED_ROOTS 방어 로직이 존재하지만 classifyGithub에는 동일한 예약어 방어가 없다는 코드 비대칭이 근거.

2. sourceType / sourceKey 판정 👤 판단 반영

2.1 sourceType 적합도 👤 판단 반영

패턴현재 type판정/제안sourceKeyconf근거사용자 결정
github.com/{owner}/{repo}
sourceType='github', sourceKey=${owner}/${repo}.toLowerCase() (classifyGithub segments[0]&&segments[1] 분기)변경 없음owner/repo (lowercase)high라우터가 segments[0]/[1]만 취해 tree/blob/pull 등 하위 경로 4개 template(합 6건)도 동일 sourceKey로 자연 수렴 — repo 프로필 판정에 문제 없음. fetcher는 sourceKey.includes('/')로 repo 분기해 GET /repos/{owner}/{repo} 정확히 호출. 반환 필드(createdAt fixed / owner fixed / stars,forks,pushedAt mutable)는 트레이더 페르소나의 '팀 진정성'(레포 실활동 vs 사칭) 판별에 바로 쓸 수 있는 actionable 조합 — createdAt+pushedAt로 '방금 만들고 방치' 패턴, stars/forks로 실체 여부 확인 가능. 관측 74건으로 커버리지 최다.audit 지시 반영 — github_repo로 신규 분리("repo가 end니 github_repo처럼"). router sourceKey는 owner/repo(alias) 유지하되 canonical 조인키는 repo 숫자 id, creator 링크는 owner.id(실측: repo 응답에 추가 쿼리 없이 포함).
github.com/{login}
sourceType='github', sourceKey=segments[0].toLowerCase()변경 없음(단, org/user 구분 불가는 GitHub API 자체 한계이지 라우터 결함 아님)login (lowercase)highsegments[1]이 없을 때만 이 분기로 빠지므로 pattern1과 상호배타적으로 정확히 분리됨. fetcher는 '/' 없음→/users/{login} 호출, createdAt(fixed)+followers/publicRepos(mutable) 반환. 계정 신선도(러그 tell)·활동량 판별에 쓰이는 트레이더 actionable 필드. organization도 동일 REST 응답 스키마를 쓰므로(GitHub 공식 사양) 오분류가 아니라 자연 흡수 — URL만으로는 애초에 org/user 구분이 불가능하므로 split 근거 없음.audit 지시 반영 — github_owner로 신규 분리. sourceKey=login(alias), canonical=user 숫자 id. org/user 구분 불가는 GitHub API 한계라는 기존 판단 유지 (type 필드로 사후 구분 가능하므로 keep).
{login}.github.io
host.endsWith('.github.io') 우선 체크 → path 무시하고 host에서 접미사만 제거해 sourceKey, fetcher는 user로 취급해 /users/{login} 호출변경 없음. 다만 path(sub-project)를 버리는 것이 의도적 설계인지 문서화 필요login (Pages 소유자 handle)mediumpattern2와 동일 sourceKey 스킴(계정 단위)으로 수렴하는 것 자체는 일관적 — Pages 소유자 계정의 신선도/활동량이라는 동일한 트레이더 신호를 준다. 다만 관측 사례(selforg-npa.github.io/, dhekatz.github.io/DhEKaTz-, nostalgicgareth.../unlockladder)처럼 서로 다른 프로젝트 sub-path가 계정 하나로 뭉개지는 것은 '어느 프로젝트가 사칭인지' 세분화는 불가 — 다만 이는 field-necessity 관점에서 트레이더가 프로젝트별로 안 나눠도 되는 수준(계정 신뢰도만 보면 충분)이라 split 강제할 근거는 약함. 관측 3~5건으로 표본 작아 split 필요성 판단 보류.github_owner에 편입(audit이 같은 줄에 묶어 지시). path(sub-project)를 버리는 현행은 의도적 설계로 문서화 — Pages 경로는 계정 단위 신호만 필요.
gist.github.com/{login}/{gistId}
classify()가 host==='github.com' 또는 endsWith('.github.io')만 매칭 — gist.github.com은 둘 다 불일치 → fallback { sourceType: 'website', sourceKey: apexDomain(host) }. apexDomain('gist.github.com')은 마지막 2 라벨만 취하므로 결과 sourceKey='github.com' (host 자체는 'github.com'이 아니라 'gist.github.com'인데 apex 축약으로 동일 키가 됨).classify()의 github 매칭 조건에 host==='gist.github.com' 추가 → classifyGithub 내부에 gist 전용 분기(sourceType 'github' 유지하되 sourceKey=gistId 또는 login/gistId, fetcher에 GET /gists/{id} 케이스 추가 필요) 신설gistId (또는 login/gistId)high코드 구조상 사실로 확정 가능한 갭 — sourceType이 'github'가 아닌 'website'로, sourceKey도 실제 gist 식별자 대신 뭉뚱그린 apex domain('github.com')으로 오염되어 다른 무관 github.com 하위 링크(있다면)와 키가 충돌할 소지. look-ahead 관점 문제는 없으나(website fetcher가 별개 동작) field-necessity 관점에서 '분류 키 오염'은 명백한 손실. 다만 실측 151건 표본에 gist 링크가 0건이라 실제 발생 빈도는 미상 — 트레이더 가치도 낮음(gist는 팀 진정성 신호로서 repo/profile보다 약함). 코드 수정 우선순위는 낮되 라우팅 정합성 자체는 gap.✅ 기존 제안 유지(확정) — classify() host 매칭에 gist.github.com 추가. ⚠ 실측 보강: username 변경 시 gist URL은 리다이렉트 없이 404가 되므로 gist 키도 login이 아니라 gistId 기준이어야 함.
github.com/sponsors/{login} · github.com/orgs/{org}/... · github.com/apps/{name}
classifyGithub은 segments[0]&&segments[1] 존재 시 무조건 owner/repo로 취급 — 'sponsors/{login}', 'orgs/{org}/teams' 등 예약 루트도 그대로 sourceKey가 되어 fetcher가 GET https://api.github.com/repos/sponsors/{login} 같은 존재하지 않는 레포를 조회. X 라우팅에는 X_RESERVED_ROOTS 방어 로직이 있으나 classifyGithub에는 대응 방어가 없음(코드 비대칭 확인).GITHUB_RESERVED_ROOTS Set(sponsors, orgs, apps, marketplace, notifications, settings, issues, pulls, topics, trending, collections, sponsors 등) 신설 후 classifyGithub 시작부에서 segments[0]이 예약어면 unknown 또는 별도 sourceType으로 분기 — X_RESERVED_ROOTS와 동일 패턴 재사용없음 — 현재 구현상 오분류(잘못된 sourceKey)로 귀결high실측 표본(151건)에는 해당 사례가 없어 당장 데이터 오염 증거는 없지만, 코드가 X 라우팅과 비대칭적으로 방어가 빠져있는 것은 구조적 결함. 결과가 fetcher에서 'not_found'로 조용히 실패하므로 즉각적 신호 오염(risk)은 낮지만(에러가 잘못된 데이터로 둔갑하지 않고 not_found로 명확히 걸러짐), GitHub API rate limit을 예약 경로 재조회로 낭비하고 잠재적으로 우연히 실재하는 'sponsors/아무개' 레포(사용자가 만들 수도 있음)가 있으면 완전히 틀린 레포 데이터가 실제 sponsors 페이지의 신호인 것처럼 오분류될 위험이 있음. 트레이더 관점에서 낮은 빈도지만 field-necessity 관점(정합성)에서는 명백한 gap.✅ 기존 제안 유지(확정) — GITHUB_RESERVED_ROOTS 신설로 sponsors/orgs/apps 등 예약경로가 owner/repo로 오인되는 것 방어.

2.2 id 추출 적합도 👤 판단 반영

패턴추출 idresolve?판정conf근거사용자 결정
github.com/{owner}/{repo}sourceKey = ${segments[0]}/${segments[1]}.toLowerCase() (e.g. 'rohitg00/agentmemory')okhighclassifyGithub은 segments[0]/[1]이 모두 존재하면 소문자화한 'owner/repo'를 sourceKey로 쓰고, fetcher는 '/' 포함 여부로 repo 판정 후 GET /repos/{owner}/{repo}를 호출한다. GitHub repo full_name은 대소문자 무관 unique 식별자이므로 소문자화해도 조회에 문제없다. live-test로 실제 https://api.github.com/repos/rohitg00/agentmemory가 200 OK로 정확히 매칭되고 createdAt(fixed)/owner(fixed)/stars·forks·pushedAt(mutable)이 샘플과 일치함을 확인. context.md의 fixed/mutable 분류 원칙과도 fetcher의 valueNature 태깅이 정합함. tree/blob/pull 등 하위 경로가 붙은 템플릿도 segments[0]/[1]만 취해 동일 sourceKey로 정확히 수렴하므로 오히려 정규화가 잘 동작.owner/repo 추출은 정확. 단 저장 키는 숫자 id로 통일(login·repo명 모두 rename 가능).
github.com/{login}sourceKey = segments[0].toLowerCase() (e.g. 'rentahuman')okhighsegments[1]이 없을 때 segments[0]만 소문자화해 sourceKey로 쓰고, fetcher는 GET /users/{login}을 호출한다. GitHub username은 대소문자 무관 unique 식별자라 소문자화로도 정확히 원 계정에 resolve된다. live-test에서 GET /users/RentAHuman(원형)과 동일 결과를 반환할 것으로 기대되는 /users/rentahuman(소문자, 실제 라우터 sourceKey)까지 함께 검증되지는 않았지만 selforg-npa 케이스(패턴3)에서 대소문자 무관 조회 성공이 이미 실측 확인됨 — 동일 API 엔드포인트를 쓰므로 이 패턴에도 그대로 적용된다. organization도 동일 엔드포인트로 흡수되는 점은 sourceType 분류상 특이사항이지만 sourceKey 고유성 자체에는 영향 없음(조직명도 'login' 네임스페이스를 공유해 유니크).✅ login 추출 정확. 단 키는 숫자 id로 통일 — login은 alias로 격하.
{login}.github.iosourceKey = host에서 '.github.io' 접미사 제거(소문자, 라우터의 host 정규화가 이미 소문자화) (e.g. 'selforg-npa')okhighclassifyGithub은 host.endsWith('.github.io')를 먼저 체크해 path는 무시하고 host에서 접미사만 제거한 값을 sourceKey로 쓴다. GitHub Pages의 <login>.github.io 서브도메인은 계정명과 1:1이므로 이 값 자체는 계정을 고유하게 가리킨다. live-test로 GET /users/selforg-npa가 200 OK로 실제 계정 SelfOrg-NPA(원형 대소문자 보존 login 필드 포함)와 정확히 매칭됨을 확인. 다만 페이지 내부 sub-path(/unlockladder, /#growing 등)는 라우터가 보지 않아 '어느 레포/프로젝트 페이지인지'는 유실되고 계정 단위로만 뭉뚱그려짐 — 이는 sourceKey='login' 자체의 고유성 문제가 아니라 fetcher가 애초에 repo-level이 아닌 user-level 정보만 반환하도록 설계된 것과 일관된 스코프 제한. context.md의 '진위/사칭 판별' 목적(계정 나이·활동)에는 충분하나, 특정 프로젝트 페이지 단위 신선도/원본성 판별에는 정보 손실이 있다는 점은 field-necessity 판정관에 넘길 사안.✅ login 추출 정확. 단 키는 숫자 id로 통일 — login은 alias로 격하.
gist.github.com/{login}/{gistId}라우터 fallback: sourceType='website', sourceKey=apexDomain(host)='github.com' (코드 구조상 추정, 실측 URL 없음)wronghighsocial-fetcher.router.ts의 classify() host 매칭 목록을 직접 읽어 확인: host==='github.com' 또는 host.endsWith('.github.io') 두 조건만 github 경로로 라우팅되고, gist.github.com은 어느 쪽에도 걸리지 않아 89행의 최종 fallback { sourceType: 'website', sourceKey: apexDomain(host) }으로 빠진다. apexDomain('gist.github.com')은 마지막 2 라벨인 'github.com'을 반환하므로, gist 링크가 서로 다른 login/gistId를 가리켜도 전부 동일한 sourceKey='github.com'으로 붕괴한다 — 즉 '진짜 고유 식별자'가 전혀 아니고 오히려 github.com 프로필/레포 패턴들과도 sourceType이 달라 충돌하지 않을 뿐 자기들끼리는 전원 충돌한다. 표본에 gist 링크 자체가 없어 id-probe 실측은 없었으나(패턴 제안자도 명시), 코드 판독만으로 명백한 설계 공백이라 confidence는 high로 유지. context.md의 sameHandle/사칭 판별 원칙에 비춰도 이 sourceKey로는 gist 작성자를 전혀 구분할 수 없어 목적에 안 맞음.✅ 현재 website로 새는 것 맞음. host 추가 후 gistId 기준 키. 기존 제안 유지.
github.com/sponsors/{login} · github.com/orgs/{org}/... · github.com/apps/{name}classifyGithub이 예약어 방어 없이 segments[0]/[1]을 그대로 owner/repo로 취급 → sourceKey='sponsors/{login}' 또는 'orgs/{org}' 또는 'apps/{name}' (소문자)wronghighclassifyGithub 코드를 직접 읽어 확인: segments[0]&&segments[1]이면 무조건 owner/repo로 간주해 소문자 조합을 sourceKey로 만든다(226-231행). X 라우팅에는 X_RESERVED_ROOTS 방어 세트가 있지만(4-21행) classifyGithub에는 동일한 예약어 방어가 전혀 없다 — 코드 비대칭이 실제로 존재함을 확인. 그 결과 'sponsors/{login}'·'orgs/{org}'·'apps/{name}'이 실존하지 않는 레포 slug로 오인되어 fetcher가 GET /repos/sponsors/{login} 등 없는 엔드포인트를 호출한다. live-test에서 존재하지 않는 owner/repo 조합(this-org-does-not-exist-zzz999/no-repo-zzz999)이 404 Not Found를 반환함을 실측 확인했고, 이는 예약 경로 오분류 시에도 동일하게 404→status='not_found'로 귀결될 것임을 뒷받침하는 근거가 된다(다만 이 특정 reserved-root URL 자체로 실측한 것은 아님). 즉 sourceKey가 만들어지긴 하나 '고유 식별자'로서 실체(계정/레포)를 가리키지 못하고 항상 실패로 resolve된다.✅ 예약경로가 owner/repo로 오인되는 문제 확인 — RESERVED_ROOTS 방어. 기존 제안 유지.
커버리지 갭 — gist.github.com — 현재 website sourceType/apex-domain 키로 오분류됨. 표본에 미관측이나 코드상 확정된 gap.
커버리지 갭 — github.com 예약 루트(sponsors/orgs/apps 등) — X_RESERVED_ROOTS와 동일한 방어가 classifyGithub엔 없어 잘못된 owner/repo로 API 오조회 가능. 표본에 미관측.

3. Fetch 테스트 + 획득 방법

3.1 획득 사다리 (공짜 → 유료)

방법비용설명트레이드오프conf
확정 ✅ (2026-07-21)사용자 선택 완료 — github.com/{owner}/{repo}→official:rest-pat (무료 (5,000 req/hr — 2026-07 WebSearch로 현재도 동일 한도 확인)) · github.com/{login} (+ {login}.github.io)→official:rest-pat (무료 (5,000 req/hr)) adopted무료 (5,000 req/hr — 2026-07 WebSearch로 현재도 동일 한도 확인) / 무료 (5,000 req/hr)Phase A 후보 사다리에서 사람이 선택한 확정 source. §4 통합 필드 뷰는 이 source의 실제 스키마 기준.신규 채택 source는 현행 코드 미구현분이 §4에서 parseStatus=dropped(구현 필요)로 표시됨. 실제 코드 전환·스키마 검증은 반영 단계에서.high
0 (현재 구현)GitHub REST API 비인증 호출 (api.github.com/users/<login>, /repos/<org>/<repo>) 이미 구현됨 — src/common/social-fetcher/fetchers/github.fetcher.ts무료router의 classifyGithub이 github.com/<org>[/repo] 또는 <org>.github.io를 sourceKey='org' 혹은 'org/repo'(소문자)로 분류. fetcher는 sourceKey에 '/'가 있으면 repos 엔드포인트, 없으면 users 엔드포인트 호출. user 응답에서 createdAt(fixed)/publicRepos/followers(mutable)/login(fixed) 추출, repo 응답에서 createdAt/pushedAt/stars/forks/owner 추출. GITHUB_TOKEN 환경변수 있으면 Authorization: Bearer 헤더 부착.비인증 시 IP당 60 req/hr로 매우 낮음(2025-05 GitHub가 비인증 한도를 낮춤). 저볼륨 온디맨드에도 버스트 시 즉시 소진 위험. verified/인증배지 필드 자체가 GitHub API에 없음(우리 요구사항 '인증' 항목은 GitHub에서 근본적으로 조달 불가) — X 등 타 플랫폼과 달리 매핑 실패 항목.high — 코드 직접 확인, GitHub 공식 문서로 rate limit 교차검증
1 (즉시 적용 가능한 무료 업그레이드)GitHub REST API + Personal Access Token(PAT) 인증 코드는 이미 지원(GITHUB_TOKEN 있으면 사용); 실제 토큰 발급/설정만 하면 됨무료 (GitHub 계정 1개로 발급하는 fine-grained/PAT)인증 시 60→5,000 req/hr로 83배 증가. fetcher 코드 변경 없이 .env에 GITHUB_TOKEN만 채우면 즉시 적용. 저볼륨 온디맨드라면 이 단계만으로 충분할 가능성 높음.여전히 GitHub에는 '게시물(post)' 개념이 없음 — repo/user 메타데이터만 제공. 참여수(engagement)에 대응하는 것은 issue/PR/gist의 reactions API 정도이며, 트윗류 '게시물'과 의미가 다름. 팔로워 수는 있으나 팔로워 리스트 열거는 별도 페이지네이션 필요(사용자당 요청 추가 소비).high
2GitHub GraphQL API v4 (api.github.com/graphql) 미구현무료 (토큰 필요, REST와 동일 계정 한도 내 point 기반: 5,000 point/hr)user/repo/followers/createdAt 등 여러 필드를 단일 쿼리로 묶어 REST 대비 요청 수를 줄일 수 있음(다건 조회 시 유리). 우리 케이스는 온디맨드 단건 조회라 이점이 제한적.쿼리 복잡도에 따라 point 소모가 달라 저볼륨 단건 조회 목적엔 REST 대비 이득이 작음. 도입 비용(쿼리 설계) 대비 실익 낮음 — 우선순위 낮게 권고.medium — point 계산 방식은 GitHub 공식 문서 기준, 실측은 아님
3GH Archive / GitHub BigQuery public dataset 미구현, 아키텍처 부적합무료(GCP BigQuery 쿼리 비용은 발생 가능, 소량이면 무시 가능 수준)공개 이벤트(push/PR/issue/star 등) 대량 히스토리 덤프. 배치/오프라인 리서치용.실시간·온디맨드 단건 조회에 맞지 않음(배치 지연 존재). 우리 유스케이스(저볼륨 온디맨드 단건 fetch)와 목적이 다름 — 참고용으로만 기록.medium
4 (유료 서드파티, API로 안 되는 것만)Apify GitHub 스크레이퍼 actor (예: fetch_cat/github-profile-scraper, automation-lab/github-scraper 등) 미구현actor별 pay-per-result: 예 apivault_labs/github-profile-scraper $4/1K profile, automation-lab/github-scraper $0.002/repo, scrapesage/github-scraper $1.9/1K export. Apify 플랫폼 자체 구독/크레딧 별도.공식 API에 없는 필드(이메일 등 프로필 페이지 HTML에만 노출되는 값) 긁어올 때 쓰는 용도. 대부분 actor가 내부적으로 GitHub REST/검색 API를 감싼 wrapper이거나 프로필 HTML 파싱.벤더 소개 페이지 자체 설명(fetch_cat/apivault_labs/automation-lab/scrapesage)에 의존한 가격·기능 표기라 실사용 검증 안 됨(신뢰도 낮게 봐야 함). 우리가 필요한 필드(팔로워/생성일/공개저장소 수, repo star/fork)는 이미 무료 공식 API로 100% 커버되므로 이 단계까지 갈 이유가 현재는 없음. '게시물 참여수' 요구사항도 GitHub 도메인 자체에 대응 개념이 없어 Apify로도 못 채움(어떤 actor도 '트윗 유사 게시물+참여수'를 GitHub에서 생성해내지 못함 — 존재하지 않는 데이터).low-medium — 가격은 벤더 페이지 자체 주장, 제3자 검증 없음. 벤더 편향 유의.

3.2 공식 API 상세

확신도 high — GitHub REST/GraphQL 어디에도 (1) '인증(verified) 배지' 필드, (2) X/Telegram 같은 '게시물+참여수(좋아요/리트윗류)' 개념이 없음. 우리 요구사항 중 '프로필의 인증 여부'와 '게시물의 참여수'는 GitHub 데이터 모델 자체에 대응물이 없어 무료든 유료든 GitHub에서는 조달 불가 — repo star/fork/워치/issue reactions 정도가 그나마 유사 개념(참여 신호이긴 하나 '게시물'과 성격이 다름). 이 갭은 소스 자체의 한계이므로 Apify로도 메울 수 없음.
단계내용conf
현재 상태: 비인증 REST 호출, 60 req/hrsrc/common/social-fetcher/fetchers/github.fetcher.ts가 GITHUB_TOKEN 미설정 시 이 상태로 동작. 저볼륨이라도 다건 배치 시 쉽게 소진.high
권장 우선 조치: GITHUB_TOKEN 발급/설정GitHub 계정에서 PAT(fine-grained, 별도 scope 불필요 — public read only) 발급 후 .env에 주입. 코드 수정 불필요, rate limit 60→5,000/hr.high
필요 시 GraphQL로 전환 검토다건 배치 조회가 늘어나면 요청 수 절감 목적으로 GraphQL 검토. 현재 온디맨드 단건 구조에서는 이점 낮음.medium

3.3 라이브 테스트 실측

대상방법과금결과비고
GET https://api.github.com/repos/rohitg00/agentmemory (sourceType=github, sourceKey='rohitg00/agentmemory', template github.com/{value}/{value})curl + GITHUB_TOKEN(Bearer) 인증, User-Agent/Accept 헤더는 fetcher와 동일무료200 OK. 인증 성공(rate limit 5000/hr, remaining 4998). fetcher 추출 필드: kind='repo', createdAt='2026-02-25T07:32:52Z'(고정), pushedAt='2026-07-19T10:58:13Z'(가변, 샘플 시점 대비 갱신됨), stars=25347(가변, 샘플 24310→증가), forks=2101(가변), owner='rohitg00'(고정). 샘플과 구조 완전 일치.
GET https://api.github.com/users/RentAHuman (sourceType=github, sourceKey='rentahuman', template github.com/{value})curl + GITHUB_TOKEN 인증무료200 OK. fetcher 추출 필드: kind='user', createdAt='2026-02-06T13:23:34Z'(고정), publicRepos=1(가변), followers=5(가변), login='RentAHuman'(고정, 원형 케이스 보존). 샘플과 완전 일치. 응답 원문에 GitHub API가 실제로 email/bio/company 등 프로필 필드도 제공하지만 fetcher는 미사용.
GET https://api.github.com/users/selforg-npa (sourceType=github, sourceKey='selforg-npa' — <org>.github.io Pages URL이 라우터에서 sourceKey=서브도메인으로 분류되어 users 엔드포인트로 매핑됨)curl + GITHUB_TOKEN 인증무료200 OK. classifyGithub의 '<org>.github.io → sourceKey=org(소문자)' 규칙 확인: selforg-npa.github.io#growing → users/selforg-npa 호출이 실제 계정 SelfOrg-NPA와 정확히 매칭(대소문자 무관 조회 성공). id-probe 결과 라우터 sourceKey와 실제 canonical login 간 괴리 없음(GitHub username은 대소문자 무관 unique이므로 라우터의 lc() 소문자화가 API 조회에 문제없음).
GET https://api.github.com/repos/this-org-does-not-exist-zzz999/no-repo-zzz999 (존재하지 않는 repo, fetcher 'not_found' 분기 검증)curl + GITHUB_TOKEN 인증무료404. GitHub API는 res.data가 없거나 예외를 던지는 형태로 응답 → fetcher 코드 상 httpGet이 4xx를 어떻게 처리하는지는 social-fetcher.util.ts 미확인이라 단정 못하나(catch 블록에서 status='error'로 처리될 가능성; buildResult(routed,'not_found')는 sourceKey가 falsy일 때만 명시적으로 호출됨), 실제 HTTP 계층에서 404가 반환됨은 확인.
GET https://api.github.com/users/this-user-does-not-exist-zzz999 (존재하지 않는 user)curl + GITHUB_TOKEN 인증무료404, 동일 패턴.
GET https://api.github.com/repos/rohitg00/agentmemory (비인증, HEAD)curl -sI 무헤더(토큰 없이)무료200. x-ratelimit-limit=60, remaining=53(요청 누적) — acquisition 문서의 '비인증 60/hr, 인증 5000/hr' 주장을 실측으로 확인.
GitHub REST API — user/repo 응답의 숫자 id 및 미기재 필드 확인 (조인키 확정용)GET https://api.github.com/users/RentAHuman · GET https://api.github.com/repos/rohitg00/agentmemory (무인증, 무료)무료success (둘 다 HTTP 200)조인키 확정 근거: repo 응답이 owner.id추가 쿼리 없이 제공 → audit이 짚은 "repo에 owner가 있으니 매핑가능"이 숫자 id 수준에서 성립. 문서·audit 둘 다 놓친 필드 발견: fork(포크 위장 tell), homepage(사칭 도메인 대조), twitter_username(sameHandle 크로스플랫폼 대조), topics/language.
README 조달 가능 여부 (audit 요청: "README 는 있으면 어떤건지 파악하기 좋을 듯")GET https://api.github.com/repos/rohitg00/agentmemory/readme (무인증, 무료)무료success (HTTP 200)조달 가능 → decision=keep 승격. ⚠ repo API 1콜에 딸려오지 않고 별도 호출 1회 추가 필요(무료지만 rate limit 소모).

GET https://api.github.com/repos/rohitg00/agentmemory (sourceType=github, sourceKey='rohitg00/agentmemory', template github.com/{value}/{value}) 실측 응답 원문:

{"id":1166408297,...,"full_name":"rohitg00/agentmemory",...,"owner":{"login":"rohitg00",...},...,"stargazers_count"(응답 중간 생략, 필드는 전체 응답에 존재)...}

GET https://api.github.com/users/RentAHuman (sourceType=github, sourceKey='rentahuman', template github.com/{value}) 실측 응답 원문:

{"login":"RentAHuman",...,"public_repos":1,"followers":5,"created_at":"2026-02-06T13:23:34Z",...}

GET https://api.github.com/users/selforg-npa (sourceType=github, sourceKey='selforg-npa' — <org>.github.io Pages URL이 라우터에서 sourceKey=서브도메인으로 분류되어 users 엔드포인트로 매핑됨) 실측 응답 원문:

{"kind":"user","createdAt":"2025-12-20T14:51:52Z","publicRepos":1,"followers":0,"login":"SelfOrg-NPA"}

GET https://api.github.com/repos/this-org-does-not-exist-zzz999/no-repo-zzz999 (존재하지 않는 repo, fetcher 'not_found' 분기 검증) 실측 응답 원문:

{"message":"Not Found","documentation_url":"https://docs.github.com/rest/repos/repos#get-a-repository","status":"404"}

GET https://api.github.com/users/this-user-does-not-exist-zzz999 (존재하지 않는 user) 실측 응답 원문:

{"message":"Not Found","documentation_url":"https://docs.github.com/rest","status":"404"}

GET https://api.github.com/repos/rohitg00/agentmemory (비인증, HEAD) 실측 응답 원문:

x-ratelimit-limit: 60
x-ratelimit-remaining: 53
x-ratelimit-used: 7

GitHub REST API — user/repo 응답의 숫자 id 및 미기재 필드 확인 (조인키 확정용) 실측 응답 원문:

user(33키): id=259870598, login="RentAHuman", type="User", created_at="2026-02-06T13:23:34Z", public_repos=1, followers=5, blog="https://rentahuman.ai/", company="RentAHuman", email=null, twitter_username=null, name, location, updated_at, public_gists, following, hireable, node_id …
repo(84키): id=1166408297, full_name="rohitg00/agentmemory", owner={id:48523873, login:"rohitg00", type:"User"}, created_at, pushed_at="2026-07-29T09:21:54Z", stargazers_count=25956, watchers_count=25956, forks_count=2167, open_issues_count=418, subscribers_count=73, network_count=2167, license={...}, archived=false, fork=false, homepage="https://agent-memory.dev", topics=[...], language="TypeScript", size, has_wiki, is_template, default_branch, visibility, updated_at, node_id …

README 조달 가능 여부 (audit 요청: "README 는 있으면 어떤건지 파악하기 좋을 듯") 실측 응답 원문:

HTTP 200 — base64 인코딩된 README 본문 반환
GITHUB_TOKEN이 .env.dev/.env.prod 양쪽에 이미 설정되어 있음(acquisition 문서의 rank 1 '즉시 적용 가능한 무료 업그레이드'가 사실상 이미 적용된 상태). 실측 결과 인증 호출은 5000/hr 한도(remaining 4998→확인), 비인증은 60/hr(remaining 53)로 acquisition 주장과 일치.
라우터·fetcher·실 API 응답 3자 대조 결과 완전 일치: repo/user 두 dataType 모두 필드명·값 성격(fixed/mutable) 모두 코드 그대로 재현됨. github.io Pages → users 엔드포인트 매핑도 selforg-npa 사례로 실증(대소문자 무관 GitHub username 특성상 라우터의 소문자화가 조회에 문제 없음).
acquisition 문서가 지적한 갭(verified 배지, '게시물+참여수' 개념 부재)은 API 응답 원문에서도 재확인됨 — repo/user 응답 어디에도 verified 필드 없고, engagement에 대응하는 것은 stargazers_count/forks_count 정도(게시물 단위 아님). 이 부분은 GitHub 데이터 모델 자체 한계로 실측으로도 메꿀 수 없음이 재확인됨.
not_found(404) 케이스에서 fetcher의 실제 처리 분기(social-fetcher.util.ts의 httpGet 4xx 핸들링)는 이번 조사 범위(router+github.fetcher만 Read 지정됨)에 포함되지 않아 catch(error)로 떨어져 status='error'가 되는지, 혹은 data undefined로 'not_found'가 되는지는 미확인 — 필요 시 social-fetcher.util.ts 별도 확인 요망.

4. 객체별 필드 통합 (변동성 · 파싱상태 · 트레이딩 유용성) 👤 판단 반영

Creator/Content 객체별로 필드를 한 표에 통합. 값 변동성 = 값이 시간에 따라 변하나(immutable 역사적 사실 / mutable 드리프트 / derivable 계산값) → look-ahead 안전성이 여기서 도출(immutable=safe · mutable=conditional/as-of · derivable=unsafe). 파싱 상태 = 현재 파이프라인이 실제로 저장하나.

4.1 · Creator (user/org 프로필) — github (user/org)

source: GitHub REST API official (GET /users/{login}), PAT 인증 — src/common/social-fetcher/fetchers/github.fetcher.ts · mutable 값(followers/publicRepos)은 fetch 시점 스냅샷 — 진입시점과 다를 수 있어 as-of 주의. immutable(login/createdAt)은 나중에 재조회해도 동일(look-ahead safe). GitHub REST는 user/org를 동일 엔드포인트로 응답하므로 URL만으로는 개인/조직 구분 불가(API kind 필드로만 구분).
필드설명값 변동성파싱 상태(현재)최종 결정트레이딩 유용성
login계정 핸들. 변경 가능하고 옛 username은 타인이 선점 가능하며, GitHub 리다이렉트도 새 주인이 같은 이름의 repo를 만들면 깨짐 → 키 부적격, 표시/해석용 alias로만 보관mutable✅ 캡처keepactionable — 소셜에서 주장하는 팀 핸들과 대조하는 sameHandle 사칭 tell. 단 조인·dedup 사용 금지(변경+재할당)
createdAt계정 생성 시각(API created_at). 예: '2026-02-06T13:23:34Z'immutable✅ 캡처keepactionable — 러그리스크: 런칭 며칠 전 급조 계정 판별의 핵심 이진 tell
publicRepos공개 저장소 개수(API public_repos). 예: 1mutable✅ 캡처keepcontext — 팀 진정성 보조(빈 repo로도 부풀릴 수 있어 단독 결정 트리거 아님)
followersGitHub 팔로워 수(API followers). 예: 5mutable✅ 캡처keepnoise — 개발자 커뮤니티 지표라 밈코인 모멘텀(X/TG 도달)과 무관
kind라우터 내부 태그, 고정 리터럴 'user'immutable✅ 캡처skipnoise — 라우팅용, 매매판단 비관여
bio프로필 소개글(API bio). live-test로 응답에 존재 확인, fetcher 미파싱mutable⚠️ actor제공·미파싱keepcontext — 내러티브/사칭 tell 보조
company소속 조직 표기(API company)mutable⚠️ actor제공·미파싱keepcontext — 팀 실체 대조 보조
email공개 이메일(API email, null 가능)mutable⚠️ actor제공·미파싱keepcontext — 팀 연락처 실재 여부(러그 팀은 흔히 비공개)
blog프로필 외부링크(API blog 필드, 웹사이트/링크트리 등)mutable⚠️ actor제공·미파싱keepactionable — 사칭 도메인·스캠 링크 tell(IG externalUrl과 동일 원칙)
id계정 숫자 id(API id) — login 개명에도 불변하는 안정 join 키immutable⚠️ actor제공·미파싱🔑 keycontext — 핸들 리네임 대비 join 안정키
type'User' vs 'Organization'(API type) — URL만으로는 구분 불가한 계정 종류immutable⚠️ actor제공·미파싱keepcontext — 개인 vs 조직 구분(팀진정성 해석 보정)
verified(인증배지)GitHub REST/GraphQL 어디에도 대응 필드 없음 — X/IG류 '인증 배지' 개념 자체가 GitHub 데이터 모델에 부재immutable❌ 없음해당없음 — 애초에 GitHub이 조달 불가한 필드(유료 API로도 불가)
twitter_username2026-07-29 실측 신규 확인. 프로필이 선언한 X 핸들(무료 API 제공, 문서·audit 둘 다 미기재)mutable⚠️ actor제공·미파싱keepactionable — 검증된 신호 sameHandle 사칭 판별에 직결되는 크로스플랫폼 대조 필드
name / location / updated_at / public_gists / following / hireable / node_id / avatar_url 등2026-07-29 실측 신규 확인(user API 33키 중 미채택분)mutable⚠️ actor제공·미파싱skipnoise — 표시 메타이거나 기존 필드와 중복

4.2 · Content (repo) — github (repo)

source: GitHub REST API official (GET /repos/{owner}/{repo}), PAT 인증 — 동일 fetcher · stars/forks/pushedAt/open_issues_count(mutable)은 fetch 시점 스냅샷 — 코인 인기로 인한 역인과(밈 열기→star 유입) 오염 가능성 있어 as-of 재구성 시 raw 시계열로 저장 권장. createdAt/owner(immutable)는 look-ahead safe. GitHub에는 '게시물' 개념 자체가 없어 참여속도(engagement velocity)는 구조적으로 관측 불가.
필드설명값 변동성파싱 상태(현재)최종 결정트레이딩 유용성
owner (login)repo 소유자 login(API owner.login, 원형 대소문자). 예: 'rohitg00'mutable✅ 캡처keepactionable — 팀 핸들과의 sameHandle 사칭 대조. 단 조인은 owner.id로(위 신규 행)
createdAtrepo 생성 시각(API created_at). 예: '2026-02-25T07:32:52Z'immutable✅ 캡처keepcontext — 급조 스캐폴드 의심 근거지만 단독으론 배경, pushedAt·owner와 결합해야 액션
pushedAt마지막 커밋 push 시각(API pushed_at). 예: '2026-07-19T10:58:13Z'mutable✅ 캡처keepactionable — 러그리스크: 생성 후 push 정지=방치된 죽은 스캐폴드 tell
starsstar 수(API stargazers_count). 예: 25347mutable✅ 캡처keepnoise — 스타 판매/봇으로 손쉽게 부풀려짐, 트레이더는 X/TG 참여속도로 모멘텀 판단
forksfork 수(API forks_count). 예: 2101mutable✅ 캡처keepnoise — stars보다도 약한 신호, 개발자 채택이지 트레이더 확산과 무관
kind라우터 내부 태그, 고정 리터럴 'repo'immutable✅ 캡처skipnoise — 라우팅용, 매매판단 비관여
open_issues_count오픈 이슈 수(API open_issues_count, PR 포함)mutable⚠️ actor제공·미파싱keepcontext — 활동/관리 여부 보조(단독 신호 약함)
license라이선스 종류(API license.spdx_id, 없으면 null)mutable⚠️ actor제공·미파싱removenoise — 밈코인 repo 대부분 무관/부재, 공식성 판단에 거의 안 씀
archived저장소 보관(읽기전용) 처리 여부(API archived)mutable⚠️ actor제공·미파싱keepactionable — archived=true는 팀 스스로 프로젝트 종료를 선언한 강한 러그 tell. audit은 license와 한 줄에 묶어 제거 지시했으나, license(밈코인과 무관)와 성격이 다르고 불리언 1개라 저장비용이 사실상 0이라 keep으로 뒤집음(사용자 확인, 2026-07-29)
descriptionrepo 한줄 설명(API description)mutable⚠️ actor제공·미파싱keepcontext — 프로젝트 내러티브/티커 언급 대조
README(본문)repo 대문 문서. 별도 엔드포인트 GET /repos/{owner}/{repo}/readme로 조달(실측 200, 무료). repo API 1콜에는 딸려오지 않음mutable⚠️ actor제공·미파싱keepcontext — 프로젝트 정당성/내러티브 근거 소재. audit이 "있으면 어떤건지 파악하기 좋을 듯"으로 요청
(참여속도/engagement velocity)트윗류 '게시물+좋아요/리트윗' 참여속도에 대응하는 개념 — GitHub 데이터 모델 자체에 부재(star/fork는 게시물 단위 아님)derivable❌ 없음skip해당없음 — GitHub이 근본적으로 조달 불가, X/Telegram이 실제 모멘텀 관측처
id (repo 숫자 ID)repo 고유 숫자 ID. 실측 1166408297. repo rename에도 불변이라 dedup/조인 키immutable⚠️ actor제공·미파싱🔑 keycontext — 조인키 용도, 그 자체로 매매결정 안 바꿈
owner.id (creator 링크)repo 응답에 동봉된 소유자 숫자 계정 ID. 실측 48523873추가 쿼리 불필요immutable⚠️ actor제공·미파싱🔑 keycontext — 조인 성립의 필수 조건
full_name{login}/{repo} 형태 표시명. 실측 rohitg00/agentmemory. login·repo 모두 rename 가능하므로 aliasmutable⚠️ actor제공·미파싱keepcontext — 표시/대조용(조인은 id로)
fork2026-07-29 실측 신규 확인. 다른 repo를 포크한 것인지 여부(문서·audit 둘 다 미기재)immutable⚠️ actor제공·미파싱keepactionable — 남의 repo를 포크해 자기 프로젝트로 위장하는 밈코인 러그의 전형 패턴을 직접 가리키는 스캐폴드 tell
homepage2026-07-29 실측 신규 확인. repo가 선언한 프로젝트 웹사이트 URL(실측 https://agent-memory.dev)mutable⚠️ actor제공·미파싱keepactionable — 사칭 도메인·드레이너 링크 대조. profile의 blog, IG externalUrls[], X expanded_url과 동일 계열
topics[] / language2026-07-29 실측 신규 확인. repo 태그 배열 / 주 언어(실측 TypeScript)mutable⚠️ actor제공·미파싱keepcontext — 밈 스캐폴드 패턴 보조(단독 결정력 약함)
watchers_count / subscribers_count / network_count / size / has_wiki / has_issues / is_template / default_branch / visibility / updated_at / node_id2026-07-29 실측 신규 확인(repo API 84키 중 미채택분). watchers_count는 stars와 동일값으로 관측됨mutable⚠️ actor제공·미파싱skipnoise — 기존 지표와 중복이거나 개발 메타

4-부록. actor raw 응답 스키마 (ground truth)

위 통합 표의 원천 — actor가 실제 반환하는 원본 필드 전체.

dataType: "github / repo (sourceKey에 '/' 포함, github.com/{org}/{repo})"

필드예시값설명
kind"repo"고정 리터럴 'repo'
createdAt"2026-02-25T07:32:52Z"repo 생성일, fixed(불변) — GitHub API created_at 그대로
pushedAt"2026-07-19T10:58:13Z"마지막 push 시각, mutable — API pushed_at
stars25347star 수, mutable — API stargazers_count
forks2101fork 수, mutable — API forks_count
owner"rohitg00"repo 소유자 login, fixed — API owner.login
id1166408297repo 숫자 ID — rename 불변 조인키
owner.id48523873소유자 숫자 계정 ID — creator 조인키(추가 쿼리 불필요)
full_namerohitg00/agentmemory{login}/{repo} 표시명
forkfalse포크 여부 — 남의 repo 위장 tell
homepagehttps://agent-memory.devrepo 선언 프로젝트 웹사이트
topics[] / languageTypeScriptrepo 태그 / 주 언어
open_issues_count / subscribers_count / watchers_count / network_count / size / has_wiki / is_template / default_branch / visibility / updated_at / node_idopen_issues_count=4182026-07-29 실측 신규 확인

dataType: "github / user (sourceKey에 '/' 없음: github.com/{org} 또는 {org}.github.io Pages)"

필드예시값설명
kind"user"고정 리터럴 'user'
createdAt"2026-02-06T13:23:34Z"계정 생성일, fixed — API created_at
publicRepos1공개 repo 수, mutable — API public_repos
followers5팔로워 수, mutable — API followers
login"RentAHuman"계정 login(원형 케이스 보존), fixed — API login
id259870598계정 숫자 ID — canonical 조인키
twitter_usernamenull (이 계정은 미설정)프로필 선언 X 핸들 — sameHandle 대조
bio / company / email / blog / typeblog=https://rentahuman.ai/기존 objectFields에 있으나 raw 스키마 목록엔 없던 항목
name / location / updated_at / public_gists / following / hireable / node_idpublic_gists=02026-07-29 실측 신규 확인(미채택)

다음 액션