Commit Graph
6857 Commits
Author SHA1 Message Date
thePR0M3TH3AN e522efc191 client-reliability-3: record full 426-file and native browser validation 2026-10-19 18:08:49 -04:00
thePR0M3TH3AN 607d5ce1a1 client-reliability-3: preserve shared badge callbacks and guard reentrant disposal 2026-10-19 18:02:46 -04:00
thePR0M3TH3AN 712b05cf87 client-reliability-3: cancel queued torrent probes after last card owner disposes 2026-10-19 17:56:25 -04:00
thePR0M3TH3AN 66832dc3a9 land: area/dispatch 03766d39ef (dispatch) 2026-10-19 17:47:52 -04:00
thePR0M3TH3AN 03766d39ef dispatch-2 client-reliability-3: verify landings and route reproduced obsolete probe bug 2026-10-19 17:47:47 -04:00
thePR0M3TH3AN f9adfc8f53 land: area/client-reliability af16ee1d09 (client-reliability) 2026-10-19 16:35:24 -04:00
thePR0M3TH3AN af16ee1d09 Merge branch 'unstable' into area/client-reliability 2026-10-19 16:35:22 -04:00
thePR0M3TH3AN cee4962166 client-reliability-1 client-reliability-2: close verified landed items 2026-10-19 16:35:21 -04:00
thePR0M3TH3AN de6918cee8 land: area/client-reliability 683cedf0bf (client-reliability) 2026-10-19 16:29:12 -04:00
thePR0M3TH3AN 683cedf0bf client-reliability-1 client-reliability-2: record full 425-file validation and unblock landing 2026-10-19 16:29:08 -04:00
thePR0M3TH3AN 181eae95d9 client-reliability-2: make concurrent-init test hermetic and close feed transport 2026-10-19 16:22:57 -04:00
thePR0M3TH3AN 3968a97922 Merge branch 'unstable' into area/client-reliability 2026-10-19 16:20:34 -04:00
thePR0M3TH3AN 3770eb4186 land: area/dispatch 4a6978ebc4 (dispatch) 2026-10-19 16:20:13 -04:00
thePR0M3TH3AN 4a6978ebc4 Merge branch 'unstable' into area/dispatch 2026-10-19 16:20:12 -04:00
thePR0M3TH3AN 16f6dca41e dispatch-2 client-reliability-2: route retained relay cleanup to existing worker 2026-10-19 16:20:10 -04:00
thePR0M3TH3AN 6da037f59b client-reliability-1: record checked fix and newly exposed full-gate blocker 2026-10-19 16:13:49 -04:00
thePR0M3TH3AN dbdac18df1 client-reliability-1: preserve native hidden-attribute behavior in style fixture 2026-10-19 16:09:26 -04:00
thePR0M3TH3AN d02240786d Merge branch 'unstable' into area/client-reliability 2026-10-19 16:07:49 -04:00
thePR0M3TH3AN be6058b0af client-reliability-1: preserve prior integrity notes alongside modal entry 2026-10-19 16:07:46 -04:00
thePR0M3TH3AN c3fee19059 client-reliability-1: bound modal fixture style work with native focus contract 2026-10-19 16:07:36 -04:00
thePR0M3TH3AN e106a15ea5 land: area/dispatch f303ab0e72 (dispatch) 2026-10-19 16:03:01 -04:00
thePR0M3TH3AN f303ab0e72 dispatch-2: record verified worker launch and preserved local preview 2026-10-19 16:03:01 -04:00
thePR0M3TH3AN 9e6c310d80 land: area/dispatch c312399117 (dispatch) 2026-10-19 16:01:33 -04:00
thePR0M3TH3AN c312399117 Merge branch 'unstable' into area/dispatch 2026-10-19 16:01:11 -04:00
thePR0M3TH3AN 3514c0570d dispatch-2: register approved client-reliability worker and scoped bootstrap gate decision 2026-10-19 16:01:10 -04:00
thePR0M3TH3AN 3e451aac0b land: area/dispatch 8b204687d2 (dispatch) 2026-10-19 15:52:32 -04:00
thePR0M3TH3AN 8b204687d2 dispatch-1: record verified startup landing and close preparation 2026-10-19 15:52:32 -04:00
thePR0M3TH3AN fa538097bd land: area/dispatch 386cf14bbe (dispatch) 2026-10-19 15:52:15 -04:00
thePR0M3TH3AN 386cf14bbe dispatch-1: record fleet goal, baseline, and first worker proposal 2026-10-19 15:52:05 -04:00
thePR0M3TH3AN d90591163f chore: initialize Codex agent fleet on unstable 2026-10-19 15:41:55 -04:00
thePR0M3TH3AN 5fdf53deb8 chore: pause Bitvid automated design audit 2026-09-14 18:54:18 -04:00
thePR0M3TH3ANandClaude Fable 5 4dd3eb0330 Add repo memory layer and agent governance
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-12 20:57:52 -04:00
thePR0M3TH3ANandClaude Fable 5 911afb1c05 Split AGENTS.md reference sections into docs/; keep thin agent constitution
Extracts Playwright harness tables and Dark Factory testing standard to
docs/testing/, and dated incident writeups to docs/lessons/, bringing
AGENTS.md under the 32KiB context budget agent harnesses eagerly load.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-12 15:20:08 -04:00
thePR0M3TH3ANandClaude Fable 5 6eb89afcec Dedupe CLAUDE.md testing rules into AGENTS.md pointer; untrack agent memory scratch
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-12 15:15:08 -04:00
thePR0M3TH3ANandClaude Fable 5 c098612c94 Make 'npm test' run the real unit suite
package.json had no "test" script, so `npm test` failed with
"Missing script" and the obvious fallback -- `node --test tests/*.test.mjs`
-- reports ~10 bogus failures. Those files are not broken: the runner
sets NODE_ENV=test (so nostrToolsBootstrap uses the mock toolkit) and
imports tests/test-helpers/setup-localstorage.mjs, and without that
harness they fail on missing globals. tests/modal-accessibility.test.mjs,
for example, is 8/8 under the runner and 0/1 under a bare node --test.

Aliasing test -> run-unit-tests.mjs means the obvious command is also the
correct one, so nobody re-derives that false failure list. CI is
unaffected (it calls test:unit and the shards, which are unchanged).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-04 16:44:47 -04:00
thePR0M3TH3AN 1ddfa95a84 [auth] Vendor BitLogin 30b4f34 and allow WASM in the app CSP
Picks up BitLogin's login-surface expansion (NIP-07 extension, NIP-46
remote signer with nostrconnect QR, passkey sign-in), three rounds of
adversarial-audit fixes, and the mandatory recovery-phrase ceremony for
passkey-created accounts. Vendored via scripts/build-bitlogin-widget.mjs,
which pins the source commit in vendor/bitlogin.integrity.json; the
shared-chunk hashes changed, so three old chunks are removed and three
new ones added.

CSP fix, required for sign-in to work at all: BitLogin's crypto worker
compiles an Argon2id WASM module, and index.html's script-src had no
'wasm-unsafe-eval', so WebAssembly.compile would be blocked and every
BitLogin password flow would fail -- silently, because the page still
loads. This exact omission broke sign-in on bitlogin.network for four
days. The keyword permits WASM compilation only; JS eval stays blocked,
and the CSP comment's stale "no bundle uses wasm" claim is corrected.

tests/csp-policy.test.mjs now pins the keyword for index.html so it
cannot be dropped again. Baseline verified unchanged: npm run test:unit
green, npm run lint clean, and the raw tests/*.test.mjs glob fails the
same 10 pre-existing files before and after this change.

test_integrity_note:
  change_type: ["new_tests"]
  scenarios:
    - id: SCN-csp-allows-wasm-for-bitlogin
      given: "index.html mounts <bitlogin-auth>, whose worker compiles an Argon2id WASM module"
      when: "the page's Content-Security-Policy script-src is evaluated"
      then: "'wasm-unsafe-eval' is present, so WebAssembly.compile is permitted while 'unsafe-eval' remains absent"
  observable_outcomes:
    - "script-src directive parsed from the index.html CSP meta tag contains 'wasm-unsafe-eval'"
    - "existing assertions still forbid 'unsafe-inline' and 'unsafe-eval'"
  determinism_controls:
    - "pure static parse of a committed HTML file; no clock, network, or browser"
  anti_cheat_rationale:
    prevents:
      - "silently relaxing script-src to make sign-in work"
      - "dropping the keyword and shipping a login page that cannot run Argon2id"
  relaxation:
    did_relax_any_assertion: false
    if_true_explain_spec_basis: ""
2026-08-04 16:13:09 -04:00
thePR0M3TH3ANandClaude Opus 5 fbac54dd48 Re-vendor BitLogin at 205b067, and record its provenance
Updates the vendored widget to BitLogin 205b067, which includes the
second-audit hardening the previous bytes predated -- phrase-gated sudo key,
deterministic migration, the pinned derivation chain -- plus the entropy
work: the closed nonce/IV surface, fail-closed RNG tests, and the
package-wide Math.random ban.

Also ports the provenance recording from BitUnlock's vendoring script. The
manifest now carries repository, commit, commit date and toolchain, and the
script refuses to vendor from a BitLogin checkout with uncommitted changes,
resolved before vendorDir is deleted so the refusal leaves the committed
files intact. Hashes prove the bytes have not changed since they were
committed; only the commit says which BitLogin produced them, and version
"0.1.0" has covered many substantive changes.

EXISTING SIGN-INS ARE UNAFFECTED, which matters most here since this is the
one consumer with real users. normalize.ts, argon2id.ts, hkdf.ts and
scalarExpand.ts are byte-identical between the previously vendored build and
205b067, so login name + password derive the same locator, signing scalar
and capsule key as before. Accounts created with a hand-typed password still
sign in: the manual-password removal took away the creation, recovery and
rotation CONTROLS, not the acceptance, and nothing on the login path
inspects the password's shape. BitLogin's legacyPassword.e2e.test.ts pins
that, including the migration path of signing in with an old typed password
and rotating onto a generated one.

What does change for users: creating a new account, recovering, or rotating
now hands out a generated six-word passphrase instead of accepting a typed
one.

2354 unit tests pass, including the 10 bitlogin-specific ones in
auth-providers-bitlogin and bitlogin-modal-integration.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
2026-07-31 22:17:08 -04:00
thePR0M3TH3ANandClaude Fable 5 58922e55c3 Record the caching decision: content-hash filenames, then immutable
Option A chosen. Noting explicitly that Option B should not ship as an interim
step -- the two are not stackable, and a bounded max-age shipped now is the
thing that never gets revisited.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
2026-07-31 14:53:07 -04:00
thePR0M3TH3ANandClaude Fable 5 5e69fa4a7d Todo: static asset caching, and why "just add immutable" would break it
/css/* and /js/* have no header rule at all, so every stylesheet and script
revalidates on every page load. The obvious fix is a trap: asset URLs are not
content-hashed, so a long max-age with immutable would pin returning users to
stale CSS/JS after each deploy with no way to bust it. Records both real
options and the measured live headers.

Also corrects an earlier hand-off note claiming ~10 failing tests here; all
three suites pass on unstable as of today.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
2026-07-31 12:31:36 -04:00
thePR0M3TH3ANandClaude Fable 5 8d40d85079 Delete netlify.toml; the site deploys on Vercel
Vestigial. Verified dead before removing: the live headers on
bitvid.network come from vercel.json, not from this file -- /js/* is
served with Vercel's default `max-age=0, must-revalidate` rather than
the `immutable, max-age=31536000` netlify.toml asks for, which is proof
the file is not consulted by anything deploying this site. It cost real
time today by making the deploy target look like Netlify.

Two rules it carried that vercel.json does NOT, both deliberately left
out rather than silently dropped:
- `Content-Security-Policy: frame-ancestors *` on /*. No behaviour
  change: absence is equally permissive, and the embed page relies on
  being framable, not on the header.
- Long-lived immutable caching for /css/* and /js/*. This one is a real
  (small) performance regression that predates this commit -- the live
  site has been serving those with max-age=0 for as long as it has been
  on Vercel. Worth porting into vercel.json separately; deleting a file
  nothing reads is not the change that should carry it.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
2026-07-31 10:14:43 -04:00
thePR0M3TH3ANandClaude Fable 5 847a855ec8 Update the vendored BitLogin widget to the security-audit build
Was on the 2026-07-25 build. Carries an adversarial audit's fixes, the
ones that matter most for a site that hands the widget real identities:

- Origin binding is enforced INSIDE the crypto worker and derived from
  self.location instead of a caller-supplied field, so a page cannot
  read or adopt a wallet connection bound to a different site.
- Phrase recovery no longer trips the rollback alarm on every later
  login (the mark is keyed by the everyday pubkey, which recovery
  preserves, while the recovered capsule restarts at generation 0) --
  users who had ever rotated a password previously saw "possibly
  revoked credentials" forever, with no way to clear it.
- quorumMet counts relays that ANSWERED rather than ones that merely
  accepted a socket, and relay responses are now checked against the
  address requested, so a single junk event can no longer block
  registration, rotation, and recovery.
- Password rotation checks the new capsule reached quorum BEFORE
  publishing the tombstone that destroys the old one; a failed rotation
  used to be able to leave neither password working.
- Derived secrets (Argon2id output, both PRKs, the BIP-39 seed) are now
  wiped at their derivation site, as the spec always claimed.
- The worker RPC validates message shapes, times out, and rejects
  pending calls when the worker dies, so a torn-down worker surfaces as
  an error instead of a permanent hang.
- Synthetic (script-dispatched) clicks no longer drive consent UI.

Verified: the 10 pre-existing test failures in this suite are unchanged
by this update (checked by stashing the vendor directory and re-running
-- 1330 pass / 10 fail either way), and the BitLogin auth-provider
tests pass. dist/ is gitignored build output and regenerates.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
2026-07-31 10:02:48 -04:00
thePR0M3TH3ANandClaude Fable 5 5cce3b726a docs: close stale innerHTML TODO — ShareNostrModal has no innerHTML left
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:45:23 -04:00
thePR0M3TH3ANandClaude Fable 5 975b996f4c [nostr-core] Pin the NIP-46 multi-account lifecycle contract (TODO #33)
The 2026-06-25 audit blamed "logout logs out everyone" / broken profile
switching / unknown-user-after-refresh on the single shared nip46Client and
single-slot session storage. Re-auditing the current code shows every named
suspect has since been fixed piecemeal: per-account v2 session map with v1
last-connected default, keepStored logout, scoped no-arg clear (v1 slot only),
reuseStored+expectPubkey switch wired end-to-end into
useStoredRemoteSigner({pubkey}), and a validator-enforced boot restore.

None of that was pinned at the manager level, so any layer could regress
silently. tests/nip46-signer-lifecycle.test.mjs now exercises the real
SignerManager against the real signer registry and real (polyfilled) storage:

- logging out the active NIP-46 account destroys its live client exactly once
  while BOTH accounts' stored sessions and the other account's registry signer
  survive
- a failed targeted restore (passphrase-locked or missing session) fails typed
  and deletes nothing
- disconnectRemoteSigner with and without keepStored never touches the
  per-account map

Mutation-checked: reinjecting the historical bugs (logout without keepStored;
no-arg clear wiping the v2 map) fails 2/6; real code passes 6/6.

TODO #33 updated: remaining work is the on-phone Amber verification the item
already gates on — and if that still misbehaves, the failure is now known to
live ABOVE this contract (UI/state reconciliation on restore failure), which
narrows the search considerably.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:33:26 -04:00
thePR0M3TH3ANandClaude Fable 5 2eb7d09865 docs: note that visual baselines are CI-canonical now
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:23:10 -04:00
thePR0M3TH3ANandClaude Fable 5 e99ba0e817 docs: refresh KNOWN_ISSUES against current test reality
- jsdom entry: resolved long ago (28.1.0 installed, in devDeps) — was still
  marked Active with an install remediation.
- webseed-playbook.spec.ts:31: resolved by f48150ed; documents the actual fix
  (record attached srcs instead of asserting the final cleared src).
- uploadModal-reset: not reproducible across 2026-07-28..30 sweeps; left on
  file with instructions if the ordering-dependent hang recurs.
- login-flows.spec.ts:149: corrected — it is NOT a passes-in-isolation flake;
  it failed in isolation on 2026-07-28 (local + CI e2e-headless) while passing
  in the e2e job. Notes the reverted fix attempt and links it to pre-launch
  TODO #33, which is the same subsystem.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:22:21 -04:00
github-actions[bot] ab120a03e1 test(visual): regenerate baselines on ubuntu-latest
Captured by the update-visual-baselines workflow so the baseline environment matches the visual-regression job that compares against them.
2026-07-30 15:16:54 +00:00
thePR0M3TH3ANandClaude Fable 5 5d0709f5f4 [ci] Fix baseline workflow YAML — literal block was terminated early [update-visual-baselines]
The multi-line git commit message inside the run block dropped below the
literal block's indentation, ending the block mid-command and failing the
whole workflow file at parse time (0s failure, no jobs). Use two -m flags on
one shell line instead. YAML now validated locally before push.

Token included so this push performs the regeneration.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:15:26 -04:00
thePR0M3TH3ANandClaude Fable 5 350feae907 [ci] Allow triggering baseline regeneration from unstable [update-visual-baselines]
workflow_dispatch only works for workflows on the default branch, which this
file will not reach until the next promotion. Gate the job on an explicit
[update-visual-baselines] commit-message token instead so it is dispatchable
from unstable now; the workflow's own commit omits the token, so it cannot
retrigger itself.

This commit carries the token, so pushing it performs the first regeneration.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:14:17 -04:00
thePR0M3TH3ANandClaude Fable 5 31be84ba82 [ci] Add a workflow to regenerate visual baselines on the CI runner
The visual-regression job pixel-compares tests/visual/baselines.json on
ubuntu-latest, but the committed baselines were captured on developer machines.
Chromium builds and font fallbacks differ between environments — the token
stack's "Inter"/"Fira Code" are not shipped or installed anywhere, so every
machine renders its own system fallback — and the kitchen-sink default-theme
diff drifted past MAX_DIFF_RATIO on CI while passing 13/13 locally. ci.yml
documents exactly this mismatch as the reason the job is quarantined from
blocking deploys.

The CI diff artifact confirms it: baseline and actual render identically except
for ghosted/offset text in the high-contrast lower half — font-metric drift,
not a design change. (The dark upper half diffs too little to trip the 0.2
pixelmatch threshold, which is why only the default theme fails.)

Fix the class of problem instead of the instance: capture baselines in the SAME
runner image, browser install and font stack that the comparison job uses.
workflow_dispatch only — regenerating baselines is an explicit decision made
when a visual change is intentional, never a side effect of a push. The
workflow re-runs the comparison against its own output before committing, so a
bad capture cannot land.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LHH3wPBsoruwCaJo8Rpf6a
2026-07-30 11:11:14 -04:00
thePR0M3TH3ANandClaude Opus 5 f48150ed6b [ci] Fix the stale tests that had CI red
CI has been failing on unstable for weeks, across four unit files and a set of
e2e specs. None of it was a product regression: every failure is a test that
encodes behavior a later commit deliberately changed. Each is corrected against
the spec that superseded it, not adjusted until it passed.

Unit:

- video-modal-moderation: the fixture set flat `blurThumbnail`/`trustedMuteCount`,
  but normalizeVideoModerationContext derives shouldShow from
  `original.blurThumbnail`/`trustedCount`, so the assertion ran against a
  context whose early return had just deleted the blur it was checking. 4525c1c6
  also made a lone trusted mute a non-blocking ranking signal (its sibling test
  was renamed to say exactly that; this one was missed). Fixture now mirrors
  what moderationDecorator emits.
- trustBootstrap: asserted a subscription to onWhitelistChange that 18e08bf2
  deliberately removed -- buildTrustedSeeds derives seeds from the super admin,
  editors and fallback seeds, so a whitelist change cannot alter them. The
  removal is now pinned so it is not reinstated by reflex.
- moderation-service: 18e08bf2 removed `status.whitelisted ||` from
  isTrustedReporter (being allowed to publish is not a statement that your
  reports carry weight). A whitelisted reporter now counts toward the report
  total but not toward trusted.
- playbackService_forcedSource: forced P2P now falls back to a hosted URL when
  the torrent definitively fails -- playbackService documents the change and its
  rollback. The old assertion did not merely fail, it HUNG: forced sources skip
  the start timeout, so the now-reachable hosted attempt waited forever on a
  <video> that never emits.

E2E:

- ui-modals: asserted exactly one `.bv-modal` per component page, but
  profile-modal.html also bundles #storageCorsModal (d7ad1516). Requires at
  least one and drives the primary, which is what the test's own injected
  querySelector already used.
- coverage-utility-modules: used `author:abc123`, which 9afbc0cb correctly began
  rejecting as undecodable. Uses a real pubkey for the success path and pins the
  rejection separately.
- webseed-playback: asserted the FINAL src equals the CDN URL while also
  tolerating "No playable source found" in its status check -- contradictory,
  since a failed attempt calls resetVideoElement() and clears src. Headless CI
  cannot decode the archive.org H.264 sample. Now records src attachments and
  asserts the URL was attached, which is the behavior under test.
- nostr-runtime-coverage: asserted a legacy plaintext session-actor entry reads
  back as null. Since 8692dac6 added per-account storage, readV1Entry PURGES the
  plaintext entry and the reader falls back to the sole remaining encrypted
  account -- so null no longer describes the security property. Asserts the
  property directly: no plaintext key survives, in the entry or in raw storage.

Also drops the syncAuthUiState share-gate wiring added in d141c316. It was
redundant: Application.updateShareNostrAuthState() already fires on init, login,
logout, pubkey-change and signer-change and forwards to
videoModal.setShareNostrAuthState(). That call short-circuited on its own
`if (!this.videoModal?.setShareNostrAuthState) return;` guard purely because the
method did not exist -- adding it (d141c316) was the whole fix. The tests now
pin that contract instead of a second, competing code path.

All 416 unit files, all three CI shards, both DM suites and lint are green.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-28 17:37:24 -04:00