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>
557 lines
36 KiB
Markdown
557 lines
36 KiB
Markdown
---
|
||
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 **56–66 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 60–90
|
||
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 4–6; this
|
||
repository's documents scored 2 across the board) and **이유 연결어미 / 문장 100개** (reference 6.7–23.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.
|