Skip to content

fix(accessibility): validate editor language tags before emitting lang #233

Description

@seonghobae

Buyer-visible accessibility/data-integrity boundary

Protected main@3b38ead2d00f44eb578d0689087b9293b3dabe1e documents languageTag as BCP 47 metadata, while the historical runtime path trimmed and emitted any in-bound string directly as the editable surface's HTML lang attribute. An untyped/deserialized malformed host value could therefore silently produce invalid language metadata for authored content and assistive technology.

Inkspan owns only validation of its public local attribute contract. Host language choice/localization and registry-content policy remain host-owned; this adds no inference, transport, persistence, credentials, tenancy, model/provider, network, runtime registry, or durable-audit authority.

Standards correction and canonical owner

RFC 5646 Language-Tag includes normal langtag, private-use, and grandfathered syntax. ECMA-402 Intl.getCanonicalLocales() is a narrower locale-processing boundary and rejected valid RFC 5646 forms exercised by this lane, including private-use-only x-private, grandfathered i-klingon, and extlang zh-cmn-Hans-CN. Platform locale canonicalization is therefore not a valid substitute for Inkspan's declared syntax contract.

Draft PR #230 is the sole active writer for src/components/editorAccessibility.ts and focused metadata/runtime tests. At exact head 59d82f8b65cfad5230fa9e11afb97867293a43f5, the branch uses local deterministic RFC 5646 well-formed-syntax validation for the portions that can be decided without an IANA registry snapshot, including private-use-only, grandfathered, permanent extlang position, script/region/variant/extension/private-use sequences, duplicate variants, and duplicate extension singletons. Accepted tags preserve the caller's trimmed spelling; Inkspan does not infer, alias-normalize, case-normalize, or claim registry-content validity.

TDD / exact-current evidence

  • The initial malformed-tag RED established that a non-blank malformed runtime languageTag was emitted instead of rejected.
  • Test-only 64e46d780cd25bbcc9b821470b641f48820b7e63 proved the first Intl.getCanonicalLocales() remedy was too narrow; hosted CI 31534174592 failed the RFC 5646 preservation regressions for x-private, i-klingon, and zh-cmn-Hans-CN.
  • Invalid extlang-position RED lineage is 0551ae31809dc37e146f1bba60bf5d13daf04b60.
  • Exact-current fix(accessibility): harden editor metadata runtime contracts #230 repository workflows are terminal success: CI 32322070195, Security Scan 32322070146, and SAST Semgrep 32322070224. Predecessor evidence does not transfer.

Acceptance

  1. Reject malformed bounded runtime language tags with the stable payload-redacted local error contract while preserving blank-as-absent behavior.
  2. Preserve complete locally decidable RFC 5646 well-formed syntax, including private-use-only, grandfathered, extlang, script/region/variant/extension/private-use sequences; do not substitute narrower ECMA-402 locale grammar.
  3. Preserve the caller's accepted trimmed spelling rather than silently canonicalizing it.
  4. Do not infer language, normalize aliases/case, echo rejected values, or add model/network/runtime-registry dependencies. Registry-content validity remains host policy.
  5. Preserve accessibility metadata bounds, accessible-name precedence, direction and ARIA state behavior.
  6. Maintain exact owned-production coverage and all applicable package/browser/Office/security gates on the eventual integration head.
  7. Close only when canonical fix(accessibility): harden editor metadata runtime contracts #230 integrates into protected main; Draft/head-green evidence is not protected shipped truth.

Integration boundary

Keep #230 Draft/unmerged while #118 freezes protected main for v0.6.0 operational acceptance and while qualifying independent approval plus every then-live merge/review/governance gate remain incomplete. Never transfer predecessor CI/review evidence or create a competing writer for the same source.

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: bugDefect or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions