ident
All repositories: gitoria
5.0 KB
#!/usr/bin/env python3# tests/realdata-compare.py (ident mission 009, from gitoria's mission 002): compare two tests/realdata-baseline.mjs# outputs. Masks only what is not the app's output:# every file "at":<ms> (the seed's request time), "since":<ms> (a session's sign-in time), "who":<hex> (the connection), "site":"<file:l:c>" and Child@<line>:<col> (source positions of# View nodes / mount keys: they move when lines move), ?v=<hash> and hl-shell-<hash> (hl:web's content hashes of the modules, the worker's cache name)# 'w-' files (the writes) what is random or a clock per run: new mpackdb ids, rids / codes / pick ids / hashes (hex),# API keys and secrets, invite tokens, new short ids, millisecond times, "YYYY-MM-DD HH:MM" stamps, six-digit codes;# the stored state (w-store) is compared line by line, sorted after masking# '-module-' files (the browser half) count as the same when their own code is the same with every source position# masked and every imported name it uses is the same kind with the same body (moving a static to another# file changes the module's tables, not the behaviour); `var x=` ↔ `const x=` is masked (the `let` step).# python3 tests/realdata-compare.py <dirA> <dirB> [-v] → counts + the differing files; exit 1 on a real differenceimport os, re, sys, diffliba, b = sys.argv[1], sys.argv[2]; verbose = '-v' in sys.argvmasks = [(re.compile(r'\\"at\\":\d+'), r'\"at\":T'), (re.compile(r'"at":\d+'), '"at":T'),(re.compile(r'\\"site\\":\\"[^"\\]*\\"'), r'\"site\":S'), (re.compile(r'"site":"[^"]*"'), '"site":S'),(re.compile(r'\?v=[0-9a-f]+'), '?v=H'), (re.compile(r'hl-shell-[0-9a-f]+'), 'hl-shell-H'), (re.compile(r'([A-Z]\w*)@\d+:\d+'), r'\1@L:C'),(re.compile(r'(\\?"since\\?":)\d+'), r'\1T'), (re.compile(r'(\\?"who\\?":\\?")[0-9a-f]+'), r'\1W')]wmasks = [(re.compile(r'pk_[0-9a-f]{32}'), 'pk_KEY'), (re.compile(r'sk_[0-9a-f]{48}'), 'sk_SECRET'), (re.compile(r'\b0m[0-9a-z]{10}\b'), 'ID'), (re.compile(r'\b[0-9a-f]{64}\b'), 'H64'), (re.compile(r'\b[0-9a-f]{48}\b'), 'H48'),(re.compile(r'\b[0-9a-f]{32}\b'), 'H32'),(re.compile(r'\b1[789]\d{11}\b'), 'MS'), (re.compile(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}'), 'TIME'),(re.compile(r'(?<![\d.])\d{6}(?![\d.])'), 'CODE'), (re.compile(r'(shortId\\?":\\?"|class="shortid">)[0-9a-z]{5}'), r'\1SHORT')]POS = re.compile(r'[\w-]+\.hl:\d+:\d+|[A-Z]\w*@\d+:\d+|\b(?:var|const) (?=\w+=)')def moduleParts(t):t = re.sub(r'\?v=[0-9a-f]+', '?v=H', t)kinds, own = {}, []lines = t.split('\n'); i = 0while i < len(lines):l = lines[i]m = re.match(r'\$_\d+\.(\w+)=(.*)$', l)if m:if re.match(r'\(\)=>_\d+\(', m.group(2)): kinds.setdefault(m.group(1), ('stub', ''))else:body = [m.group(2)]while not lines[i].endswith('}));') and not (lines[i].endswith(';') and lines[i] is l and '=>{' not in l):i += 1; body.append(lines[i])kinds[m.group(1)] = ('fn', POS.sub('P', re.sub(r'\$_\d+', '$_N', '\n'.join(body))))i += 1; continueif l.startswith('import{') and '/__hl/hl-runtime.js' in l: i += 1; continueif re.match(r'const \$_\d+=\{\};$', l) or re.match(r'const \w+=\$_\d+\.\w+;$', l) or re.match(r'const \w+=\(\)=>_\d+\(2,', l):m2 = re.match(r'const (\w+)=\(\)=>_\d+\(2,', l)if m2: kinds[m2.group(1)] = ('plugin', '')i += 1; continueown.append(POS.sub('P', re.sub(r'\$_\d+', '$_N', l))); i += 1return kinds, '\n'.join(own)def sameModule(x, y):kx, ox = moduleParts(x); ky, oy = moduleParts(y)if ox != oy: return Falsewords = set(re.findall(r'\b\w+\b', ox))return all(kx.get(n) == ky.get(n) for n in words & (set(kx) | set(ky)))def norm(t, w, store=False):for r, s in masks: t = r.sub(s, t)if w:for r, s in wmasks: t = r.sub(s, t)if store: t = '\n'.join(sorted(t.split('\n')))return tskip = {'0000-server-log'}fa, fb = sorted(f for f in os.listdir(a) if f not in skip), sorted(f for f in os.listdir(b) if f not in skip)if fa != fb: print('FILE LISTS DIFFER', sorted(set(fa) ^ set(fb))[:20]); sys.exit(1)same = masked = modules = 0; bad = []for f in fa:x, y = open(os.path.join(a, f), errors='replace').read(), open(os.path.join(b, f), errors='replace').read()if x == y: same += 1; continuew = '-w-' in f; st = f.endswith('-w-store')if norm(x, w, st) == norm(y, w, st): masked += 1; continueif '-module-' in f and sameModule(x, y): modules += 1; continuebad.append(f)if verbose:print('==== DIFF', f)for l in list(difflib.unified_diff(norm(x, w, st).split('\n'), norm(y, w, st).split('\n'), lineterm='', n=0))[:12]: print(' ', l[:300])reads = sum(1 for f in fa if '-w-' not in f)print(f'{len(fa)} files ({reads} reads, {len(fa) - reads} writes): {same} byte-identical, {masked} identical after masking, {modules} browser modules the same (code, imported functions), {len(bad)} DIFFERENT')for f in bad[:40]: print(' DIFF', f)sys.exit(1 if bad else 0)
Branches
- mainmain branch
Latest commits
- 5fdbb6b2ident mission 009: report — scratch folder notemre
- 74235815ident mission 009 (4/4): docs (README files map + same-output test, STATUS, LOG), report, tests/letcount.py + realdata-baseline/comparemre
- fe183516ident mission 009 (3/4): let only where reassigned — 293 never-reassigned lets are plain declarations; kept: reassigned, loop bodies, names of a file member, a name declared twice in one function; same outputmre
- d2e7f91bident mission 009 (2/4): one lib file per topic (login, accounts, identities, apps, invites, selector, notify + helpers, util), function routes as thin wrappers in lib/api.hl, project.hl = the map; same outputmre
- 91017164ident mission 009 (1/4): file moves — the root .hl files into lib/ (api.hl → lib/api-helpers.hl), styles.hl → components/styles.hl; imports adjusted, no other changemre
- f8bdcbc2ident: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); all gates greenmre
- ff78726cident: Hybriel master 190aa11d (fc838894 GC correctness, #127, #126 closure scopes); gates all greenmre
- a3a7d21aident: Hybriel master 8efba065 (#126 GC by bytes, #48 lambda params copy); session-writing lambdas take &sessionmre
- 98226b41antcolony#40: mission references point to the moved missionsmre
- ff805b9aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
- 51a7bcdfident: Hybriel master 73267707 (#122); /code uses the new page() signature; pending address passed as parameter; once-checksmre
- 836f644fident#24: installable app (manifest, service worker, data-free offline /start), own iconmre
- 8bebbbf2deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
- cc063ea2deploy.sh: never send .git or .gitignore to Byrodinmre
- 81b15b7bState of 2026-09-27, before the move to gitoriamre