"""Targeted native Markdown/edit/split/browser check through physical QMP input.

The guest exports fixed read-only state and model diagnostics. No guest code,
DOM, memory, source file, or host-browser screenshot is injected. The browser
secure-refusal check deliberately does not qualify Bing or CSS parity.
"""
import hashlib
import json
from pathlib import Path
import re
import time

from PIL import Image
from TestWebsiteDocument import (RENDER_FRAMES, paint_evidence, wait_document,
                                 wait_document_presented_frame)


MODEL = re.compile(r'XFE_MONACO_VALUE_BEGIN\r?\n(.*?)\r?\nXFE_MONACO_VALUE_END', re.S)
BROWSER_STATE = re.compile(r'XFE_BROWSER_STATE_BEGIN\r?\n(\d+)\|([^\r\n]+)\r?\n'
                           r'(.*?)\r?\nXFE_BROWSER_STATE_END', re.S)
CORE_BEGIN = 'XFE_BROWSER_SCRIPT_BEGIN|0.52.2/Core/EditorCore.js|'
CORE_END = 'XFE_BROWSER_SCRIPT_END|0.52.2/Core/EditorCore.js|'
FAILURES = ('CPU EXCEPTION:', '[FAILFAST]', '*** UNHANDLED EXCEPTION',
            'XFE_RUNTIME_OOM|', 'XFE_RUNTIME_STACK_OOM|')
DOCUMENT_PATH = 'X:\\Users\\Default\\Documents\\Readme.md'
INITIAL_SOURCE = ('# XFESystem Markdown\n\n**Website renderer** is active.\n\n'
                  '- C# desktop\n- JavaScript preview\n')


def reading_progress_pixels(frame, viewport, scale):
    """Measure the real dark-theme purple/cyan 3 CSS px bar, never DOM width."""
    image = frame.convert('RGB')
    vx, vy, width, _ = viewport
    left, top, right = round(vx * scale), round(vy * scale), round((vx + width) * scale)
    expected_height = round(3 * scale)

    def colored(pixel):
        r, g, b = pixel
        return 60 <= r <= 195 and 130 <= g <= 240 and b >= 200 and b >= r + 20 and b >= g + 8

    row = top + expected_height // 2
    columns = [x for x in range(left, right) if colored(image.getpixel((x, row)))]
    if not columns:
        return {'Passed': False, 'Reason': 'No actual purple/cyan progress fill at the pane top',
                'Viewport': viewport, 'NativeTop': top, 'NativeExpectedHeight': expected_height}
    end = max(columns) + 1
    colored_rows = []
    for y in range(max(0, top - round(2 * scale)), min(image.height, top + round(7 * scale))):
        matches = sum(colored(image.getpixel((x, y))) for x in range(left, end))
        if matches >= max(3, len(columns) * .8): colored_rows.append(y)
    inset = max(1, round(scale))
    early_x = left + min(max(inset, (end - left) // 10), end - left - 1)
    late_x = max(left, end - max(inset + 1, (end - left) // 10))
    early, late = image.getpixel((early_x, row)), image.getpixel((late_x, row))
    rows_pinned = colored_rows and min(colored_rows) == top and max(colored_rows) == top + expected_height - 1
    contiguous = len(columns) >= (end - left) - max(2, round(2 * scale)) and min(columns) <= left + 1
    gradient = early[0] > late[0] + 30 and late[1] > early[1] + 20
    return {'Passed': bool(rows_pinned and contiguous and gradient), 'Viewport': viewport,
            'NativeBounds': [left, top, end, top + expected_height], 'NativeTrackWidth': right - left,
            'NativeFillWidth': end - left, 'FillFraction': (end - left) / (right - left),
            'NativeColoredRows': colored_rows, 'NativeExpectedHeight': expected_height,
            'PinnedToPaneTop': bool(rows_pinned), 'ContiguousFill': contiguous,
            'PurpleToCyanGradient': gradient, 'StartSampleRgb': list(early), 'EndSampleRgb': list(late),
            'Meaning': 'Measured gradient pixels in the original PNG; no DOM width, synthetic pixels or host screenshot substitution.'}


def flat_article_pixels(frame, proof, viewport, scale):
    """Check layout has no outer border inset and empty edge pixels are flat."""
    image = frame.convert('RGB')
    vx, vy, width, height = viewport
    article = proof['Article']['Bounds']
    host_style = any(url.endswith('/css/docs/xfesystem-desktop.css') for url in proof['Styles'])
    samples = []
    for y in (8, 40, 80, 120):
        if y >= height: continue
        reference = image.getpixel((round((vx + 10) * scale), round((vy + y) * scale)))
        for x in (0, 1, 3):
            pixel = image.getpixel((round((vx + x) * scale), round((vy + y) * scale)))
            samples.append({'CssPosition': [x, y], 'Rgb': list(pixel), 'FlatReferenceRgb': list(reference),
                            'MatchesFlatSurface': max(abs(a - b) for a, b in zip(pixel, reference)) <= 1})
    no_border_inset = abs(article['X']) < .01 and abs(article['Width'] - width) < .01
    return {'Passed': host_style and no_border_inset and bool(samples) and all(item['MatchesFlatSurface'] for item in samples),
            'HostOverrideLoaded': host_style, 'NoOuterBorderInset': no_border_inset,
            'ArticleClientBounds': article, 'Samples': samples,
            'Meaning': 'The explicit flat host stylesheet is loaded, article fills the pane without border inset, and native edge/corner samples match its flat surface.'}


def seeded_document_order():
    """Check the source-bound pristine RAM seed, then verify the clicked path in guest diagnostics."""
    root = Path(__file__).resolve().parents[1]
    names = set()
    hashes = {}
    for relative in ('Source/XFESystem.Core/MemoryWorkspace.cs', 'Source/XFESystem.Kernel/Kernel.cs'):
        payload = (root / relative).read_bytes()
        hashes[relative] = hashlib.sha256(payload).hexdigest()
        names.update(re.findall(r'WriteText\(SystemPaths\.Combine\(SystemPaths\.Documents,\s*"([^"\r\n]+)"\)', payload.decode('utf-8-sig')))
    ordered = sorted(names, key=str.casefold)
    assert ordered == ['Hello.cs', 'Hello.js', 'Readme.md', 'WebsiteParity.md', 'ZCSharp.cs'], ordered
    return {'Names': ordered, 'MarkdownRowIndex': ordered.index('Readme.md'), 'LongMarkdownRowIndex': ordered.index('WebsiteParity.md'), 'SeedSourceSha256': hashes,
            'Meaning': 'Pristine RAM seed order from source-bound image; the actual row click must separately report the exact guest path.'}


def run_desktop_documents(qmp, read_log, wait_log, screenshot, width, height, scale, pointer, desktop_snapshots):
    started = time.monotonic()
    result = {'Kind': 'NativeDesktopMarkdownModesAndSecureBrowserFailure', 'Passed': False,
              'AllUserRequirementsMet': False, 'BingCssParityPassed': False, 'BingHomepageLoaded': False,
              'GpuExecutionClaimed': False, 'HostJavaScriptInjection': False, 'PhysicalHardwareAcceptance': False,
              'Input': 'Actual QMP keyboard/mouse packets only', 'Actions': [], 'ShortcutSamples': [],
              'MaximumShortcutResponseSeconds': 1.0, 'Images': [], 'Seed': seeded_document_order()}
    first_image = Path(screenshot('DesktopDocuments-Before'))
    output = first_image.parent / 'DesktopDocuments.json'

    def persist():
        result['ElapsedHostSeconds'] = time.monotonic() - started
        output.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding='utf-8')

    def safe():
        log = read_log()
        assert not any(marker in log for marker in FAILURES), log[-6000:]
        return log

    def phase(name):
        result['CurrentPhase'] = name
        result['Actions'].append({'Action': name, 'HostSeconds': time.monotonic() - started})
        safe(); persist()

    def move(x, y):
        target = [round(x * scale), round(y * scale)]
        while pointer != target:
            dx = max(-80, min(80, target[0] - pointer[0]))
            dy = max(-80, min(80, target[1] - pointer[1]))
            qmp('input-send-event', {'events': [{'type': 'rel', 'data': {'axis': 'x', 'value': dx}},
                                               {'type': 'rel', 'data': {'axis': 'y', 'value': dy}}]})
            pointer[0] += dx; pointer[1] += dy
            time.sleep(.012)

    def click(x, y):
        move(x, y)
        qmp('input-send-event', {'events': [{'type': 'btn', 'data': {'down': True, 'button': 'left'}}]})
        time.sleep(.06)
        qmp('input-send-event', {'events': [{'type': 'btn', 'data': {'down': False, 'button': 'left'}}]})

    def key(code):
        keys = code.split('-')
        qmp('input-send-event', {'events': [{'type': 'key', 'data': {'down': True,
            'key': {'type': 'qcode', 'data': value}}} for value in keys]})
        time.sleep(.04)
        qmp('input-send-event', {'events': [{'type': 'key', 'data': {'down': False,
            'key': {'type': 'qcode', 'data': value}}} for value in reversed(keys)]})
        time.sleep(.06)

    def type_text(value):
        for character in value:
            code = {' ': 'spc', '\n': 'ret'}.get(character, character)
            assert re.fullmatch(r'[a-z0-9]|spc|ret', code), character
            key(code)

    def wait_state(after, predicate, timeout=45):
        deadline = time.monotonic() + timeout
        last = None
        while time.monotonic() < deadline:
            states = desktop_snapshots(safe()[after:])
            if states:
                last = dict(states[-1], SerialOffset=after + states[-1]['SerialOffset'])
                if predicate(last): return last
            time.sleep(.025)
        raise AssertionError(('No complete corresponding desktop state', last, safe()[-4000:]))

    def current_state():
        states = desktop_snapshots(safe())
        assert states, 'No sealed native desktop state'
        return states[-1]

    def same_editor(editor_id, files_id):
        state = current_state()
        assert state['ActiveId'] == editor_id and {key: value['Application'] for key, value in state['Windows'].items()} == {files_id: 'Files', editor_id: 'Editor'}, state
        return state['Windows'][editor_id]['Bounds']

    def wait_model(after, expected, timeout=150):
        deadline = time.monotonic() + timeout
        latest = None
        while time.monotonic() < deadline:
            for match in reversed(list(MODEL.finditer(safe(), after))):
                latest = match.group(1).replace('\r', '')
                if latest == expected:
                    return {'SerialOffset': match.start(), 'Characters': len(expected),
                            'Utf8Sha256': hashlib.sha256(expected.encode('utf-8')).hexdigest(),
                            'ExactModelReadback': True, 'Readback': 'Actual worker-owned Monaco getValue snapshot'}
            time.sleep(.05)
        raise AssertionError(('Actual Monaco source mismatch', expected, latest))

    def model_kind(after, window_id, kind):
        expression = re.compile(r'^XFE_EDITOR_BACKGROUND\|WorkBegin\|Window\|' + str(window_id) +
            r'\|Generation\|\d+\|UiThread\|(\d+)\|Thread\|(\d+)\|Kind\|' + kind + r'\|[^\r\n]*\r?\n', re.M)
        matches = list(expression.finditer(safe(), after))
        assert matches and all(match[1] != match[2] for match in matches), ('No independently owned background page', kind)
        return [{'UiThread': int(match[1]), 'WorkerThread': int(match[2]), 'SerialOffset': match.start()} for match in matches]

    def pane_viewport(bounds, split=False):
        x, y, w, h = bounds
        if not split: return [x + 2, y + 67, w - 4, h - 96]
        left = (w - 8) // 2
        return [x + 2 + left + 4, y + 67, w - 4 - left - 4, h - 96]

    def record_image(path, extra=None):
        image = {'Path': str(path), 'Sha256': hashlib.sha256(path.read_bytes()).hexdigest()}
        if extra: image.update(extra)
        result['Images'].append(image)
        return image

    def capture_preview(tag, after, bounds, split=False, expected_text=None):
        viewport = pane_viewport(bounds, split)
        proof = wait_document(safe, after, lambda item: (item.get('Heading') or {}).get('Text') == 'XFESystem Markdown' and
            (expected_text is None or expected_text in item.get('BodyText', '')) and
            item['Article']['Bounds']['Width'] <= viewport[2] + 1, timeout=150)
        assert 'Readme.md' in proof['Title'], ('Preview evidence belongs to another file', proof['Title'])
        frames = RENDER_FRAMES.findall(safe()[:after])
        presented = {}
        wait_document_presented_frame(safe, after, proof, int(frames[-1]) if frames else 0, presented, timeout=60)
        move(width / scale - 80, height / scale - 90)
        deadline = time.monotonic() + 45
        attempt = 0
        while True:
            attempt += 1
            path = Path(screenshot(tag if attempt == 1 else tag + '-Retry' + str(attempt)))
            with Image.open(path) as image:
                assert image.size == (width, height)
                pixels = paint_evidence(image, proof, viewport, scale, require_heading=True)
                progress = reading_progress_pixels(image, viewport, scale)
                flat = flat_article_pixels(image, proof, viewport, scale)
            if pixels['Passed'] and progress['Passed'] and flat['Passed']:
                record_image(path, {'PreviewViewport': viewport, 'ActualHeadingPixels': pixels, 'ReadingProgressPixels': progress, 'FlatArticlePixels': flat})
                return {'Document': proof, 'Presentation': presented, 'Screenshot': str(path), 'PixelEvidence': pixels,
                        'ReadingProgressPixels': progress, 'FlatArticlePixels': flat, 'IntentionalFlatHostOverride': True}
            assert attempt < 4 and time.monotonic() < deadline, ('No matching native document pixels', pixels, progress, flat)
            time.sleep(.25)

    def capture_long_progress(tag, after, bounds, previous=None):
        viewport = pane_viewport(bounds)
        proof = wait_document(safe, after, lambda item: item.get('Title', '').endswith('WebsiteParity.md') and
            (item.get('Heading') or {}).get('Text') == 'XFESystem 文档预览' and
            '图表组件加载失败' in (item.get('MermaidState') or {}).get('Text', '') and
            (previous is None or item['Article']['Bounds']['Y'] < previous['Document']['Article']['Bounds']['Y'] - 30), timeout=150)
        assert proof['Theme'] == 'dark', 'The native pixel classifier requires the actual default dark theme'
        frames = RENDER_FRAMES.findall(safe()[:after]); presented = {}
        wait_document_presented_frame(safe, after, proof, int(frames[-1]) if frames else 0, presented, timeout=60)
        move(width / scale - 80, height / scale - 90)
        attempts = []
        for attempt in range(1, 5):
            path = Path(screenshot(tag if attempt == 1 else tag + '-Retry' + str(attempt)))
            with Image.open(path) as image:
                progress = reading_progress_pixels(image, viewport, scale)
                flat = flat_article_pixels(image, proof, viewport, scale)
            grew = previous is None or progress.get('NativeFillWidth', 0) >= previous['ReadingProgressPixels']['NativeFillWidth'] + round(8 * scale)
            attempts.append({'Screenshot': str(path), 'Progress': progress, 'Flat': flat, 'GrewFromBeforeWheel': grew})
            if progress['Passed'] and flat['Passed'] and grew:
                record_image(path, {'ReadingProgressPixels': progress, 'FlatArticlePixels': flat})
                return {'Document': proof, 'Presentation': presented, 'Screenshot': str(path), 'ReadingProgressPixels': progress,
                        'FlatArticlePixels': flat, 'Attempts': attempts}
            if attempt != 4: time.sleep(.25)
        raise AssertionError(('The real long-document progress pixels did not advance after physical scrolling', attempts))

    def shortcut_during_core(after, expected_id):
        before = time.monotonic(); key('meta_l-d')
        state = wait_state(after, lambda value: value['ActiveId'] == expected_id, timeout=10)
        elapsed = time.monotonic() - before
        core_end = safe().find(CORE_END, result['CoreScriptBeginSerialOffset'])
        sample = {'Shortcut': 'Win+D', 'ExpectedActiveWindowId': expected_id,
                  'HostInputToAcknowledgementSeconds': elapsed, 'UnderOneSecond': elapsed < 1,
                  'AcknowledgementSerialOffset': state['SerialOffset'],
                  'AcknowledgedBeforeCoreScriptEnd': core_end < 0 or state['SerialOffset'] < core_end}
        result['ShortcutSamples'].append(sample); persist()
        assert sample['UnderOneSecond'], ('Desktop shortcut was blocked during editor loading', sample)
        return sample

    try:
        phase('OpenSeededMarkdownInDefaultPreview')
        assert not current_state()['Windows'], 'This targeted profile requires a fresh desktop'
        offset = len(safe()); key('meta_l-e')
        files = wait_state(offset, lambda value: value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Files')
        files_id = files['ActiveId']; fx, fy, _, _ = files['Windows'][files_id]['Bounds']
        record_image(Path(screenshot('DesktopDocuments-Files')))
        opened = len(safe())
        click(fx + 70, fy + 110 + result['Seed']['MarkdownRowIndex'] * 28)
        state = wait_state(opened, lambda value: len(value['Windows']) == 2 and value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Editor')
        editor_id = state['ActiveId']; bounds = same_editor(editor_id, files_id)
        wait_log('XFE_BROWSER_STATE_BEGIN\n' + str(editor_id) + '|' + DOCUMENT_PATH, opened, 90)
        result['DefaultPreview'] = capture_preview('DesktopDocuments-DefaultPreview', opened, bounds)
        result['DefaultPreview']['BackgroundOwners'] = model_kind(opened, editor_id, 'Document')
        assert CORE_BEGIN not in safe()[opened:], 'Opening Markdown default preview unexpectedly initialized Monaco'
        assert not list(MODEL.finditer(safe(), opened)), 'Default preview unexpectedly exposed an editor model'
        result['DefaultPreview'].update({'EditorWindowId': editor_id, 'SameEditorWindow': True, 'MonacoInitializedBeforeEdit': False,
                                        'ExactGuestPathObserved': DOCUMENT_PATH})

        phase('EditLoadsMonacoWhileDesktopRemainsResponsive')
        edit_start = len(safe()); click(bounds[0] + bounds[2] - 50, bounds[1] + 49)
        wait_log(CORE_BEGIN, edit_start, 150)
        result['CoreScriptBeginSerialOffset'] = safe().index(CORE_BEGIN, edit_start)
        hidden = shortcut_during_core(len(safe()), 0)
        record_image(Path(screenshot('DesktopDocuments-EditorLoading-Hidden')))
        shortcut_during_core(len(safe()), editor_id)
        assert hidden['AcknowledgedBeforeCoreScriptEnd'], 'No hide acknowledgement overlapped actual Monaco core execution'
        wait_log('XFE_EDITOR_BACKGROUND|Ready|Window|' + str(editor_id) + '|', edit_start, 150)
        result['EditModel'] = wait_model(edit_start, INITIAL_SOURCE)
        result['EditModel'].update({'BackgroundOwners': model_kind(edit_start, editor_id, 'Editor'),
            'PlainTextLanguage': 'Verified by production ReadyEditorLayout plaintext gate; no C# color proof is claimed'})
        bounds = same_editor(editor_id, files_id)
        record_image(Path(screenshot('DesktopDocuments-Edit')))

        phase('SplitHasTwoPanesAndPreviewFollowsUnsavedEdits')
        split_start = len(safe()); click(bounds[0] + bounds[2] - 148, bounds[1] + 49)
        result['SplitInitial'] = capture_preview('DesktopDocuments-Split', split_start, bounds, split=True)
        same_editor(editor_id, files_id)
        sx, sy, _, _ = bounds
        click(sx + 100, sy + 170)
        edit_start = len(safe()); key('ctrl-end')
        suffix = '\n\nnative split preview'
        type_text(suffix)
        expected = INITIAL_SOURCE + suffix
        result['SplitEditedModel'] = wait_model(edit_start, expected)
        result['SplitEditedPreview'] = capture_preview('DesktopDocuments-SplitEdited', edit_start, bounds, split=True, expected_text='native split preview')
        same_editor(editor_id, files_id)
        save_start = len(safe()); key('ctrl-s')
        wait_log('XFE_DESKTOP_SAVED|' + DOCUMENT_PATH + '|' + str(len(expected)) + '\n', save_start, 90)
        result['Saved'] = {'Path': DOCUMENT_PATH, 'Characters': len(expected), 'SerialOffset': save_start,
                           'Persistence': 'RAM session only; no reboot or physical-storage claim'}

        phase('ReopenSavedMarkdownDefaultsToPreviewWithUpdatedContent')
        close_start = len(safe()); key('alt-f4')
        wait_state(close_start, lambda value: value['ActiveId'] == files_id and len(value['Windows']) == 1)
        reopen_start = len(safe()); click(fx + 70, fy + 110 + result['Seed']['MarkdownRowIndex'] * 28)
        state = wait_state(reopen_start, lambda value: len(value['Windows']) == 2 and value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Editor')
        reopened_id = state['ActiveId']; reopened_bounds = state['Windows'][reopened_id]['Bounds']
        result['ReopenedPreview'] = capture_preview('DesktopDocuments-Reopened', reopen_start, reopened_bounds, expected_text='native split preview')
        assert CORE_BEGIN not in safe()[reopen_start:], 'Reopened Markdown preview unexpectedly initialized Monaco'
        close_start = len(safe()); key('alt-f4')
        wait_state(close_start, lambda value: value['ActiveId'] == files_id and len(value['Windows']) == 1)

        phase('LongMarkdownReadingProgressTracksActualWheelScroll')
        long_start = len(safe()); click(fx + 70, fy + 110 + result['Seed']['LongMarkdownRowIndex'] * 28)
        state = wait_state(long_start, lambda value: len(value['Windows']) == 2 and value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Editor')
        long_id = state['ActiveId']; long_bounds = same_editor(long_id, files_id)
        wait_log('XFE_BROWSER_STATE_BEGIN\n' + str(long_id) + '|X:\\Users\\Default\\Documents\\WebsiteParity.md', long_start, 90)
        before_progress = capture_long_progress('DesktopDocuments-LongProgress-BeforeWheel', long_start, long_bounds)
        assert before_progress['ReadingProgressPixels']['FillFraction'] < .9, 'The long fixture must begin with reading remaining'
        viewport = pane_viewport(long_bounds)
        move(viewport[0] + 8, viewport[1] + min(180, viewport[3] / 2))
        wheel_start = len(safe())
        for _ in range(6):
            qmp('input-send-event', {'events': [{'type': 'btn', 'data': {'down': True, 'button': 'wheel-down'}}]})
            time.sleep(.05)
            qmp('input-send-event', {'events': [{'type': 'btn', 'data': {'down': False, 'button': 'wheel-down'}}]})
            time.sleep(.1)
        after_progress = capture_long_progress('DesktopDocuments-LongProgress-AfterWheel', wheel_start, long_bounds, previous=before_progress)
        result['LongDocumentProgress'] = {'Passed': True, 'WindowId': long_id, 'PhysicalWheelSteps': 6,
            'Before': before_progress, 'After': after_progress,
            'NativeFillWidthIncrease': after_progress['ReadingProgressPixels']['NativeFillWidth'] - before_progress['ReadingProgressPixels']['NativeFillWidth'],
            'Meaning': 'Same document/pane, real scroll moves article geometry upward while the fixed 3 CSS px gradient remains at pane top and visibly fills farther.'}
        def rejected_large_dependency(after):
            activity = safe()[after:]
            rejected = [line for line in activity.splitlines() if line.startswith('XFE_BROWSER_SCRIPT_REJECTED|') and
                        'mermaid.min.js' in line and '|Reason|ResourceBudget' in line]
            assert rejected, 'The native resource admission did not explicitly reject the oversized diagram dependency'
            assert not any(line.startswith('XFE_BROWSER_SCRIPT_BEGIN|') and 'mermaid.min.js' in line
                           for line in activity.splitlines()), 'The oversized diagram dependency reached AST evaluation'
            return {'RejectedBeforeEvaluation': True, 'Diagnostics': rejected,
                    'DiagramRenderingSupported': False, 'OriginalSourceFallbackVisible': True}
        result['NativeLargeDependency'] = rejected_large_dependency(long_start)
        same_editor(long_id, files_id)
        close_start = len(safe()); key('alt-f4')
        wait_state(close_start, lambda value: value['ActiveId'] == files_id and len(value['Windows']) == 1)

        phase('RepeatBudgetedLongPreviewAndRealEditSavePreview')
        result['RepeatedDocumentCycles'] = []
        for cycle in range(1, 3):
            cycle_start = len(safe()); click(fx + 70, fy + 110 + result['Seed']['LongMarkdownRowIndex'] * 28)
            state = wait_state(cycle_start, lambda value: len(value['Windows']) == 2 and value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Editor')
            cycle_id = state['ActiveId']; cycle_bounds = same_editor(cycle_id, files_id)
            long_preview = capture_long_progress('DesktopDocuments-Repeat' + str(cycle) + '-LongPreview', cycle_start, cycle_bounds)
            budget = rejected_large_dependency(cycle_start)
            close_start = len(safe()); key('alt-f4')
            wait_state(close_start, lambda value: value['ActiveId'] == files_id and len(value['Windows']) == 1)

            readme_start = len(safe()); click(fx + 70, fy + 110 + result['Seed']['MarkdownRowIndex'] * 28)
            state = wait_state(readme_start, lambda value: len(value['Windows']) == 2 and value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Editor')
            repeat_id = state['ActiveId']; repeat_bounds = same_editor(repeat_id, files_id)
            capture_preview('DesktopDocuments-Repeat' + str(cycle) + '-Readme', readme_start, repeat_bounds, expected_text='native split preview')
            edit_start = len(safe()); click(repeat_bounds[0] + repeat_bounds[2] - 50, repeat_bounds[1] + 49)
            wait_log('XFE_EDITOR_BACKGROUND|Ready|Window|' + str(repeat_id) + '|', edit_start, 150)
            wait_model(edit_start, expected)
            click(repeat_bounds[0] + 100, repeat_bounds[1] + 170)
            edit_start = len(safe()); key('ctrl-end')
            addition = '\n\nnative reopen ' + str(cycle)
            type_text(addition); expected += addition
            edited_model = wait_model(edit_start, expected)
            save_start = len(safe()); key('ctrl-s')
            wait_log('XFE_DESKTOP_SAVED|' + DOCUMENT_PATH + '|' + str(len(expected)) + '\n', save_start, 90)
            preview_start = len(safe()); click(repeat_bounds[0] + repeat_bounds[2] - 50, repeat_bounds[1] + 49)
            updated = capture_preview('DesktopDocuments-Repeat' + str(cycle) + '-SavedPreview', preview_start, repeat_bounds,
                                      expected_text='native reopen ' + str(cycle))
            close_start = len(safe()); key('alt-f4')
            wait_state(close_start, lambda value: value['ActiveId'] == files_id and len(value['Windows']) == 1)
            result['RepeatedDocumentCycles'].append({'Cycle': cycle, 'LongPreview': long_preview, 'ResourceBudget': budget,
                'EditedModel': edited_model, 'SavedCharacters': len(expected), 'SavedPreview': updated, 'Passed': True})
            persist()

        phase('DefaultBingAddressFailsSecurelyAndDoesNotClaimCssParity')
        hide_start = len(safe()); key('meta_l-d')
        wait_state(hide_start, lambda value: value['ActiveId'] == 0)
        work_height = height / scale - 48
        if work_height >= 554: icon_y = 84 + 2 * 94 + 37
        else:
            icon_height = max(40, min(74, int((work_height - 80) / 5)))
            gap = max(4, min(12, int((work_height - 32 - icon_height * 5) / 4)))
            icon_y = 16 + 2 * (icon_height + gap) + icon_height / 2
        browser_start = len(safe()); click(65, icon_y)
        state = wait_state(browser_start, lambda value: value['Windows'].get(value['ActiveId'], {}).get('Application') == 'Browser')
        browser_id = state['ActiveId']
        deadline = time.monotonic() + 90; actual = None
        while time.monotonic() < deadline:
            for match in reversed(list(BROWSER_STATE.finditer(safe(), browser_start))):
                if int(match[1]) == browser_id and match[2] == 'https://www.bing.com/' and 'HTTPS' in match[3] and 'TLS' in match[3]:
                    actual = {'WindowId': browser_id, 'Address': match[2], 'Text': match[3], 'SerialOffset': match.start()}; break
            if actual is not None: break
            time.sleep(.05)
        assert actual is not None, 'The real default Bing URL did not show an explicit native HTTPS/TLS refusal'
        model_kind(browser_start, browser_id, 'Navigation')
        frames = RENDER_FRAMES.findall(safe()); baseline_frames = int(frames[-1]) if frames else 0
        move(width / scale - 80, height / scale - 90)
        deadline = time.monotonic() + 30
        while True:
            reports = RENDER_FRAMES.findall(safe())
            if reports and int(reports[-1]) > baseline_frames: break
            assert time.monotonic() < deadline, 'No completed browser error frame'; time.sleep(.05)
        path = Path(screenshot('DesktopDocuments-BingSecureFailure'))
        record_image(path)
        result['Bing'] = {**actual, 'DefaultAddressPassed': True, 'ExpectedSecureRefusalObserved': True,
            'HomepageLoaded': False, 'CssParityPassed': False, 'WindowsBrowserComparisonPassed': False,
            'Screenshot': str(path), 'RequirementMet': False,
            'Meaning': 'The guest lacks verified native TLS. This verifies truthful visible failure only, never Bing rendering or CSS parity.'}
        result['Passed'] = True
        result['TargetedDesktopChecksPassed'] = True
        result['Meaning'] = 'Targeted Markdown modes, real edit/save/preview and secure browser failure passed. Bing, hardware, GPU and complete-release acceptance remain outside this result.'
        phase('Complete')
        return result
    except Exception as error:
        result['Failure'] = str(error); result['Passed'] = False
        persist(); raise
