Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,9 @@ HWPX 내부 구조가 처음이라면 [내부 실전 가이드](docs/internals/)
## License · Maintainer

Apache-2.0 ([LICENSE](LICENSE) · [NOTICE](NOTICE)) — **Kohkyuhyun** [@airmang](https://github.com/airmang) · [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)

### Experimental native-preview scene

Applications that provide glyph metrics can opt into the cache-independent
[experimental scene API](docs/native-preview-scenes.md). Native font loading,
rasterization and desktop file handling remain in the automation/plugin layers.
12 changes: 12 additions & 0 deletions docs/architecture/module-ownership.json
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,18 @@
"disposition": "core",
"approvedBy": "formfit-glyph-widths",
"rationale": "FormFit glyph widths beyond measure._GLYPHS: per face, the design advance of each glyph of the KS X 1001 symbols, the full-width forms and eight common Unicode blocks, read from the font files, and the face Hancom lays a glyph out from when a face lacks it. Data only; imports nothing."
},
{
"path": "src/hwpx/layout/body_scene.py",
"disposition": "core",
"approvedBy": "native-preview/PR-467",
"rationale": "Experimental format-native paragraph reflow and page geometry with injected glyph metrics; no font discovery, rasterizer, worker or host workflow."
},
{
"path": "src/hwpx/layout/object_scene.py",
"disposition": "core",
"approvedBy": "native-preview/PR-467",
"rationale": "Experimental format-native table, picture and page-story geometry composed with the body scene; image inspection and glyph metrics are injected by the application."
}
],
"removed": [
Expand Down
6 changes: 3 additions & 3 deletions docs/coverage-ledger.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"corpusOnly": 38,
"corpusObserved": 229,
"codeRead": 266,
"codeWriteApi": 208,
"codeWriteFrozenTemplate": 11,
"codeWriteApi": 209,
"codeWriteFrozenTemplate": 10,
"codeWriteNone": 126,
"capabilityMapped": 111,
"renderVerified": 132,
Expand Down Expand Up @@ -4100,7 +4100,7 @@
"corpusFrequency": 0.8987,
"corpusFileCount": 213,
"codeRead": true,
"codeWrite": "frozen-template",
"codeWrite": "api",
"capabilityArea": "문단·표 저작/편집",
"capabilityStatus": "Parse·Preserve·Edit·Create·Render-verified",
"verificationBasis": "by-capability-area",
Expand Down
9 changes: 4 additions & 5 deletions docs/coverage-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
**5) 속성 축.** 요소별 관측 속성 **이름** 집합을 census가 함께 기록한다(`observedAttributes` 컬럼, 값 빈도까지는 이번 사이클 범위 밖 — 생성기 독스트링에 명시).
**6) openrate 코퍼스 환류(v4~v21).** `docs/openrate/report-v{4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21}.json`의 스트라타별 실한컴 수용(`render_checked>0`·`render_failed==0`, 구세대 스키마는 `opened==requested>0`도 함께)을 `verificationBasis`로 환류한다(`by-openrate-corpus`/`by-capability-area+openrate-corpus`) — 2026-08-04 감사 R4가 지목한 v4 배선(원 이름 `by-v4-corpus`)을 2026-08 사이클 6.5 트레인⑰에서 v8까지, 사이클 6.6 트레인⑳에서 v9까지, 사이클 6.7 트레인㉔에서 v10까지 확장하며 버전-중립 이름으로 바꿨다. 두 경로로 매핑한다: 이미 등록된 capabilityArea와 1:1 대응하는 스트라타는 `_OPENRATE_STRATUM_TO_CAPABILITY_AREA`(차트·체크박스·수식·각주 2종·테두리채우기·하이라이트·메모·그룹컨테이너·문서옵션호환성), capabilityArea가 아직 없거나 있어도 혼합 지원 영역이라 요소만 지목해야 하는 신규 능력(글꼴·탭·도형텍스트·캡션·쪽번호제어·문자서식·필드파라미터·arc/polygon·인라인 원자 3종)은 `_OPENRATE_STRATUM_TO_ELEMENTS`로 요소를 직접 지목한다 — 둘 다 근거는 각 생성기 스크립트 독스트링이 실제로 부른다고 명시하는 것뿐(무근거 매핑 금지, `fieldBegin`을 일부러 안 매핑한 것과 같은 원칙).

**전 vs 후 (감사가 하한을 인용한 것과 같은 슬라이스 — corpusFileCount>0인 요소만)**: 감사 인용 하한은 관측 228건 중 write=none **70** · read=none **56** · frozen-template **28**([감사 판정문](2026-08-04-completeness-audit-verdict.md) 요약표). 이 원장 재생성 기준으로는 관측 229건 중 write=none **21** · read=none **2** · frozen-template **11**. **주의**: 두 population이 다르다(모집단을 재정의했다 — 위 4항목) — 이 비교는 "같은 잣대로 다시 잰 정확한 델타"가 아니라 분류기 수리가 방향대로 움직였는지의 참고 신호다. 분류기 수리 자체의 정확도 증거는 위 1~3항의 요소별 재현 로그가 1차 근거다.
**전 vs 후 (감사가 하한을 인용한 것과 같은 슬라이스 — corpusFileCount>0인 요소만)**: 감사 인용 하한은 관측 228건 중 write=none **70** · read=none **56** · frozen-template **28**([감사 판정문](2026-08-04-completeness-audit-verdict.md) 요약표). 이 원장 재생성 기준으로는 관측 229건 중 write=none **21** · read=none **2** · frozen-template **10**. **주의**: 두 population이 다르다(모집단을 재정의했다 — 위 4항목) — 이 비교는 "같은 잣대로 다시 잰 정확한 델타"가 아니라 분류기 수리가 방향대로 움직였는지의 참고 신호다. 분류기 수리 자체의 정확도 증거는 위 1~3항의 요소별 재현 로그가 1차 근거다.

## 전체 통계

Expand All @@ -29,8 +29,8 @@
| 코퍼스에만 있음(스키마 미대응) | 38 | 11.0% |
| 실코퍼스에서 관측(빈도>0) | 229 | 66.4% |
| 코드 읽기 | 266 | 77.1% |
| 코드 쓰기(api) | 208 | 60.3% |
| 쓰기 frozen-template | 11 | 3.2% |
| 코드 쓰기(api) | 209 | 60.6% |
| 쓰기 frozen-template | 10 | 2.9% |
| 쓰기 none | 126 | 36.5% |
| 능력 영역 매핑됨 | 111 | 32.2% |
| Render-verified(매핑 근거) | 132 | 38.3% |
Expand Down Expand Up @@ -60,7 +60,6 @@
| `hc:right` | 1.0000 | 237 | True | frozen-template | — |
| `hh:head` | 1.0000 | 237 | True | frozen-template | — |
| `hh:typeInfo` | 0.9747 | 231 | True | frozen-template | — |
| `hp:lineseg` | 0.8987 | 213 | True | frozen-template | 문단·표 저작/편집 |
| `hh:metaTag` | 0.0422 | 10 | True | frozen-template | — |
| `hh:forbiddenWord` | 0.0127 | 3 | True | none | — |
| `hh:forbiddenWordList` | 0.0127 | 3 | True | none | — |
Expand Down Expand Up @@ -93,7 +92,7 @@
| `hh` | 126 | 125 | 64 | 72 | 63 | 3 | 60 |
| `hhs` | 10 | 10 | 0 | 10 | 0 | 0 | 10 |
| `hm` | 2 | 2 | 0 | 2 | 0 | 0 | 2 |
| `hp` | 171 | 161 | 132 | 146 | 120 | 1 | 50 |
| `hp` | 171 | 161 | 132 | 146 | 121 | 0 | 50 |
| `hs` | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
| `hv` | 2 | 1 | 1 | 2 | 1 | 0 | 1 |

Expand Down
28 changes: 28 additions & 0 deletions docs/native-preview-scenes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Experimental preview scenes

`hwpx.layout.body_scene` and `hwpx.layout.object_scene` produce an experimental,
cache-independent page scene from HWPX bytes. A caller supplies glyph metrics;
core does not discover fonts, rasterize images, start workers or load an office
application. No native rendering dependency is added to the default install.

`build_body_scene(data, provider)` handles the bounded body slice.
`build_document_scene(data, provider)` also handles supported tables, pictures
and page stories. `BodySceneSession(provider)` can reuse owned paragraph
measurements across edits; returned scenes are detached from its cache.

The provider implements `shape(text, attributes, style)` and `manifest()`.
Page-number stories additionally use `font_metrics(family, height)`, and pictures
use `inspect_picture(raw_bytes)`. Font metrics and picture decoding belong to the
application layer. Missing fonts and unsupported controls must produce an
unsupported result with no partial pages. Requested font substitutions remain an
explicit application decision.

Coordinates use HWPUNIT. The returned dictionary includes `status`, `pages`,
`unsupported`, `errors`, source/layout hashes and `qualityValidated=False`.
Saved line-segment arrays and cell sub-list measurements are excluded before
measurement. The `ignore`, `remove` and `poison` cache modes support metamorphic
testing; none authorizes using source layout caches as measurements.

This is a versioned experimental scene format, not a fidelity guarantee or a
replacement for an independent office-rendering oracle. Unsupported layout
policies fail closed. The existing HTML preview and save-gate APIs are unchanged.
2 changes: 1 addition & 1 deletion docs/python-example-ledger.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"fenceCount": 115,
"sourceSha256": "b924d97f4a04691b26d3098514b1e2db25faac02715aa9646fedc91ca5182444",
"manualSha256": {
"README.md": "d6d08f94d81e4b7634c80d6738b933050e4ad7e466c1036d68649839760bacf3",
"README.md": "55067f4daa444dd2bbd7a142296933512af3ebdd1636b40c1337661888a25ca7",
"README_EN.md": "da40f5ba537c1d2b05c5afdedc097f6c8effbf6e2b3b8fcb26e2bf5712d098a0",
"docs/quickstart.md": "44d8ca82ee70c0e3dfdf087713a4e4ce935e64cd3f6a546311f95b054a285a18",
"docs/recipes-traversal.md": "b63f42b1a6ed23812688599474dcf83300509b86a94b5daceae679bfdbde9343",
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ python_version = "3.10"
follow_imports = "skip"
files = [
"src/hwpx/document.py",
"src/hwpx/layout/body_scene.py",
"src/hwpx/layout/object_scene.py",
"src/hwpx/errors.py",
"src/hwpx/mutation_report.py",
"src/hwpx/capabilities.py",
Expand Down Expand Up @@ -365,6 +367,8 @@ ignore_missing_imports = true
# both central facades and every extracted/touched runtime owner to the gate.
include = [
"src/hwpx/document.py",
"src/hwpx/layout/body_scene.py",
"src/hwpx/layout/object_scene.py",
"src/hwpx/errors.py",
"src/hwpx/mutation_report.py",
"src/hwpx/capabilities.py",
Expand Down
Loading
Loading