Öffentliches Register
Software-GesundheitsberichtSchema 0.27.0 · Metriken 1.13.0 · 2026-07-23 00:14 UTC

krauthaufen / wombat.base

TypeScriptMIT★ 0 Sterne⑂ 0 Forksseit Apr. 2026Auf GitHub ansehen ↗

krauthaufen/wombat.base erreicht einen Gesundheitsindex von 42 von 100 und liegt damit im Bereich Gefährdet. Am stärksten schneidet es bei Vitality (70/100) ab, am schwächsten bei Security (21/100). Zuletzt vor 5 Tagen aktualisiert. Ein einzelner Mitwirkender trägt den Großteil der jüngsten Arbeit.

42
gesamt / 100
Gefährdet

Software-Gesundheitsindex

Metriken werden auf einer Skala von 1–100 in gewichtete Kategorien gruppiert. Der Gesamtwert beginnt als ihr Mittel; sobald öffentliche Evidenz die Richtlinie für Hochrisikojurisdiktionen auslöst, wird die Bewertung angepasst und erhält die Obergrenze 49 (Gefährdet). AI Readiness liegt außerhalb.

42
Exzellent85-100Vorbildlich; erfüllt im Wesentlichen alle geprüften Kriterien
Gut70-84Gesund; geringfügige Lücken
Mittel50-69Akzeptabel mit deutlichen Lücken; Überprüfung empfohlen
Gefährdet30-49Erhebliche Schwächen; eine Übernahme erfordert Vorsicht
Kritisch1-29Schwerwiegende Probleme (aufgegeben, nur ein Maintainer, keine Hygiene)
VitalitätCommunity &VerbreitungNachhaltigkeit &GovernanceEngineering-QualitätSicherheitAI Readiness

Bewertungsprofil

Jede Achse ist eine Kategorie. Die Form zählt mehr als der Durchschnitt — ein gesundes Projekt füllt die gesamte Fläche, während ein Profil aus Spitzen und Kratern bedeutet, dass Stärke in einer Dimension Risiken in einer anderen verdeckt.

Eigentümerschaft

Georg HaaserPersönliches Konto
64 Follower97 öffentliche Reposseit Jan. 2014@vrvis @aardworx

Dieses Repository gehört einem persönlichen Konto. Ein Projekt mit nur einem Eigentümer trägt ein höheres Kontinuitätsrisiko als ein organisationsgetragenes.

Paket-Ökosysteme

RegistryPaketVersionDownloads / MonatVersionenZuletzt veröffentlichtTags
npm@aardworx/wombat.base0.6.02.34514vor 5 Tagenwombataardvarkmathgeometryvectormatrixquaternionlinear-algebra

Metriken nach Kategorie

Vitalität

Lebt das Projekt — wird Code geschrieben und werden Releases ausgeliefert?

70Gut · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 5 Tagen
4.8/36Commit-Rhythmus — 7/52 Wochen mit Commits
16.8/18Commit-Volumen — 73 Commits im letzten Jahr
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Verwendete Eingangsdaten
commits_last_year73
human_commit_share1
days_since_last_push5
active_weeks_last_year7
Wie die Bewertung erfolgt
16.2/27Liefert Releases aus — 7 Versions-Tags (keine GitHub-Releases)
36/36Release-Aktualität — letztes Release vor 62 Tagen
27/27Release-Rhythmus — ein Release etwa alle 3,5 Tage
0/10OpenSSF Scorecard: Signed-Releases — keine Daten
Verwendete Eingangsdaten
releases_count7
latest_release_tagv0.5.0
releases_from_tagsja
days_since_latest_release62
mean_days_between_releases3,5
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): OpenSSF Scorecard: Signed-Releases. Die verbleibenden Gewichte wurden renormalisiert.

Community & Verbreitung

Hat das Projekt Nutzer, Downloads, Aufmerksamkeit und ein einladendes Umfeld für Beitragende?

32Gefährdet · 18 % des Gesamtindex
Wie die Bewertung erfolgt
0/60Stars — 0 Stars
0/25Forks — 0 Forks
0/15Watcher — 0 Watcher
Verwendete Eingangsdaten
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Wie die Bewertung erfolgt
22.5/22.5README
22.5/22.5Lizenz — anerkannte Lizenz (MIT)
0/18CONTRIBUTING-Leitfaden
0/13.5Verhaltenskodex
0/7.2Issue-Vorlage
0/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licenseja
has_contributingnein
has_issue_templatenein
has_code_of_conductnein
has_pull_request_templatenein
Wie die Bewertung erfolgt
44.9/80Downloads pro Monat — 2.345 Downloads/Monat über npm
0/20Abhängige in der Registry — von diesem Ökosystem nicht ausgewiesen
Verwendete Eingangsdaten
packages@aardworx/wombat.base
dependents
ecosystemsnpm
total_downloads
monthly_downloads2.345
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Abhängige in der Registry. Die verbleibenden Gewichte wurden renormalisiert.

Nachhaltigkeit & Governance

Überdauert das Projekt die Menschen, die es tragen — Bus-Faktor, Reaktionsfähigkeit, Trägerschaft und Paketpflege?

41Gefährdet · 24 % des Gesamtindex
Wie die Bewertung erfolgt
9/54Bus-Faktor — 1 Beitragende decken die Hälfte aller Commits ab
0/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 100 % der Commits
1.4/13.5Breite der Beitragenden — 1 Beitragende
10/10OpenSSF Scorecard: Contributors — project has 5 contributing companies or organizations
Verwendete Eingangsdaten
bus_factor1
contributors_sampled1
top_contributor_share1
Wie die Bewertung erfolgt
0/46.8Issue-Lösungsquote — keine Issues oder keine Daten
0/38.3PR-Annahme — keine entschiedenen Pull Requests oder keine Daten
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Verwendete Eingangsdaten
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Issue-Lösungsquote, PR-Annahme. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
10/30Organisatorische Trägerschaft — persönliches (Nutzer-)Konto
0/20Verifizierte Domain — für Nutzerkonten nicht anwendbar
13/25Reichweite des Inhabers — 64 Follower von krauthaufen
25/25Kontohistorie — 97 öffentliche Repos, Kontoalter ca. 12 Jahre
Verwendete Eingangsdaten
followers64
owner_typeUser
is_verified
owner_loginkrauthaufen
public_repos97
account_age_days4.576
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Verifizierte Domain. Die verbleibenden Gewichte wurden renormalisiert.

Paketpflege

100Exzellent
Wie die Bewertung erfolgt
25/25Veröffentlicht & auflösbar — 1 Paket(e) auf npm
35/35Veröffentlichungsaktualität — letzte Veröffentlichung vor 5 Tagen
20/20Versionshistorie — 14 veröffentlichte Versionen
20/20Nicht veraltet — aktiv, nicht veraltet oder zurückgezogen
Verwendete Eingangsdaten
packages@aardworx/wombat.base
ecosystemsnpm
any_deprecatednein
min_days_since_publish5

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

40Gefährdet · 20 % des Gesamtindex
Wie die Bewertung erfolgt
0/24CI-Workflows
24/24Tests vorhanden
0/16Linter-Konfiguration
0/9.6Pre-Commit-Hooks
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — keine Daten
Verwendete Eingangsdaten
has_cinein
has_testsja
has_editorconfignein
has_linter_confignein
has_precommit_confignein
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): OpenSSF Scorecard: CI-Tests. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
30/30README
25/25Dokumentationsverzeichnis
0/15Dokumentations-/Homepage-Site
0/10Repository-Beschreibung
0/10Topics
0/10Wiki
Verwendete Eingangsdaten
topics
has_wikinein
homepage
has_readmeja
has_docs_dirja
has_descriptionnein

Sicherheit

Sind die sichtbaren Sicherheits- und Lieferkettenpraktiken belastbar, ohne ungeklärte Exposition gegenüber Hochrisikojurisdiktionen?

21Kritisch · 16 % des Gesamtindex

Sicherheitslage

21Kritisch
Wie die Bewertung erfolgt
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — keine Daten
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 5 contributing companies or organizations
0/10Dangerous-Workflow — keine Daten
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Lizenz — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — keine Daten
0/5Pinned-Dependencies — keine Daten
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — keine Daten
0/7.5Token-Permissions — keine Daten
1.5/7.5Vulnerabilities — 8 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2,1
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Die verbleibenden Gewichte wurden renormalisiert.

AI Readiness

Wie gut ist das Repository dafür ausgestattet, mit KI-Coding-Agenten entwickelt und gepflegt zu werden? Ein unabhängiges, experimentelles Badge — Gewicht 0,0, es wird eigenständig ausgewiesen und verändert den Gesamt-Gesundheitswert nicht.

70Gut · 0 % des Gesamtindex
Wie die Bewertung erfolgt
45/45Agentenanweisungen — CLAUDE.md
0/15Maschinenlesbare Doku (llms.txt)
40/40Lesbare Commit-Historie — 63 von 73 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtnein
legible_history_share0,863
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes4.491
Wie die Bewertung erfolgt
0/18Bootstrap mit einem Befehl
22/22Automatisierte Tests
0/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — tsconfig.json
10/10Reproduzierbare Umgebung — lockfile
0/10Belegte Agentenpraxis — keine von Agenten verfassten Commits unter den letzten 73
0/8Automatisierte Wartung — keine automatisierten Abhängigkeits-Updates beobachtet
0/10OpenSSF Scorecard: Pinned-Dependencies — keine Daten
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfilespackage-lock.json
has_dockerfilenein
typed_languageja
bootstrap_files
has_devcontainernein
has_linter_confignein
typecheck_configstsconfig.json
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): OpenSSF Scorecard: Pinned-Dependencies. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
45/45Typprüfbarer Code — TypeScript (statisch typisiert)
55/55Handhabbare Dateigrößen — 0/248 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languageTypeScript
largest_source_bytes50.407
source_files_sampled248
oversized_source_files0

Eckdaten

0GitHub-Sterne
1Mitwirkende
73Commits, letzte 12 Monate
5Tage seit letztem Push
7Releases
1Bus-Faktor
0offene Issues
npmPaket-Ökosysteme

Warnungen zur Datenerhebung

  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index npm:@aardworx/wombat.base@0.6.0; advisories assessed against the repository dependency graph instead

Weitere Details

OpenSSF Scorecard 2.1 / 10
2.1Gesamtwert

Unabhängige, werkzeugneutrale Sicherheitsbewertung durch das quelloffene OpenSSF Scorecard. Jede Prüfung honoriert eine Sicherheits-Praxis, nicht das Werkzeug eines bestimmten Anbieters. Prüfungen, die Scorecard nicht ermitteln konnte, sind mit k. A. markiert und vom Sicherheitswert ausgeschlossen (nie als null gezählt).Scorecard v5.5.0 · 2026-07-23 00:14 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
k. A.CI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
10Contributorsproject has 5 contributing companies or organizations
k. A.Dangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
k. A.Packagingpackaging workflow not detected
k. A.Pinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
k. A.Signed-Releasesno releases found
k. A.Token-PermissionsNo tokens found
2Vulnerabilities8 existing vulnerabilities detected
Direkte Abhängigkeiten 4
RegistryPaketVersionsvorgabeManifest
npmclipper-lib^6.4.2package.json
npmlibtess^1.2.2package.json
npmopentype.js^1.3.5package.json
npmpoly2tri^1.5.0package.json
Alle Abhängigkeiten nicht erhoben

Der aufgelöste Abhängigkeitssatz konnte für diesen Bericht nicht erhoben werden: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1603,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "JavaScript": 6702,
        "TypeScript": 1443319
      },
      "pushed_at": "2026-07-17T16:25:30Z",
      "created_at": "2026-04-29T15:10:46Z",
      "owner_type": "User",
      "updated_at": "2026-07-17T16:26:02Z",
      "description": null,
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "master",
      "license_spdx_raw": "MIT",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Georg Haaser",
      "type": "User",
      "login": "krauthaufen",
      "company": "@vrvis @aardworx",
      "location": "Vienna",
      "followers": 64,
      "avatar_url": "https://avatars.githubusercontent.com/u/6370801?v=4",
      "created_at": "2014-01-10T16:58:46Z",
      "is_verified": null,
      "public_repos": 97,
      "account_age_days": 4576
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-05-21T18:48:28Z"
        },
        {
          "tag": "v0.4.4",
          "kind": "patch",
          "published_at": "2026-05-21T15:04:56Z"
        },
        {
          "tag": "v0.4.2",
          "kind": "patch",
          "published_at": "2026-05-07T04:03:10Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-05-07T03:59:24Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-05-06T09:51:37Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-04-30T14:01:37Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-04-30T13:48:31Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "d00d551ade7a9efe47be290ff43c02fbd200e0d7",
          "body": null,
          "is_bot": false,
          "headline": "0.6.0",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-07-17T16:25:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1a49cb6a375623ca1cba41bc4e2c00e0fd6a178e",
          "body": "…ics for f64; drops view+ArrayBuffer+native per instance (f32 types keep buffers for rounding)",
          "is_bot": false,
          "headline": "double types on plain number[] — Float64Array backing added no semant…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-07-17T12:45:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef6c402ad2bef646c1360dc5a7950552d31836a0",
          "body": null,
          "is_bot": false,
          "headline": "release v0.5.1",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-07-13T20:26:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a37aed71bea8ce13ddf352109e6b5b261d91c538",
          "body": "…cally centered)",
          "is_bot": false,
          "headline": "layoutText: explicit newline support (per-line centering, block verti…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-07-12T21:27:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e7d3816f8ff1d4a3ae288b7b3f52d33b875490ca",
          "body": "…exact inverses",
          "is_bot": false,
          "headline": "reversed-Z perspective projections (RH/RHFov), infinite far default, …",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-07-11T21:59:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b8368e5af78424d98bb7a0b7be612971ae2fe9d",
          "body": null,
          "is_bot": false,
          "headline": "release v0.5.0",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T18:48:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1a9fa20a22d36c72d13d1dbb747caaa5ddb7d7f",
          "body": "Adds mul/add/sub/div/neg to Number.prototype (idempotent, non-enumerable,\nside-effect of importing the package; listed in sideEffects so bundlers\nkeep it). Pairs with the type declaration in @aardworx/wombat.shader so\nscalar math can use the SAME method style as V*/M* — `x.mul(y)` etc. —\nboth type-checking AND running, with no build plugin. boperators stays an\nopt-in for operator glyphs (the brand statics remain on the math types).",
          "is_bot": false,
          "headline": "feat: install scalar operator-methods on Number.prototype at runtime",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T18:35:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3d39dcb9e32190c26fd071530652007c3845bbea",
          "body": "Verified TODO items against source (dropped items already shipped), bumped\nversions, marked shipped features, fixed links to removed plan/status docs.",
          "is_bot": false,
          "headline": "docs: accuracy pass — refresh README/CLAUDE/TODO against current code",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T16:10:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "46cc11ec915123620ffdbc6a09c8648dcead0c45",
          "body": "Central cross-repo status + architectural TODOs now live in the user's\n~/claude/wombat-todo.md; design/reference docs under docs/ are kept.",
          "is_bot": false,
          "headline": "docs: consolidate open items into TODO.md; drop stale plan/status docs",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T15:59:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07594ae2669cab95135df99bb8b278b86168d9c4",
          "body": null,
          "is_bot": false,
          "headline": "release v0.4.4",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T15:04:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33e964c08e444b7aa9100ca2ee7a6223cde0af13",
          "body": "- band overlap fix: convexity guard on edge-flips so the inflated band\n  no longer emits overlapping triangles across concave quads\n- replace the per-vertex candidate cap with a per-band-triangle CSR\n  candidate buffer (bandCand{Off,Idx}); curve indices live in the SSBO\n- halo 0.1 -> 0.05 em; exhaus\n[…]\np\n- emit VERTEX_KIND_FILL_RAMP \"shell\" triangles for near-boundary\n  interior tris, carrying CSR candidates like the band (the inside half\n  of the symmetric AA ramp); deep interior stays flat alpha=1",
          "is_bot": false,
          "headline": "font: per-band CSR candidates + interior shell tris for symmetric AA",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-21T14:51:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "828f13fdec8695e3d70335fd0fe771dbecdaff4f",
          "body": null,
          "is_bot": false,
          "headline": "chore: cross-platform clean script (rimraf, works on Windows)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-18T09:34:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "71e48b625a46daf2b8a68f4a867d208f6b9eda80",
          "body": "For packing into GPU uniform buffers without the throwaway number[] that\ntoArray() allocates per call (the M44d.toArray slice in the heap-demo-sg\nboot profile). Typed-array dst narrows on store; plain-array dst gets a\nloop. Added across all matrix + vector types.",
          "is_bot": false,
          "headline": "matrix/vector: add copyTo(dst, offset?) — zero-alloc flat write",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-12T15:07:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "16e37b9301b2e06d29e9d57e8beddd5ac85d86bc",
          "body": "Convex-hull traversal alongside the existing AABB-based\n`getIntersecting`. Inputs are 6 inward-facing `Plane3d`s\ndefining the frustum; tests each node's bbox via\n`Plane3d.classify(box) === \"below\"` (SAT-style box vs plane)\nto prune subtrees that lie entirely outside any plane. Same\ncomplexity as the AABB path but stays tight when the hull's\nAABB would blow up — e.g. unprojected pick-disc frustums\nlooking along the scene diagonal, where the corner-AABB\ncollapses to the whole scene.",
          "is_bot": false,
          "headline": "Bvh: getIntersectingFrustum — box-vs-6-plane-hull traversal",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-11T16:19:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "39ca5bd3fa470ab18532a2f4cda0f1b74d5705bf",
          "body": "Adds row-vector × matrix to V2f×M22f, V3f×M33f, V2d×M22d, V3d×M33d,\nV4d×M44d (V4f×M44f shipped in 0.4.1). Symmetric with the existing\nM*V form on each matrix.\n\nBumps to 0.4.2.",
          "is_bot": false,
          "headline": "V*M overloads for the remaining square pairs",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-07T04:03:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4641826e0d39adfff0bceada59cba1311161da8d",
          "body": "(v · M)[c] = Σ v[r] · M[r,c] using M44f's row-major _data layout.\nEnables the inv-transpose normal trick in shader DSL — n.mul(MTI)\ncomputes transpose(MTI) · n = NormalMatrix · n without binding the\nNormalMatrix uniform separately.\n\nBumps to 0.4.1.",
          "is_bot": false,
          "headline": "V4f.mul(M44f): add row-vector × matrix overload",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-07T03:59:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "af6eb2594a06f755e616df30545d1fc7c41a885f",
          "body": null,
          "is_bot": false,
          "headline": "release v0.4.0",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-06T09:51:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "80241963fb7d711e0d8f10f3cae98121c319ad51",
          "body": "Three additions across the vector + matrix classes:\n\n1. **Swizzle accessors on V2f / V3f / V4f**. Every multi-component\n   swizzle from the source's own alphabet (V2f → {x,y}, V3f →\n   {x,y,z}, V4f → {x,y,z,w}) returns a fresh V2f / V3f / V4f at\n   the dim corresponding to the swizzle length. Type-l\n[…]\n3f / M44f.\n   Identical semantics to the existing `m.row(i)` / `m.col(i)`\n   methods, just spelled as direct getters that the wombat.shader\n   frontend can lower to `MatrixRow` / `MatrixCol` IR nodes.",
          "is_bot": false,
          "headline": "vector swizzles + I/O constants; matrix R0-R3 / C0-C3 accessors",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-06T05:03:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b26404926d4a340eac914577a3059bb2a2d1291b",
          "body": "- band-builder: flip inner-polyline rule. Outward bulge now uses the\n  legs (start, p1, end), inward uses the chord. Inner polyline\n  always sits on the *outer* boundary of the lens region, so band\n  geometry never overlaps the body. The lens triangle owns the gap.\n- compileTessellation: park the LO\n[…]\nndices. Lens FS now\n  has a fixed K=3 candidate list to run the same Newton/AA pipeline\n  as the band uses for outside-curve fragments.\n- BAND_HALO_EM bumped 0.05 → 0.1 for visible AA at typical zoom.",
          "is_bot": false,
          "headline": "font/band: lens triangles cover their own outside-curve AA",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T19:27:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1278815212342bdc4204a873a0c32d10ca6dc823",
          "body": "- band-builder pass-2 now tops up any tri with <6 cands (was: only\n  the 0-cand orphan case), pulling neighbours' cands ranked by\n  triToCurveDistSq. Existing tagged cands stay as 0-distance.\n- New edge-flip post-process: orphan tri (3 outer-ring verts)\n  flips a shared edge with a neighbour whose t\n[…]\nnew\n  vec2 attribute reading from offset 40). Keeps stride at 48 by\n  reusing kind=4 band tris' unused klm.x slot for a running per-tri\n  id (used as a primitive-id surrogate by the SDF debug shader).",
          "is_bot": false,
          "headline": "font/band: K=6 candidates, edge-flip pass for orphan tris",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T17:02:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "588e083182fbac5af899950ce2ba9cc48206f32b",
          "body": "`typescript.tsdk` and `typescript.enablePromptUseWorkspaceTsdk` are\ndeprecated in current VSCode and surface a \"this setting is\ndeprecated\" warning. Replace with the renamed keys:\n  - \"js/ts.tsdk.path\"                       (was typescript.tsdk)\n  - \"js/ts.tsdk.promptToUseWorkspaceVersion\" (was typescript.enablePromptUseWorkspaceTsdk)",
          "is_bot": false,
          "headline": ".vscode: switch to current TS-SDK setting keys",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T10:04:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "14a5ba08b6fe3096c51d6382dd28cb79935d425a",
          "body": "Each band triangle now carries up to K=4 candidate curve/line SSBO\nindices instead of having every band fragment scan the glyph's full\nSSBO range. Candidates derive from which curves the triangle's\ninner-side vertices belong to:\n  - anchor-point vertex contributes its 2 adjacent contour edges\n  - le\n[…]\n — the\nbody's m sign is the canonical answer.\n\nSubdivides long inner-polyline edges to step ≤ halo via\n`buildInsideBodyPolyline` adding Steiner points so libtess always\nhas a nearby inner-side vertex.",
          "is_bot": false,
          "headline": "base 0.3.3: per-tri band candidate dispatch via inner-vertex tags",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T09:27:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5ff20b4cad76dcc7f8be7b6f7307239ea3b1a8e7",
          "body": "…nner polyline\n\nReplaces the ±halo annulus with a one-sided design:\n\n  innerPolyline = piecewise-linear approximation of the body\n                  interior, walked per outline edge:\n                    line / arc / cubic           → chord\n                    bezier2 P1 outside body      → chord  (l\n[…]\ndates.ts (per-tri closest-curves filter via real\ngeometric distance + longest-edge bisection), kept as\ninfrastructure for the next perf pass even though the FS still does\na full SSBO range scan today.",
          "is_bot": false,
          "headline": "font/band-builder: outer-only band via Clipper offset + body-shaped i…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T07:53:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3a03789013da3e6af15a04dcb6944dd2271ead6c",
          "body": "GlyphCache now emits a band geometry layer alongside the body:\n  - For every contour, the band is a triangulated annulus at ±halo_em\n    around the contour (`band-builder.ts`). Geometry built CPU-side\n    via clipper-lib polygon offsetting (`InflatePaths +halo` and\n    `-halo`, `Difference` for the \n[…]\nO range clipping (band FS currently scans every\n    glyph curve per fragment — bounded but heavy on mobile GPUs).\n  - Body-side coverage probe.\n  - Halo as a runtime knob, not a compile-time constant.",
          "is_bot": false,
          "headline": "font: per-pixel SDF text via Clipper2 ±halo annulus + per-curve Newton",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-05T05:48:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c787b902a4a56db00e6634abf13a4d08d4627777",
          "body": "GlyphCache now also builds, alongside the rasterized vertex/index\natlas, two extra per-font buffers used by the per-pixel triangle-\nSDF path in wombat.dom:\n\n  * sdfSegmentBuffer() — flat array of (start, end, control,\n    fillNormal, kind) per quadratic-bezier or line segment, plus\n    per-glyph (sd\n[…]\ne ribbons (kind=3).\n\nAlso: existing buffers.ts and triangulate.ts pick up the\nVERTEX_KIND_DISTANCE_FIELD = 4 and the per-vertex (kind, klm)\nHaloTriangle layout already used by the discarded halo path.",
          "is_bot": false,
          "headline": "font: per-glyph SDF segment + packed-triangle buffers for FS-side AA",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-04T08:31:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e8cb0d20e1dd9c6a95dec397f8477831f253b50d",
          "body": "Each glyph face's surrounding 0.2-bbox rectangle is now tiled by\nconstrained-Delaunay triangles (poly2tri) treating the face's outer\ncontour as a hole and each inner counter contour as its own simple-\npolygon. Halo triangles ride the existing bezier2 path with klm =\n(1, 0, 1) so the Loop-Blinn fragm\n[…]\nning, so glyphs with inner counters (e/a/o/b/d/p/q/g)\nget every contour as a separate simple polygon; outward-bulging\ncurve sub-pieces inject their control vertex so the halo wraps the\ncurve triangle.",
          "is_bot": false,
          "headline": "path: watertight per-glyph halo via poly2tri CDT",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-03T13:45:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e3f4f5b7df2521942d1fe212f99f6cf90c4cd2d6",
          "body": "`triangulateFace` / `triangulateFilledFaces` now emit a third class\nof triangles alongside the flat interior fill and curve triangles:\n1-pixel-wide outline ribbons along boundary LINE half-edges (skipped\nfor curves and Stage 3.5 bridges).\n\nEach line ribbon is a 4-vertex / 2-triangle quad sitting AT \n[…]\n The chord-end \"skirt\"\nthat would close tip-AA at curve/line corners is the next step.\n\nTest surface 902 → 902 (one assertion updated to account for the\n4 new line ribbons on the unit-square fixture).",
          "is_bot": false,
          "headline": "path: outline-ribbon emission for line-edge AA",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T19:29:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dc0c65b28d323ab0df6140d72e2e01ff46b0a7b2",
          "body": "`GlyphCache(font)` lazily runs the Stage 0–6a pipeline on first\nsight of a code-point and appends the resulting (vertices, indices)\ninto a single growing atlas. Per-glyph metadata records:\n\n  { firstIndex, indexCount, baseVertex, vertexCount, advance, bbox, empty }\n\nso callers can issue `drawIndexed\n[…]\nrow the\natlas. The shift preserves V2d identity for arc start/end so the\nplanar-graph spatial-hash invariant stays bit-exact across the\ncentering transform.\n\n5 new vitest cases — base suite 897 → 902.",
          "is_bot": false,
          "headline": "font: GlyphCache — per-Font lazy tessellation atlas",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T18:05:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d2cd4bb2f778bf676b560d7f880e425982fc1a5e",
          "body": "`layoutText(font, text)` shapes a string left-to-right by mapping\neach Unicode codepoint to one glyph via `font.charToGlyph` and\nplacing it at the running pen X. Returns ShapedGlyph[] (with\ncodepoint / glyphIndex / x / y / advance), total advance, and\nunion bbox in font units.\n\n`segmentsFromLayout(f\n[…]\nt Vibes), bidi reordering, complex-\nscript shaping (Arabic / Indic). The harfbuzzjs hook is the planned\nextension point.\n\n6 new vitest cases on the same Great Vibes fixture; full base\nsuite 891 → 897.",
          "is_bot": false,
          "headline": "Stage 9: text layout (sequential, char→glyph for Latin)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T17:21:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e53b162223ed249416762af92fb552f7b2311b3b",
          "body": "New `svg/` module with `pathFromSvgD(d)` parsing the W3C SVG 1.1\npath-data grammar:\n\n  M m   moveto              C c   cubic Bezier\n  L l   lineto              S s   smooth cubic (reflected c2)\n  H h   horizontal lineto   Q q   quadratic Bezier\n  V v   vertical lineto     T t   smooth quadratic (ref\n[…]\ncover each command kind, implicit-repetition, smooth-curve\nreflection, the arc endpoint→centre conversion, and a\nmulti-subpath glyph-like outline tessellated through the planar\ngraph + face extractor.",
          "is_bot": false,
          "headline": "Stage 8: SVG path-d -> PathSegment lowering",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T17:15:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fdbe4c9c439d65e9fb9d946e0ab9033aaf49141a",
          "body": "New `font/` module wrapping `opentype.js` so callers can lower a\nreal font glyph to our `PathSegment[]` pipeline directly. Exposes:\n\n  Font.parse(buffer) / Font.load(url)\n  font.charToSegments(char, { scale, offset })\n  font.charBoundingBox(char) / advanceWidth(char)\n  pathFromGlyph(glyph, options)\n\n[…]\nl in opentype.js. Adds a\nfixture-based vitest suite (Great Vibes TTF) covering metrics,\ncommand coverage, scale/offset, multi-subpath tessellation, and\nthe four canonical command-shape lowering paths.",
          "is_bot": false,
          "headline": "Stage 7: TTF/OTF outline -> PathSegment lowering",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T17:11:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a050f7d97e69738a8809133251978ba9c511d093",
          "body": "Two-pass face polygon construction in `buildFacePolygon`:\n\n  1. chord polyline (segment endpoints + sub-piece break points\n     from `chordPoints`) used as the \"nonCurved\" reference;\n  2. for each curve sub-triangle, test its \"extra\" vertex\n     (bez2 control / arc apex) against the chord polyline. \n[…]\nridges now subtract correctly, so glyphs with thin\nstrokes and counter-loops render with the right thickness instead\nof the over-thick chord polyline.\n\nAlso exports `chordPoints` from the path barrel.",
          "is_bot": false,
          "headline": "Path: faithful Aardvark-style flat/curve composition",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T17:00:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d2e1f5b75740468ea8417f1b20893ab3ec0c3d5f",
          "body": "Adds buildPlanarGraph, extractFaces, computeWindings, filledFaceIndices,\nFillRule / FillRules, detectComponents, connectComponents,\ntessellatePath, classifyBezier2/Arc/Bezier3, classifyCurve,\ncubicToQuadratics, earClip, triangulateFace, triangulateFilledFaces,\nand compileTessellation to the public surface — needed by the\npath-rendering demo and any consumer that wants to drive the\ntessellator end-to-end.",
          "is_bot": false,
          "headline": "Path: re-export full Stage 2–6a surface from main barrel",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T12:43:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9cb68d12159ff752f54f8d8aaa651e6e9e1c7bd0",
          "body": "Vertex layout simplifies to 2 attributes:\n  a_position : V2f          (location 0)\n  a_klmKind  : V4f (k,l,m,kind)  (location 1)\n\nkind ∈ {0=interior, 1=bezier2, 2=arc} as f32 — each triangle has the\nsame kind on all 3 vertices, so f32 interpolation gives the constant\nvalue across the triangle interi\n[…]\nhe fragment to route to the appropriate implicit-form test.\n\nInterior klm is now (0, 1, 1) so k² − l = −1 — the unified Loop-Blinn\nfragment test 'discard if k² − l > 0' never discards interior pixels.",
          "is_bot": false,
          "headline": "Path buffers: pack klm + kind into one V4f; kind as f32 (no flat interp)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T12:27:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8b55677663d5bfbd13750b793d57799c7e969d90",
          "body": "compileTessellation(faceTriangulation) packs the Stage 5 output into\ninterleaved vertex + index buffers ready for upload to WebGPU:\n\n  Per-vertex layout (24 bytes): 5×f32 + 1×u32\n    [x, y, k, l, m, kind]\n  with kind ∈ { 0=interior, 1=bezier2, 2=arc }.\n\nOutput reports two index ranges — interiorRang\n[…]\n a\nDataView to preserve the bit pattern across f32 reinterpret.\n\nTests: 4 cases — flat-only square, square + bez2 boundary, semi-\ncircle + chord, and area sum invariant for round-trip through\nindices.",
          "is_bot": false,
          "headline": "Path: GPU buffer compilation (Stage 6a)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T12:18:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2a3a26787532034cd9c0a83050bc1a4eba630026",
          "body": "…t (Stage 5)\n\ntriangulate.ts:\n  earClip(polygon)        — ear-clip a simple CCW polygon. Each\n                            candidate ear is verified by the convex\n                            test, no-vertex-strictly-inside test, AND\n                            no-non-adjacent-edge-crosses-diagonal\n  \n[…]\ne triangles.\n\n  triangulateFilledFaces  — top-level: filter to bounded (positive-\n                            area) faces and concatenate triangles.\n\nStage 5 complete; full wombat.base suite: 866/866.",
          "is_bot": false,
          "headline": "Path: ear-clipping triangulation + face → flat + curve triangle outpu…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T12:01:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f4f5e2012484628b03ca73e3868c13ae624733af",
          "body": "…ge 4b)\n\ncubicToQuadratics(c, tolerance) approximates a cubic Bezier as a\nsequence of quadratic Beziers via recursive bisection at t=0.5,\nemitting one quadratic per piece whose third-difference deviation\n‖P0 − 3P1 + 3P2 − P3‖ · √3/36 falls below tolerance. Each piece\nrecovers its quadratic control p\n[…]\nubdivides; pieces stitch\nendpoint-to-endpoint; tolerance scaling; numerical approximation\nwithin the requested tolerance verified by dense sampling.\n\nStage 4 complete; full wombat.base suite: 858/858.",
          "is_bot": false,
          "headline": "Path: cubic Bezier Loop-Blinn via cubic-to-quadratic subdivision (Sta…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T11:54:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e8c2f2ac3636fdf5451e7e8819e31163fa865ec1",
          "body": "CurveTriangle is the per-curve GPU-side representation: 3 world-\nspace vertices forming a triangle that covers the curve, plus per-\nvertex (u, v, m) texcoords for the fragment-side implicit-form\ntest, plus a bulgesOutward flag for the flat-polygon-fill stage\n(true: filled side adds to polygon; false\n[…]\niangulation in Stage 5).\n\nTests: 11 cases covering quad endpoints, full-circle subdivision,\nrotated ellipse arcs, vertex-identity preservation, bulge sign\nconsistency. Full wombat.base suite: 853/853.",
          "is_bot": false,
          "headline": "Path: Loop-Blinn texcoord classification for bezier2 + arc (Stage 4a)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T11:48:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "74faffc7b95719b5985d79cd7956719d058639b4",
          "body": "bridge.ts (sub-stage 3.5c+d):\n  Per-segment-kind y-line crossing finders (line/bez2/bez3/arc) used\n  to ray-cast leftward from each non-root component's leftmost\n  vertex, find the closest enclosing-component edge, and split that\n  edge if the bridge target lands in its interior. Bridge edges are\n  \n[…]\n-6).\n\nTests: full bridge.test.ts suite (5/5), tessellate.test.ts (4/4),\nfill-rule mix (non-zero / even-odd / positive / exactly(k)) on the\nstar-of-david configuration. Full wombat.base suite: 838/838.",
          "is_bot": false,
          "headline": "Path: bridge insertion + tessellatePath helper (closes Stage 3.5)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T11:44:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "752bb8d66c24448a9acb96c54cc9017b383a0c63",
          "body": "…ge 3.5b)\n\ndetectComponents partitions a FaceExtractionResult by traversing\ntwin/next pointers via BFS. Each ComponentInfo records its half-edge\n/ face / edge / vertex sets, the local-outer face (most-negative\nsigned area within the component), the bbox of its vertices, and\nthe leftmost vertex (smallest x, ties broken by smallest y) — used\nby the bridge-insertion stage as the anchor when the component is\nenclosed by another.",
          "is_bot": false,
          "headline": "Path: connected-component detection over the half-edge graph (sub-sta…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T11:31:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a10aca934b13ad92876cb2df3bef7cbd15e569c1",
          "body": "FillRule = (winding: number) => boolean. filledFaceIndices accepts\nany predicate; FillRules constant provides the standard ones:\n\n  nonZero      w !== 0                  (SVG default)\n  evenOdd      (Math.trunc(w) & 1) === 1\n  positive     w > 0\n  negative     w < 0\n  absGreater(k) Math.abs(w) > k\n \n[…]\nero\nfills everything inside either triangle; evenOdd excludes the centre\nhexagon (winding 2); exactly(2) selects only the hexagon. User-\ndefined rules are arbitrary predicates over the winding number.",
          "is_bot": false,
          "headline": "Path: arbitrary fill-rule abstraction (sub-stage 3.5a)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T11:28:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2a8ed19ccc22fea26eb95fe3b480d2035ecf7290",
          "body": "Stage 3a — DCEL half-edge graph + face cycles (face-extract.ts):\n  Two half-edges per PlanarEdge (forward + reversed). Per-vertex\n  outgoing half-edges sorted CCW by tangent angle. next pointers via\n  the standard 'rotate around the destination' formula:\n    next(h) = outgoing half-edge at h.dst imm\n[…]\nnar\n  graphs (single closed contour, including ones with intersections\n  / multiple touching contours) work correctly today.\n\nTests: 4 passing winding cases + 3 todo'd; full suite 827/830 with 3 todo.",
          "is_bot": false,
          "headline": "Path: face extraction (DCEL) + winding via ray-cast (stages 3a + 3b)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:50:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eaa13ed17f679019d5e57dc51e297cafcdf80c35",
          "body": "…age 2)\n\nPlanarGraph stage takes a flat list of PathSegments and emits a graph\nof non-crossing sub-segments connected at shared vertices. Output:\n  - vertices: V2d[] deduplicated within eps via spatial-hash (cell\n    size = eps, 3x3 neighbour probe)\n  - edges: each carrying a sub-segment + (startV, \n[…]\nby initialising 'result' from the coincidence\nprefilter and merging analytic hits via pushUnique. Caught by the\n\"circle crossed by a diameter\" planar-graph test.\n\nStage 2 complete; 816/816 tests pass.",
          "is_bot": false,
          "headline": "Path: planar-graph builder + merge coincidence with analytic hits (st…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:34:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c6e41b88ef7b34c47d034ab35f079d565e6063d1",
          "body": "… pairs (sub-stage 1c)\n\nGeneric numericIntersect handles bez2×bez2, bez2×bez3, bez2×arc,\nbez3×bez3, bez3×arc, arc×arc — every pair where at least one side is\nnot a line. Same policy Aardvark uses for its bez3 cases; we extend it\nto bez2-pair and arc-pair too so all six implicit cases share one\nrobus\n[…]\n1 now complete: all 16 (kind, kind) cases dispatch to a real\nsolver. Tests cover known geometric cases plus randomized fuzz against\nthe subdivision+Newton reference; full wombat.base suite at 809/809.",
          "is_bot": false,
          "headline": "Path intersection: subdivision+Newton solver for the 6 implicit-curve…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:24:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2a8c0f6089fb1c12c560220f9d8827cfa65949a3",
          "body": "Three textbook substitution-based solvers:\n\n  arc × line:  transform line endpoints to ellipse-local frame (where\n               the ellipse becomes the unit circle), solve quadratic\n               |o + s·d|² = 1, recover the arc parameter from the\n               local intersection angle via atan2. \n[…]\n(tb), J = [a', −b'], step via\nCramer; ta/tb advance by +δ as the root-correction step.\n\nDispatcher routes flipped pairs (line, arc/bez2/bez3) through the\nsame solvers and swaps the output coordinates.",
          "is_bot": false,
          "headline": "Path intersection: arc/bez2/bez3 × line solvers (sub-stage 1b)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:20:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4cf5e7efdba7c8d7b582ad7a31b20b35faf5d072",
          "body": "Sets up the all-pairs intersection module with:\n  - public `intersections(a, b, eps)` returning [ta, tb] pairs sorted by ta\n  - shared endpoint-coincidence prefilter used by every solver\n  - DEFAULT_EPS / T_EPS tunables matching Aardvark's tolerances\n  - line × line solver (2x2 linear system + slack\n[…]\n\" throws for the 14 remaining pair cases\n\nSubsequent commits add: arcLine, bezier2Line, bezier3Line, bezier2,\nbezier2Arc, arcs, and the generic numeric-subdivision fallback for the\ncubic-Bezier cases.",
          "is_bot": false,
          "headline": "Path intersection scaffold + line×line solver (sub-stage 1a)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:08:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a8213b9639a873f93f585991030dd101f40a0008",
          "body": "…verse\n\nEndpoints were previously computed on access via pointAt(startAngle) /\npointAt(startAngle + deltaAngle), so two arcs that share a vertex\ndisagreed at ~1e-16 because the trig differs by parametric path. The\nplanar-graph stage of the path tessellator depends on bit-identical\nshared V2d instanc\n[…]\nn\nthe two halves; reverse() re-uses the existing start/end instances.\nLock-in tests verify the identity invariant.\n\nLine / Bezier2 / Bezier3 already had this property — only ArcSegment\nneeded the fix.",
          "is_bot": false,
          "headline": "ArcSegment: store start/end explicitly, share by identity in split/re…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:04:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d2b807d12265ae3e718a1e6fe7238868ad81f0a5",
          "body": "Matches Aardvark's Ellipse2d / ArcSeg shape: two semi-axis vectors\n(direction + magnitude baked together) instead of separate (rx, ry,\nrotation) fields. Downstream math becomes free of explicit rotation\nmatrices — eval / derivative / bounds / length / signedAreaTerm all\nread directly off the axis ve\n[…]\nhe centred contribution to\nthe signed-area integral collapses to (axis0 × axis1) · Δθ.\n\n`fromRadiiRotation` retained as a convenience constructor for the\nclassical (rx, ry, rotation) parameterization.",
          "is_bot": false,
          "headline": "Switch ArcSegment to (axis0, axis1) representation",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T10:01:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "03fb379f43e77f0508710bf0d4f9aab1d2e7eb46",
          "body": "…tage 0)\n\nDiscriminated union of {Line, Bezier2, Bezier3, Arc} in 2D, faithful to\nAardvark.Rendering.Text: arcs are first-class ellipse arcs, NOT lowered\nto Beziers. Each segment provides eval/derivative/bounds/split/reverse/\nlength/signedAreaTerm; bounds is the analytic tight box (not control\nhull)\n[…]\ntch, plus closure of last to first) and aggregates length /\nsigned area / bounds.\n\nAdds Gauss-Legendre quadrature helper (8/16-point + adaptive variant)\nfor the transcendental length / area integrals.",
          "is_bot": false,
          "headline": "PathSegment + closed Path foundation (Aardvark.Rendering.Text port, s…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T09:55:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a043b3f1d3190c61e2dc190d2ce3d8e5615f2e24",
          "body": "…planeXY intersectables\n\n- src/numerics/polynomial.ts — ~480 LOC port of Aardvark.Base's\n  Polynomial.cs: derivative, multiply, evaluate, real-root finders\n  through quartic via Ferrari (depressed cubic fallback for casus\n  irreducibilis), b-sign-aware quadratic to dodge cancellation, all\n  the prec\n[…]\n Aardvark.Dom.Intersectable.fs.\n  Cylinder + cone use the shared Polynomial.realRootsOf for the\n  side-quadratic.\n\n751/751 tests (was 731; +20 polynomial sweeps + 22 intersectable\nshapes). Bump 0.3.2.",
          "is_bot": false,
          "headline": "Polynomial solver (Aardvark.Base verbatim) + cylinder/cone/tetra/oct/…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-02T09:02:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3b4975a43c604ccf7fb83b6b9ed1ee172748d74e",
          "body": null,
          "is_bot": false,
          "headline": "0.3.1",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-01T12:20:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "516885872bce8283d5d1d37bce8c28c066876d50",
          "body": "IIntersectable: ray-against-primitive interface returning { t, point,\nnormal } or undefined. Factories: box (slab method), sphere, triangle\n(Möller-Trumbore), quad (split), triangles array, transformed (wraps\nan inner intersectable in a Trafo3d).\n\nBvh<K,V>: faithful port of Aardvark.Geometry.BvhTree\n[…]\nests: ray-primitive correctness across primitives + transformed\ncase; brute-force vs BVH agreement on 1000 random spheres x 100 rays;\nrebuild-on-bad-cost; getIntersecting + filter; union; determinism.",
          "is_bot": false,
          "headline": "IIntersectable + immutable keyed BVH (Aardvark.Geometry port)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-05-01T12:19:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "76cba44885d766083535707019518b41f3a33495",
          "body": "Cross-references in the README + SCOPE.md updated to match the\nshipped package layout: wombat.adaptive → wombat.base →\nwombat.shader → (in-progress) wombat.rendering. The early\nadaptive-ui experiment is no longer part of the line.",
          "is_bot": false,
          "headline": "docs: drop adaptive-ui; rename tshade → @aardworx/wombat.shader-runtime",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-30T21:21:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7c118ad39bc21138fee3133a6c1ce4782877e07f",
          "body": null,
          "is_bot": false,
          "headline": "0.3.0",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-30T14:01:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3bfd9d8f90c97e89ba407716c38896aff7883ff",
          "body": "V3i / V4i / V3ui / V4ui now accept the same GLSL/WGSL-style\npromotion forms as the float vectors (e.g. `new V4i(v3, w)`,\n`new V4ui(v2, z, w)`).\n\nM22f / M33f / M44f static factories `fromCols` / `fromRows`\naccept both an array of vectors and varargs. Both forms produce\nthe same matrix; varargs is what wombat.shader emits when it\nrecognises `M44f.fromCols(c0, c1, c2, c3)` static-factory calls\ninside shader markers.",
          "is_bot": false,
          "headline": "V*i/V*ui mixed-arg ctors + M*f varargs factories",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-30T14:01:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "499f318db1cc191812cff2f42e45eb29810904a2",
          "body": null,
          "is_bot": false,
          "headline": "0.2.0",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-30T13:48:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "783cc9486ff75f605c8d7016508b511c12b33155",
          "body": "Match GLSL/WGSL vec3/vec4 promotion. `new V4f(v3, w)`,\n`new V4f(v2, z, w)`, `new V3f(v2, z)`, etc. all work both on\nthe CPU and inside wombat.shader markers, so the shader frontend\ncan drop its parallel `vec*()` recognition path without losing\nthe promotion ergonomics.",
          "is_bot": false,
          "headline": "V3f/V4f: mixed-arg constructor promotion forms",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-30T13:48:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0022793e10b09748f650dba725c4c2b7f8d34908",
          "body": "- Replace home-grown @aardworx/aardvark-operators + tsserver plugin with\n  the third-party boperators stack (transform plugin, vite plugin, ts\n  language-server plugin). Static \"+\", \"-\", \"*\", \"/\" and compound forms\n  declared on every math class.\n- Add Aardvark.Base-parity static factories: per-comp\n[…]\new operator tests per\n  family + Aardvark.Base parity smoke tests + mixed-operator parity vs.\n  matrix-multiplication ground truth.\n- CLAUDE.md documents conventions, cycle gotchas, composition rules.",
          "is_bot": false,
          "headline": "migrate to boperators; parity additions; mixed-type 3D operators",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T23:51:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "48130db1b7969a66a86de7b70ac84101d327deb7",
          "body": "…reservation\n\nPlugin now does sub-range anchor mapping (operator '+' hover lands\non '.add' method docs, jump-to-def goes to the method) and the\nrewritten source preserves every comment, blank line, and column\noutside of operator expressions.",
          "is_bot": false,
          "headline": "bump operators 0.4.1 + tsserver 0.3.1: position-mapping with trivia p…",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T19:48:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a247c5604164547bf1ae60589961a6d41621bf7b",
          "body": "Source rewriting in the LSP plugin now uses local AST-diff\ntext edits instead of full-file reformat. Editor positions\nalign: hovers, inferred types, and jump-to-def all work on\nidentifiers outside rewritten expressions.",
          "is_bot": false,
          "headline": "bump operators 0.3.1 + tsserver 0.2.2: local-edit rewriting",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T19:28:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "10dacbb295f3cfabf4410678087ce5d7de2fde91",
          "body": "The tsserver-plugin now ships as a self-contained esbuild bundle\nincluding the transformer; no relative requires that get lost when\nthe plugin is loaded out of context.",
          "is_bot": false,
          "headline": "bump operators 0.3.0 + tsserver 0.2.1 (bundled)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T19:08:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b45a5c7b597f0f18cd1c3dbf1d7d031323a71fe5",
          "body": "Also includes user-level fix: VS Code 1.118 needs workspace trust\ndisabled OR the workspace TSDK path explicit so the bundled\ntsserver doesn't shadow the workspace one (which is where the LSP\nplugin lives via node_modules walk-up). See docs/EDITOR-SETUP.md\n(coming next).",
          "is_bot": false,
          "headline": "bump operator plugins to 0.2.2 / 0.1.1; add .vscode/settings.json",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T18:11:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b1dc106f894039c6fdcf3842e817d5f3847f0a21",
          "body": "Every Ray3d.intersection(...) and Ray2d.intersection(...) now\nreturns 'number | undefined' — the ray's t parameter at the first\nhit, or undefined on miss. 'First hit' = smallest t >= 0. For\nvolumes (Sphere3d, Box3d in 3D; Box2d, Circle2d, Triangle2d,\nPolygon2d, Quad2d in 2D) an origin already inside\n[…]\n— those still return their richer shape because\nthe operand isn't a ray and 'first hit t' isn't the natural answer.\n\nSphere3d.intersects(Ray3d) simplified accordingly.\n\n581/581 tests, typecheck clean.",
          "is_bot": false,
          "headline": "Ray3d/Ray2d intersections return ray-t (single number)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T17:50:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "04d042c4d37fecff3921b72680f13f6b74f3590e",
          "body": "ARRAY VIEWS (9 new): the int / uint / bool family of packed AoS\nbuffers parallel to V*fArray / V*dArray.\n  V2bArray / V3bArray / V4bArray   Uint8Array, 0/1\n  V2iArray / V3iArray / V4iArray   Int32Array\n  V2uiArray / V3uiArray / V4uiArray  Uint32Array\nSame get / getInto / viewAt / forEachInto / set /\n[…]\nTriangle3d × Box3d and Plane3d × Box3d are hosted on\nthe Triangle / Plane sides to keep imports acyclic; Box3d delegates\nwhen needed via type-only imports.\n\n579 tests across 74 files. typecheck clean.",
          "is_bot": false,
          "headline": "non-float vector arrays + comprehensive geometry intersections",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T17:40:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dd3e27008151d1d012eeeb0f7bb20aa9326cc434",
          "body": "BigInt-backed integer coordinates so the spatial hierarchy is exact\nat any depth. Each cell is (x, y, z, exp, isCentered). Uncentered\ncells cover [x·2^e, (x+1)·2^e]; centered cells cover [x·2^e − 2^(e-1),\nx·2^e + 2^(e-1)] so the centered lattice is shifted half a cell from\nthe uncentered one — commo\n[…]\noctant) / contains(p|cell) /\nintersects(box) / boundingBox / equals / getHashCode (32-bit FNV\nmix matching the rest of the package, usable as HashMap key).\n\n486 tests across 64 files, typecheck clean.",
          "is_bot": false,
          "headline": "spatial cells: Cell (octree) + Cell2d (quadtree)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T17:30:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5eb8a9ccd5affeb4160290a2130106a229f99ddc",
          "body": "Three parallel additions land together:\n\nTRANSFORMATIONS (src/trafo/, 12 types, all double-precision):\n  Shift3d  Scale3d  Euclidean3d  Similarity3d  Affine3d  Trafo3d\n  Shift2d  Scale2d  Euclidean2d  Similarity2d  Affine2d  Trafo2d\n\n  Most types use the standard mathematical convention — a.mul(b)\n \n[…]\nor Ray3d ∩ Triangle3d, slab method for\n  Ray3d ∩ Box3d, two-plane intersection via cross-product line\n  direction, even-odd point-in-polygon for Polygon2d.\n\n461 tests across 62 files, typecheck clean.",
          "is_bot": false,
          "headline": "transformations + linear algebra + geometry; flip Trafo composition",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T17:26:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "20b349e9b78da3093d3d35cb7c972cb0d357cbf8",
          "body": "Three parallel additions:\n\nROTATIONS (src/rotation/):\n  Rot2f / Rot2d   2D rotation as scalar radians, Float*Array(1) backed\n  Rot3f / Rot3d   3D rotation as unit quaternion (W,X,Y,Z) — matches\n                  Aardvark.Base.Rot3d storage order\n  Hamilton product, axis-angle / Euler / matrix / two-\n[…]\nte.\n\nWired Rot3d into nextRotation and Box3d into nextInBox after the\nparallel agents landed. Two integration tests verify unit-length\nrotations + nextInBox bounds.\n\n353 tests passing across 38 files.",
          "is_bot": false,
          "headline": "rotations + ranges/boxes + random (XoroShiro128+); wire integration",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T17:12:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0c3f29c94964f55422ed67aebc3ed7a783e42fb1",
          "body": "Some editors (notably VS Code in some configurations) don't follow\npackage.json exports sub-paths when resolving tsserver plugin names.\n@aardworx/aardvark-operators/lang-service silently failed to load in\nthose editors. The dedicated -tsserver package's main IS the plugin,\nso the resolution path is unambiguous everywhere.",
          "is_bot": false,
          "headline": "switch to dedicated @aardworx/aardvark-operators-tsserver package",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T16:40:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ce23b8d48295511ee7c8830916e7b6c7994d5d7",
          "body": "18 matrix files in src/matrix/ following the V3f canonical pattern:\n  M22f/M33f/M44f, M22d/M33d/M44d         square float32 / float64\n  M{R}{C}f / M{R}{C}d for {R,C} in       rectangular float32/64\n    {(2,3), (2,4), (3,2), (3,4), (4,2), (4,3)}\n\nStorage is row-major — _data[r * C + c] for an M{R}{C}\n[…]\nf, 8 for M33d,\nM22f/d smoke, rectangular smoke (transpose round-trip + transform),\nmatrix operator test (m1 * m2, m * v, m * scalar, 2 * m, m + m,\n-m, +=). Total 245 tests, all green; typecheck clean.",
          "is_bot": false,
          "headline": "matrix taxonomy: square + rectangular, row-major (Aardvark convention)",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T16:28:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8b44326f432c1e9e5e09a87a6a2a506d6f807732",
          "body": "15 vector classes following the V3f canonical pattern:\n  V2b/V3b/V4b   bool      Uint8Array\n  V2i/V3i/V4i   int32     Int32Array       + bitwise ops\n  V2ui/V3ui/V4ui uint32   Uint32Array      no neg\n  V2f/V3f/V4f   float32   Float32Array\n  V2d/V3d/V4d   float64   Float64Array\n\nNumeric vectors carry \n[…]\nr over every\nsource file before invoking the TypeScript type checker, so\noperator usage in tests/v3f.operators.test.ts typechecks cleanly\n(plain tsc --noEmit doesn't pick up language-service plugins).",
          "is_bot": false,
          "headline": "fan out vector taxonomy: V2/V3/V4 in b/i/ui/f/d + array views",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T16:03:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c8208e8cfed36877c13881aa0a830336bf760fbf",
          "body": "- ts-patch + tspc replace plain tsc; tsconfig.json plugins array\n  declares both the transform plugin (build) and the lang-service\n  plugin (editor).\n- vitest.config.ts has an inline Vite plugin that runs the same\n  transformer over .ts files at test time, using a project-wide\n  ts.Program for type \n[…]\nector/v3f.operators.test.ts uses operators directly:\n  a + b, 2 * v, (a+b)*2+c, r += b, reflection formula\n  (v - 2 * v.dot(n) * n). 12/12 pass alongside the existing 54\n  method-API tests = 66 total.",
          "is_bot": false,
          "headline": "wire @aardworx/aardvark-operators into build, vitest, editor",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T15:44:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "184ac620a9e7e1a8e497cd058f8fcc511bcaecf6",
          "body": "V3f is Float32Array-backed end-to-end. Standalone construction\nallocates a fresh buffer; V3f.viewOnto(buffer, byteOffset) creates\nan aliasing instance (used by V3fArray.viewAt). Both share the same\nprototype, so every method works identically whether the V3f owns\nits bytes or is viewing a slot of a \n[…]\ne will plug\nstraight into HashMap/HashSet keys.\n\nscalar.ts has the constants and free helpers (clamp, lerp,\nsmoothstep, fract, sign0, wrap, log2Floor/Ceil, approxEqual).\n\n54/54 tests, typecheck clean.",
          "is_bot": false,
          "headline": "v0.1 foundations: V3f canonical pattern + V3fArray",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T15:21:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1a08948f65ff6be522c40483abf9c7e35a2df908",
          "body": "The math/geometry foundation for the TS port of the Aardvark stack.\nPure types and pure functions; no DOM, no WebGL, no adaptive.\n\ndocs/SCOPE.md captures: type taxonomy with Aardvark naming\n(V*/M*/C*/Rot*/Trafo*/Euclidean*/Box*/etc.), precision semantics\nunder TS's 'only number' constraint via Typed\n[…]\nrrayBuffer view, indexable into V3f instances that share storage\nor get copies), uniform algebraic surface, algorithm list\n(LU/QR/SVD/Cholesky/symmetric-eigen), package layout, and a\n~13-week roadmap.",
          "is_bot": false,
          "headline": "scaffold: scope + design for @aardworx/aardvark-ts",
          "author_name": "krauthaufen",
          "author_login": "krauthaufen",
          "committed_at": "2026-04-29T15:10:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 7,
      "commits_last_year": 73,
      "latest_release_at": "2026-05-21T18:48:28Z",
      "latest_release_tag": "v0.5.0",
      "releases_from_tags": true,
      "days_since_last_push": 5,
      "active_weeks_last_year": 7,
      "days_since_latest_release": 62,
      "mean_days_between_releases": 3.5
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": false,
      "has_contributing": false,
      "health_percentage": 28,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "@aardworx/wombat.base",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "wombat",
            "aardvark",
            "math",
            "geometry",
            "vector",
            "matrix",
            "quaternion",
            "linear-algebra"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@aardworx/wombat.base",
          "is_deprecated": false,
          "latest_version": "0.6.0",
          "repository_url": "https://github.com/krauthaufen/wombat.base",
          "versions_count": 14,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2345,
          "first_published_at": "2026-04-29T23:52:49.337000Z",
          "latest_published_at": "2026-07-17T16:20:42.637000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 50407,
      "source_files_sampled": 248,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 4491
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "clipper-lib",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^6.4.2"
        },
        {
          "name": "libtess",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.2.2"
        },
        {
          "name": "opentype.js",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.3.5"
        },
        {
          "name": "poly2tri",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.5.0"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "krauthaufen",
          "commits": 73,
          "avatar_url": "https://avatars.githubusercontent.com/u/6370801?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 5 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 2,
            "reason": "8 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "d00d551ade7a9efe47be290ff43c02fbd200e0d7",
        "ran_at": "2026-07-23T00:14:05Z",
        "aggregate_score": 2.1,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-17T16:25:31Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/krauthaufen/wombat.base",
    "host": "github.com",
    "name": "wombat.base",
    "owner": "krauthaufen"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 42,
      "inputs": {
        "security": 21,
        "vitality": 70,
        "community": 32,
        "governance": 41,
        "engineering": 40
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 70,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 58,
            "inputs": {
              "commits_last_year": 73,
              "human_commit_share": 1,
              "days_since_last_push": 5,
              "active_weeks_last_year": 7
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "7/52 weeks with commits",
                "points": 4.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "73 commits in the last year",
                "points": 16.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 73
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 88,
            "inputs": {
              "releases_count": 7,
              "latest_release_tag": "v0.5.0",
              "releases_from_tags": true,
              "days_since_latest_release": 62,
              "mean_days_between_releases": 3.5
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "7 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 62 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 62
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~3.5 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 3.5
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 32,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 56,
            "inputs": {
              "packages": [
                "@aardworx/wombat.base"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 2345
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "2,345 downloads/month across npm",
                "points": 44.9,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 2345,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 41,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "followers": 64,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "krauthaufen",
              "public_repos": 97,
              "account_age_days": 4576
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "64 followers of krauthaufen",
                "points": 13,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 64,
                      "login": "krauthaufen"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "97 public repos, account ~12 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 97
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 12
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "@aardworx/wombat.base"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 5
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 5 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "14 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 14
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "at_risk",
        "name": "Engineering Quality",
        "value": 40,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "has_ci": false,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "critical",
        "name": "Security",
        "value": 21,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 21,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 2.1
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "8 existing vulnerabilities detected",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 4
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 70,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.863,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 4491
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "63 of 73 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 63,
                      "sampled": 73
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 48,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 73",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 73
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 50407,
              "source_files_sampled": 248,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/248 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 248,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index npm:@aardworx/wombat.base@0.6.0; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-23T00:14:10.156982Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/k/krauthaufen/wombat.base.svg",
  "full_name": "krauthaufen/wombat.base",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Bewertungen sind Signale, keine Garantien. Sie spiegeln öffentlich sichtbare Praxis auf GitHub wider — kein Code-Audit und keine Sicherheitsgarantie.

Fehlende Daten werden ausgeschlossen und die Gewichte neu normiert, nie als null bewertet. Die Methodik ist versioniert und offen: Metriken v1.13.0, Schema v0.27.0 — vollständige Methodik · Metriken-Wiki.

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte Statistikennpm.