*! version 1.0.0  20260715  Eric A. Booth, Sr Researcher, Texas 2036
*! reshapehelper: diagnose the data and SUGGEST (never run) the likely reshape
*
*  reshapehelper never reshapes the caller's data.  It scans variable names
*  for wide patterns, hunts for i/j candidates (honoring xtset/tsset and
*  svyset), composes a candidate -reshape- command, and tests it on a small
*  sample inside preserve/restore, iterating on reshape's own errors.  The
*  caller's data are restored untouched; the only side effects are the
*  returned r() results, the $reshapehelper_cmd global, and a viewable SMCL
*  file holding the unwrapped suggestion.

program define reshapehelper, rclass
    version 16.0

    syntax [anything] [, TO(string) I(varlist) J(string) STUBs(string)   ///
        SAMPle(integer 500) NOTESt SMCL(string) REPLACE GLobal(name)     ///
        Detail ]

    * ---- bare-token shorthand: reshapehelper long / reshapehelper wide ------
    local scanvars ""
    if `"`anything'"' != "" {
        local rest `"`anything'"'
        gettoken tk rest : rest
        while "`tk'" != "" {
            capture unab chk : `tk'
            if !_rc local scanvars `scanvars' `chk'
            else if inlist("`tk'", "long", "wide") {
                if "`to'" != "" & "`to'" != "`tk'" {
                    di as err "you typed `tk' but also to(`to'); pick one"
                    exit 198
                }
                local to `tk'
            }
            else {
                di as err "`tk' is neither a variable nor long/wide"
                exit 198
            }
            gettoken tk rest : rest
        }
    }
    if !inlist("`to'", "", "long", "wide") {
        di as err "to() must be long or wide"
        exit 198
    }
    if `sample' < 10 {
        di as err "sample() must be at least 10"
        exit 198
    }
    if "`global'" == "" local global reshapehelper_cmd
    if c(k) == 0 | _N == 0 {
        di as err "no data in memory to diagnose"
        exit 2000
    }
    if `"`smcl'"' != "" {
        if lower(substr(`"`smcl'"', -5, .)) != ".smcl" local smcl `"`smcl'.smcl"'
        if "`replace'" == "" {
            capture confirm new file `"`smcl'"'
            if _rc {
                di as err `"smcl file `smcl' already exists; specify replace"'
                exit 602
            }
        }
    }

    local NFULL = _N
    local KFULL = c(k)

    * =========================================================================
    * 1. Declared structure: xtset/tsset and svyset are the analyst's own
    *    statement of i and j; take them as high-priority candidates.
    * =========================================================================
    local xtpanel ""
    local xttime  ""
    capture quietly xtset
    if _rc == 0 {
        local xtpanel `"`r(panelvar)'"'
        local xttime  `"`r(timevar)'"'
        if `"`xtpanel'"' == "." local xtpanel ""
        if `"`xttime'"'  == "." local xttime  ""
    }
    local svypsu ""
    capture quietly svyset
    if _rc == 0 {
        local svypsu `"`r(su1)'"'
        if `"`svypsu'"' == "." | `"`svypsu'"' == "_n" local svypsu ""
    }

    * =========================================================================
    * 2. Name scans (names only, no data touched).  A varlist restricts which
    *    variables the PATTERN SCAN considers (stub discovery going long, the
    *    measure list going wide); the i/j hunt always sees every variable, so
    *    typing "reshapehelper inc80 inc81" does not hide the id.
    * =========================================================================
    unab allv : _all
    if "`scanvars'" != "" local scanv `scanvars'
    else                  local scanv `allv'

    * ---- 2a. trailing-numeric suffix groups:  inc80 inc81 inc82 -------------
    local nng 0
    foreach v of local scanv {
        if regexm("`v'", "^(.*[^0-9])([0-9]+)$") {
            local s = regexs(1)
            local x = regexs(2)
            local hit 0
            forvalues g = 1/`nng' {
                if "`ng_stub`g''" == "`s'" {
                    local ng_sufs`g' `ng_sufs`g'' `x'
                    local ng_vars`g' `ng_vars`g'' `v'
                    local hit 1
                    continue, break
                }
            }
            if !`hit' {
                local ++nng
                local ng_stub`nng' `s'
                local ng_sufs`nng' `x'
                local ng_vars`nng' `v'
            }
        }
    }
    * keep groups with >= 2 distinct suffixes
    local numgroups ""
    forvalues g = 1/`nng' {
        local u : list uniq ng_sufs`g'
        local nu : word count `u'
        if `nu' >= 2 local numgroups `numgroups' `g'
    }

    * ---- 2b. doubly-wide: two digit runs:  ht_k1_t2 --------------------------
    local ndb 0
    foreach v of local scanv {
        if regexm("`v'", "^(.*[^0-9])([0-9]+)([^0-9]+)([0-9]+)$") {
            local p1 = regexs(1)
            local d1 = regexs(2)
            local md = regexs(3)
            local d2 = regexs(4)
            local hit 0
            forvalues g = 1/`ndb' {
                if "`db_p1`g''" == "`p1'" & "`db_mid`g''" == "`md'" {
                    local db_d1s`g' `db_d1s`g'' `d1'
                    local db_d2s`g' `db_d2s`g'' `d2'
                    local hit 1
                    continue, break
                }
            }
            if !`hit' {
                local ++ndb
                local db_p1`ndb'  `p1'
                local db_mid`ndb' `md'
                local db_d1s`ndb' `d1'
                local db_d2s`ndb' `d2'
            }
        }
    }
    local dblgroups ""
    forvalues g = 1/`ndb' {
        local u1 : list uniq db_d1s`g'
        local u2 : list uniq db_d2s`g'
        if `: word count `u1'' >= 2 & `: word count `u2'' >= 2 {
            local dblgroups `dblgroups' `g'
        }
    }

    * ---- 2c. @ mid-name: digits inside, letters after:  inc80r ---------------
    local nat 0
    foreach v of local scanv {
        if regexm("`v'", "^([a-zA-Z_]+)([0-9]+)([a-zA-Z_]+)$") {
            local pre = regexs(1)
            local dig = regexs(2)
            local suf = regexs(3)
            local hit 0
            forvalues g = 1/`nat' {
                if "`at_pre`g''" == "`pre'" & "`at_suf`g''" == "`suf'" {
                    local at_digs`g' `at_digs`g'' `dig'
                    local hit 1
                    continue, break
                }
            }
            if !`hit' {
                local ++nat
                local at_pre`nat'  `pre'
                local at_suf`nat'  `suf'
                local at_digs`nat' `dig'
            }
        }
    }
    local atgroups ""
    forvalues g = 1/`nat' {
        local u : list uniq at_digs`g'
        if `: word count `u'' >= 2 local atgroups `atgroups' `g'
    }

    * ---- 2d. string suffix after last underscore:  bp_before bp_after --------
    local nsg 0
    foreach v of local scanv {
        if regexm("`v'", "^(.+_)([a-zA-Z][a-zA-Z0-9]*)$") {
            local s = regexs(1)
            local x = regexs(2)
            local hit 0
            forvalues g = 1/`nsg' {
                if "`sg_stub`g''" == "`s'" {
                    local sg_sufs`g' `sg_sufs`g'' `x'
                    local hit 1
                    continue, break
                }
            }
            if !`hit' {
                local ++nsg
                local sg_stub`nsg' `s'
                local sg_sufs`nsg' `x'
            }
        }
    }
    local strgroups ""
    forvalues g = 1/`nsg' {
        local u : list uniq sg_sufs`g'
        if `: word count `u'' >= 2 local strgroups `strgroups' `g'
    }

    * ---- 2e. prefix-as-j: qld_p nsw_p vic_p (the j sits in FRONT) -------------
    *      group by the trailing token; the prefixes are the j values
    local npg 0
    foreach v of local scanv {
        if regexm("`v'", "^([a-zA-Z][a-zA-Z0-9]*)(_[a-zA-Z][a-zA-Z0-9]*)$") {
            local pfx = regexs(1)
            local tail = regexs(2)
            local hit 0
            forvalues g = 1/`npg' {
                if "`pg_tail`g''" == "`tail'" {
                    local pg_pfx`g' `pg_pfx`g'' `pfx'
                    local hit 1
                    continue, break
                }
            }
            if !`hit' {
                local ++npg
                local pg_tail`npg' `tail'
                local pg_pfx`npg' `pfx'
            }
        }
    }
    * conservative: either >=2 tail-groups sharing an identical prefix set, or
    * a single group with >=3 prefixes (first_name/last_name must NOT trigger)
    local pfxgroups ""
    forvalues g = 1/`npg' {
        local u : list uniq pg_pfx`g'
        local nu : word count `u'
        if `nu' >= 3 local pfxgroups `pfxgroups' `g'
        else if `nu' == 2 {
            forvalues h = 1/`npg' {
                if `h' == `g' continue
                local uh : list uniq pg_pfx`h'
                local uh : list sort uh
                local us : list sort u
                local same : list us === uh
                if `same' {
                    local pfxgroups `pfxgroups' `g'
                    continue, break
                }
            }
        }
    }
    local pfxgroups : list uniq pfxgroups

    * a numeric-suffix group beats a string reading of the same variables, and
    * doubly-wide groups subsume their single-run parses; user-supplied
    * stubs() are wide evidence by declaration
    local widejudge = ("`numgroups'`dblgroups'`atgroups'`strgroups'`pfxgroups'" != "") ///
        | ("`stubs'" != "")

    * =========================================================================
    * 3. Value probes on a sample, inside preserve.  BEFORE-snapshot is taken
    *    first, in original row order.  All heavy checks run on the sample.
    * =========================================================================
    preserve
    if _N > `sample' quietly keep in 1/`sample'
    local NS = _N

    * distinct counts for candidate scoring, stored POSITIONALLY (dist1...)
    * and looked up through dvlist with posof: a variable name near Stata's
    * 32-char limit would make a name-keyed local ("dist_<name>") illegal.
    * Skips strL; caps at 80 vars.  A variable absent from dvlist simply has
    * no distinct-count info and drops out of i/j candidacy.
    local dvlist ""
    foreach v of local allv {
        local ty : type `v'
        if "`ty'" == "strL" continue
        if `: word count `dvlist'' >= 80 continue, break
        tempvar f
        quietly bysort `v': gen byte `f' = (_n == 1)
        quietly count if `f'
        local dd = r(N)          // grab r(N) before anything can clear it
        drop `f'
        local dvlist `dvlist' `v'
        local dist`: word count `dvlist'' = `dd'
    }

    * ---- i candidates: unique in sample, or declared, or name-prior ----------
    local icands ""
    if "`i'" != "" local icands `i'
    else {
        if "`xtpanel'" != "" local icands `xtpanel'
        foreach v of local allv {
            local dpos : list posof "`v'" in dvlist
            if `dpos' == 0 continue
            local nm = lower("`v'")
            local prior = regexm("`nm'", "(^|_)(id|code|fips|ssn|key)$|^id|id$|county|state|dist|inst|firm|person|hh|fam|stu|patient")
            if `dist`dpos'' == `NS' local icands `icands' `v'
            else if `prior' local icands `icands' `v'
        }
        if "`svypsu'" != "" local icands `icands' `svypsu'
        local icands : list uniq icands
    }

    * ---- j candidates (for long->wide): low cardinality, time-ish names ------
    local jcands ""
    if "`j'" != "" {
        capture confirm variable `j'
        if !_rc local jcands `j'
    }
    if "`jcands'" == "" {
        if "`xttime'" != "" local jcands `xttime'
        foreach v of local allv {
            local dpos : list posof "`v'" in dvlist
            if `dpos' == 0 continue
            if `dist`dpos'' < 2 continue
            if `dist`dpos'' > min(60, ceil(`NS'/2)) continue
            local nm = lower("`v'")
            if regexm("`nm'", "year|^yr|wave|time|round|visit|period|qtr|quarter|month|week|grade|term|semester|^j$|^t$") {
                local jcands `jcands' `v'
            }
        }
        * fall back: any small-cardinality integer var not already an i cand
        if "`jcands'" == "" {
            foreach v of local allv {
                local dpos : list posof "`v'" in dvlist
                if `dpos' == 0 continue
                if `dist`dpos'' < 2 | `dist`dpos'' > 30 continue
                local isi : list v in icands
                if `isi' continue
                capture confirm numeric variable `v'
                if !_rc {
                    capture assert `v' == int(`v') | missing(`v')
                    if !_rc local jcands `jcands' `v'
                }
                else local jcands `jcands' `v'
            }
        }
        local jcands : list uniq jcands
    }

    * =========================================================================
    * 4. Direction
    * =========================================================================
    local direction ""
    local note ""
    * long evidence: some i+j combo uniquely identifies sample rows.
    * A var that is unique BY ITSELF is skipped as a lone i: in long data the
    * id repeats across j, and widening one-row groups is degenerate.
    * When name-based i candidates fail, fall back to trying other variables,
    * singly and in pairs (this is how a compound i like (animal, arm) or
    * (household, year) gets found without being named id-anything).
    local longi ""
    local longj ""
    * singles pool: named candidates first, then a bounded general fill, so a
    * simple one-variable i is always tried before any pair
    local ipool2 `icands'
    foreach v of local allv {
        if `: word count `ipool2'' >= 12 continue, break
        local in1 : list v in ipool2
        local dpos : list posof "`v'" in dvlist
        if !`in1' & `dpos' > 0 local ipool2 `ipool2' `v'
    }
    local sparsecand ""
    local sparsej ""
    foreach jv of local jcands {
        foreach iv of local ipool2 {
            if "`iv'" == "`jv'" continue
            capture isid `iv' `jv'
            if !_rc {
                * plausibility: in real long data each i repeats across j, so
                * an i with (nearly) one row per value is an accident of the
                * data (auto's weight+mpg), not a design.  Record such a
                * would-be i so the checklist can flag a genuinely sparse panel
                * (most units seen once, a few repeated) rather than stay mute.
                local dpos : list posof "`iv'" in dvlist
                if `dpos' > 0 {
                    if `dist`dpos'' > `NS'/2 {
                        if "`sparsecand'" == "" {
                            local sparsecand `iv'
                            local sparsej `jv'
                        }
                        continue
                    }
                }
                local longi `iv'
                local longj `jv'
                continue, break
            }
        }
        if "`longi'" != "" continue, break
        * pairs: name-based candidates first, then a bounded general pool.
        * A variable that is unique BY ITSELF is barred from pairs: it would
        * make any isid trivially true (the measure would end up inside i).
        local ppool ""
        foreach v of local icands {
            local dpos : list posof "`v'" in dvlist
            if `dpos' == 0 continue
            if `dist`dpos'' < `NS' & "`v'" != "`jv'" local ppool `ppool' `v'
        }
        foreach v of local allv {
            if `: word count `ppool'' >= 6 continue, break
            local in1 : list v in ppool
            if `in1' | "`v'" == "`jv'" continue
            local dpos : list posof "`v'" in dvlist
            if `dpos' == 0 continue
            if `dist`dpos'' < `NS' local ppool `ppool' `v'
        }
        local np : word count `ppool'
        forvalues a = 1/`= min(`np', 6)' {
            forvalues b = `= `a' + 1'/`= min(`np', 6)' {
                local iva : word `a' of `ppool'
                local ivb : word `b' of `ppool'
                capture isid `iva' `ivb' `jv'
                if !_rc {
                    tempvar gg
                    quietly bysort `iva' `ivb': gen byte `gg' = (_n == 1)
                    quietly count if `gg'
                    local ngrp = r(N)
                    drop `gg'
                    if `ngrp' > `NS'/2 continue
                    local longi `iva' `ivb'
                    local longj `jv'
                    continue, break
                }
            }
            if "`longi'" != "" continue, break
        }
        if "`longi'" != "" continue, break
    }
    local longjudge = ("`longi'" != "")

    if "`to'" == "long" {
        if `widejudge' local direction wide2long
        else           local direction none_for_long
    }
    else if "`to'" == "wide" {
        if `longjudge' | "`j'" != ""   local direction long2wide
        else if "`jcands'" != ""       local direction long2wide
        else                           local direction none_for_wide
    }
    else {
        if `widejudge' & "`dblgroups'" != "" local direction doubly
        else if `widejudge'                  local direction wide2long
        else if `longjudge'                  local direction long2wide
        else                                 local direction unknown
    }

    * =========================================================================
    * 5. Compose the candidate command(s)
    * =========================================================================
    local status needinfo
    local cmd ""
    local cmd2 ""
    local preline ""
    local usei ""
    local usej ""
    local usestubs ""
    local tested 0
    local finalrc .
    local resultN .
    local resultK .
    local caution ""
    local diagmsg ""

    * ---------- 5a. WIDE -> LONG ---------------------------------------------
    if "`direction'" == "wide2long" {
        * strongest pattern family: numeric > @ > string suffix > prefix-j
        * (a doubly-wide layout also matches the numeric scan; the single-step
        *  suggestion it yields is the correct FIRST of the two chained steps)
        local family ""
        if "`numgroups'" != ""      local family num
        else if "`atgroups'" != ""  local family at
        else if "`strgroups'" != "" local family str
        else if "`pfxgroups'" != "" local family pfx
        if "`stubs'" != "" local family user

        * stub list + j metadata per family
        local jstring ""
        local sufset ""
        if "`family'" == "num" {
            * merge groups whose suffix sets match, or overlap in >=2 places
            * with one set containing the other (reshape long fills the gaps
            * of an unbalanced stub with missings - manual Example 6)
            local g1 : word 1 of `numgroups'
            local ref : list uniq ng_sufs`g1'
            local ref : list sort ref
            local usestubs "`ng_stub`g1''"
            local stubvars `ng_vars`g1''
            local unbal 0
            foreach g of local numgroups {
                if `g' == `g1' continue
                local u : list uniq ng_sufs`g'
                local u : list sort u
                local same : list ref === u
                local ovl : list ref & u
                local novl : word count `ovl'
                local sub1 : list u in ref
                local sub2 : list ref in u
                if `same' {
                    local usestubs "`usestubs' `ng_stub`g''"
                    local stubvars `stubvars' `ng_vars`g''
                }
                else if `novl' >= 2 & (`sub1' | `sub2') {
                    local usestubs "`usestubs' `ng_stub`g''"
                    local stubvars `stubvars' `ng_vars`g''
                    local unbal 1
                    if `sub2' {
                        local ref : list ref | u
                        local ref : list sort ref
                    }
                }
            }
            local sufset `ref'
            if `unbal' local note "stubs are unbalanced (a stub is missing some suffixes); reshape fills the gaps with missing values"
            * fold in @-groups that share the same suffix set (inc@r beside ue)
            foreach g of local atgroups {
                local u : list uniq at_digs`g'
                local u : list sort u
                local same : list sufset === u
                if `same' {
                    local usestubs "`usestubs' `at_pre`g''@`at_suf`g''"
                    foreach d of local u {
                        local stubvars `stubvars' `at_pre`g''`d'`at_suf`g''
                    }
                }
            }
        }
        else if "`family'" == "at" {
            local g1 : word 1 of `atgroups'
            local usestubs "`at_pre`g1''@`at_suf`g1''"
            local sufset : list uniq at_digs`g1'
            local stubvars ""
            foreach d of local sufset {
                local stubvars `stubvars' `at_pre`g1''`d'`at_suf`g1''
            }
        }
        else if "`family'" == "str" {
            local g1 : word 1 of `strgroups'
            local ref : list uniq sg_sufs`g1'
            local ref : list sort ref
            local usestubs "`sg_stub`g1''"
            foreach g of local strgroups {
                if `g' == `g1' continue
                local u : list uniq sg_sufs`g'
                local u : list sort u
                local same : list ref === u
                if `same' local usestubs "`usestubs' `sg_stub`g''"
            }
            local sufset `ref'
            local jstring " string"
            local stubvars ""
            foreach s of local usestubs {
                foreach x of local sufset {
                    capture confirm variable `s'`x'
                    if !_rc local stubvars `stubvars' `s'`x'
                }
            }
        }
        else if "`family'" == "pfx" {
            * the j values are the PREFIXES; stubs are @tail forms
            local g1 : word 1 of `pfxgroups'
            local usestubs "@`pg_tail`g1''"
            local sufset : list uniq pg_pfx`g1'
            local stubvars ""
            foreach p of local sufset {
                local stubvars `stubvars' `p'`pg_tail`g1''
            }
            foreach g of local pfxgroups {
                if `g' == `g1' continue
                local u : list uniq pg_pfx`g'
                local u : list sort u
                local ref : list sort sufset
                local same : list ref === u
                if `same' {
                    local usestubs "`usestubs' @`pg_tail`g''"
                    foreach p of local u {
                        local stubvars `stubvars' `p'`pg_tail`g''
                    }
                }
            }
            local jstring " string"
        }
        else if "`family'" == "user" {
            local usestubs `stubs'
            local stubvars ""
            foreach s of local stubs {
                local s2 : subinstr local s "@" "*", all
                capture unab got : `s2'*
                if !_rc local stubvars `stubvars' `got'
            }
        }

        * i for wide->long: must uniquely identify rows; exclude stub vars
        local ipool : list icands - stubvars
        if "`xttime'" != "" {
            local intime : list xttime in stubvars
            if !`intime' local ipool `ipool' `xttime'
        }
        local ipool : list uniq ipool
        if "`i'" != "" local usei `i'
        else {
            foreach iv of local ipool {
                capture isid `iv'
                if !_rc {
                    local usei `iv'
                    continue, break
                }
            }
            if "`usei'" == "" {
                local np : word count `ipool'
                forvalues a = 1/`= min(`np', 5)' {
                    forvalues b = `= `a' + 1'/`= min(`np', 5)' {
                        local iva : word `a' of `ipool'
                        local ivb : word `b' of `ipool'
                        capture isid `iva' `ivb'
                        if !_rc {
                            local usei `iva' `ivb'
                            continue, break
                        }
                    }
                    if "`usei'" != "" continue, break
                }
            }
        }
        * wide-long panel note: the row id already includes a time variable
        local nw : word count `usei'
        if `nw' >= 2 {
            foreach iv of local usei {
                if regexm(lower("`iv'"), "year|^yr|wave|time|period|qtr|quarter|month|date") {
                    local note "rows already carry `iv'; this reshape adds a SECOND long dimension"
                }
            }
        }

        * j name: infer, avoid collisions with existing variables
        if "`j'" != "" local usej `j'
        else {
            local usej j
            local all4 1
            local all2 1
            foreach x of local sufset {
                if !regexm("`x'", "^(19|20)[0-9][0-9]$") local all4 0
                if !regexm("`x'", "^[4-9][0-9]$")        local all2 0
            }
            if "`sufset'" == "" {
                local all4 0
                local all2 0
            }
            if (`all4' | `all2') & "`jstring'" == "" local usej year
            else if "`family'" == "pfx"              local usej j
            else if "`jstring'" != ""                local usej period
            foreach cand in `usej' j _j {
                capture confirm variable `cand'
                if _rc {
                    local usej `cand'
                    continue, break
                }
            }
        }
        capture confirm variable `usej'
        if !_rc local usej _j

        * suffix-numbers-may-be-items caution
        if "`jstring'" == "" & "`family'" != "at" {
            local smallsuf 1
            foreach x of local sufset {
                if real("`x'") > 12 local smallsuf 0
            }
            if `smallsuf' & "`sufset'" != "" {
                local caution "suffixes `sufset' could be item numbers rather than repeats over time; confirm these are repeated measures before reshaping"
            }
            * mixed-width suffixes: the manual's inc2-beside-inc80 false match.
            * reshape would happily build a mostly-missing j group; offer the
            * explicit j-value restriction instead of silence
            local lens ""
            foreach x of local sufset {
                local lens `lens' `= strlen("`x'")'
            }
            local lens : list uniq lens
            if `: word count `lens'' >= 2 {
                local caution "suffix widths differ (`sufset'): a stray variable like inc2 beside inc80-inc82 matches the same stub and would create a mostly-missing j group; if any suffix is a false match, restrict j explicitly, e.g. j(`usej' 80 81 82), or rename the stray variable first"
            }
        }

        if "`usei'" != "" & "`usestubs'" != "" {
            local cmd "reshape long `usestubs', i(`usei') j(`usej')`jstring'"
            local status ok
        }
        else if "`usestubs'" != "" {
            local status needinfo
            local diagmsg "wide pattern found (stubs: `usestubs') but no variable or pair uniquely identifies the rows; rerun with i(yourid)"
        }
    }

    * ---------- 5b. DOUBLY WIDE -> LONG-LONG (two chained reshapes) -----------
    if "`direction'" == "doubly" {
        local g1 : word 1 of `dblgroups'
        local p1  `db_p1`g1''
        local md  `db_mid`g1''
        local d1s : list uniq db_d1s`g1'
        local d1s : list sort d1s
        local d2s : list uniq db_d2s`g1'
        * step 1: long over the LAST digit run; one stub per first-index value
        local st1 ""
        foreach d of local d1s {
            local st1 `st1' `p1'`d'`md'
        }
        * i: unique row id
        if "`i'" != "" local usei `i'
        else {
            foreach iv of local icands {
                capture isid `iv'
                if !_rc {
                    local usei `iv'
                    continue, break
                }
            }
        }
        local j2 time
        capture confirm variable `j2'
        if !_rc local j2 _t
        local j1 grp
        capture confirm variable `j1'
        if !_rc local j1 _g
        if "`usei'" != "" {
            local cmd  "reshape long `st1', i(`usei') j(`j2')"
            local cmd2 "reshape long `p1'@`md', i(`usei' `j2') j(`j1')"
            local usestubs "`st1'"
            local usej "`j2' then `j1'"
            local status ok
            local note "doubly wide: two chained reshapes; rename `j1'/`j2' to your real dimensions afterward"
        }
        else {
            local status needinfo
            local diagmsg "doubly-wide pattern found (`p1'#`md'#) but no unique row id; rerun with i(yourid)"
        }
    }

    * ---------- 5c. LONG -> WIDE ----------------------------------------------
    if "`direction'" == "long2wide" {
        if "`j'" != "" {
            capture confirm variable `j'
            if _rc {
                di as err "j(`j') not found: going wide, j() must name an EXISTING variable (going long it names the variable to create)"
                exit 111
            }
            local usej `j'
        }
        else if "`longj'" != "" local usej `longj'
        else local usej : word 1 of `jcands'
        if "`i'" != "" local usei `i'
        else           local usei `longi'
        if "`usei'" == "" & "`usej'" != "" {
            * j is settled but i is not: try named candidates, then a bounded
            * general pool, singly and in pairs
            * pool excludes j and any unique-by-itself variable (a measure
            * with all-distinct values would make isid trivially true)
            local ipool3 ""
            foreach v of local icands {
                if "`v'" == "`usej'" continue
                local dpos : list posof "`v'" in dvlist
                if `dpos' == 0 continue
                if `dist`dpos'' < `NS' local ipool3 `ipool3' `v'
            }
            foreach v of local allv {
                if `: word count `ipool3'' >= 8 continue, break
                local in1 : list v in ipool3
                if `in1' | "`v'" == "`usej'" continue
                local dpos : list posof "`v'" in dvlist
                if `dpos' == 0 continue
                if `dist`dpos'' < `NS' local ipool3 `ipool3' `v'
            }
            foreach iv of local ipool3 {
                capture isid `iv' `usej'
                if !_rc {
                    local dpos : list posof "`iv'" in dvlist
                    if `dpos' > 0 {
                        if `dist`dpos'' > `NS'/2 {
                            if "`sparsecand'" == "" {
                                local sparsecand `iv'
                                local sparsej `usej'
                            }
                            continue
                        }
                    }
                    local usei `iv'
                    continue, break
                }
            }
            if "`usei'" == "" {
                local np : word count `ipool3'
                forvalues a = 1/`= min(`np', 6)' {
                    forvalues b = `= `a' + 1'/`= min(`np', 6)' {
                        local iva : word `a' of `ipool3'
                        local ivb : word `b' of `ipool3'
                        capture isid `iva' `ivb' `usej'
                        if !_rc {
                            tempvar gg
                            quietly bysort `iva' `ivb': gen byte `gg' = (_n == 1)
                            quietly count if `gg'
                            local ngrp = r(N)
                            drop `gg'
                            if `ngrp' > `NS'/2 continue
                            local usei `iva' `ivb'
                            continue, break
                        }
                    }
                    if "`usei'" != "" continue, break
                }
            }
        }

        if "`usei'" != "" & "`usej'" != "" {
            * stubs = variables that VARY within i (across j); constants ride along
            local usestubs ""
            local consts ""
            foreach v of local scanv {
                local ini : list v in usei
                if `ini' | "`v'" == "`usej'" continue
                tempvar w
                capture confirm string variable `v'
                if !_rc quietly bysort `usei' (`v'): gen byte `w' = (`v'[1] != `v'[_N])
                else    quietly bysort `usei' (`v'): gen byte `w' = (`v'[1] != `v'[_N]) & !(missing(`v'[1]) & missing(`v'[_N]))
                quietly count if `w'
                if r(N) > 0 local usestubs `usestubs' `v'
                else        local consts `consts' `v'
                drop `w'
            }
            if "`usestubs'" == "" {
                local status needinfo
                local diagmsg "no variable varies within i(`usei') across j(`usej'); nothing to widen"
            }
            else {
                * string j pre-checks: option string; spaces cleaned first
                local jstring ""
                local badj 0
                capture confirm string variable `usej'
                if !_rc {
                    local jstring " string"
                    quietly count if strpos(`usej', " ") > 0
                    if r(N) > 0 {
                        local preline `"replace `usej' = subinstr(`usej', " ", "_", .)"'
                        quietly replace `usej' = subinstr(`usej', " ", "_", .)
                        local note "j values contained spaces; the first line below cleans them (reshape refuses a string j with spaces)"
                    }
                }
                else {
                    capture assert `usej' == int(`usej') | missing(`usej')
                    if _rc {
                        local badj 1
                        local status needinfo
                        local diagmsg "j candidate `usej' has non-integer values; reshape wide needs an integer or string j"
                    }
                }
                if !`badj' {
                    local cmd "reshape wide `usestubs', i(`usei') j(`usej')`jstring'"
                    local status ok
                    * a COMPOUND i() that still holds a low-cardinality factor
                    * means the data can widen FURTHER (the long-long case).  A
                    * single-variable i() is just the identifier, so the note
                    * must not fire there - it would call the id a "factor".
                    if `: word count `usei'' >= 2 {
                        foreach iv of local usei {
                            local dpos : list posof "`iv'" in dvlist
                            if `dpos' == 0 continue
                            if `dist`dpos'' >= 2 & `dist`dpos'' <= 12 {
                                local note "i() still contains the factor `iv'; this reshape widens one dimension - rerun reshapehelper on the result to widen the next, or fold factors into one j: egen newj = concat(`usej' `iv'), p(_)"
                            }
                        }
                    }
                    * long stub names + suffix may exceed 32 chars.  The j value
                    * is spliced into a string for length only.  It is compound-
                    * quoted and read with -macval- so a value carrying a " does
                    * not unbalance the quotes, and the whole probe is wrapped in
                    * -capture- so an exotic value (a backtick, say) can never
                    * escape to the caller; the caution is advisory, so on any
                    * failure it is simply skipped.
                    local maxlen 0
                    capture {
                        foreach s of local usestubs {
                            quietly levelsof `usej' in 1/`= min(_N, 200)', ///
                                local(jl) clean
                            foreach lv of local jl {
                                if strlen(`"`s'`macval(lv)'"') > 32 local maxlen 1
                            }
                        }
                    }
                    if `maxlen' local caution "some new names (stub+j) would exceed 32 characters; shorten stubs or j values first"
                }
            }
        }
        else if "`usej'" != "" {
            local status needinfo
            * if a candidate DID make i+j unique but was set aside as sparse, the
            * cause is sparseness, not duplicates; the dedicated sparse note (in
            * the checklist) carries the advice, so keep this diagnosis short.
            if "`sparsecand'" != "" {
                local diagmsg "no i() both identifies the rows and repeats enough to widen (see the sparse-units note below)"
            }
            else {
                local topi : word 1 of `icands'
                if "`topi'" != "" & "`topi'" != "`usej'" {
                    tempvar dtag
                    capture duplicates tag `topi' `usej', generate(`dtag')
                    local ndup 0
                    if !_rc {
                        quietly count if `dtag' > 0
                        local ndup = r(N)
                        drop `dtag'
                    }
                    local diagmsg "no i() makes i+j unique with j(`usej'); with i(`topi'), `ndup' of `NS' sample rows share an (i, j) pair. Remedies: duplicates report `topi' `usej' then drop true duplicates; collapse repeated measures; sequence them: bysort `topi' `usej': gen seq = _n and use i(`topi' seq); or fold a second factor into j: egen newj = concat(`usej' otherfactor), p(_) then reshape on j(newj) string"
                }
                else local diagmsg "j(`usej') looks right but no i makes i+j unique; run: duplicates report <yourid> `usej'"
            }
        }
    }

    * ---------- 5d. nothing discernible ---------------------------------------
    if inlist("`direction'", "unknown", "none_for_long", "none_for_wide") {
        local status needinfo
        if "`direction'" == "none_for_long" ///
            local diagmsg "you asked for to(long) but no wide naming pattern (stub+suffix) was found"
        if "`direction'" == "none_for_wide" ///
            local diagmsg "you asked for to(wide) but no i+j combination uniquely identifies the rows"
    }

    * ---------- xpose / sxpose advisory ----------------------------------------
    local xposeflag 0
    if "`status'" == "needinfo" & `NFULL' <= 40 {
        local nstr 0
        local nnum 0
        foreach v of local allv {
            capture confirm string variable `v'
            if !_rc local ++nstr
            else    local ++nnum
        }
        if `nnum' >= 2 & `nstr' <= 1 & "`icands'" == "" local xposeflag 1
        if `nnum' >= 2 & `nstr' == 1 & `NFULL' < `KFULL' local xposeflag 1
    }

    * =========================================================================
    * 6. BEFORE snapshot (original order), then the dry run
    * =========================================================================
    restore, preserve
    if _N > `sample' quietly keep in 1/`sample'

    * pick display vars for the before box
    local shovars ""
    if "`usei'" != "" local shovars `usei'
    if "`direction'" == "long2wide" local shovars `shovars' `usej'
    local nsv : word count `shovars'
    foreach v of local allv {
        if `: word count `shovars'' >= 5 continue, break
        local in1 : list v in shovars
        if !`in1' {
            local instub : list v in stubvars
            if "`direction'" == "long2wide" {
                local instub : list v in usestubs
            }
            if `instub' local shovars `shovars' `v'
        }
    }
    if `: word count `shovars'' < 2 {
        local shovars ""
        local kk 0
        foreach v of local allv {
            local ++kk
            if `kk' > 4 continue, break
            local shovars `shovars' `v'
        }
    }
    _rh_snap, vars(`shovars') rows(3)
    local b_hdr `"`r(hdr)'"'
    local b_n   = r(n)
    forvalues r = 1/`b_n' {
        local b_l`r' `"`r(l`r')'"'
    }
    local b_obs = _N

    * ---- the dry run: run suggestion on the sample, iterate on failures ------
    local a_hdr ""
    local a_n 0
    if "`cmd'" != "" & "`notest'" == "" {
        if `"`preline'"' != "" quietly capture `preline'
        local attempt 0
        local lastrc .
        while `attempt' < 4 {
            local ++attempt
            capture `cmd'
            local lastrc = _rc
            if `lastrc' == 0 continue, break
            * iterate: known fixable failures (rc map verified against Stata:
            * 109 string j w/o -string-; 498 string suffixes read as all-missing
            * j in reshape long; 110 j name already exists; 111 no xij found /
            * string j with spaces; 9 uniqueness & constancy failures)
            if inlist(`lastrc', 109, 498) & strpos("`cmd'", " string") == 0 {
                local cmd "`cmd' string"
                continue
            }
            if `lastrc' == 110 & "`direction'" != "long2wide" {
                * proposed j name collides with an existing variable
                if "`usej'" != "_j" local usej _j
                else                local usej _jj
                local cmd "reshape long `usestubs', i(`usei') j(`usej')`jstring'"
                continue
            }
            if `lastrc' == 111 & "`direction'" != "long2wide" {
                local diagmsg "reshape found no variables matching stub(s) `usestubs' (r(111) no xij variables); check the naming with: describe `: word 1 of `usestubs''*"
                continue, break
            }
            if `lastrc' == 9 & "`direction'" == "long2wide" {
                * duplicates within i,j: diagnose, then try augmenting i once
                tempvar dtag
                capture duplicates tag `usei' `usej', generate(`dtag')
                if !_rc {
                    quietly count if `dtag' > 0
                    local ndup = r(N)
                    local diagmsg "`ndup' sample rows share the same (i, j): reshape wide cannot place two values in one cell. Check: duplicates report `usei' `usej' - then drop true duplicates, collapse repeated measures, add the distinguishing variable to i(), or fold a second factor into j: egen newj = concat(`usej' otherfactor), p(_) - and reshape on j(newj) string. After your own failed try, -reshape error- lists the offending rows"
                    drop `dtag'
                }
                local aug 0
                foreach av of local jcands {
                    if "`av'" == "`usej'" continue
                    local ini : list av in usei
                    if `ini' continue
                    capture isid `usei' `av' `usej'
                    if !_rc {
                        local usei `usei' `av'
                        local cmd "reshape wide `usestubs', i(`usei') j(`usej')`jstring'"
                        local note "i() was widened to include `av' to make rows unique - confirm that is the design"
                        local aug 1
                        continue, break
                    }
                }
                if !`aug' continue, break
                continue
            }
            if `lastrc' == 9 & "`direction'" == "wide2long" {
                local diagmsg "i(`usei') does not uniquely identify the wide rows; check: duplicates report `usei' - or supply a fuller i()"
                continue, break
            }
            continue, break
        }
        local finalrc = `lastrc'
        if `lastrc' == 0 {
            local tested 1
            * chained second step for doubly-wide
            if "`cmd2'" != "" {
                capture `cmd2'
                if _rc {
                    local tested 0
                    local finalrc = _rc
                    local diagmsg "step 1 ran but step 2 failed with r(`finalrc'); run step 1, inspect, then adjust step 2"
                }
            }
        }
        if `tested' {
            local resultN = _N
            local resultK = c(k)
            * AFTER snapshot from the actually-reshaped sample
            local avars ""
            if "`usei'" != "" local avars `usei'
            if "`direction'" != "long2wide" & "`cmd2'" == "" {
                capture confirm variable `usej'
                if !_rc local avars `avars' `usej'
            }
            unab aall : _all
            foreach v of local aall {
                if `: word count `avars'' >= 5 continue, break
                local in1 : list v in avars
                if !`in1' local avars `avars' `v'
            }
            _rh_snap, vars(`avars') rows(3)
            local a_hdr `"`r(hdr)'"'
            local a_n   = r(n)
            forvalues r = 1/`a_n' {
                local a_l`r' `"`r(l`r')'"'
            }
        }
        else if "`status'" == "ok" {
            local status blocked
            if "`diagmsg'" == "" ///
                local diagmsg "the dry run failed with r(`finalrc'); run the command under -capture noisily- on a copy, or see help reshape"
        }
    }
    restore

    * =========================================================================
    * 7. Emit
    * =========================================================================
    di as txt _n "{hline 70}"
    di as txt "reshapehelper 1.0.0 " as txt "{c |} " as res `NFULL' as txt " obs, " ///
        as res `KFULL' as txt " vars" _c
    if "`xtpanel'`xttime'" != "" di as txt " {c |} xtset: " as res "`xtpanel' `xttime'" _c
    if "`svypsu'" != "" di as txt " {c |} svy psu: " as res "`svypsu'" _c
    di as txt ""
    di as txt "{hline 70}"

    if "`detail'" != "" {
        di as txt "patterns:  numeric-suffix groups: " as res `: word count `numgroups'' ///
            as txt "   @-groups: " as res `: word count `atgroups'' ///
            as txt "   string-suffix: " as res `: word count `strgroups'' ///
            as txt "   doubly-wide: " as res `: word count `dblgroups''
        di as txt "i candidates: " as res "`icands'"
        di as txt "j candidates: " as res "`jcands'"
        di as txt "{hline 70}"
    }

    * ---- the diagram -----------------------------------------------------------
    if `b_n' > 0 {
        local shape1 = cond("`direction'" == "long2wide", "long", "wide")
        local bmore = cond(`b_obs' > `b_n', "more", "")
        di as txt _n "  NOW (`shape1'): " as res `b_obs' as txt " sample obs"
        _rh_box, hdr(`"`b_hdr'"') n(`b_n') l1(`"`b_l1'"') l2(`"`b_l2'"') l3(`"`b_l3'"') `bmore'
    }
    if `tested' & `a_n' > 0 {
        di as txt "        {c |}"
        if "`cmd2'" == "" di as txt "        {c |}  " as res "`cmd'"
        else {
            di as txt "        {c |}  " as res "`cmd'"
            di as txt "        {c |}  " as res "`cmd2'"
        }
        di as txt "        v"
        local shape2 = cond("`direction'" == "long2wide", "wide", "long")
        local amore = cond(`resultN' > `a_n', "more", "")
        di as txt "  AFTER (`shape2'): " as res `resultN' as txt " obs, " ///
            as res `resultK' as txt " vars  " as res "[dry run: OK]"
        _rh_box, hdr(`"`a_hdr'"') n(`a_n') l1(`"`a_l1'"') l2(`"`a_l2'"') l3(`"`a_l3'"') `amore'
    }

    * ---- verdict + suggestion ----------------------------------------------------
    if "`status'" == "ok" | "`status'" == "blocked" {
        di as txt _n "suggested command" _c
        if "`notest'" != "" di as txt " (not dry-run tested):"
        else if `tested' di as txt " (dry-run " as res "PASSED" as txt " on `b_obs' sample obs):"
        * the FAILED verdict is a report, not an error: -as err- output is never
        * suppressed by -quietly-, which would leak a bare "FAILED198" out of
        * -quietly reshapehelper-.  Genuine errors above still use -as err-.
        else di as txt " (dry-run " as res "FAILED" as txt ", r(" as res "`finalrc'" as txt ")):"
        local ls = c(linesize)
        capture set linesize 255
        if `"`preline'"' != "" di as res `"  `preline'"'
        di as res `"  `cmd'"'
        if "`cmd2'" != "" di as res `"  `cmd2'"'
        capture set linesize `ls'
        if "`note'" != ""    di as txt _n "  note: `note'"
        if "`caution'" != "" di as txt "  caution: `caution'"
        if "`diagmsg'" != "" & "`status'" == "blocked" di as txt _n "  what to check: `diagmsg'"

        * global + smcl + links.  The globals always mirror THIS run: a run
        * with no second step clears the stale `global'2 from a previous run
        * (a pipeline testing "$reshapehelper_cmd2" != "" must not fire on the
        * prior dataset's chained step).
        global `global' `"`cmd'"'
        if "`cmd2'" != "" global `global'2 `"`cmd2'"'
        else              global `global'2
        if `"`smcl'"' == "" {
            local smclout = c(tmpdir)
            if substr(`"`smclout'"', -1, .) != "/" & substr(`"`smclout'"', -1, .) != "\" ///
                local smclout `"`smclout'/"'
            local smclout `"`smclout'reshapehelper_suggestion.smcl"'
        }
        else local smclout `"`smcl'"'
        capture {
            tempname fh
            file open `fh' using `"`smclout'"', write text replace
            file write `fh' "{smcl}" _n
            file write `fh' "{txt}reshapehelper suggestion  {c -}  `c(current_date)' `c(current_time)'" _n
            file write `fh' "{hline}" _n
            if `"`preline'"' != "" file write `fh' `"{res}`preline'"' _n
            file write `fh' `"{res}`cmd'"' _n
            if "`cmd2'" != "" file write `fh' `"{res}`cmd2'"' _n
            file write `fh' "{txt}{hline}" _n
            file write `fh' "{txt}also stored in r(cmd) and " _char(36) "`global'" _n
            file close `fh'
        }
        * only advertise the file if it was actually written (smcl() can name an
        * unwritable directory; the write above is captured)
        capture confirm file `"`smclout'"'
        local haveout = (_rc == 0)
        di as txt ""
        * click-to-RUN links.  A link is emitted only when it is safe to click:
        * the command carries no double-quote, and there is no pre-clean line it
        * would skip.  A chained (doubly-wide) suggestion gets one link per step.
        local safe1 = (strpos(`"`cmd'"', `"""') == 0 & `"`preline'"' == "")
        if `safe1' & "`cmd2'" == "" {
            di as smcl `"  {stata `"`cmd'"':>> click to RUN this on the full data}"'
        }
        else if `safe1' & "`cmd2'" != "" & strpos(`"`cmd2'"', `"""') == 0 {
            di as smcl `"  {stata `"`cmd'"':>> click to RUN step 1}"'
            di as smcl `"  {stata `"`cmd2'"':>> click to RUN step 2 (after step 1)}"'
        }
        if `haveout' {
            di as smcl `"  {view `"`smclout'"':>> click to VIEW/copy the unwrapped syntax}"'
        }
        di as txt  `"  stored: r(cmd)  and  "' _char(36) `"`global'"'
        if `haveout' return local smcl `"`smclout'"'
    }
    else {
        * ---- needinfo: no suggestion, so the mirror globals are cleared too ---
        global `global'
        global `global'2
        di as txt _n "reshapehelper could not settle on a single command."
        if "`diagmsg'" != "" di as txt "  diagnosis: `diagmsg'"
        * sparse-panel note: a candidate DID make i+j unique but was set aside
        * because it barely repeats (near one row per unit).  Say so plainly and
        * give advice even though no command is offered.
        if "`sparsecand'" != "" & "`usei'" == "" {
            di as txt _n "  {bf:possible cause: sparse units.}  " as res "`sparsecand'" ///
                as txt " together with " as res "`sparsej'" as txt " does uniquely"
            di as txt "  identify the rows, but each unit appears only about once, so it was"
            di as txt "  set aside as an unlikely identifier.  If this is a genuinely sparse"
            di as txt "  panel (most units observed once, a few repeated), that is a valid but"
            di as txt "  unusual design.  Then either:"
            di as txt "    - force it: " as res "reshapehelper, to(wide) i(`sparsecand') j(`sparsej')"
            di as txt "    - or confirm there are repeats to widen at all: " ///
                as res "duplicates report `sparsecand'"
            di as txt "  If instead most rows should share an id, the real identifier may be"
            di as txt "  missing or mis-typed (e.g. a name with trailing spaces); clean it first."
        }
        di as txt _n "  Things to check or supply, then rerun reshapehelper:"
        local k 1
        if "`icands'" == "" {
            di as txt "   `k'. no unique row identifier found - state one with i(): " ///
                as res "reshapehelper, i(yourid)"
            local ++k
        }
        else {
            di as txt "   `k'. confirm the row identifier: " as res "isid `: word 1 of `icands''"
            local ++k
        }
        if !`widejudge' & "`to'" != "wide" {
            di as txt "   `k'. no stub+suffix naming pattern found; if the data are wide," ///
                " rename to a consistent pattern first, e.g. " as res "rename inc* income*"
            local ++k
            * near-miss report: single-suffix stubs that almost form a family
            local nearmiss ""
            forvalues g = 1/`nng' {
                local u : list uniq ng_sufs`g'
                if `: word count `u'' == 1 {
                    local nearmiss "`nearmiss' `ng_stub`g''(`u')"
                }
            }
            if `: word count `nearmiss'' >= 2 {
                di as txt "      near-miss stubs seen, each with only one suffix:" ///
                    as res "`nearmiss'"
                di as txt "      if these are the same measure, unify the stems" ///
                    " (rename income81 inc81 ...) and rerun"
            }
        }
        local ic1 : word 1 of `icands'
        local jc1 : word 1 of `jcands'
        if "`jc1'" != "" & "`ic1'" != "`jc1'" & "`ic1'" != "" & "`to'" != "long" {
            di as txt "   `k'. duplicates may block a wide reshape - inspect: " ///
                as res "duplicates report `ic1' `jc1'"
            local ++k
        }
        di as txt "   `k'. tell reshapehelper the target shape: " ///
            as res "reshapehelper, to(long)" as txt " or " as res "to(wide)"
        local ++k
        di as txt "   `k'. or hand it the pieces: " ///
            as res "reshapehelper, to(wide) i(id) j(year)"
        local njc : word count `jcands'
        if `njc' >= 2 & "`to'" != "long" {
            local ++k
            di as txt "   `k'. if several category variables together define the column," ///
                " fold them into one j first: " ///
                as res "egen newj = concat(`: word 1 of `jcands'' `: word 2 of `jcands''), p(_)"
        }
        if `xposeflag' {
            local ++k
            di as txt "   `k'. this looks more like a TRANSPOSE than a reshape (few rows," ///
                " columns are really observations): see " as res "help xpose" ///
                as txt " (or ssc install sxpose for string data)"
        }
    }
    di as txt "{hline 70}"

    * ---- returns -----------------------------------------------------------------
    * none_for_long / none_for_wide are internal "you asked for X but the
    * evidence is not there" states; collapse them to the documented -unknown-
    local retdir "`direction'"
    if inlist("`retdir'", "none_for_long", "none_for_wide") local retdir unknown
    return local  status    "`status'"
    return local  direction "`retdir'"
    return local  cmd       `"`cmd'"'
    return local  cmd2      `"`cmd2'"'
    return local  preclean  `"`preline'"'
    return local  i         "`usei'"
    return local  j         "`usej'"
    return local  stubs     "`usestubs'"
    return local  icands    "`icands'"
    return local  jcands    "`jcands'"
    return local  note      "`note'"
    return local  caution   "`caution'"
    return local  diagnosis "`diagmsg'"
    if "`status'" == "needinfo" & "`usei'" == "" & "`sparsecand'" != "" ///
        return local sparse "`sparsecand'"
    return scalar tested    = `tested'
    return scalar rc        = cond(`finalrc' == ., 0, `finalrc')
    return scalar xpose     = `xposeflag'
end


* -----------------------------------------------------------------------------
* _rh_snap: capture header + up to rows() formatted lines of vars() from the
* data in memory.  Cells are fixed 9 wide; strings truncated to 8 chars.
* -----------------------------------------------------------------------------
program define _rh_snap, rclass
    version 16.0
    syntax , VARS(varlist) ROWS(integer)

    local hdr ""
    foreach v of local vars {
        local vn = abbrev("`v'", 8)
        local hdr `"`hdr'`vn'"'
        local pad = 9 - strlen("`vn'")
        forvalues p = 1/`pad' {
            local hdr `"`hdr' "'
        }
    }
    local n = min(`rows', _N)
    forvalues r = 1/`n' {
        local line ""
        foreach v of local vars {
            capture confirm string variable `v'
            if !_rc {
                local cell = substr(`v'[`r'], 1, 8)
                * a cell value can carry a " or ` (inch marks, coded text);
                * scrub the quote characters so re-expansion of the assembled
                * line cannot unbalance quotes or start a phantom macro
                local cell : subinstr local cell `"""' "'", all
                local cell : subinstr local cell "`=char(96)'" "'", all
            }
            else {
                local cell = strofreal(`v'[`r'], "%8.0g")
                local cell = strtrim("`cell'")
            }
            local line `"`macval(line)'`macval(cell)'"'
            local pad = 9 - strlen(`"`macval(cell)'"')
            if `pad' < 1 local pad 1
            forvalues p = 1/`pad' {
                local line `"`macval(line)' "'
            }
        }
        return local l`r' `"`macval(line)'"'
    }
    return local hdr `"`hdr'"'
    return scalar n = `n'
end


* -----------------------------------------------------------------------------
* _rh_box: draw a boxed snapshot from _rh_snap output
* -----------------------------------------------------------------------------
program define _rh_box
    version 16.0
    syntax , HDR(string) N(integer) [ L1(string) L2(string) L3(string) MORE ]
    local w = strlen(`"`hdr'"') + 2
    if `w' > 74 local w 74
    local dash : di _dup(`w') "-"
    di as txt "  +`dash'+"
    di as txt "  | " as txt `"`= substr(`"`hdr'"', 1, 72)'"' as txt " |"
    forvalues r = 1/`n' {
        local pad = `w' - 2 - strlen(`"`l`r''"')
        local sp ""
        if `pad' > 0 local sp : di _dup(`pad') " "
        di as txt "  | " as res `"`= substr(`"`l`r''"', 1, 72)'"' `"`sp'"' as txt " |"
    }
    if "`more'" != "" di as txt "  | ..." _col(`= `w' + 3') " |"
    di as txt "  +`dash'+"
end