diff --git a/.github/workflows/catalog-quality.yml b/.github/workflows/catalog-quality.yml new file mode 100644 index 0000000..a75343d --- /dev/null +++ b/.github/workflows/catalog-quality.yml @@ -0,0 +1,165 @@ +name: Catalog Quality Check with Auto Issue Reporting + +# 카탈로그 검사 도구(catalogutil.cs / checkimages.cs)를 주기적으로 실행하여 +# 발견된 오류를 하나의 추적(tracking) 이슈로 자동 등록/갱신합니다. +# 검출은 자동, 실제 수정(카탈로그 갱신)은 사람 또는 AI 에이전트가 담당합니다. + +on: + schedule: + # 매주 월요일 00:00 UTC (한국시간 월요일 09:00) + - cron: '0 0 * * 1' + workflow_dispatch: + inputs: + assign_copilot: + description: '생성/갱신된 추적 이슈를 Copilot 코딩 에이전트에 배정합니다.' + type: boolean + default: false + push: + branches: + - main + paths: + - 'docs/Catalog.xml' + - 'docs/images/**' + +permissions: + contents: read + issues: write + +jobs: + quality-check: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + ISSUE_LABEL: catalog-quality + ISSUE_MARKER: '' + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + # 이미지 검증 (오프라인, 결정론적): 누락/미사용 로고 이미지를 검출합니다. + - name: Run image validation (checkimages.cs) + id: checkimages + run: | + code=0 + dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images \ + > checkimages.log 2>&1 || code=$? + echo "exit_code=$code" >> "$GITHUB_OUTPUT" + + # 스키마 검증 및 리소스 생성 (URL 접속성 경고 포함). + - name: Run catalog validation (catalogutil.cs) + id: catalogutil + run: | + code=0 + dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/ \ + > catalogutil.log 2>&1 || code=$? + echo "exit_code=$code" >> "$GITHUB_OUTPUT" + + - name: Build issue body and decide action + id: report + run: | + set -euo pipefail + + IMAGES_EXIT="${{ steps.checkimages.outputs.exit_code }}" + UTIL_EXIT="${{ steps.catalogutil.outputs.exit_code }}" + + # 도구가 문제(비정상 종료 코드)를 보고했는지 판단합니다. + PROBLEMS=0 + if [ "${IMAGES_EXIT:-0}" != "0" ] || [ "${UTIL_EXIT:-0}" != "0" ]; then + PROBLEMS=1 + fi + echo "problems=$PROBLEMS" >> "$GITHUB_OUTPUT" + + { + echo "$ISSUE_MARKER" + echo "## 카탈로그 품질 검사 리포트" + echo + echo "이 이슈는 \`catalog-quality\` 워크플로우가 자동으로 생성/갱신합니다." + echo "검출은 자동으로 이뤄지며, 실제 카탈로그 수정은 사람 또는 AI 에이전트가 담당합니다." + echo + echo "- **실행 시각(UTC)**: $(date -u '+%Y-%m-%dT%H:%M:%SZ')" + echo "- **커밋**: \`${GITHUB_SHA}\`" + echo "- **워크플로우 실행**: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + echo + echo "### 이미지 검증 (checkimages.cs) — 종료 코드 \`${IMAGES_EXIT:-N/A}\`" + echo + echo '```text' + # ANSI 이스케이프가 남아 있을 경우를 대비해 제거합니다. + sed -r 's/\x1B\[[0-9;]*[A-Za-z]//g' checkimages.log || cat checkimages.log + echo '```' + echo + echo "### 스키마/URL 검증 (catalogutil.cs) — 종료 코드 \`${UTIL_EXIT:-N/A}\`" + echo + echo "> 참고: URL 접속성 경고에는 CI 환경의 일시적 네트워크 문제가 포함될 수 있습니다." + echo + echo '```text' + sed -r 's/\x1B\[[0-9;]*[A-Za-z]//g' catalogutil.log || cat catalogutil.log + echo '```' + echo + echo "### 권장 조치" + echo + echo "- **누락된 이미지**: 해당 서비스의 공식 로고를 \`docs/images//.png\`로 추가하세요. (\`src/fetchfavicon.cs\` 참고)" + echo "- **미사용 이미지**: Catalog.xml에서 삭제된 서비스의 이미지라면 함께 제거하세요." + echo "- **스키마 오류**: Catalog.xml의 구조/속성을 XSD에 맞게 수정하세요." + echo + echo "수정 후 다음으로 재검증하세요:" + echo + echo '```bash' + echo "dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images" + echo "dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/" + echo '```' + echo + echo "---" + echo "*generated by \`.github/workflows/catalog-quality.yml\`*" + } > issue-body.md + + - name: Create or update tracking issue + env: + PROBLEMS: ${{ steps.report.outputs.problems }} + ASSIGN_COPILOT: ${{ github.event.inputs.assign_copilot }} + run: | + set -euo pipefail + + # 라벨이 없으면 생성합니다. + gh label create "$ISSUE_LABEL" \ + --description "자동 카탈로그 품질 검사 리포트" \ + --color BFD4F2 --force >/dev/null 2>&1 || true + + # 열려 있는 기존 추적 이슈를 찾습니다 (라벨 기준, 최대 1건). + EXISTING=$(gh issue list --state open --label "$ISSUE_LABEL" \ + --limit 1 --json number --jq '.[0].number // empty') + + TITLE="[카탈로그 품질] 자동 검사에서 문제가 발견되었습니다" + + if [ "$PROBLEMS" = "1" ]; then + if [ -n "$EXISTING" ]; then + echo "기존 추적 이슈 #$EXISTING 를 갱신합니다." + gh issue edit "$EXISTING" --body-file issue-body.md + gh issue comment "$EXISTING" \ + --body "🔄 최신 검사 결과로 이슈 본문을 갱신했습니다. (실행 ${GITHUB_RUN_ID})" + ISSUE_NUMBER="$EXISTING" + else + echo "새 추적 이슈를 생성합니다." + ISSUE_URL=$(gh issue create --title "$TITLE" \ + --body-file issue-body.md --label "$ISSUE_LABEL") + echo "생성됨: $ISSUE_URL" + ISSUE_NUMBER=$(basename "$ISSUE_URL") + fi + + # 요청 시 Copilot 코딩 에이전트에 배정 (best-effort). + if [ "${ASSIGN_COPILOT:-false}" = "true" ] && [ -n "${ISSUE_NUMBER:-}" ]; then + gh issue edit "$ISSUE_NUMBER" --add-assignee "@copilot" \ + || echo "Copilot 배정에 실패했습니다 (수동 배정이 필요할 수 있습니다)." + fi + else + echo "문제가 발견되지 않았습니다." + if [ -n "$EXISTING" ]; then + echo "기존 추적 이슈 #$EXISTING 를 닫습니다." + gh issue comment "$EXISTING" \ + --body "✅ 최신 자동 검사에서 더 이상 문제가 발견되지 않아 이슈를 닫습니다. (실행 ${GITHUB_RUN_ID})" + gh issue close "$EXISTING" + fi + fi diff --git a/.github/workflows/savings-bank-merger-watch.yml b/.github/workflows/savings-bank-merger-watch.yml new file mode 100644 index 0000000..cdc4f10 --- /dev/null +++ b/.github/workflows/savings-bank-merger-watch.yml @@ -0,0 +1,125 @@ +name: Savings Bank Merger Watch (AI Agent Assisted) + +# 기관 통폐합이 잦은 저축은행 업계 특성을 감안하여, 주기적으로 AI 에이전트에게 +# "최근 저축은행 통폐합/명칭변경/폐업 뉴스"를 조사하도록 위임하는 이슈를 자동 생성합니다. +# 실제 뉴스 검색·판정은 AI 에이전트(Copilot 코딩 에이전트 / Claude Code 등)가 수행하고, +# 카탈로그 반영(merge)은 사람이 최종 검토합니다. + +on: + schedule: + # 매월 1일 00:00 UTC (한국시간 매월 1일 09:00) + - cron: '0 0 1 * *' + workflow_dispatch: + inputs: + assign_copilot: + description: '생성된 조사 이슈를 Copilot 코딩 에이전트에 배정합니다.' + type: boolean + default: false + +permissions: + contents: read + issues: write + +jobs: + merger-watch: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + ISSUE_LABEL: savings-bank-merger-watch + steps: + - uses: actions/checkout@v4 + + - name: Extract savings bank entries from catalog + id: extract + run: | + set -euo pipefail + + # Catalog.xml에서 DisplayName에 "저축은행"이 포함된 Service 항목을 추출합니다. + grep -oP ']*DisplayName="[^"]*저축은행[^"]*"[^>]*Url="[^"]*"' \ + docs/Catalog.xml > matches.txt || true + + : > entries.md + COUNT=0 + while IFS= read -r line; do + ID=$(printf '%s' "$line" | grep -oP 'Id="\K[^"]*' | head -n1 || true) + NAME=$(printf '%s' "$line" | grep -oP 'DisplayName="\K[^"]*' | head -n1 || true) + URL=$(printf '%s' "$line" | grep -oP 'Url="\K[^"]*' | head -n1 || true) + [ -z "$ID" ] && continue + echo "- \`$ID\` — $NAME (<$URL>)" >> entries.md + COUNT=$((COUNT + 1)) + done < matches.txt + + echo "count=$COUNT" >> "$GITHUB_OUTPUT" + echo "저축은행 항목 $COUNT건을 추출했습니다." + + - name: Build research issue body + run: | + set -euo pipefail + PERIOD=$(date -u '+%Y-%m') + echo "period=$PERIOD" >> "$GITHUB_ENV" + + { + echo "" + echo "## 저축은행 통폐합 점검 요청 (${PERIOD})" + echo + echo "저축은행 업계는 인수합병·통폐합·명칭변경이 잦습니다. 이 이슈는 매월 자동 생성되며," + echo "**AI 에이전트가 최근 업계 뉴스를 조사하여 카탈로그에 반영이 필요한 변경을 식별**하도록 위임합니다." + echo + echo "### AI 에이전트 작업 지침" + echo + echo "1. 아래 카탈로그에 등록된 저축은행 목록을 기준으로, **최근(대략 지난 3~6개월) 국내 저축은행의 통폐합/인수합병/명칭변경/영업정지·폐업** 관련 뉴스를 검색하세요." + echo " - 참고 출처: 금융감독원, 저축은행중앙회(), 주요 경제 뉴스." + echo "2. 확인된 변경 건마다 다음을 정리하세요." + echo " - 대상 기관(현재 카탈로그 \`Id\`/\`DisplayName\`), 변경 유형(통폐합/명칭변경/폐업), 공식 발표·뉴스 **출처 URL**, 시점." + echo " - 카탈로그 반영 방향 제안: \`Url\` 교체 / \`DisplayName\`·\`Id\` 갱신 / 항목 삭제 / 신규 항목 추가." + echo "3. **검증**: 변경 후보 기관의 현재 사이트 접속 상태를 확인하세요." + echo + echo '```bash' + echo "dotnet run --file src/checksites.cs -- probe ./docs/ ./health-report/ --only " + echo '```' + echo + echo "4. 실제 반영이 필요한 건은 이 이슈에 코멘트로 근거(출처 URL 포함)와 함께 제안하고, 승인 후 PR로 처리하세요." + echo " - **자동 삭제 금지**: 폐업·통폐합으로 삭제가 필요한 항목은 반드시 사람의 승인을 받으세요." + echo "5. 조사 결과 반영할 변경이 없으면, 확인한 범위를 코멘트로 남기고 이 이슈를 닫아도 됩니다." + echo + echo "### 현재 카탈로그의 저축은행 목록 (${{ steps.extract.outputs.count }}건)" + echo + if [ -s entries.md ]; then + cat entries.md + else + echo "_(추출된 항목이 없습니다. 추출 로직을 확인하세요.)_" + fi + echo + echo "---" + echo "*generated by \`.github/workflows/savings-bank-merger-watch.yml\`*" + } > issue-body.md + + - name: Create research issue (deduplicated per month) + env: + ASSIGN_COPILOT: ${{ github.event.inputs.assign_copilot }} + run: | + set -euo pipefail + + gh label create "$ISSUE_LABEL" \ + --description "저축은행 통폐합 AI 점검 요청" \ + --color D4C5F9 --force >/dev/null 2>&1 || true + + # 제목에 해당 연-월(${period})이 포함된 열린 이슈를 찾아 중복 생성을 방지합니다. + EXISTING=$(gh issue list --state open --label "$ISSUE_LABEL" \ + --limit 100 --json number,title \ + --jq "map(select(.title | contains(\"$period\"))) | .[0].number // empty") + + if [ -n "$EXISTING" ]; then + echo "이번 달(${period}) 조사 이슈 #$EXISTING 가 이미 존재합니다. 건너뜁니다." + exit 0 + fi + + TITLE="[저축은행 통폐합 점검] ${period} — 업계 통폐합 뉴스 조사 요청" + ISSUE_URL=$(gh issue create --title "$TITLE" \ + --body-file issue-body.md --label "$ISSUE_LABEL") + echo "생성됨: $ISSUE_URL" + + if [ "${ASSIGN_COPILOT:-false}" = "true" ]; then + gh issue edit "$(basename "$ISSUE_URL")" --add-assignee "@copilot" \ + || echo "Copilot 배정에 실패했습니다 (수동 배정이 필요할 수 있습니다)." + fi diff --git a/README.md b/README.md index eb13762..55939ff 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,15 @@ dotnet run .\src\checksites.cs issue .\health-report\\ 자동 검출과 사람 판정의 분리, GitHub 이슈 자동 등록, AI 어시스트(Claude Code 등)를 활용한 후속 카탈로그 갱신 방법은 [docs/SITE_HEALTH_WORKFLOW.md](docs/SITE_HEALTH_WORKFLOW.md)를 참고하세요. +#### AI 에이전트 기반 카탈로그 품질 관리 (자동 이슈 등록) + +카탈로그 검사 도구에서 발견되는 오류를 GitHub 이슈로 자동 등록하고, AI 에이전트(Copilot 코딩 에이전트·Claude Code 등)의 도움을 받아 해결하는 워크플로가 준비되어 있습니다. 검출은 자동, 최종 판정과 카탈로그 반영(merge)은 사람이 담당합니다. + +- **[`.github/workflows/catalog-quality.yml`](.github/workflows/catalog-quality.yml)**: `checkimages.cs`·`catalogutil.cs`를 주기적으로 실행하여 발견된 오류를 하나의 추적 이슈로 등록/갱신하고, 문제가 해소되면 자동으로 닫습니다. +- **[`.github/workflows/savings-bank-merger-watch.yml`](.github/workflows/savings-bank-merger-watch.yml)**: 통폐합이 잦은 저축은행 업계를 대상으로, 매월 AI 에이전트에게 업계 통폐합 뉴스 조사를 위임하는 이슈를 자동 생성합니다. + +두 워크플로의 전체 흐름과 AI 에이전트 작업 지침은 [docs/CATALOG_QUALITY_WORKFLOW.md](docs/CATALOG_QUALITY_WORKFLOW.md)를 참고하세요. + #### 제보 인테이크 스킬 (catalog-intake) GitHub에 익숙하지 않은 사용자를 위한 [Google Forms 제보](https://forms.gle/Pw6pBKhqF1e5Nesw6)를, **검토부터 카탈로그 수용까지 반자동으로 처리**하는 Claude Code 스킬입니다. [.claude/skills/catalog-intake/](.claude/skills/catalog-intake/)에 있으며, 그동안 수작업으로 처리하던 제보 반영을 자동화합니다. diff --git a/docs/CATALOG_QUALITY_WORKFLOW.md b/docs/CATALOG_QUALITY_WORKFLOW.md new file mode 100644 index 0000000..c5f6b19 --- /dev/null +++ b/docs/CATALOG_QUALITY_WORKFLOW.md @@ -0,0 +1,77 @@ +# AI 에이전트 기반 카탈로그 품질 관리 워크플로 + +이 문서는 카탈로그 검사 도구에서 발견되는 오류를 GitHub 이슈로 자동 등록하고, AI 에이전트(Copilot 코딩 에이전트 · Claude Code 등)의 도움을 받아 이를 해결하는 절차를 설명합니다. 아울러 통폐합이 잦은 저축은행 업계를 대상으로, AI 에이전트에게 업계 뉴스 조사를 위임하는 워크플로도 함께 다룹니다. + +전체 철학은 [사이트 헬스 워크플로](SITE_HEALTH_WORKFLOW.md)와 동일합니다 — **검출(detect)은 자동, 최종 판정과 카탈로그 반영(merge)은 사람**이 합니다. AI 에이전트는 검출·조사·초안 작성을 돕는 도구이지 판결자가 아닙니다. + +## 1. 카탈로그 품질 자동 검사 (`catalog-quality.yml`) + +카탈로그 검사 도구를 주기적으로 실행하여 발견된 오류를 하나의 추적(tracking) 이슈로 자동 등록/갱신합니다. + +### 트리거 + +- **스케줄**: 매주 월요일 00:00 UTC (한국시간 월요일 09:00) +- **수동 실행**: Actions 탭에서 `workflow_dispatch` + - `assign_copilot` 옵션을 켜면 생성/갱신된 추적 이슈를 Copilot 코딩 에이전트에 배정합니다. +- **푸시**: `docs/Catalog.xml` 또는 `docs/images/**` 변경이 `main`에 반영될 때 + +### 동작 + +1. [`checkimages.cs`](../src/checkimages.cs)로 누락/미사용 로고 이미지를 검출합니다. (오프라인, 결정론적) +2. [`catalogutil.cs`](../src/catalogutil.cs)로 XML 스키마 검증 및 URL 접속성 점검을 수행합니다. +3. 두 도구 중 하나라도 문제를 보고하면(비정상 종료 코드), 검사 리포트를 담은 **추적 이슈**를 생성하거나 기존 이슈를 갱신합니다. +4. 문제가 모두 해소되면 열려 있던 추적 이슈를 자동으로 닫습니다. + +이슈는 `catalog-quality` 라벨로 관리되며, **열려 있는 추적 이슈는 항상 최대 1건**입니다(중복 등록 방지). 이슈 본문에는 도구 출력 전문과 권장 조치, 재검증 명령이 포함되어 AI 에이전트가 바로 후속 작업에 착수할 수 있습니다. + +### AI 에이전트로 해결하기 + +추적 이슈를 Copilot 코딩 에이전트에 배정하거나, 이슈 본문을 Claude Code에 전달하세요. 이슈 본문의 권장 조치를 따라: + +- **누락된 이미지**: 해당 기관 공식 로고를 `docs/images//.png`로 추가 ([`fetchfavicon.cs`](../src/fetchfavicon.cs) 활용). +- **미사용 이미지**: 삭제된 서비스의 잔여 이미지라면 함께 제거. +- **스키마 오류**: `Catalog.xml`을 `Catalog.xsd`에 맞게 수정. + +수정 후 재검증: + +```bash +dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images +dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/ +``` + +## 2. 저축은행 통폐합 점검 (`savings-bank-merger-watch.yml`) + +저축은행 업계는 인수합병·통폐합·명칭변경·영업정지가 잦습니다. 이 워크플로는 매월 AI 에이전트에게 **"최근 저축은행 통폐합 뉴스"를 조사**하도록 위임하는 이슈를 자동 생성합니다. + +### 트리거 + +- **스케줄**: 매월 1일 00:00 UTC (한국시간 매월 1일 09:00) +- **수동 실행**: Actions 탭에서 `workflow_dispatch` (`assign_copilot` 옵션 지원) + +### 동작 + +1. `Catalog.xml`에서 이름에 "저축은행"이 포함된 서비스 항목을 모두 추출합니다. +2. 추출한 목록과 AI 에이전트 작업 지침을 담은 **조사 요청 이슈**를 생성합니다. (`savings-bank-merger-watch` 라벨) +3. 같은 달에 이미 조사 이슈가 열려 있으면 중복 생성하지 않습니다. + +### AI 에이전트의 역할 + +이슈에 배정된 AI 에이전트는 다음을 수행합니다. + +1. 카탈로그의 저축은행 목록을 기준으로 최근(지난 3~6개월) 국내 저축은행 통폐합/인수합병/명칭변경/폐업 뉴스를 검색 (금융감독원, [저축은행중앙회](https://www.fsb.or.kr/), 경제 뉴스 등). +2. 확인된 변경 건마다 대상 기관, 변경 유형, **출처 URL**, 시점, 반영 방향(URL 교체 / 명칭·Id 갱신 / 삭제 / 신규 추가)을 정리. +3. [`checksites.cs`](../src/checksites.cs) `probe`로 대상 사이트 상태를 검증. +4. 근거(출처 URL 포함)와 함께 이슈에 제안하고, 승인 후 PR로 처리. + +> **자동 삭제 금지**: 폐업·통폐합으로 항목 삭제가 필요한 경우 반드시 사람의 승인을 받으세요. + +## 자동 vs 사람 판정 경계선 + +| 단계 | 자동 | 사람/승인 필요 | +|------|:---:|:---:| +| 도구 실행 및 문제 검출 | ✓ | | +| 이슈 등록/갱신/종료 | ✓ | | +| 뉴스 조사·초안 작성 (AI) | ✓ | | +| 이미지 추가 (누락 보완) | ✓ | | +| 항목 삭제 / Id 변경 / 통폐합 반영 | | ✓ | +| PR 병합(merge) | | ✓ |