Skip to content

LF-single-node script corruption in Virgin.root (embedded LF, zero CR); webBrowser.openURL root cause, #855 unblocker #881

Closed

Description

@jsavin

Rationale

LF-single-node script corruption in Virgin.root — a THIRD stored-damage mechanism, distinct from #866's scanner bug and #877's stale DB. Signature: entire script body crammed into ONE outline node with embedded LF (0x0A) bytes and zero CR — a .ut import path that skipped LF→CR normalization. This is the ROOT CAUSE of #865's webBrowser.openURL failure. Repair is cheap and proven: reinstall once via script.newScriptObject (which does LF→CR normalization first-thing) repairs both affected scripts, persists across fileMenu.save + fresh process, verified behaviorally. Works on pre-#866-fix binaries too (no #866 dependency). This is the #855 unblocker.

Current State

LF-node corruption identified (2026-08-10):

  • Entire script body in ONE outline node with embedded LF (0x0A) bytes
  • Zero CR bytes (native UserTalk line ending is CR 0x0D)
  • Signature of .ut import that skipped LF→CR normalization

Confirmed victims:

  1. system.verbs.builtins.webBrowser.openURL (1 node, 26 LF) — THIS IS webBrowser.openUrl fails to compile headless; blocks first-run finishInstall flow #865's root cause
  2. string.isValidUrl (1 node, 15 LF)

Repair verification (proven, 2026-08-10):

Impact:

Desired Outcome

  1. Repair the 2 known LF-node scripts (openURL, isValidUrl) via script.newScriptObject
  2. Scan Virgin.root corpus for stored-node-text-containing-LF to size the class beyond 2 known
  3. Identify provenance (which import path skipped LF→CR normalization)
  4. Update webBrowser.openUrl fails to compile headless; blocks first-run finishInstall flow #865 to reflect actual root cause (LF corruption, not missing headless implementation)
  5. Unblock Virgin.root ships firstRootRun=false, breaking firstRootRun contract; 9 integration tests depend on skipped init #855 (first-run flow can proceed after repair + flag flip)

Recommendation

Immediate (dispatchable now, no #866 dependency):

For each of webBrowser.openURL and string.isValidUrl:
1. Read current script via protocol: string(@system.verbs.builtins.webBrowser.openURL)
2. Reinstall via script.newScriptObject (normalizes LF→CR automatically)
3. Verify: script compiles in place, behaviorally correct (e.g., isValidUrl("foo@bar.com") returns true)
4. Persist via fileMenu.save

Follow-up:

  1. Corpus-wide scan for stored-node-text-containing-LF
  2. Identify count and names of all affected scripts
  3. Batch repair via script.newScriptObject
  4. Investigate provenance (trace which import caused LF→CR skip)

Exit Criteria

Related Context

Distinct from Other Issues

Methodology Note

The cheap repair (script.newScriptObject does LF→CR normalization automatically) proves the issue: if reinstall fixes it, the damage is in the stored bytes, not in the code path. Behavioral verification (isValidUrl returns correct result) proves the fix is functional, not just syntactic.

Activity

  1. added
    priority/p1High priority - address soon
    scope/medium1-2 weeks, requires design work
    type/bugDefect in existing functionality, needs fix
    on Aug 11, 2026
  2. jsavin commented on Aug 11, 2026

    @jsavin
    OwnerAuthor

    C-Level Mechanism Proven (#881 LF Corruption Deep Dive):

    Root cause chain:

    1. op.insert routes through isoutlinetext() (Common/source/opstructure.c:2685)
    2. isoutlinetext() decides split-vs-flat by searching ONLY for CR (textpatternmatch on chreturn)
    3. LF-only text looks "flat" → lands in ONE node with literal \n embedded
    4. Result: webBrowser.openURL (26 LF), string.isValidUrl (15 LF)

    Damage window (bootstrap ordering trap):

    Frozen since birth: Both victims carry identical md5 since creation (never re-normalized after the C-layer fix).

    Corpus scan complete (3,499 script+outline values on current Virgin.root):

    • Exactly 2 values carry embedded LF (fully enumerated, nothing hidden)
    • This damage class is closed

    METHODOLOGY WARNING for repair/verification (burned three scans):

    • string(adr^) deref form FAILS on LF-single-node scripts
    • try/else silently yields "" on these scripts (sweep under-reports the damage it hunts)
    • Use the indexed form: string(table^[name]) instead
    • Validate any scanner against known positive (isValidUrl → 15 LF) before trusting zero
    • Also: string.mid(s, k, sizeof(s)) overruns — use sizeof(s)-k+1

    Repair confirmed working: script.newScriptObject normalizes LF→CR automatically (C-layer fix via PR #542 now active).

  3. added a commit that references this issue on Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority/p1High priority - address soonscope/medium1-2 weeks, requires design worktype/bugDefect in existing functionality, needs fixworkstream/database-architectureDatabase format, migration, serialization

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions