SSM-Clock—Appendix A — CLI Reference & Pocket Calculator

A.1 CLI reference (one screen, copy-paste)

Single-shot inverse (one snapshot -> tau_hat_days, confidence)

python ssm_clock_runner.py --manifest "clock_manifest.json" --obs "clock_obs.csv" --grid_step_min 2.0 --refine brent

Streaming inverse (ticks -> tau_days per line)

python ssm_clock_stream_v2.py --manifest "clock_manifest.json" ^
  --obs_stream "clock_obs_stream.csv" --dt_days 0.0416667 --grid_step_min 2.0 --refine brent

Acceptance bench (v1.1 knobs; stacked + multistart + Brent)

python ssm_clock_longbench_v2.py ^
  --period_sets "1,7,29.5306,365.2422" ^
  --seeds 200 ^
  --noise_list "2,6" ^
  --grid_step_min 2.0 ^
  --alpha_kz 0.0 ^
  --stack 5 --stack_dt_days 0.5 ^
  --multistart_k 7 --refine brent --refine_steps 80 --bracket_mult 2

Optional: live stream tee to file (PowerShell; ensure UTF-8 or prefer CMD > )

powershell -NoProfile -Command ^
"python ssm_clock_stream_v2.py --manifest 'clock_manifest.json' --obs_stream 'clock_obs_stream.csv' --dt_days 0.0416667 --grid_step_min 2.0 --refine brent | Tee-Object -FilePath 'notes\\tau_stream.log'"

CSV formats

# Pairs (robust)
label,phi,label,phi,label,phi,label,phi
day,120.0,week,40.0,lunar,275.0,solar,15.0

# Wide (fast; columns must match manifest order)
day,week,lunar,solar
120.0,40.0,275.0,15.0


A.2 Pocket calculator (stdlib-only, ASCII)

Paste the following into a file named ssm_clock_calc.py. It provides quick checks for T_search, minutes↔days conversion, modeled phases, residuals and energy, circular error, and tau features.

#!/usr/bin/env python3
# ssm_clock_calc.py  (stdlib-only; ASCII)
import argparse, json, math, sys
EPS_INT = 1e-9

def wrap360(x):
    y = x % 360.0
    return (y + 360.0) if (y < 0.0) else y

def angdiff(a, b):
    return ((a - b + 180.0) % 360.0) - 180.0

def gcd(a, b):
    # a,b are integers
    while b:
        a, b = b, a % b
    return abs(a)

def lcm(a, b):
    return abs(a * b) // gcd(a, b) if a and b else 0

def lcm_days(periods):
    # assumes all periods are exact integers (days)
    vals = [int(round(p)) for p in periods]
    L = vals[0]
    for x in vals[1:]:
        L = lcm(L, x)
    return float(L)

def load_manifest(path):
    with open(path, "r", encoding="utf-8") as f:
        M = json.load(f)
    chans = M.get("channels", [])
    if not chans:
        print("error: manifest has no channels", file=sys.stderr)
        sys.exit(2)
    return M, chans

def is_all_integers(periods):
    return all(abs(p - round(p)) < EPS_INT for p in periods)

def compute_tsearch(periods):
    if is_all_integers(periods):
        return lcm_days(periods)
    return max(periods)

def print_labels(chans):
    print(",".join([c["label"] for c in chans]))

def cmd_tsearch(args):
    M, chans = load_manifest(args.manifest)
    periods = [float(c["period_days"]) for c in chans]
    T = compute_tsearch(periods)
    print(f"T_search_days={T:.10f}")

def cmd_convert(args):
    if args.minutes is not None:
        d = float(args.minutes) / 1440.0
        print(f"days={d:.12f}")
    if args.days is not None:
        m = float(args.days) * 1440.0
        print(f"minutes={m:.6f}")
    if args.minutes is None and args.days is None:
        print("error: provide --minutes or --days", file=sys.stderr); sys.exit(2)

def modeled_phase_at(ch, t_days):
    b0 = float(ch["b0_deg"])
    w  = float(ch["w_deg_per_day"])
    return wrap360(b0 + w * t_days)

def parse_phi_kv(items):
    # items like ["day=120","week=40",...]
    out = {}
    for kv in items or []:
        if "=" not in kv:
            print(f"warn: ignoring '{kv}' (expected label=deg)", file=sys.stderr)
            continue
        k,v = kv.split("=",1)
        out[k.strip()] = float(v.strip())
    return out

def cmd_phase(args):
    M, chans = load_manifest(args.manifest)
    t = float(args.t_days)
    for ch in chans:
        lab = ch["label"]
        phi = modeled_phase_at(ch, t)
        print(f"{lab}={phi:.6f}")

def cmd_labels(args):
    _, chans = load_manifest(args.manifest)
    print_labels(chans)

def cmd_err(args):
    M, chans = load_manifest(args.manifest)
    t = float(args.t_days)
    obs = {}
    if args.ordered:
        vals = [float(x.strip()) for x in args.ordered.split(",") if x.strip()!=""]
        if len(vals) != len(chans):
            print("error: --ordered count must equal #channels", file=sys.stderr); sys.exit(2)
        for ch, val in zip(chans, vals):
            obs[ch["label"]] = float(val)
    else:
        obs = parse_phi_kv(args.phi)
        missing = [c["label"] for c in chans if c["label"] not in obs]
        if missing:
            print(f"error: missing phases for labels: {','.join(missing)}", file=sys.stderr); sys.exit(2)

    E = 0.0
    for ch in chans:
        lab = ch["label"]
        model = modeled_phase_at(ch, t)
        e = angdiff(obs[lab], model)
        E += e*e
        print(f"err[{lab}]={e:.6f} deg")
    print(f"E(t)={E:.6f}")

def cmd_cerror(args):
    T  = float(args.tsearch_days)
    a  = float(args.a_days)
    b  = float(args.b_days)
    d  = abs(a - b)
    err_days = min(d, T - d)
    err_min  = 1440.0 * err_days
    print(f"err_days={err_days:.10f}")
    print(f"err_min={err_min:.4f}")

def cmd_features(args):
    M, chans = load_manifest(args.manifest)
    periods = [float(c["period_days"]) for c in chans]
    T = compute_tsearch(periods)
    tau = float(args.tau_days)
    conf = float(args.confidence) if (args.confidence is not None) else 1.0
    two_pi = 6.283185307179586
    x = (tau % T) / T
    f0 = math.sin(two_pi * x)
    f1 = math.cos(two_pi * x)
    print(f"tau_norm_sin={f0:.12f}")
    print(f"tau_norm_cos={f1:.12f}")
    print(f"confidence={conf:.6f}")
    if args.per_cycle:
        for ch in chans:
            P = float(ch["period_days"])
            xi = (tau % P) / P
            si = math.sin(two_pi * xi) * (conf if args.mask_by_conf else 1.0)
            ci = math.cos(two_pi * xi) * (conf if args.mask_by_conf else 1.0)
            print(f"{ch['label']}_sin={si:.12f}")
            print(f"{ch['label']}_cos={ci:.12f}")

def main():
    ap = argparse.ArgumentParser(description="SSM-Clock pocket calculator (ASCII, stdlib-only)")
    sp = ap.add_subparsers(dest="cmd", required=True)

    p = sp.add_parser("tsearch"); p.add_argument("--manifest", required=True); p.set_defaults(func=cmd_tsearch)
    p = sp.add_parser("convert"); p.add_argument("--minutes", type=float); p.add_argument("--days", type=float); p.set_defaults(func=cmd_convert)
    p = sp.add_parser("phase");   p.add_argument("--manifest", required=True); p.add_argument("--t_days", required=True, type=float); p.set_defaults(func=cmd_phase)
    p = sp.add_parser("labels");  p.add_argument("--manifest", required=True); p.set_defaults(func=cmd_labels)
    p = sp.add_parser("err");     p.add_argument("--manifest", required=True); p.add_argument("--t_days", required=True, type=float)
    p.add_argument("--phi", action="append"); p.add_argument("--ordered"); p.set_defaults(func=cmd_err)
    p = sp.add_parser("cerror");  p.add_argument("--tsearch_days", required=True, type=float); p.add_argument("--a_days", required=True, type=float); p.add_argument("--b_days", required=True, type=float); p.set_defaults(func=cmd_cerror)
    p = sp.add_parser("features");p.add_argument("--manifest", required=True); p.add_argument("--tau_days", required=True, type=float)
    p.add_argument("--per_cycle", action="store_true"); p.add_argument("--mask_by_conf", action="store_true"); p.add_argument("--confidence", type=float)
    p.set_defaults(func=cmd_features)

    args = ap.parse_args()
    args.func(args)

if __name__ == "__main__":
    main()

Quick sanity checks

# Horizon from manifest
python ssm_clock_calc.py tsearch --manifest clock_manifest.json

# Convert minutes <-> days
python ssm_clock_calc.py convert --minutes 5
python ssm_clock_calc.py convert --days 0.1

# Model phases at t = 0.25 d
python ssm_clock_calc.py phase --manifest clock_manifest.json --t_days 0.25

# Residuals and E(t) with inline phases
python ssm_clock_calc.py err --manifest clock_manifest.json --t_days 0.25 --phi day=120 --phi week=40 --phi lunar=275 --phi solar=15

# Residuals and E(t) with ordered list (manifest label order)
python ssm_clock_calc.py labels --manifest clock_manifest.json
python ssm_clock_calc.py err --manifest clock_manifest.json --t_days 0.25 --ordered "120,40,275,15"

# Circular error modulo horizon
python ssm_clock_calc.py cerror --tsearch_days 29.5306 --a_days 0.1 --b_days 29.6

# Tau features (global + per-cycle embeddings)
python ssm_clock_calc.py features --manifest clock_manifest.json --tau_days 1.234 --per_cycle --confidence 0.92


Navigation

Back: SSM-Clock—Acceptance Note & Provenance Chain (7.7–7.8)
Next: Appendix B — Manifest JSON Schema


Explore further:

https://github.com/OMPSHUNYAYA/Symbolic-Mathematical-Clock