* Add Seoul Bike live station lookup
Expose narrow Seoul Open Data proxy surfaces for realtime bike availability, station master pages, and coordinate-based nearby lookups while keeping the upstream key server-side. Add a single Python skill entrypoint plus docs so agents can answer last-mile bike and dock availability questions.
Constraint: Issue #274 requires , TDD, three proxy routes, branch feature/#274, and PR to dev.
Rejected: Client-side Seoul OpenAPI key handling | would leak upstream credentials and violate existing proxy patterns.
Confidence: high
Scope-risk: moderate
Directive: Keep these routes read-only; do not add rental/booking mutations or user-key requirements.
Tested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; local fake-proxy smoke run; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg08RBix6:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci.
Not-tested: Live hosted Seoul Open Data request with production SEOUL_OPEN_API_KEY.
* Prevent Seoul Bike upstream errors from masquerading as empty availability
Constraint: Seoul Open API can return application-level error JSON with HTTP 200, so proxy routes must inspect RESULT envelopes before caching or normalizing rows.
Rejected: Treating missing rentBikeStatus.row as an empty success | it masks quota/service failures and caches false no-station results.
Confidence: high
Scope-risk: narrow
Directive: Preserve non-cacheable proxy error behavior for Seoul Open API semantic failures across realtime, stations, and nearby routes.
Tested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; local fake-proxy seoul_bike.py nearby smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0j0fIum:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci; architect review APPROVED.
Not-tested: Live Seoul Open API error response from production service.
* Reject ambiguous Seoul Bike integer input
Tighten the public Seoul Bike query boundary so malformed integer strings cannot be partially parsed into valid requests.
Constraint: PR #277 review found parseInt accepted partially numeric query values on Seoul Bike routes.\nRejected: Keep parseInt with bounds checks | bounds still allow misleading values like 10abc and 1.5.\nConfidence: high\nScope-risk: narrow\nDirective: Keep Seoul Bike public query aliases strict; do not reintroduce partial numeric parsing.\nTested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; explicit app.inject invalid-query smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0uv50Mt:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci\nNot-tested: live hosted Seoul Open API traffic
* Protect hosted Seoul Bike proxy secrets
Sanitize Seoul Bike upstream fetch and parse failures before they can reach the global error handler, and reject blank nearby coordinates before JavaScript can coerce them to zero.\n\nConstraint: PR #277 round-3 review found server-side Seoul Open API keys could leak through exception messages containing keyed upstream URLs.\nRejected: Letting the global error handler format Seoul Bike upstream exceptions | it echoes exception messages and can expose the hosted proxy API key.\nConfidence: high\nScope-risk: narrow\nDirective: Keep server-side API-key-bearing upstream URLs out of client-visible error messages and logs for hosted no-user-key routes.\nTested: node --test packages/k-skill-proxy/test/server.test.js --test-name-pattern 'seoul bike'; PYTHONPATH=.:scripts python3 -m unittest scripts.test_seoul_bike; explicit app.inject smoke for sanitized Seoul Bike failures and blank coordinates; local fake-proxy seoul-bike nearby smoke; PATH="/Users/jeffrey/.pyenv/versions/3.11.9/bin:/Users/jeffrey/.codex/tmp/arg0/codex-arg0mxZmWx:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/jeffrey/.cmuxterm/omo-bin:/opt/homebrew/share/android-commandlinetools/platform-tools:/opt/homebrew/share/android-commandlinetools/emulator:/opt/homebrew/share/android-commandlinetools/cmdline-tools/latest/bin:/Users/jeffrey/.local/bin:/Users/jeffrey/.bun/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/opt/openjdk@21/bin:/opt/homebrew/opt/postgresql@18/bin:/Users/jeffrey/.jenv/shims:/Users/jeffrey/.jenv/bin:/opt/homebrew/opt/imagemagick/bin:/opt/homebrew/Cellar/pyenv-virtualenv/1.4.0/shims:/Users/jeffrey/.pyenv/shims:/opt/homebrew/opt/openssl@3/bin:/Users/jeffrey/.rbenv/shims:/Users/jeffrey/.rbenv/bin:/Users/jeffrey/google-cloud-sdk/bin:/Applications/cmux.app/Contents/Resources/bin:/Users/jeffrey/Library/pnpm:/Users/jeffrey/.nvm/versions/node/v24.13.0/bin:/Users/jeffrey/.cops/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/Library/Apple/usr/bin:/Library/TeX/texbin:/Users/jeffrey/.cargo/bin:/Users/jeffrey/Library/Application Support/JetBrains/Toolbox/scripts:/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin:/Users/jeffrey/xcode-projects/marshroom/cli" npm run ci.\nNot-tested: Live Seoul Open API network failure from production Cloud Run.
Add an E-Gen based emergency-room skill that resolves a user location, queries the public nearby emergency-room list, and reports operation flags while documenting that exact remaining bed counts are not exposed by this surface.
Constraint: Issue #255 requested NEMC emergency bed status using public monitoring/E-Gen surfaces.
Rejected: Scraping private monitoring dashboards or claiming exact bed utilization | public endpoints expose operation flags, not per-hospital remaining bed counts.
Confidence: high
Scope-risk: narrow
Directive: Preserve the public-data limitation text unless a verified official bed-count endpoint is added.
Tested: npm run lint --workspace emergency-room-beds; npm test --workspace emergency-room-beds; node --test scripts/skill-docs.test.js; npm run typecheck; npm pack --workspace emergency-room-beds --dry-run; ./scripts/validate-skills.sh; live E-Gen coordinate smoke.
Not-tested: npm run ci end-to-end due local Python 3.14 pip/pyexpat import error before tests.
Constraint: Issue #228 requires a skill that discovers latest report pages from the provided GitHub Pages mirror and makes them agent-readable.\nRejected: Screen-scraping GitHub Pages directory listings | the GitHub recursive tree API is a more stable public index.\nConfidence: high\nScope-risk: narrow\nDirective: Keep this skill on public unauthenticated GitHub/raw endpoints unless upstream starts requiring an API key; do not add a proxy route for public pages.\nTested: npm run lint --workspace daishin-report-search; npm run test --workspace daishin-report-search; npm pack --workspace daishin-report-search --dry-run; npm run ci; live CLI list/detail smoke tests.\nNot-tested: Authenticated GitHub API higher-rate-limit path.
Preserve the PR's workspace release coverage while keeping the newer manus bundle test entry from dev.\n\nConstraint: PR #233 was non-mergeable because package.json changed on both head and dev.\nRejected: Taking either side wholesale | would drop either gangnamunni pack coverage or manus bundle test coverage.\nConfidence: high\nScope-risk: narrow\nDirective: Keep additive package script conflicts merged rather than replacing workspace entries.\nTested: node JSON parse for package.json; git diff --check.\nNot-tested: Full npm run ci pending after merge commit.
Move KOSIS general lookups and Kakao Local geocoding behind k-skill-proxy so users do not need to manage those API keys for common skill flows. Keep KOSIS bigdata/direct calls user-keyed because userStatsId is account-specific.
Constraint: Free API proxy policy allows proxying upstreams that require API keys while keeping routes narrow, cache-backed, and public.
Rejected: Proxy ODsay transit routing | Basic quota is low, time-limited, and IP-whitelist-bound, so centralizing it would create quota and operations risk.
Confidence: high
Scope-risk: moderate
Directive: Keep KOSIS bigdata direct unless a per-user credential design is added; do not route broad Kakao surfaces without explicit allowlists and rate limits.
Tested: npm run ci; local KOSIS proxy smoke via /v1/kosis/search and /v1/kosis/meta; local Kakao proxy smoke via /v1/kakao-local/geocode q=서울역.
Not-tested: Production proxy deployment after main merge/cron update.
Address PR review blockers by aligning install docs, preserving raw Next.js JSON parsing semantics, bounding upstream fetches, and reducing sensitive query leakage in errors.\n\nConstraint: Issue #220 follow-up required TDD, full CI, live CLI smoke, deslop pass, push to feature/#220, and one signed PR comment.\nRejected: Pre-decoding the entire __NEXT_DATA__ script body before JSON.parse | corrupts valid JSON strings containing literal entity-looking text.\nConfidence: high\nScope-risk: narrow\nDirective: Keep entity-decoded parsing as a tested compatibility fallback only; do not make it the primary parse path.\nTested: npm test --workspace gangnamunni-clinic-search; node --test scripts/skill-docs.test.js; node packages/gangnamunni-clinic-search/src/cli.js "강남 성형외과" --limit 1; npm run ci twice, including post-deslop.\nNot-tested: Browser-rendered Gangnam Unni UI beyond the public Next.js payload smoke.
* Add public marathon schedule lookup
Implement a read-only Korean marathon schedule skill so agents can report event dates, venues, registration deadlines, and categories from public race pages, with best-effort triathlon coverage.
Constraint: Issue #211 requires 장소, 신청 마감일, 종목, and possible triathlon inclusion without interactive clarification.
Constraint: Public unauthenticated GoRunning and triathlon.or.kr surfaces do not require k-skill-proxy.
Rejected: Proxy route | upstream pages are public and need no API key, so proxying would violate the free API proxy inclusion rule.
Confidence: high
Scope-risk: moderate
Directive: Keep source parsing fail-soft with explicit warnings when one public source changes or is temporarily unavailable.
Tested: npm test --workspace korean-marathon-schedule; live CLI smoke for 고령 2026 triathlon category; npm run ci; architect verification approved.
Not-tested: Real-time coverage of every future race page variant across both upstream sites.
Co-authored-by: OmX <omx@oh-my-codex.dev>
* Keep marathon locations authoritative
Fix the reviewed GoRunning region inference bug by ranking event location fields ahead of full-page text, and remove the unrelated public SH notice proxy/skill surface so the PR remains inside the approved marathon scope and proxy policy.
Constraint: PR #222 review required TDD, full verification, and removal of public unauthenticated SH proxy routes before merge-readiness.
Rejected: Keeping /v1/sh-notice as a proxy route | violates the repository free-API proxy inclusion rule for public unauthenticated HTML.
Confidence: high
Scope-risk: narrow
Directive: Do not reintroduce public unauthenticated SH scraping through k-skill-proxy without an explicit documented policy exception.
Tested: npm test --workspace korean-marathon-schedule; node packages/korean-marathon-schedule/src/cli.js 용인 --from 2026-05-01 --to 2026-06-30 --limit 3; node packages/korean-marathon-schedule/src/cli.js 고령 --from 2026-01-01 --to 2026-12-31 --include-triathlon --limit 5; npm run lint --workspace k-skill-proxy; npm test --workspace k-skill-proxy; grep -RIn 'sh-notice\|i-sh.co.kr' README.md docs packages package.json package-lock.json .changeset; npm run ci; git diff --check; architect verification CLEAR.
Not-tested: None.
* Bound marathon schedule crawling to trusted sources
Fix review-round false negatives by continuing beyond the old pre-filter windows while adding an explicit per-source detail budget and warnings for partial crawls. Keep race detail traversal constrained to documented hosts and filter triathlon non-race rows before fetching details.\n\nConstraint: Review round required TDD, live verification, full CI, and preserving the public no-proxy source boundary.\nRejected: Exhaustive unbounded detail traversal | it maximizes recall but can over-crawl public list pages.\nConfidence: high\nScope-risk: narrow\nDirective: Keep future crawling changes host-allowlisted, budgeted, and warning-producing when partial.\nTested: npm test --workspace korean-marathon-schedule; npm run lint --workspace korean-marathon-schedule; node packages/korean-marathon-schedule/src/cli.js 고령 --from 2026-01-01 --to 2026-12-31 --include-triathlon --limit 5; node packages/korean-marathon-schedule/src/cli.js 용인 --from 2026-05-01 --to 2026-06-30 --limit 3; npm run ci; architect verification CLEAR.\nNot-tested: Live off-origin or malformed upstream HTML beyond mocked regressions.
* Honor explicit public crawl budgets
Keep broad triathlon searches bounded by applying one detail budget across selected year lists and exposing the same budget control in the CLI.
Constraint: PR #222 review requested shared triathlon crawl budget and CLI access to maxDetailsPerSource.
Rejected: Per-year triathlon budget counters | they can exceed the documented per-source crawl cap on multi-year ranges.
Confidence: high
Scope-risk: narrow
Directive: Keep public-source crawl caps source-scoped and documented when adding more list partitions.
Tested: npm test --workspace korean-marathon-schedule; npm run lint --workspace korean-marathon-schedule; live CLI 고령 smoke; CLI help grep; npm run ci; git diff --check; architect verification CLEAR
Not-tested: Live multi-year low-budget triathlon crawl against upstream beyond mocked regression.
---------
Co-authored-by: OmX <omx@oh-my-codex.dev>
* feat: add SH notice search skill
* fix(sh-notice): require srchTp for keyword search, parse real attachments, cap pageSize
- Default srchTp to title ("1") when srchWord is provided without an explicit
type. SH 게시판 ignores srchWord without srchTp and silently returns the full
list, so /v1/sh-notice/search?q=행복주택 was returning all 1608 notices.
- Rewrite parseAttachments to ignore icon-template anchors (.pdf, .hwp, ...)
and require existFile() onclick for real file rows. Multi-attachment notices
now expose every real attachment with the correct filename.
- Drop unverified download_hint field from attachment objects; preview_url
remains the only documented stable path.
- Cap pageSize at 10 to match the SH board's fixed page size and update docs
to direct callers to use the page parameter for more results.
- Add multiItmSeq digits-only validation and a 100-char keyword length cap to
bound cache cardinality.
- Add README, docs/install.md, packages/k-skill-proxy/README.md, and
docs/features/sh-notice-search.md entries to register the skill in the
repo's public surface.
Verified live against www.i-sh.co.kr:
- q=행복주택 → 96 hits (was 1608, unfiltered)
- seq=303994 → 11 real attachments with correct filenames (was 1 with '.pdf')
- pageSize=50 → caps at 10 with correct summary.page_size
- Validation errors return 400 with clear messages.
---------
Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
* feat: 국가데이터처 KOSIS 통계 조회(kosis-stats) 스킬 추가
KOSIS Open API 4개 endpoint(statisticsSearch / statisticsData getMeta /
statisticsParameterData / statisticsBigData) read-only 호출을 단일 Python
helper로 묶었다. 인증키는 KSKILL_KOSIS_API_KEY 환경변수(또는 기본
secrets.env)로 사용자별 발급한다 — proxy 미사용.
- kosis-stats/SKILL.md, scripts/run_kosis_stats.py: stdlib only,
search/meta/data/bigdata 서브커맨드, --json/--text/--dry-run
- kosis-stats/references/kosis-openapi-guide.md: 인증키 발급, 호출 한도
(분당 1000건/40k cells), 에러 코드, HTTPS 전용 정책 정리
- kosis-stats/tests/: stdlib unittest 36개, mock 기반 (네트워크 X) +
KSKILL_KOSIS_API_KEY 가 있을 때만 도는 라이브 smoke 1개
- docs/features/kosis-stats.md, README, install/setup/security-and-secrets/
sources, examples/secrets.env.example, package.json lint/test 등록
* fix(kosis-stats): 사용자 시나리오 e2e 검증 기반 UX 보강
4개 sonnet 서브에이전트 병렬 시나리오(단일수치/시계열/지역비교/실패회복)
검증에서 발견된 P1/P2 UX 부족함 보강. 4개 회복 시나리오 친절도 평균 2.75
→ 4.5 (S4c 코드 20 막힘 P1 해결).
- ERROR_CODE_HINTS: 코드 20/21/30/31 모두 next-step 명령 예시 포함
(코드 20은 ITM 메타 우선 안내 — 실제 표 다수에서 OBJ 비어 있음)
- render_search_text: Next 액션 흐름 안내 추가
- render_meta_text: 빈 결과 시 다른 --meta-type 시도 안내
- render_data_text: 빈 결과 시 필터/meta 재확인 안내,
새 [summary] 라인(rows/period/unit, UNIT_NM 누락 명시)
- SKILL.md Workflow: 코드 20 회복 절차, 행정구역 코드(시도 2자리/시군구
5자리) 관례 명시
- SKILL.md Failure modes: 코드 20 추가, meta 30 분기, UNIT_NM 누락 처리,
코드 20/31 회복 시나리오 예시
- docs/features/kosis-stats.md "흔한 문제 해결"에 코드 20 회복 절차 추가
- tests: 8개 회귀 테스트 추가 (hint 키워드/render 메시지/[summary] 라인)
* fix(kosis-stats): drop xls bigdata format and detect json error envelope in non-json formats
Reviewer follow-up on PR #216:
- Removes `xls` from bigdata --format choices. KOSIS returns xls as a
binary Excel payload, but the helper streams text-only output, which
would corrupt the file. json/sdmx/csv (text) remain supported.
- Detects KOSIS `{err, errMsg}` envelopes even when --format is csv/sdmx,
so non-json bigdata responses surface auth/limit errors instead of
printing a misleading error envelope as raw success output.
- Updates SKILL.md, references/kosis-openapi-guide.md, and
docs/features/kosis-stats.md so the advertised contract matches the
helper's actual capabilities.
- Adds 3 unit tests: xls rejection, json error envelope detection in csv
mode, and clean csv passthrough when no error envelope is present.
---------
Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
* Help donors choose verified recipients by place and cause
Add a read-only donation-place search skill and npm helper that ranks Korean donation recipients by user-provided location/category while keeping final verification on official 1365 and recipient pages. The implementation avoids proxy routes because the chosen verification surface is public and does not require an API key.
Constraint: Issue #212 requested 기부처 조회 recommendations by place and category under TDD with a PR to dev.
Constraint: k-skill free API proxy policy allows proxying only when upstream requires API keys; 1365 verification links are public.
Rejected: Screen-scraping 1365 result pages | headless requests were slow/unstable and would be brittle for a recommendation helper.
Rejected: Treating general-purpose charities as matches for every requested category | architect review found it could return off-category results, so matching now requires explicit category tags.
Confidence: high
Scope-risk: narrow
Directive: Do not add automatic donation/payment submission; keep this skill read-only and require official-page verification before final donation decisions.
Tested: npm test --workspace donation-place-search
Tested: node smoke invocation of recommendDonationPlaces + formatDonationRecommendationReport for 서울 마포구/동물
Tested: npm run lint --workspace donation-place-search
Tested: npm run typecheck
Tested: npm run ci
Tested: architect verification approved after off-category regression fix
Not-tested: Live 1365 search result scraping; intentionally not used because the skill returns official verification links instead.
Co-authored-by: OmX <omx@oh-my-codex.dev>
* Keep donation recommendations on requested intent
Prioritize specific donation category keywords before broad general donation terms, and make item-level 1365 links candidate-specific while preserving the broad result search link.
Constraint: PR #214 review required TDD fixes for category normalization and per-candidate 1365 link semantics.
Rejected: Rewording item URLs as broad portal searches | the issue explicitly asks for candidate-specific verification links.
Confidence: high
Scope-risk: narrow
Directive: Keep item officialSearchUrl candidate-specific; use result officialSearchUrl for broad latest portal searches.
Tested: npm test --workspace donation-place-search; node smoke invocation; npm run lint --workspace donation-place-search; npm run typecheck; npm run ci; code-reviewer APPROVE; architect CLEAR.
Not-tested: Live 1365 HTTP availability, because the workflow only builds official read-only search links and prior review documented headless 1365 timeouts.
* Harden donation skill follow-up guarantees
Constraint: PR #214 review follow-up required TDD, empty category defaults, README discoverability, and release-pack coverage without pinning package versions.\nRejected: Static pack dry-run allowlist | it already missed a publishable workspace and would drift again.\nConfidence: high\nScope-risk: narrow\nDirective: Keep pack dry-run coverage dynamic over publishable workspaces; do not assert workspace package versions in tests.\nTested: npm test --workspace donation-place-search; node smoke for empty category URL/recommend/report; npm run lint --workspace donation-place-search; npm run typecheck; npm run ci; git diff --check; code-reviewer APPROVE; architect CLEAR.\nNot-tested: Live 1365 portal filtering semantics, by design; links remain read-only verification entry points.
* Clarify donation verification links
Reject misleading 1365 URL contracts and keep item search categories aligned with the candidate that is being recommended.
Constraint: PR #214 round-3 review required TDD fixes for multi-category candidate links, clean install docs, and evidence-safe 1365 wording.
Rejected: Keep broad first-request category on every item URL | It mislabels later-category candidates in multi-category requests.
Rejected: Preserve public baseUrl override | It conflicts with the official 1365 helper contract.
Confidence: high
Scope-risk: narrow
Directive: Keep 1365 URLs framed as best-effort verification assists unless browser-observed 1365 search parameters are documented.
Tested: npm test --workspace donation-place-search; node --test --test-name-pattern 'donation-place-search' scripts/skill-docs.test.js; npm run lint --workspace donation-place-search; npm run typecheck; npm run ci; node smoke for multi-category URLs, malformed limits, baseUrl rejection, and empty category.
Not-tested: Live 1365 parameter behavior; headless HTTP remains documented as unreliable.
Co-authored-by: OmX <omx@oh-my-codex.dev>
---------
Co-authored-by: OmX <omx@oh-my-codex.dev>
* chore: version packages
* Merge dev into main (#197)
* fix(toss-securities): clarify session expiry and quote 403 handling
* Clarify toss empty-output session expiry
Portfolio and watchlist reads can exit successfully with empty payloads when the stored Toss session has expired. The empty-output path now verifies the session before JSON parsing and only promotes confirmed invalid auth doctor data into TossSessionExpiredError.
Constraint: Scope is limited to toss-securities issue #126 follow-up on PR #192
Rejected: Treat auth doctor execution failures as expired sessions | unsupported or failing doctor output is inconclusive without parsed session.valid=false
Confidence: high
Scope-risk: narrow
Directive: Keep empty-result session expiry classification tied to explicit auth doctor confirmation
Tested: npm run test --workspace toss-securities; npm run lint --workspace toss-securities; npm run ci; manual mock tossctl blank stdout invalid/inconclusive doctor checks
* Avoid false session-expiry labels for validation errors
The toss wrapper now treats bare validation_error text as an upstream command failure instead of a session-expired signal. Structured auth doctor JSON remains the source of truth for empty portfolio/watchlist invalid-session promotion, while known stored-session-invalid stderr still maps to TossSessionExpiredError.\n\nConstraint: PR #192 follow-up must stay scoped to issue #126 toss-securities behavior.\nRejected: Keep validation_error in the global regex | it mislabels auth doctor transport failures and quote 403 validation errors as session expiry.\nConfidence: high\nScope-risk: narrow\nDirective: Do not broaden the free-text session classifier without regressions for auth doctor and quote upstream validation failures.\nTested: npm run lint --workspace toss-securities; npm run test --workspace toss-securities; npm run ci; manual mock tossctl validation_error checks; architect verification CLEAR\nNot-tested: Live tossctl network/auth session against real Toss upstream
* Align court auction lookup with monthly site search (#196)
The court auction notice page posts a YYYYMM search key from its 조회 button and returns a month of rows. Keep day inputs as a compatibility filter over the monthly response and normalize the current nested detail payload shape.
Constraint: courtauction.go.kr has no public API and blocks bursty automated calls.
Rejected: querying every day independently | the upstream search surface is month-based and day calls return false empty results.
Confidence: high
Scope-risk: narrow
Directive: Preserve the site-observed YYYYMM notice search contract unless the PGJ143M01 XHR changes again.
Tested: npm --workspace packages/court-auction-notice-search test; npm run ci; live 서울중앙지방법원 2026-05 notice/detail smoke lookup.
Not-tested: PR CI after push.
Co-authored-by: OmX <omx@oh-my-codex.dev>
* Guide crawler skills toward reusable discovery (#195)
* chore: version packages
* Guide crawler skills toward reusable discovery
Constraint: User requested insane-search-style guidance for future crawling k-skills without unrelated implementation changes.
Rejected: Adding crawler code or a standalone template | too broad for a docs guidance change and risks dependency creep.
Confidence: high
Scope-risk: narrow
Directive: Keep site-specific access details inside individual skills after a site-agnostic discovery pass.
Tested: npm run ci
Not-tested: Live crawler behavior; documentation-only change.
* Clarify crawler skill discovery guidance
Constraint: Crawling k-skills need site-dependent recipes, but should derive them through a reusable discovery pass.
Rejected: Leaving guidance only in docs/adding-a-skill.md | AGENTS.md and CLAUDE.md also guide future agents.
Confidence: high
Scope-risk: narrow
Directive: Use site-agnostic discovery to find, then explicitly package, the target site's stable access path.
Tested: npm run ci
Not-tested: Live crawler behavior; documentation-only change.
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Ground corporate registration guidance in official form sources
Keep the consulting skill focused on draft/checklist support while pointing users to current IROS and law.go.kr form sources for submission-ready artifacts.
Constraint: official registry forms can change outside the repository and must be re-downloaded at use time
Rejected: committing copied official HWP/HWPX/PDF forms | they would become stale and risk misleading users
Confidence: high
Scope-risk: narrow
Directive: do not treat Markdown templates as substitutes for official registry submission forms
Tested: npm test
* Ground incorporation drafting in real HWP forms
Bundle official court incorporation forms plus public startup incorporation attachments, and make rhwp-filled HWP outputs the default drafting path for the corporate-registration skill. Replace the listed-company articles reference with a startup-suitable Ministry of Justice stock-company form and record source manifests for bundled binaries.
Constraint: user requires actual sourced HWP templates, not generated placeholder binaries.
Rejected: markdown-only drafting | it cannot produce submission-shaped Korean registry forms.
Rejected: listed-company standard articles as the default reference | it is mismatched for typical startup incorporation.
Confidence: high
Scope-risk: moderate
Directive: keep bundled HWP forms source-backed, sanitized, and edited only through copied working files.
Tested: node --test scripts/skill-docs.test.js; npm run lint; k-skill-rhwp info on bundled HWP files; kordoc conversion spot checks.
Not-tested: manual opening every HWP in Hancom Office and live registry submission.
Co-authored-by: OmX <omx@oh-my-codex.dev>
* Streamline corporate registration forms workflow
Prioritize saved HWP forms for ordinary stock-company promoter incorporations, make required court-registry receipts and director identity certificates explicit, and remove the redundant markdown articles template so the skill stays HWP-first.
Constraint: 법원등기소 기준 체크리스트 must include fee receipts, director seal/signature certificates, and resident-record documents.
Rejected: Keeping a separate markdown articles template | duplicated the stored HWP articles workflow and encouraged non-HWP drafting.
Confidence: high
Scope-risk: narrow
Directive: Keep corporate-registration-consulting focused on stored HWP form copies and explicit issued-document checklists.
Tested: node --test --test-name-pattern 'corporate-registration-consulting' scripts/skill-docs.test.js; node --check scripts/skill-docs.test.js; ./scripts/validate-skills.sh; git diff --check
Not-tested: Full npm run ci was not run because this is a skill documentation/template refactor, not release or package automation.
---------
Co-authored-by: galvaomica <galvaomica@galvaomicaui-MacBookAir.local>
Co-authored-by: OmX <omx@oh-my-codex.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* chore: version packages (#198)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat(realtyprice): add address parsing and sido code mapping
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(realtyprice): use string sido codes for consistency with upstream API
* feat(realtyprice): add response normalization and buildResponse
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(realtyprice): add upstream cascade fetch functions with timeout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(realtyprice): add lookupGongsijiga orchestrator with region matching
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(realtyprice): add simple in-memory cache with TTL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(proxy): register GET /realtyprice route with caching
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add gongsijiga-search SKILL.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: add changeset for gongsijiga-search
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(realtyprice): align with actual realtyprice.kr API response format
- Response wraps data in model.list (not bjdList/gsiList)
- Field names are code/name (not bjd_cd/bjd_nm)
- bun2 empty → send "0000" (not empty string)
- eupmyeondong matching: try full string match first (API returns
combined "면 리" names like "청계면 청천리")
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(gongsijiga-search): align /realtyprice route with v1 API convention
- Change route from /realtyprice to /v1/realtyprice for consistency with other proxy endpoints.
- Add realtypriceConfigured flag to /health upstreams.
- Normalize address cache key by collapsing multiple whitespaces.
- Update SKILL.md and README.md to reflect the new v1 path.
* feat(gongsijiga-search): add Sejong special-city support
- parseAddress: allow 3-token minimum for Sejong (no sigungu) and set sigungu to empty string.
- lookupGongsijiga: skip sigungu lookup for Sejong (sidoCode 29), use fixed sggCode 36110.
- Add Sejong parseAddress and lookupGongsijiga test cases.
- Update SKILL.md with Sejong address format examples.
* refactor(gongsijiga-search): split realtyprice.kr lookup into standalone package
realtyprice.kr is a fully public endpoint that needs no API key, so per
the new k-skill-proxy inclusion rule (proxy is for keyed upstreams only)
the helper now ships as `gongsijiga-search` and is invoked directly from
the user's machine.
- new workspace package packages/gongsijiga-search/ following the
blue-ribbon-nearby/coupang-product-search convention (publishConfig,
files, repository, keywords)
- remove /v1/realtyprice route, realtyprice.js, realtyprice.test.js, and
the realtypriceConfigured health flag from k-skill-proxy
- document the inclusion rule in AGENTS.md and CLAUDE.md so future skills
default to direct calls when no key is required
- advertise the new skill in README.md, docs/install.md, and add
docs/features/gongsijiga-search.md
- drop the hardcoded toss-securities lockfile version assertion that
pinned a workspace version (would block changesets version-packages)
and document the anti-pattern in AGENTS.md / CLAUDE.md
- changesets: refresh the proxy refactor message and add a patch
changeset so the new gongsijiga-search package gets published
---------
Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: galvaomica <galvaomica@galvaomicaui-MacBookAir.local>
Co-authored-by: OmX <omx@oh-my-codex.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement Workflow A (매각공고 → 사건/물건 펼치기) and Workflow B
(사건번호 직조회) MVP for the official 대법원경매정보 site
courtauction.go.kr. The package exposes searchSaleNotices,
getSaleNoticeDetail, getCaseByCaseNumber, and getCourtCodes plus a
court-auction-notice-search CLI mirror. Direct HTTP transport is the
default with a Playwright fallback (rebrowser-playwright /
playwright-core, dynamic import) for blocked/5xx situations.
Anti-bot guardrails: minimum 2s + jitter between calls, 10-call
session budget, immediate BLOCKED throw on data.ipcheck === false, and
no automatic retry to avoid extending the site's IP block. Fixtures
were captured from live courtauction.go.kr endpoints during discovery
and live smoke tests verify each public API end-to-end.
Workflow C (자유 조건검색), Workflow D (일별/월별 캘린더), 매각물건
사진/PDF, and 동산 경매는 follow-up issues로 분리됨.
The wrapper advertised upstream /jangbu-* routing for both Claude and agent-compatible installs, but only nested the pinned upstream checkout. The installer now registers the upstream subskills at top level in both home skill roots while appending the wrapper attribution and accounting disclaimer policy to direct subskill use.
Constraint: PR review required top-level discovery for ~/.claude/skills and ~/.agents/skills
Constraint: korean-jangbu-for responses must retain original link, @kimlawtech (SpeciAI), Apache-2.0, and accounting/tax disclaimer
Rejected: Copy raw upstream subskills unchanged | direct /jangbu-* use would bypass mandatory wrapper response policy
Confidence: high
Scope-risk: narrow
Tested: node --test scripts/skill-docs.test.js --test-name-pattern='korean-jangbu-for'
Tested: bash korean-jangbu-for/scripts/install.sh plus top-level Claude/agents subskill marker checks
Tested: upstream runtime install and verify with Python 3.11 shim
Tested: npm run ci
Issue #173 needs a k-skill entry point centered on kimlawtech/korean-jangbu-for while preserving upstream attribution and accounting/tax disclaimers. Add a thin wrapper with pinned upstream install, bundled Apache license/disclaimer/notice, docs, and regression coverage for the required original link and @kimlawtech (SpeciAI) mention.\n\nConstraint: Upstream implementation remains in kimlawtech/korean-jangbu-for and is installed by pinned SHA instead of vendoring runtime payload into k-skill\nConstraint: Generated accounting/tax outputs are reference drafts, not official audits or tax filings\nRejected: Reimplement ledger automation locally | would duplicate upstream and widen maintenance scope\nConfidence: high\nScope-risk: narrow\nDirective: Keep responses for this skill citing https://github.com/kimlawtech/korean-jangbu-for and @kimlawtech (SpeciAI); do not remove tax/accounting disclaimers\nTested: node --test scripts/skill-docs.test.js --test-name-pattern='korean-jangbu-for'\nTested: bash korean-jangbu-for/scripts/install.sh\nTested: bash ~/.claude/skills/korean-jangbu-for/upstream/scripts/install.sh with Python 3.11 PATH shim\nTested: bash ~/.claude/skills/korean-jangbu-for/upstream/scripts/verify.sh\nTested: npm run ci\nNot-tested: CODEF live collection flow; requires user BYOK credentials and external auth
Add a conservative k-skill-cleaner workflow that interviews users, scans best-effort agent trigger logs, and reports deletion or review candidates without mutating skill directories automatically.
Constraint: Trigger-count storage differs by coding agent and may be absent or rotated locally
Rejected: Auto-delete low-usage skills | cleanup recommendations need explicit user approval because log signals are incomplete
Confidence: high
Scope-risk: narrow
Directive: Keep deletion behavior recommendation-only unless a future issue explicitly approves mutation with stronger safeguards
Tested: PYTHONPATH=scripts python3 -m unittest scripts.test_k_skill_cleaner; helper CLI smoke; npm run lint; npm run typecheck && npm test; npm run ci; architect verification
Not-tested: Live exports from OpenClaw/ClawHub or Hermes Agent because no stable public local trigger-count schema is assumed
Issue #175 needs a 등기부등본 skill grounded in the challengekim reference implementation while preserving user control over IROS login, authentication, and payment. Add a docs-first skill with regression coverage that locks the upstream credit, safety boundaries, and repository documentation wiring.
Constraint: Original author link must be mentioned in documentation.\nConstraint: IROS login, certificate authentication, and card payment must remain user-controlled.\nRejected: Add a packaged automation wrapper | no dependency or executable implementation was required and credential/payment flows are high-risk.\nConfidence: high\nScope-risk: narrow\nDirective: Do not remove the challengekim upstream credit or weaken the manual login/payment boundary without a new review.\nTested: node --test --test-name-pattern='iros-registry-automation' scripts/skill-docs.test.js; ./scripts/validate-skills.sh; npm run ci\nNot-tested: Live IROS smoke with real login/payment, intentionally not run without user credentials and payment authority
Add a reference-only corporate registration consulting skill for first-time Korean incorporation workflows. The skill keeps user decisions explicit, provides conservative articles/document templates, and routes HWP automation through existing rhwp/kordoc surfaces instead of introducing new machinery.
Constraint: Issue #168 requires legal-disclaimer wording, tax pitfall guidance, rhwp-based form support, TDD, and PR delivery to dev.
Rejected: Add a new package or external automation dependency | existing skill docs and rhwp tooling are enough for this documentation/template workflow.
Confidence: high
Scope-risk: narrow
Directive: Do not present generated registration documents as legal or tax advice; keep official-source verification and professional review caveats visible.
Tested: node --test --test-name-pattern='corporate-registration-consulting' scripts/skill-docs.test.js; npx --yes k-skill-rhwp create-blank/info smoke; npm run ci
Not-tested: Live court registry submission or live tax payment, intentionally outside reference-skill scope
Splits HWP handling into three focused skills per issue #155:
- hwp (kept): kordoc-based read/convert (Markdown, JSON, diffing, form
fields, Markdown->HWPX). Description narrowed to 'read-only' to make
the routing policy explicit.
- rhwp-edit (new): HWP binary editing via new k-skill-rhwp npm package
that wraps the @rhwp/core WASM bindings as CLI subcommands: info,
list-paragraphs, search, insert-text, delete-text, replace-all,
create-table, set-cell-text, create-blank, and render.
- rhwp-advanced (new): guidance for the upstream Rust rhwp CLI
(export-svg --debug-overlay, dump, dump-pages, ir-diff, thumbnail,
convert) for layout debugging, IR inspection, version comparison,
and read-only-document unlocking.
The new k-skill-rhwp package under packages/ ships a Node.js 18+ CLI
and library that round-trips HWP 5.x documents entirely in-process; no
Rust toolchain is required. It auto-installs the WASM-required
globalThis.measureTextWidth shim for headless Node, and all editing
subcommands always write to a distinct output path so the source file
is never mutated. HWPX save remains disabled per the upstream rhwp
#196 data-safety gate; HWPX input is accepted but output is written as
HWP 5.x.
Includes 24 node:test cases covering init, round-trip insertText,
replaceAll, createTable + setCellText, deleteText, searchText,
listParagraphs, renderPage (SVG/HTML), and full CLI arg-parse +
end-to-end round-trip through the CLI layer.
Wires README feature table (3 rows for hwp / rhwp-edit / rhwp-advanced),
docs/install.md optional-install list, docs/roadmap.md (marks HWP
advanced editing as shipped while keeping Windows/security-module
automation out of scope), docs/sources.md (adds rhwp upstream, CLI
source, @rhwp/core, @rhwp/editor, and rhwp #196 references), and the
root pack:dry-run script. Adds a Changesets entry for k-skill-rhwp
minor.
Closes#155.
* Add official KBL results support so basketball queries use live league data
Issue #129 needs a read-only skill and reusable package for KBL schedules, results, and standings. The implementation follows the existing sports package pattern and uses the league's live JSON APIs after verifying they respond successfully in real requests.
Constraint: Must use official KBL JSON surfaces before considering scraping
Constraint: Packaging changes must pass npm run ci and include docs plus Changesets updates
Rejected: Browser scraping first | official api.kbl.or.kr endpoints are live and simpler to maintain
Rejected: Reuse KBO/K League package shapes verbatim | KBL payload and team/status fields differ materially
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep seasonGrade=1 as the default KBL path unless future docs/tests explicitly widen to D-League flows
Tested: npm run ci; npm run lint --workspace kbl-results; npm test --workspace kbl-results; live getKBLSummary("2026-04-01", { team: "KCC", includeStandings: true })
Not-tested: Historical standings snapshots for past seasons via alternative KBL endpoints
* Prevent optional standings lookups from over-fetching the KBL API
The new kbl-results summary helper exposes includeStandings=false, so the
regression suite now proves that path stays schedule-only and never calls
the standings endpoint when the caller opts out.
Constraint: The KBL package should preserve the caller's no-standings contract
Rejected: Rely on manual inspection of the helper options | a targeted test is cheaper and safer
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep includeStandings=false side-effect free unless the public API contract changes explicitly
Tested: npm test --workspace kbl-results; npm run lint --workspace kbl-results
Not-tested: Full-repo CI before stacking this commit onto the rebased branch
Merged origin/dev into feature/#119 and reconciled the install/test contract around the kordoc-based HWP workflow so the branch keeps the public-restroom and proxy updates from dev without regressing the new HWP docs contract.
Constraint: PR #125 must stay on feature/#119 and remain reviewable without self-merging\nRejected: Reintroduce @ohah/hwpjs install guidance | conflicts with the kordoc-first contract under test\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep docs/install.md and scripts/skill-docs.test.js aligned whenever global install guidance changes\nTested: node --test scripts/skill-docs.test.js; npm run ci; temp-dir kordoc markdownToHwpx roundtrip back to Markdown\nNot-tested: GitHub-side mergeability checks before remote push
* Add nationwide scholarship search skill workflow
* Rename scholarship skill to 장학금 주세요 쮜에발
* Fix scholarship skill validation in CI
* Trigger GitHub PR diff refresh after dev rebase on main
* Fix scholarship helper status handling and test coverage
* Use KST as scholarship helper default date basis
* Rename scholarship skill display name
---------
Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
The follow-up closes the last runnable-contract gaps from review by documenting the working one-shot npx form and separating Node API examples into a local project install path. The regression suite now locks both install notes so future edits do not drift back to broken command shapes.
Constraint: Published kordoc CLI still requires pdfjs-dist at startup
Constraint: Global NODE_PATH does not make ESM imports from kordoc resolvable in the documented examples
Rejected: Keep bare `npx kordoc` examples | fails in a clean environment
Rejected: Keep global-install Node API guidance | ESM import remains unresolved
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep HWP docs aligned to verified published kordoc surfaces until the package contract changes upstream
Tested: node --test scripts/skill-docs.test.js
Tested: npm run ci
Tested: temp-dir local npm install kordoc pdfjs-dist plus markdownToHwpx -> sample.hwpx -> one-shot kordoc roundtrip smoke
Not-tested: upstream unpublished kordoc features beyond the verified CLI and Node API surfaces
The issue #119 follow-up needs the repository contract to match what the
currently published kordoc package actually supports. This narrows the
HWP skill/docs/tests to the verified install requirement and supported
CLI/Node API surfaces, and removes unsupported fill/mcp claims.
Constraint: Published kordoc CLI fails at startup without pdfjs-dist
Constraint: Docs/tests must reflect the current npm package behavior, not intended future features
Rejected: Keep fill/mcp examples with caveats | still documents unsupported entrypoints
Confidence: high
Scope-risk: narrow
Directive: Reintroduce fill/mcp docs only after verifying the published package exposes them in both CLI and Node API
Tested: node --test scripts/skill-docs.test.js; npm run ci; temp-dir clean install smoke; temp-dir kordoc+pdfjs-dist watch/parse/extractFormFields/compare/markdownToHwpx/roundtrip smoke; Claude architect review
Not-tested: Real-world HWPX template that produces non-empty extractFormFields output
Issue #119 replaces the previous HWP guidance with kordoc so the skill matches the newer agent-native document flow. The docs and regression tests now center the HWP skill on kordoc parsing, JSON extraction, diffing, form filling, and Markdown-to-HWPX round-tripping, while the install/source references stay in sync.
Constraint: The repository treats skill behavior as documentation contracts backed by regression tests
Constraint: The requested branch/PR flow must target dev with TDD and verified execution evidence
Rejected: Keep @ohah/hwpjs or hwp-mcp as fallback guidance | issue #119 explicitly approves replacing the prior stack with kordoc
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep future hwp skill/docs/tests aligned to a single kordoc-first contract unless a new issue explicitly reintroduces multi-backend routing
Tested: node --test scripts/skill-docs.test.js; npm run ci; temp-dir kordoc roundtrip via markdownToHwpx -> sample.hwpx -> kordoc CLI markdown output; architect review APPROVED
Not-tested: Live parsing of user-provided proprietary HWP/HWPX samples outside the generated roundtrip fixture
The Korean stock proxy used to silently drop failed market snapshots during
search and could turn an empty holiday trade snapshot into a 502 by falling
back into base-info lookup.
This change surfaces degraded market metadata on partial search success,
short-circuits empty trade snapshots to not_found, and refreshes the user
docs to use a real trading day in examples.
Constraint: KOSPI base-info approval is granted separately from other KRX routes
Constraint: Healthy markets should still return usable search results during a partial outage
Rejected: Return 502 on every partial search failure | hides still-usable markets and breaks current clients unnecessarily
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep degraded search metadata when any market snapshot fetch fails so partial outages stay visible
Tested: npm test --workspace k-skill-proxy
Tested: node --test scripts/skill-docs.test.js
Tested: npm run ci
Not-tested: Live KOSPI base-info behavior after the new KRX permission is approved
This adds a new public-restroom-nearby skill and reusable package that resolves a user-provided location, narrows the official 공중화장실정보 dataset by region when possible, and ranks nearby restroom results with opening-time hints and map links.
Constraint: Must use free official/open surfaces without introducing new dependencies
Constraint: Must follow TDD and keep release/docs metadata aligned in the same change
Rejected: Add a proxy route first | direct official CSV access already works and keeps scope narrower
Rejected: Use nationwide-only ranking without regional narrowing | too much noisy data for dense urban anchors
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: If Kakao place-panel or localdata CSV schema changes, update parser fixtures before broad logic changes
Tested: npm run ci; live smoke via searchNearbyPublicRestroomsByLocationQuery('광화문', { limit: 3 }); architect review APPROVED
Not-tested: Non-Seoul live smoke across every regional orgCode
Issue #120 only needs a repository skill payload, discoverability docs,
and regression coverage. This change adds the new skill, wires it into
existing docs surfaces, and locks the remote-MCP-only contract in tests
so future edits keep the phone-only event flow and verbatim message
relay behavior.
Constraint: The upstream Hola Poke flow lives on a remote MCP server, so this repo should not add proxy/runtime code
Constraint: Tests must be written before refining the new docs/skill wording
Rejected: Add local package or proxy support for Hola Poke | would over-scope a docs-only skill addition
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep this skill limited to 올라포케 역삼점 and treat the MCP response message as the event source of truth
Tested: node --test scripts/skill-docs.test.js --test-name-pattern='hola-poke-yeoksam'
Tested: npm run ci
Tested: Live MCP initialize/tools/list/get_menu/get_shop_info/enter_event(phone_format) smoke checks against https://hola-poke-yeoksam-skill.onrender.com/mcp
Not-tested: Successful live event entry with a real phone number
The GeekNews follow-up review found two merge blockers outside the new helper itself: rejected NEIS upstream fetches escaped as Fastify 500s, and the documented selective install block split into two shell commands. This change adds regression coverage first, catches rejected NEIS fetches at the route boundary with the established proxy_error/502 contract, and locks the multiline install snippet so copy-paste works.
Constraint: Keep NEIS proxy failures aligned with existing public proxy error handling
Constraint: Preserve the published GeekNews verification commands and current PR scope
Rejected: Wrapping fetch inside the NEIS helper functions | route-level handling matches the surrounding Fastify endpoint pattern
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep public proxy routes fail-closed on rejected upstream fetches and keep multiline install snippets copy-pasteable
Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_geeknews_search; node --test scripts/skill-docs.test.js; node --test packages/k-skill-proxy/test/server.test.js; python3 scripts/geeknews_search.py list --limit 3; python3 scripts/geeknews_search.py search --query Claude --limit 3; python3 scripts/geeknews_search.py detail --id 28439; node NEIS rejected-fetch repro; npm run ci
Not-tested: Live NEIS upstream success responses against the real public API in this follow-up
Issue #108 needs a dedicated read-only skill that can browse,
search, and inspect GeekNews posts using the public feed alone.
The implementation adds a fixture-backed Atom helper, skill/docs
surfaces, and install/README wiring, then verifies the helper
against the live GeekNews feed.
Constraint: Must stay RSS-first and avoid new dependencies or unofficial APIs
Constraint: Skill development requires syncing the skill into ~/.claude/skills and ~/.agents/skills during verification
Rejected: Fetch article pages directly for v1 | expands scope beyond the approved RSS-driven workflow
Rejected: Use XML parser modules | current python3 environment has expat issues, so regex + HTML parsing is safer here
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep the root helper and geeknews-search/scripts copy behaviorally identical because the installed skill must remain self-contained
Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_geeknews_search; node --test scripts/skill-docs.test.js; python3 scripts/geeknews_search.py list --limit 3; python3 scripts/geeknews_search.py search --query Claude --limit 3; python3 scripts/geeknews_search.py detail --id 28439; npm run ci
Not-tested: Non-default feed mirrors or future Atom schema changes beyond the current public GeekNews feed shape
Related: Issue #108
Issue #98 was approved as a conservative implementation: structure the official LOST112 and 서울교통공사 workflows instead of pretending a stable public API exists. The new helper builds the documented search payload, the docs explain the v1 hybrid scope, and regression coverage locks the helper plus repo docs into the shipped flow.
Constraint: Public subway lost-property APIs remain unconfirmed, so v1 must stay guidance-first
Rejected: Full automated scraping of live result tables | unstable without confirmed API/session guarantees
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep this skill on official HTTPS entry points until a stable public API is verified end-to-end
Tested: python3 -m unittest scripts.test_subway_lost_property; python3 scripts/subway_lost_property.py --station 강남역 --item 지갑 --days 14 --verify-live; npm run ci
Not-tested: Browser-only user journey through LOST112 search submission beyond payload generation
Implement a reusable Market Kurly workspace package plus a repo skill/doc set
that uses the unauthenticated Kurly search and goods-page surfaces.
The change keeps the scope read-only, adds regression coverage, updates
release/docs metadata, and records the new publishable package through
Changesets.
Constraint: Must rely on unauthenticated public web surfaces instead of login/session flows
Constraint: Release workflow requires Changesets for publishable Node packages
Rejected: Docs-only skill | issue approval called for real lookup helpers and live verification
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Kurly endpoints are web-internal surfaces; verify schema behavior before extending fields or adding action flows
Tested: npm run ci; live node smoke for countProducts/searchProducts/getProductDetail on 2026-04-09
Not-tested: Pagination beyond page 1; long-term stability of Kurly internal response schema
Merged origin/dev into feature/#65, resolved the package.json and docs-test conflicts by keeping the Korean character count helper coverage while also preserving the newer MFDS safety skill wiring from dev. This keeps the branch reviewable without dropping either side's verification surface.
Constraint: PR #87 had to be updated from dev without regressing either shipped korean-character-count checks or newer dev-only MFDS coverage
Rejected: Re-resolve by favoring one side of the conflict wholesale | would silently drop verified test coverage from the other branch
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: If package.json test wiring changes again, keep both the korean-character-count and MFDS helper suites in the root scripts unless the underlying features are intentionally removed
Tested: node --test scripts/skill-docs.test.js scripts/test_korean_character_count.js; node scripts/korean_character_count.js --text '가나다' --format json; node scripts/korean_character_count.js --file <tmpfile> --profile neis --format text; printf '한\r\n나' | node scripts/korean_character_count.js --stdin --format json; npm test; npm run ci
Not-tested: Live authenticated MFDS API success path still depends on external API key state
Issue #65 needs deterministic Korean character, line, and byte counting for self-intros and similar forms, so this adds a bundled helper plus skill/docs/tests around a fixed grapheme/UTF-8 contract with an explicit NEIS compatibility profile.
Constraint: Must avoid LLM estimation and keep results deterministic across repeated runs
Constraint: No new dependencies; rely on Node 18+ Intl.Segmenter and Buffer.byteLength
Rejected: Per-request ad hoc scripts only | contract drift would make repeated counts inconsistent
Rejected: Legacy encoding heuristics as the default | modern UTF-8 contract is safer unless the target explicitly says otherwise
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep and profile semantics in sync with docs/tests before changing counting rules
Tested: node --test scripts/skill-docs.test.js scripts/test_korean_character_count.js; helper smoke via text/file/stdin; npm test; npm run ci; LSP diagnostics on changed JS files
Not-tested: Proprietary site-specific counters beyond the documented default/NEIS contracts
The approved issue narrowed scope to two public-health skills: one for
official MFDS drug safety lookups and one for food safety / recall
lookups. This change adds both skills, bundles runnable Python helpers,
locks the docs and helper behavior with TDD regressions, and updates
repo docs so the interview-first safety flow is installed and verified
with the rest of k-skill.
Constraint: User-approved scope requires mandatory symptom follow-up before answering and forbids direct diagnosis
Constraint: Live MFDS data.go.kr success paths depend on upstream key approval/status; local verification on 2026-04-08 surfaced HTTP 403 with the available key
Rejected: Single generic health skill | weaker safety boundaries and less explicit user routing
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep red-flag escalation and interview-first wording intact unless official clinical scope is expanded deliberately
Tested: python3 scripts/mfds_drug_safety.py --help; python3 scripts/mfds_drug_safety.py interview --question '타이레놀이랑 판콜 같이 먹어도 되나요?' --symptoms '두드러기와 어지러움'; python3 scripts/mfds_food_safety.py --help; python3 scripts/mfds_food_safety.py interview --question '이 김밥 먹어도 되나요?' --symptoms '복통과 설사'; python3 scripts/mfds_food_safety.py search --query '대장균' --sample-recalls --limit 1; PYTHONPATH=.:scripts python3 -m unittest scripts.test_mfds_drug_safety scripts.test_mfds_food_safety; node --test scripts/skill-docs.test.js; npm run ci
Not-tested: Successful authenticated MFDS live data.go.kr lookup path with a fully approved service key