Files
document-haness/.agents/skills/rewriting-technical-prose-naturally/SKILL.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

557 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: rewriting-technical-prose-naturally
description: Use when an existing Korean technical document, section, or heading already contains grounded facts but sounds AI-written, slogan-like, overly polished, abstract, compressed, or mechanically contrasted and must be rewritten without changing its technical meaning.
---
# Rewriting Technical Prose Naturally
## Scope
Rewrite the style of existing Korean technical prose so it reads like a Korean engineer wrote it. Do not
use this skill to create the technical content, fill an evidence gap, correct an implementation, or add a
claim about this system that the source did not make.
Two things that look like new content but are not, and that this skill is expected to supply: **the
standard definition of a term the source already uses**, and **the ordering slots in
[references/document-skeleton.md](references/document-skeleton.md)** — moving an existing definition ahead
of its first use, or an existing outcome into the closing. Both rearrange or unpack what is already there.
Neither invents a fact.
**Priority: source preservation > natural Korean > polish.** If preservation and naturalness conflict,
keep the meaning — but fix the sentence by *adding a short clause that states the condition*, not by
twisting a word into a shape no one uses. A sentence that is technically exact and unspeakable is a
sentence that still needs work.
Before the first rewrite in a task, read all three references:
- [references/document-skeleton.md](references/document-skeleton.md) — how a Korean tech blog article
is ordered: opener, audience bar, definition section, case template, closing.
- [references/article-shape.md](references/article-shape.md) — **how much explanation goes inside a
section.** Ordering can be right while the piece still reads thin. This is the one that fails most often.
- [references/korean-tech-blog-register.md](references/korean-tech-blog-register.md) — what Korean
tech blogs actually do with definitions, verbs, particles, subjects, headings, and numbers.
## Unpacking is not inventing
A compressed source and a thin source look the same on the page, and they are not. Four moves recover
what the source already holds. None of them adds a fact.
| Move | Where the material comes from |
|---|---|
| **Restore a number the prose rounded off** | The record's own fields — `검증 환경`, `재현 조건`, the evidence file, the `확인한 것` table. A body that says 「세 곳에서 막는다」 while `검증 환경` lists ports 8088 · 8081 · 4180 dropped those numbers on the way in. Put them back. |
| **Define a term at its first use** | The standard, public definition of a term the source already uses. `MessageDigest.isEqual`, `auth_request`, `forward-auth` — one clause each, where the reader first needs it. |
| **Turn a table row into a sentence** | The table already in the source. A row like `host port 닫힘 \| 외부 직접 경로` becomes the sentence that says which ports, closed how, and what still gets through. The table stays as the summary. |
| **Show the code the source only named** | The repository, at the revision the record pins. `EdgeIdentityController.currentUser` named in prose becomes the method body — trimmed to what the section is about, cut marked `// …`. |
What is still off limits: a measurement nobody took, a cause the source did not establish, a benefit or
drawback the source did not claim, a failure story that did not happen. If a section needs a number that
was never measured, write that it was not measured and leave the slot open — `article-shape.md` shows the
six articles doing exactly that.
**The test:** point at the sentence you added and name the field, file, or line it came from. If you
cannot, it is invention, not unpacking.
- [references/regression-examples.md](references/regression-examples.md) — rewrites that failed and why.
Read the complete source and the nearby context needed to interpret pronouns, comparisons, and causes.
Do not rewrite an isolated paragraph when its protected meaning depends on the surrounding section.
## Required sequence
This is an **editorial** pass. The source's facts, evidence, causal chain, uncertainty, decision status,
and technical depth are the contract. Work in this order — the steps that have their own section are
named here so the spine stays visible.
1. **Read the whole record once without editing.** A paragraph fixed before you know how the piece ends
is fixed against the wrong context.
2. **Mark the protected literals and the sentences that carry technical weight** — `Establish the meaning
contract` below, and `references/protected-content.md`.
3. **Name the stylistic problems, and only those.** Repeated sentence frames, forced conversational tone,
abstract filler, too many headings, translated constructions, a conclusion restated in three places,
paragraphs of identical length, bolding that has stopped meaning anything.
4. **Edit diction, sentence order inside a paragraph, paragraph boundaries, and headings.** Do not move a
fact between sections while doing it.
5. **Re-read against the original** and restore every technical fact, limitation, condition, and evidence
detail that fell out. This step finds more than it seems it should.
6. **Close with `Mechanical pass` then `Final check`.** The checkers read surface patterns; the read-aloud
test and the preservation questions decide.
### Hard rules for this pass
- Do not shorten merely to look more human.
- **Do not remove implementation detail because the paragraph feels dense.** Density is not a style defect.
- **A section is a claim plus its evidence.** Evidence is code, output, a number, or a table — at least
one. A section that is two paragraphs of prose with neither was cut at the wrong place; merge it with
its neighbour. `references/article-shape.md`.
- **Do not let a table carry an explanation that was never written.** Tables summarise prose that already
ran. If the table is the first place a distinction appears, write the prose first and keep the table.
- Do not create `처음에는`, `해보니`, `놀랍게도`, `저희는` or other experience language unless the source
records that experience.
- **Do not imitate one company's or one author's voice.** `style_profile.mjs` measures against five
Woowahan articles because they are a *sample of engineering writing*, not a target to sound like. Apply
the cross-source patterns in `references/editorial-rules.md`; do not adopt a house style.
- Do not make every section equally polished, equally long, or structurally symmetric.
## Establish the meaning contract
Make an internal claim ledger before editing. Do not print it unless asked. Record:
- every number, sign, unit, date, version, identifier, annotation, command, path, status, and observed output;
- success and failure results;
- each stated cause and its stated result;
- comparison targets and axes;
- environment, dataset, topology, timing, and other verification conditions;
- confirmed facts, inferences, possibilities, assumptions, recommendations, unknowns, and excluded scope;
- exceptions, limitations, and facts the source explicitly did not verify.
Every material sentence in the rewrite must map to the source ledger. Every material source claim must
remain represented. Do not combine claims when the combination creates a stronger generalization.
## Structure comes from the source, not from a checklist
An earlier version of this skill listed nine slots a document "must have" and a checker that failed a
document for missing them. That was wrong, and it produced a new defect: every rewrite came out in the
same order — 요약 → 지도 → 호출 순서 → 테스트 → 공백 → 다음 읽기 — with a Findings list at the end. The
sentences read like Korean; the document read like a report generator's stable output format.
[references/document-skeleton.md](references/document-skeleton.md) records what five reference articles
happen to do. **It is an observation, not a form to fill in.** Read it to see what moves exist, then let
the source decide which of them this document needs.
### Five things not to do
1. **Do not promote every verified fact to a section.** A code reading turns up dozens of true
observations. Only the ones the document's central question needs belong in the flow. The rest stay
out, even though you confirmed them and it feels wasteful to drop them. Wanting to include everything
confirmed is the most reliable machine tell there is.
2. **Do not build a fixed running order.** No document owes you 지도 → 순서 → 테스트 → 공백 → 다음 읽기.
Two documents about the same subsystem should not have the same section skeleton.
3. **Do not re-package what the body already said as a closing Findings list.** Eight bullets of
"현재 구현 공백" after the body already explained each one reads as an agent's analysis output, not as
a person writing. If a limitation matters, it belongs next to the thing it limits.
4. **Do not write sentences that instruct the reader how to think.** `먼저 결론을 구분해야 합니다`,
`여기서 typed label과 end-to-end 동작을 구분해야 합니다` — go straight to the event instead:
`CacheAsideExecutor까지 따라가면 동작이 달라집니다`. One or two orienting sentences in a whole
document is plenty; more than that and you are narrating your own analysis process.
5. **Do not keep working notes in the published document.** `다음에 열어볼 source 순서`,
`잘못 읽기 쉬운 지점` are an agent's memo to itself. A reader did not ask what you plan to open next.
### What to keep
Where the source genuinely carries one of these, keep it and put it in the right place: what the document
is about, who it is for and what they need to know first, a definition before its first use, what happened
and why. **A slot the source is silent about stays absent — and so does a slot the source could fill but
this particular document does not need.**
## Write Korean, not translated Korean
This is the part that keeps failing. Details and quoted corpus examples are in
[references/korean-tech-blog-register.md](references/korean-tech-blog-register.md); the rules below are
the ones to apply on every sentence.
### Define the term before you use it
At the first appearance of an API name, metric, counter, annotation, or domain word, write one sentence
saying **what it is and what it does**. Korean tech blogs open this way as a matter of course:
`MDC(Mapped Diagnostic Context)는 ... 메타 정보를 넣고 관리하는 공간입니다`,
`화면에 렌더링되어 사용자에게 노출되는 문자열을 '문구'라고 하겠습니다`.
Keep the original name. Expand an acronym in parentheses at first use. Where a plain-text field cannot
carry a code name, put the meaning first and the name in parentheses: `준비된 SQL 문장(PreparedStatement)`.
**This is not "adding content."** A standard definition of a term the source already uses is prerequisite
knowledge the reader needs, and supplying it is part of the job. What you may not add is a new claim
about this system, this measurement, or this decision. Definition: yes. New finding: no.
**A definition you can only produce by reading the identifier's name is not a definition — it is a guess.**
`deniedCommandCount`는 거절된 명령의 수이고 `rejectedRequestCount`는 거절된 요청의 수다 looks like a
harmless gloss, but if the source never said what either one counts, you just decided it. A definition may
come from the source document, the codebase, or the framework's own documentation — nowhere else. When
none of those give you the meaning, keep the name, say what the source does say, and leave the rest alone:
`두 값은 1과 200으로 달랐습니다. 각각이 무엇을 세는지는 이 문서에서 확인하지 않았습니다.`
This applies hardest to internal counters and metrics, where a plausible-sounding gloss silently redefines
what was measured.
### Write Korean words in Korean. Latin script is for identifiers only
This is the single largest difference between this repository's prose and the reference articles, and the
earlier version of this skill made it worse by telling you to "keep the name" without saying which names.
Measured over the five reference articles versus nine rewritten sections here:
| | 우아한형제들 | 이 저장소 |
|---|---|---|
| 문장당 영문 토큰 | **1.4** | **4.4** |
| 글자 중 한글 비율 | **0.58** | **0.34** |
| 쿼리 / `query` | 66 / 5 | 5 / 4 |
| 캐시 / `cache` | 2 / 0 | 0 / 19 |
| 상태 / `status` | 48 / 0 | 6 / 7 |
| 설정 / `config` | 49 / 3 | 5 / 6 |
A page of Latin nouns strung together with Korean particles is what "AI가 정리한 기술 보고서" actually
means. Fixing it changes no fact, because a bare common noun was never a protected span.
**Four buckets. Only the first stays in Latin script.**
1. **식별자 — 그대로 둔다.** Class, method, field, config key, command, constant, file name, annotation:
`CacheAsideExecutor`, `getLoadCount()`, `min-replicas-to-write 1`, `application.yml`, `@ManyToOne`.
These are protected spans. Keep them in backticks and never translate them.
2. **한국어에 자리잡은 외래어 — 한글로 적는다.** 쿼리 · 캐시 · 클래스 · 테스트 · 요청 · 응답 · 상태 ·
설정 · 키 · 스레드 · 세션 · 토큰 · 인덱스 · 라이브러리 · 컴포넌트 · 메서드 · 필드 · 어댑터 ·
인스턴스 · 클라이언트 · 커넥션 · 타임아웃. The reference articles write every one of these in Hangul.
3. **한국어 낱말이 이미 있는 영어 일반명사 — 한국어로 쓴다.** `credential` 자격 증명 · `budget` 상한 ·
`owner` 소유자 · `source` 원본 · `reply` 응답 · `warning` 경고 · `account` 계정 · `material` 값 ·
`group` 묶음 · `lane` 갈래 · `contributor` 항목. Where the document has already declared one as its
own term, keep that term — but declare it once, in Korean, rather than leaving the English in every
sentence.
4. **고유명사·제품명 — 그대로 둔다.** Redis, Nginx, Hibernate, Spring, Actuator, Keycloak, PostgreSQL.
**After the first mention, refer back in Korean.** `optional contributor는 … optional contributor가 …`
becomes `… 이 항목이 …`. Repeating the full English name in every sentence is what pushes the count to
four per sentence. Pointing back with 이/그 + a Korean noun changes nothing about which thing you mean.
An unavoidably English term that has no Korean equivalent gets introduced once as `한글 뜻(English)` and
then used in Hangul. Do not carry the Latin form through the whole section.
### Order: define, then what happens, then the problem, then the replacement
Where the source explains a term or a mechanism, keep that order: what it is → how it is used → what goes
wrong → what to use instead. Deferring the definition makes the reader carry an unknown word through two
paragraphs. Skip the fourth step when the source never considered an alternative.
TechLog records link to each other, so a record can be short. It still has to carry its own core claim and
the prerequisite knowledge that claim needs. Deeper background belongs in a linked record; the definition
a reader needs to parse *this* sentence does not.
### Join cause and effect inside one sentence
Use `~기 때문에`, `~다 보니`, `~어서`, `~(으)므로`, `~는데`, `~니`, `~면`. Do not chop a reason into
separate sentences to satisfy a one-fact-per-sentence rule — `A였다. B였다. 그래서 C였다.` is machine
Korean, and no Korean tech blog writes that way.
**Break a sentence when the subject changes, not when the second clause starts.** Same subject carrying a
reason or condition stays in one sentence.
Measured across the five reference articles: prose sentences average **5666 characters**, and fewer than
5% run past 120.
**That average is a mixture, not a target length for every sentence.** Joining every reason into a
compound sentence pushes the average to 80+ and makes the section as hard to read as the choppy version
it replaced. Some sentences are *supposed* to be short, and they are always the same five jobs:
| 짧게 끊는 문장 (20~35자) | 예 |
|---|---|
| 정의 한 줄 | `'진입점'은 사용자 요청의 시작점을 의미합니다.` |
| 다음에 볼 것 예고 | `먼저 할당 API를 살펴보겠습니다.` |
| 수치 한 줄 | `쿼리를 수행한 인덱스의 문서 수는 4천만 건입니다.` |
| 코드·표로 넘기기 | `당시 쿼리는 다음과 같은 구조로 작성되어 있었습니다.` |
| 방향 전환 | `다만, 이와 같은 해결 방법에도 문제점이 있습니다.` |
Only the explanatory sentence — the one carrying a cause, a condition, or a consequence — earns 6090
characters. Definitions, announcements, bare numbers, and hand-offs stay short. Do not weld them onto the
sentence next door to satisfy the joining rule.
None of these five require the vivid register. They are the reason the reference articles have short
sentences without inventing an experience.
This cuts both ways. Joining is the fix for choppy prose, but a sentence that runs through two subjects,
two measurement scales, or two results is now too long — split it at the point where the subject changes.
`N=10에서는 ~ 문제가 보이지 않았는데, N=1,000에서는 ~ 50.0×까지 벌어졌습니다` is two sentences wearing
one comma.
### Vary how sentences end
The reference articles use **four to six different sentence endings**; every document in this repository
before the rewrite used two. That single number is most of what makes the prose feel machine-made, and it
is the easiest thing to fix.
| 끝맺음 | 쓰는 자리 |
|---|---|
| `~합니다` / `~했습니다` | 사실·측정·코드 동작. 대부분 여기다 |
| `~입니다` | 정의, 지금 무엇인지 |
| `~하겠습니다` / `~살펴보겠습니다` | 다음에 무엇을 볼지 예고 |
| `~할까요?` / `~뭐죠?` | 독자가 품을 물음을 대신 꺼낼 때 |
| `~해봅시다` / `~확인해봅시다` | 수치나 코드로 넘어갈 때 |
| `~지만` / `~인데요` | 앞과 어긋나는 것을 이어 붙일 때 |
Do not sprinkle these to hit a count. Each one belongs to a job: a heading that asks a question, a
sentence that hands off to a table, a line that announces the next section. When those jobs are being
done, the variety appears on its own. When the whole section is flat `~했습니다`, it usually means those
jobs are not being done at all — the document is a list of facts with no one walking the reader through it.
### Say what happened with a verb, and pick the verb the context takes
`쿼리가 나갔습니다` / `응답 속도가 개선되었습니다` / `약 1분이 소요되었습니다` / `문제가 발생합니다` /
`AST 노드를 순회합니다` / `위반으로 잡습니다`. The register file has the full context→verb table.
Do not turn an event into a counted noun phrase — `채워진 목록 수`, `준비한 SQL 문장`,
`획득한 문장 객체 수` — to keep a metric name technically safe. Code behavior takes present tense
(`~합니다`); measurements and things that happened take past tense (`~했습니다`). Do not mix them.
### Never invent a private idiom for a numeric relationship
`~를 따라 늘었다`, `~를 따라갔다`, `~를 좇았다` are not Korean. `따라가다` takes a person, a path, or a
standard — not a count. Write the relationship the way it is actually said:
| 관계 | 쓴다 |
|---|---|
| 같은 수 | `아이템이 100개면 조회도 100번 나갔습니다` · `N과 같은 수로 늘었습니다` |
| 비례 | `N에 비례해 늘었습니다` · `N이 커진 만큼 늘었습니다` |
| 배수 | `약 3배 증가했습니다` · `50배까지 벌어졌습니다` |
| 변하지 않음 | `N을 바꿔도 2개로 그대로였습니다` · `페이지 크기에 고정되었습니다` |
| 단위마다 증가 | `배치 크기마다 한 번씩 늘었습니다` |
Numbers take the shape `<잰 것>이/가 <수치만큼> <동사>했습니다`, with before/after as
`기존에는 ~, 개선 후에는 ~`. Keep ``, `이상`, `정도`, and every unit exactly as the source had them.
### Particles
`이/가` marks the measured subject. `은/는` marks a before/after contrast. `(으)로` marks the resulting
state. `에 비해`/`보다` marks a comparison. Do not chain `` three deep — `조회 수의 증가 형태의 비교`
becomes `조회 수가 어떻게 늘었는지`. Do not join nouns with `~에 대한`; use the verb —
`쿼리 수에 대한 측정` becomes `쿼리 수를 측정했습니다`.
### Choose the subject by what kind of sentence it is
Decisions and actions take a person (`저는 ~하기로 했습니다`). Results and observations take the measured
thing with a passive verb (`슬로우쿼리가 모두 제거되었습니다`). Code explanations take the code element
(`이 규칙은 ~를 허용하는데`). Drop the subject when the previous sentence already fixed it.
## Name the thing, not its role in your argument
`기준선`, `비교 대상`, `최소한의 선`, `위반`, `핵심`, `본질`, `구조적 문제`, `증가 형태`, `실체`, and a
bare `관계` name a slot in an argument instead of naming the thing. A word that only tells the reader how
to read — `읽으면 안 된다`, `봐야 한다`, `주의해서 보자` — is not a fact either. State the observation
that would make them read it that way.
| 쓰지 않는다 | 쓴다 |
|---|---|
| 이 구현을 기준선으로 삼았다 | 이 코드를 그대로 두고 측정했다 |
| 같은 기준선에 두 가지 위반이 있었다 | 어떤 요구가 어떤 두 가지 방식으로 깨졌는지 적는다 |
| 현재 기준선에는 batch가 없다 | 이 구현에는 batch 설정이 없다 |
| 두 값은 비교 대상이 아니다 | 두 값은 세는 것이 다르다. A는 `<A가 세는 것>`, B는 `<B가 세는 것>`이다 |
| 최소한의 선은 지켰다 | `<지킨 조건>`은 지켰다 |
| 두 엔티티의 관계가 문제였다 | `FeedItem`과 `Highlight`의 `@OneToMany` 매핑이 문제였다 |
| 이 실행계획을 최적이라고 읽으면 안 된다 | 실행 시간이 0.173 ms라고 해서 필요한 만큼만 읽는 것은 아니다 |
| 증가 기준은 A가 아니라 B였다 | A가 늘어도 그대로였고, B가 늘 때 같이 늘었다 |
These are replacements, not deletions. The fact the framing word was standing in for still has to be in
the rewrite. `관계` is fine as part of a real name (`연관 관계`, `@ManyToOne 관계`); it is not fine as a
stand-in for a mapping you did not name.
## Delete the sentence that only sets up the next one
Cut every sentence that prepares, frames, or restates:
- a first sentence that repeats the heading (`반복되는 ~를 실행계획으로 확인했다` under a heading that says so);
- a scene-setter before the explanation (`이 코드는 반복문이 없는 상황이다`, `여기서는 ~를 다룬다`);
- a wrap-up that announces what you just showed (`이 관찰은 두 가지를 보여준다`).
**Test: delete it and ask what the reader lost.** If nothing, it stays deleted.
A forward-looking sentence that tells the reader *from what angle* the next part is examined is different,
and Korean tech blogs do write it — `이번에는 ~를 ~ 중심으로 살펴보겠습니다`. That adds information the
heading did not carry. Keep at most one per section, and only when it names the angle.
## Do not package the source
Do not newly introduce slogans, metaphors, or polished conclusions such as:
- `이는 ~를 보여준다`
- `결국 문제는 ~이다`
- `단순히 ~가 아니라 ~이다`
- `비용이 ~로 이동했다`
- `새로운 책임이 생긴다`
- `정반대의 결과를 보였다`
- `회계 항등식`
These strings are not a blind deletion list. If the source explicitly makes the same claim, restate it
with the concrete facts that support it. Do not add a lesson, advantage, drawback, recommendation, or
causal explanation just because it would complete the paragraph. End after the supported cause or result;
do not force every paragraph into observation → interpretation → lesson.
**Two things this rule does not ban.** Korean tech blogs use both, and cutting them makes the prose
worse, not cleaner:
- **Steering the reader inside the article.** `중요한 것은 아래 세 가지 컨벤션을 반드시 지켜야 한다는
점입니다` picks which of the things just listed to carry forward. That is navigation, not a
manufactured conclusion. The banned use is the same phrase pasted next to a measurement to make the
data look like it proved something it did not.
- **A closing opinion in the closing section.** `26388` ends with `AI는 요술램프가 아닙니다 … 안목이 더욱
중요해지고 있습니다`. That belongs in 맺는 글, is the author's own view, and appears once. Keep one the
source already states; never write a new one, and never let it migrate into the middle of the document.
Use contrast words only when the contrast is needed to understand the facts. Do not manufacture symmetry
with `반면`, `반대로`, `이에 비해`, or `하지만`.
Korean tech blogs also carry vivid, personal, sometimes funny sentences. **Do not import that register.**
It comes from something the author actually lived through. Inventing an experience, a failure, an emotion,
or a first-person aside that the source does not record breaks this repository's rules. What transfers
without a source is plain verbs, concrete nouns, reasons joined inside the sentence, and definitions
placed first.
## Headings
A heading names what the section examines or what it does. These are the shapes the reference articles
actually use — none of them builds a contrast or poses a riddle:
| 형태 | 실제 제목 |
|---|---|
| 용어를 묻는다 | `WMS란?` · `진입점이 뭐죠?` · `MDC를 아시나요?` · `공간 (Spatial) 데이터 타입이란?` |
| 이유를 묻는다 | `근데 왜 진입점 정보가 남아야 해요?` |
| 상황을 묻는다 | `할당과 취소를 동시에 요청한다면?` |
| 동작 + 목적 | `한글 문구에 번역 API를 사용해 번역 누락 막기` · `<Trans> 계열 컴포넌트는 필요할 때만 사용해 코드 복잡도 낮추기` |
| 단계 | `1 단계: 분산 락 추가하기` · `2 단계: 분산 락 대기하기` |
| 청유 | `할당과 취소가 동시에 처리되는 것을 막아보자` |
| 대상 | `공간데이터 및 GeoJSON` · `@lib/i18n과 세 가지 컨벤션` |
| 상태·한계 | `사람과 AI 검수의 한계` · `한계점` · `남은 과제들` |
`현재 구현 공백과 잘못 읽기 쉬운 지점` 같은 분류형 제목은 이 목록에 없다. 보고서의 절 이름이지
블로그 글의 제목이 아니다. 한계를 분류해서 한곳에 모으지 말고, 그것이 제한하는 대상 옆에 적는다.
| 고정 칸 | `현상` · `문제 원인 분석 및 해결` · `개선 결과` · `해결방법` · `문제점` |
`동작 + 목적`(`~해 ~하기`) is the one to reach for when a section describes a fix: it names the action and
what the action buys, and it cannot become a slogan because both halves are concrete.
The `현상 / 문제 원인 분석 및 해결 / 개선 결과` triple repeats five times in `20161`. When a document walks
through several independent cases, reusing one fixed set of headings is clearer than inventing a fresh
phrase per case.
## Explain one scale, and let the table carry the series
Pick one N for the worked example and stay there. Picking the largest N to sound dramatic is padding.
Restating 10/100/1,000 in every sentence forces the reader to re-orient each time; the table already
shows the shape of the growth.
## Figures
A figure earns its place only when it carries something the sentences cannot: a sequence with actors and
order, a structure with parts and boundaries, a measurement with axes and values, or a captured artifact —
a log, a plan, a screen. Three boxes and two arrows that redraw one sentence
(`요청 → 초기화 N회 → SELECT N회`) add nothing; the sentence already said it, and the alt text says it a
third time. Delete the figure instead of writing a caption that apologizes for it.
Before keeping a figure, say what a reader learns from it that the paragraph next to it does not tell
them. If there is no answer, remove it.
## Quick reference
| Symptom | Rewrite direction |
|---|---|
| Numbers became an adjective or trend | Restore every value and its condition |
| A cause became `캐시 효과` or another summary | State the actual reuse, query, or state change |
| Two results became a polished contrast | Explain each result in the order observed |
| A sentence became shorter but denser | Restore the subject, action, and reason |
| A paragraph ends with a generic lesson | Remove the lesson unless the source stated it |
| A heading sounds like a slogan or riddle | Name the checked operation, object, or limit |
| An API or metric name appears with no explanation | Add one sentence defining it at first use and keep the name |
| A framing noun (`기준선`, `비교 대상`, `관계`) stands in for the thing | Name the method, request, mapping, or requirement |
| The sentence tells the reader how to read | Replace it with the observation that supports it |
| A metric name pushed the sentence into a noun phrase | Say what happened with a verb; leave the metric name and its caution in the body |
| `~를 따라 늘었다` / `~를 따라갔다` | Use the real relationship: 같은 수 · 비례 · 배수 · 고정 |
| Sentences are all short and choppy | Rejoin with `~기 때문에`, `~다 보니`, `~어서`; break only where the subject changes |
| One sentence runs through two subjects, scales, or results | Split it at the subject change |
| A metric is glossed from its identifier name | Only define it from the source, the code, or the framework docs; otherwise leave it undefined and say so |
| ``가 세 겹, or `~에 대한` | Unfold into a verb |
| Code and measurement mix tense | Code `~합니다`, measurement `~했습니다` |
| A sentence only prepares or restates the next one | Delete it |
| The example jumps between N=10, 100, 1,000 | Pick one scale and explain there; leave the series to the table |
| A figure redraws a sentence | Remove it, or replace it with a log, plan, or measurement it cannot say |
| A possibility sounds certain | Restore the original modality and unverified scope |
## Mechanical pass
Run the checker on the rewritten file before the final check.
```bash
node .agents/skills/rewriting-technical-prose-naturally/scripts/check_prose.mjs [--doc] [--warn] <파일.md>
```
`--doc` adds the whole-document checks (prerequisite knowledge, running order, closing); use it when you
rewrote a full document, not a single section. `--warn` shows the judgment-call findings too.
`--rules` is for rule documents — `README.md`, `CLAUDE.md`, the skill files themselves. Those are lists of
items ending in `~한다`, and mixing in `~살펴보겠습니다` to satisfy a count makes them worse, so it turns
off `monotone-endings` and `no-reader-steering`. Every other rule still runs. Do not reach for it on prose:
those two errors are the ones that catch machine writing in an article.
It reports two levels. **`error` must be zero before you call the rewrite done** — these are the
regressions that keep coming back, plus the four things whose absence made earlier rewrites read like a
machine: a term defined after its first use, one single sentence ending used throughout, no sentence that
carries the reader, and a missing closing. **`warn` is a prompt to look**, not a defect: `반면` is right
where the source really contrasts, `관계` is right inside `연관 관계`, and plenty of acronyms
(`SKU`, `GS`, `AOP`) are left unexpanded by good writers.
**The baseline is the reference articles themselves.** All five Woowahan articles in
[references/document-skeleton.md](references/document-skeleton.md) pass with zero errors. If you add a
rule, re-run it against them — a rule those articles fail is a rule that is stricter than the standard,
and it will push you into contorting prose to satisfy a check no human writer meets.
Then measure depth. `check_prose.mjs` reads sentences; this reads how much is in them.
```bash
node .agents/skills/rewriting-technical-prose-naturally/scripts/density.mjs [--구조] <파일.md>
```
Default thresholds are for a piece that reports something measured — a Case. Pass `--구조` for one that
explains how something works — a Concept — where two to five figures is normal and thirteen is not.
Ranges come from the six articles in [examples/](examples/).
**These are not targets to hit.** A low count names a place where explanation is missing; adding
paragraphs to move the number produces a worse document that passes. Read the flagged line, find the
section it points at, and decide whether the source actually holds what belongs there.
Then take the style profile:
```bash
node .agents/skills/rewriting-technical-prose-naturally/scripts/style_profile.mjs <파일.md>
```
It prints six numbers and flags any that fall outside the band measured on the five reference articles.
The two that catch machine prose almost every time are **종결어미 종류 수** (reference 46; this
repository's documents scored 2 across the board) and **이유 연결어미 / 문장 100개** (reference 6.723.6).
A number outside the band is a symptom to trace back to a real sentence, never something to fix by
padding — inserting `~해봅시다` to raise a count produces exactly the kind of writing this skill exists to
remove.
Clean output does not mean the rewrite is good. Both tools read surface patterns and cannot see meaning;
every rule above still applies, and the read-aloud test below is the one that decides.
## 참조
- `examples/` — **통과 기준이 되는 글 여섯 편.** 이 정도로 읽히면 통과다
- `references/article-shape.md` — 한 절 안을 무엇으로 채우는가. 잰 값과 그 값을 만드는 것
- `references/regression-examples.md` — 고친 예와 실패 이유
- `references/protected-content.md` — 옮길 때 한 글자도 바꾸면 안 되는 것
- `references/editorial-rules.md` — 편집 규칙
- `references/research-method.md` — 문체 기준값을 다시 재는 방법
- `references/corpus/` — 한국어 기술 글 코퍼스 조사 노트
문장 규칙 두 개는 `writing-tech-log-records` 스킬에 있다. 두 스킬이 같은 규칙을 쓰므로 사본을
만들지 않는다.
- `../writing-tech-log-records/references/explaining.md` — 설명하는 법
- `../writing-tech-log-records/references/ai-tells.md` — 문서군 전체의 리듬
## Final check
First, read every rewritten sentence aloud and ask: **would a Korean-speaking developer say this to a
colleague this way?** A sentence that is accurate but unspeakable is not finished. Fix it by adding the
condition as a short clause, never by bending a word into an unusual grammatical role.
Then compare the source and rewrite sentence by sentence:
1. Are all numbers, units, code names, identifiers, and observed results preserved?
2. Are cause and result still connected in the same direction?
3. Are comparison targets and axes unchanged?
4. Did a possibility, inference, proposal, or unknown become a confirmed fact?
5. Was any new cause, benefit, drawback, conclusion, or recommendation added?
6. Did any exception, failure, condition, or unverified scope disappear?
7. Did a concrete technical statement become a broader abstraction?
8. Can every rewritten claim be pointed back to a specific source claim?
9. Is every API name, counter, and internal metric defined where it first appears, with what it counts unchanged?
10. Does the reader have the prerequisite knowledge to follow the core claim, or does an undefined term still block them?
11. Did any experience, emotion, or first-person aside appear that the source does not record?
If any answer reveals a mismatch, rewrite again or restore the original sentence. Do not declare the edit
complete until the mismatch is gone.