Repository navigation
fix(accessibility): validate editor language tags before emitting lang #233
Description
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
languageTagwas emitted instead of rejected. - Test-only
64e46d780cd25bbcc9b821470b641f48820b7e63proved the firstIntl.getCanonicalLocales()remedy was too narrow; hosted CI31534174592failed the RFC 5646 preservation regressions forx-private,i-klingon, andzh-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 Scan32322070146, and SAST Semgrep32322070224. Predecessor evidence does not transfer.
Acceptance
- Reject malformed bounded runtime language tags with the stable payload-redacted local error contract while preserving blank-as-absent behavior.
- 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.
- Preserve the caller's accepted trimmed spelling rather than silently canonicalizing it.
- Do not infer language, normalize aliases/case, echo rejected values, or add model/network/runtime-registry dependencies. Registry-content validity remains host policy.
- Preserve accessibility metadata bounds, accessible-name precedence, direction and ARIA state behavior.
- Maintain exact owned-production coverage and all applicable package/browser/Office/security gates on the eventual integration head.
- 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.
Activity