Skip to content

fix: #102, #103 수정사항 반영#105

Open
hon2be wants to merge 20 commits intoNomaDamas:devfrom
hon2be:feature/k-schoollunch-menu
Open

fix: #102, #103 수정사항 반영#105
hon2be wants to merge 20 commits intoNomaDamas:devfrom
hon2be:feature/k-schoollunch-menu

Conversation

@hon2be
Copy link
Copy Markdown
Contributor

@hon2be hon2be commented Apr 10, 2026

수정내용


  • 환경변수 누락 방지용 안내문 추가
- 머지 충돌시 병합 실수로 인한 빌드 불가 문제 수정
  • /v1/household-waste/info에 pageNo·numOfRows 필수, 값은 1·100만 허용(미충족·비정수 문자열은 400)
  • validate-skills.sh에서 .cursor·.vscode 디렉터리 제외
  • household-waste·k-skill-proxy 문서, 스킬, 패키지 README에 NEIS·생활쓰레기 curl 예시 정리

왜


  • 필요 최소한의 데이터만 찾도록 pageNo·numOfRows 값 고정

  • proxy 구성시 필요데이터 누락 방지를 위한 md 파일 내 설명 추가

  • 빌드 불가로 인한 테스팅 실패 수정

  • 명확히 스킬에 해당하는 내용만 반영되도록 validate-skills.sh에서 .cursor·.vscode 디렉터리 제외



테스트내용

기타 (main 브랜치 반영 필요)


  • 환경변수 누락 방지용 안내문 추가.
  • /v1/household-waste/info에 pageNo·numOfRows 필수, 값은 1·100만 허용(미충족·비정수 문자열은 400)
  • validate-skills.sh에서 .cursor·.vscode 디렉터리 제외
  • household-waste·k-skill-proxy 문서, 스킬, 패키지 README에 NEIS·생활쓰레기 curl 예시 정리

    이 건은 누락되지 않게 메인에도 동일하게 해당부분 수정 후 PR 드리겠습니다.

Co-Authored-By: Cursor (Sonnet 4.6)

hyeongr and others added 17 commits April 7, 2026 19:35
생활쓰레기 조회 스킬 문서와 기능 가이드를 추가하고, 프록시 라우트를 구현해 조회 흐름을 완성했다. 설치/설정 문서도 스킬 사용 흐름에 맞게 정리했다.

Made-with: Cursor
…x SKILL.md newline

- Drop user-supplied returnType and force "json" upstream so the cache key
  (which omits returnType) cannot be poisoned by alternate response shapes.
- Add server tests covering: missing SGG_NM (400), missing API key (503),
  serviceKey injection + cache hit on second call, returnType=xml override
  ignored, upstream non-200 surfaced as 502.
- Add trailing newline to household-waste-info/SKILL.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vkehfdl1's review on PR NomaDamas#82: skill/docs claimed support for
cond[DAT_CRTR_YMD::*] / cond[DAT_UPDT_PNT::*] filters and an optional
returnType, but the proxy only forwards pageNo, numOfRows, and
cond[SGG_NM::LIKE], and forces returnType=json. Typical user queries
("강남구 쓰레기 배출 요일") only need 시군구 검색, so shrink the
documented contract to match the proxy instead of widening pass-through.

- household-waste-info/SKILL.md: list only proxy-supported params, note
  returnType is server-forced, fix failure modes.
- docs/features/household-waste-info.md: switch base example to the
  proxy route, drop the bare upstream curl, call out unsupported
  filters explicitly.
- docs/install.md, docs/security-and-secrets.md, k-skill-setup/SKILL.md:
  describe the skill as calling the proxy /v1/household-waste/info
  route rather than the raw upstream endpoint.
The 인증/시크릿 column mixed user-side credentials, proxy URL hints,
and "use this fallback" notes — confusing for end users who only need
to know "do I have to log in or not?". Operator-managed secrets that
ship in k-skill-proxy are not the user's problem.

- Rename column to "사용자 로그인" with a one-line preface explaining
  the new contract.
- Reclassify proxy-fronted skills (서울 지하철, 한강 수위, 부동산,
  생활쓰레기, 가장 싼 주유소, 한국 법령 remote endpoint) to 불필요.
- Only SRT, KTX, 토스증권 keep 필요 (real per-user account login).
- Tighten the household-waste-info row to use the proxy-route phrasing
  consistent with the rest of the docs in this PR.
- Update skill-docs tests to assert the new binary classification for
  서울 지하철 and 한국 법령 rows.
The 설명 column was leaking implementation details — k-skill-proxy
routing notes, upstream package names, anti-bot helper mentions —
that don't help a user decide whether the skill does what they want.

Rewrite each row to state only "what this skill does for the user",
dropping references to k-skill-proxy, upstream library names
(real-estate-mcp, kakaocli, daiso-mcp, coupang-mcp, tossctl,
korean-law-mcp, Dynapath helper, Kakao Map anchor, Opinet, etc.) and
proxy route paths. The 사용자 로그인 column already captures the
"do I need credentials?" question, so the description is free to
focus on the capability itself.
- KEDU_INFO_KEY로 /v1/neis/school-search, /v1/neis/school-meal 중계
- 시도교육청 자연어 해석(neis-office-codes.js)
- k-schoollunch-menu 스킬, README·설치/설정/보안·프록시 문서 반영
- docs/adding-a-skill.md 스킬 추가 가이드

Made-with: Cursor
- upstream 생활쓰레기 프록시/스킬·skill-docs 변경 반영
- README 표에 학교 급식 행 복원, security에 KEDU_INFO_KEY·household 라우트 문구 정리
- NEIS 프록시 단위 테스트 블록 복원

Made-with: Cursor
The existing school lunch feature branch was mergeable in shape, but review
found that the public household-waste route still forwarded unchecked
pagination inputs, user-facing secrets docs suggested storing a server-only
KEDU key locally, and the proxy/operator docs omitted the new
household-waste env requirements. This follow-up validates the public query
surface before fetch, aligns docs with the proxy-only secret policy, and
keeps the requested validation workflow green by ignoring hidden metadata
folders in the skill-layout checker.

Constraint: Public proxy routes must stay narrow and keep upstream keys server-only
Rejected: Forward arbitrary pageNo values | violates the documented public-route contract
Rejected: Leave validate-skills unchanged | hidden metadata directories break the requested verification flow
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep household-waste parameter support and docs/tests in lockstep when widening this route
Tested: npm run lint
Tested: npm run typecheck
Tested: node --test packages/k-skill-proxy/test/server.test.js
Tested: node --test scripts/skill-docs.test.js
Tested: bash scripts/validate-skills.sh
Tested: local proxy smoke (/health, household-waste invalid 400, household-waste valid 200)
Not-tested: Live NEIS curl smoke test (KEDU_INFO_KEY unavailable locally)
Issue #0's core proxy and NEIS changes were already present on feature/#0, but the
setup guide still omitted the hosted/self-host household-waste entry that users
need when checking which features require local secrets. Add a regression test
first, then document the household-waste row and guide link so the setup matrix
stays aligned with the shipped proxy routes.

Constraint: Keep the follow-up diff narrow and avoid touching already-approved proxy behavior
Rejected: Leave the setup matrix as-is | it would keep user-facing docs inconsistent with the shipped route list
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When proxy-backed skills move between hosted and self-host flows, update docs/setup.md alongside the feature docs
Tested: node --test scripts/skill-docs.test.js
Tested: npm run lint
Tested: npm run typecheck
Tested: node --test packages/k-skill-proxy/test/server.test.js
Tested: bash scripts/validate-skills.sh
Not-tested: Live hosted proxy deployment docs rendering on GitHub
The setup guide already described proxy-hosted household-waste and NEIS flows elsewhere, but the opening summary still omitted school lunch from the no-user-key hosted-proxy list. This adds a regression test first, then aligns the intro sentence and test label so the doc stays consistent with the shipped proxy-backed feature set.

Constraint: Keep the follow-up scoped to existing Issue #0/PR NomaDamas#103 documentation surfaces
Rejected: Broader setup guide rewrite | unnecessary for the approved follow-up
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep hosted-proxy/no-user-key summaries aligned with the per-feature setup matrix when adding new proxy-backed skills
Tested: Targeted red/green skill-docs regression; npm run lint; npm run typecheck; node --test packages/k-skill-proxy/test/server.test.js; bash scripts/validate-skills.sh; node --test scripts/skill-docs.test.js; buildServer runtime smoke for /health, household-waste validation, and NEIS missing-key behavior
Not-tested: Live NEIS upstream call with a real KEDU_INFO_KEY
Related: PR NomaDamas#102
Related: PR NomaDamas#103
The approved PR NomaDamas#103 follow-up extends the setup-doc regression
coverage so it checks the hosted KSKILL_PROXY_BASE_URL guidance and
both household-waste + school-lunch setup entries, then updates the
guide text to match the shipped hosted-proxy behavior.

Constraint: Must stay within the approved PR NomaDamas#103 follow-up scope
Rejected: Broader setup-doc wording sweep across unrelated features | unnecessary for this approved follow-up
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep docs/setup.md and scripts/skill-docs.test.js aligned whenever hosted proxy coverage changes
Tested: node --test scripts/skill-docs.test.js
Tested: npm run lint
Tested: npm run typecheck
Tested: node --test packages/k-skill-proxy/test/server.test.js
Tested: bash scripts/validate-skills.sh
Tested: local buildServer(...).inject(...) smoke for /health and household-waste pagination
Not-tested: Live NEIS curl smoke with a real KEDU_INFO_KEY
The feature/#0 follow-up already had the proxy/runtime fixes in place,
but the branch still needed the final regression locks and doc wording
that keep the review fixes durable. This commit adds lower-bound
household-waste pagination tests and aligns install/security docs with
the proxy-only KEDU_INFO_KEY policy so the school lunch feature stays
on the hosted-proxy / no-user-key path.

Constraint: Follow-up had to stay on feature/#0 so PR NomaDamas#103 updates in place
Constraint: User-facing secrets guidance must not imply KEDU_INFO_KEY belongs in the default client env file
Rejected: Broaden the pass into more proxy/doc rewrites | unnecessary beyond the approved Issue #0 follow-up
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep school lunch docs and regression text aligned with the hosted proxy policy whenever setup/security wording changes
Tested: npm run lint; npm run typecheck; node --test packages/k-skill-proxy/test/server.test.js; bash scripts/validate-skills.sh; node --test scripts/skill-docs.test.js; local proxy smoke for /health, invalid household-waste 400, valid household-waste 200, NEIS without KEDU_INFO_KEY 503
Not-tested: Live NEIS curl against a valid KEDU_INFO_KEY-enabled proxy
Related: PR NomaDamas#102
Related: PR NomaDamas#103
The setup skill had drifted behind docs/setup.md after the household-waste
and school-lunch proxy follow-ups. This updates the skill guidance and locks it
with a regression so future doc edits keep the hosted-proxy and server-only-key
story consistent across the user-facing setup surfaces.

Constraint: Follow-up scope is limited to the approved docs/setup consistency gap from PR NomaDamas#103 review
Rejected: Broad setup-doc sweep | unnecessary beyond the approved drift fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep k-skill-setup/SKILL.md aligned with docs/setup.md whenever hosted proxy coverage changes
Tested: npm run lint; npm run typecheck; node --test packages/k-skill-proxy/test/server.test.js; bash scripts/validate-skills.sh; node --test scripts/skill-docs.test.js; local buildServer smoke for /health and household-waste pagination
Not-tested: Live upstream NEIS/Data.go.kr network calls with real server credentials
Related: PR NomaDamas#103
- /v1/household-waste/info에 pageNo·numOfRows 필수, 값은 1·100만 허용(미충족·비정수 문자열은 400)
- validateHouseholdWastePaginationQuery 오동작 수정
- validate-skills.sh에서 .cursor·.vscode 디렉터리 제외
- household-waste·k-skill-proxy 문서, 스킬, 패키지 README에 NEIS·생활쓰레기 curl 예시 정리

Made-with: Cursor
- setup.md·k-skill-setup: 생활쓰레기/급식을 기본 hosted·unset base URL 문구에 포함, 서버 키(DATA_GO_KR·KEDU) 명시
- 표·다음 문서: 생활쓰레기 행·가이드 링크, pageNo/numOfRows 필수
- proxy README·feature doc·household-waste 스킬: 키·페이지네이션·400 계약 보강
- skill-docs.test.js: hosted 생활쓰레기/급식 흐름 회귀 테스트, 예시 secrets에 KEDU_INFO_KEY 금지

Made-with: Cursor
@vkehfdl1
Copy link
Copy Markdown
Contributor

REQUEST CHANGES

/v1/household-waste/info validation still has one blocking hole in the new path.

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:1559-1584
    cond[SGG_NM::LIKE] is treated as a string and .trim() is called directly, but Fastify will parse repeated query params as an array. With a request like
    GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&cond[SGG_NM::LIKE]=서초구&pageNo=1&numOfRows=100
    the handler throws TypeError: sggNm.trim is not a function and returns 500 / proxy_error instead of the documented 400 validation response. Since this PR is tightening the household-waste contract, I think this should be normalized/rejected explicitly and covered by a regression test before merge.

Real Result

  • npm ci
  • npm test
  • npm run lint
  • Direct runtime repro on the checked-out PR branch:
    • invalid pagination: 400 bad_request as expected
    • ambiguous NEIS office (educationOffice=경상): 400 ambiguous_education_office as expected
    • duplicated cond[SGG_NM::LIKE]: 500 proxy_error with sggNm.trim is not a function (unexpected)

Fastify parses repeated query parameters as arrays, so the household-waste
normalizer now rejects repeated scalar fields before any upstream request.
This adds a regression test for duplicated cond[SGG_NM::LIKE] values and keeps
invalid requests on the documented 400 bad_request path.

Constraint: Household-waste validation must fail before any upstream fetch
Rejected: Join repeated query values into one filter | ambiguous request semantics
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep repeated scalar query params on the 400 path unless the public contract is expanded intentionally
Tested: node --test packages/k-skill-proxy/test/server.test.js; npm test; npm run lint; npm run typecheck; local proxy smoke on duplicated cond[SGG_NM::LIKE]
Not-tested: Live household-waste upstream success path with a real DATA_GO_KR_API_KEY
@vkehfdl1 vkehfdl1 mentioned this pull request Apr 10, 2026
@vkehfdl1
Copy link
Copy Markdown
Contributor

수정 반영했습니다.

  • /v1/household-waste/info에서 cond[SGG_NM::LIKE] 중복 전달 시 배열로 파싱되더라도 500이 아니라 400 bad_request로 명시적으로 거절하도록 고쳤습니다.
  • 같은 scalar query 검증 경로를 pageNo, numOfRows에도 재사용해 중복 값이 upstream까지 전달되지 않게 정리했습니다.
  • 회귀 테스트를 추가해 duplicated cond[SGG_NM::LIKE] 요청이 upstream fetch 전에 400으로 막히는 것을 고정했습니다.
  • 검증: npm run lint, npm run typecheck, npm run test, 로컬 서버 + curl로 duplicated cond[SGG_NM::LIKE] 요청 400 확인.
  • 반영 브랜치/PR: feature/#0 / PR Feature/#0 #103 (dev 대상).

@vkehfdl1
Copy link
Copy Markdown
Contributor

중복 cond[SGG_NM::LIKE] 쿼리 파라미터가 500으로 터지던 경로를 400 검증 실패로 막도록 보완했습니다.

  • packages/k-skill-proxy/src/server.js에서 반복되면 안 되는 scalar query 값(cond[SGG_NM::LIKE], pageNo, numOfRows)을 배열로 받으면 즉시 400 경로로 거절하도록 정규화 로직을 보강했습니다.
  • packages/k-skill-proxy/test/server.test.js에 duplicated cond[SGG_NM::LIKE] 회귀 테스트를 추가해 upstream fetch 없이 bad_request를 반환하는지 고정했습니다.
  • 검증: npm run lint, npm run typecheck, npm run test, 로컬 proxy smoke test(cond[SGG_NM::LIKE] 중복 요청 시 400 확인)

@vkehfdl1
Copy link
Copy Markdown
Contributor

REQUEST CHANGES

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:1559-1563,1581-1583,1610
    The previous blocking issue is still reproducible on the current PR branch. query["cond[SGG_NM::LIKE]"] is still treated as a scalar and .trim() is called directly. Fastify parses repeated query params as arrays, so a request like
    GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&cond[SGG_NM::LIKE]=서초구&pageNo=1&numOfRows=100
    still throws TypeError: sggNm.trim is not a function and returns 500 proxy_error instead of the documented 400 bad_request.

  • HIGH (blocking)packages/k-skill-proxy/test/server.test.js:1824-2028
    The new household-waste coverage exercises missing/invalid pagination and returnType, but it still does not lock the duplicated cond[SGG_NM::LIKE] regression. That is why the full suite stays green while the runtime path above still fails.

Real Result

  • npm run lint
  • npm run typecheck
  • npm run test
  • Direct runtime repro on the checked-out PR branch:
    • request: duplicated cond[SGG_NM::LIKE] with pageNo=1&numOfRows=100
    • result: 500
    • body: {"error":"proxy_error","message":"sggNm.trim is not a function"}
    • stack points to packages/k-skill-proxy/src/server.js:1561

So from this round's verification, the prior blocking issue is not fixed yet.

Review follow-up found that mixed alias pagination params could still bypass the narrowed public route contract even after duplicate scalar handling was added. This tightens the query normalizer so pageNo/page_no and numOfRows/num_of_rows must appear exactly once and match the fixed allowed values, expands regression coverage for those alias combinations, and aligns the public docs/examples with the exact pageNo=1 + numOfRows=100 contract. The household-waste test setup was also de-duplicated within the scoped suite to keep the follow-up readable without widening behavior.

Constraint: The public household-waste proxy route must stay narrow and reject ambiguous scalar query shapes before any upstream fetch
Rejected: Keep alias resolution as first-non-null | mixed pageNo/page_no and numOfRows/num_of_rows would still bypass the documented 400 path
Rejected: Broaden the route to support alternate page sizes | outside the approved issue scope and contrary to the fixed-value contract
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep household-waste docs and regression tests aligned whenever the allowed query surface changes, including alias handling
Tested: node --test packages/k-skill-proxy/test/server.test.js
Tested: node --test scripts/skill-docs.test.js
Tested: npm run lint
Tested: npm run typecheck
Tested: npm run test
Tested: local proxy smoke on port 4121 for mixed pageNo/page_no 400, mixed numOfRows/num_of_rows 400, and returnType override reaching upstream with fixed pagination
Not-tested: Live successful household-waste upstream response with a real DATA_GO_KR_API_KEY
@vkehfdl1
Copy link
Copy Markdown
Contributor

중복/별칭 household-waste 쿼리 검증 누락을 마저 막았습니다.

  • packages/k-skill-proxy/src/server.js에서 pageNo/page_no, numOfRows/num_of_rows, cond[SGG_NM::LIKE] 같은 scalar query가 중복되거나 mixed alias로 함께 오면 upstream fetch 전에 즉시 400 bad_request로 거절하도록 보강했습니다.
  • /v1/household-waste/infopageNo=1, numOfRows=100만 허용하도록 고정했고, 관련 회귀 테스트를 mixed alias 케이스까지 추가했습니다.
  • household-waste / proxy 문서와 README 예시를 동일 계약(pageNo=1, numOfRows=100, NEIS curl 예시 포함)으로 정리했고, scripts/skill-docs.test.js로 문서 계약도 고정했습니다.

검증:

  • node --test packages/k-skill-proxy/test/server.test.js
  • node --test scripts/skill-docs.test.js
  • npm run lint
  • npm run typecheck
  • npm run test
  • 로컬 서버 smoke: mixed pageNo/page_no 400, mixed numOfRows/num_of_rows 400, duplicated cond[SGG_NM::LIKE] 400 확인

@vkehfdl1
Copy link
Copy Markdown
Contributor

REQUEST CHANGES

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:1559-1563,1581-1583,1610
    query["cond[SGG_NM::LIKE]"] is still treated as a scalar and .trim() is called directly. Fastify parses repeated query params as arrays, so duplicated cond[SGG_NM::LIKE] still crashes before the 400 validation path and returns 500 proxy_error instead of the documented 400 bad_request.

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:857-892, packages/k-skill-proxy/test/server.test.js:1824-2034, docs/features/household-waste-info.md:30, household-waste-info/SKILL.md:63-64, docs/features/k-skill-proxy.md:159
    The pagination validator still does query.pageNo ?? query.page_no and query.numOfRows ?? query.num_of_rows, so conflicting mixed-alias scalar params are silently accepted instead of being rejected. That means requests like pageNo=1&page_no=99 or numOfRows=100&num_of_rows=5 still reach upstream, even though the docs say these inputs should be rejected with 400 before any upstream call. The new tests still do not cover duplicate/mixed-alias scalar cases, which is why the suite stays green while the runtime contract is still broken.

Real Result

  • npm run lint
  • npm run typecheck
  • node --test packages/k-skill-proxy/test/server.test.js scripts/skill-docs.test.js
  • Local server repro (KSKILL_PROXY_PORT=4123 DATA_GO_KR_API_KEY=test-key node packages/k-skill-proxy/src/server.js):
    • duplicated cond[SGG_NM::LIKE] + pageNo=1&numOfRows=100500 {"error":"proxy_error","message":"sggNm.trim is not a function"}; Fastify log stack points to packages/k-skill-proxy/src/server.js:1561
    • conflicting pageNo=1&page_no=99&numOfRows=100502 upstream_error, proving the request was not rejected locally
    • conflicting pageNo=1&numOfRows=100&num_of_rows=5502 upstream_error, same issue
    • control checks: pageNo=99&numOfRows=5 still returns 400 as expected, and /v1/neis/school-search?educationOffice=경상&schoolName=중학교 returns 400 ambiguous_education_office as expected

RECOMMENDATION: REQUEST CHANGES

@vkehfdl1
Copy link
Copy Markdown
Contributor

REQUEST CHANGES

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:1559-1561
    The original blocking hole is still live on the current PR branch. query["cond[SGG_NM::LIKE]"] is still treated as a scalar and .trim() is called directly, so Fastify's repeated-query array form still crashes the handler instead of returning the documented validation error. On the checked-out branch I reproduced:
    GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&cond[SGG_NM::LIKE]=서초구&pageNo=1&numOfRows=100
    500 {"error":"proxy_error","message":"sggNm.trim is not a function"}
    That needs to be normalized/rejected before .trim() and locked with a regression test before merge.

  • HIGH (blocking)packages/k-skill-proxy/src/server.js:861-862, packages/k-skill-proxy/src/server.js:1558-1561
    The claimed mixed-alias rejection is also not implemented on this branch. validateHouseholdWastePaginationQuery() still uses query.pageNo ?? query.page_no and query.numOfRows ?? query.num_of_rows, so conflicting duplicates are silently accepted instead of rejected. I verified with a stubbed fetch on the checked-out branch:
    GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&pageNo=1&page_no=9&numOfRows=100&num_of_rows=9
    200, upstream fetch executed once, response query payload still reports page_no: "1", num_of_rows: "100".
    That contradicts the implementation note in the thread (“mixed alias로 함께 오면 … 400”) and means clients can still send ambiguous scalar input without getting the advertised 400 bad_request.

  • HIGH (blocking)packages/k-skill-proxy/test/server.test.js:1824-2015
    The household-waste suite is still green because it never exercises either of the two blocking cases above. There is coverage for missing/invalid pagination, fixed pageNo=1&numOfRows=100, and returnType, but no regression test for duplicated cond[SGG_NM::LIKE] arrays and no test for mixed pageNo/page_no or numOfRows/num_of_rows. Until those are added, the suite will keep missing the runtime failures I reproduced.

Real Result

  • node --test packages/k-skill-proxy/test/server.test.js ✅ (56/56 passing)
  • Direct runtime repro on the checked-out PR branch:
    • duplicated cond[SGG_NM::LIKE] + pageNo=1&numOfRows=100500 proxy_error / sggNm.trim is not a function
    • mixed alias pageNo=1&page_no=9&numOfRows=100&num_of_rows=9200, upstream fetch still runs once

So from this round's real verification, the household-waste validation tightening described in the PR body/thread is still not actually enforced on the current branch.

@vkehfdl1
Copy link
Copy Markdown
Contributor

중복/별칭 household-waste 쿼리 검증 누락이 이미 feature/#0에 반영되어 있는 것을 기준으로 다시 검증했습니다.

  • packages/k-skill-proxy/src/server.jsnormalizeHouseholdWasteInfoQuery()cond[SGG_NM::LIKE] 단일값 검증과 pageNo/page_no, numOfRows/num_of_rows 고정값 검증을 공통 helper로 처리해, 중복 배열·mixed alias 입력을 upstream fetch 전에 400 bad_request로 막습니다.
  • packages/k-skill-proxy/test/server.test.js에 duplicated cond[SGG_NM::LIKE], duplicated pageNo, mixed pageNo/page_no, mixed numOfRows/num_of_rows 회귀 테스트가 들어가 있어 동일 문제가 다시 열리지 않도록 고정돼 있습니다.
  • 문서도 같은 계약으로 정렬돼 있습니다: docs/features/household-waste-info.md, docs/features/k-skill-proxy.md, household-waste-info/SKILL.md, packages/k-skill-proxy/README.md, scripts/skill-docs.test.js.

검증:

  • npm run lint
  • npm run typecheck
  • npm run test
  • 로컬 서버 smoke (KSKILL_PROXY_PORT=4123 DATA_GO_KR_API_KEY=test-key node packages/k-skill-proxy/src/server.js)
    • duplicated cond[SGG_NM::LIKE]400 bad_request
    • mixed pageNo/page_no400 bad_request
    • mixed numOfRows/num_of_rows400 bad_request
  • 추가 architect review: APPROVED

@vkehfdl1
Copy link
Copy Markdown
Contributor

REJECT

Short reason: the household-waste validation tightening described in the PR is still not enforced on the current PR head d3d048e82291eb87b415efe9d67ee52e932b4575.

Real Result

  • npm run lint
  • npm run typecheck
  • node --test packages/k-skill-proxy/test/server.test.js ✅ (56/56)
  • Actual runtime verification on the checked-out PR head via buildServer() + stubbed global.fetch:
    • GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&cond[SGG_NM::LIKE]=서초구&pageNo=1&numOfRows=100
      • 500 {"error":"proxy_error","message":"sggNm.trim is not a function"}
      • Fastify stack points to packages/k-skill-proxy/src/server.js:1561
      • upstream fetch calls: 0
    • GET /v1/household-waste/info?cond[SGG_NM::LIKE]=강남구&pageNo=1&page_no=9&numOfRows=100&num_of_rows=9
      • 200
      • upstream fetch calls: 1
      • captured upstream URL still sent pageNo=1&numOfRows=100, so conflicting alias input was silently accepted instead of being rejected with local 400 bad_request
  • Code on this branch still matches the failing behavior:
    • packages/k-skill-proxy/src/server.js:857-860 still uses query.pageNo ?? query.page_no / query.numOfRows ?? query.num_of_rows
    • packages/k-skill-proxy/src/server.js:1559-1561 still reads query["cond[SGG_NM::LIKE]"] and calls .trim() directly
    • packages/k-skill-proxy/test/server.test.js household-waste coverage still does not lock duplicated cond[SGG_NM::LIKE] or mixed alias scalar regressions, which is why the suite stays green while the runtime contract is broken

Recommendation: keep this blocked until duplicated scalar arrays and mixed alias duplicates are rejected with 400 bad_request before any upstream fetch, and add regression tests for those cases.

NEIS 급식·생활쓰레기 프록시·문서·skill-docs 테스트 정렬 충돌을 해소했다.

Made-with: Cursor
@hon2be
Copy link
Copy Markdown
Contributor Author

hon2be commented Apr 11, 2026

검증 환경

  • 브랜치: feature/k-schoollunch-menu (로컬 HEAD 기준)
  • 명령: npm run test (전체 스위트)

테스트 결과

  • scripts/skill-docs.test.js: 103 pass / 0 fail
  • packages/k-skill-proxy/test/server.test.js: 105 pass / 0 fail
  • Python 유닛 스위트 (4개): pass
  • workspace packages (kleague, lck-analytics 등): pass
  • 전체 fail=0

핵심 검증 항목

생활쓰레기 /v1/household-waste/info 쿼리 검증

  • cond[SGG_NM::LIKE] 중복(배열) → 400, upstream 미호출 ✅
  • pageNo 비정수(abc 등) → 400 ✅
  • pageNo != 1 → 400 ✅
  • numOfRows != 100 → 400 ✅
  • pageNo + page_no 혼용 → 400 ✅
  • numOfRows + num_of_rows 혼용 → 400 ✅
  • returnType=json 강제 (클라이언트 override 무시) ✅

NEIS 급식·학교검색

  • KEDU_INFO_KEY 미설정 → 503 upstream_not_configured ✅
  • schoolName 누락 → 400 ✅
  • ambiguous_education_office → 400 + candidate_codes ✅
  • 캐시 hit/miss 동작 ✅
  • /health neisSchoolMealConfigured 필드 ✅

문서·보안 정합성

  • KEDU_INFO_KEY, DATA_GO_KR_API_KEY 모두 secrets.env.example 미포함 ✅
  • 전 문서(install, setup, security, SKILL.md)에서 두 키가 프록시 서버 전용이라는 서술 일치 ✅
  • KSKILL_PROXY_BASE_URL 미설정 시 hosted default 안내 일치 ✅
  • skill-docs.test.js가 위 계약을 회귀 테스트로 잠금 ✅

기타

  • 이전 PR들에서 feature/#0 을 머지해야 하는 것처럼 써져 있어, 머지후 재작업 했습니다.
  • 앞으로 Reject 이 있으면 claude를 통해 한번 더 검증하고 올리겠습니다. 일단 지금은 에이전트 통해서 프롬프트를 추천받아 돌렸는데 혹시 추천하는 프롬프트 있으시면 공유 부탁 드립니다.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants