Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-23 00:14 UTC

krauthaufen / wombat.base

TypeScriptMIT★ 0 estrellas⑂ 0 forksdesde abr 2026Ver en GitHub ↗

krauthaufen/wombat.base tiene un índice de salud de 42 sobre 100, lo que lo sitúa en la banda En riesgo. Su puntuación más alta es Vitality (70/100) y la más baja, Security (21/100). Se actualizó por última vez hace 5 días. Una sola persona concentra la mayor parte del trabajo reciente.

42
global / 100
En riesgo

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

42
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

Georg HaaserCuenta personal
64 seguidores97 repositorios públicosdesde ene 2014@vrvis @aardworx

Este repositorio pertenece a una cuenta personal. Un proyecto con un único propietario conlleva más riesgo de continuidad que uno respaldado por una organización.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
npm@aardworx/wombat.base0.6.0234514hace 5 díaswombataardvarkmathgeometryvectormatrixquaternionlinear-algebra

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

70Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 5 días
4.8/36Cadencia de commits — 7/52 semanas con commits
16.8/18Volumen de commits — 73 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year73
human_commit_share1
days_since_last_push5
active_weeks_last_year7
Cómo se puntúa
16.2/27Publica versiones — 7 etiquetas de versión (sin releases de GitHub)
36/36Recencia de las versiones — última versión hace 62 días
27/27Cadencia de publicación — una versión cada ~3,5 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count7
latest_release_tagv0.5.0
releases_from_tags
days_since_latest_release62
mean_days_between_releases3,5
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

32En riesgo · 18% del índice global
Cómo se puntúa
0/60Estrellas — 0 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
44.9/80Descargas mensuales — 2345 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packages@aardworx/wombat.base
dependents
ecosystemsnpm
total_downloads
monthly_downloads2345
Excluidos de la puntuación (sin datos o no aplicable): Dependientes en el registro. Los pesos restantes se han renormalizado.

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

41En riesgo · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 5 contributing companies or organizations
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
0/46.8Resolución de issues — sin issues o sin datos
0/38.3Aceptación de PR — sin PR decididos o sin datos
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
Excluidos de la puntuación (sin datos o no aplicable): Resolución de issues, Aceptación de PR. Los pesos restantes se han renormalizado.
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
13/25Alcance del propietario — 64 seguidores de krauthaufen
25/25Trayectoria — 97 repos públicos, cuenta de ~12 años
Datos de entrada utilizados
followers64
owner_typeUser
is_verified
owner_loginkrauthaufen
public_repos97
account_age_days4576
Excluidos de la puntuación (sin datos o no aplicable): Dominio verificado. Los pesos restantes se han renormalizado.
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 5 días
20/20Historial de versiones — 14 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packages@aardworx/wombat.base
ecosystemsnpm
any_deprecatedno
min_days_since_publish5

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

40En riesgo · 20% del índice global
Cómo se puntúa
0/24Flujos de trabajo de CI
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_cino
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.

Documentación

55Moderado
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
0/10Descripción del repositorio
0/10Topics
0/10Wiki
Datos de entrada utilizados
topics
has_wikino
homepage
has_readme
has_docs_dir
has_descriptionno

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

21Crítico · 16% del índice global
Cómo se puntúa
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 — sin datos
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 — sin datos
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — sin datos
0/5Pinned-Dependencies — sin datos
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — sin datos
1.5/7.5Vulnerabilities — 8 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2,1
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

70Bueno · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 63 de 73 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,863
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes4491
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — tsconfig.json
10/10Entorno reproducible — lockfile
0/10Práctica demostrada con agentes — ningún commit con autoría de agente entre los últimos 73
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — sin datos
Datos de entrada utilizados
has_nixno
has_tests
lockfilespackage-lock.json
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configstsconfig.json
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Pinned-Dependencies. Los pesos restantes se han renormalizado.
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
55/55Tamaños de archivo manejables — 0/248 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes50.407
source_files_sampled248
oversized_source_files0

Datos clave

0estrellas de GitHub
1contribuidores
73commits en los últimos 12 meses
5días desde el último push
7versiones publicadas
1factor bus
0issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

  • 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

Más detalle

OpenSSF Scorecard 2.1 / 10
2.1agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).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
n/dCI-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
n/dDangerous-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
n/dPackagingpackaging workflow not detected
n/dPinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
n/dToken-PermissionsNo tokens found
2Vulnerabilities8 existing vulnerabilities detected
Dependencias directas 4
RegistroPaqueteRestricción de versiónManifiesto
npmclipper-lib^6.4.2package.json
npmlibtess^1.2.2package.json
npmopentype.js^1.3.5package.json
npmpoly2tri^1.5.0package.json
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "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"
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasnpm.