From 996fcab8c346aa89ae12e2c12c7caa725af1a431 Mon Sep 17 00:00:00 2001 From: bits-bytes-nn Date: Thu, 20 Aug 2026 00:01:18 +0900 Subject: [PATCH 1/3] Revert "hide the two empty section pages from the nav and sitemap" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrong call, reverted at the author's direction. Removing the tab does not read as "this section is still filling up" — it reads as "this section was removed", and it left the nav with four items huddled beside the logo against a full-width hero, visibly off-balance. `Paper Summaries` and `Tech Guides` get `main_nav: true` and their original nav_order back, and lose `sitemap: false`. The empty-state line from _includes/category-posts.html is the honest signal that they are not filled yet; the tab is the statement that this blog writes those kinds of posts at all. Keeps the other half of the reverted commit — the

that repeated each page's own title stays gone, since that was a rendering defect and not part of this. For the record on why they are empty: the automated PRs that would have filled them were closed unmerged — #37/#38 (MAI-Thinking-1) and #39-#43 (Argo CD). The MAI-Thinking-1 draft still exists on origin/paper-reviews/mai-thinking-1-… if it is ever wanted; as written it would not pass the writing gates (emoji headings, 평서체 instead of 입니다체, ~2.1k words against a 6k target). --- README.ko.md | 7 +++---- README.md | 9 ++++----- docs/tech-doc.md | 24 ++++++++++++++---------- paper-summaries.md | 13 +++++++------ tech-guides.md | 7 +++---- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/README.ko.md b/README.ko.md index c2ba49e..d4ec0d3 100644 --- a/README.ko.md +++ b/README.ko.md @@ -138,10 +138,9 @@ RSS ``에 실리는 문장입니다. 생략하면 `_plugins/post_descri 카테고리는 **두 단계**입니다. - `categories[0]` — **유형**: `Paper Reviews`, `Paper Summaries`, `Tech Guides`, - `Insights` 중 하나. 글이 어느 섹션 페이지에 들어갈지를 정합니다. 현재 글이 있는 유형은 - `Paper Reviews`와 `Insights`뿐이라 내비에도 이 둘만 있습니다 — `paper-summaries.md`와 - `tech-guides.md`는 `main_nav` 없이 `sitemap: false` 상태이고, 첫 글이 들어오면 어떤 두 - 값을 되살리면 되는지가 각 파일 프런트매터에 적혀 있습니다. + `Insights` 중 하나. 글이 어느 내비 탭에 들어갈지를 정합니다. `Paper Summaries`와 + `Tech Guides`는 아직 글이 없지만 **탭은 유지합니다** — 빈 상태 문구를 대신 띄웁니다. + 탭이 없으면 "아직 채우는 중인 섹션"이 아니라 "없어진 섹션"으로 읽히기 때문입니다. - `categories[1]` — **주제**: `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI` 등. 필요하면 자유롭게 추가합니다. diff --git a/README.md b/README.md index d6d98a4..c7fd458 100644 --- a/README.md +++ b/README.md @@ -142,11 +142,10 @@ share one. Categories are **two levels**: - `categories[0]` — the **type**: `Paper Reviews`, `Paper Summaries`, - `Tech Guides`, or `Insights`. This decides which section page the post appears - on. Only `Paper Reviews` and `Insights` have posts today, so only those two are - in the nav — `paper-summaries.md` and `tech-guides.md` sit at `sitemap: false` - with no `main_nav`, and their front matter says which two keys to restore when - the first post lands in either. + `Tech Guides`, or `Insights`. This decides which nav tab the post appears under. + `Paper Summaries` and `Tech Guides` have no posts yet and still keep their tabs: + they render an empty-state line, because a missing tab reads as a section that + was removed rather than one still filling up. - `categories[1]` — the **topic**: `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI`, … (add new ones freely). diff --git a/docs/tech-doc.md b/docs/tech-doc.md index 87212b4..302304e 100644 --- a/docs/tech-doc.md +++ b/docs/tech-doc.md @@ -107,9 +107,9 @@ Pages가 그대로 서빙.** 포스트는 프런트매터에 **2단계** 카테고리를 가진다: `categories: ["<유형>", "<주제>"]`. - **0단계 (유형)** — `Paper Reviews`, `Paper Summaries`, `Tech Guides`, `Insights` 중 하나. - 글이 어느 섹션 페이지에 들어갈지를 정한다. 넷 다 전용 페이지를 가지지만, 지금 글이 있는 - 유형은 `Paper Reviews`(28편)와 `Insights`(7편)뿐이고 내비에는 이 둘만 올라간다(아래 - "내비게이션은 코드가 아니라 데이터가 만든다" 참조). + 글이 어느 내비 탭에 들어갈지를 정한다. 넷 다 전용 페이지와 탭을 가진다. 지금 글이 있는 + 유형은 `Paper Reviews`(28편)와 `Insights`(7편)뿐이고, 나머지 둘은 빈 상태 문구를 띄운다 + (아래 "내비게이션은 코드가 아니라 데이터가 만든다" 참조). - **1단계 (주제)** — `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI` 등. 세부 주제이며 필요하면 자유롭게 추가한다. @@ -135,17 +135,21 @@ _site/paper reviews/language-models/2025/01/23/.html | nav_order | 페이지 | 소스 | |-----------|--------|------| | 1 | About | `about.md` | +| 2 | Paper Summaries | `paper-summaries.md` — `site.categories['Paper Summaries']` 필터 | | 3 | Paper Reviews | `paper-reviews.md` — `site.categories['Paper Reviews']` 필터, 주제별 그룹화 | +| 4 | Tech Guides | `tech-guides.md` — `site.categories['Tech Guides']` 필터 | | 5 | Insights | `insights.md` — `site.categories['Insights']` 필터 | | 6 | Search | `search.md` | -`nav_order`의 2·4번이 빈 것은 실수가 아니다. `paper-summaries.md`(2)와 -`tech-guides.md`(4)는 **글이 0편이라 내비에서 내렸다** — 여섯 탭 중 둘이 -"this space will fill up soon"으로 이어지고 있었고, 같은 페이지가 사이트맵에도 올라가 -검색엔진에 빈 페이지를 내밀고 있었다. 두 파일은 `main_nav` 없이 `sitemap: false`로 -남아 있고(URL로는 계속 열린다), 첫 글이 그 유형으로 들어오면 프런트매터 주석이 지시하는 -대로 `main_nav: true`와 원래 `nav_order`를 되살리면 된다. 번호를 다시 매기지 않은 이유가 -이것이다. +**빈 섹션도 탭을 유지한다.** `Paper Summaries`와 `Tech Guides`는 아직 머지된 글이 0편이라 +`_includes/category-posts.html`의 `empty` 문구를 띄운다("Summaries are in the works…"). +한때 "빈 탭은 마찰"이라는 이유로 둘을 내비에서 내렸는데 잘못된 판단이었다 — 탭이 사라지면 +채우는 중인 섹션이 아니라 **없어진 섹션**으로 읽힌다. 빈 상태 문구가 정직한 신호이고, +탭 자체가 "이 블로그는 이 종류의 글도 쓴다"는 선언이다. + +> 참고: 두 섹션에 글이 없는 건 자동 생성 PR(#37·#38 `MAI-Thinking-1`, #39~#43 Argo CD)이 +> 머지되지 않고 닫혔기 때문이다. `MAI-Thinking-1` 초안은 아직 +> `origin/paper-reviews/mai-thinking-1-...` 브랜치에 남아 있다. `categories.html`(`/categories/`)과 `tags.html`(`/tags/`)은 *모든* 카테고리/태그를 가로지르는 전체 색인 페이지다. 메인 내비에는 없고, 각 포스트 하단의 메타데이터에서 링크된다. diff --git a/paper-summaries.md b/paper-summaries.md index 90b2cb1..d815305 100644 --- a/paper-summaries.md +++ b/paper-summaries.md @@ -5,12 +5,13 @@ permalink: /paper-summaries/ description: >- Concise digests of AI/ML papers, posts, and talks — distilled to their core contributions and insights. -# No `main_nav` and `sitemap: false` while this category is empty: every post so -# far is a Paper Review or an Insight, so the nav advertised a section whose only -# content was "check back soon", and the sitemap offered search engines a page -# with no posts on it. Restore both — `main_nav: true` and `nav_order: 2` — with -# the first post filed under this category. -sitemap: false +# Stays in the nav even with no posts yet. It was briefly pulled out on the +# grounds that a tab leading to "check back soon" is friction — wrong call: a +# missing tab reads as a section that was removed, not one that is still filling +# up. The empty-state line below is the honest signal, and the tab is what says +# this blog does summaries. +main_nav: true +nav_order: 2 --- {%- comment -%} No heading here — see insights.md. {%- endcomment -%} diff --git a/tech-guides.md b/tech-guides.md index 6390f1e..c143594 100644 --- a/tech-guides.md +++ b/tech-guides.md @@ -5,10 +5,9 @@ permalink: /tech-guides/ description: >- Hands-on technical guides and tutorials for the libraries, frameworks, tools, and platforms I work with. -# See paper-summaries.md: hidden from the nav and the sitemap while empty. -# Restore `main_nav: true` and `nav_order: 4` with the first post in this -# category. -sitemap: false +# Stays in the nav even with no posts yet — see paper-summaries.md. +main_nav: true +nav_order: 4 --- {%- comment -%} No heading here — see insights.md. {%- endcomment -%} From b8092aa513651d26af3e673e0cb00377300a8eac Mon Sep 17 00:00:00 2001 From: bits-bytes-nn Date: Thu, 20 Aug 2026 00:05:31 +0900 Subject: [PATCH 2/3] Restore the MCP tag, and drop stateful facts from the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two corrections, both mine: 1. The MCP tag was renamed to Model-Context-Protocol. Renaming is removing, and the approved scope was *adding* topic tags — so this was out of scope, and it killed a live anchor: /tags/#mcp stopped existing in production while the PR claimed "nothing is removed, so no live /tags/ anchor moves". MCP is back alongside the long form, so the anchor resolves and the two posts still connect. Whether to fold them later is a separate decision. 2. The docs carried post counts ("Paper Reviews (28편)", "35편 전부", "220 of 264 tags") and work history (PR numbers, a branch name, "this was once done and it was wrong"). Counts are false the moment a post lands, and history belongs in git. Both replaced with the rule and its reason: a tag phrased as one paper's contribution can only apply to that paper, related_posts.rb needs a shared tag, therefore a post tagged only that way gets no Related reading block. search.json's size is stated as "grows linearly with post count" with the command to measure it, instead of a figure that goes stale. --- README.ko.md | 9 ++--- README.md | 11 +++--- ...-agentcore-harness-engineering-analysis.md | 2 +- docs/tech-doc.md | 39 ++++++++----------- 4 files changed, 27 insertions(+), 34 deletions(-) diff --git a/README.ko.md b/README.ko.md index d4ec0d3..1d9b94f 100644 --- a/README.ko.md +++ b/README.ko.md @@ -146,11 +146,10 @@ RSS ``에 실리는 문장입니다. 생략하면 `_plugins/post_descri ### 태그: 세부 태그 위에 주제 태그를 하나 -태그는 자유 형식·하이픈 연결이고, 대부분 논문 하나의 기여를 서술합니다 -(`Fine-Grained-Expert-Segmentation`). 색인으로는 좋지만 글을 **잇지는** 못합니다 — 태그 -264개 중 220개가 단 한 편에만 붙어 있었고, `_plugins/related_posts.rb`는 **공유** 태그를 -요구하므로 11편이 관련 글을 하나도 얻지 못했습니다. 서로 남남이던 그래프 RAG 논문 네 편이 -거기 있었습니다. +태그는 자유 형식·하이픈 연결입니다. 논문 하나의 기여를 그대로 옮긴 태그 +(`Fine-Grained-Expert-Segmentation`)는 그 논문에만 붙을 수 있습니다. 색인으로는 정확하지만 +글을 **잇지는** 못하고, `_plugins/related_posts.rb`가 **공유** 태그를 요구하므로 그렇게만 +달린 글은 "Related reading"이 아예 붙지 않은 채 배포됩니다. 그래서 글마다 아래 통제된 주제 태그를 최소 하나 답니다. diff --git a/README.md b/README.md index c7fd458..ce8e902 100644 --- a/README.md +++ b/README.md @@ -152,12 +152,11 @@ Categories are **two levels**: ### Tags: one topic tag on top of the specific ones -Tags are free-form and hyphenated, and most describe one paper's contribution -(`Fine-Grained-Expert-Segmentation`). Those are a good index but they connect -nothing: 220 of 264 tags were used by exactly one post, and since -`_plugins/related_posts.rb` requires a **shared** tag, 11 posts got no related -reading at all — including four graph-RAG papers that share no tag with each -other. +Tags are free-form and hyphenated, and a tag phrased as one paper's contribution +(`Fine-Grained-Expert-Segmentation`) can only ever apply to that paper. Those +make a precise index and connect nothing, and `_plugins/related_posts.rb` +requires a **shared** tag — so a post tagged only that way ships with no +"Related reading" block at all. So also give each post at least one tag from the controlled topic layer: diff --git a/_posts/2026-04-12-agentcore-harness-engineering-analysis.md b/_posts/2026-04-12-agentcore-harness-engineering-analysis.md index 36c6559..b65e36a 100644 --- a/_posts/2026-04-12-agentcore-harness-engineering-analysis.md +++ b/_posts/2026-04-12-agentcore-harness-engineering-analysis.md @@ -7,7 +7,7 @@ description: >- Build·Deploy·Assess 세 층으로 열어 하네스 체크리스트의 어디를 채우고 어디를 비워 두었는지 짚습니다. date: 2026-04-12 12:00:00 categories: ["Insights", "Agentic-AI"] -tags: ["AgentCore", "AWS-Bedrock", "Harness-Engineering", "Agentic-Infrastructure", "Model-Context-Protocol", "Cedar-Policy", "Managed-RAG", "Agent-Registry", "Agentic-AI"] +tags: ["AgentCore", "AWS-Bedrock", "Harness-Engineering", "Agentic-Infrastructure", "MCP", "Model-Context-Protocol", "Cedar-Policy", "Managed-RAG", "Agent-Registry", "Agentic-AI"] cover: /assets/images/insights.jpg use_math: false --- diff --git a/docs/tech-doc.md b/docs/tech-doc.md index 302304e..886c8da 100644 --- a/docs/tech-doc.md +++ b/docs/tech-doc.md @@ -107,9 +107,8 @@ Pages가 그대로 서빙.** 포스트는 프런트매터에 **2단계** 카테고리를 가진다: `categories: ["<유형>", "<주제>"]`. - **0단계 (유형)** — `Paper Reviews`, `Paper Summaries`, `Tech Guides`, `Insights` 중 하나. - 글이 어느 내비 탭에 들어갈지를 정한다. 넷 다 전용 페이지와 탭을 가진다. 지금 글이 있는 - 유형은 `Paper Reviews`(28편)와 `Insights`(7편)뿐이고, 나머지 둘은 빈 상태 문구를 띄운다 - (아래 "내비게이션은 코드가 아니라 데이터가 만든다" 참조). + 글이 어느 내비 탭에 들어갈지를 정한다. 넷 다 전용 페이지와 탭을 가지며, 글이 없는 유형은 + 빈 상태 문구를 띄운다(아래 "내비게이션은 코드가 아니라 데이터가 만든다" 참조). - **1단계 (주제)** — `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI` 등. 세부 주제이며 필요하면 자유롭게 추가한다. @@ -141,15 +140,11 @@ _site/paper reviews/language-models/2025/01/23/.html | 5 | Insights | `insights.md` — `site.categories['Insights']` 필터 | | 6 | Search | `search.md` | -**빈 섹션도 탭을 유지한다.** `Paper Summaries`와 `Tech Guides`는 아직 머지된 글이 0편이라 -`_includes/category-posts.html`의 `empty` 문구를 띄운다("Summaries are in the works…"). -한때 "빈 탭은 마찰"이라는 이유로 둘을 내비에서 내렸는데 잘못된 판단이었다 — 탭이 사라지면 -채우는 중인 섹션이 아니라 **없어진 섹션**으로 읽힌다. 빈 상태 문구가 정직한 신호이고, -탭 자체가 "이 블로그는 이 종류의 글도 쓴다"는 선언이다. - -> 참고: 두 섹션에 글이 없는 건 자동 생성 PR(#37·#38 `MAI-Thinking-1`, #39~#43 Argo CD)이 -> 머지되지 않고 닫혔기 때문이다. `MAI-Thinking-1` 초안은 아직 -> `origin/paper-reviews/mai-thinking-1-...` 브랜치에 남아 있다. +**빈 섹션도 탭을 유지한다.** 글이 없는 유형은 `_includes/category-posts.html`의 `empty` +문구를 띄운다("Summaries are in the works…"). 편수가 0이라고 `main_nav`를 떼지 않는다 — +탭이 사라지면 채우는 중인 섹션이 아니라 **없어진 섹션**으로 읽히고, 남은 탭이 로고 옆에 +좁게 뭉쳐 전체 폭 히어로와 어긋난다. 빈 상태 문구가 정직한 신호이고, 탭 자체가 "이 블로그는 +이 종류의 글도 쓴다"는 선언이다. `categories.html`(`/categories/`)과 `tags.html`(`/tags/`)은 *모든* 카테고리/태그를 가로지르는 전체 색인 페이지다. 메인 내비에는 없고, 각 포스트 하단의 메타데이터에서 링크된다. @@ -178,15 +173,14 @@ _site/paper reviews/language-models/2025/01/23/.html `Knowledge-Graph`, `Llama`, `Mixture-of-Experts`, `Multimodal-Models`, `Reasoning-Models`, `Retrieval-Augmented-Generation`. -세부 태그만 있으면 관련 글 기능이 굶는다. 태그 264개 중 220개(83%)가 단 한 편에만 붙어 -있었고, `related_posts.rb`가 공유 태그를 요구하므로 11편이 관련 글 0개였다 — 그중 넷은 -RAPTOR·GraphRAG·LightRAG·Zep, 즉 서로 붙어야 마땅한 그래프 RAG 논문들이었다. 한 주제를 세 -이름으로 부른 것(`Agentic-Architecture`/`Agentic-Patterns`/`Agentic-Infrastructure`)도 같은 -증상을 만들었다. +**세부 태그만 달면 관련 글이 안 붙는다.** 논문 하나의 기여를 그대로 옮긴 태그는 그 논문에만 +붙을 수 있고, `related_posts.rb`는 공유 태그를 요구한다. 그래서 세부 태그만 달린 글은 +"Related reading" 없이 배포된다. 한 주제를 여러 이름으로 부르는 것도 같은 증상을 만든다 +(`Agentic-Architecture`/`Agentic-Patterns`/`Agentic-Infrastructure`가 그랬다). -주제 태그를 한 층 얹어 35편 전부가 관련 글을 얻게 했다. 고친 곳이 `related_posts.rb`의 -규칙이 아니라 **글의 프런트매터**라는 점이 중요하다 — 규칙을 느슨하게 풀면 공통점 없는 글이 -서로 추천된다. 세부 태그는 지우지 않았다(살아 있는 `/tags/` 앵커가 움직인다). +고칠 지점은 `related_posts.rb`의 규칙이 아니라 **글의 프런트매터**다. 규칙을 느슨하게 풀어 +카테고리만으로 연결하면 공통점 없는 글이 서로 추천된다(위 `TAG_WEIGHT` 설명 참조). 그리고 +세부 태그는 지우지 않는다 — 살아 있는 `/tags/` 앵커가 움직인다. 주제 태그를 **얹기만** 한다. ## 4. 수식 렌더링 @@ -240,8 +234,9 @@ MathJax 설정은 `head.html`에 있고 `{% if page.use_math %}`로 감싸 **프 없이 단순 부분문자열 매칭을 한다. 즉 색인에 없는 글자는 못 찾는다. 예전에 snippet(앞 40단어)만 색인했더니, "어텐션"·"트랜스포머"가 본문 중·후반에 18개 포스트나 있는데 발췌엔 안 들어가 검색 결과가 **0건**으로 나왔다. `content`로 전체를 색인해 한글 재현율을 회복했다. - 대가는 실측 **3.2 MB, gzip 991 KB**다(글이 늘면 같이 는다). `/search/`에서만 내려받으므로 - 다른 페이지 속도엔 영향이 없다. + 대가는 파일 크기다 — 본문 전체가 들어가므로 **글 수에 비례해 선형으로 커진다**(현재 규모는 + MB 단위, gzip 후 그 3분의 1 아래). `/search/`에서만 내려받으므로 다른 페이지 속도엔 영향이 + 없다. 실제 값이 궁금하면 `curl -so /dev/null -w '%{size_download}' /search.json`. > **알려진 한계 — 매치가 안 보일 수 있다.** 색인은 본문 전체인데 결과 카드에 찍히는 건 > 앞 40단어짜리 `snippet`뿐이다. 그래서 5만 번째 글자에서 걸린 검색어는 스니펫에 없고 From 9a31d5471c831323c50640dc39b70ff27d18cbf5 Mon Sep 17 00:00:00 2001 From: bits-bytes-nn Date: Thu, 20 Aug 2026 00:13:07 +0900 Subject: [PATCH 3/3] docs: revise the READMEs and the tech doc end to end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies the "no stateful facts, no work history" rule to all three documents, not just the passages edited most recently, and reconciles every claim against the code. Corrected, in rough order of how much damage each could do: - `_sass/_syntax.scss` was described as a generated file to be recreated with `rougify style monokai.sublime`. It is hand-edited: two Monokai colours were raised to clear 4.5:1 against the code background, with the original values and ratios in a comment at the top. Following the old instruction would have silently reverted the contrast fix. Now flagged do-not-regenerate. - Both READMEs still listed `archive` in the layout chain, which no longer exists. - The pre-push command block claimed "the same three checks" while listing four, built into `_site/`, and sat directly above a note explaining why you must not build into `_site/`. It now matches CI exactly and builds to /tmp/site-verify. - `test/` was described as covering three plugins; it covers all five, one file each. Stated that way so it stays true. - The tags section had been inserted into the middle of "Categories drive the URL", orphaning the output-path example under a heading about tags. Moved back, and the URL-immutability warning now sits with it. - A cross-reference pointed at a `TAG_WEIGHT` discussion that exists only in the plugin, not in this document. Now points at the plugin. - The plugin roll-call in three places named three of the five plugins; `related_posts.rb` also owns the prev/next links now. De-stated: post counts, tag counts, search.json byte sizes, "html-proofer caught 128 of these", "18 posts were affected". Each is either false after the next post lands or already false. Where the number carried the point, the point is now made structurally — search.json "grows linearly with post count", with the curl command to measure it. De-historied: "this was once X and it was wrong", closed-PR numbers, a branch name, "the repo has already been migrated". Rules and reasons kept, narrative dropped — git holds that. Also fixed: the search section documented `_config.yml` as unable to control the index only in passing, as a parenthetical about a block that had been deleted; it is now a standing warning, since that is the mistake it prevents. And the known search limitation (index is the full body, the card shows a 40-word head) is stated once in §5 and listed in §9 rather than half-explained in both. --- README.ko.md | 78 ++++++++++++++++++----------------- README.md | 85 ++++++++++++++++++++------------------ docs/tech-doc.md | 104 ++++++++++++++++++++++++++--------------------- 3 files changed, 144 insertions(+), 123 deletions(-) diff --git a/README.ko.md b/README.ko.md index 1d9b94f..3f5ebea 100644 --- a/README.ko.md +++ b/README.ko.md @@ -56,9 +56,8 @@ bundle exec jekyll build # 결과물은 _site/ 에 생성 ``` > **왜 `github-pages` gem이 아니라 순수 `jekyll`인가요?** -> 이 사이트는 `_plugins/`에 직접 만든 Ruby 플러그인(읽기 시간, 이미지 lazy-load, 글 설명문 생성)을 씁니다. -> `github-pages` gem은 보안 샌드박스 때문에 커스텀 플러그인을 막으므로, -> 로컬과 CI 모두 Jekyll을 직접 실행합니다. +> 이 사이트는 `_plugins/`에 직접 만든 Ruby 플러그인을 씁니다. `github-pages` gem은 보안 +> 샌드박스 때문에 커스텀 플러그인을 막으므로, 로컬과 CI 모두 Jekyll을 직접 실행합니다. --- @@ -66,7 +65,7 @@ bundle exec jekyll build # 결과물은 _site/ 에 생성 ``` _posts/ 글 — YYYY-MM-DD-slug.md (한국어 기본, 영어 번역본은 -en.md) -_layouts/ 페이지 템플릿: default → post / page / archive +_layouts/ 페이지 템플릿: default → post / page _includes/ 재사용 조각: head, header, footer, nav_links, page_divider, category-posts, language_switcher, related_posts @@ -76,7 +75,7 @@ _sass/ 스타일: _layout, _post, _tags, _syntax(Rouge 코드 테마 _plugins/ reading_time.rb (한·영 읽기 시간 계산) lazy_images.rb (에 loading="lazy" 추가) post_description.rb (글의 page.description 채우기) - related_posts.rb (글의 page.related 채우기) + related_posts.rb (page.related, 그리고 이전/다음 글 링크) scrollable_tables.rb (넓은 표를 스크롤 컨테이너로 감싸기) css/ main.scss(Sass 진입점) · search.css(검색 페이지 전용) js/ main.js(테마 토글·코드 복사·목차·메뉴·이미지 확대 등) @@ -138,12 +137,23 @@ RSS ``에 실리는 문장입니다. 생략하면 `_plugins/post_descri 카테고리는 **두 단계**입니다. - `categories[0]` — **유형**: `Paper Reviews`, `Paper Summaries`, `Tech Guides`, - `Insights` 중 하나. 글이 어느 내비 탭에 들어갈지를 정합니다. `Paper Summaries`와 - `Tech Guides`는 아직 글이 없지만 **탭은 유지합니다** — 빈 상태 문구를 대신 띄웁니다. - 탭이 없으면 "아직 채우는 중인 섹션"이 아니라 "없어진 섹션"으로 읽히기 때문입니다. + `Insights` 중 하나. 글이 어느 내비 탭에 들어갈지를 정합니다. 아직 글이 없는 유형도 + **탭을 유지하고** 빈 상태 문구를 띄웁니다 — 탭이 없으면 채우는 중인 섹션이 아니라 + 없어진 섹션으로 읽히기 때문입니다. - `categories[1]` — **주제**: `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI` 등. 필요하면 자유롭게 추가합니다. +Jekyll은 이 둘과 날짜를 합쳐 출력 경로를 만듭니다. + +``` +categories: ["Paper Reviews", "Language-Models"] + date: 2025-01-23 + ↓ +_site/paper reviews/language-models/2025/01/23/.html +``` + +그래서 **이미 게시된 글의 카테고리나 날짜를 바꾸면 URL이 바뀝니다.** 외부에서 걸린 링크와 +검색 결과가 깨지므로, 한 번 정하면 그대로 둡니다. + ### 태그: 세부 태그 위에 주제 태그를 하나 태그는 자유 형식·하이픈 연결입니다. 논문 하나의 기여를 그대로 옮긴 태그 @@ -160,17 +170,11 @@ Retrieval-Augmented-Generation ``` 기존 세부 태그는 **그대로 남깁니다.** 주제 태그가 담지 못하는 내용을 담고 있고, 지우면 이미 -살아 있는 `/tags/` 앵커가 움직입니다. 새 주제 태그를 만들기 전에 위 목록이나 이미 두 편 -이상이 쓰는 태그로 덮이는지 먼저 확인하세요. `Agentic-Architecture`·`Agentic-Patterns`· -`Agentic-Infrastructure`가 한 주제의 세 이름이었던 것이 그 묶음에 링크가 없던 이유입니다. - -Jekyll은 이 둘과 날짜를 합쳐 출력 경로를 만듭니다. +살아 있는 `/tags/` 앵커가 움직입니다. **주제 태그는 얹는 것이지 바꿔 다는 게 아닙니다.** -``` -categories: ["Paper Reviews", "Language-Models"] + date: 2025-01-23 - ↓ -_site/paper reviews/language-models/2025/01/23/.html -``` +새 주제 태그를 만들기 전에 위 목록에 이미 덮이는 게 없는지 확인하세요. 한 개념을 세 이름으로 +부르면(`Agentic-Architecture`·`Agentic-Patterns`·`Agentic-Infrastructure`) 글마다 아무도 +공유하지 않는 태그를 하나씩 들고 있게 되고, 그건 주제 태그가 없는 것과 같습니다. ### 수식은 반드시 `$$…$$`로 @@ -184,39 +188,39 @@ kramdown이 내용을 그대로 보존해 `\(…\)`로 내보내므로 안전합 ### 푸시 전에 확인하세요 +CI가 돌리는 네 게이트를 같은 순서로 미리 돌립니다. `_site/`가 아니라 임시 경로로 빌드하는 +이유는 아래 주의에 있습니다. + ```bash -ruby test/run_all.rb # 플러그인 로직이 여전히 맞나? -bundle exec jekyll build # 빌드가 깨끗한가? -bundle exec htmlproofer ./_site --disable-external # 깨진 링크·이미지는 없나? -script/validate-site.sh # 사이트맵·피드·메타데이터·헤딩 +ruby test/run_all.rb # 플러그인 로직이 여전히 맞나? +bundle exec jekyll build --strict-front-matter \ + --destination /tmp/site-verify # 빌드가 깨끗한가? +bundle exec htmlproofer /tmp/site-verify --disable-external \ + --allow-hash-href --no-enforce-https # 깨진 링크·이미지·앵커는 없나? +script/validate-site.sh /tmp/site-verify # 사이트맵·피드·메타데이터·헤딩 ``` -CI도 같은 세 검사를 돌립니다. 로컬에서 미리 잡으면 배포 실패를 막을 수 있습니다. - -`test/`는 `_plugins/`를 검사합니다 — 설명문 추출, 읽기 시간 계산, 이미지 lazy-load -치환. `bundle exec`가 아니라 plain `ruby`인 이유는, 플러그인이 Jekyll·Liquid 등록을 -`defined?`로 감싸 로직만 단독 로드되게 해 두었고 minitest는 Ruby에 기본 포함이기 -때문입니다. **`_plugins/`를 건드리면 사이트의 모든 페이지가 바뀝니다.** 동작을 바꾸기 -전에 테스트 케이스를 먼저 추가하세요. - > **검사 결과가 말이 안 되면 먼저 떠 있는 `jekyll serve`를 찾으세요.** 파일을 감시하며 > `_site/`를 계속 덮어쓰고, `site.url`을 `http://localhost:4000`으로 바꾸며(사이트맵 URL이 > 전부 틀리게 보입니다), 시작할 때 읽은 `_config.yml`을 계속 들고 있어 그 뒤에 추가한 -> `exclude`가 적용되지 않습니다. 종료하거나, 다른 경로로 빌드해서 검사하세요. +> `exclude`가 적용되지 않습니다. 다른 경로로 빌드하면 세 문제를 한꺼번에 비켜 갑니다. > > ```bash > ps aux | grep '[j]ekyll serve' -> bundle exec jekyll build --destination /tmp/site-verify -> script/validate-site.sh /tmp/site-verify > ``` +`test/`는 `_plugins/`의 순수 로직을 플러그인당 한 파일씩 단위 테스트합니다. `bundle exec`가 +아니라 plain `ruby`인 이유는, 각 플러그인이 Jekyll·Liquid 등록을 `defined?`로 감싸 로직만 +단독 로드되게 해 두었고 minitest는 Ruby에 기본 포함이기 때문입니다. **`_plugins/`를 건드리면 +사이트의 모든 페이지가 바뀝니다.** 동작을 바꾸기 전에 테스트 케이스를 먼저 추가하세요. + --- ## 배포 `.github/workflows/jekyll.yml`은 `main` 푸시뿐 아니라 **`main`으로 향하는 PR에서도** -돕니다. 그래서 아래 네 게이트가 잘못된 머지를 보고만 하지 않고 막습니다. 1~4단계는 양쪽 -모두에서, 5단계는 PR에서 건너뜁니다. +돕니다. 그래서 아래 게이트가 잘못된 머지를 사후에 보고하는 데 그치지 않고 막습니다. +1~4단계는 두 경우 모두, 5단계는 PR에서 건너뜁니다. 순서대로: 1. **`ruby test/run_all.rb`**로 `_plugins/` 단위 테스트를 돌리고 2. `JEKYLL_ENV=production`으로 사이트를 빌드하고 @@ -228,8 +232,8 @@ CI도 같은 세 검사를 돌립니다. 로컬에서 미리 잡으면 배포 중복되지 않는지, 저작 원본이 배포되지 않았는지를 검사한 뒤 5. GitHub Pages에 배포합니다. -워크플로우가 실패한다면 대개 3·4단계입니다. Actions 로그에 어떤 링크·이미지·페이지가 -문제인지 그대로 나옵니다. 수동 배포 단계는 없습니다. +실패하면 대개 3·4단계입니다. Actions 로그에 어떤 링크·이미지·페이지가 문제인지 그대로 +나옵니다. 수동 배포 단계는 없습니다. > **⚠ `google*.html` / `naver*.html`을 `_config.yml`의 `exclude`에 넣지 마세요.** > Search Console·네이버 소유권 인증 토큰이라 사이트 루트에 그대로 올라가야 합니다. diff --git a/README.md b/README.md index ce8e902..58fdd43 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,8 @@ bundle exec jekyll build ``` > **Why plain `jekyll` and not `github-pages`?** This site uses custom Ruby -> plugins in `_plugins/` (read time, lazy images, post descriptions), which the -> sandboxed `github-pages` gem disallows. So both local builds and CI run Jekyll -> directly. +> plugins in `_plugins/`, which the sandboxed `github-pages` gem disallows. So +> both local builds and CI run Jekyll directly. --- @@ -68,7 +67,7 @@ bundle exec jekyll build ``` _posts/ Posts — YYYY-MM-DD-slug.md (Korean; English twin is -en.md) -_layouts/ Page templates: default → post / page / archive +_layouts/ Page templates: default → post / page _includes/ Reusable fragments: head, header, footer, nav_links, page_divider, category-posts, language_switcher, related_posts @@ -78,7 +77,7 @@ _sass/ Styles: _layout, _post, _tags, _syntax (Rouge code theme), _plugins/ reading_time.rb (KO/EN-aware read time) lazy_images.rb (adds loading="lazy" to ) post_description.rb (fills page.description for posts) - related_posts.rb (fills page.related for posts) + related_posts.rb (page.related, and the prev/next links) scrollable_tables.rb (wraps wide tables so they scroll) css/ main.scss (Sass entry point) · search.css (search page only) js/ main.js (theme toggle, code-copy, TOC, menu, image zoom…) @@ -143,13 +142,23 @@ Categories are **two levels**: - `categories[0]` — the **type**: `Paper Reviews`, `Paper Summaries`, `Tech Guides`, or `Insights`. This decides which nav tab the post appears under. - `Paper Summaries` and `Tech Guides` have no posts yet and still keep their tabs: - they render an empty-state line, because a missing tab reads as a section that - was removed rather than one still filling up. + A type with no posts yet keeps its tab and renders an empty-state line: a + missing tab reads as a section that was removed, not one still filling up. - `categories[1]` — the **topic**: `Language-Models`, `Multimodal-Learning`, `Finetuning`, `Retrieval-Augmented-Generation`, `Agentic-AI`, … (add new ones freely). +Jekyll combines the two with the date to build the output path: + +``` +categories: ["Paper Reviews", "Language-Models"] + date: 2025-01-23 + ↓ +_site/paper reviews/language-models/2025/01/23/.html +``` + +So **changing the categories or date of a published post changes its URL**, which +breaks inbound links and search results. Set them once and leave them. + ### Tags: one topic tag on top of the specific ones Tags are free-form and hyphenated, and a tag phrased as one paper's contribution @@ -167,18 +176,12 @@ Retrieval-Augmented-Generation ``` Keep the specific tags — they say something the topic tag does not, and dropping -them would move live `/tags/` anchors. Before inventing a topic tag, check -whether one of the above (or an existing tag used by 2+ posts) already covers it: -`Agentic-Architecture`, `Agentic-Patterns` and `Agentic-Infrastructure` were three -names for one thing, which is why that cluster had no links. - -Jekyll combines them with the date to build the output path: +them would move live `/tags/` anchors. **Add the topic tag, don't swap for it.** -``` -categories: ["Paper Reviews", "Language-Models"] + date: 2025-01-23 - ↓ -_site/paper reviews/language-models/2025/01/23/.html -``` +Before coining a new topic tag, check that nothing above already covers it. Three +names for one idea (`Agentic-Architecture`, `Agentic-Patterns`, +`Agentic-Infrastructure`) leave every post holding a tag no other post shares, +which is the same as having no topic tag at all. ### Math: always use `$$…$$` @@ -192,40 +195,42 @@ dollar signs like `$10M` are fine — they're not math.) ### Validate before pushing +These are the four gates CI runs, in the same order. Build to a throwaway +directory rather than `_site/`, for the reason in the note below: + ```bash -ruby test/run_all.rb # plugin logic still correct? -bundle exec jekyll build # does it build clean? -bundle exec htmlproofer ./_site --disable-external # any broken links/images? -script/validate-site.sh # sitemap, feed, metadata, headings +ruby test/run_all.rb # plugin logic still correct? +bundle exec jekyll build --strict-front-matter \ + --destination /tmp/site-verify # does it build clean? +bundle exec htmlproofer /tmp/site-verify --disable-external \ + --allow-hash-href --no-enforce-https # broken links, images, anchors? +script/validate-site.sh /tmp/site-verify # sitemap, feed, metadata, headings ``` -CI runs the same three checks, so catching it locally saves a failed deploy. - -`test/` covers `_plugins/` — the description derivation, the read-time estimate, -and the lazy-image rewrite. Plain `ruby`, not `bundle exec`: the plugins guard -their Jekyll/Liquid registration behind `defined?` so their logic loads -standalone, and minitest ships with Ruby. **Anything you change in `_plugins/` -changes every page on the site**, so add a case there before changing behaviour. - -> **If the checks report something impossible, look for a running `jekyll serve` +> **If a check reports something impossible, look for a running `jekyll serve` > first.** It watches the tree and rewrites `_site/` behind you, it overrides > `site.url` with `http://localhost:4000` (so every sitemap URL looks wrong), and -> it keeps the `_config.yml` it started with — so `exclude` entries added since -> then don't apply. Either stop it, or build somewhere else: +> it holds the `_config.yml` it started with — so `exclude` entries added since +> then don't apply. Building elsewhere sidesteps all three: > > ```bash > ps aux | grep '[j]ekyll serve' -> bundle exec jekyll build --destination /tmp/site-verify -> script/validate-site.sh /tmp/site-verify > ``` +`test/` unit-tests the pure logic in `_plugins/` — one file per plugin. Plain +`ruby`, not `bundle exec`: each plugin guards its Jekyll/Liquid registration +behind `defined?` so the logic loads standalone, and minitest ships with Ruby. +**Anything you change in `_plugins/` changes every page on the site**, so add a +case before changing behaviour. + --- ## Deployment `.github/workflows/jekyll.yml` runs on **pull requests to `main` as well as -pushes to it**, so the four gates below block a bad merge instead of only -reporting one. Steps 1–4 run on both; step 5 is skipped for pull requests. It: +pushes to it**, so the gates below block a bad merge rather than merely reporting +one after the fact. Steps 1–4 run on both events; step 5 is skipped for pull +requests. In order, it: 1. runs **`ruby test/run_all.rb`** (the `_plugins/` unit tests), 2. builds the site with `JEKYLL_ENV=production`, @@ -238,8 +243,8 @@ reporting one. Steps 1–4 run on both; step 5 is skipped for pull requests. It: no authoring sources published — and 5. deploys to GitHub Pages. -If the workflow fails, it's almost always step 3 or 4 — open the Actions log, -which names the exact link, image, or page. No manual deploy step is needed. +A failure is almost always step 3 or 4; the Actions log names the exact link, +image, or page. There is no manual deploy step. > **⚠ Don't add `google*.html` / `naver*.html` to `_config.yml`'s `exclude`.** > They're Search Console / Naver ownership-verification tokens that must ship to diff --git a/docs/tech-doc.md b/docs/tech-doc.md index 886c8da..0b6b66e 100644 --- a/docs/tech-doc.md +++ b/docs/tech-doc.md @@ -68,8 +68,8 @@ Pages가 그대로 서빙.** > **실행을 거부**하게 만든다. 그래서 외부에서 불러오는 것은 버전을 고정하고 SRI를 붙인다. > **왜 GitHub Pages 기본 빌드가 아니라 Jekyll을 직접 돌리나?** GitHub Pages의 내장 -> 빌드는 보안 샌드박스라 우리가 `_plugins/`에 만든 커스텀 플러그인(읽기시간·lazy-load·설명문)을 -> 막는다. 그래서 로컬과 CI 모두 순수 `jekyll`을 직접 실행한다. +> 빌드는 보안 샌드박스라 우리가 `_plugins/`에 만든 커스텀 플러그인을 막는다. 그래서 로컬과 +> CI 모두 순수 `jekyll`을 직접 실행한다. ## 2. 빌드 파이프라인 — 마크다운 한 편이 HTML이 되기까지 @@ -156,12 +156,13 @@ _site/paper reviews/language-models/2025/01/23/.html > `site.categories['<유형>']`으로 먼저 거른 뒤** 주제별로 그룹화한다 — 절대 반대 순서로 > 하지 않는다. -> **함정 — 앵커 점프 깨짐.** 메타데이터의 카테고리/태그 링크는 모두 `slugify` 필터로 ID를 -> 만든다. 과거에는 링크 쪽은 `downcase`(공백 유지), 제목(H2)의 id는 원본 케이스(`Paper -> Reviews`)를 써서 서로 어긋났고, 클릭해도 해당 위치로 점프하지 못했다(html-proofer가 -> 128건 적발). 지금은 양쪽 다 `slugify`로 통일했다 — `paper-reviews.md`가 마지막까지 -> `id="{{cat}}"`로 원본 케이스를 내고 있었는데, 그 앵커를 가리키는 링크가 없어 html-proofer가 -> 잡지 못했다. 새 목록 페이지를 만들 땐 `| slugify`를 빼먹지 않는다. +> **함정 — 앵커 점프 깨짐.** 카테고리·태그 앵커는 **링크 쪽과 헤딩 `id` 쪽이 같은 방식으로 +> 슬러그를 만들어야** 한다. 양쪽 다 `slugify` 필터를 쓴다. 한쪽만 `downcase`거나 원본 +> 케이스(`id="{{cat}}"`)를 내면 클릭해도 해당 위치로 점프하지 않는다. 새 목록 페이지를 만들 땐 +> `| slugify`를 빼먹지 않는다. +> +> 이 어긋남은 **아무 링크도 그 앵커를 가리키지 않으면 html-proofer가 잡지 못한다.** 목록 +> 페이지가 자기 헤딩으로 들어오는 링크를 갖고 있지 않은 경우가 그렇다. ### 태그: 세부 태그 + 통제된 주제 태그 @@ -178,9 +179,13 @@ _site/paper reviews/language-models/2025/01/23/.html "Related reading" 없이 배포된다. 한 주제를 여러 이름으로 부르는 것도 같은 증상을 만든다 (`Agentic-Architecture`/`Agentic-Patterns`/`Agentic-Infrastructure`가 그랬다). -고칠 지점은 `related_posts.rb`의 규칙이 아니라 **글의 프런트매터**다. 규칙을 느슨하게 풀어 -카테고리만으로 연결하면 공통점 없는 글이 서로 추천된다(위 `TAG_WEIGHT` 설명 참조). 그리고 -세부 태그는 지우지 않는다 — 살아 있는 `/tags/` 앵커가 움직인다. 주제 태그를 **얹기만** 한다. +관련 글이 비어 보일 때 고칠 지점은 `related_posts.rb`의 규칙이 아니라 **글의 프런트매터**다. +규칙을 느슨하게 풀어 카테고리만으로 연결하면, "둘 다 Paper Reviews / Language-Models"라는 +이유로 공통점 없는 글이 서로 추천된다. 가중치가 그걸 막는 구조는 플러그인 상단 주석 +(`TAG_WEIGHT`·`SUBCATEGORY_WEIGHT`·`CATEGORY_WEIGHT`)에 설명돼 있다. + +그리고 세부 태그는 지우지 않는다 — 살아 있는 `/tags/` 앵커가 움직인다. 주제 태그를 +**얹기만** 한다. ## 4. 수식 렌더링 @@ -202,10 +207,9 @@ kramdown은 단일 `$`를 수식으로 **취급하지 않는다**. `$x_i + y_j$` MathJax에는 이미 망가진 입력이 전달된다(위 그림의 빨간 경로). 예를 들어 `$a*b*c$`가 `$abc$`가 되어버린다. -과거의 임시 우회책은 모든 언더스코어를 `\_`로 손수 이스케이프하는 것이었다. 근본 해결은 -**`$$`를 쓰는 것** — 구간 안의 마크다운 처리를 통째로 끈다. 저장소는 이미 일괄 -마이그레이션되었다(git 히스토리 참조). 참고로 코드 블록 *안*의 단일 `$` 수식(예: DeepSeek-R1 -글의 `` 트레이스)은 verbatim(있는 그대로) 코드로 표시되므로 이 문제와 무관하다. +언더스코어를 `\_`로 하나하나 이스케이프해도 증상은 사라지지만, 그건 우회책이다. 해결은 +**`$$`를 쓰는 것** — 구간 안의 마크다운 처리를 통째로 끈다. 참고로 코드 블록 *안*의 단일 +`$`는 verbatim(있는 그대로) 코드로 표시되므로 이 문제와 무관하다. > **통화 표기 주의.** 본문에 쓰는 달러 기호(`$1.2B`, `$250M`)는 수식이 아니므로 단일 `$`로 > 둬야 한다. 그래서 MathJax 설정에서 `$`를 인라인 구분자에서 **일부러 뺐다**(`\(...\)`만 @@ -230,31 +234,31 @@ MathJax 설정은 `head.html`에 있고 `{% if page.use_math %}`로 감싸 **프 빌드 때 모든 포스트를 `{title, url, date, category, tags, snippet, content}` 형태로 뽑아낸다. 여기서 `snippet`은 결과 카드에 보여줄 40단어짜리 발췌, `content`는 매칭에 쓰는 **HTML을 제거한 전체 본문**이다. -- **왜 발췌가 아니라 전체 본문을 색인하나** — `simple-jekyll-search`는 똑똑한 형태소 분석 - 없이 단순 부분문자열 매칭을 한다. 즉 색인에 없는 글자는 못 찾는다. 예전에 snippet(앞 - 40단어)만 색인했더니, "어텐션"·"트랜스포머"가 본문 중·후반에 18개 포스트나 있는데 발췌엔 - 안 들어가 검색 결과가 **0건**으로 나왔다. `content`로 전체를 색인해 한글 재현율을 회복했다. +- **왜 발췌가 아니라 전체 본문을 색인하나** — `simple-jekyll-search`는 형태소 분석 없이 + 단순 부분문자열 매칭을 한다. **색인에 없는 글자는 못 찾는다.** 발췌만 색인하면 본문 + 중·후반에만 나오는 단어("어텐션", "트랜스포머" 같은)는 검색 결과가 0건이 된다. `content`로 + 전체를 색인하는 건 한글 재현율을 위한 의도된 선택이다. 대가는 파일 크기다 — 본문 전체가 들어가므로 **글 수에 비례해 선형으로 커진다**(현재 규모는 MB 단위, gzip 후 그 3분의 1 아래). `/search/`에서만 내려받으므로 다른 페이지 속도엔 영향이 - 없다. 실제 값이 궁금하면 `curl -so /dev/null -w '%{size_download}' /search.json`. + 없다. 실제 값은 `curl -so /dev/null -w '%{size_download}' /search.json`로 확인한다. - > **알려진 한계 — 매치가 안 보일 수 있다.** 색인은 본문 전체인데 결과 카드에 찍히는 건 - > 앞 40단어짜리 `snippet`뿐이다. 그래서 5만 번째 글자에서 걸린 검색어는 스니펫에 없고 - > `` 강조도 안 걸려서, 맞는 결과가 엉뚱한 결과처럼 보인다. 고치려면 매치 위치 - > 주변을 잘라 보여 주는 스니펫이 필요하다(`simple-jekyll-search`의 템플릿 밖 작업). + > **비대칭에 주의.** 매칭은 `content`(전체)로 하고 표시는 `snippet`(앞 40단어)으로 한다. + > 그래서 본문 깊은 곳에서 걸린 검색어는 결과 카드에 보이지 않는다(§9). - **`js/search.js`** 가 `simple-jekyll-search`(CDN 버전 **고정 + SRI**: `1.10.0`)를 `search.md`의 `#search-input` 입력칸에 연결한다. 매칭된 키워드를 ``로 강조하고 결과 개수를 라이브 상태줄에 표시한다. 강조 처리는 결과가 다 그려진 뒤 **디바운스**로 단 - 한 번만 실행한다(예전엔 키를 누를 때마다 `setTimeout`을 쌓아 서로 경합하며 깜빡였다). + 한 번만 실행한다 — 키 입력마다 `setTimeout`을 쌓으면 타이머가 서로 경합해 화면이 깜빡인다. > **용어 — 디바운스(debounce).** 사용자가 빠르게 연속으로 일으키는 이벤트(타이핑 등)에서, > 마지막 입력 뒤 잠깐 멈출 때까지 기다렸다가 **딱 한 번만** 함수를 실행하는 기법이다. - `category`/`tags`도 색인에 들어가므로 제목·본문뿐 아니라 메타데이터로도 검색된다. 색인에는 **글(`site.posts`)만** 들어간다 — `search.json`이 `site.posts`를 순회하므로 - About·Search·index 같은 페이지는 애초에 후보가 아니다. (`_config.yml`에 `about.md`· - `search.md`·`index.html`을 열거하던 `simple_jekyll_search.exclude` 블록이 있었는데, - `simple-jekyll-search`는 브라우저에서 도는 JS라 `_config.yml`을 읽을 수 없어 아무것도 하지 - 않았다. 지워졌고, 왜 없는지가 `_config.yml`의 주석으로 남아 있다.) + About·Search·index 같은 페이지는 애초에 후보가 아니다. + + > **주의 — `_config.yml`로는 검색을 제어할 수 없다.** `simple-jekyll-search`는 브라우저에서 + > 도는 JS라 `_config.yml`을 읽지 못한다. 색인 대상을 바꾸려면 `search.json`의 Liquid를 + > 고쳐야 한다. `_config.yml`에 `simple_jekyll_search:` 같은 블록을 만들어도 아무 일도 + > 일어나지 않는다. ## 6. 스타일 (Sass) @@ -269,9 +273,13 @@ Bourbon → base/ → Neat → _layout → _post → _tags → _syntax(Rouge 코 - **수정해도 되는 곳**: `_sass/_layout.scss`, `_sass/_post.scss`, `_sass/_tags.scss`, `_sass/base/*`(특히 색·간격·브레이크포인트를 모아 둔 `_variables.scss`). -- **수정하면 안 되는 곳**: `_sass/bourbon/**`, `_sass/neat/**`(외부에서 가져온 벤더 - 프레임워크 — 우리가 만든 게 아니다), `_sass/_syntax.scss`(자동 생성물 — - `rougify style monokai.sublime`로 재생성한다). +- **수정하면 안 되는 곳**: `_sass/bourbon/**`, `_sass/neat/**` — 외부에서 가져온 벤더 + 프레임워크다. +- **`_sass/_syntax.scss`는 재생성하지 말 것**: 원래 `rougify style monokai.sublime`의 + 출력이지만 **그 뒤 손으로 고쳤다.** Monokai 기본 팔레트의 주석·키워드 색이 코드 배경에서 + 명도 대비 4.5:1을 못 넘겨 두 색을 올려 놨고, 파일 맨 위 주석에 원래 값과 대비 수치가 + 적혀 있다. `rougify`로 덮어쓰면 그 수정이 조용히 사라진다. 색을 바꿔야 하면 이 파일을 + 직접 고치고 주석도 함께 갱신한다. - **디자인 토큰을 쓸 것**: 값을 하드코딩하지 말고 미리 정의된 변수를 쓴다. 전환은 `$transition-*`, 그림자는 `$shadow-*`, 강조색/보조 텍스트는 `$action-color`/`$medium-gray`. `0.3s ease`나 `#aaaaaa` 같은 리터럴을 직접 박지 않는다. (예: `$medium-gray`는 @@ -279,8 +287,8 @@ Bourbon → base/ → Neat → _layout → _post → _tags → _syntax(Rouge 코 읽히는 진한 파랑으로 헤더/푸터 배경용.) - **절대 금지**: HTML 안의 인라인 `