Explaining an input failure did not require sending the whole manuscript and screen. The stage and structure of a blocked control can provide narrower clues. Starting from my browser's structural diagnostics, I made an independent report builder that does not accept unrestricted content fields.

This does not redact arbitrary logs

The example does not accept log strings or HTML and automatically identify sensitive fragments. It defines a new strict structure. Adding message, url, path or account to an event, or raw value/name/placeholder to a node, is rejected. It does not silently remove a few fields and call the remainder safe.

Stage, function alias and error code come from fixed teaching vocabularies, without original paths or task IDs. Reducing accepted fields is not a guarantee that every resulting publication is safe. A live integration still needs a trusted supply boundary and final editorial review. Safe_to_publish_verified always remains False rather than treating schema validation as publication certification.

Retain only small structural control descriptions

A node accepts an enumerated tag, editability, label-presence flag, dimensions and ancestor visible/hidden/inert booleans. A label existing differs from sending its text. At most six ancestors and eight nodes are accepted. A caller-declared sensitive node is excluded, retaining only the exclusion count.

Dimensions are checked as bounded integers, quantized to eight-pixel steps and clipped at 4096. That is an independent example choice, not an exact copy of original measurements. Structure itself can reveal information, so quantization is not described as complete anonymity. The code also does not discover real password or OTP controls; sensitivity is a caller declaration.

Do not assume the original surrounding envelope is public-safe

The original fixed probeInput reads structure from actual input nodes without returning values, text or accessibility names. It excludes password and sensitive-autocomplete controls and nodes from another document. That narrow function's scope can be inspected in source and tests.

However, the surrounding ControlProbe frames include origin, while the wider RepairDiagnostic can contain URL and message. Inferring that the whole original diagnostic is publishable because one node function omits raw text would be wrong. This module therefore does not accept that envelope wholesale. Structural collection, private investigation and public editing retain separate boundaries.

Explore the implementation

Complete independent synthetic implementation

"""Strict structural synthetic reports, not arbitrary-log redaction or repair."""
from copy import deepcopy

STAGES={'lookup':'resolve_target','prepare':'prepare_input','dispatch':'send_native_input','verify':'verify_input'}
CODES={'TARGET_MISSING','INPUT_UNSUPPORTED','TARGET_COVERED','DOCUMENT_CHANGED','OUTCOME_UNKNOWN','INPUT_MISMATCH','CONTEXT_LIMIT'}
NODE_KEYS={'tag','editable','width','height','label_present','sensitive','parents'}


def exact(value,keys):
    if type(value) is not dict or set(value)!=set(keys):raise ValueError('EXACT_STRUCTURAL_FIELDS_REQUIRED')


def boolean(value):
    if type(value) is not bool:raise ValueError('BOOLEAN_REQUIRED')
    return value


def dimension(value):
    if type(value) is not int or not 0<=value<=32768:raise ValueError('DIMENSION_INVALID')
    return min(4096,((value+4)//8)*8)


def node(raw):
    exact(raw,NODE_KEYS)
    if raw['tag'] not in ('input','textarea','div','select','button'):raise ValueError('TAG_NOT_ALLOWED')
    for key in ('editable','label_present','sensitive'):boolean(raw[key])
    width,height=dimension(raw['width']),dimension(raw['height'])
    parents=raw['parents']
    if type(parents) is not list or len(parents)>6:raise ValueError('PARENT_LIMIT')
    clean=[]
    for p in parents:
        exact(p,{'visible','hidden','inert'})
        clean.append({k:boolean(p[k]) for k in ('visible','hidden','inert')})
    if raw['sensitive']:return None
    return {'tag':raw['tag'],'editable':raw['editable'],'width':width,'height':height,
            'label_present':raw['label_present'],'parents':clean}


def report(raw):
    exact(raw,{'stage','code','function','outcome_uncertain','nodes'})
    stage=raw['stage']
    if type(stage) is not str or stage not in STAGES or raw['function']!=STAGES[stage]:raise ValueError('STAGE_FUNCTION_INVALID')
    if type(raw['code']) is not str or raw['code'] not in CODES:raise ValueError('ERROR_CODE_NOT_ALLOWED')
    boolean(raw['outcome_uncertain'])
    if type(raw['nodes']) is not list or len(raw['nodes'])>8:raise ValueError('NODE_LIMIT')
    converted=[node(n) for n in raw['nodes']]
    return {'stage':stage,'code':raw['code'],'function':raw['function'],'outcome_uncertain':raw['outcome_uncertain'],
            'nodes':[n for n in converted if n is not None],'excluded_sensitive_nodes':sum(n is None for n in converted),
            'automatic_replay':False,'source_fix_verified':False}


def bundle(events):
    if type(events) is not list or not 1<=len(events)<=20:raise ValueError('EVENT_LIMIT')
    reports=[report(e) for e in events]
    return {'version':1,'reports':deepcopy(reports),'events':len(reports),
            'stage_counts':{s:sum(r['stage']==s for r in reports) for s in STAGES},
            'safe_to_publish_verified':False,'scope_identity_authenticated':False,
            'automatic_replay':False,'arbitrary_log_redaction':False}

Classification must not become replay permission

Reports retain teaching stages such as lookup/prepare/dispatch/verify, an error code and outcome uncertainty. A function alias must match its stage; an arbitrary sentence cannot be inserted as a function name. Stage counts describe reported events, not successfully verified features.

Recording OUTCOME_UNKNOWN makes no server readback or resubmission happen. Automatic_replay and source_fix_verified stay False. Original internal self-repair is retired history, not a capability restored by this package. Output fields make clear that more detailed diagnostics do not themselves authorize a source change or another external action.

Thirty-two tests include rejected data

Tests reject raw-content fields and arbitrary error/function/tag strings, string values masquerading as booleans, and excessive ancestor/node/event counts. They check sensitive-node omission, dimension quantization and detached output. Another case ensures that a rejection message does not echo the sensitive string supplied in the invalid input.

Thirty-two tests run against independent source and again after ZIP extraction. Five records come from actual local function calls; the selector reads those results. No customer log collection or original browser diagnostic was executed. Synthetic inputs and the precise verification scope remain explicit, rather than inheriting credibility from unrelated original product tests.

A read-only viewer of synthetic local records

Sharing requires a clearer input boundary

Code, tests, record generation and documentation permit modification and reuse. Operations still need a trusted connection to actual observations and event ownership, followed by a decision about disclosure. The package implements no identity authentication, persistent journal, DOM probe, repair patch or model call.

Passing an unrestricted raw log into this function is invalid input, not a supported redaction workflow. Useful diagnosis starts by identifying the structure needed to explain an error rather than collecting everything. I share the investigation principle through a small public contract whose limitations remain as visible as its accepted fields.

Download code, tests and records
Python standard library, synthetic data, modification and reuse permitted