* Remove client-side Seoul subway key setup Route Seoul subway arrival lookups through k-skill-proxy so the hosted proxy owns the Seoul Open Data upstream key and end users only need the proxy base URL. Add proxy route coverage, update skill/docs guidance, and align setup materials with the hosted proxy flow used for fine dust. Constraint: Must keep the proxy public, read-only, and dependency-free Constraint: Must satisfy TDD-first verification and ship on feature/#35 targeting dev Rejected: Add a separate client helper package | unnecessary extra layer for a single proxy route Rejected: Keep SEOUL_OPEN_API_KEY as an end-user requirement | defeats the issue goal Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the Seoul subway proxy surface limited to station-arrival passthrough unless tests/docs expand the contract Tested: npm run ci; local proxy runtime on 127.0.0.1:4120 for /health and /v1/seoul-subway/arrival on 2026-03-31 with an invalid upstream key Not-tested: Live success response with a valid Seoul Open API key Related: #35 * Prevent broken Seoul subway proxy defaults before hosted rollout The Seoul subway proxy endpoint code is present locally, but the hosted public route is not live yet. This change turns the user-facing subway docs back into an explicit proxy configuration flow, replaces the misleading hosted default in setup examples, and keeps subway proxy examples on self-host/local URLs until rollout is verified. Constraint: Hosted k-skill-proxy.nomadamas.org/v1/seoul-subway/arrival is not live yet Rejected: Keep the hosted Seoul subway URL as the default path | would send default users to a 404 route Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not restore a hosted Seoul subway default until the public proxy route is deployed and smoke-verified Tested: node --test scripts/skill-docs.test.js; npm run ci; local proxy smoke on 127.0.0.1:4120 with stubbed Seoul upstream (GET /health, GET /v1/seoul-subway/arrival?stationName=강남) Not-tested: Live hosted proxy smoke after deployment * Reduce Seoul subway proxy upstream pressure with request caching The public subway arrival route already normalized caller input but still re-fetched the Seoul upstream for every identical poll. This change adds a short-TTL cache keyed from the normalized subway query, annotates JSON responses with cache metadata, and locks the repeated-read collapse with a regression that proves alias/default normalization still reuses the cached result. Constraint: The endpoint must stay public/no-auth while protecting a shared server-side SEOUL_OPEN_API_KEY from unnecessary repeated upstream hits Rejected: Add a new shared cache abstraction for proxy metadata | unnecessary for this narrow fix and would enlarge the diff Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep subway cache keys tied to normalizeSeoulSubwayQuery output so alias/default query forms continue collapsing to one upstream request Tested: node --test packages/k-skill-proxy/test/server.test.js Tested: npm run ci Tested: Local proxy runtime on 127.0.0.1:4120 with SEOUL_OPEN_API_KEY=test-seoul-key and stubbed fetch for /health plus repeated /v1/seoul-subway/arrival requests Not-tested: Live hosted proxy rollout state * Document OpenClaw support in the public compatibility list The approved scope for issue #29 was narrowed to README support messaging, so this change adds OpenClaw/ClawHub to the supported-client line and locks that wording with a regression test in the docs suite. Constraint: Issue #29 was approved as a README-only compatibility/docs change Rejected: Broader install-doc updates | out of approved scope for this issue Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep OpenClaw support wording aligned with the supported-client README line and its docs regression test Tested: Focused Node docs regression, npm run lint, npm run typecheck, npm run build, npm test Not-tested: Live OpenClaw or ClawHub install flow (issue scope was documentation-only) * Protect README client-support claims from ClawHub regressions The README already advertises OpenClaw/ClawHub, but the docs regression only matched OpenClaw. Tighten the assertion to the exact supported-client fragment so a future edit cannot silently remove ClawHub while keeping the issue verification command stable. Constraint: PR #39 already publishes a verification command keyed to the current test name Rejected: Rename the test to mention ClawHub explicitly | would drift from the published verification command Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep this regression synchronized with the README supported-client line whenever that copy changes Tested: node --test scripts/skill-docs.test.js --test-name-pattern 'README advertises OpenClaw among the supported coding agents' Tested: npm run lint Tested: npm run typecheck Tested: npm run build Tested: npm test Tested: lsp diagnostics for scripts/skill-docs.test.js (0 errors) Not-tested: N/A * Make Coupang shopper research usable without pretending scraping is stable Coupang blocks unattended shopper queries in this environment, so the new package focuses on the durable pieces we can ship honestly: official URL builders, browser-captured HTML parsers, and explicit automation probes. The docs and skill now explain the seller-API limitation, the verified anti-bot behavior, and the browser-capture fallback expected by callers. Constraint: No general shopper Open API surfaced in Coupang's official developer docs Constraint: Headless/direct retrieval is anti-bot blocked in verified local probes Rejected: Bundle a scraping bypass or hidden browser dependency | violates repo policy and would over-claim reliability Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep probe/docs behavior aligned with fresh live verification before claiming unattended Coupang access works Tested: npm run ci; live probeAutomation(query=생수) with direct fetch + Playwright-core browserFetchHtml; LSP diagnostics on changed JS/test files Not-tested: Headed/manual browser sessions with a human-authenticated Coupang context * Keep the Coupang workspace installable and its entrypoint honest Review follow-up found two contract gaps in the first issue #36 rollout: fresh installs were missing the new workspace link in package-lock, and the package README documented parser helpers that were not exported from the package entrypoint. Refreshing the lockfile and re-exporting the parsers keeps npm ci and consumer imports aligned with the published API. Constraint: npm ci must succeed from a clean checkout Rejected: Narrow the README API list to only client helpers | would hide useful parsers that the package already ships and tests Confidence: high Scope-risk: narrow Reversibility: clean Directive: When adding a new workspace, refresh package-lock and verify the package entrypoint matches README public API claims Tested: npm run ci; workspace coupang-product-search tests; LSP diagnostics on coupang-product-search JS/test files Not-tested: published npm install from registry (local pack dry-run only) * Keep Coupang anti-bot docs honest as probe results drift A same-day PR rerun showed the published mobile probe snapshot was already stale, so the follow-up locks the 403/access-denied mobile path with regression coverage and softens the docs/skill contract to describe blocked outcome classes instead of one frozen signature. The published guidance now also explains that browser results only appear when browserFetchHtml is injected, matching what a clean checkout can actually reproduce. Constraint: Coupang anti-bot responses vary by edge/challenge between reruns on the same day Rejected: Freeze one exact mobile probe snapshot | same-day reruns already diverged Confidence: high Scope-risk: narrow Reversibility: clean Directive: Refresh Coupang anti-bot docs only with same-day live probe evidence, and prefer blocked outcome classes over a single exact signature when reruns disagree Tested: npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch Not-tested: Non-Chrome Playwright-core executables * Keep the Coupang skill honest about clean-checkout browser probes The approved follow-up already documented that clean-checkout probeAutomation runs leave browser unset unless a browser fetcher is injected, but the skill text itself had not made that null contract explicit. This commit adds a regression test that locks the browser-null wording across the published docs surfaces and updates the skill so the stated behavior matches the package implementation and clean-checkout reality. Constraint: probeAutomation() only populates browser when browserFetchHtml is supplied by the caller Rejected: Leave the skill wording implicit and rely on README examples alone | the skill could drift away from the shipped package contract again Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the README, feature doc, and skill aligned whenever the probeAutomation browser contract changes Tested: node --test packages/coupang-product-search/test/index.test.js; npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch; codex exec review --uncommitted Not-tested: Alternative browser engines beyond local Google Chrome for the manual browserFetchHtml probe * Keep Coupang browser probe docs aligned with manual verification paths The approved PR #40 follow-up still had one wording gap: the skill said when browser results appear, but it did not explicitly say those populated results come from an injected manual/external browserFetchHtml path. This change locks that contract with a failing regression first, then updates the skill text to match the already-shipped README/feature-doc guidance and runtime behavior. Constraint: clean-checkout probeAutomation() must keep browser null unless browserFetchHtml is supplied Rejected: change runtime browser probe behavior | approved follow-up was docs/test only and runtime contract is already correct Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep Coupang probe docs aligned with the shipped browserFetchHtml injection contract; do not imply built-in browser probing in clean checkouts Tested: node --test packages/coupang-product-search/test/index.test.js; npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch; lsp diagnostics on changed files; architect review approved Not-tested: alternate browser engines beyond local Google Chrome + playwright-core manual runner * Route Korean law lookups through korean-law-mcp Add a documentation-first korean-law-search skill and lock the repo docs around the rule that Korean law queries must go through korean-law-mcp rather than a new in-repo package. The change updates install/setup/security guidance, publishes the new feature doc, and adds regression tests so future edits keep the LAW_OC + korean-law-mcp contract intact. Constraint: Issue #41 requires korean-law-mcp for every Korean law lookup Constraint: Must not add a new npm or python package in this repository Rejected: Add a repo-local law package | violates the no-new-package requirement and duplicates upstream MCP work Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep Korean law lookup guidance pinned to korean-law-mcp unless issue requirements explicitly change Tested: node --test scripts/skill-docs.test.js Tested: npm install -g korean-law-mcp && korean-law list && korean-law help search_law Tested: npm run ci Tested: npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json Not-tested: live search_law/get_law_text against a real LAW_OC credential * Clarify Korean law setup modes to avoid credential confusion A review found the new korean-law-search docs treated LAW_OC as an unconditional prerequisite even though the upstream remote MCP endpoint is configured separately from the local CLI/server path. This update makes the docs and regression tests mode-specific: local CLI/MCP uses LAW_OC, while the remote endpoint stays a korean-law-mcp-only url fallback without a user-supplied credential. Constraint: Upstream korean-law-mcp uses LAW_OC on the local CLI/server path while the documented remote MCP endpoint is configured with url only Rejected: Keep LAW_OC mandatory for every korean-law-mcp mode | contradicts upstream docs and reviewer evidence Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep README/setup/skill docs and regression tests aligned on the local-vs-remote korean-law-mcp contract Tested: node --test scripts/skill-docs.test.js; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm run ci; lsp_diagnostics scripts/skill-docs.test.js Not-tested: Live remote MCP endpoint connection against https://korean-law-mcp.fly.dev/mcp * Record issue #41 follow-up after approved verification The approved korean-law-search change was already present on feature/#41, so this follow-up records a fresh verification pass and updates the PR without introducing unnecessary code churn. Constraint: Existing branch already contained the approved implementation Rejected: Touch repo files without need | would create noise without improving behavior Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the korean-law-mcp-only + mode-specific LAW_OC contract aligned with upstream docs before changing these surfaces again Tested: node --test scripts/skill-docs.test.js; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npm run ci Not-tested: Live korean-law queries that require a real LAW_OC or remote endpoint session * Keep the Korean law feature diff merge-ready Verification uncovered trailing whitespace in the new korean-law feature guide when checking the branch diff. I added a regression to the skill docs suite and removed the whitespace so the approved documentation contract stays clean and reviewable. Constraint: Preserve the existing korean-law-mcp + mode-specific LAW_OC contract without widening scope Rejected: Leave the whitespace issue as-is | git diff --check stayed dirty on the branch Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep docs/features/korean-law-search.md free of trailing whitespace so diff hygiene stays enforced by the regression Tested: node --test scripts/skill-docs.test.js; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npm run ci; git diff --check Not-tested: Live credentialed LAW_OC search execution against the upstream API * Keep Korean law skill guidance aligned with supported lookups The approved issue #41 feature already worked, but the shipped skill text still under-described ordinance and interpretation lookups compared with the documented capability set. This follow-up tightens the skill copy and locks that contract with a doc regression so the branch stays merge-ready without changing the underlying korean-law-mcp routing rules. Constraint: Must preserve the existing korean-law-mcp-only and mode-specific LAW_OC setup contract Rejected: Leave the skill wording as-is | drift from the documented lookup surface would remain Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the skill examples and doc regression aligned whenever supported korean-law-mcp search surfaces change Tested: node --test scripts/skill-docs.test.js Not-tested: live LAW_OC-backed upstream API queries * Keep Korean law completion guidance in sync with enforced lookups The previous follow-up aligned the main skill examples, but the done-criteria text still left interpretation and ordinance routing implicit. This commit makes the completion checklist explicit and extends the doc regression so future edits cannot silently drop those lookup paths. Constraint: Must stay within the existing issue #41 korean-law-mcp-only contract Rejected: Leave the done checklist implicit | reviewers and future edits could drift from the enforced lookup set Confidence: high Scope-risk: narrow Reversibility: clean Directive: When the supported Korean-law lookup set changes, update the done checklist and regression together Tested: node --test scripts/skill-docs.test.js Not-tested: full CI before commit * Enable repeatable used-car price lookups from a rental-company source Issue #46 required surveying major Korean rental companies before implementation and then choosing the easiest stable provider. SK렌터카 다이렉트 exposes 타고BUY inventory in public Next.js page data, so the feature stays dependency-free while still supporting live repeated lookups and documented provider rationale. Constraint: Must compare major Korean rental companies before implementation Constraint: Must verify 10+ live lookups against a real provider surface Rejected: 롯데오토옥션 as v1 provider | public list contract was unstable and legacy .do flows returned inconsistent or 404 pages Rejected: 레드캡렌터카 as v1 provider | no public used-car inventory or API surface was found Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the v1 provider read-only and inventory-snapshot-based unless a stable documented public API is confirmed Tested: npm run ci Tested: Live 10-query run against https://www.skdirect.co.kr/tb at 2026-04-02T07:22:46Z Tested: LSP diagnostics on affected files Not-tested: Seller-specific detail drilldowns or non-SK providers Related: #46 * Keep used-car-price-search releasable after merge Review feedback found that the new used-car workspace would not ship because it lacked a changeset, and the fallback install docs still omitted the runtime package. This follow-up adds regression coverage first, then restores both release and install-path coverage with the smallest possible diff. Constraint: New publishable workspaces must be wired through Changesets to reach npm release automation Constraint: Fallback install docs must list runtime packages users need when skill files are present but global packages are missing Rejected: Fix only the changeset gap | would leave the documented fallback install path incomplete Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep used-car-price-search in both the fallback global install example and a Changesets entry whenever release wiring changes Tested: node --test scripts/skill-docs.test.js; npx changeset status; live 10-query used-car run against SK direct at 2026-04-02T07:38:44.949Z; npm run ci; LSP diagnostics on used-car package files and scripts/skill-docs.test.js; architect verification Not-tested: No additional live provider permutations beyond the verified 10-query smoke run * Keep used-car verification docs resilient to live inventory churn A fresh rerun showed the SK direct inventory total continues to move during the day, so the feature doc now records the verified smoke-run timestamp without freezing a brittle exact count. The regression suite was updated first so the docs stay variability-aware and diff-clean in future follow-ups. Constraint: Live SK direct inventory totals change over time even when the parsing contract stays stable Rejected: Keep documenting a fixed total from one smoke run | it immediately drifted and made the docs stale Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the used-car live verification note timestamped and variability-aware instead of pinning an exact inventory total Tested: node --test scripts/skill-docs.test.js; git diff --check; npm run ci; npx changeset status; live 10-query run against https://www.skdirect.co.kr/tb at 2026-04-02T07:59:41.391Z; LSP diagnostics on scripts/skill-docs.test.js; architect verification Not-tested: No additional content changes outside the used-car feature doc * Keep used-car query summaries honest when results are limited The review found that query-level stats were being computed from the post-limit slice, so common searches like 아반떼 under-reported both match counts and price ranges. This change locks the regression first, then computes the full filtered set before slicing only the returned items. Constraint: PR #48 must preserve the existing API shape while fixing the review-blocking stats bug Rejected: Expanding the response with separate limited/full summary fields | unnecessary API churn for a targeted bug fix Confidence: high Scope-risk: narrow Reversibility: clean Directive: Query-level summary and matchedCount must stay derived from the full filtered set, not the display limit slice Tested: npm test --workspace used-car-price-search; npm run ci; git diff --check; npx changeset status; live SK direct smoke run on 2026-04-02T08:23:59Z; LSP diagnostics on used-car-price-search source and test files; architect verification APPROVED Not-tested: limit=0 semantics remain unchanged and still coerce to the default limit Related: PR #48 * Keep korean-law-search available during upstream outages (#45) Issue #44 adds Beopmang as the documented fallback when the primary korean-law-mcp path is unavailable, and locks the new routing into the doc regression suite so future edits do not silently revert the policy. Constraint: Existing guidance must still prefer korean-law-mcp and keep LAW_OC scoped to the local CLI/MCP path Rejected: Add a repo-local Beopmang client package | issue only requires fallback registration, not a new implementation surface Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the primary-first rule intact; Beopmang is an outage fallback, not the default path Tested: node --test scripts/skill-docs.test.js; npm run ci; korean-law list; python3 live Beopmang search smoke for 관세법 Not-tested: Live Beopmang MCP handshake from a GUI MCP client * Replace coupang scraping package with coupang-mcp server integration Drop the browser-based scraping package (packages/coupang-product-search) and switch to the uju777/coupang-mcp MCP server for all Coupang product searches. This removes the anti-bot workaround complexity and provides 8 ready-to-use tools via MCP Streamable HTTP with no API key required. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add disclaimer to used-car-price-search README Clarify that the package queries SK렌터카 타고BUY public data with no affiliation or sponsorship, and that ad/partnership inquiries are welcome. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Refactor used-car-price-search into provider-based architecture SK 타고BUY 전용 로직을 src/providers/sk-tagobuy.js로 분리하고, 공급자를 수평 확장할 수 있는 registry 구조로 전환한다. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Ship LCK analytics inside k-skill's managed release flow Adapt jerjangmin's upstream lck-analytics skill/package into a new workspace and skill pack, wire docs/install/release surfaces, and add regression fixtures/tests plus script smoke coverage so the feature is verifiable before publish. Constraint: Upstream package is not published to npm yet Constraint: Must preserve attribution to original source and author in shipped docs Rejected: Keep the upstream lck-results install wording in k-skill | conflicts with repo workspace/package naming Rejected: Ship only the npm package without the local skill scripts | issue explicitly requested the skill as well Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep Changesets as the only version-bump path for lck-analytics; do not hand-edit versions for release Tested: node --test packages/lck-analytics/test/index.test.js scripts/skill-docs.test.js Tested: npm run lint --workspace lck-analytics Tested: npm test --workspace lck-analytics Tested: live getLckSummary('2026-04-01', { team: '한화', includeStandings: true }) Tested: node lck-analytics/scripts/sync-oracle.js --csv lck-analytics/samples/oracle-lck-sample.csv --cache .tmp/lck-cache && node lck-analytics/scripts/build-match-report.js --date 2026-04-01 --team 한화 --cache .tmp/lck-cache && node lck-analytics/scripts/analyze-live-game.js --game game-1 --window packages/lck-analytics/test/fixtures/live-window-game-1.json --details packages/lck-analytics/test/fixtures/live-details-game-1.json --cache .tmp/lck-cache Tested: npm run ci Tested: npx tsc --noEmit --project /Users/jeffrey/Projects/k-skill/tsconfig.json Not-tested: Riot live feed behavior for arbitrary future game ids outside the fixture-backed smoke path * Enable policy-aware Korean spell checking from the official Nara surface Add a skill guide and Python helper that use the approved old_speller HTML flow, chunk long text conservatively, and report original/suggestion/reason deltas. The docs also record the public-site limits, Cloudflare behavior, and non-commercial usage policy so agents do not overreach the free surface. Constraint: Public site is HTML-only and may return 403 to non-browser clients Constraint: Must not add new dependencies or high-volume crawling behavior Rejected: Node fetch client | Cloudflare returned 403 in this environment Rejected: Paid API integration | no public contract or credentials were available for this task Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep usage low-rate and non-commercial unless supplier-approved API terms are added Tested: npm run lint Tested: npm run typecheck Tested: npm test Tested: npm run build Tested: python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json Tested: python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json Not-tested: Paid API/order flow Not-tested: High-volume commercial workloads Not-tested: Non-UTF-8 file inputs * Preserve korean spell-check layout in corrected output The Nara payload can collapse paragraph separators into normalized page text, so the helper now maps corrections back onto the original chunk before rebuilding corrected_text. The CLI also rejects non-positive --max-chars values, and regression tests cover both the layout-preservation path and invalid argument handling. Constraint: Nara result pages can normalize blank lines and sentence spacing before exposing errInfo offsets Rejected: Narrow docs away from file/Markdown proofreading | preserving original chunk separators keeps the documented workflow intact Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep multiline separator preservation tied to the original chunk whenever a suggestion only changes whitespace across collapsed boundaries Tested: python3 -m unittest scripts.test_korean_spell_check; npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n왠지 않되요.' --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Not-tested: Live multi-page Nara payloads with separator-sensitive corrections across multiple returned pages * Preserve file-proofreading layout in Korean spell check output The spell-check helper now keeps exact blank-line runs and paragraph indentation when chunking and reassembling file-style input, while still allowing the official service's spacing corrections to flow through. Regression coverage now locks the collapsed-layout, triple-blank-line, and cross-boundary spacing cases that triggered the PR review. Constraint: Official Nara/PNU payloads can collapse layout and sometimes merge corrections across preserved paragraph boundaries Rejected: Narrow docs away from file-level proofreading | the existing feature scope explicitly supports file and Markdown checks Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve exact layout tokens only at original newline boundaries; do not reintroduce global strip/join normalization without real file-mode verification Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --file <tmpfile> --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Not-tested: Live upstream behavior for extremely long leading/trailing-whitespace-only files Related: PR #60 * Keep layout-preserving chunk splits from tripping on separator-boundary fixes The follow-up layout preservation pass renamed the working unit variable, but one separator-length guard still referenced the old paragraph name. This commit finishes the refactor so exact-boundary paragraph chunks keep the preserved-separator logic reachable and the new regression coverage stays green. Constraint: Must preserve the existing feature/#47 branch and PR #60 flow while fixing the approved review follow-up Rejected: Revert the layout-preserving chunking refactor | would discard the verified file-layout fix and its regressions Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep chunk reassembly lossless; new chunking changes should continue to round-trip original separators byte-for-byte Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --file <tempfile-with-triple-blank-lines> --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json (expected argument error) Not-tested: Live multi-page service responses beyond the local smoke cases * Preserve spell-check chunk separators when units overflow The file-layout follow-up already preserved blank runs and indentation, but the overlong-unit path still checked the wrong variable when extracting a trailing separator. That could strand separators in a standalone chunk and break exact reassembly for tight max-char limits. This commit fixes the separator extraction guard and locks the behavior with a regression that proves chunk concatenation still matches the original text when an overlong paragraph is followed by a blank-line separator. Constraint: File-mode reconstruction must preserve exact layout while chunking long input Rejected: Broader chunking rewrite | existing structure only needed the overflow guard corrected Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep split_text_into_chunks chunk concatenation identical to the original input for layout-sensitive file checks Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json; manual --file smoke with triple blank lines and indentation Not-tested: Live-service failure modes such as Cloudflare/browser challenges * Prevent clean spell-check chunks from crashing mixed file runs The Nara/PNU surface can return a plain 'no issues found' HTML page without the embedded result payload when a chunk is already clean. Chunked file and markdown runs could hit that response on earlier chunks, raise a ValueError, and never reach later chunks that still needed corrections. Treat the no-issues page as an empty result set and lock the behavior with narrow regression coverage. Constraint: Upstream no-issue responses omit the JavaScript payload entirely and can split the status message across HTML whitespace Rejected: Fabricate a synthetic result page | empty-page handling already preserves the original clean chunk Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep empty-result detection aligned with the upstream no-issues message unless the service publishes a structured empty payload contract Tested: python3 -m unittest scripts.test_korean_spell_check Tested: npm run lint Tested: npm run typecheck Tested: npm test Tested: npm run build Tested: python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json Tested: python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json Tested: python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Tested: python3 scripts/korean_spell_check.py --file <tmpfile> --format json Tested: python3 scripts/korean_spell_check.py --file <tmpfile> --max-chars 18 --format json Not-tested: Other upstream empty-result templates beyond the current no-issues HTML wording * Make Joseon Sillok lookups reproducible from the official site Add a joseon-sillok-search skill and a Python helper that scrape the official Joseon Annals search/detail pages. The helper normalizes king/year metadata, fetches detail excerpts, and locks the repository docs plus regression coverage around the shipped workflow. Constraint: v1 must stay on official public HTML surfaces only Constraint: Must avoid adding new dependencies for a simple scraping helper Constraint: Shell connectivity to sillok.history.go.kr became intermittent during final live reruns Rejected: Ship a new npm workspace | repo skill/docs pattern is enough for v1 Rejected: Add BeautifulSoup or another parser dependency | unnecessary for the bounded HTML patterns Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Keep year filtering Gregorian and derived from official regnal metadata unless the upstream site exposes a better structured contract Tested: npm run ci Tested: Earlier live POST/detail probes against search/searchResultList.do and /id/kda_12512030_002 during implementation Tested: Live official article inspection for kda_12512030_002 via the public site Not-tested: Final end-to-end CLI live run after the last refactor, because the shell hit transient TCP timeouts to sillok.history.go.kr Related: #59 * Prevent sillok follow-up fixes from missing filtered results or weakening trust This follow-up addresses the blocking PR review items on the Joseon Sillok helper. The search loop now derives total pages from the first live page size so king/year filtering can reach later pages, TLS verification stays enabled on both requests and urllib paths, detail parsing accepts the live classification brackets, and repo docs stop linking to missing Korean spell-check assets on this branch. Constraint: Must preserve the existing joseon-sillok-search surface and avoid new dependencies Rejected: Keep verify=False behind an implicit fallback | still weakens authenticity for the default path Rejected: Infer pagination from the hardcoded 50-row default | misses valid later-page matches when the site serves smaller pages Confidence: high Scope-risk: narrow Reversibility: clean Directive: If the official site changes page size or pagination markup again, update the first-page pagination regression before altering search_sillok pagination math Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: python3 scripts/sillok_search.py --query '훈민정음' --king 세종 --year 1443 --limit 1 --timeout 20 Tested: python3 - <<'PY' ... fetch_detail_page(..., article_id='kda_12512030_002', timeout=20) ... PY Not-tested: Successful live sillok.history.go.kr responses in this environment (POST and detail GET both timed out at 20s) Related: PR #62 * Make joseon-sillok-search installs work outside the repo The skill installer only ships the skill directory, so the sillok helper has to live inside that payload. This moves the authoritative helper into joseon-sillok-search/scripts/, keeps the repo-root script as a thin shim for tests and docs, and trims footer metadata from parsed article bodies so excerpts match the published examples. Constraint: skills add exposes only the installed skill payload, not repo-root helpers Rejected: Keep the helper only under scripts/ | installed skill commands fail after copy-only installs Confidence: high Scope-risk: narrow Directive: Keep the repo-root sillok wrapper thin and update the bundled helper first when behavior changes Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: temp installed-skill smoke run of python3 scripts/sillok_search.py --help plus footer-cleaning parse_detail_page check Tested: npm run ci Not-tested: live sillok.history.go.kr shell requests still hit connect timeouts in this environment * Restore the sillok CLI's verified stdlib transport fallback The helper already shipped a stdlib urllib opener that can reach the official search endpoint in environments where requests/urllib3 aborts. This change keeps that opener available even when requests imports successfully and falls back to it on retryable requests transport failures. Added regression coverage for opener availability and the requests-to-urllib fallback so the default CLI path matches the live verified behavior. Constraint: Official sillok detail GETs can still time out transiently in this environment Constraint: Keep TLS verification enabled and preserve the documented CLI entrypoints Rejected: Force urllib for every request | keep the existing requests fast path when it succeeds Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve the stdlib fallback tests whenever the transport layer changes Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: live forced-fallback probe against searchResultList.do with requests.post patched to OSError(22) Not-tested: full live CLI completion through the detail GET in this environment * Document the approved real-estate MCP skill without vendoring upstream Issue #53 is intentionally doc-only, so this change adds the real-estate-search skill, feature guide, setup/security notes, and regression coverage around the upstream real-estate-mcp integration instead of importing server code. The new docs keep the original MCP link, cover Codex/Claude registration, and spell out the self-host + Cloudflare Tunnel + launchd path for environments where no fixed hosted endpoint is available. Constraint: Must use tae0y/real-estate-mcp without copying its source into this repository Constraint: Must include the original MCP link and a stable self-host fallback when no hosted endpoint is available Rejected: Vendor the upstream MCP source | issue explicitly requires skill docs only Rejected: Assume a public hosted MCP endpoint exists | upstream docs did not publish one Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep this integration doc-only; do not add a workspace or vendored server without revisiting issue #53 constraints Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: upstream bootstrap smoke (`uv sync`, `uv run real-estate-mcp --help`, HTTP initialize on 127.0.0.1:8017) Not-tested: live property data queries with a valid DATA_GO_KR_API_KEY * Prevent misleading real-estate self-host instructions Tighten the real-estate skill docs so the launchd fallback stays operational and the Onbid bid-result tools are described with the same WIP caveat the upstream project still publishes. Constraint: Upstream Docker compose already uses restart: unless-stopped while `docker compose ... up -d` daemonizes immediately Rejected: Keep a separate server LaunchAgent with RunAtLoad + KeepAlive | launchd would restart-loop on the exiting compose command Confidence: high Scope-risk: narrow Reversibility: clean Directive: Mirror upstream capability caveats in k-skill docs and do not wrap daemonized server commands in launchd KeepAlive jobs Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: uv sync Tested: uv run real-estate-mcp --help Tested: DATA_GO_KR_API_KEY=dummy uv run real-estate-mcp --transport http --host 127.0.0.1 --port 8017 Tested: curl initialize on http://127.0.0.1:8017/mcp returned protocolVersion 2024-11-05 Not-tested: Live 거래 조회 with a real DATA_GO_KR_API_KEY * Keep install docs from reintroducing broken launchd guidance The install guide had drifted from the real-estate skill and feature docs and still implied that macOS launchd should auto-run both the server and tunnel. This narrows the guidance back to tunnel-only launchd ownership and extends regression coverage so docs/install.md cannot silently reintroduce the server-side loop wording. Constraint: Upstream docker compose already uses restart: unless-stopped Constraint: Review-round-2 scope is limited to docs and regression coverage Rejected: Leave docs/install.md under a generic launchd presence check | it missed the exact server/터널 regression Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep docs/install.md aligned with the detailed real-estate feature guide when self-host guidance changes Tested: node --test scripts/skill-docs.test.js; npm run ci; fresh-clone upstream smoke with uv sync, uv run real-estate-mcp --help, and HTTP initialize on 127.0.0.1:8017/mcp Not-tested: None * Allow Han River water-level lookups without user API keys The proxy now resolves HRFCO water-level stations via waterlevel/info and fetches the latest 10-minute measurement via waterlevel/list, exposing a public summary route plus a hosted skill/docs path. Constraint: HRFCO requires a ServiceKey and station-code-based latest lookup Rejected: Raw passthrough only | forces users to manage upstream details and misses the approved no-key UX Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep this route summary-only and public; expand rainfall/dam/bo/fldfct in separate issues Tested: npm run ci; local server smoke test with HRFCO sample key against /v1/han-river/water-level; tsc diagnostics on packages/k-skill-proxy/src/server.js and src/hrfco.js Not-tested: Hosted production proxy rollout * Expose official nearby fuel prices for location-based gas station lookups Add the first cheap-gas-nearby skill/package pair so nearby gas-price queries can resolve a user-supplied location, translate it into Opinet's KATEC search contract, and return the cheapest nearby stations with address and facility detail. The docs and setup surfaces now advertise the new skill and its Opinet API key requirement. Constraint: Nearby fuel prices must come from the official KNOC Opinet API when available Constraint: No new external dependencies were allowed for coordinate conversion or location resolution Rejected: Map-only gas price scraping | official Opinet Open API exists and is the preferred source Rejected: Require lat/lng input only | poorer UX than supporting landmark/station queries through anchor resolution Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep `OPINET_API_KEY` as the only supported official-price credential unless the repo adopts an Opinet proxy later Tested: npm run ci; node --test packages/cheap-gas-nearby/test/index.test.js; offline fixture smoke via searchCheapGasStationsByLocationQuery('서울역', ...) Not-tested: Live Opinet API call with a real `OPINET_API_KEY` (no non-placeholder key was configured locally) Related: #54 * Explain Blue Ribbon premium gating instead of failing opaquely Blue Ribbon's nearby endpoint now returns PREMIUM_REQUIRED for public requests, so the package now upgrades that response into a stable domain error and updates user-facing docs to describe the degraded nearby state. Regression tests cover both location-query and coordinate-query entrypoints while keeping the existing happy path intact. Constraint: Must not attempt to bypass Blue Ribbon premium access controls Constraint: Package releases must use Changesets metadata Rejected: Silently return empty results on PREMIUM_REQUIRED | would hide the upstream contract change from callers Rejected: Keep generic 403 error and docs unchanged | leaves the main failure mode opaque and misleading Confidence: high Scope-risk: narrow Reversibility: clean Directive: If Blue Ribbon reopens a public nearby surface later, update the docs and replace the premium_required remap only after fresh live verification Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro now returns premium_required metadata Not-tested: Official premium-authenticated nearby flow, because no approved premium credentials are available * Reduce duplicate premium-required test assertions The implementation diff was already verified, so this follow-up keeps the new regression coverage easier to read by sharing one assertion helper instead of repeating the same predicate twice. Constraint: Must preserve the verified PREMIUM_REQUIRED regression coverage exactly Rejected: Leave duplicated inline predicates in both tests | repeats the same contract and adds noise to future edits Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep location-query and coordinate-query regressions aligned when the premium_required error contract changes Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci Not-tested: Additional live Blue Ribbon requests beyond the previously verified premium_required repro * Document an Olive Young search skill around the upstream daiso CLI Issue #61 asked for an Olive Young lookup workflow without vendoring the upstream daiso-mcp server into k-skill, so this change adds a docs-only skill, threads it through repository docs, and locks the guidance with regression assertions. The new guidance prefers CLI-first verification (`npx daiso`) and a clone fallback (`git clone https://github.com/hmmhmmhm/daiso-mcp.git`) instead of requiring direct Claude Code MCP installation. The existing daiso-product-search skill remains untouched. Constraint: Must mention the original https://github.com/hmmhmmhm/daiso-mcp repo Constraint: Must avoid changing the existing daiso-product-search skill Constraint: Must prefer upstream CLI/package usage over direct Claude Code MCP installation Rejected: Vendor upstream Olive Young code into k-skill | contradicts the minimal-addition design request Rejected: Make Claude Code MCP setup the default path | issue explicitly asked for CLI-first usage Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the Olive Young docs aligned with upstream `daiso` CLI behavior and note public endpoint instability when live verification shows it Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: 2026-04-05 live /tmp/daiso-mcp CLI checks for health, /api/oliveyoung/stores, /api/oliveyoung/products, /api/oliveyoung/inventory Not-tested: Authenticated/private Olive Young flows or ordering/payment paths * Keep Han River docs honest until hosted rollout lands The local HRFCO proxy route already works, but the deployed public proxy still lacks /v1/han-river/water-level as of 2026-04-05. This follow-up changes the user-facing docs to require a self-hosted or deployment-verified proxy URL, keeps the intended hosted path documented as rollout-pending, and locks that caveat with a regression test. Constraint: Hosted k-skill-proxy deployment still returns 404 for /v1/han-river/water-level on 2026-04-05 Rejected: Keep advertising the hosted route as the default live path | current deployment is not live yet Confidence: high Scope-risk: narrow Reversibility: clean Directive: Restore hosted-default wording only after the public proxy route and HRFCO configuration are verified live Tested: node --test scripts/skill-docs.test.js; npm run ci; local mocked smoke via node packages/k-skill-proxy/src/server.js + GET /v1/han-river/water-level?stationName=한강대교 Not-tested: Live hosted k-skill-proxy behavior after deployment * Keep cheap gas lookups from failing on recoverable Kakao and input issues The lookup now walks ranked Kakao anchor candidates until one returns usable coordinates, and it rejects invalid limit inputs instead of silently collapsing non-empty results into an empty list. The regression suite now locks both review repros plus the null-coordinate normalization edge case that surfaced while implementing the fallback. Constraint: Kakao place panels can be partially populated or return 404 for otherwise valid search candidates Rejected: Default invalid limit/detailLimit values silently | still masks caller bugs and can look like no results nearby Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep anchor resolution tolerant of unusable Kakao panels before failing the whole lookup Tested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...) Not-tested: Live Opinet/Kakao network path without a real OPINET_API_KEY * Keep Olive Young install guidance aligned with live retry behavior Issue #61's initial branch already shipped the olive-young-search skill/docs set, but the install guide did not have a regression lock for the public endpoint instability note captured during live verification. This follow-up adds that test first and updates the install quickstart so retry-or-clone fallback guidance stays in sync with the verified daiso CLI workflow. Constraint: Must keep the follow-up scoped to the approved issue #61 docs behavior Constraint: Public olive-young endpoint can intermittently return 5xx/503 during live verification Rejected: Re-open the broader feature docs set | the existing branch already covered the main feature scope Rejected: Leave the retry guidance untested in install docs | risk of future doc drift across surfaces Confidence: high Scope-risk: narrow Reversibility: clean Directive: If live olive-young verification changes again, update install docs and the regression together so retry/fallback guidance stays honest Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: cd /tmp/daiso-mcp && npx daiso health Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/stores --keyword 명동 --limit 3 --json Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/products --keyword 선크림 --size 3 --json Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json Not-tested: Authenticated Olive Young flows or sustained-rate retry behavior beyond the documented smoke checks * Preserve ranked Kakao anchor fallbacks after panel failures The resolver already retried later Kakao panels, but after the best panel failed it walked the remaining candidates in raw HTML order. Centralizing the full anchor ranking in parse.js keeps fallback iteration aligned with the existing scoring rules and locks the review repro with a regression test for 강남역 ordering. Constraint: Kakao place panels can 404 or omit coordinates even when later ranked candidates are usable Rejected: Re-rank only after a failed panel | duplicates scoring logic and drifts from selectAnchorCandidate Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep resolveAnchor fallback order tied to the shared anchor scoring logic rather than raw Kakao result order Tested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); lsp diagnostics on affected files Not-tested: Live Kakao/Opinet network calls with a non-placeholder OPINET_API_KEY * Clarify that Blue Ribbon coordinate lookups fail the same way The premium gate now affects both location-query and coordinate-entry nearby flows. Record that parity in the skill and docs so the live 2026-04-05 repro evidence stays aligned with the shipped public contract. Constraint: /restaurants/map remains premium-gated for public requests as of 2026-04-05 Rejected: Add more code changes without a behavior gap | would add churn after the approved fix already landed Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the docs/examples aligned with live repro evidence whenever Blue Ribbon changes nearby access behavior Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro for location + coordinates premium_required contract Not-tested: New upstream success-path live nearby payloads, because public access is still premium-gated * Document a runnable Olive Young clone fallback The follow-up review found that clone-local `npx daiso` commands do not run from a built `hmmhmmhm/daiso-mcp` checkout because the generated bin file is not executable. This updates the olive-young skill and docs to use the verified `node dist/bin.js ...` path for clone fallback, and locks that behavior with regression tests while keeping the public CLI-first path unchanged.\n\nConstraint: Upstream clone checkouts can fail with `Permission denied` when invoked through clone-local `npx daiso`\nConstraint: Keep the existing daiso-product-search skill untouched\nRejected: Leave install docs unchanged | PR body and docs would keep a broken clone fallback path\nRejected: Vendor or patch upstream daiso-mcp inside k-skill | issue explicitly requires documenting upstream flow instead\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep clone-fallback docs and PR verification commands aligned with the actually runnable local invocation\nTested: node --test scripts/skill-docs.test.js\nTested: npm run ci\nTested: cd /tmp/daiso-mcp && npm install && npm run build && node dist/bin.js health\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/stores --keyword 명동 --limit 3 --json\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/products --keyword 선크림 --size 3 --json\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json\nNot-tested: Public npx endpoint stability beyond the verified smoke-test window * Record fresh verification for the approved cheap-gas follow-up The ranked Kakao fallback-order and invalid-limit fixes are already present on feature/#54, so no further code edits were necessary. This empty follow-up commit records the requested rerun verification for PR #67 before posting the implementation update.\n\nConstraint: Existing branch head already contains the approved cheap-gas-nearby follow-up\nRejected: Invent another code/doc change just to force a non-empty diff | unnecessary risk after approval\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep Kakao anchor fallback iteration tied to the shared ranking helper and preserve finite-number validation for limit inputs\nTested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); lsp diagnostics on affected files\nNot-tested: Live Kakao/Opinet network calls with a non-placeholder OPINET_API_KEY * Record verified delivery for approved cheap-gas-nearby rollout The approved Issue #54 implementation was already present on feature/#54 when this follow-up began, so this checkpoint records fresh verification evidence and keeps PR #67 moving without introducing extra code churn. Constraint: Existing approved fixes were already on the branch and the follow-up still required a pushed update plus implementation comment Rejected: Add additional code or docs churn | approved scope was already satisfied and green locally Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve the Kakao fallback-order and invalid-count regression coverage unless equivalent runtime repros replace it Tested: node --test packages/cheap-gas-nearby/test/index.test.js; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); npm run ci; LSP diagnostics on affected cheap-gas-nearby files Not-tested: Live Kakao/Opinet network path without a non-placeholder OPINET_API_KEY * Keep Blue Ribbon premium-gate remapping explicitly bounded The issue #63 fix already remaps PREMIUM_REQUIRED for nearby lookups. This follow-up adds a regression that proves non-premium /restaurants/map failures still surface as generic request errors, and clarifies that boundary in the package and feature docs. Constraint: PR #68 already carries the shipped behavior change and must stay aligned with current live premium-gated upstream behavior Rejected: Broaden domain remapping to all 403 nearby errors | would hide distinct upstream failure modes Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep only PREMIUM_REQUIRED on /restaurants/map mapped to premium_required unless a new verified upstream contract is documented Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro for location+coordinate nearby lookups on 2026-04-06; LSP diagnostics on src/test Not-tested: Alternative non-premium upstream status codes beyond the mocked 403 ACCESS_DENIED path * Keep Olive Young clone fallback docs runnable from a fresh clone Round 3 review found that the inline fallback shorthand skipped `cd daiso-mcp`, which made `npm install` run outside the cloned upstream repo even though the fenced examples were already correct. This tightens the two published shorthand snippets and adds regression coverage so both docs surfaces reject the broken chain in future edits. Constraint: Existing node dist/bin.js clone fallback examples were already verified and had to stay aligned Constraint: The follow-up had to stay scoped to docs/test coverage without touching the existing daiso-product-search skill Rejected: Convert the shorthand to prose only | the review specifically requested a runnable inline form or an explicit removal Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep inline clone fallback snippets synchronized with the fenced node dist/bin.js examples and require `cd daiso-mcp` before install/build Tested: node --test scripts/skill-docs.test.js; npm run ci; cd /tmp/daiso-mcp && npm install && npm run build; cd /tmp/daiso-mcp && node dist/bin.js health; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/stores --keyword 명동 --limit 3 --json; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/products --keyword 선크림 --size 3 --json; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json Not-tested: Public npx path in this follow-up round (previous PR verification already covered it) Related: PR #71 * Bundle korean-spell-check script inside skill directory for packageless installs The Python helper lived only in the repo-root scripts/ folder, so `skills add` never shipped it. Move the real implementation into korean-spell-check/scripts/ (mirroring joseon-sillok-search) and replace the root copy with a thin re-export wrapper so lint/test still resolve from the repo root. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Exclude .claude directory from skill validation to fix CI in worktrees Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * real-estate-search: MCP self-host → k-skill-proxy HTTP 전환 사용자가 직접 real-estate-mcp를 clone/self-host하는 대신 k-skill-proxy에 MOLIT 실거래가 API route를 추가해서 다른 스킬(한강수위, 미세먼지 등)과 동일한 패턴으로 사용 가능하게 함. - GET /v1/real-estate/region-code — 지역코드 검색 - GET /v1/real-estate/:assetType/:dealType — 9개 거래 유형 조회 - molit.js: XML 파싱, 필드 정규화, 취소거래 필터링, 요약통계 - region-lookup.js: 284개 법정동 5자리 코드 토큰 매칭 - SKILL.md/docs를 HTTP proxy 기반으로 전면 재작성 - DATA_GO_KR_API_KEY를 사용자 필수항목에서 프록시 운영자 전용으로 이동 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * cheap-gas-nearby: proxy 경유로 전환 + 프로덕션 배포 구조 문서화 - cheap-gas-nearby: OPINET_API_KEY 없이 k-skill-proxy 경유로 동작하도록 변경 - fetchAroundStations/fetchDetailById에 proxy fallback 추가 - SKILL.md, feature doc에서 사용자 API key 요구 제거 - AGENTS.md, CLAUDE.md: proxy 개발/배포 워크플로우 문서화 - docs/features/k-skill-proxy.md: opinet route 추가, 프로덕션 자동 배포 구조 설명 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * blue-ribbon-nearby: proxy 경유로 전환 + 프리미엄 세션 프록시 라우트 Blue Ribbon /restaurants/map이 프리미엄 전용으로 전환되어, k-skill-proxy에 BLUE_RIBBON_SESSION_ID 기반 프록시 라우트를 추가하고 blue-ribbon-nearby 패키지가 기본적으로 프록시를 경유하도록 변경. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Document a bunjang-cli workflow for Bunjang marketplace lookups Issue #73 adds a new root skill plus matching repository docs/tests so agents can guide 번개장터 searches, detail reads, optional login-gated favorites/chats, and bulk export flows without vendoring upstream code. Constraint: Reuse upstream bunjang-cli instead of adding a new crawler or package wrapper Constraint: favorite/chat flows require a headful TTY login and cannot be fully smoke-tested non-interactively Rejected: Add a local workspace/package wrapper | docs-only skill scope does not justify new abstraction Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the skill CLI-first and treat favorite/chat/purchase as optional login flows unless a live authenticated session is intentionally available Tested: npm run ci Tested: npx --yes bunjang-cli --help Tested: npx --yes bunjang-cli --json auth status Tested: npx --yes bunjang-cli --json search "아이폰" --max-items 1 Tested: npx --yes bunjang-cli --json item get 354957625 Tested: bunjang-cli JSON/AI export smoke runs with --with-detail/--output and --ai --output Not-tested: Authenticated favorite/chat round-trip in a logged-in interactive browser session * Prevent Bunjang agents from trusting noisy search summaries Live bunjang-cli verification showed that search results are safe for title/price triage, but not for reliable description/status/location decisions. This update tightens the skill and feature docs around that boundary and locks it with a regression assertion so future edits do not drift back into summary-field assumptions. Constraint: bunjang-cli search summary fields are transport-dependent and can omit or mangle description/status/location Rejected: Keep region/status-first shortlist guidance in search docs | live verification returned malformed location and missing description/status Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not reintroduce description/status/location-based search triage without re-verifying the live search payload contract Tested: node --test scripts/skill-docs.test.js; npm run ci; npx --yes bunjang-cli --help; npx --yes bunjang-cli --json auth status; npx --yes bunjang-cli --json search "아이폰" --max-items 1; npx --yes bunjang-cli --json item get 354957625; npx --yes bunjang-cli search "아이폰" --max-items 2 --with-detail --output /tmp/bunjang-73-export-XXXXXX.json; npx --yes bunjang-cli search "아이폰" --max-items 2 --with-detail --ai --output /tmp/bunjang-73-ai-Xp2bu0 Not-tested: Authenticated favorite/chat round-trip still requires an interactive TTY login session * Shield Korean stock lookups behind the proxy so users avoid KRX key setup Use the local k-skill proxy as the public integration surface for Korea Exchange stock data. The new skill/docs flow starts with stock search, then narrows into base-info and trade-info lookups, while the proxy injects KRX credentials server-side only. Constraint: KRX_API_KEY must remain server-side under the repo's free read-only proxy policy Rejected: Expose upstream korea-stock-mcp setup to end users | would force user-issued KRX keys and a heavier install path Confidence: high Scope-risk: moderate Directive: Keep Korean stock access proxy-first and read-only; do not move KRX_API_KEY into client setup docs Tested: node --test packages/k-skill-proxy/test/server.test.js scripts/skill-docs.test.js; npm run ci; local proxy smoke on port 4120 (/health 200, /v1/korean-stock/search 503 without KRX_API_KEY) Not-tested: Live upstream success path with a real local KRX_API_KEY * Protect KRX proxy responses from insecure or mismatched upstream data Review follow-up switches KRX endpoints to HTTPS and removes the single-row trade fallback that could mislabel an unrelated stock as the requested code. Regression tests now assert HTTPS transport for search/base/trade flows and 404 behavior for unmatched single-row trade responses. Constraint: KRX key must never leave the proxy over plaintext transport Constraint: No local KRX_API_KEY is available for live upstream success verification Rejected: Keep the single-row trade fallback with a synthetic code rewrite | can fabricate mismatched stock responses Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not reintroduce inferred short-code fallbacks without validating them against matching base-info first Tested: node --test packages/k-skill-proxy/test/server.test.js scripts/skill-docs.test.js; npm run ci; local proxy smoke on 127.0.0.1:4120 (/health 200, /v1/korean-stock/search?q=삼성전자&bas_dd=20260404 503 without KRX_API_KEY); lsp diagnostics on changed files Not-tested: live KRX upstream success path with a real KRX_API_KEY * Close the remaining Korean stock proxy gaps before public rollout The KRX search route trusted spoofable direct-request IP headers and failed whole-search fanout when one market snapshot errored. This change keys rate limits off Fastify's resolved request.ip, reuses per-market base snapshots across same-date queries, and keeps healthy search results available when one market fails while new regressions lock the behavior. Constraint: Public proxy routes stay unauthenticated, so abuse controls must not depend on untrusted client headers Constraint: Search must still fail loudly when every market fetch fails Rejected: Keep trusting cf-connecting-ip on direct requests | direct clients can rotate the header to reset the bucket Rejected: Promise.all all-or-nothing market fanout | one failing market hid healthy KOSPI results Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep Korean stock rate limiting keyed to Fastify-resolved client IP unless trust-proxy behavior is explicitly audited end-to-end Tested: node --test packages/k-skill-proxy/test/server.test.js scripts/skill-docs.test.js; npm run ci; local proxy smoke on 127.0.0.1:4120; targeted inject script for spoofed-header rate limiting and partial-market failure Not-tested: Live KRX success with a real KRX_API_KEY * Feature/#57 (#69) * Hide KMA forecast keys behind the public proxy Add a Korea weather skill plus a new k-skill-proxy route for the KMA short-term forecast API. The route accepts grid coordinates or lat/lon, defaults to the latest safe base time, and keeps the user workflow keyless while the proxy owns the upstream credential. Constraint: KMA short-term forecast requires a service key and 5km grid parameters Constraint: Must keep the client flow dependency-free and free of user API issuance Rejected: Direct client-side KMA calls | would force end users to issue and store their own keys Rejected: Add a third-party geocoder dependency | unnecessary for v1 when lat/lon-to-grid conversion is enough Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep future KMA integrations on explicit allowlisted proxy routes and avoid documenting upstream keys for clients Tested: npm run ci; local HTTP smoke test for /v1/korea-weather/forecast with mocked upstream fetch; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json Not-tested: Live KMA upstream call with a production service key * Reject invalid weather coordinates before proxying The korea-weather forecast route already normalized valid lat/lon requests, but out-of-range inputs could still project to NaN grid values and consume upstream quota. This change rejects invalid latitude/longitude pairs at the boundary and locks the behavior with a regression that proves invalid coordinates never reach fetch. Constraint: Public proxy endpoints must reject malformed caller input before upstream calls Rejected: Allow upstream KMA failures to handle invalid coordinates | wastes quota and returns opaque errors Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep coordinate validation local to query normalization so cache keys and upstream URLs only see finite grid values Tested: node --test packages/k-skill-proxy/test/server.test.js; local app.inject smoke for /v1/korea-weather/forecast with mocked fetch; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm run ci Not-tested: Live KMA upstream behavior for invalid coordinates (intentionally blocked before proxying) * Protect proxied public-data API keys with HTTPS transport The new korea-weather route already hid the KMA service key behind the proxy, but it was still forwarding that key over plaintext HTTP. Switching the shared data.go.kr proxy base URL to HTTPS keeps the existing request contract intact while closing the transport exposure. Regression coverage now locks the weather route and direct KMA proxy helper to HTTPS so the downgrade does not regress. Constraint: The follow-up had to stay minimal on the existing PR branch Rejected: Add a KMA-only base URL constant | unnecessary divergence from the shared data.go.kr transport setting Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep proxied upstreams on HTTPS whenever the provider supports it, especially when operator-managed keys are injected server-side Tested: node --test packages/k-skill-proxy/test/server.test.js; local buildServer().inject smoke with mocked fetch; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm run ci Not-tested: Live network call to KMA upstream with a real service key * Merge dev into main: new skills & proxy enhancements (#72) * Remove client-side Seoul subway key setup Route Seoul subway arrival lookups through k-skill-proxy so the hosted proxy owns the Seoul Open Data upstream key and end users only need the proxy base URL. Add proxy route coverage, update skill/docs guidance, and align setup materials with the hosted proxy flow used for fine dust. Constraint: Must keep the proxy public, read-only, and dependency-free Constraint: Must satisfy TDD-first verification and ship on feature/#35 targeting dev Rejected: Add a separate client helper package | unnecessary extra layer for a single proxy route Rejected: Keep SEOUL_OPEN_API_KEY as an end-user requirement | defeats the issue goal Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the Seoul subway proxy surface limited to station-arrival passthrough unless tests/docs expand the contract Tested: npm run ci; local proxy runtime on 127.0.0.1:4120 for /health and /v1/seoul-subway/arrival on 2026-03-31 with an invalid upstream key Not-tested: Live success response with a valid Seoul Open API key Related: #35 * Prevent broken Seoul subway proxy defaults before hosted rollout The Seoul subway proxy endpoint code is present locally, but the hosted public route is not live yet. This change turns the user-facing subway docs back into an explicit proxy configuration flow, replaces the misleading hosted default in setup examples, and keeps subway proxy examples on self-host/local URLs until rollout is verified. Constraint: Hosted k-skill-proxy.nomadamas.org/v1/seoul-subway/arrival is not live yet Rejected: Keep the hosted Seoul subway URL as the default path | would send default users to a 404 route Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not restore a hosted Seoul subway default until the public proxy route is deployed and smoke-verified Tested: node --test scripts/skill-docs.test.js; npm run ci; local proxy smoke on 127.0.0.1:4120 with stubbed Seoul upstream (GET /health, GET /v1/seoul-subway/arrival?stationName=강남) Not-tested: Live hosted proxy smoke after deployment * Reduce Seoul subway proxy upstream pressure with request caching The public subway arrival route already normalized caller input but still re-fetched the Seoul upstream for every identical poll. This change adds a short-TTL cache keyed from the normalized subway query, annotates JSON responses with cache metadata, and locks the repeated-read collapse with a regression that proves alias/default normalization still reuses the cached result. Constraint: The endpoint must stay public/no-auth while protecting a shared server-side SEOUL_OPEN_API_KEY from unnecessary repeated upstream hits Rejected: Add a new shared cache abstraction for proxy metadata | unnecessary for this narrow fix and would enlarge the diff Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep subway cache keys tied to normalizeSeoulSubwayQuery output so alias/default query forms continue collapsing to one upstream request Tested: node --test packages/k-skill-proxy/test/server.test.js Tested: npm run ci Tested: Local proxy runtime on 127.0.0.1:4120 with SEOUL_OPEN_API_KEY=test-seoul-key and stubbed fetch for /health plus repeated /v1/seoul-subway/arrival requests Not-tested: Live hosted proxy rollout state * Document OpenClaw support in the public compatibility list The approved scope for issue #29 was narrowed to README support messaging, so this change adds OpenClaw/ClawHub to the supported-client line and locks that wording with a regression test in the docs suite. Constraint: Issue #29 was approved as a README-only compatibility/docs change Rejected: Broader install-doc updates | out of approved scope for this issue Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep OpenClaw support wording aligned with the supported-client README line and its docs regression test Tested: Focused Node docs regression, npm run lint, npm run typecheck, npm run build, npm test Not-tested: Live OpenClaw or ClawHub install flow (issue scope was documentation-only) * Protect README client-support claims from ClawHub regressions The README already advertises OpenClaw/ClawHub, but the docs regression only matched OpenClaw. Tighten the assertion to the exact supported-client fragment so a future edit cannot silently remove ClawHub while keeping the issue verification command stable. Constraint: PR #39 already publishes a verification command keyed to the current test name Rejected: Rename the test to mention ClawHub explicitly | would drift from the published verification command Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep this regression synchronized with the README supported-client line whenever that copy changes Tested: node --test scripts/skill-docs.test.js --test-name-pattern 'README advertises OpenClaw among the supported coding agents' Tested: npm run lint Tested: npm run typecheck Tested: npm run build Tested: npm test Tested: lsp diagnostics for scripts/skill-docs.test.js (0 errors) Not-tested: N/A * Make Coupang shopper research usable without pretending scraping is stable Coupang blocks unattended shopper queries in this environment, so the new package focuses on the durable pieces we can ship honestly: official URL builders, browser-captured HTML parsers, and explicit automation probes. The docs and skill now explain the seller-API limitation, the verified anti-bot behavior, and the browser-capture fallback expected by callers. Constraint: No general shopper Open API surfaced in Coupang's official developer docs Constraint: Headless/direct retrieval is anti-bot blocked in verified local probes Rejected: Bundle a scraping bypass or hidden browser dependency | violates repo policy and would over-claim reliability Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep probe/docs behavior aligned with fresh live verification before claiming unattended Coupang access works Tested: npm run ci; live probeAutomation(query=생수) with direct fetch + Playwright-core browserFetchHtml; LSP diagnostics on changed JS/test files Not-tested: Headed/manual browser sessions with a human-authenticated Coupang context * Keep the Coupang workspace installable and its entrypoint honest Review follow-up found two contract gaps in the first issue #36 rollout: fresh installs were missing the new workspace link in package-lock, and the package README documented parser helpers that were not exported from the package entrypoint. Refreshing the lockfile and re-exporting the parsers keeps npm ci and consumer imports aligned with the published API. Constraint: npm ci must succeed from a clean checkout Rejected: Narrow the README API list to only client helpers | would hide useful parsers that the package already ships and tests Confidence: high Scope-risk: narrow Reversibility: clean Directive: When adding a new workspace, refresh package-lock and verify the package entrypoint matches README public API claims Tested: npm run ci; workspace coupang-product-search tests; LSP diagnostics on coupang-product-search JS/test files Not-tested: published npm install from registry (local pack dry-run only) * Keep Coupang anti-bot docs honest as probe results drift A same-day PR rerun showed the published mobile probe snapshot was already stale, so the follow-up locks the 403/access-denied mobile path with regression coverage and softens the docs/skill contract to describe blocked outcome classes instead of one frozen signature. The published guidance now also explains that browser results only appear when browserFetchHtml is injected, matching what a clean checkout can actually reproduce. Constraint: Coupang anti-bot responses vary by edge/challenge between reruns on the same day Rejected: Freeze one exact mobile probe snapshot | same-day reruns already diverged Confidence: high Scope-risk: narrow Reversibility: clean Directive: Refresh Coupang anti-bot docs only with same-day live probe evidence, and prefer blocked outcome classes over a single exact signature when reruns disagree Tested: npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch Not-tested: Non-Chrome Playwright-core executables * Keep the Coupang skill honest about clean-checkout browser probes The approved follow-up already documented that clean-checkout probeAutomation runs leave browser unset unless a browser fetcher is injected, but the skill text itself had not made that null contract explicit. This commit adds a regression test that locks the browser-null wording across the published docs surfaces and updates the skill so the stated behavior matches the package implementation and clean-checkout reality. Constraint: probeAutomation() only populates browser when browserFetchHtml is supplied by the caller Rejected: Leave the skill wording implicit and rely on README examples alone | the skill could drift away from the shipped package contract again Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the README, feature doc, and skill aligned whenever the probeAutomation browser contract changes Tested: node --test packages/coupang-product-search/test/index.test.js; npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch; codex exec review --uncommitted Not-tested: Alternative browser engines beyond local Google Chrome for the manual browserFetchHtml probe * Keep Coupang browser probe docs aligned with manual verification paths The approved PR #40 follow-up still had one wording gap: the skill said when browser results appear, but it did not explicitly say those populated results come from an injected manual/external browserFetchHtml path. This change locks that contract with a failing regression first, then updates the skill text to match the already-shipped README/feature-doc guidance and runtime behavior. Constraint: clean-checkout probeAutomation() must keep browser null unless browserFetchHtml is supplied Rejected: change runtime browser probe behavior | approved follow-up was docs/test only and runtime contract is already correct Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep Coupang probe docs aligned with the shipped browserFetchHtml injection contract; do not imply built-in browser probing in clean checkouts Tested: node --test packages/coupang-product-search/test/index.test.js; npm run lint; npm run typecheck; npm test; npm run ci; live probeAutomation("생수") with direct fetch + Playwright-core browser fetch; lsp diagnostics on changed files; architect review approved Not-tested: alternate browser engines beyond local Google Chrome + playwright-core manual runner * Route Korean law lookups through korean-law-mcp Add a documentation-first korean-law-search skill and lock the repo docs around the rule that Korean law queries must go through korean-law-mcp rather than a new in-repo package. The change updates install/setup/security guidance, publishes the new feature doc, and adds regression tests so future edits keep the LAW_OC + korean-law-mcp contract intact. Constraint: Issue #41 requires korean-law-mcp for every Korean law lookup Constraint: Must not add a new npm or python package in this repository Rejected: Add a repo-local law package | violates the no-new-package requirement and duplicates upstream MCP work Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep Korean law lookup guidance pinned to korean-law-mcp unless issue requirements explicitly change Tested: node --test scripts/skill-docs.test.js Tested: npm install -g korean-law-mcp && korean-law list && korean-law help search_law Tested: npm run ci Tested: npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json Not-tested: live search_law/get_law_text against a real LAW_OC credential * Clarify Korean law setup modes to avoid credential confusion A review found the new korean-law-search docs treated LAW_OC as an unconditional prerequisite even though the upstream remote MCP endpoint is configured separately from the local CLI/server path. This update makes the docs and regression tests mode-specific: local CLI/MCP uses LAW_OC, while the remote endpoint stays a korean-law-mcp-only url fallback without a user-supplied credential. Constraint: Upstream korean-law-mcp uses LAW_OC on the local CLI/server path while the documented remote MCP endpoint is configured with url only Rejected: Keep LAW_OC mandatory for every korean-law-mcp mode | contradicts upstream docs and reviewer evidence Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep README/setup/skill docs and regression tests aligned on the local-vs-remote korean-law-mcp contract Tested: node --test scripts/skill-docs.test.js; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm run ci; lsp_diagnostics scripts/skill-docs.test.js Not-tested: Live remote MCP endpoint connection against https://korean-law-mcp.fly.dev/mcp * Record issue #41 follow-up after approved verification The approved korean-law-search change was already present on feature/#41, so this follow-up records a fresh verification pass and updates the PR without introducing unnecessary code churn. Constraint: Existing branch already contained the approved implementation Rejected: Touch repo files without need | would create noise without improving behavior Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the korean-law-mcp-only + mode-specific LAW_OC contract aligned with upstream docs before changing these surfaces again Tested: node --test scripts/skill-docs.test.js; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npm run ci Not-tested: Live korean-law queries that require a real LAW_OC or remote endpoint session * Keep the Korean law feature diff merge-ready Verification uncovered trailing whitespace in the new korean-law feature guide when checking the branch diff. I added a regression to the skill docs suite and removed the whitespace so the approved documentation contract stays clean and reviewable. Constraint: Preserve the existing korean-law-mcp + mode-specific LAW_OC contract without widening scope Rejected: Leave the whitespace issue as-is | git diff --check stayed dirty on the branch Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep docs/features/korean-law-search.md free of trailing whitespace so diff hygiene stays enforced by the regression Tested: node --test scripts/skill-docs.test.js; npx tsc --noEmit --pretty false --project /Users/jeffrey/Projects/k-skill/tsconfig.json; npm install -g korean-law-mcp && korean-law list && korean-law help search_law; npm run ci; git diff --check Not-tested: Live credentialed LAW_OC search execution against the upstream API * Keep Korean law skill guidance aligned with supported lookups The approved issue #41 feature already worked, but the shipped skill text still under-described ordinance and interpretation lookups compared with the documented capability set. This follow-up tightens the skill copy and locks that contract with a doc regression so the branch stays merge-ready without changing the underlying korean-law-mcp routing rules. Constraint: Must preserve the existing korean-law-mcp-only and mode-specific LAW_OC setup contract Rejected: Leave the skill wording as-is | drift from the documented lookup surface would remain Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the skill examples and doc regression aligned whenever supported korean-law-mcp search surfaces change Tested: node --test scripts/skill-docs.test.js Not-tested: live LAW_OC-backed upstream API queries * Keep Korean law completion guidance in sync with enforced lookups The previous follow-up aligned the main skill examples, but the done-criteria text still left interpretation and ordinance routing implicit. This commit makes the completion checklist explicit and extends the doc regression so future edits cannot silently drop those lookup paths. Constraint: Must stay within the existing issue #41 korean-law-mcp-only contract Rejected: Leave the done checklist implicit | reviewers and future edits could drift from the enforced lookup set Confidence: high Scope-risk: narrow Reversibility: clean Directive: When the supported Korean-law lookup set changes, update the done checklist and regression together Tested: node --test scripts/skill-docs.test.js Not-tested: full CI before commit * Enable repeatable used-car price lookups from a rental-company source Issue #46 required surveying major Korean rental companies before implementation and then choosing the easiest stable provider. SK렌터카 다이렉트 exposes 타고BUY inventory in public Next.js page data, so the feature stays dependency-free while still supporting live repeated lookups and documented provider rationale. Constraint: Must compare major Korean rental companies before implementation Constraint: Must verify 10+ live lookups against a real provider surface Rejected: 롯데오토옥션 as v1 provider | public list contract was unstable and legacy .do flows returned inconsistent or 404 pages Rejected: 레드캡렌터카 as v1 provider | no public used-car inventory or API surface was found Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the v1 provider read-only and inventory-snapshot-based unless a stable documented public API is confirmed Tested: npm run ci Tested: Live 10-query run against https://www.skdirect.co.kr/tb at 2026-04-02T07:22:46Z Tested: LSP diagnostics on affected files Not-tested: Seller-specific detail drilldowns or non-SK providers Related: #46 * Keep used-car-price-search releasable after merge Review feedback found that the new used-car workspace would not ship because it lacked a changeset, and the fallback install docs still omitted the runtime package. This follow-up adds regression coverage first, then restores both release and install-path coverage with the smallest possible diff. Constraint: New publishable workspaces must be wired through Changesets to reach npm release automation Constraint: Fallback install docs must list runtime packages users need when skill files are present but global packages are missing Rejected: Fix only the changeset gap | would leave the documented fallback install path incomplete Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep used-car-price-search in both the fallback global install example and a Changesets entry whenever release wiring changes Tested: node --test scripts/skill-docs.test.js; npx changeset status; live 10-query used-car run against SK direct at 2026-04-02T07:38:44.949Z; npm run ci; LSP diagnostics on used-car package files and scripts/skill-docs.test.js; architect verification Not-tested: No additional live provider permutations beyond the verified 10-query smoke run * Keep used-car verification docs resilient to live inventory churn A fresh rerun showed the SK direct inventory total continues to move during the day, so the feature doc now records the verified smoke-run timestamp without freezing a brittle exact count. The regression suite was updated first so the docs stay variability-aware and diff-clean in future follow-ups. Constraint: Live SK direct inventory totals change over time even when the parsing contract stays stable Rejected: Keep documenting a fixed total from one smoke run | it immediately drifted and made the docs stale Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the used-car live verification note timestamped and variability-aware instead of pinning an exact inventory total Tested: node --test scripts/skill-docs.test.js; git diff --check; npm run ci; npx changeset status; live 10-query run against https://www.skdirect.co.kr/tb at 2026-04-02T07:59:41.391Z; LSP diagnostics on scripts/skill-docs.test.js; architect verification Not-tested: No additional content changes outside the used-car feature doc * Keep used-car query summaries honest when results are limited The review found that query-level stats were being computed from the post-limit slice, so common searches like 아반떼 under-reported both match counts and price ranges. This change locks the regression first, then computes the full filtered set before slicing only the returned items. Constraint: PR #48 must preserve the existing API shape while fixing the review-blocking stats bug Rejected: Expanding the response with separate limited/full summary fields | unnecessary API churn for a targeted bug fix Confidence: high Scope-risk: narrow Reversibility: clean Directive: Query-level summary and matchedCount must stay derived from the full filtered set, not the display limit slice Tested: npm test --workspace used-car-price-search; npm run ci; git diff --check; npx changeset status; live SK direct smoke run on 2026-04-02T08:23:59Z; LSP diagnostics on used-car-price-search source and test files; architect verification APPROVED Not-tested: limit=0 semantics remain unchanged and still coerce to the default limit Related: PR #48 * Keep korean-law-search available during upstream outages (#45) Issue #44 adds Beopmang as the documented fallback when the primary korean-law-mcp path is unavailable, and locks the new routing into the doc regression suite so future edits do not silently revert the policy. Constraint: Existing guidance must still prefer korean-law-mcp and keep LAW_OC scoped to the local CLI/MCP path Rejected: Add a repo-local Beopmang client package | issue only requires fallback registration, not a new implementation surface Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the primary-first rule intact; Beopmang is an outage fallback, not the default path Tested: node --test scripts/skill-docs.test.js; npm run ci; korean-law list; python3 live Beopmang search smoke for 관세법 Not-tested: Live Beopmang MCP handshake from a GUI MCP client * Replace coupang scraping package with coupang-mcp server integration Drop the browser-based scraping package (packages/coupang-product-search) and switch to the uju777/coupang-mcp MCP server for all Coupang product searches. This removes the anti-bot workaround complexity and provides 8 ready-to-use tools via MCP Streamable HTTP with no API key required. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add disclaimer to used-car-price-search README Clarify that the package queries SK렌터카 타고BUY public data with no affiliation or sponsorship, and that ad/partnership inquiries are welcome. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Refactor used-car-price-search into provider-based architecture SK 타고BUY 전용 로직을 src/providers/sk-tagobuy.js로 분리하고, 공급자를 수평 확장할 수 있는 registry 구조로 전환한다. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Ship LCK analytics inside k-skill's managed release flow Adapt jerjangmin's upstream lck-analytics skill/package into a new workspace and skill pack, wire docs/install/release surfaces, and add regression fixtures/tests plus script smoke coverage so the feature is verifiable before publish. Constraint: Upstream package is not published to npm yet Constraint: Must preserve attribution to original source and author in shipped docs Rejected: Keep the upstream lck-results install wording in k-skill | conflicts with repo workspace/package naming Rejected: Ship only the npm package without the local skill scripts | issue explicitly requested the skill as well Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep Changesets as the only version-bump path for lck-analytics; do not hand-edit versions for release Tested: node --test packages/lck-analytics/test/index.test.js scripts/skill-docs.test.js Tested: npm run lint --workspace lck-analytics Tested: npm test --workspace lck-analytics Tested: live getLckSummary('2026-04-01', { team: '한화', includeStandings: true }) Tested: node lck-analytics/scripts/sync-oracle.js --csv lck-analytics/samples/oracle-lck-sample.csv --cache .tmp/lck-cache && node lck-analytics/scripts/build-match-report.js --date 2026-04-01 --team 한화 --cache .tmp/lck-cache && node lck-analytics/scripts/analyze-live-game.js --game game-1 --window packages/lck-analytics/test/fixtures/live-window-game-1.json --details packages/lck-analytics/test/fixtures/live-details-game-1.json --cache .tmp/lck-cache Tested: npm run ci Tested: npx tsc --noEmit --project /Users/jeffrey/Projects/k-skill/tsconfig.json Not-tested: Riot live feed behavior for arbitrary future game ids outside the fixture-backed smoke path * Enable policy-aware Korean spell checking from the official Nara surface Add a skill guide and Python helper that use the approved old_speller HTML flow, chunk long text conservatively, and report original/suggestion/reason deltas. The docs also record the public-site limits, Cloudflare behavior, and non-commercial usage policy so agents do not overreach the free surface. Constraint: Public site is HTML-only and may return 403 to non-browser clients Constraint: Must not add new dependencies or high-volume crawling behavior Rejected: Node fetch client | Cloudflare returned 403 in this environment Rejected: Paid API integration | no public contract or credentials were available for this task Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep usage low-rate and non-commercial unless supplier-approved API terms are added Tested: npm run lint Tested: npm run typecheck Tested: npm test Tested: npm run build Tested: python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json Tested: python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json Not-tested: Paid API/order flow Not-tested: High-volume commercial workloads Not-tested: Non-UTF-8 file inputs * Preserve korean spell-check layout in corrected output The Nara payload can collapse paragraph separators into normalized page text, so the helper now maps corrections back onto the original chunk before rebuilding corrected_text. The CLI also rejects non-positive --max-chars values, and regression tests cover both the layout-preservation path and invalid argument handling. Constraint: Nara result pages can normalize blank lines and sentence spacing before exposing errInfo offsets Rejected: Narrow docs away from file/Markdown proofreading | preserving original chunk separators keeps the documented workflow intact Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep multiline separator preservation tied to the original chunk whenever a suggestion only changes whitespace across collapsed boundaries Tested: python3 -m unittest scripts.test_korean_spell_check; npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n왠지 않되요.' --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Not-tested: Live multi-page Nara payloads with separator-sensitive corrections across multiple returned pages * Preserve file-proofreading layout in Korean spell check output The spell-check helper now keeps exact blank-line runs and paragraph indentation when chunking and reassembling file-style input, while still allowing the official service's spacing corrections to flow through. Regression coverage now locks the collapsed-layout, triple-blank-line, and cross-boundary spacing cases that triggered the PR review. Constraint: Official Nara/PNU payloads can collapse layout and sometimes merge corrections across preserved paragraph boundaries Rejected: Narrow docs away from file-level proofreading | the existing feature scope explicitly supports file and Markdown checks Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve exact layout tokens only at original newline boundaries; do not reintroduce global strip/join normalization without real file-mode verification Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --file <tmpfile> --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Not-tested: Live upstream behavior for extremely long leading/trailing-whitespace-only files Related: PR #60 * Keep layout-preserving chunk splits from tripping on separator-boundary fixes The follow-up layout preservation pass renamed the working unit variable, but one separator-length guard still referenced the old paragraph name. This commit finishes the refactor so exact-boundary paragraph chunks keep the preserved-separator logic reachable and the new regression coverage stays green. Constraint: Must preserve the existing feature/#47 branch and PR #60 flow while fixing the approved review follow-up Rejected: Revert the layout-preserving chunking refactor | would discard the verified file-layout fix and its regressions Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep chunk reassembly lossless; new chunking changes should continue to round-trip original separators byte-for-byte Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --file <tempfile-with-triple-blank-lines> --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json (expected argument error) Not-tested: Live multi-page service responses beyond the local smoke cases * Preserve spell-check chunk separators when units overflow The file-layout follow-up already preserved blank runs and indentation, but the overlong-unit path still checked the wrong variable when extracting a trailing separator. That could strand separators in a standalone chunk and break exact reassembly for tight max-char limits. This commit fixes the separator extraction guard and locks the behavior with a regression that proves chunk concatenation still matches the original text when an overlong paragraph is followed by a blank-line separator. Constraint: File-mode reconstruction must preserve exact layout while chunking long input Rejected: Broader chunking rewrite | existing structure only needed the overflow guard corrected Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep split_text_into_chunks chunk concatenation identical to the original input for layout-sensitive file checks Tested: npm run lint; npm run typecheck; npm test; npm run build; python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json; python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json; python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json; manual --file smoke with triple blank lines and indentation Not-tested: Live-service failure modes such as Cloudflare/browser challenges * Prevent clean spell-check chunks from crashing mixed file runs The Nara/PNU surface can return a plain 'no issues found' HTML page without the embedded result payload when a chunk is already clean. Chunked file and markdown runs could hit that response on earlier chunks, raise a ValueError, and never reach later chunks that still needed corrections. Treat the no-issues page as an empty result set and lock the behavior with narrow regression coverage. Constraint: Upstream no-issue responses omit the JavaScript payload entirely and can split the status message across HTML whitespace Rejected: Fabricate a synthetic result page | empty-page handling already preserves the original clean chunk Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep empty-result detection aligned with the upstream no-issues message unless the service publishes a structured empty payload contract Tested: python3 -m unittest scripts.test_korean_spell_check Tested: npm run lint Tested: npm run typecheck Tested: npm test Tested: npm run build Tested: python3 scripts/korean_spell_check.py --text '아버지가방에들어가신다.' --format json Tested: python3 scripts/korean_spell_check.py --text $'아버지가방에들어가신다.\n\n아버지가방에들어가신다.' --max-chars 15 --format json Tested: python3 scripts/korean_spell_check.py --text 테스트 --max-chars 0 --format json Tested: python3 scripts/korean_spell_check.py --file <tmpfile> --format json Tested: python3 scripts/korean_spell_check.py --file <tmpfile> --max-chars 18 --format json Not-tested: Other upstream empty-result templates beyond the current no-issues HTML wording * Make Joseon Sillok lookups reproducible from the official site Add a joseon-sillok-search skill and a Python helper that scrape the official Joseon Annals search/detail pages. The helper normalizes king/year metadata, fetches detail excerpts, and locks the repository docs plus regression coverage around the shipped workflow. Constraint: v1 must stay on official public HTML surfaces only Constraint: Must avoid adding new dependencies for a simple scraping helper Constraint: Shell connectivity to sillok.history.go.kr became intermittent during final live reruns Rejected: Ship a new npm workspace | repo skill/docs pattern is enough for v1 Rejected: Add BeautifulSoup or another parser dependency | unnecessary for the bounded HTML patterns Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Keep year filtering Gregorian and derived from official regnal metadata unless the upstream site exposes a better structured contract Tested: npm run ci Tested: Earlier live POST/detail probes against search/searchResultList.do and /id/kda_12512030_002 during implementation Tested: Live official article inspection for kda_12512030_002 via the public site Not-tested: Final end-to-end CLI live run after the last refactor, because the shell hit transient TCP timeouts to sillok.history.go.kr Related: #59 * Prevent sillok follow-up fixes from missing filtered results or weakening trust This follow-up addresses the blocking PR review items on the Joseon Sillok helper. The search loop now derives total pages from the first live page size so king/year filtering can reach later pages, TLS verification stays enabled on both requests and urllib paths, detail parsing accepts the live classification brackets, and repo docs stop linking to missing Korean spell-check assets on this branch. Constraint: Must preserve the existing joseon-sillok-search surface and avoid new dependencies Rejected: Keep verify=False behind an implicit fallback | still weakens authenticity for the default path Rejected: Infer pagination from the hardcoded 50-row default | misses valid later-page matches when the site serves smaller pages Confidence: high Scope-risk: narrow Reversibility: clean Directive: If the official site changes page size or pagination markup again, update the first-page pagination regression before altering search_sillok pagination math Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: python3 scripts/sillok_search.py --query '훈민정음' --king 세종 --year 1443 --limit 1 --timeout 20 Tested: python3 - <<'PY' ... fetch_detail_page(..., article_id='kda_12512030_002', timeout=20) ... PY Not-tested: Successful live sillok.history.go.kr responses in this environment (POST and detail GET both timed out at 20s) Related: PR #62 * Make joseon-sillok-search installs work outside the repo The skill installer only ships the skill directory, so the sillok helper has to live inside that payload. This moves the authoritative helper into joseon-sillok-search/scripts/, keeps the repo-root script as a thin shim for tests and docs, and trims footer metadata from parsed article bodies so excerpts match the published examples. Constraint: skills add exposes only the installed skill payload, not repo-root helpers Rejected: Keep the helper only under scripts/ | installed skill commands fail after copy-only installs Confidence: high Scope-risk: narrow Directive: Keep the repo-root sillok wrapper thin and update the bundled helper first when behavior changes Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: temp installed-skill smoke run of python3 scripts/sillok_search.py --help plus footer-cleaning parse_detail_page check Tested: npm run ci Not-tested: live sillok.history.go.kr shell requests still hit connect timeouts in this environment * Restore the sillok CLI's verified stdlib transport fallback The helper already shipped a stdlib urllib opener that can reach the official search endpoint in environments where requests/urllib3 aborts. This change keeps that opener available even when requests imports successfully and falls back to it on retryable requests transport failures. Added regression coverage for opener availability and the requests-to-urllib fallback so the default CLI path matches the live verified behavior. Constraint: Official sillok detail GETs can still time out transiently in this environment Constraint: Keep TLS verification enabled and preserve the documented CLI entrypoints Rejected: Force urllib for every request | keep the existing requests fast path when it succeeds Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve the stdlib fallback tests whenever the transport layer changes Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_sillok_search Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: live forced-fallback probe against searchResultList.do with requests.post patched to OSError(22) Not-tested: full live CLI completion through the detail GET in this environment * Document the approved real-estate MCP skill without vendoring upstream Issue #53 is intentionally doc-only, so this change adds the real-estate-search skill, feature guide, setup/security notes, and regression coverage around the upstream real-estate-mcp integration instead of importing server code. The new docs keep the original MCP link, cover Codex/Claude registration, and spell out the self-host + Cloudflare Tunnel + launchd path for environments where no fixed hosted endpoint is available. Constraint: Must use tae0y/real-estate-mcp without copying its source into this repository Constraint: Must include the original MCP link and a stable self-host fallback when no hosted endpoint is available Rejected: Vendor the upstream MCP source | issue explicitly requires skill docs only Rejected: Assume a public hosted MCP endpoint exists | upstream docs did not publish one Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep this integration doc-only; do not add a workspace or vendored server without revisiting issue #53 constraints Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: upstream bootstrap smoke (`uv sync`, `uv run real-estate-mcp --help`, HTTP initialize on 127.0.0.1:8017) Not-tested: live property data queries with a valid DATA_GO_KR_API_KEY * Prevent misleading real-estate self-host instructions Tighten the real-estate skill docs so the launchd fallback stays operational and the Onbid bid-result tools are described with the same WIP caveat the upstream project still publishes. Constraint: Upstream Docker compose already uses restart: unless-stopped while `docker compose ... up -d` daemonizes immediately Rejected: Keep a separate server LaunchAgent with RunAtLoad + KeepAlive | launchd would restart-loop on the exiting compose command Confidence: high Scope-risk: narrow Reversibility: clean Directive: Mirror upstream capability caveats in k-skill docs and do not wrap daemonized server commands in launchd KeepAlive jobs Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: uv sync Tested: uv run real-estate-mcp --help Tested: DATA_GO_KR_API_KEY=dummy uv run real-estate-mcp --transport http --host 127.0.0.1 --port 8017 Tested: curl initialize on http://127.0.0.1:8017/mcp returned protocolVersion 2024-11-05 Not-tested: Live 거래 조회 with a real DATA_GO_KR_API_KEY * Keep install docs from reintroducing broken launchd guidance The install guide had drifted from the real-estate skill and feature docs and still implied that macOS launchd should auto-run both the server and tunnel. This narrows the guidance back to tunnel-only launchd ownership and extends regression coverage so docs/install.md cannot silently reintroduce the server-side loop wording. Constraint: Upstream docker compose already uses restart: unless-stopped Constraint: Review-round-2 scope is limited to docs and regression coverage Rejected: Leave docs/install.md under a generic launchd presence check | it missed the exact server/터널 regression Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep docs/install.md aligned with the detailed real-estate feature guide when self-host guidance changes Tested: node --test scripts/skill-docs.test.js; npm run ci; fresh-clone upstream smoke with uv sync, uv run real-estate-mcp --help, and HTTP initialize on 127.0.0.1:8017/mcp Not-tested: None * Allow Han River water-level lookups without user API keys The proxy now resolves HRFCO water-level stations via waterlevel/info and fetches the latest 10-minute measurement via waterlevel/list, exposing a public summary route plus a hosted skill/docs path. Constraint: HRFCO requires a ServiceKey and station-code-based latest lookup Rejected: Raw passthrough only | forces users to manage upstream details and misses the approved no-key UX Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep this route summary-only and public; expand rainfall/dam/bo/fldfct in separate issues Tested: npm run ci; local server smoke test with HRFCO sample key against /v1/han-river/water-level; tsc diagnostics on packages/k-skill-proxy/src/server.js and src/hrfco.js Not-tested: Hosted production proxy rollout * Expose official nearby fuel prices for location-based gas station lookups Add the first cheap-gas-nearby skill/package pair so nearby gas-price queries can resolve a user-supplied location, translate it into Opinet's KATEC search contract, and return the cheapest nearby stations with address and facility detail. The docs and setup surfaces now advertise the new skill and its Opinet API key requirement. Constraint: Nearby fuel prices must come from the official KNOC Opinet API when available Constraint: No new external dependencies were allowed for coordinate conversion or location resolution Rejected: Map-only gas price scraping | official Opinet Open API exists and is the preferred source Rejected: Require lat/lng input only | poorer UX than supporting landmark/station queries through anchor resolution Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep `OPINET_API_KEY` as the only supported official-price credential unless the repo adopts an Opinet proxy later Tested: npm run ci; node --test packages/cheap-gas-nearby/test/index.test.js; offline fixture smoke via searchCheapGasStationsByLocationQuery('서울역', ...) Not-tested: Live Opinet API call with a real `OPINET_API_KEY` (no non-placeholder key was configured locally) Related: #54 * Explain Blue Ribbon premium gating instead of failing opaquely Blue Ribbon's nearby endpoint now returns PREMIUM_REQUIRED for public requests, so the package now upgrades that response into a stable domain error and updates user-facing docs to describe the degraded nearby state. Regression tests cover both location-query and coordinate-query entrypoints while keeping the existing happy path intact. Constraint: Must not attempt to bypass Blue Ribbon premium access controls Constraint: Package releases must use Changesets metadata Rejected: Silently return empty results on PREMIUM_REQUIRED | would hide the upstream contract change from callers Rejected: Keep generic 403 error and docs unchanged | leaves the main failure mode opaque and misleading Confidence: high Scope-risk: narrow Reversibility: clean Directive: If Blue Ribbon reopens a public nearby surface later, update the docs and replace the premium_required remap only after fresh live verification Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro now returns premium_required metadata Not-tested: Official premium-authenticated nearby flow, because no approved premium credentials are available * Reduce duplicate premium-required test assertions The implementation diff was already verified, so this follow-up keeps the new regression coverage easier to read by sharing one assertion helper instead of repeating the same predicate twice. Constraint: Must preserve the verified PREMIUM_REQUIRED regression coverage exactly Rejected: Leave duplicated inline predicates in both tests | repeats the same contract and adds noise to future edits Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep location-query and coordinate-query regressions aligned when the premium_required error contract changes Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci Not-tested: Additional live Blue Ribbon requests beyond the previously verified premium_required repro * Document an Olive Young search skill around the upstream daiso CLI Issue #61 asked for an Olive Young lookup workflow without vendoring the upstream daiso-mcp server into k-skill, so this change adds a docs-only skill, threads it through repository docs, and locks the guidance with regression assertions. The new guidance prefers CLI-first verification (`npx daiso`) and a clone fallback (`git clone https://github.com/hmmhmmhm/daiso-mcp.git`) instead of requiring direct Claude Code MCP installation. The existing daiso-product-search skill remains untouched. Constraint: Must mention the original https://github.com/hmmhmmhm/daiso-mcp repo Constraint: Must avoid changing the existing daiso-product-search skill Constraint: Must prefer upstream CLI/package usage over direct Claude Code MCP installation Rejected: Vendor upstream Olive Young code into k-skill | contradicts the minimal-addition design request Rejected: Make Claude Code MCP setup the default path | issue explicitly asked for CLI-first usage Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the Olive Young docs aligned with upstream `daiso` CLI behavior and note public endpoint instability when live verification shows it Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: 2026-04-05 live /tmp/daiso-mcp CLI checks for health, /api/oliveyoung/stores, /api/oliveyoung/products, /api/oliveyoung/inventory Not-tested: Authenticated/private Olive Young flows or ordering/payment paths * Keep Han River docs honest until hosted rollout lands The local HRFCO proxy route already works, but the deployed public proxy still lacks /v1/han-river/water-level as of 2026-04-05. This follow-up changes the user-facing docs to require a self-hosted or deployment-verified proxy URL, keeps the intended hosted path documented as rollout-pending, and locks that caveat with a regression test. Constraint: Hosted k-skill-proxy deployment still returns 404 for /v1/han-river/water-level on 2026-04-05 Rejected: Keep advertising the hosted route as the default live path | current deployment is not live yet Confidence: high Scope-risk: narrow Reversibility: clean Directive: Restore hosted-default wording only after the public proxy route and HRFCO configuration are verified live Tested: node --test scripts/skill-docs.test.js; npm run ci; local mocked smoke via node packages/k-skill-proxy/src/server.js + GET /v1/han-river/water-level?stationName=한강대교 Not-tested: Live hosted k-skill-proxy behavior after deployment * Keep cheap gas lookups from failing on recoverable Kakao and input issues The lookup now walks ranked Kakao anchor candidates until one returns usable coordinates, and it rejects invalid limit inputs instead of silently collapsing non-empty results into an empty list. The regression suite now locks both review repros plus the null-coordinate normalization edge case that surfaced while implementing the fallback. Constraint: Kakao place panels can be partially populated or return 404 for otherwise valid search candidates Rejected: Default invalid limit/detailLimit values silently | still masks caller bugs and can look like no results nearby Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep anchor resolution tolerant of unusable Kakao panels before failing the whole lookup Tested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...) Not-tested: Live Opinet/Kakao network path without a real OPINET_API_KEY * Keep Olive Young install guidance aligned with live retry behavior Issue #61's initial branch already shipped the olive-young-search skill/docs set, but the install guide did not have a regression lock for the public endpoint instability note captured during live verification. This follow-up adds that test first and updates the install quickstart so retry-or-clone fallback guidance stays in sync with the verified daiso CLI workflow. Constraint: Must keep the follow-up scoped to the approved issue #61 docs behavior Constraint: Public olive-young endpoint can intermittently return 5xx/503 during live verification Rejected: Re-open the broader feature docs set | the existing branch already covered the main feature scope Rejected: Leave the retry guidance untested in install docs | risk of future doc drift across surfaces Confidence: high Scope-risk: narrow Reversibility: clean Directive: If live olive-young verification changes again, update install docs and the regression together so retry/fallback guidance stays honest Tested: node --test scripts/skill-docs.test.js Tested: npm run ci Tested: cd /tmp/daiso-mcp && npx daiso health Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/stores --keyword 명동 --limit 3 --json Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/products --keyword 선크림 --size 3 --json Tested: cd /tmp/daiso-mcp && npx daiso get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json Not-tested: Authenticated Olive Young flows or sustained-rate retry behavior beyond the documented smoke checks * Preserve ranked Kakao anchor fallbacks after panel failures The resolver already retried later Kakao panels, but after the best panel failed it walked the remaining candidates in raw HTML order. Centralizing the full anchor ranking in parse.js keeps fallback iteration aligned with the existing scoring rules and locks the review repro with a regression test for 강남역 ordering. Constraint: Kakao place panels can 404 or omit coordinates even when later ranked candidates are usable Rejected: Re-rank only after a failed panel | duplicates scoring logic and drifts from selectAnchorCandidate Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep resolveAnchor fallback order tied to the shared anchor scoring logic rather than raw Kakao result order Tested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); lsp diagnostics on affected files Not-tested: Live Kakao/Opinet network calls with a non-placeholder OPINET_API_KEY * Clarify that Blue Ribbon coordinate lookups fail the same way The premium gate now affects both location-query and coordinate-entry nearby flows. Record that parity in the skill and docs so the live 2026-04-05 repro evidence stays aligned with the shipped public contract. Constraint: /restaurants/map remains premium-gated for public requests as of 2026-04-05 Rejected: Add more code changes without a behavior gap | would add churn after the approved fix already landed Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the docs/examples aligned with live repro evidence whenever Blue Ribbon changes nearby access behavior Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro for location + coordinates premium_required contract Not-tested: New upstream success-path live nearby payloads, because public access is still premium-gated * Document a runnable Olive Young clone fallback The follow-up review found that clone-local `npx daiso` commands do not run from a built `hmmhmmhm/daiso-mcp` checkout because the generated bin file is not executable. This updates the olive-young skill and docs to use the verified `node dist/bin.js ...` path for clone fallback, and locks that behavior with regression tests while keeping the public CLI-first path unchanged.\n\nConstraint: Upstream clone checkouts can fail with `Permission denied` when invoked through clone-local `npx daiso`\nConstraint: Keep the existing daiso-product-search skill untouched\nRejected: Leave install docs unchanged | PR body and docs would keep a broken clone fallback path\nRejected: Vendor or patch upstream daiso-mcp inside k-skill | issue explicitly requires documenting upstream flow instead\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep clone-fallback docs and PR verification commands aligned with the actually runnable local invocation\nTested: node --test scripts/skill-docs.test.js\nTested: npm run ci\nTested: cd /tmp/daiso-mcp && npm install && npm run build && node dist/bin.js health\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/stores --keyword 명동 --limit 3 --json\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/products --keyword 선크림 --size 3 --json\nTested: cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json\nNot-tested: Public npx endpoint stability beyond the verified smoke-test window * Record fresh verification for the approved cheap-gas follow-up The ranked Kakao fallback-order and invalid-limit fixes are already present on feature/#54, so no further code edits were necessary. This empty follow-up commit records the requested rerun verification for PR #67 before posting the implementation update.\n\nConstraint: Existing branch head already contains the approved cheap-gas-nearby follow-up\nRejected: Invent another code/doc change just to force a non-empty diff | unnecessary risk after approval\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep Kakao anchor fallback iteration tied to the shared ranking helper and preserve finite-number validation for limit inputs\nTested: node --test packages/cheap-gas-nearby/test/index.test.js; npm run ci; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); lsp diagnostics on affected files\nNot-tested: Live Kakao/Opinet network calls with a non-placeholder OPINET_API_KEY * Record verified delivery for approved cheap-gas-nearby rollout The approved Issue #54 implementation was already present on feature/#54 when this follow-up began, so this checkpoint records fresh verification evidence and keeps PR #67 moving without introducing extra code churn. Constraint: Existing approved fixes were already on the branch and the follow-up still required a pushed update plus implementation comment Rejected: Add additional code or docs churn | approved scope was already satisfied and green locally Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve the Kakao fallback-order and invalid-count regression coverage unless equivalent runtime repros replace it Tested: node --test packages/cheap-gas-nearby/test/index.test.js; offline fixture smoke for searchCheapGasStationsByLocationQuery('서울역', ...); npm run ci; LSP diagnostics on affected cheap-gas-nearby files Not-tested: Live Kakao/Opinet network path without a non-placeholder OPINET_API_KEY * Keep Blue Ribbon premium-gate remapping explicitly bounded The issue #63 fix already remaps PREMIUM_REQUIRED for nearby lookups. This follow-up adds a regression that proves non-premium /restaurants/map failures still surface as generic request errors, and clarifies that boundary in the package and feature docs. Constraint: PR #68 already carries the shipped behavior change and must stay aligned with current live premium-gated upstream behavior Rejected: Broaden domain remapping to all 403 nearby errors | would hide distinct upstream failure modes Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep only PREMIUM_REQUIRED on /restaurants/map mapped to premium_required unless a new verified upstream contract is documented Tested: npm test --workspace blue-ribbon-nearby; npm run lint --workspace blue-ribbon-nearby; npm run ci; live node repro for location+coordinate nearby lookups on 2026-04-06; LSP diagnostics on src/test Not-tested: Alternative non-premium upstream status codes beyond the mocked 403 ACCESS_DENIED path * Keep Olive Young clone fallback docs runnable from a fresh clone Round 3 review found that the inline fallback shorthand skipped `cd daiso-mcp`, which made `npm install` run outside the cloned upstream repo even though the fenced examples were already correct. This tightens the two published shorthand snippets and adds regression coverage so both docs surfaces reject the broken chain in future edits. Constraint: Existing node dist/bin.js clone fallback examples were already verified and had to stay aligned Constraint: The follow-up had to stay scoped to docs/test coverage without touching the existing daiso-product-search skill Rejected: Convert the shorthand to prose only | the review specifically requested a runnable inline form or an explicit removal Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep inline clone fallback snippets synchronized with the fenced node dist/bin.js examples and require `cd daiso-mcp` before install/build Tested: node --test scripts/skill-docs.test.js; npm run ci; cd /tmp/daiso-mcp && npm install && npm run build; cd /tmp/daiso-mcp && node dist/bin.js health; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/stores --keyword 명동 --limit 3 --json; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/products --keyword 선크림 --size 3 --json; cd /tmp/daiso-mcp && node dist/bin.js get /api/oliveyoung/inventory --keyword 선크림 --storeKeyword 명동 --size 2 --json Not-tested: Public npx path in this follow-up round (previous PR verification already covered it) Related: PR #71 * Bundle korean-spell-check script inside skill directory for packageless installs The Python helper lived only in the repo-root scripts/ folder, so `skills add` never shipped it. Move the real implementation into korean-spell-check/scripts/ (mirroring joseon-sillok-search) and replace the root copy with a thin re-export wrapper so lint/test still resolve from the repo root. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Exclude .claude directory from skill validation to fix CI in worktrees Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * real-estate-search: MCP self-host → k-skill-proxy HTTP 전환 사용자가 직접 real-estate-mcp를 clone/self-host하는 대신 k-skill-proxy에 MOLIT 실거래가 API route를 추가해서 다른 스킬(한강수위, 미세먼지 등)과 동일한 패턴으로 사용 가능하게 함. - GET /v1/real-estate/region-code — 지역코드 검색 - GET /v1/real-estate/:assetType/:dealType — 9개 거래 유형 조회 - molit.js: XML 파싱, 필드 정규화, 취소거래 필터링, 요약통계 - region-lookup.js: 284개 법정동 5자리 코드 토큰 매칭 - SKILL.md/docs를 HTTP proxy 기반으로 전면 재작성 - DATA_GO_KR_API_KEY를 사용자 필수항목에서 프록시 운영자 전용으로 이동 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * cheap-gas-nearby: proxy 경유로 전환 + 프로덕션 배포 구조 문서화 - cheap-gas-nearby: OPINET_API_KEY 없이 k-skill-proxy 경유로 동작하도록 변경 - fetchAroundStations/fetchDetailById에 proxy fallback 추가 - SKILL.md, feature doc에서 사용자 API key 요구 제거 - AGENTS.md, CLAUDE.md: proxy 개발/배포 워크플로우 문서화 - docs/features/k-skill-proxy.md: opinet route 추가, 프로덕션 자동 배포 구조 설명 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic… * Feature/#58 (#70) * Add an official KIPRIS patent-search skill for Korean IP lookups Issue #58 adds a bundled stdlib Python helper plus install/setup/docs coverage for KIPRIS Plus keyword search and application-number detail lookup. The implementation keeps auth explicit via KIPRIS_PLUS_API_KEY -> ServiceKey and locks the repo contract with doc/install and regression tests. Constraint: KIPRIS Plus requires a per-user ServiceKey and no valid key was available for live success-path runs Constraint: No new dependencies allowed for bundled skill helpers Rejected: Add a new npm/python workspace | docs+helper pattern already fits repo and keeps install payload lighter Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the helper aligned with official KIPRIS Plus XML fields and ServiceKey naming before widening the skill surface Tested: python3 scripts/patent_search.py --help; python3 scripts/patent_search.py --query '배터리' --service-key dummy; python3 scripts/patent_search.py --application-number 1020240001234 --service-key dummy; PYTHONPATH=.:scripts python3 -m unittest scripts.test_patent_search; node --test scripts/skill-docs.test.js; npm run lint; npm run typecheck; npm test Not-tested: Successful live KIPRIS search with a valid production ServiceKey Related: #58 * Accept copied KIPRIS portal keys without request corruption KIPRIS Plus users commonly paste the percent-encoded ServiceKey shown by the portal. The helper now normalizes that key once before query serialization, adds regression coverage for explicit and env-driven inputs, and clarifies the documentation so copied portal keys remain valid instead of being double- encoded on the wire. Constraint: KIPRIS Plus still expects the standard ServiceKey query parameter contract Rejected: Preserve raw percent signs during urlencode only for ServiceKey | more brittle than normalizing once at the boundary Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep ServiceKey normalization at the input boundary so future request-building changes do not reintroduce double-encoding Tested: python3 scripts/patent_search.py --help; python3 scripts/patent_search.py --query '배터리' --service-key dummy; python3 scripts/patent_search.py --application-number 1020240001234 --service-key dummy; PYTHONPATH=.:scripts python3 -m unittest scripts.test_patent_search; node --test scripts/skill-docs.test.js; npm run lint; npm run typecheck; npm test Not-tested: Live KIPRIS Plus lookup with a real KIPRIS_PLUS_API_KEY * Record fresh verification for the approved KIPRIS key fix The approved ServiceKey normalization fix is already present on feature/#58, so no further code edits were necessary. This empty follow-up commit records the requested rerun verification and keeps PR #70 moving without reopening a settled implementation path. Constraint: Existing branch head already contains the approved code and docs fix Rejected: Invent an extra code/doc change just to produce a non-empty diff | unnecessary risk after approval Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not change ServiceKey handling again without reproducing the percent-encoded portal-key path Tested: python3 scripts/patent_search.py --help; python3 scripts/patent_search.py --query '배터리' --service-key dummy; python3 scripts/patent_search.py --application-number 1020240001234 --service-key dummy; PYTHONPATH=.:scripts python3 -m unittest scripts.test_patent_search; node --test scripts/skill-docs.test.js; npm run lint; npm run typecheck; npm test Not-tested: Live KIPRIS request with a real KIPRIS_PLUS_API_KEY * Record fresh Issue #58 verification without reopening the approved fix The approved KIPRIS ServiceKey normalization change was already present on feature/#58, so this follow-up records a fresh verification point for the existing implementation instead of reopening the code path. Constraint: User requested commit/push + PR follow-up on the existing issue branch Rejected: Reopen the already-approved implementation | no new blocker or code defect remained Confidence: high Scope-risk: narrow Reversibility: clean Directive: If this helper changes again, preserve support for percent-encoded portal keys and keep the URL serialization regression coverage intact Tested: patent helper smoke commands, patent/doc regression tests, lint, typecheck, full npm test suite, encoded-key reproduction, architect review Not-tested: Live KIPRIS success path with a real KIPRIS_PLUS_API_KEY * fix: decode percent-encoded ServiceKey in build_search_params and build_detail_params The low-level helper functions still double-encoded percent-encoded KIPRIS portal keys when callers bypassed resolve_service_key(). Apply unquote() at the param-builder boundary so copied portal keys work regardless of call path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: trigger GitHub merge-status recalculation --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Enable session-bound Hi-Pass receipt workflows without promising unattended login Issue #79 was approved specifically as a logged-in-session-only automation surface, so the change adds a new hipass-receipt skill/package that focuses on query building, usage-history parsing, receipt payload assembly, and session-expiry detection. The docs now make manual login, session expiry, and official flow limits explicit while wiring the new skill into install/setup/source surfaces. Constraint: Hi-Pass uses short-lived server sessions and multi-step login flows that are not safe to reimplement as raw HTTP automation Rejected: Unattended cookie/session reuse bot | server session expires and redirects back to login Rejected: Docs-only skill with no helper package | would not provide runnable, testable behavior for payload parsing and session detection Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep this feature scoped to logged-in browser sessions; do not promise credential automation or long-lived session recovery without new evidence from the official site Tested: npm run ci Tested: CLI fixture-demo and chrome-command smoke runs Tested: Live inspectHipassPage smoke against /comm/lginpg.do and /usepculr/InitUsePculrTabSearch.do Not-tested: Authenticated live receipt popup opening with a real Hi-Pass account/session * Keep hipass-receipt's published workflow runnable from a clean install Reviewer verification found three blocking gaps in the follow-up: the browser workflow still navigated to an undefined endpoint, the published package did not carry the runtime CDP client or fixture smoke assets, and the documented encrypted-card-number flag was silently ignored. This update bundles the CDP client + published fixtures, fixes the usage-history init route, and normalizes the alias in code and docs while locking the behavior with mocked-CDP and pack dry-run regressions. Constraint: Hi-Pass support remains logged-in-browser-session-only; no automated credential entry or long-lived unattended login Constraint: The published npm package must support the documented fixture smoke path from an unpacked tarball Rejected: Document a separate manual playwright install only | reviewer found the advertised clean-install flow should work as shipped Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep CLI aliases, published files, and README smoke commands aligned whenever hipass-receipt packaging changes Tested: npm run ci; node packages/hipass-receipt/src/cli.js fixture-demo --fixture packages/hipass-receipt/test/fixtures/usage-history-list.html --start-date 2026-04-01 --end-date 2026-04-07; node packages/hipass-receipt/src/cli.js chrome-command --profile-dir "/Users/jeffrey/.cache/k-skill/hipass-chrome" --debugging-port 9222; live unauthenticated inspectHipassPage smoke for /comm/lginpg.do and /usepculr/InitUsePculrTabSearch.do; packed tarball install smoke with npm ls playwright-core + fixture-demo; LSP diagnostics 0 on hipass-receipt JS files Not-tested: authenticated live list/receipt against a real logged-in Hi-Pass browser session * Keep Hi-Pass live receipt automation runnable end-to-end Regression tests now lock the Playwright navigation target and browser lifecycle so live list/receipt sessions use an absolute URL and close their CDP connection before exit. The implementation switches the init navigation to the exported absolute endpoint and closes the browser in finally blocks for both workflows, matching the blocked review findings without widening scope. Constraint: Hi-Pass live automation depends on an existing logged-in Chrome CDP session Constraint: Review blockers required fixing both real Playwright navigation and clean CLI exit behavior without changing the manual-login contract Rejected: Keep the relative path and relax mocks | would miss the real invalid-URL failure mode Rejected: Leave browser lifecycle ownership to CLI callers | library users would still hang on list/receipt Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep usage-history navigation on absolute URLs and preserve explicit browser.close() regression coverage for both list and receipt flows Tested: node --test packages/hipass-receipt/test/index.test.js; node packages/hipass-receipt/src/cli.js fixture-demo --fixture packages/hipass-receipt/test/fixtures/usage-history-list.html --start-date 2026-04-01 --end-date 2026-04-07; node packages/hipass-receipt/src/cli.js chrome-command --profile-dir "/Users/jeffrey/.cache/k-skill/hipass-chrome" --debugging-port 9222; live unauthenticated inspectHipassPage smoke for /comm/lginpg.do and /usepculr/InitUsePculrTabSearch.do; mocked CLI list/receipt exit smoke; npm run ci Not-tested: Real authenticated Hi-Pass CDP session with a manually logged-in user profile * 📝 docs: 블루리본 맛집 스킬 지원 중단 안내 bluer.co.kr 측이 자동화 접근을 전면 차단해 스킬이 더 이상 동작하지 않는다. 표에 취소선·경고 태그를 달고 표 아래에 상세 사유 blockquote를 추가한다. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✅ test: 블루리본 deprecated 테이블 행 패턴 반영 README에 취소선·지원중단 태그가 붙으면서 기존 regex가 플레인 `| 근처 블루리본 맛집 |` 를 요구해 CI가 깨졌다. 새 deprecated 행 형태와 상세 안내 blockquote 존재를 assertion 으로 확정해 문서가 다시 편집돼 경고가 사라지는 회귀를 잡는다. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
6.2 KiB
번개장터 검색 가이드
이 기능으로 할 수 있는 일
upstream bunjang-cli / pinion05/bunjangcli 를 사용해 번개장터 검색, 상세조회, 선택적 찜/채팅, 대량 수집, AI TOON export 를 처리한다.
search로 검색item get/item list로 상세조회favorite add/favorite remove/favorite list로 선택적 찜 관리chat list/chat start/chat send로 선택적 채팅--start-page,--pages,--max-items,--with-detail,--output으로 대량 수집--ai --output <directory>로 TOON chunk 저장
가장 중요한 규칙
이 기능은 upstream 원본을 그대로 쓴다.
k-skill 안에 번개장터 수집기를 새로 넣지 않고, CLI first 문서/스킬만 유지한다.
즉 기본 경로는 아래다.
npx --yes bunjang-cli ...- 반복 사용이면
npm install -g bunjang-cli
먼저 필요한 것
- 인터넷 연결
node22+npx또는npm- 선택적으로 interactive TTY 터미널
2026-04-06 기준 npm view bunjang-cli version 은 0.2.1 이고, README 요구 사항은 Node.js 22+ 다.
가장 빠른 시작: npx CLI
npx --yes bunjang-cli --help
npx --yes bunjang-cli --json auth status
npx --yes bunjang-cli --json search "아이폰" --max-items 3 --sort date
npx --yes bunjang-cli --json item get 354957625
반복 사용이면 전역 설치도 가능하다.
npm install -g bunjang-cli
export NODE_PATH="$(npm root -g)"
bunjang-cli --help
로그인은 선택적 interactive 플로우
npx --yes bunjang-cli auth login
npx --yes bunjang-cli auth logout
npx --yes bunjang-cli --json auth status
auth login은 브라우저에서 로그인 후 터미널로 돌아와 Enter 를 눌러야 완료된다.- 즉 TTY / interactive 세션 이 아닌 환경에서는 로그인 완료 처리가 멈출 수 있다.
- 그래서 기본 문서는 검색/상세조회/대량 수집을 먼저 안내하고, 찜/채팅은 로그인된 경우에만 선택적으로 진행한다.
기본 흐름
1. 검색
npx --yes bunjang-cli search "아이폰"
npx --yes bunjang-cli search "아이폰" --price-min 500000 --price-max 1200000
npx --yes bunjang-cli search "아이폰" --sort date
npx --yes bunjang-cli --json search "아이폰" --max-items 5
검색 결과에는 매입글/광고/악세서리 글이 섞이고, live search payload 에서는 location 이 noisy 하거나 description / status 가 빠질 수 있다. 그래서 검색 단계는 제목/가격 중심 1차 triage 로만 쓰고, 세부 판단은 상세조회 이후로 미룬다.
2. 상세조회
npx --yes bunjang-cli item get 354957625
npx --yes bunjang-cli --json item get 354957625
npx --yes bunjang-cli --json item list --ids 354957625,354801707
상세에서는 price, description, location, category, status, sellerName, sellerReviewCount, favoriteCount, transportUsed 를 우선 본다. 즉 description / status / 믿을 만한 location 이 필요하면 반드시 item get 또는 --with-detail 이후 에만 판정한다.
3. 대량 수집
npx --yes bunjang-cli search "아이폰" \
--start-page 1 \
--pages 5 \
--max-items 50 \
--sort date \
--with-detail \
--output artifacts/bunjang-iphone.json
export 검증 시에는 결과 파일 존재 여부와 top-level items[] 안의 summary / detail / optional error 구조, item 별 sourcePage 또는 summary.raw.page 를 함께 확인한다.
4. AI TOON chunk
npx --yes bunjang-cli search "아이폰" \
--start-page 1 \
--pages 5 \
--max-items 50 \
--with-detail \
--ai \
--output artifacts/bunjang-iphone-ai
--ai에서는--output이 디렉토리 여야 한다.- 결과는
items-1.toon같은 chunk 로 나뉜다. - 대량 후보를 여러 에이전트에게 분산 평가시키기 좋다.
5. 찜/채팅은 로그인 후에만
npx --yes bunjang-cli --json favorite list
npx --yes bunjang-cli --json favorite add 354957625
npx --yes bunjang-cli --json favorite remove 354957625
npx --yes bunjang-cli --json chat list
npx --yes bunjang-cli --json chat start 354957625 --message "안녕하세요"
npx --yes bunjang-cli --json chat send 84191651 --message "상품 상태 괜찮을까요?"
favorite와chat은 로그인이 필요한 선택적 기능이다.- 기본 검색/분석 요청이라면 실행하지 않고 명령만 안내한다.
- 검증이 필요하면
favorite list로 세션을 먼저 확인한 뒤 add/remove 를 왕복 실행한다.
라이브 확인 메모
2026-04-06 기준 아래 흐름을 실제로 실행해 응답을 확인했다.
npx --yes bunjang-cli --help→ top-level commands (auth,search,item,chat,favorite,purchase) 확인npx --yes bunjang-cli --json auth status→authenticated: false,headfulLoginRequired: true확인npx --yes bunjang-cli --json search "아이폰" --max-items 1→items[0].id = 354957625,transportUsed = browser확인npx --yes bunjang-cli --json item get 354957625→description,location,sellerReviewCount,favoriteCount,transportUsed = api확인
같은 날짜에 search summary 는 title/price 중심 triage 용으로만 안전했고, status / description 은 summary 에서 안정적으로 오지 않았다. 그래서 문서에서는 상세 필드 의존 판단을 item get / --with-detail 뒤로 고정한다.
같은 날짜에 favorite list 는 로그인 브라우저를 띄운 뒤 터미널 Enter 를 기다렸다. 그래서 문서에서는 찜/채팅을 로그인 후 선택적으로만 실행 하도록 고정한다.
제한사항
- 로그인 없는 환경에서는 찜/채팅/구매 흐름을 바로 검증하기 어렵다.
- 검색 결과에는 매입글/광고/악세서리 노이즈가 섞일 수 있다.
- DOM/API 변경에 따라 browser transport 동작이 깨질 수 있다.
- 구매 자동 확정/결제는 다루지 않는다.
참고 링크
- npm package:
https://www.npmjs.com/package/bunjang-cli - upstream repo:
https://github.com/pinion05/bunjangcli