Skip to content

feat(hangul): import and edit HWP/HWPX documents #319

Description

@seonghobae

Current authoritative state

The HWP/HWPX feature is implemented on the existing canonical single-writer Draft PR #320 / branch feat/hwp-hwpx-authoring. Protected shipped truth remains exact main@3b38ead2d00f44eb578d0689087b9293b3dabe1e; current exact Draft head is 5ee6e4d0c3b2a804f39a8d186a8bdd7c2a38a782, with PR base metadata aligned to that protected tip. GitHub reports the Draft mechanically mergeable; mergeability is not authorization.

Inkspan owns the bounded deterministic HWP/HWPX byte/JSON bridge, local conversion rules, deterministic frozen capability metadata, payload-redacted diagnostics, resource validation, cleanup containment, and committed synthetic fixture contracts. The host injects and owns HangulDocumentEngine and retains filesystem/network/WASM initialization, transport, auth, tenancy, persistence, credentials, model policy, deployment and durable-audit authority. Standalone Inkspan requires no service, DB, credential, network or model.

Implemented active-PR contract

  • open HWP/HWPX through host-owned engine capability and project the supported structural subset into framework-neutral editor JSON;
  • export edited JSON as HWPX by default or legacy HWP explicitly;
  • preserve paragraphs, headings, alignment, bold/italic/strike, structural lists, block quotes, code blocks and basic table topology;
  • fail closed on unsupported structures rather than silently discarding them;
  • enforce source/output byte ceilings and genuine Uint8Array snapshots;
  • reject host structural metadata above 4,096 sections, 1,000,000 paragraphs per section, or 16,777,216 UTF-16 code units per paragraph before traversal, host indexing, selection, deletion, or paste mutation (fix(reliability): validate Hangul engine structural counts before traversal #367);
  • treat those values as Inkspan safety/resource ceilings, not HWP/HWPX format maxima;
  • contain hostile option access (fix(reliability): redact hostile Hangul option access failures #366) and cleanup failures (fix(reliability): contain Hangul engine cleanup failures #365) without reflecting unknown thrown values;
  • validate host-returned source format / selection HTML as strings before member access or coercion;
  • expose one frozen deterministic capabilities object instead of forcing hosts to infer support from failures;
  • verify synthetic known-document HWPX/HWP fixtures and semantic reopen/round-trip behavior without customer documents.

docs/HANGUL.md, ADR 0030, and src/hangul/documentationContract.test.ts on the active branch bind the finite traversal ceilings and authority boundary into both human-readable and machine-checkable contracts. Active-PR documentation is not protected-main shipped truth.

Test-first lineage

  • deterministic capability metadata RED 59740977d26beadb5ef61cdd83990749e0616b31 failed typecheck because the required capabilities surface did not exist; GREEN e389742f85a2916241198af4676510f431207cdb adds the frozen capability object;
  • cleanup RED 4481666a6bbddb467ac0d9318c45d3b37a411cad -> GREEN 521900fde4347bc8b9cb4b966d7f1a930e9c7155;
  • hostile-option RED 907b088a77a6c0324b2907cba13235da8d508e58 -> GREEN 0786240d8e30e66effd8326fad3d5d67af427f4d;
  • structural-metadata REDs 6610482f5c9456274befe43dfde024da6975220d, c5615c9b28b741343fc234599a662eb117e50e7b, and f99891581dcdaae37bd8ccbf5136785f461af086 establish malformed host metadata rejection and stable traversal bounds;
  • resource-bound RED 030512a5496c8fa869fc0cb1c79724334d6919b1, exact-checkout CI 32394561877, build/test job 96508269729, typechecked and then exhausted the Node/Vitest heap near 4 GiB while exercising forged enormous metadata. That non-passing run proves safe-integer validation alone did not bound work;
  • narrow source repair 88936bd85345ec81daba1eaa497ed21418ce6dab applies the finite section/paragraph/paragraph-length ceilings before child traversal or host mutation;
  • dcefbe6d40bacc66e2b04dc85b68a04dca37d013, 487e6cb172454e6c0d90a7ecce3838ec068eefc3, and current 5ee6e4d0c3b2a804f39a8d186a8bdd7c2a38a782 converge executable documentation, docs/HANGUL.md, and ADR 0030 on those exact ceilings;
  • non-string engine-text RED 642ec3c1aef0d9b12441909ef253658c9526fecd -> GREEN 7c79ade8e6f00d47fcd2039412aebda67a01d364 (replayed on the synchronized branch as 38e0ff0);
  • committed known-document fixtures remain fail-closed and semantically reopenable on the current branch.

Exact-current-head evidence

For unchanged head 5ee6e4d0c3b2a804f39a8d186a8bdd7c2a38a782 against protected base 3b38ead2d00f44eb578d0689087b9293b3dabe1e at the latest fresh refetch:

  • CI 32395091285: completed / success;
  • build-and-test 96510085342: exact-current-head checkout, 161 test files / 898 tests, 100% statements / branches / functions / lines, packed-package verification, library build and demo build all successful;
  • Office Python 3.11-3.14 jobs: completed / success with dependency, coverage, docstring, wheel, schema and license gates;
  • Cross-engine Clipboard / Playwright job: completed / success;
  • Security Scan 32395091192: completed / success;
  • SAST Semgrep 32395091052: completed / success;
  • qualifying approving latest-push review remains absent.

All observed repository-owned exact-head workflows are terminal success; the absent qualifying latest-push approval remains non-passing. Predecessor evidence does not transfer. Any head/base movement invalidates this exact-current classification.

Integration boundary

The feature is active-PR truth only and is not protected-main shipped behavior. Keep #320 Draft/unmerged while #118 owns the exact v0.6.0 release/publication boundary. Before any lifecycle transition refetch exact head/live base, ancestry, rules/permissions, reviews/threads and every applicable repository/central workflow. Do not create a competing Hangul writer, transfer predecessor evidence, self-approve, weaken gates, move protected main or fabricate release identity.

Close this issue only after #320 integrates under live governance and the resulting protected-main generation proves the feature on that exact integrated head.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: dependenciesDependency or lockfile maintenancearea: securitySecurity boundary, hardening, or vulnerability preventionpriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capability

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions