diff --git a/AGENTS.md b/AGENTS.md index 428ba86..1eade42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -147,8 +147,10 @@ archives the feature to `.sdlc/archive//`. | What | Where | Written by | |---|---|---| - | A product's business rule (정책) — "a submitted answer cannot be edited" | `memory/areas/.md` Business rules, numbered P1… (templates/area.md) | close merge, shipped only | - | What changed in an area, when | the area page's History, one line per feature | close merge, shipped only | + | A product's business rule (정책) — "a submitted answer cannot be edited" | `memory/areas/.md` Business rules table, one row per rule — P1…, one plain sentence (templates/area.md) | close merge, shipped only | + | How an on-screen count, rate, score or chart figure is calculated | the same page's Numbers table, one row per figure — N1… (templates/area.md) | close merge, shipped only | + | Where a rule or figure came from, and the code behind the area | the same page's evidence block at the bottom (`
`, or the folded callout `> [!info]-` in an Obsidian store (index_style: obsidian)): the Where line, then one evidence row per rule or figure — `\| P1 \| source \| set by \| verified \|` | close merge | + | What changed in an area, when | the area page's History table, one row per feature | close merge, shipped only | | A fact that holds for one area only | the area page's How it works | close merge | | A term, or a system fact/constraint that spans areas | `memory/DOMAIN.md` (100 lines max) | close merge | | A trap and the correct move | `memory/lessons/-.md` + one `INDEX.md` line (50 lines max) | close merge | @@ -159,7 +161,13 @@ archives the feature to `.sdlc/archive//`. named by its menu path (`학습 > 평가 > 제출`); otherwise a module, API, job, or CLI command — not the `--area` knowledge folder of rule 7. summary.md's `Area:` line and the page's `Menu:` line use the same words, - which is how `kb.sh` links them. DOMAIN over its limit: move + which is how `kb.sh` links them. The page's file name is that Menu with + each ` > ` written ` - ` and any of `/ \ : * ? " < > |` replaced with `-` + (`교사 > 학생 > 학급 분석` → `memory/areas/교사 - 학생 - 학급 분석.md`). + An area page reads reader first: rules, figures and history as table rows + and how it works as bullets, in plain language, on top; every source, verification, and code identifier + in the evidence block at the bottom — a `
` block, or the folded + callout in an Obsidian store (index_style: obsidian). DOMAIN over its limit: move area-specific facts to their area page. INDEX over its limit: merge near-duplicates, drop superseded entries, replace promoted ones (skills/6-maintain). @@ -167,8 +175,11 @@ archives the feature to `.sdlc/archive//`. stages and researchers append candidates — one line each — to `.sdlc/work//harvest.md` (templates/harvest.md). At close, merge every candidate into its row above — creating an area page from the - template when none exists, numbering new rules, adding the feature's - History line to each area it changed — then delete harvest.md. Business + template when none exists (file named by its menu path, as above), + numbering new rules, writing each rule or figure as a table row and its + source as its evidence row, adding the feature's History row to each + area it changed (a line-shaped candidate becomes a row) — then delete + harvest.md. Business rules and History describe what the product DOES, so they merge only when the feature closes `shipped`: any other close drops them (summary.md keeps the story), and a stale merge leaves them in harvest.md for that close; diff --git a/README.ko.md b/README.ko.md index 5b52b32..7ac45d1 100644 --- a/README.ko.md +++ b/README.ko.md @@ -145,7 +145,7 @@ agent APPROVED: intent of claims-status (.sdlc/work/claims-status/intent.md) │ ├── POLICY.md # 사람이 선언한 하드 룰, 에이전트는 전사만 │ ├── INDEX.md # 교훈 포인터, 50줄 이하 │ ├── DOMAIN.md # 여러 제품 영역에 걸친 용어 · 사실 · 제약 -│ ├── areas/.md # 제품 영역(웹앱은 메뉴)마다 한 장: 업무 정책 P1… · 동작 · 변경 이력 +│ ├── areas/<메뉴 경로>.md # 제품 영역(웹앱은 메뉴)마다 한 장, 예: "학습 - 평가 - 제출.md": 업무 정책 P1… · 통계 산정 N1…(선택) · 동작 · 변경 이력 · 근거(접힘) │ └── lessons/-.md ├── work// # 열린 피처만 │ ├── origin.md # 요청 당시의 티켓 · 기획서 스냅샷 — intent 게이트가 결합 @@ -169,7 +169,7 @@ agent APPROVED: intent of claims-status (.sdlc/work/claims-status/intent.md) **기록을 어디에 둘지는 사용자가 정합니다.** 기본값은 프로젝트 작업 사본 안이고, `init.sh . --area ~/knowledge`를 쓰면 사용자가 고른 폴더 아래 `/<단위이름>-<체크아웃 식별자>/`에 저장하고 `.sdlc`를 그곳으로 연결합니다. 체크아웃마다 저장소가 하나씩이므로 워크트리 두 개가 승인 상태를 공유하는 일이 없습니다. 영역이 프로젝트 안에 있거나 프로젝트가 영역 안에 있을 때, 다른 체크아웃이 이미 그 저장소를 소유할 때, 실제 `.sdlc` 디렉터리가 이미 있을 때(자동으로 옮기지 않습니다), 링크를 만들 수 없을 때는 아무것도 쓰지 않고 분명히 실패합니다. 이 소유권은 init 시점뿐 아니라 실행 시점에도 다시 확인합니다. `/PROJECT`에 적힌 체크아웃이 지금 실행 중인 체크아웃과 다르면 `check-gate.sh`, `approve.sh`, `close.sh`, `status.sh`, `tools/auto.sh`, `tools/verify.sh`, `tools/handoff.sh`가 판정을 내리거나 상태를 쓰기 전에 거부하므로, 심볼릭 링크를 그대로 복사한 작업 사본(`cp -R`, rsync, 대부분의 백업 복원)이 다른 체크아웃의 게이트를 열거나 그 피처를 닫을 수 없습니다. 읽기는 이 제약을 받지 않아 `tools/kb.sh show|search|list`는 그대로 쓸 수 있고, 소유권을 자동으로 옮기거나 다시 묶는 일은 없습니다. 어느 쪽을 고르든 **저장소 백업은 사용자의 몫입니다.** git이 더 이상 대신해 주지 않습니다. -**지식은 제품 영역별로 정리됩니다.** 웹앱이면 제품 영역은 메뉴 하나이고 메뉴 경로(`학습 > 평가 > 제출`)로 부릅니다. 다른 소프트웨어는 모듈, API, 배치 작업, CLI 명령입니다. 제품 영역마다 `memory/areas/.md` 한 장이 있고, 여기에 개발자가 아니어도 읽을 수 있는 문장으로 쓴 업무 정책(P1, P2…), 동작 방식, 그 영역을 바꾼 피처별 이력 한 줄이 담깁니다. 피처의 `summary.md`는 `Area:` 줄로 제품 영역을 적고, spec은 어떤 정책을 유지하거나 바꾸는지 밝히고, Side effects 검증자는 건드리지 않아야 할 정책이 그대로인지 다시 확인하며, close 병합이 새로 생기거나 바뀐 정책을 페이지에 올립니다. `tools/kb.sh show "학습 > 평가 > 제출"`(또는 페이지 파일 이름)은 그 페이지와 그 제품 영역을 바꾼 피처를 함께 보여줍니다. +**지식은 제품 영역별로 정리됩니다.** 웹앱이면 제품 영역은 메뉴 하나이고 메뉴 경로(`학습 > 평가 > 제출`)로 부릅니다. 다른 소프트웨어는 모듈, API, 배치 작업, CLI 명령입니다. 제품 영역마다 페이지가 한 장 있고, 파일 이름은 메뉴 경로입니다 — `memory/areas/학습 - 평가 - 제출.md`(` > `는 ` - `로, `/ \ : * ? " < > |`는 `-`로 바꿉니다). 페이지는 읽는 사람 우선입니다. 위에는 개발자가 아니어도 읽을 수 있는 문장으로 쓴 업무 정책(P1, P2…), 동작 방식, 그 영역을 바꾼 피처별 이력 한 행이 오고(정책·수치·이력·근거는 한 줄에 하나씩 쓰는 마크다운 표), 출처·검증·코드 위치는 모두 맨 아래 접힌 근거 블록에 둡니다. 건수·비율·점수·차트를 보여주는 영역은 통계 산정(N1, N2…) 섹션도 가지며, 화면의 수치 하나마다 무엇을 세는지와 출처를 한 행으로 남깁니다 — 업무 정책과 같은 영속성·처리 방식을 따릅니다. 피처의 `summary.md`는 `Area:` 줄로 제품 영역을 적고, spec은 어떤 정책이나 수치를 유지하거나 바꾸는지 밝히고, Side effects 검증자는 건드리지 않아야 할 것이 그대로인지 다시 확인하며, close 병합이 새로 생기거나 바뀐 정책·수치를 페이지에 올립니다. `tools/kb.sh show "학습 > 평가 > 제출"`(또는 페이지 파일 이름)은 그 페이지와 그 제품 영역을 바꾼 피처를 함께 보여줍니다. **기록을 다시 읽는 도구는 `tools/kb.sh`입니다.** `index`는 목차 페이지를 다시 만듭니다(`init.sh`와 `close.sh`가 자동으로 실행합니다). 페이지는 정책 수·마지막 변경·피처를 담은 제품 영역 표, 상태·날짜·제품 영역·태그를 담은 개요 표(최신순), 아직 close가 병합하지 않은 harvest 목록, 피처별 절 순서입니다. `show `는 피처 하나를 요약본으로 보여줍니다. 목표, `summary.md`(제품 영역·무엇이 문제였나·Before → After·확인 방법을 담는, 계속 갱신하도록 만든 유일한 기록), 배포 상태, 병합되지 않은 harvest 후보, 교훈 제목이 먼저 나오고 파일 경로는 마지막입니다. `search "<문자열>"`은 열린 피처와 닫힌 피처, 지속 메모리를 대상으로 출력량을 제한한 문자열 검색을 하고, `harvest [--stale <일수>]`는 harvest.md가 아직 memory/에 들어가지 않은 열린 피처를 유휴 기간과 함께 나열합니다(유휴 상태가 오래된 피처는 close 없이 병합할 수 있습니다 — AGENTS.md 규칙 4). `--area <폴더>`를 붙이면 그 폴더 안의 모든 저장소를 대상으로 같은 일을 하며, 원래 체크아웃이 사라진 피처도 읽을 수 있습니다. 저장소 config.md에 `index_style: obsidian`을 적으면 Obsidian 볼트용 frontmatter와 인라인 `#태그`를 덧붙입니다. 생성 시각은 절대 쓰지 않으므로 내용이 같으면 diff도 생기지 않습니다. 종료 코드는 `0` 찾음, `1` 없음, `2` 사용법 오류 또는 거부입니다. diff --git a/README.md b/README.md index f025bd4..7f358e1 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ Per feature, inside the **target project**: │ ├── POLICY.md # human-declared hard rules; agents transcribe only │ ├── INDEX.md # ≤50 lines of lesson pointers │ ├── DOMAIN.md # terms · facts and constraints that span areas -│ ├── areas/.md # one per product area (web app: one menu): business rules P1… · how it works · history +│ ├── areas/.md # one per product area (web app: one menu), e.g. "학습 - 평가 - 제출.md": business rules P1… · numbers N1… (optional) · how it works · history · evidence (folded) │ └── lessons/-.md ├── work// # OPEN features only │ ├── origin.md # the ticket / 기획서 as requested — bound by the intent gate @@ -169,7 +169,7 @@ Per feature, inside the **target project**: **Where the records live is your choice.** By default they sit in the project's working copy. `init.sh . --area ~/knowledge` puts them in a folder you choose instead — `/-/`, with `.sdlc` linked to it, one store per checkout so two worktrees never share approvals. The area is refused if it sits inside the project (or the project inside it), if another checkout already owns that store, if a real `.sdlc` directory is already there (nothing is ever relocated for you), or if the link cannot be made. That ownership is re-checked at RUNTIME, not only at init: `check-gate.sh`, `approve.sh`, `close.sh`, `status.sh`, `tools/auto.sh`, `tools/verify.sh` and `tools/handoff.sh` refuse before any verdict or write when `/PROJECT` names a different checkout, so a copied working copy (`cp -R`, rsync and most restores keep the symlink) can neither open another checkout's gate nor close its features. Reading is never bound that way: `tools/kb.sh show|search|list` still works, and nothing is ever re-bound or moved for you. Whichever you choose, **the store is yours to back up** — git no longer does it for you. -**Knowledge is filed by product area.** For a web app an area is one menu, named by its menu path (`학습 > 평가 > 제출`); for other software a module, API, job, or CLI command. Each area has one page, `memory/areas/.md`: its business rules numbered P1, P2… in sentences a non-developer can read, how it works, and a history line per feature that changed it. A feature's `summary.md` names its area on an `Area:` line, the spec states which rules it keeps or changes, the Side effects verifier re-checks the rules it should not have touched, and the close merge files new or changed rules on the page. `tools/kb.sh show "학습 > 평가 > 제출"` (or the page's file name) prints the page with the features that changed it. +**Knowledge is filed by product area.** For a web app an area is one menu, named by its menu path (`학습 > 평가 > 제출`); for other software a module, API, job, or CLI command. Each area has one page, named by its menu path — `memory/areas/학습 - 평가 - 제출.md` (each ` > ` written ` - `; any of `/ \ : * ? " < > |` becomes `-`). The page reads reader first: its business rules numbered P1, P2… in sentences a non-developer can read, how it works, and a history row per feature that changed it — rules, figures, history and evidence are markdown tables, one row each; every source, verification, and code location sits in a folded evidence block at the bottom. An area that shows counts, rates, scores or charts also gets a Numbers section, N1, N2…, one row per figure recording what it counts and its source — the same permanence and treatment as a business rule. A feature's `summary.md` names its area on an `Area:` line, the spec states which rules or figures it keeps or changes, the Side effects verifier re-checks the ones it should not have touched, and the close merge files new or changed rules and figures on the page. `tools/kb.sh show "학습 > 평가 > 제출"` (or the page's file name) prints the page with the features that changed it. **Reading the records back** is `tools/kb.sh`: `index` regenerates the contents page (`init.sh` and `close.sh` do it for you) — the product areas with their rule count, last change and features, an overview table by state, date, area and tags, newest first, the harvests no close has merged yet, then one section per feature; `show ` prints one feature as a digest — goal, its `summary.md` (area, what was wrong, before → after, how to check, the one record meant to be kept current), delivery, unmerged harvest candidates, lesson titles, then the paths; `search ""` does a bounded literal search over open and closed features plus durable memory; `harvest [--stale ]` lists open features whose harvest.md is not in memory yet, with idle time (a stale one may be merged without closing — AGENTS.md rule 4); and `--area ` does any of these across every store in that folder — including features whose checkout no longer exists. `index_style: obsidian` in the store's config.md adds frontmatter and inline `#tags` for a vault; no timestamp is ever written, so an unchanged page produces no diff. Exit codes: `0` found, `1` nothing found, `2` usage error or refusal. diff --git a/VERSION b/VERSION index 86dd09a..cfe6c00 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.15.0 +v0.16.0 diff --git a/gates/selftest.sh b/gates/selftest.sh index aa602c0..16e60da 100755 --- a/gates/selftest.sh +++ b/gates/selftest.sh @@ -67,6 +67,36 @@ LC_ALL=en_US.UTF-8 bash "$kit/tools/kb.sh" index >/dev/null grep -qF '| [명단 > 내보내기](memory/areas/roster.md) | 1 | — | f1 |' .sdlc/README.md || fail "area table wrong: $(grep '명단' .sdlc/README.md)" out=$(bash "$kit/tools/kb.sh" show "명단 > 내보내기") case "$out" in (*"P1: 현재 학기만"*) ;; (*) fail "show did not print the rule: $out";; esac +# a page named by its menu path (" > " → " - "), reader first, in tables: +# rules counted from rows above the evidence block (evidence and retired rows +# are not), last change from the History table, header words free +mkdir -p .sdlc/work/f3; printf -- '- Area: 교사 > 학생 > 학급 분석\n' > .sdlc/work/f3/summary.md +printf -- '%s\n' '# Area: 교사 > 학생 > 학급 분석' '- Menu: 교사 > 학생 > 학급 분석' '## Business rules (정책)' '| # | 정책 |' '|---|---|' \ + '| P1 | 자기 학급만 본다 |' '| P2 | 전학생은 빠진다 |' '| ~~P3~~ | ~~지난 학기도 보인다~~ |' '| P4 | |' \ + '## History' '| 날짜 | 작업 | 바뀐 점 |' '|---|---|---|' '| 2026-09-01 | f3 | 참여율 추가 |' '| 2026-08-01 | f1 | 처음 |' \ + '
' '근거 · 코드 위치 (개발자용)' '' '- Where: ClassAnalysis#get' '' '| # | 출처 | 작업 | 검증 |' '|---|---|---|---|' \ + '| P1 | 기획서 | f3 | code — 2026-09-01 |' '| P3 | retired 2026-09-01 by f3: 정책 변경 | f3 | human |' '' '
' > ".sdlc/memory/areas/교사 - 학생 - 학급 분석.md" +# the Obsidian form of the evidence block: a folded callout, lines prefixed "> " +printf -- '%s\n' '- Menu: 학생 > 과제' '## Business rules (정책)' '| # | Rule |' '|---|---|' '| P1 | 마감 후 제출 불가 |' \ + '## History' '| Date | Feature | What changed |' '|---|---|---|' '| 2026-09-02 | f4 | 마감 표시 |' \ + '> [!info]- 근거 · 코드 위치 (개발자용)' '> - Where: HomeworkApi#submit' '>' '> | # | Source | Set by | Verified |' '> |---|---|---|---|' \ + '> | P1 | 기획서 | f4 | test — 2026-09-02 |' '> | P2 | 증거 행은 규칙이 아니다 | f4 | — |' > ".sdlc/memory/areas/학생 - 과제.md" +LC_ALL=en_US.UTF-8 bash "$kit/tools/kb.sh" index >/dev/null +grep -qF '| [교사 > 학생 > 학급 분석](memory/areas/교사%20-%20학생%20-%20학급%20분석.md) | 2 | 2026-09-01 | f3 |' .sdlc/README.md \ + || fail "menu-named table page row wrong: $(grep '교사' .sdlc/README.md)" +grep -qF '| [학생 > 과제](memory/areas/학생%20-%20과제.md) | 1 | 2026-09-02 | — |' .sdlc/README.md || fail "callout page row wrong: $(grep '과제' .sdlc/README.md)" +for q in "교사 > 학생 > 학급 분석" "교사 - 학생 - 학급 분석"; do + out=$(bash "$kit/tools/kb.sh" show "$q") || fail "show '$q' found no page" + case "$out" in (*"| P1 | 자기 학급만"*"| 2026-09-01 | f3 |"*"근거 · 코드 위치 (개발자용):"*"Where: ClassAnalysis#get"*"| P3 | retired"*) ;; (*) fail "show '$q' not reader first: $out";; esac + case "$out" in (*""*) fail "show printed a placeholder row: $out";; esac +done +out=$(bash "$kit/tools/kb.sh" show "학생 > 과제") || fail "show found no callout page" +case "$out" in (*"| P1 | 마감 후"*"History:"*"근거 · 코드 위치 (개발자용):"*" - Where: HomeworkApi#submit"*" | P1 | 기획서 | f4 |"*) ;; (*) fail "callout evidence not read last: $out";; esac +printf '%s\n' "$out" | grep -q '^ *>' && fail "callout prefix printed: $out" +fns=$(sed -n -e '/^kb_field() {/,/^}/p' -e '/^kb_get() {/,/^}/p' "$kit/tools/kb.sh") +where=$(eval "$fns"; kb_get ".sdlc/memory/areas/학생 - 과제.md" Where) +[ "$where" = "HomeworkApi#submit" ] || fail "kb_get did not read Where inside the callout: '$where'" +bash "$kit/tools/kb.sh" show "../areas/roster" >/dev/null 2>&1 && fail "area lookup followed a path" echo "ok: knowledge by product area" echo "SELFTEST PASS" diff --git a/init.sh b/init.sh index ca585fb..b7cf26f 100755 --- a/init.sh +++ b/init.sh @@ -303,7 +303,7 @@ EOF [ -f .sdlc/memory/DOMAIN.md ] || cat > .sdlc/memory/DOMAIN.md <<'EOF' # Domain knowledge — how THIS system works: terms and facts that span areas -# (≤100 lines; over → move area-specific facts to memory/areas/.md) +# (≤100 lines; over → move area-specific facts to memory/areas/.md) # ONE writer: the close step. Mid-loop candidates stage in the feature's # work//harvest.md and merge here at close (AGENTS.md rule 4). # Facts carry [verified: how — YYYY-MM-DD]. Recency wins: a merge candidate diff --git a/log/changelog-v0.16.0.md b/log/changelog-v0.16.0.md new file mode 100644 index 0000000..4d09165 --- /dev/null +++ b/log/changelog-v0.16.0.md @@ -0,0 +1,140 @@ +# v0.16.0 — area pages: figures, menu-path file names, reader-first layout + +v0.15.0 gave a product area one home for its business rules (P-numbers). A +menu that shows counts, rates, scores or charts had nowhere to say what a +number on screen actually means — "what is counted, out of what, real-time +or batch" lived in someone's head or nowhere. This release adds an optional +Numbers section to the area page, numbered N1… with the same permanence and +filing rules as a business rule. It also names each area page by its menu +path, so the file list reads like the product's menus, and lays the page out +reader first: plain language on top for a non-developer, every source, +verification, and code location folded into an evidence block at the +bottom, with rules, figures, history and evidence as markdown tables. Gates, +approvals, and the `--json` schema are unchanged; `kb.sh`'s rule count still +counts only live rules (a `| P |` row, or an older `- P:` line). + +## Changes + +- **`templates/area.md`** gains an optional **Numbers (통계 산정)** section + between Business rules and How it works: one row per on-screen figure, + named as the screen labels it, recording what it counts, out of what, + whether it is real-time or batch (job, refresh, data-as-of), its source, + and who set it. Delete the section for an area with no figures. N-numbers + follow the P-number rules: permanent, a changed figure is edited in place, + a retired one stays struck through. +- **The loop treats a figure like a business rule** wherever omitting it + would leave it unprotected: + - `templates/spec.md`'s "Business rules touched" section gains a sibling + line for numbers touched (kept/changed/new), so the Side effects + verifier re-checks a figure it did not set out to change, the same way + it already re-checks a P-number. + - Ship's retrospective (`skills/5-ship/SKILL.md`) writes a figure a + feature sets, changes, or retires as an area candidate, same as a + business rule. + - `templates/harvest.md`'s Area candidates format gains the `N` + line shape the close merge numbers, next to the existing `P` one. + - AGENTS.md rule 4's "what goes where" table gains a row: a figure's + calculation method files to the area page's Numbers, written by the + close merge on a shipped close only — same as a business rule. +- **An area page is named by its menu path.** The file name is the Menu + line with each ` > ` written ` - `, and any character a Windows or macOS + file name may not hold (`/ \ : * ? " < > |`) replaced with `-`: Menu + `교사 > 학생 > 학급 분석` → `memory/areas/교사 - 학생 - 학급 분석.md`. The + "ASCII kebab-case file name" instruction is gone from `templates/area.md`, + AGENTS.md rule 4, the READMEs, and `init.sh`'s DOMAIN.md header; the + close merge (AGENTS.md rule 4, `skills/5-ship`) is told the rule when it + creates a page. +- **`tools/kb.sh`** finds an area page by its file name, by its Menu line, + or by the file name a Menu gives (`kb_area_file`); a name holding `/` or + `\`, or starting with `.`, is still never looked up as a file. The + contents page's Product areas links percent-encode space `%` `(` `)` `[` + `]` `#` `<` `>` (`kb_area_href`) so a link to `교사 - 학생 - 학급 분석.md` + opens in GitHub and Obsidian; Hangul bytes stay as written. `kb_body` + prints a `…` line as a section label, so `show` prints + the page top first and the evidence block last, under + `근거 · 코드 위치 (개발자용):` — the part the line bound cuts first. The + Rules column no longer counts an unfilled template row `| P1 | <…> |` + (or line `- P1: <…>`), and `show` drops such a line the way it already + dropped `- Where: <…>`. +- **Reader-first `templates/area.md`.** Menu and Aliases on top; Business + rules, Numbers, How it works, and History in plain sentences with no + source and no code; then a `
` block — "근거 · 코드 위치 + (개발자용)" — holding the Where line and one evidence row per rule or + figure: `| P1 | source | set by | verified |`. Evidence rows sit below + the block's opening line, where the rule count stops, so they are never + counted as rules. A retired rule stays struck through on top + (`| ~~P3~~ | ~~rule~~ |`) and its evidence row's Source cell carries + `retired YYYY-MM-DD by : `. The section + headings are unchanged. `templates/harvest.md`'s area candidates split + the plain sentence from its evidence the same way, and ship's + retrospective says which part goes where. +- **Obsidian form of the evidence block.** Obsidian does not render markdown + inside `
`, so a store with `index_style: obsidian` writes it as + a folded callout (`> [!info]- 근거 · 코드 위치 (개발자용)`, every line + prefixed `> `); `kb.sh` reads both forms (Where found, callout lines + printed last without `> `, never counted as rules). +- **Tables for rules, figures, history and evidence.** Each is one + markdown table row (`| P1 | |`, `| N1 | label | counted | out of + | timing |`, `| YYYY-MM-DD | slug | what changed |`, and in the evidence + block `| P1 | source | set by | verified |` under the `- Where:` line); + Menu, Aliases and How it works stay list lines. A retired rule is + `| ~~P3~~ | ~~rule~~ |`, its reason in its evidence row's Source cell. + Header words are free (`| # | 정책 |` works); a literal `|` in a cell is + `\|`. `kb.sh` keys on row shapes only: the Rules count reads `| P |` + rows above the evidence block (the `
` or `> [!…]` line), the + last change reads History's first `| YYYY-MM-DD |` row, and `show` + prints tables as written — callout rows without `> ` — dropping only a + template placeholder row (every cell after the first `<…>`) and the + header of a table left with no rows. The close merge (AGENTS.md rule 4, + ship, harvest.md) writes rows; harvest candidates stay line-shaped. +- **README.md / README.ko.md**: the "Knowledge is filed by product area" + paragraph and the memory-tree comment now mention the optional Numbers + section, the menu-path file name, and the folded evidence block. + +## Compatibility + +**Existing ASCII-named area pages keep working.** `kb.sh show ""` still finds a page by its Menu line whatever the file is called, +the contents page still lists and links it, and features still file under +it by their `Area:` line. Only a newly created page takes the menu-path +name. To rename an old page, move it to the name its Menu line gives (a +plain `mv` when the store is not in git), then regenerate the contents page: + +```bash +git mv ".sdlc/memory/areas/class-analysis.md" ".sdlc/memory/areas/교사 - 학생 - 학급 분석.md" +tools/kb.sh index +``` + A feature whose `Area:` line names the old file name +instead of the Menu should be changed to the Menu words. Nothing is renamed +for you. + +**List-form pages keep working.** A page written with `- P: rule` +lines and `- YYYY-MM-DD — …` History lines (v0.15.0 and the first +v0.16.0 commits) is still counted and dated, and a page may mix both forms; +convert it to rows whenever the close merge next edits it. + +**Existing pages with inline sources keep working.** A rule written the old +way — `- P1: — source: … · set by …` — still counts and still +prints; the close merge moves its source to the evidence block the next +time it edits that rule, or you can move it by hand. + +An area page with no Numbers section is unaffected: the section is +optional and `kb.sh`'s Rules column stays a P-number count only (a store +with only P-numbers renders identically to before). No script parses the +`N:` line; filing it is an instruction to the agent, exactly like a +`P:` line. + +## Validation + +- `bash gates/selftest.sh` → `SELFTEST PASS`. Its "knowledge by product + area" test now also files a feature under a Hangul menu page named + `교사 - 학생 - 학급 분석.md`, laid out reader first with evidence rows and + a retired rule: the contents-page row links the percent-encoded path with + a Rules count of 2 (evidence and retired rows not counted); `show` by + Menu and by file name prints the rules before the evidence block; a + lookup holding `/` is refused; a second page in the Obsidian callout form + is read the same way. Both pages are in table form with Korean header + words: evidence rows, a retired row and a placeholder row are not + counted, the last change comes from the History table, and `show` + prints the tables with the evidence last. The list-form `roster` page + still counts. With the old `kb.sh`, the test fails. diff --git a/skills/5-ship/SKILL.md b/skills/5-ship/SKILL.md index 0fb0661..f136cd5 100644 --- a/skills/5-ship/SKILL.md +++ b/skills/5-ship/SKILL.md @@ -66,10 +66,18 @@ no lesson. Write what there is into the feature's `.sdlc/work//harvest.md` (lesson candidates in the skill 6 format; durable terms, verified facts, and constraints as domain candidates; AGENTS.md rule 4). **Every business rule this feature set, changed, or -retired is an area candidate** — the rule in one testable sentence, its -source (the origin, the spec R-item or compact intent O-item), the P-number -it changes or retires — plus one -history line per area it changed. Then finish the feature's `summary.md`: +retired is an area candidate** — the rule in one plain, testable sentence a +non-developer can read, the P-number it changes or retires, and, as its +evidence, the source (the origin, the spec R-item or compact intent O-item) +and how it was verified — plus one history line per area it changed. **A +figure the area page shows a Numbers section for is treated the same way**: +the N-number it sets, changes, or retires, named on screen, with what it +counts, and its source as evidence. The close merge writes the sentence as +a table row on top of the area page (a history candidate as a History row) +and the evidence as its evidence row in the `
` block at the bottom (or the folded callout in an Obsidian store, +index_style: obsidian); a page it creates is named by its menu path — the Menu with each +` > ` written ` - ` and any of `/ \ : * ? " < > |` replaced with `-` +(templates/area.md). Then finish the feature's `summary.md`: `Status` says only what delivery.md confirms (a pushed review branch is not a deployment), Before → After and How to check match what was actually built and proven, Remember holds the one thing worth knowing next time. diff --git a/templates/area.md b/templates/area.md index a03db05..ec9cee5 100644 --- a/templates/area.md +++ b/templates/area.md @@ -1,32 +1,79 @@ -# Area: 평가 > 제출> +# Area: - + -- Menu: -- Where: -- Aliases: +- Menu: +- Aliases: + + ## Business rules (정책) - +| # | Rule | +|---|---| +| P1 | | + +## Numbers (통계 산정) + +| # | Label on screen | What is counted | Out of | Timing | +|---|---|---|---|---| +| N1 |