[태그:] Input validation

  • What if your app submits before you finish composing Korean text?

    A checking method, and why measurement never started

    Can an app distinguish Enter pressed to finish composing Korean text from Enter pressed to send it? Does a “20-character” limit keep accents and emoji intact? We prepared a test form to examine these questions, but no measured test run took place. We had no verified route through a real Korean input method, and the tool intended to run completed-string checks did not pass its final checks for stopping and cleaning up after a problem. This article explains what we designed the checks to establish, what the preparation verified, and why we stopped. A record template at the end shows what to check yourself.

    In this article

    Finishing a character is not the same as sending

    Composition means assembling text through an input method before finalizing it. According to the documents checked on October 13, 2026, the contents of the field can change during composition. Finalizing the text being composed and asking the app to save it are separate actions. The browser's “composing now” indicator, isComposing, marks that interval, but the documentation says boundary key-press notifications (keydown) can fall outside it. Checking that indicator alone does not establish correct behavior. This preparation did not observe event order in the installed browsers. W3C UI Events, MDN keydown guide

    We defined this form's behavior as follows: Enter used to finalize composition must not save. Once composition has ended, another Enter or a press of Save must save input of 1–20 clusters once per explicit submission in an independent trial. A 21-cluster input must save nothing even on the second Enter. This is a product rule chosen for this app, not a universal requirement for every text field. It also differs from expecting one Enter to finalize and send together. Checking the Save button cannot establish the behavior of the second Enter.

    Checking this requires a record of keystrokes passing through the real OS input method, the input method selected at the time, the composing state, and the app's event trace. Pasting a completed sentence or generating composition events in code does not test real Korean composition. During this preparation, no human operator was available to perform the input, and the automation had not established that its input passed through the real OS input method. Whether the form distinguishes finalizing composition from submission therefore remains unanswered.

    The original plan covered Safari and Chrome on one Mac, with real composition limited to six inputs: precomposed 가 and 각, each repeated 19, 20, or 21 times. The procedure was to leave the last character composing, press Enter to finalize it, and press Enter again after 500 ms. It does not represent fast typing or all input methods. Korean 2-Set appeared in the input-source preferences; its actual selection and use were not established. Neither browser was measured. Decomposed Hangul, accents, and emoji belonged to the completed-string check below.

    What counts as a “character”, and is the text kept exactly?

    Length limits raise a different question. In the documentation checked on the same date, HTML's maxlength counts UTF-16 code units. These need not correspond to what a reader perceives as a single character. For example, the prepared corpus treats e plus a combining acute accent as one cluster, but the pair occupies two UTF-16 units. MDN maxlength reference

    Here, we define the limit in extended grapheme clusters: units formed by grouping characters according to rules. They approximate perceived characters, but do not always mean one visual shape or the same screen width. Intl.Segmenter provides segmentation at this granularity. Older browsers need an availability check first. Having that capability is separate from confirming that a particular browser produces the expected boundaries. Unicode text segmentation rules, Intl.Segmenter reference

    The corpus contains 30 synthetic strings: ten base strings, including Latin text, precomposed and decomposed Hangul, combining accents, and emoji, each repeated to make 19, 20, or 21 clusters. The corpus does not cover empty input, lengths 1–18, or mixtures of different kinds of clusters. The rule is to save the 19- and 20-cluster strings unchanged once per explicit submission. A 21-cluster string must not be saved, but must remain fully available for editing with an explanation of the rejection. Cutting off the excess does not count as success.

    “Unchanged” is not judged by appearance alone. The design compares arrays of code points (the numbers identifying characters) and UTF-16 units before delivery, after delivery, and after saving. Precomposed and decomposed Hangul can look the same while using different internal representations. Finalizing composition differs from normalization, which puts the text's representation into a specified form; our rule permits neither automatic normalization nor whitespace trimming. Storage here means records held in page memory. The design does not test a database or persistence after a reload.

    We designed the completed-string check as an app-logic simulation: inserting values through code and separately invoking the Save button or sending code-generated Enter events. This check was NOT RUN. It cannot verify real keyboard default submission or OS composition. The maxlength rules also distinguish script-set values from user edits, so code insertion cannot substitute for a real-paste check. We also planned a real-paste diagnostic in a separate maxlength field, but did not run it because there was no verified route for capturing the delivered string.

    What the preparation checks established

    On October 14, 2026, we created the form code, the 30-string manifest, reference data specifying expected saved values and boundaries, and an event recorder. Seven initial preparation tests of the core input logic and recorder passed without a browser. They were not measurements of saving in a real browser. Later checks deliberately introduced faults, such as duplicate saves and truncation of rejected text, to see whether the verifier detected them. These were checks of the testing tools, not defects discovered in the actual form or measured effects of a repair.

    The October 17 independent review recorded no disagreements when comparing code-point and UTF-16 arrays and grapheme boundaries for 90 text representations—the 30 originals and 60 normalization reference variants—with a separate calculation. That calculation used Python UCD 13.0.0 and explicit boundary rules limited to this corpus. It does not mean originals and normalized variants were identical to each other. Node reported Unicode 17.0 data; the cited Unicode 18 rules explain the intended standard, not a certification of this calculation. Agreement on this finite corpus cannot certify full Unicode 18 conformance or browser behavior.

    We also checked the test machine in preparation for local testing without outside requests. On October 17, four socket-address binds and four connection attempts were denied with permission errors under the OS-level network restriction. That finding is limited to those eight attempts. Chrome's preparation check also failed. The later coordinator record attributed this to failure of Chrome's internal sandbox to initialize under the outer restriction. This was not a Korean-input failure. We then prepared an alternative that retained Chrome's own sandbox and used browser settings to restrict external communication. The record judged this weaker than OS-level enforcement by design. That difference was not measured, and the follow-up test-machine check was never performed.

    Why we stopped despite passing tests

    The checking tool must track work it starts, such as a browser, and be able to stop and clean it up after a problem. The October 26 review found that this runner treated a failed process-status inspection as evidence that the process was absent. After a repair, an independent review used a mock check to confirm that this case returned failure without sending termination signals or deleting anything. The preparation tools also passed 40 tests, but those passes did not resolve the cleanup defect below.

    A new defect nevertheless remained. If writing the ownership record failed immediately after starting a child process, one path made no attempt to terminate or wait for that process. A mock check that deliberately caused the record write to fail exposed the problem. This was not an observation of an actual leaked process.

    We applied a rule we had set in advance: stop if the final review still did not clear the runner for execution. We did not continue with another repair even though some time remained. The plan allowed a before-and-after form repair comparison only if a measured form defect was found. None was established; the runner repair above is separate. Completed-string measurements, real Korean-composition measurements, the paste diagnostic, and before-and-after form repair comparisons were all NOT RUN. Passing test counts cannot be converted into an app success rate, and there is no conclusion that one browser or repair approach is better than another.

    What to record when checking your own field

    The following is a record template for a local test form. Use only synthetic text on a page that sends nothing outside and stores records only in page memory. Limit key capture to the test field, and do not copy real personal text into the worksheet. Filling in the template does not itself prove the input route; leave items you cannot verify as “unknown.” Start with what is visible: the number of saved records, retained text, and rejection explanation. Checking composition state or internal values requires tools such as event logs.

    Table 1 · What to record when checking your own field
    What to record Questions to answer
    Environment and action
    Which OS, browser, and input method? Was the input typed, pasted, or inserted through code?
    Composition and submission
    How many saves occurred before and after the Enter that finalizes composition, and before and after the next Enter? Do those counts match the expected counts?
    Length and preservation
    What unit defines the limit? Just below, at, and above the limit (19, 20, and 21 here), do the saved string and the editable value left after rejection match the original? Is the rejection explained?
    Evidence for the judgment
    Can you connect the actual action, composing state, and save record? Does the text merely look the same while its internal value remains unknown?

    Distinguish checks that were not executed (NOT RUN), attempted checks with compromised input provenance or records (INVALID), and valid checks that violated the declared contract (FAIL). Keep NOT RUN and INVALID entries in the record; do not remove them to manufacture a success rate. Agreement on length cannot stand in for a real-composition check. First write down the intended Enter behavior and counting unit, then check save counts and exact text separately. This preparation provides a method and its limits, not measured evidence that the form works correctly.

    AI assisted with research and drafting. The author reviewed the final manuscript and directed the revisions.