Skip to content

Roadmap "Next" wave: ledger read-path flip, optional embeddings tier, Playwright visual gate#35

Merged
CodeWithJuber merged 6 commits into
masterfrom
claude/whitepaper-implementation-plan-x8f7bh
Jul 7, 2026
Merged

Roadmap "Next" wave: ledger read-path flip, optional embeddings tier, Playwright visual gate#35
CodeWithJuber merged 6 commits into
masterfrom
claude/whitepaper-implementation-plan-x8f7bh

Conversation

@CodeWithJuber

Copy link
Copy Markdown
Owner

Ships the three items at the top of ROADMAP "Next", built in parallel worktrees and integrated on top of v0.6.0.

1. Ledger read-path flip (src/ledger_read.js)

Reads are now a merged view (legacy ∪ ledger), so teammate knowledge that arrives with forge ledger merge actually reaches injection and retrieval:

  • claimToLesson maps ledger lesson claims onto the legacy lesson shape with an evidence-derived status: tombstoned → retired, val ≥ 0.6 → active, val < 0.45 with a contradiction → quarantined, else candidate.
  • Flipped surfaces: cortex lessonsForContext / startupBlock / summary (and through them forge cortex, the MCP server, doctor, and the session-start/pre-edit hooks), the substrate advisory count, routing's past-mistake density, recall list / MEMORY.md, and brain's AGENTS.md index.
  • Dedup is by legacy id/slug with the local file winning; every ledger read is best-effort (missing/corrupt ledger degrades to legacy-only).
  • Write paths (recordMistake's confirm-vs-create lookup, recordContradiction, applyDistillation) deliberately keep reading the legacy store they edit — convergence comes from content-addressed claim ids.
  • Guard beyond the brief: reconcileFacts now only tombstones locally-authored claims, so forge recall consolidate can no longer silently delete merged teammate facts.
  • Proof test: a teammate's lesson claim, after forge ledger merge, injects into startupBlock/lessonsForContext with no legacy file materialized.

2. Optional embeddings tier (src/embed.js, ADR-0005)

  • FORGE_EMBED=cmd:<command> (stdin/stdout JSON protocol — any local model or script) or FORGE_EMBED=http:<url> (OpenAI-compatible; $FORGE_EMBED_MODEL / $FORGE_EMBED_KEY, key never logged).
  • forge reuse query and forge ledger query replace the MinHash rel term with embedding cosine (near/adapt ≥ 0.85/0.7 — a higher bar than Jaccard's 0.8/0.6 to match dense cosine's noise floor), fixing the documented weak spot on very short specs. Both commands print the backend that served (sim: minhash / sim: embed(cmd)).
  • Vectors are disk-cached in .forge/embed-cache.jsonl (content-hash keyed, corrupt-line tolerant, truncate-oldest under a 4 MiB cap). Any provider failure — crash, timeout, garbage, wrong count — degrades silently to MinHash.
  • dependencies stays empty; the pure ledger core never imports the tier (callers inject sim).
  • Proof test: spec "delete a user account" vs query "remove a user account" is a MinHash miss (Jaccard ≈ 0) but an embed NEAR hit — verified at unit, store, and spawned-CLI level with a deterministic fake provider.

3. Playwright visual gate (forge uicheck visual <file-or-url>)

  • Renders headless Chromium at 1280×800 and 390×844, fingerprints the computed styles of every visible element (used auto-margins kept symbolic via the Typed OM; never-painted UA noise filtered by getClientRects()), and runs the identical design gate over that rendered vector. Screenshots land in .forge/ui/.
  • Playwright stays an optional tier: no new dependency; absence degrades to "skipped (no browser runtime)" with exit 0; npm i -D playwright-core or FORGE_PLAYWRIGHT=<path> enables it.
  • Security guard runs before any browser resolution: local paths → file://; http(s) only for loopback hosts; non-local URLs refused with an explicit exfiltration warning (--remote to override); lookalike hosts and non-web schemes refused.
  • Live evidence: the dashboard renders as a 4px-base, 100%-on-scale spacing signature — matching the static gate — with real screenshots verified.

Verification

  • npm test: 437 pass, 0 fail, 1 auto-skip (401 baseline unmodified + 16 readflip + 11 embed + 10 visual; the skip is the Playwright live test without a configured browser runtime — it ran 411/411 with one in the build worktree).
  • npm run typecheck: 0 errors; biome clean on all touched files; node scripts/bump.mjs check: version fields agree at 0.6.0.
  • Dogfooded on this repo: forge doctor all clear; forge ledger query prints the new sim: backend line live.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Fc2MvWJbQ1cyNQ76ymv4hs


Generated by Claude Code

claude added 6 commits July 7, 2026 20:43
The PCM ledger has been the convergent write store since P1 while the
legacy stores served every read, so knowledge arriving via `forge ledger
merge` never reached injection. New src/ledger_read.js maps lesson claims
onto the legacy lesson shape (status derived from evidence: tombstoned →
retired, val ≥ 0.6 → active, val < 0.45 with a contradiction →
quarantined, else candidate) and exposes merged lesson/fact reads deduped
by legacy id/slug with the local file winning — best-effort, so a missing
or corrupt ledger degrades to legacy-only.

Flipped read surfaces: cortex lessonsForContext/startupBlock/summary,
substrate advisory, route past-mistake density, recall list/MEMORY.md,
brain AGENTS.md index. Write paths (recordMistake's confirm-vs-create
lookup, recordContradiction, applyDistillation) deliberately keep reading
the legacy files they edit; convergence comes from content-addressed
claim ids. reconcileFacts now only tombstones locally-authored claims so
a merged teammate fact survives `forge recall consolidate`.

Legacy formats are still written — full retirement is the next step
(ROADMAP updated).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc2MvWJbQ1cyNQ76ymv4hs
…styles through the design gate

The static fingerprint (src/uifingerprint.js) parses source CSS/classes and
cannot see rendered reality. New src/uivisual.js closes the loop (spec
07-ui-quality-gate.md §5) while keeping package.json dependency-free
(ADR-0005 optional tier):

- resolvePlaywright(): dynamic import of playwright-core/playwright, or an
  explicit FORGE_PLAYWRIGHT module path; null on absence, never a throw.
- renderedFingerprint(): headless chromium at 1280x800 + 390x844, walks
  visible elements and lifts computed color/background-color, margin/
  padding/gap, font-family, border-radius, box-shadow — margins via the
  Typed OM so used auto-margins (centering residue) don't pollute the
  spacing scale, zero-client-rect elements (e.g. <option>) skipped so UA
  stylesheet noise stays out. Values serialize into synthetic CSS fed to
  the SAME fingerprintText vector as the static gate; one screenshot per
  viewport lands in .forge/ui/.
- visualGate(): rendered fingerprint through the identical uiGate +
  scaleChecks + taste-profile pipeline as `uicheck design`.
- CLI: `forge uicheck visual <file-or-url> [--taste <name>] [--json]
  [--remote]`. Missing browser runtime prints an enable hint and exits 0
  ("skipped" is not failure); gate failure exits 1. Security default:
  non-loopback http(s) targets are refused — fetching arbitrary URLs by
  default is an exfiltration hazard — with --remote as the explicit
  override, enforced before any browser work.

Tests: 10 new (URL guard incl. lookalike hosts, computed-record → vector
mapping, graceful absence, CLI exit codes) + one live test that auto-skips
without a runtime; verified live against src/dash.html — the rendered
fingerprint reproduces the static gate's findings (4px spacing base, 100%
on-scale, radii [4,10], 0 shadows). Docs: GUIDE section, CHANGELOG, spec §5
status, ROADMAP.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc2MvWJbQ1cyNQ76ymv4hs
…near-match

MinHash rel is weak on very short specs (the documented honest limit): one
changed word swings the estimated Jaccard below threshold. This adds the
ADR-0005 optional tier — a pluggable embedding provider that, when configured,
replaces the lexical similarity in Eq. 3 retrieval and the reuse cache's
near-match. MinHash remains the always-working, zero-dependency default.

- src/embed.js (stdlib only): FORGE_EMBED=cmd:<shell-command> (JSON over
  stdin/stdout — any local model or script) or http:<url> (OpenAI-compatible,
  $FORGE_EMBED_MODEL / $FORGE_EMBED_KEY via env only, never logged, never in
  argv); getProvider() memoized per env value; embed() with timeout, size
  caps, and best-effort null on any failure; cosine(); content-hash-keyed
  disk cache (.forge/embed-cache.jsonl, corrupt-tolerant reader, size-capped
  truncate-oldest) so repeated retrieval never re-pays the provider.
- src/ledger.js: score()/retrieve() accept an optional sim(query, claim);
  the pure core never imports embed.js — callers assemble the sim. A null or
  non-finite sim value falls back to MinHash per claim; negatives clamp to 0.
- src/reuse.js: lookup() takes the same optional sim; reuseQuery/reusePeek
  construct it via embed.claimSim when FORGE_EMBED is set. Cosine thresholds
  NEAR_COS/ADAPT_COS = 0.85/0.7 sit above Jaccard's 0.8/0.6 because dense
  cosines have a higher noise floor (unrelated sentences score 0.4–0.6 where
  unrelated shingle sets sit near 0); per-candidate MinHash fallback when a
  vector is missing; LSH prefilter skipped under sim (banding indexes
  sketches, not vectors).
- CLI: no new flags — the env var is the switch; forge ledger query and
  forge reuse query print the backend that served (sim: minhash /
  sim: embed(cmd)) so results are explainable.
- Tests (no network): deterministic fake provider fixture proves the short
  reworded spec MinHash misses becomes a near hit with the provider;
  crash/garbage/timeout degrade cleanly to MinHash; the disk cache avoids
  re-spawning (spawn-counted via side-effect file); CLI backend lines.
  401 baseline tests stay green (now 412); tsc 0 errors; biome clean.
- Docs: README honest limits, GUIDE FORGE_EMBED section, CHANGELOG.
  package.json untouched — dependencies stays absent (ADR-0005 condition 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc2MvWJbQ1cyNQ76ymv4hs
@CodeWithJuber CodeWithJuber marked this pull request as ready for review July 7, 2026 20:55
@CodeWithJuber CodeWithJuber merged commit 26b76cd into master Jul 7, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants