Commit Graph
15 Commits
Author SHA1 Message Date
dsql bbfcc4818b release: 1.0.0
first stable release. pre-1.0.0 verification complete: all surviving MED regressions and
gaps resolved and independently re-fired, tree audited clean across the suite.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-09 18:53:15 -04:00
dsql 0030daeb7b refactor: simplify masking to dumb mask_url/mask_proxy + add stable_id
The selective-key URL/proxy machinery (_mask_qs, SENSITIVE_QUERY_KEYS,
_split_host, _bullet_trailing_fields) tried to redact tokens inside arbitrary
URL structure and leaked on shapes it didn't anticipate (SPA-route fragments,
colon-passwords). Replace with purpose-honest functions that cannot leak or
over-mask:

- mask_url: strips query + fragment, keeps scheme/host/path. Does not parse or
  hunt for sensitive params - a secret in a URL is the caller's bug.
- mask_proxy: partial user-reportable proxy id - drops any userinfo credentials
  and masks an IPv4 host's middle octets (A.***.***.D, port kept); non-IPv4
  host passes through; no parseable host raises ValueError.
- stable_id: deterministic sha256-derived id from ordered str parts (\x00-joined,
  regenerable); empty/non-str part or non-positive length raises ValueError.

credit/cvv/phantom/provider unchanged. Export stable_id from the facade.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-06 18:25:06 -04:00
dsql 7fa5916eda fix: deep_set fails loud on a tuple instead of silently replacing it; add deep_gets/deep_sets wildcard verbs
deep_set stepping into or through a tuple used to fall through to the dict branch and
replace the tuple with {}, silently corrupting data on a deep_get/deep_set round-trip
(deep_get traverses tuples read-only). it now raises TypeError - tuples are immutable, so
an in-place update is impossible. also adds deep_gets/deep_sets: '*' path segments for
bulk get (always a list) and bulk set (plain value or fn(current)->new); a '*' passed to
the scalar deep_get/deep_set raises ValueError so the return type is never ambiguous.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-06 16:35:58 -04:00
dsql 718c8a79b0 fix: mask_proxy and mask_url no longer leak credentials in non-4-part specs or url fragments
Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-03 19:08:39 -04:00
dsql e86184986f fix: mask_url re-encodes non-sensitive query values on rebuild (v0.3.4)
the identity quote_via lambda disabled percent-encoding on re-emit, so a
non-sensitive value with a reserved character (e.g. x=%26%3D) came out
structurally corrupted (x=&=). re-encode with quote_plus (safe="*" so the
masked "***" stays literal) instead of the identity function - display
fidelity only, the secret is still always masked to "***" first.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-03 16:20:50 -04:00
dsql 18646f313c docs: compress prose/module docstrings, em-dash->hyphen (de-bloat wave 1)
Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-03 00:14:44 -04:00
dsql 4f835ff003 fix: provider() unicode-digit crash + phantom() short-value false-mask (v0.3.2)
provider() used str.isdigit(), which accepts unicode digit lookalikes (e.g. superscript
²) that int() can't parse, crashing on digit-only-looking input; _digits() now filters
on isdecimal()+isascii() so only real ASCII digits pass through. phantom() revealed the
entire value for len <= 10 while still looking masked (first6+last4 fully covers or
double-covers short strings); those now fully mask instead. Also compresses several
essay-length docstrings (retry, masking, paths) to a line plus the real nuance, with
zero behavior change, and bumps the README install pin.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-02 23:21:51 -04:00
dsql 19e6f4aa06 feat: mask_url/mask_proxy display maskers; fix: deep_set now indexes into lists on numeric segments (commons-2)
mask_url/mask_proxy redact credentials from connection strings for logging
(display only, not a security control). deep_set previously destroyed a list
when a numeric path segment landed on it (isinstance(nxt, dict) check
replaced the list wholesale); it now mirrors deep_get's list indexing so a
get/set round-trip on the same dotted path never corrupts data, raising
IndexError on an out-of-range segment instead of silently mis-storing.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-07-02 17:36:03 -04:00
dsql 4be69f3c95 docs: pin install line to release, note unpinned-latest option
Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-29 18:13:38 -04:00
dsql 5d444eaf16 docs: show unpinned install line; note tag-pinning for reproducibility
Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-29 18:07:22 -04:00
dsql 449f790571 fix: guard geo parse helpers against non-dict JSON; de-dup timeout build (v0.2.3)
- _parse_ipify/_parse_reverse return None on a truthy non-dict body instead of raising
  AttributeError, honoring the documented 'None on any parse failure' contract (L9)
- build the geo request ClientTimeout once instead of twice (nit)
- drop the stale 'live proxy region- contract' wording from _state_slug's docstring (nit).

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-29 17:57:54 -04:00
dsql a5b91bed0d fix: state slug uses underscore + ascii-fold to match the proxy region- contract
addr.geo.fetch_location produced a hyphen slug with no unicode fold (new-york / québec), but the live proxy region- token the original utils.py fed expects underscore + ascii-fold (new_york / quebec). a multi-word state silently routed to an unrecognized region with no error. added _state_slug (NFKD ascii-fold, lowercase, spaces->underscore) and routed _parse_reverse through it. bump to v0.2.2.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-29 03:25:14 -04:00
dsql de6911fb05 fix: retry log uses total attempts as the denominator
the retry warning logged index/last_index (attempts-1), so a 3-attempt retry showed 'retry 1/2'. now logs index+1 of attempts. both retry and aretry.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-28 17:18:28 -04:00
dsql 0939917172 feat: retry/backoff module (commons v0.2.0)
add commons.retry: exponential-backoff retry as sync `retry` and async `aretry`,
each usable as a call form or a decorator. backoff is min(backoff*factor**n,
max_backoff) with optional full jitter; the schedule is a pure generator so it
tests without real sleeps (sleep + rand injectable). `on=` narrows retryable
exception types, `give_up(exc)` stops early on a non-retryable error, and after
attempts are exhausted the LAST exception is re-raised (fail loud, never swallowed).

de-dups retry logic written 3x divergently (aiowebhooks 429/5xx, aioproxies
burn/rotate, aiomail reconnect).

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-27 21:33:55 -04:00
dsql 5997e3f1a1 init: small stdlib-only sync helpers (timing, paths, masking, addr)
Signed-off-by: disqualifier <dev@disqualifier.me>
2026-06-24 22:18:37 -04:00